mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 10:02:24 +02:00
merging with master
This commit is contained in:
commit
8efdec1e51
46 changed files with 1657 additions and 689 deletions
|
@ -656,6 +656,8 @@ void Agent::queryAvatars() {
|
|||
ViewFrustum view;
|
||||
view.setPosition(scriptedAvatar->getWorldPosition());
|
||||
view.setOrientation(scriptedAvatar->getHeadOrientation());
|
||||
view.setProjection(DEFAULT_FIELD_OF_VIEW_DEGREES, DEFAULT_ASPECT_RATIO,
|
||||
DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP);
|
||||
view.calculate();
|
||||
ConicalViewFrustum conicalView { view };
|
||||
|
||||
|
@ -876,18 +878,30 @@ void Agent::aboutToFinish() {
|
|||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
||||
// destroy all other created dependencies
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
|
||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||
DependencyManager::destroy<SoundCacheScriptingInterface>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
|
||||
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||
DependencyManager::destroy<AnimationCacheScriptingInterface>();
|
||||
DependencyManager::destroy<EntityScriptingInterface>();
|
||||
DependencyManager::destroy<ResourceScriptingInterface>();
|
||||
DependencyManager::destroy<UserActivityLoggerScriptingInterface>();
|
||||
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<AnimationCache>();
|
||||
|
||||
DependencyManager::destroy<recording::Deck>();
|
||||
DependencyManager::destroy<recording::Recorder>();
|
||||
DependencyManager::destroy<recording::ClipCache>();
|
||||
|
||||
DependencyManager::destroy<AvatarHashMap>();
|
||||
DependencyManager::destroy<AssignmentParentFinder>();
|
||||
DependencyManager::destroy<MessagesClient>();
|
||||
DependencyManager::destroy<ResourceManager>();
|
||||
|
||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||
|
||||
// drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting
|
||||
// this ensures that the ScriptEngine goes down before ScriptEngines
|
||||
_scriptEngine.clear();
|
||||
|
|
|
@ -129,17 +129,12 @@ void AssignmentClient::stopAssignmentClient() {
|
|||
QThread* currentAssignmentThread = _currentAssignment->thread();
|
||||
|
||||
// ask the current assignment to stop
|
||||
BLOCKING_INVOKE_METHOD(_currentAssignment, "stop");
|
||||
QMetaObject::invokeMethod(_currentAssignment, "stop");
|
||||
|
||||
// ask the current assignment to delete itself on its thread
|
||||
_currentAssignment->deleteLater();
|
||||
|
||||
// when this thread is destroyed we don't need to run our assignment complete method
|
||||
disconnect(currentAssignmentThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
|
||||
|
||||
// wait on the thread from that assignment - it will be gone once the current assignment deletes
|
||||
currentAssignmentThread->quit();
|
||||
currentAssignmentThread->wait();
|
||||
auto PROCESS_EVENTS_INTERVAL_MS = 100;
|
||||
while (!currentAssignmentThread->wait(PROCESS_EVENTS_INTERVAL_MS)) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <GLMHelpers.h>
|
||||
|
||||
ScriptableAvatar::ScriptableAvatar() {
|
||||
_clientTraitsHandler = std::unique_ptr<ClientTraitsHandler>(new ClientTraitsHandler(this));
|
||||
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
|
||||
}
|
||||
|
||||
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {
|
||||
|
|
|
@ -583,15 +583,29 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
|
|||
void EntityScriptServer::aboutToFinish() {
|
||||
shutdownScriptEngine();
|
||||
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
DependencyManager::destroy<SoundCacheScriptingInterface>();
|
||||
DependencyManager::destroy<ResourceScriptingInterface>();
|
||||
DependencyManager::destroy<EntityScriptingInterface>();
|
||||
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
|
||||
DependencyManager::destroy<ResourceManager>();
|
||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||
|
||||
DependencyManager::destroy<MessagesClient>();
|
||||
|
||||
DependencyManager::destroy<AssignmentDynamicFactory>();
|
||||
DependencyManager::destroy<AssignmentParentFinder>();
|
||||
DependencyManager::destroy<AvatarHashMap>();
|
||||
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
DependencyManager::destroy<PluginManager>();
|
||||
|
||||
DependencyManager::destroy<ResourceScriptingInterface>();
|
||||
DependencyManager::destroy<EntityScriptingInterface>();
|
||||
|
||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
|
|
@ -87,7 +87,6 @@
|
|||
#include <FramebufferCache.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <InfoView.h>
|
||||
#include <input-plugins/InputPlugin.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
@ -122,8 +121,6 @@
|
|||
#include <plugins/SteamClientPlugin.h>
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <UpdateSceneTask.h>
|
||||
#include <RenderViewTask.h>
|
||||
#include <render/EngineStats.h>
|
||||
#include <SecondaryCamera.h>
|
||||
#include <ResourceCache.h>
|
||||
|
@ -264,54 +261,7 @@ extern "C" {
|
|||
#include "AndroidHelper.h"
|
||||
#endif
|
||||
|
||||
enum ApplicationEvent {
|
||||
// Execute a lambda function
|
||||
Lambda = QEvent::User + 1,
|
||||
// Trigger the next render
|
||||
Render,
|
||||
// Trigger the next idle
|
||||
Idle,
|
||||
};
|
||||
|
||||
class RenderEventHandler : public QObject {
|
||||
using Parent = QObject;
|
||||
Q_OBJECT
|
||||
public:
|
||||
RenderEventHandler() {
|
||||
// Transfer to a new thread
|
||||
moveToNewNamedThread(this, "RenderThread", [](QThread* renderThread) {
|
||||
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
|
||||
qApp->_lastTimeRendered.start();
|
||||
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
|
||||
}
|
||||
|
||||
private:
|
||||
void initialize() {
|
||||
setObjectName("Render");
|
||||
PROFILE_SET_THREAD_NAME("Render");
|
||||
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
|
||||
}
|
||||
|
||||
void render() {
|
||||
if (qApp->shouldPaint()) {
|
||||
qApp->paintGL();
|
||||
}
|
||||
}
|
||||
|
||||
bool event(QEvent* event) override {
|
||||
switch ((int)event->type()) {
|
||||
case ApplicationEvent::Render:
|
||||
render();
|
||||
qApp->_pendingRenderEvent.store(false);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Parent::event(event);
|
||||
}
|
||||
};
|
||||
|
||||
#include "graphics/RenderEventHandler.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse")
|
||||
|
||||
|
@ -374,8 +324,6 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI
|
|||
static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000;
|
||||
static const int ENTITY_SERVER_CONNECTION_TIMEOUT = 5000;
|
||||
|
||||
static const uint32_t INVALID_FRAME = UINT32_MAX;
|
||||
|
||||
static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled
|
||||
|
||||
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
|
@ -2060,7 +2008,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
|
||||
properties["render_rate"] = _renderLoopCounter.rate();
|
||||
properties["render_rate"] = getRenderLoopRate();
|
||||
properties["target_render_rate"] = getTargetRenderFrameRate();
|
||||
properties["present_rate"] = displayPlugin->presentRate();
|
||||
properties["new_frame_present_rate"] = displayPlugin->newFramePresentRate();
|
||||
|
@ -2372,7 +2320,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<Keyboard>()->createKeyboard();
|
||||
|
||||
_pendingIdleEvent = false;
|
||||
_pendingRenderEvent = false;
|
||||
_graphicsEngine.startup();
|
||||
|
||||
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
|
||||
|
||||
|
@ -2642,11 +2590,6 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
// Cleanup all overlays after the scripts, as scripts might add more
|
||||
_overlays.cleanupAllOverlays();
|
||||
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
|
||||
// removal of the items.
|
||||
// See https://highfidelity.fogbugz.com/f/cases/5328
|
||||
_main3DScene->enqueueFrame(); // flush all the transactions
|
||||
_main3DScene->processTransactionQueue(); // process and apply deletions
|
||||
|
||||
// first stop all timers directly or by invokeMethod
|
||||
// depending on what thread they run in
|
||||
|
@ -2661,7 +2604,6 @@ void Application::cleanupBeforeQuit() {
|
|||
}
|
||||
|
||||
_window->saveGeometry();
|
||||
_gpuContext->shutdown();
|
||||
|
||||
// Destroy third party processes after scripts have finished using them.
|
||||
#ifdef HAVE_DDE
|
||||
|
@ -2719,10 +2661,9 @@ Application::~Application() {
|
|||
_shapeManager.collectGarbage();
|
||||
assert(_shapeManager.getNumShapes() == 0);
|
||||
|
||||
// shutdown render engine
|
||||
_main3DScene = nullptr;
|
||||
_renderEngine = nullptr;
|
||||
|
||||
// shutdown graphics engine
|
||||
_graphicsEngine.shutdown();
|
||||
|
||||
_gameWorkload.shutdown();
|
||||
|
||||
DependencyManager::destroy<Preferences>();
|
||||
|
@ -2780,8 +2721,6 @@ Application::~Application() {
|
|||
|
||||
// Can't log to file past this point, FileLogger about to be deleted
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
|
||||
_renderEventHandler->deleteLater();
|
||||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
|
@ -2871,26 +2810,13 @@ void Application::initializeGL() {
|
|||
#endif
|
||||
|
||||
|
||||
_renderEventHandler = new RenderEventHandler();
|
||||
|
||||
// Build an offscreen GL context for the main thread.
|
||||
_glWidget->makeCurrent();
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
_glWidget->swapBuffers();
|
||||
|
||||
|
||||
// Create the GPU backend
|
||||
|
||||
// Requires the window context, because that's what's used in the actual rendering
|
||||
// and the GPU backend will make things like the VAO which cannot be shared across
|
||||
// contexts
|
||||
_glWidget->makeCurrent();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
_glWidget->makeCurrent();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
|
||||
_graphicsEngine.initializeGPU(_glWidget);
|
||||
}
|
||||
|
||||
static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
|
||||
|
@ -2904,7 +2830,7 @@ void Application::initializeDisplayPlugins() {
|
|||
// Once time initialization code
|
||||
DisplayPluginPointer targetDisplayPlugin;
|
||||
foreach(auto displayPlugin, displayPlugins) {
|
||||
displayPlugin->setContext(_gpuContext);
|
||||
displayPlugin->setContext(_graphicsEngine.getGPUContext());
|
||||
if (displayPlugin->getName() == lastActiveDisplayPluginName) {
|
||||
targetDisplayPlugin = displayPlugin;
|
||||
}
|
||||
|
@ -2974,18 +2900,7 @@ void Application::initializeDisplayPlugins() {
|
|||
void Application::initializeRenderEngine() {
|
||||
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
|
||||
DeadlockWatchdogThread::withPause([&] {
|
||||
// Set up the render engine
|
||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
|
||||
#ifndef Q_OS_ANDROID
|
||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED);
|
||||
#endif
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
|
||||
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
|
||||
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
|
||||
_graphicsEngine.initializeRender(DISABLE_DEFERRED);
|
||||
DependencyManager::get<Keyboard>()->registerKeyboardHighlighting();
|
||||
});
|
||||
}
|
||||
|
@ -3186,7 +3101,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||
surfaceContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
surfaceContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
|
||||
surfaceContext->setContextProperty("FrameTimings", &_graphicsEngine._frameTimingsScriptingInterface);
|
||||
surfaceContext->setContextProperty("Rates", new RatesScriptingInterface(this));
|
||||
|
||||
surfaceContext->setContextProperty("TREE_SCALE", TREE_SCALE);
|
||||
|
@ -3235,7 +3150,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Render", _renderEngine->getConfiguration().get());
|
||||
surfaceContext->setContextProperty("Render", _graphicsEngine.getRenderEngine()->getConfiguration().get());
|
||||
surfaceContext->setContextProperty("Workload", _gameWorkload._engine->getConfiguration().get());
|
||||
surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
||||
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
|
||||
|
@ -3523,7 +3438,7 @@ void Application::resizeGL() {
|
|||
|
||||
auto renderResolutionScale = getRenderResolutionScale();
|
||||
if (displayPlugin->getRenderResolutionScale() != renderResolutionScale) {
|
||||
auto renderConfig = _renderEngine->getConfiguration();
|
||||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
assert(renderConfig);
|
||||
auto mainView = renderConfig->getConfig("RenderMainView.RenderDeferredTask");
|
||||
assert(mainView);
|
||||
|
@ -3754,8 +3669,8 @@ void Application::onPresent(quint32 frameCount) {
|
|||
postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority);
|
||||
}
|
||||
expected = false;
|
||||
if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) {
|
||||
postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||
if (_graphicsEngine.checkPendingRenderEvent() && !isAboutToQuit()) {
|
||||
postEvent(_graphicsEngine._renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4543,39 +4458,6 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||
|
||||
bool Application::shouldPaint() const {
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto displayPlugin = getActiveDisplayPlugin();
|
||||
|
||||
#ifdef DEBUG_PAINT_DELAY
|
||||
static uint64_t paintDelaySamples{ 0 };
|
||||
static uint64_t paintDelayUsecs{ 0 };
|
||||
|
||||
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
|
||||
|
||||
static const int PAINT_DELAY_THROTTLE = 1000;
|
||||
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
|
||||
qCDebug(interfaceapp).nospace() <<
|
||||
"Paint delay (" << paintDelaySamples << " samples): " <<
|
||||
(float)paintDelaySamples / paintDelayUsecs << "us";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throttle if requested
|
||||
if (displayPlugin->isThrottled() && (_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sync up the _renderedFrameIndex
|
||||
_renderedFrameIndex = displayPlugin->presentCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#include <TCHAR.h>
|
||||
|
@ -4829,26 +4711,13 @@ void Application::idle() {
|
|||
if (displayPlugin) {
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate());
|
||||
}
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, _renderLoopCounter.rate());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", uint32_t, ResourceCache::getLoadingRequestCount());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "renderLoopRate", float, getRenderLoopRate());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", uint32_t, ResourceCache::getLoadingRequests().length());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", uint32_t, ResourceCache::getPendingRequestCount());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get<StatTracker>()->getStat("Processing").toInt());
|
||||
PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
|
||||
auto renderConfig = _renderEngine->getConfiguration();
|
||||
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_gpuContext->getFrameTimerGPUAverage());
|
||||
auto opaqueRangeTimer = renderConfig->getConfig("OpaqueRangeTimer");
|
||||
auto linearDepth = renderConfig->getConfig("LinearDepth");
|
||||
auto surfaceGeometry = renderConfig->getConfig("SurfaceGeometry");
|
||||
auto renderDeferred = renderConfig->getConfig("RenderDeferred");
|
||||
auto toneAndPostRangeTimer = renderConfig->getConfig("ToneAndPostRangeTimer");
|
||||
|
||||
PROFILE_COUNTER(render_detail, "gpuTimes", {
|
||||
{ "OpaqueRangeTimer", opaqueRangeTimer ? opaqueRangeTimer->property("gpuRunTime") : 0 },
|
||||
{ "LinearDepth", linearDepth ? linearDepth->property("gpuRunTime") : 0 },
|
||||
{ "SurfaceGeometry", surfaceGeometry ? surfaceGeometry->property("gpuRunTime") : 0 },
|
||||
{ "RenderDeferred", renderDeferred ? renderDeferred->property("gpuRunTime") : 0 },
|
||||
{ "ToneAndPostRangeTimer", toneAndPostRangeTimer ? toneAndPostRangeTimer->property("gpuRunTime") : 0 }
|
||||
});
|
||||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
PROFILE_COUNTER_IF_CHANGED(render, "gpuTime", float, (float)_graphicsEngine.getGPUContext()->getFrameTimerGPUAverage());
|
||||
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
|
||||
|
@ -5223,9 +5092,6 @@ void Application::init() {
|
|||
#if !defined(DISABLE_QML)
|
||||
DependencyManager::get<DialogsManager>()->toggleLoginDialog();
|
||||
#endif
|
||||
if (!DISABLE_DEFERRED) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
}
|
||||
DependencyManager::get<AvatarManager>()->init();
|
||||
|
||||
_timerStart.start();
|
||||
|
@ -5294,7 +5160,7 @@ void Application::init() {
|
|||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _main3DScene, _entitySimulation);
|
||||
_gameWorkload.startup(getEntities()->getWorkloadSpace(), _graphicsEngine.getRenderScene(), _entitySimulation);
|
||||
_entitySimulation->setWorkloadSpace(getEntities()->getWorkloadSpace());
|
||||
}
|
||||
|
||||
|
@ -5328,7 +5194,7 @@ void Application::updateLOD(float deltaTime) const {
|
|||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||
if (!isThrottleRendering()) {
|
||||
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
|
||||
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
|
||||
float engineRunTime = (float)(_graphicsEngine.getRenderEngine()->getConfiguration().get()->getCPURunTime());
|
||||
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
|
||||
float batchTime = getGPUContext()->getFrameTimerBatchAverage();
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
@ -5729,7 +5595,7 @@ void Application::updateSecondaryCameraViewFrustum() {
|
|||
// camera should be.
|
||||
|
||||
// Code based on SecondaryCameraJob
|
||||
auto renderConfig = _renderEngine->getConfiguration();
|
||||
auto renderConfig = _graphicsEngine.getRenderEngine()->getConfiguration();
|
||||
assert(renderConfig);
|
||||
auto camera = dynamic_cast<SecondaryCameraJobConfig*>(renderConfig->getConfig("SecondaryCamera"));
|
||||
|
||||
|
@ -5798,7 +5664,7 @@ void Application::updateSecondaryCameraViewFrustum() {
|
|||
static bool domainLoadingInProgress = false;
|
||||
|
||||
void Application::update(float deltaTime) {
|
||||
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_renderFrameCount + 1);
|
||||
PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_graphicsEngine._renderFrameCount + 1);
|
||||
|
||||
if (_aboutToQuit) {
|
||||
return;
|
||||
|
@ -6214,7 +6080,7 @@ void Application::update(float deltaTime) {
|
|||
// TODO: Fix this by modeling the way the secondary camera works on how the main camera works
|
||||
// ie. Use a camera object stored in the game logic and informs the Engine on where the secondary
|
||||
// camera should be.
|
||||
updateSecondaryCameraViewFrustum();
|
||||
// updateSecondaryCameraViewFrustum();
|
||||
}
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -6290,13 +6156,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
updateRenderArgs(deltaTime);
|
||||
|
||||
// HACK
|
||||
// load the view frustum
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
myAvatar->preDisplaySide(&_appRenderArgs._renderArgs);
|
||||
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("AnimDebugDraw");
|
||||
AnimDebugDraw::getInstance().update();
|
||||
|
@ -6315,7 +6174,7 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateRenderArgs(float deltaTime) {
|
||||
editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
|
||||
_graphicsEngine.editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) {
|
||||
PerformanceTimer perfTimer("editRenderArgs");
|
||||
appRenderArgs._headPose = getHMDSensorPose();
|
||||
|
||||
|
@ -6344,7 +6203,7 @@ void Application::updateRenderArgs(float deltaTime) {
|
|||
_viewFrustum.setProjection(adjustedProjection);
|
||||
_viewFrustum.calculate();
|
||||
}
|
||||
appRenderArgs._renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
||||
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(),
|
||||
lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||
appRenderArgs._renderArgs._scene = getMain3DScene();
|
||||
|
@ -6429,6 +6288,13 @@ void Application::updateRenderArgs(float deltaTime) {
|
|||
QMutexLocker viewLocker(&_viewMutex);
|
||||
appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum);
|
||||
}
|
||||
|
||||
|
||||
// HACK
|
||||
// load the view frustum
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
myAvatar->preDisplaySide(&appRenderArgs._renderArgs);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7033,7 +6899,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
|
||||
|
||||
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Render", _renderEngine->getConfiguration().get());
|
||||
scriptEngine->registerGlobalObject("Render", _graphicsEngine.getRenderEngine()->getConfiguration().get());
|
||||
scriptEngine->registerGlobalObject("Workload", _gameWorkload._engine->getConfiguration().get());
|
||||
|
||||
GraphicsScriptingInterface::registerMetaTypes(scriptEngine.data());
|
||||
|
|
|
@ -70,11 +70,11 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
|
||||
#include "workload/GameWorkload.h"
|
||||
#include "graphics/GraphicsEngine.h"
|
||||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <graphics/Skybox.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
#include "FrameTimingsScriptingInterface.h"
|
||||
|
||||
#include "Sound.h"
|
||||
|
||||
|
@ -153,7 +153,6 @@ public:
|
|||
void updateSecondaryCameraViewFrustum();
|
||||
|
||||
void updateCamera(RenderArgs& renderArgs, float deltaTime);
|
||||
void paintGL();
|
||||
void resizeGL();
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
|
@ -203,8 +202,8 @@ public:
|
|||
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
size_t getRenderFrameCount() const { return _renderFrameCount; }
|
||||
float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
|
||||
size_t getRenderFrameCount() const { return _graphicsEngine.getRenderFrameCount(); }
|
||||
float getRenderLoopRate() const { return _graphicsEngine.getRenderLoopRate(); }
|
||||
float getNumCollisionObjects() const;
|
||||
float getTargetRenderFrameRate() const; // frames/second
|
||||
|
||||
|
@ -275,10 +274,10 @@ public:
|
|||
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
||||
int getMaxOctreePacketsPerSecond() const;
|
||||
|
||||
render::ScenePointer getMain3DScene() override { return _main3DScene; }
|
||||
const render::ScenePointer& getMain3DScene() const { return _main3DScene; }
|
||||
render::EnginePointer getRenderEngine() override { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
render::ScenePointer getMain3DScene() override { return _graphicsEngine.getRenderScene(); }
|
||||
render::EnginePointer getRenderEngine() override { return _graphicsEngine.getRenderEngine(); }
|
||||
gpu::ContextPointer getGPUContext() const { return _graphicsEngine.getGPUContext(); }
|
||||
|
||||
|
||||
const GameWorkload& getGameWorkload() const { return _gameWorkload; }
|
||||
|
||||
|
@ -515,7 +514,6 @@ private:
|
|||
bool handleFileOpenEvent(QFileOpenEvent* event);
|
||||
void cleanupBeforeQuit();
|
||||
|
||||
bool shouldPaint() const;
|
||||
void idle();
|
||||
void update(float deltaTime);
|
||||
|
||||
|
@ -535,8 +533,6 @@ private:
|
|||
|
||||
void initializeAcceptedFiles();
|
||||
|
||||
void runRenderFrame(RenderArgs* renderArgs/*, Camera& whichCamera, bool selfAvatarOnly = false*/);
|
||||
|
||||
bool importJSONFromURL(const QString& urlString);
|
||||
bool importSVOFromURL(const QString& urlString);
|
||||
bool importFromZIP(const QString& filePath);
|
||||
|
@ -586,18 +582,12 @@ private:
|
|||
|
||||
bool _activatingDisplayPlugin { false };
|
||||
|
||||
uint32_t _renderFrameCount { 0 };
|
||||
|
||||
// Frame Rate Measurement
|
||||
RateCounter<500> _renderLoopCounter;
|
||||
RateCounter<500> _gameLoopCounter;
|
||||
|
||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||
|
||||
QTimer _minimizedWindowTimer;
|
||||
QElapsedTimer _timerStart;
|
||||
QElapsedTimer _lastTimeUpdated;
|
||||
QElapsedTimer _lastTimeRendered;
|
||||
|
||||
int _minimumGPUTextureMemSizeStabilityCount { 30 };
|
||||
|
||||
|
@ -683,29 +673,9 @@ private:
|
|||
|
||||
quint64 _lastFaceTrackerUpdate;
|
||||
|
||||
render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
|
||||
render::EnginePointer _renderEngine{ new render::RenderEngine() };
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
|
||||
GameWorkload _gameWorkload;
|
||||
|
||||
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
||||
struct AppRenderArgs {
|
||||
render::Args _renderArgs;
|
||||
glm::mat4 _eyeToWorld;
|
||||
glm::mat4 _view;
|
||||
glm::mat4 _eyeOffsets[2];
|
||||
glm::mat4 _eyeProjections[2];
|
||||
glm::mat4 _headPose;
|
||||
glm::mat4 _sensorToWorld;
|
||||
float _sensorToWorldScale { 1.0f };
|
||||
bool _isStereo{ false };
|
||||
};
|
||||
AppRenderArgs _appRenderArgs;
|
||||
|
||||
|
||||
using RenderArgsEditor = std::function <void (AppRenderArgs&)>;
|
||||
void editRenderArgs(RenderArgsEditor editor);
|
||||
GraphicsEngine _graphicsEngine;
|
||||
void updateRenderArgs(float deltaTime);
|
||||
|
||||
|
||||
|
@ -751,8 +721,6 @@ private:
|
|||
|
||||
bool _keyboardDeviceHasFocus { true };
|
||||
|
||||
QString _returnFromFullScreenMirrorTo;
|
||||
|
||||
ConnectionMonitor _connectionMonitor;
|
||||
|
||||
QTimer _addAssetToWorldResizeTimer;
|
||||
|
@ -786,12 +754,8 @@ private:
|
|||
|
||||
QUrl _avatarOverrideUrl;
|
||||
bool _saveAvatarOverrideUrl { false };
|
||||
QObject* _renderEventHandler{ nullptr };
|
||||
|
||||
friend class RenderEventHandler;
|
||||
|
||||
std::atomic<bool> _pendingIdleEvent { true };
|
||||
std::atomic<bool> _pendingRenderEvent { true };
|
||||
|
||||
bool quitWhenFinished { false };
|
||||
|
||||
|
|
|
@ -19,220 +19,207 @@
|
|||
#include "Util.h"
|
||||
|
||||
|
||||
// Statically provided display and input plugins
|
||||
extern DisplayPluginList getDisplayPlugins();
|
||||
|
||||
void Application::editRenderArgs(RenderArgsEditor editor) {
|
||||
QMutexLocker renderLocker(&_renderArgsMutex);
|
||||
editor(_appRenderArgs);
|
||||
|
||||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
|
||||
_renderFrameCount++;
|
||||
_lastTimeRendered.start();
|
||||
|
||||
auto lastPaintBegin = usecTimestampNow();
|
||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
||||
if (nullptr == _displayPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayPluginPointer displayPlugin;
|
||||
{
|
||||
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||
displayPlugin = getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||
// If a display plugin loses it's underlying support, it
|
||||
// needs to be able to signal us to not use it
|
||||
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
||||
QMetaObject::invokeMethod(this, "updateDisplayMode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderArgs renderArgs;
|
||||
glm::mat4 HMDSensorPose;
|
||||
glm::mat4 eyeToWorld;
|
||||
glm::mat4 sensorToWorld;
|
||||
|
||||
bool isStereo;
|
||||
glm::mat4 stereoEyeOffsets[2];
|
||||
glm::mat4 stereoEyeProjections[2];
|
||||
|
||||
{
|
||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
renderArgs = _appRenderArgs._renderArgs;
|
||||
|
||||
// don't render if there is no context.
|
||||
if (!_appRenderArgs._renderArgs._context) {
|
||||
return;
|
||||
}
|
||||
|
||||
HMDSensorPose = _appRenderArgs._headPose;
|
||||
eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||
sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||
isStereo = _appRenderArgs._isStereo;
|
||||
for_each_eye([&](Eye eye) {
|
||||
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/gpuContextReset");
|
||||
_gpuContext->beginFrame(_appRenderArgs._view, HMDSensorPose);
|
||||
// Reset the gpu::Context Stages
|
||||
// Back to the default framebuffer;
|
||||
gpu::doInBatch("Application_render::gpuContextReset", _gpuContext, [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/renderOverlay");
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
// NOTE: There is no batch associated with this renderArgs
|
||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize());
|
||||
_applicationOverlay.renderOverlay(&renderArgs);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/updateCompositor");
|
||||
getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer finalFramebuffer;
|
||||
QSize finalFramebufferSize;
|
||||
{
|
||||
PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||
// Primary rendering pass
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||
// Final framebuffer that will be handed to the display-plugin
|
||||
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
}
|
||||
|
||||
{
|
||||
if (isStereo) {
|
||||
renderArgs._context->enableStereo(true);
|
||||
renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
}
|
||||
|
||||
renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
runRenderFrame(&renderArgs);
|
||||
}
|
||||
|
||||
auto frame = _gpuContext->endFrame();
|
||||
frame->frameIndex = _renderFrameCount;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
auto frameBufferCache = DependencyManager::get<FramebufferCache>();
|
||||
if (frameBufferCache) {
|
||||
frameBufferCache->releaseFramebuffer(framebuffer);
|
||||
}
|
||||
};
|
||||
// deliver final scene rendering commands to the display plugin
|
||||
{
|
||||
PROFILE_RANGE(render, "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
_renderLoopCounter.increment();
|
||||
displayPlugin->submitFrame(frame);
|
||||
}
|
||||
|
||||
// Reset the framebuffer and stereo state
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
|
||||
#if !defined(DISABLE_QML)
|
||||
{
|
||||
auto stats = Stats::getInstance();
|
||||
if (stats) {
|
||||
stats->setRenderDetails(renderArgs._details);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||
}
|
||||
//void Application::paintGL() {
|
||||
// // Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
//
|
||||
// _renderFrameCount++;
|
||||
// // SG: Moved into the RenderEventHandler
|
||||
// //_lastTimeRendered.start();
|
||||
//
|
||||
// auto lastPaintBegin = usecTimestampNow();
|
||||
// PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
||||
// PerformanceTimer perfTimer("paintGL");
|
||||
//
|
||||
// if (nullptr == _displayPlugin) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// DisplayPluginPointer displayPlugin;
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||
// displayPlugin = getActiveDisplayPlugin();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||
// // If a display plugin loses it's underlying support, it
|
||||
// // needs to be able to signal us to not use it
|
||||
// if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
||||
// QMetaObject::invokeMethod(this, "updateDisplayMode");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// RenderArgs renderArgs;
|
||||
// glm::mat4 HMDSensorPose;
|
||||
// glm::mat4 eyeToWorld;
|
||||
// glm::mat4 sensorToWorld;
|
||||
//
|
||||
// bool isStereo;
|
||||
// glm::mat4 stereoEyeOffsets[2];
|
||||
// glm::mat4 stereoEyeProjections[2];
|
||||
//
|
||||
// {
|
||||
// QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
// renderArgs = _appRenderArgs._renderArgs;
|
||||
//
|
||||
// // don't render if there is no context.
|
||||
// if (!_appRenderArgs._renderArgs._context) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// HMDSensorPose = _appRenderArgs._headPose;
|
||||
// eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||
// sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||
// isStereo = _appRenderArgs._isStereo;
|
||||
// for_each_eye([&](Eye eye) {
|
||||
// stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||
// stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/gpuContextReset");
|
||||
// _graphicsEngine.getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose);
|
||||
// // Reset the gpu::Context Stages
|
||||
// // Back to the default framebuffer;
|
||||
// gpu::doInBatch("Application_render::gpuContextReset", _graphicsEngine.getGPUContext(), [&](gpu::Batch& batch) {
|
||||
// batch.resetStages();
|
||||
// });
|
||||
// }
|
||||
//
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/renderOverlay");
|
||||
// PerformanceTimer perfTimer("renderOverlay");
|
||||
// // NOTE: There is no batch associated with this renderArgs
|
||||
// // the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
// renderArgs._viewport = glm::ivec4(0, 0, getDeviceSize() * getRenderResolutionScale());
|
||||
// _applicationOverlay.renderOverlay(&renderArgs);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/updateCompositor");
|
||||
// getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
// }
|
||||
//
|
||||
// gpu::FramebufferPointer finalFramebuffer;
|
||||
// QSize finalFramebufferSize;
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||
// // Primary rendering pass
|
||||
// auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
// finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||
// // Final framebuffer that will be handled to the display-plugin
|
||||
// finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// if (isStereo) {
|
||||
// renderArgs._context->enableStereo(true);
|
||||
// renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
// renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
// }
|
||||
//
|
||||
// renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
// renderArgs._hudTexture = _applicationOverlay.getOverlayTexture();
|
||||
// renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
// _graphicsEngine.render_runRenderFrame(&renderArgs);
|
||||
// }
|
||||
//
|
||||
// auto frame = _graphicsEngine.getGPUContext()->endFrame();
|
||||
// frame->frameIndex = _renderFrameCount;
|
||||
// frame->framebuffer = finalFramebuffer;
|
||||
// frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
// auto frameBufferCache = DependencyManager::get<FramebufferCache>();
|
||||
// if (frameBufferCache) {
|
||||
// frameBufferCache->releaseFramebuffer(framebuffer);
|
||||
// }
|
||||
// };
|
||||
// // deliver final scene rendering commands to the display plugin
|
||||
// {
|
||||
// PROFILE_RANGE(render, "/pluginOutput");
|
||||
// PerformanceTimer perfTimer("pluginOutput");
|
||||
// _renderLoopCounter.increment();
|
||||
// displayPlugin->submitFrame(frame);
|
||||
// }
|
||||
//
|
||||
// // Reset the framebuffer and stereo state
|
||||
// renderArgs._blitFramebuffer.reset();
|
||||
// renderArgs._context->enableStereo(false);
|
||||
//
|
||||
// {
|
||||
// Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||
// }
|
||||
//
|
||||
// uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||
// _frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||
//}
|
||||
|
||||
|
||||
// WorldBox Render Data & rendering functions
|
||||
|
||||
class WorldBoxRenderData {
|
||||
public:
|
||||
typedef render::Payload<WorldBoxRenderData> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
int _val = 0;
|
||||
static render::ItemID _item; // unique WorldBoxRenderData
|
||||
};
|
||||
|
||||
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
|
||||
auto& batch = *args->_batch;
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||
renderWorldBox(args, batch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::runRenderFrame(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
PerformanceTimer perfTimer("display");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
|
||||
|
||||
// The pending changes collecting the changes here
|
||||
render::Transaction transaction;
|
||||
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
// render models...
|
||||
PerformanceTimer perfTimer("entities");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::runRenderFrame() ... entities...");
|
||||
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
|
||||
renderArgs->_debugFlags = renderDebugFlags;
|
||||
}
|
||||
|
||||
// Make sure the WorldBox is in the scene
|
||||
// For the record, this one RenderItem is the first one we created and added to the scene.
|
||||
// We could move that code elsewhere but you know...
|
||||
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
|
||||
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||
|
||||
WorldBoxRenderData::_item = _main3DScene->allocateID();
|
||||
|
||||
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||
_main3DScene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("EngineRun");
|
||||
_renderEngine->getRenderContext()->args = renderArgs;
|
||||
_renderEngine->run();
|
||||
}
|
||||
}
|
||||
//
|
||||
//class WorldBoxRenderData {
|
||||
//public:
|
||||
// typedef render::Payload<WorldBoxRenderData> Payload;
|
||||
// typedef Payload::DataPointer Pointer;
|
||||
//
|
||||
// int _val = 0;
|
||||
// static render::ItemID _item; // unique WorldBoxRenderData
|
||||
//};
|
||||
//
|
||||
//render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||
//
|
||||
//namespace render {
|
||||
// template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
// template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
// template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
// if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
// PerformanceTimer perfTimer("worldBox");
|
||||
//
|
||||
// auto& batch = *args->_batch;
|
||||
// DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||
// renderWorldBox(args, batch);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void Application::runRenderFrame(RenderArgs* renderArgs) {
|
||||
// PROFILE_RANGE(render, __FUNCTION__);
|
||||
// PerformanceTimer perfTimer("display");
|
||||
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
|
||||
//
|
||||
// // The pending changes collecting the changes here
|
||||
// render::Transaction transaction;
|
||||
//
|
||||
// if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
// // render models...
|
||||
// PerformanceTimer perfTimer("entities");
|
||||
// PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
// "Application::runRenderFrame() ... entities...");
|
||||
//
|
||||
// RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||
//
|
||||
// renderArgs->_debugFlags = renderDebugFlags;
|
||||
// }
|
||||
//
|
||||
// // Make sure the WorldBox is in the scene
|
||||
// // For the record, this one RenderItem is the first one we created and added to the scene.
|
||||
// // We could move that code elsewhere but you know...
|
||||
// if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||
// auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
|
||||
// auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||
//
|
||||
// WorldBoxRenderData::_item = _main3DScene->allocateID();
|
||||
//
|
||||
// transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||
// _main3DScene->enqueueTransaction(transaction);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// PerformanceTimer perfTimer("EngineRun");
|
||||
// _renderEngine->getRenderContext()->args = renderArgs;
|
||||
// _renderEngine->run();
|
||||
// }
|
||||
//}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ void SecondaryCameraJobConfig::setOrientation(glm::quat orient) {
|
|||
}
|
||||
|
||||
void SecondaryCameraJobConfig::enableSecondaryCameraRenderConfigs(bool enabled) {
|
||||
qApp->getRenderEngine()->getConfiguration()->getConfig<SecondaryCameraRenderTask>()->setEnabled(enabled);
|
||||
qApp->getRenderEngine()->getConfiguration()->getConfig<SecondaryCameraRenderTask>("SecondaryCameraJob")->setEnabled(enabled);
|
||||
setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
@ -187,11 +187,13 @@ public:
|
|||
|
||||
void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) {
|
||||
auto args = renderContext->args;
|
||||
if (cachedArgs) {
|
||||
args->_blitFramebuffer = cachedArgs->_blitFramebuffer;
|
||||
args->_viewport = cachedArgs->_viewport;
|
||||
args->popViewFrustum();
|
||||
args->_displayMode = cachedArgs->_displayMode;
|
||||
args->_renderMode = cachedArgs->_renderMode;
|
||||
}
|
||||
args->popViewFrustum();
|
||||
|
||||
gpu::doInBatch("EndSecondaryCameraFrame::run", args->_context, [&](gpu::Batch& batch) {
|
||||
batch.restoreContextStereo();
|
||||
|
|
|
@ -36,114 +36,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
void renderWorldBox(RenderArgs* args, gpu::Batch& batch) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// Show center of world
|
||||
static const glm::vec3 RED(1.0f, 0.0f, 0.0f);
|
||||
static const glm::vec3 GREEN(0.0f, 1.0f, 0.0f);
|
||||
static const glm::vec3 BLUE(0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec3 GREY(0.5f, 0.5f, 0.5f);
|
||||
static const glm::vec4 GREY4(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
static const glm::vec4 DASHED_RED(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec4 DASHED_GREEN(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
static const glm::vec4 DASHED_BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
static const float DASH_LENGTH = 1.0f;
|
||||
static const float GAP_LENGTH = 1.0f;
|
||||
auto transform = Transform{};
|
||||
static std::array<int, 18> geometryIds;
|
||||
static std::once_flag initGeometryIds;
|
||||
std::call_once(initGeometryIds, [&] {
|
||||
for (size_t i = 0; i < geometryIds.size(); ++i) {
|
||||
geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
});
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED, geometryIds[0]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-HALF_TREE_SCALE, 0.0f, 0.0f), DASHED_RED,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[1]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN, geometryIds[2]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -HALF_TREE_SCALE, 0.0f), DASHED_GREEN,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[3]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE, geometryIds[4]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -HALF_TREE_SCALE), DASHED_BLUE,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[5]);
|
||||
|
||||
// X center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[6]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[7]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[8]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[9]);
|
||||
|
||||
// Z center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[10]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[11]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[12]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[13]);
|
||||
|
||||
// Center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[14]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[15]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[16]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[17]);
|
||||
|
||||
|
||||
geometryCache->renderWireCubeInstance(args, batch, GREY4);
|
||||
|
||||
// Draw meter markers along the 3 axis to help with measuring things
|
||||
const float MARKER_DISTANCE = 1.0f;
|
||||
const float MARKER_RADIUS = 0.05f;
|
||||
|
||||
transform = Transform().setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, RED);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, RED);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, GREEN);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, BLUE);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, GREY);
|
||||
}
|
||||
|
||||
// Do some basic timing tests and report the results
|
||||
void runTimingTests() {
|
||||
// How long does it take to make a call to get the time?
|
||||
|
|
|
@ -15,14 +15,9 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <render/Forward.h>
|
||||
|
||||
class ShapeEntityItem;
|
||||
class ShapeInfo;
|
||||
|
||||
void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
|
||||
|
||||
void runTimingTests();
|
||||
void runUnitTests();
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD),
|
||||
_avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0)
|
||||
{
|
||||
_clientTraitsHandler = std::unique_ptr<ClientTraitsHandler>(new ClientTraitsHandler(this));
|
||||
_clientTraitsHandler.reset(new ClientTraitsHandler(this));
|
||||
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = new MyHead(this);
|
||||
|
|
301
interface/src/graphics/GraphicsEngine.cpp
Normal file
301
interface/src/graphics/GraphicsEngine.cpp
Normal file
|
@ -0,0 +1,301 @@
|
|||
//
|
||||
// GraphicsEngine.cpp
|
||||
//
|
||||
// Created by Sam Gateau on 29/6/2018.
|
||||
// Copyright 2018 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 "GraphicsEngine.h"
|
||||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
|
||||
#include "WorldBox.h"
|
||||
#include "LODManager.h"
|
||||
|
||||
#include <GeometryCache.h>
|
||||
#include <TextureCache.h>
|
||||
#include <FramebufferCache.h>
|
||||
#include <UpdateSceneTask.h>
|
||||
#include <RenderViewTask.h>
|
||||
#include <SecondaryCamera.h>
|
||||
|
||||
#include "RenderEventHandler.h"
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <QMetaObject>
|
||||
#include "ui/Stats.h"
|
||||
#include "Application.h"
|
||||
|
||||
GraphicsEngine::GraphicsEngine() {
|
||||
}
|
||||
|
||||
GraphicsEngine::~GraphicsEngine() {
|
||||
}
|
||||
|
||||
void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
|
||||
|
||||
_renderEventHandler = new RenderEventHandler(
|
||||
[this]() { return this->shouldPaint(); },
|
||||
[this]() { this->render_performFrame(); }
|
||||
);
|
||||
|
||||
// Requires the window context, because that's what's used in the actual rendering
|
||||
// and the GPU backend will make things like the VAO which cannot be shared across
|
||||
// contexts
|
||||
glwidget->makeCurrent();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
glwidget->makeCurrent();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
|
||||
}
|
||||
|
||||
void GraphicsEngine::initializeRender(bool disableDeferred) {
|
||||
|
||||
// Set up the render engine
|
||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
|
||||
#ifndef Q_OS_ANDROID
|
||||
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !disableDeferred);
|
||||
#endif
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !disableDeferred, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_renderScene);
|
||||
|
||||
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
|
||||
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
|
||||
}
|
||||
|
||||
void GraphicsEngine::startup() {
|
||||
static_cast<RenderEventHandler*>(_renderEventHandler)->resumeThread();
|
||||
}
|
||||
|
||||
void GraphicsEngine::shutdown() {
|
||||
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
|
||||
// removal of the items.
|
||||
// See https://highfidelity.fogbugz.com/f/cases/5328
|
||||
_renderScene->enqueueFrame(); // flush all the transactions
|
||||
_renderScene->processTransactionQueue(); // process and apply deletions
|
||||
|
||||
_gpuContext->shutdown();
|
||||
|
||||
|
||||
// shutdown render engine
|
||||
_renderScene = nullptr;
|
||||
_renderEngine = nullptr;
|
||||
|
||||
_renderEventHandler->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void GraphicsEngine::render_runRenderFrame(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
PerformanceTimer perfTimer("render");
|
||||
|
||||
// Make sure the WorldBox is in the scene
|
||||
// For the record, this one RenderItem is the first one we created and added to the scene.
|
||||
// We could move that code elsewhere but you know...
|
||||
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||
render::Transaction transaction;
|
||||
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
|
||||
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||
|
||||
WorldBoxRenderData::_item = _renderScene->allocateID();
|
||||
|
||||
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||
_renderScene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
{
|
||||
_renderEngine->getRenderContext()->args = renderArgs;
|
||||
_renderEngine->run();
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
||||
|
||||
|
||||
|
||||
bool GraphicsEngine::shouldPaint() const {
|
||||
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
|
||||
#ifdef DEBUG_PAINT_DELAY
|
||||
static uint64_t paintDelaySamples{ 0 };
|
||||
static uint64_t paintDelayUsecs{ 0 };
|
||||
|
||||
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
|
||||
|
||||
static const int PAINT_DELAY_THROTTLE = 1000;
|
||||
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
|
||||
qCDebug(interfaceapp).nospace() <<
|
||||
"Paint delay (" << paintDelaySamples << " samples): " <<
|
||||
(float)paintDelaySamples / paintDelayUsecs << "us";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throttle if requested
|
||||
//if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
if ( displayPlugin->isThrottled() &&
|
||||
(static_cast<RenderEventHandler*>(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GraphicsEngine::checkPendingRenderEvent() {
|
||||
bool expected = false;
|
||||
return (_renderEventHandler && static_cast<RenderEventHandler*>(_renderEventHandler)->_pendingRenderEvent.compare_exchange_strong(expected, true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GraphicsEngine::render_performFrame() {
|
||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||
|
||||
_renderFrameCount++;
|
||||
|
||||
auto lastPaintBegin = usecTimestampNow();
|
||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
||||
DisplayPluginPointer displayPlugin;
|
||||
{
|
||||
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||
displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||
// If a display plugin loses it's underlying support, it
|
||||
// needs to be able to signal us to not use it
|
||||
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
||||
QMetaObject::invokeMethod(qApp, "updateDisplayMode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderArgs renderArgs;
|
||||
glm::mat4 HMDSensorPose;
|
||||
glm::mat4 eyeToWorld;
|
||||
glm::mat4 sensorToWorld;
|
||||
|
||||
bool isStereo;
|
||||
glm::mat4 stereoEyeOffsets[2];
|
||||
glm::mat4 stereoEyeProjections[2];
|
||||
|
||||
{
|
||||
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||
renderArgs = _appRenderArgs._renderArgs;
|
||||
|
||||
// don't render if there is no context.
|
||||
if (!_appRenderArgs._renderArgs._context) {
|
||||
return;
|
||||
}
|
||||
|
||||
HMDSensorPose = _appRenderArgs._headPose;
|
||||
eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||
sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||
isStereo = _appRenderArgs._isStereo;
|
||||
for_each_eye([&](Eye eye) {
|
||||
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/gpuContextReset");
|
||||
getGPUContext()->beginFrame(_appRenderArgs._view, HMDSensorPose);
|
||||
// Reset the gpu::Context Stages
|
||||
// Back to the default framebuffer;
|
||||
gpu::doInBatch("Application_render::gpuContextReset", getGPUContext(), [&](gpu::Batch& batch) {
|
||||
batch.resetStages();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/renderOverlay");
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
// NOTE: There is no batch associated with this renderArgs
|
||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||
renderArgs._viewport = glm::ivec4(0, 0, qApp->getDeviceSize());
|
||||
qApp->getApplicationOverlay().renderOverlay(&renderArgs);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render, "/updateCompositor");
|
||||
qApp->getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer finalFramebuffer;
|
||||
QSize finalFramebufferSize;
|
||||
{
|
||||
PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||
// Primary rendering pass
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||
// Final framebuffer that will be handled to the display-plugin
|
||||
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||
}
|
||||
|
||||
{
|
||||
if (isStereo) {
|
||||
renderArgs._context->enableStereo(true);
|
||||
renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||
}
|
||||
|
||||
renderArgs._hudOperator = displayPlugin->getHUDOperator();
|
||||
renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture();
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
render_runRenderFrame(&renderArgs);
|
||||
}
|
||||
|
||||
auto frame = getGPUContext()->endFrame();
|
||||
frame->frameIndex = _renderFrameCount;
|
||||
frame->framebuffer = finalFramebuffer;
|
||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||
auto frameBufferCache = DependencyManager::get<FramebufferCache>();
|
||||
if (frameBufferCache) {
|
||||
frameBufferCache->releaseFramebuffer(framebuffer);
|
||||
}
|
||||
};
|
||||
// deliver final scene rendering commands to the display plugin
|
||||
{
|
||||
PROFILE_RANGE(render, "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
_renderLoopCounter.increment();
|
||||
displayPlugin->submitFrame(frame);
|
||||
}
|
||||
|
||||
// Reset the framebuffer and stereo state
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
|
||||
{
|
||||
auto stats = Stats::getInstance();
|
||||
if (stats) {
|
||||
stats->setRenderDetails(renderArgs._details);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||
}
|
||||
|
||||
|
||||
void GraphicsEngine::editRenderArgs(RenderArgsEditor editor) {
|
||||
QMutexLocker renderLocker(&_renderArgsMutex);
|
||||
editor(_appRenderArgs);
|
||||
}
|
90
interface/src/graphics/GraphicsEngine.h
Normal file
90
interface/src/graphics/GraphicsEngine.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// GraphicsEngine.h
|
||||
//
|
||||
// Created by Sam Gateau on 29/6/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_GraphicsEngine_h
|
||||
#define hifi_GraphicsEngine_h
|
||||
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <qmutex.h>
|
||||
|
||||
#include <render/Engine.h>
|
||||
|
||||
#include <OctreeConstants.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
#include "FrameTimingsScriptingInterface.h"
|
||||
|
||||
|
||||
struct AppRenderArgs {
|
||||
render::Args _renderArgs;
|
||||
glm::mat4 _eyeToWorld;
|
||||
glm::mat4 _view;
|
||||
glm::mat4 _eyeOffsets[2];
|
||||
glm::mat4 _eyeProjections[2];
|
||||
glm::mat4 _headPose;
|
||||
glm::mat4 _sensorToWorld;
|
||||
float _sensorToWorldScale{ 1.0f };
|
||||
bool _isStereo{ false };
|
||||
};
|
||||
|
||||
using RenderArgsEditor = std::function <void(AppRenderArgs&)>;
|
||||
|
||||
|
||||
class GraphicsEngine {
|
||||
public:
|
||||
GraphicsEngine();
|
||||
~GraphicsEngine();
|
||||
|
||||
void initializeGPU(GLWidget*);
|
||||
void initializeRender(bool disableDeferred);
|
||||
void startup();
|
||||
void shutdown();
|
||||
|
||||
render::ScenePointer getRenderScene() const { return _renderScene; }
|
||||
render::EnginePointer getRenderEngine() const { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
|
||||
// Same as the one in application
|
||||
bool shouldPaint() const;
|
||||
bool checkPendingRenderEvent();
|
||||
|
||||
size_t getRenderFrameCount() const { return _renderFrameCount; }
|
||||
float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
|
||||
|
||||
// Feed GRaphics Engine with new frame configuration
|
||||
void editRenderArgs(RenderArgsEditor editor);
|
||||
|
||||
private:
|
||||
// Thread specific calls
|
||||
void render_performFrame();
|
||||
void render_runRenderFrame(RenderArgs* renderArgs);
|
||||
|
||||
protected:
|
||||
|
||||
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
||||
AppRenderArgs _appRenderArgs;
|
||||
|
||||
RateCounter<500> _renderLoopCounter;
|
||||
|
||||
uint32_t _renderFrameCount{ 0 };
|
||||
render::ScenePointer _renderScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
|
||||
render::EnginePointer _renderEngine{ new render::RenderEngine() };
|
||||
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
|
||||
QObject* _renderEventHandler{ nullptr };
|
||||
friend class RenderEventHandler;
|
||||
|
||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||
|
||||
friend class Application;
|
||||
};
|
||||
|
||||
#endif // hifi_GraphicsEngine_h
|
58
interface/src/graphics/RenderEventHandler.cpp
Normal file
58
interface/src/graphics/RenderEventHandler.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// RenderEventHandler.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 29/6/2018.
|
||||
// Copyright 2018 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 "RenderEventHandler.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
|
||||
#include "CrashHandler.h"
|
||||
|
||||
RenderEventHandler::RenderEventHandler(CheckCall checkCall, RenderCall renderCall) :
|
||||
_checkCall(checkCall),
|
||||
_renderCall(renderCall)
|
||||
{
|
||||
// Transfer to a new thread
|
||||
moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) {
|
||||
hifi::qt::addBlockingForbiddenThread("Render", renderThread);
|
||||
_lastTimeRendered.start();
|
||||
}, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority);
|
||||
}
|
||||
|
||||
void RenderEventHandler::initialize() {
|
||||
setObjectName("Render");
|
||||
PROFILE_SET_THREAD_NAME("Render");
|
||||
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
|
||||
}
|
||||
|
||||
void RenderEventHandler::resumeThread() {
|
||||
_pendingRenderEvent = false;
|
||||
}
|
||||
|
||||
void RenderEventHandler::render() {
|
||||
if (_checkCall()) {
|
||||
_lastTimeRendered.start();
|
||||
_renderCall();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderEventHandler::event(QEvent* event) {
|
||||
switch ((int)event->type()) {
|
||||
case ApplicationEvent::Render:
|
||||
render();
|
||||
_pendingRenderEvent.store(false);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Parent::event(event);
|
||||
}
|
||||
|
52
interface/src/graphics/RenderEventHandler.h
Normal file
52
interface/src/graphics/RenderEventHandler.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// RenderEventHandler.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 29/6/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_RenderEventHandler_h
|
||||
#define hifi_RenderEventHandler_h
|
||||
|
||||
#include <QEvent>
|
||||
#include <QElapsedTimer>
|
||||
#include "gl/OffscreenGLCanvas.h"
|
||||
|
||||
enum ApplicationEvent {
|
||||
// Execute a lambda function
|
||||
Lambda = QEvent::User + 1,
|
||||
// Trigger the next render
|
||||
Render,
|
||||
// Trigger the next idle
|
||||
Idle,
|
||||
};
|
||||
|
||||
class RenderEventHandler : public QObject {
|
||||
using Parent = QObject;
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
using CheckCall = std::function <bool()>;
|
||||
using RenderCall = std::function <void()>;
|
||||
|
||||
CheckCall _checkCall;
|
||||
RenderCall _renderCall;
|
||||
|
||||
RenderEventHandler(CheckCall checkCall, RenderCall renderCall);
|
||||
|
||||
QElapsedTimer _lastTimeRendered;
|
||||
std::atomic<bool> _pendingRenderEvent{ true };
|
||||
|
||||
void resumeThread();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
void render();
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
};
|
||||
|
||||
#endif // #include hifi_RenderEventHandler_h
|
138
interface/src/graphics/WorldBox.cpp
Normal file
138
interface/src/graphics/WorldBox.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// WorldBox.cpp
|
||||
//
|
||||
// Created by Sam Gateau on 01/07/2018.
|
||||
// Copyright 2018 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 "WorldBox.h"
|
||||
|
||||
#include "OctreeConstants.h"
|
||||
|
||||
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
|
||||
auto& batch = *args->_batch;
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||
WorldBoxRenderData::renderWorldBox(args, batch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldBoxRenderData::renderWorldBox(RenderArgs* args, gpu::Batch& batch) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// Show center of world
|
||||
static const glm::vec3 RED(1.0f, 0.0f, 0.0f);
|
||||
static const glm::vec3 GREEN(0.0f, 1.0f, 0.0f);
|
||||
static const glm::vec3 BLUE(0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec3 GREY(0.5f, 0.5f, 0.5f);
|
||||
static const glm::vec4 GREY4(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
static const glm::vec4 DASHED_RED(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec4 DASHED_GREEN(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
static const glm::vec4 DASHED_BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
static const float DASH_LENGTH = 1.0f;
|
||||
static const float GAP_LENGTH = 1.0f;
|
||||
auto transform = Transform{};
|
||||
static std::array<int, 18> geometryIds;
|
||||
static std::once_flag initGeometryIds;
|
||||
std::call_once(initGeometryIds, [&] {
|
||||
for (size_t i = 0; i < geometryIds.size(); ++i) {
|
||||
geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
});
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED, geometryIds[0]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-HALF_TREE_SCALE, 0.0f, 0.0f), DASHED_RED,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[1]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN, geometryIds[2]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -HALF_TREE_SCALE, 0.0f), DASHED_GREEN,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[3]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE, geometryIds[4]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -HALF_TREE_SCALE), DASHED_BLUE,
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[5]);
|
||||
|
||||
// X center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[6]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[7]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[8]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[9]);
|
||||
|
||||
// Z center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[10]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[11]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[12]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[13]);
|
||||
|
||||
// Center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[14]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[15]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[16]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[17]);
|
||||
|
||||
|
||||
geometryCache->renderWireCubeInstance(args, batch, GREY4);
|
||||
|
||||
// Draw meter markers along the 3 axis to help with measuring things
|
||||
const float MARKER_DISTANCE = 1.0f;
|
||||
const float MARKER_RADIUS = 0.05f;
|
||||
|
||||
transform = Transform().setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, RED);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, RED);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, GREEN);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, BLUE);
|
||||
|
||||
transform = Transform().setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE)).setScale(MARKER_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(args, batch, GREY);
|
||||
}
|
||||
|
43
interface/src/graphics/WorldBox.h
Normal file
43
interface/src/graphics/WorldBox.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// WorldBox.h
|
||||
//
|
||||
// Created by Sam Gateau on 01/07/2018.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_WorldBox_h
|
||||
#define hifi_WorldBox_h
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <render/Forward.h>
|
||||
|
||||
#include <render/Item.h>
|
||||
#include <GeometryCache.h>
|
||||
#include "Menu.h"
|
||||
|
||||
|
||||
|
||||
class WorldBoxRenderData {
|
||||
public:
|
||||
typedef render::Payload<WorldBoxRenderData> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
int _val = 0;
|
||||
static render::ItemID _item; // unique WorldBoxRenderData
|
||||
|
||||
|
||||
|
||||
static void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff);
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args);
|
||||
}
|
||||
|
||||
#endif // hifi_WorldBox_h
|
|
@ -55,8 +55,6 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
|
||||
buildFramebufferObject();
|
||||
|
||||
if (!_overlayFramebuffer) {
|
||||
|
|
|
@ -1490,7 +1490,7 @@ protected:
|
|||
bool _isClientAvatar { false };
|
||||
|
||||
// null unless MyAvatar or ScriptableAvatar sending traits data to mixer
|
||||
std::unique_ptr<ClientTraitsHandler> _clientTraitsHandler;
|
||||
std::unique_ptr<ClientTraitsHandler, LaterDeleter> _clientTraitsHandler;
|
||||
|
||||
template <typename T, typename F>
|
||||
T readLockWithNamedJointIndex(const QString& name, const T& defaultValue, F f) const {
|
||||
|
|
|
@ -22,7 +22,7 @@ ClientTraitsHandler::ClientTraitsHandler(AvatarData* owningAvatar) :
|
|||
_owningAvatar(owningAvatar)
|
||||
{
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QObject::connect(nodeList.data(), &NodeList::nodeAdded, [this](SharedNodePointer addedNode){
|
||||
QObject::connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer addedNode) {
|
||||
if (addedNode->getType() == NodeType::AvatarMixer) {
|
||||
resetForNewMixer();
|
||||
}
|
||||
|
|
|
@ -180,9 +180,7 @@ void Deck::processFrames() {
|
|||
#ifdef WANT_RECORDING_DEBUG
|
||||
qCDebug(recordingLog) << "Setting timer for next processing " << nextInterval;
|
||||
#endif
|
||||
_timer.singleShot(nextInterval, [this] {
|
||||
processFrames();
|
||||
});
|
||||
_timer.singleShot(nextInterval, this, &Deck::processFrames);
|
||||
}
|
||||
|
||||
void Deck::removeClip(const ClipConstPointer& clip) {
|
||||
|
|
|
@ -303,7 +303,7 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
|
|||
}
|
||||
|
||||
void AmbientOcclusionEffect::configure(const Config& config) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
|
||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.isEnabled());
|
||||
|
||||
bool shouldUpdateBlurs = false;
|
||||
bool shouldUpdateTechnique = false;
|
||||
|
|
|
@ -78,7 +78,6 @@ using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFrame
|
|||
|
||||
class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool horizonBased MEMBER horizonBased NOTIFY dirty)
|
||||
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
|
||||
|
|
|
@ -282,7 +282,7 @@ void BloomEffect::configure(const Config& config) {
|
|||
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
|
||||
blurName.back() = '0' + i;
|
||||
auto blurConfig = config.getConfig<render::BlurGaussian>(blurName);
|
||||
blurConfig->setProperty("filterScale", 1.0f);
|
||||
blurConfig->filterScale = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
class DebugDeferredBufferConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
Q_PROPERTY(int mode MEMBER mode WRITE setMode)
|
||||
Q_PROPERTY(glm::vec4 size MEMBER size NOTIFY dirty)
|
||||
public:
|
||||
|
|
|
@ -606,11 +606,16 @@ void RenderDeferredCleanup::run(const render::RenderContextPointer& renderContex
|
|||
}
|
||||
}
|
||||
|
||||
RenderDeferred::RenderDeferred(bool renderShadows):
|
||||
_renderShadows(renderShadows)
|
||||
{
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
}
|
||||
|
||||
void RenderDeferred::configure(const Config& config) {
|
||||
}
|
||||
|
||||
void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
PROFILE_RANGE(render, "DeferredLighting");
|
||||
|
||||
auto deferredTransform = inputs.get0();
|
||||
auto deferredFramebuffer = inputs.get1();
|
||||
|
|
|
@ -189,8 +189,7 @@ public:
|
|||
using Config = RenderDeferredConfig;
|
||||
using JobModel = render::Job::ModelI<RenderDeferred, Inputs, Config>;
|
||||
|
||||
RenderDeferred() {}
|
||||
RenderDeferred(bool renderShadows) : _renderShadows(renderShadows) {}
|
||||
RenderDeferred(bool renderShadows = false);
|
||||
|
||||
void configure(const Config& config);
|
||||
|
||||
|
|
|
@ -444,10 +444,12 @@ LightStageSetup::LightStageSetup() {
|
|||
}
|
||||
|
||||
void LightStageSetup::run(const render::RenderContextPointer& renderContext) {
|
||||
auto stage = renderContext->_scene->getStage(LightStage::getName());
|
||||
if (!stage) {
|
||||
stage = std::make_shared<LightStage>();
|
||||
renderContext->_scene->resetStage(LightStage::getName(), stage);
|
||||
if (renderContext->_scene) {
|
||||
auto stage = renderContext->_scene->getStage(LightStage::getName());
|
||||
if (!stage) {
|
||||
stage = std::make_shared<LightStage>();
|
||||
renderContext->_scene->resetStage(LightStage::getName(), stage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ using namespace render;
|
|||
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
|
||||
|
||||
void RenderShadowTask::configure(const Config& configuration) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);
|
||||
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.isEnabled());
|
||||
// This is a task, so must still propogate configure() to its Jobs
|
||||
// Task::configure(configuration);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ protected:
|
|||
|
||||
class RenderShadowTaskConfig : public render::Task::Config::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
public:
|
||||
RenderShadowTaskConfig() : render::Task::Config::Persistent(QStringList() << "Render" << "Engine" << "Shadows", true) {}
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ private:
|
|||
|
||||
class ToneMappingConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure);
|
||||
Q_PROPERTY(int curve MEMBER curve WRITE setCurve);
|
||||
public:
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
namespace render {
|
||||
class DrawSceneOctreeConfig : public Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
|
||||
Q_PROPERTY(bool showVisibleCells READ getShowVisibleCells WRITE setShowVisibleCells NOTIFY dirty())
|
||||
Q_PROPERTY(bool showEmptyCells READ getShowEmptyCells WRITE setShowEmptyCells NOTIFY dirty())
|
||||
Q_PROPERTY(int numAllocatedCells READ getNumAllocatedCells)
|
||||
|
@ -77,7 +76,6 @@ namespace render {
|
|||
|
||||
class DrawItemSelectionConfig : public Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty())
|
||||
Q_PROPERTY(bool showInsideItems READ getShowInsideItems WRITE setShowInsideItems NOTIFY dirty())
|
||||
Q_PROPERTY(bool showInsideSubcellItems READ getShowInsideSubcellItems WRITE setShowInsideSubcellItems NOTIFY dirty())
|
||||
Q_PROPERTY(bool showPartialItems READ getShowPartialItems WRITE setShowPartialItems NOTIFY dirty())
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
using namespace render;
|
||||
|
||||
void DrawStatusConfig::dirtyHelper() {
|
||||
enabled = showNetwork || showDisplay;
|
||||
_isEnabled = showNetwork || showDisplay;
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,13 @@ void doEvery(quint64& lastReportUsecs, quint64 secs, F lamdba) {
|
|||
// Maximum accuracy in msecs
|
||||
float secTimestampNow();
|
||||
|
||||
// Custom deleter for QObjects that calls deleteLater
|
||||
struct LaterDeleter {
|
||||
void operator()(QObject* ptr) {
|
||||
ptr->deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
float randFloat();
|
||||
int randIntInRange (int min, int max);
|
||||
float randFloatInRange (float min,float max);
|
||||
|
|
|
@ -18,6 +18,17 @@
|
|||
|
||||
using namespace task;
|
||||
|
||||
JobConfig::~JobConfig() {
|
||||
|
||||
}
|
||||
|
||||
void JobConfig::setEnabled(bool enable) {
|
||||
if (_isEnabled != enable) {
|
||||
_isEnabled = enable;
|
||||
emit dirtyEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void JobConfig::setPresetList(const QJsonObject& object) {
|
||||
for (auto it = object.begin(); it != object.end(); it++) {
|
||||
JobConfig* child = findChild<JobConfig*>(it.key(), Qt::FindDirectChildrenOnly);
|
||||
|
@ -68,3 +79,57 @@ void TaskConfig::refresh() {
|
|||
_task->applyConfiguration();
|
||||
}
|
||||
|
||||
TaskConfig* TaskConfig::getRootConfig(const std::string& jobPath, std::string& jobName) const {
|
||||
TaskConfig* root = const_cast<TaskConfig*> (this);
|
||||
|
||||
std::list<std::string> tokens;
|
||||
std::size_t pos = 0, sepPos;
|
||||
while ((sepPos = jobPath.find_first_of('.', pos)) != std::string::npos) {
|
||||
std::string token = jobPath.substr(pos, sepPos - pos);
|
||||
if (!token.empty()) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
pos = sepPos + 1;
|
||||
}
|
||||
{
|
||||
std::string token = jobPath.substr(pos, sepPos - pos);
|
||||
if (!token.empty()) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.empty()) {
|
||||
return root;
|
||||
}
|
||||
else {
|
||||
while (tokens.size() > 1) {
|
||||
auto taskName = tokens.front();
|
||||
tokens.pop_front();
|
||||
root = root->findChild<TaskConfig*>((taskName.empty() ? QString() : QString(taskName.c_str())));
|
||||
if (!root) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
jobName = tokens.front();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
JobConfig* TaskConfig::getJobConfig(const std::string& jobPath) const {
|
||||
std::string jobName;
|
||||
auto root = getRootConfig(jobPath, jobName);
|
||||
|
||||
if (!root) {
|
||||
return nullptr;
|
||||
}
|
||||
if (jobName.empty()) {
|
||||
return root;
|
||||
} else {
|
||||
|
||||
auto found = root->findChild<JobConfig*>((jobName.empty() ? QString() : QString(jobName.c_str())));
|
||||
if (!found) {
|
||||
return nullptr;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,12 +50,10 @@ public:
|
|||
_default = toJsonValue(*this).toObject().toVariantMap();
|
||||
|
||||
_presets.unite(list.toVariantMap());
|
||||
if (C::alwaysEnabled || C::enabled) {
|
||||
if (C::isEnabled()) {
|
||||
_presets.insert(DEFAULT, _default);
|
||||
}
|
||||
if (!C::alwaysEnabled) {
|
||||
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
|
||||
}
|
||||
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
|
||||
|
||||
auto preset = _preset.get();
|
||||
if (preset != _preset.getDefault() && _presets.contains(preset)) {
|
||||
|
@ -92,17 +90,21 @@ class JobConfig : public QObject {
|
|||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY dirtyEnabled())
|
||||
|
||||
double _msCPURunTime{ 0.0 };
|
||||
|
||||
protected:
|
||||
friend class TaskConfig;
|
||||
|
||||
bool _isEnabled{ true };
|
||||
|
||||
public:
|
||||
using Persistent = PersistentConfig<JobConfig>;
|
||||
|
||||
JobConfig() = default;
|
||||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||
JobConfig(bool enabled): _isEnabled{ enabled } {}
|
||||
~JobConfig();
|
||||
|
||||
bool isEnabled() { return alwaysEnabled || enabled; }
|
||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; emit dirtyEnabled(); }
|
||||
|
||||
bool alwaysEnabled{ true };
|
||||
bool enabled{ true };
|
||||
bool isEnabled() const { return _isEnabled; }
|
||||
void setEnabled(bool enable);
|
||||
|
||||
virtual void setPresetList(const QJsonObject& object);
|
||||
|
||||
|
@ -200,6 +202,7 @@ public:
|
|||
*/
|
||||
class TaskConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Persistent = PersistentConfig<TaskConfig>;
|
||||
|
||||
|
@ -221,27 +224,13 @@ public:
|
|||
//
|
||||
// getter for qml integration, prefer the templated getter
|
||||
Q_INVOKABLE QObject* getConfig(const QString& name) { return getConfig<TConfigProxy>(name.toStdString()); }
|
||||
|
||||
// getter for cpp (strictly typed), prefer this getter
|
||||
template <class T> typename T::Config* getConfig(std::string job = "") const {
|
||||
const TaskConfig* root = this;
|
||||
QString path = (job.empty() ? QString() : QString(job.c_str())); // an empty string is not a null string
|
||||
auto tokens = path.split('.', QString::SkipEmptyParts);
|
||||
TaskConfig* getRootConfig(const std::string& jobPath, std::string& jobName) const;
|
||||
JobConfig* getJobConfig(const std::string& jobPath) const;
|
||||
|
||||
if (tokens.empty()) {
|
||||
tokens.push_back(QString());
|
||||
}
|
||||
else {
|
||||
while (tokens.size() > 1) {
|
||||
auto name = tokens.front();
|
||||
tokens.pop_front();
|
||||
root = QObject::findChild<TaskConfig*>(name);
|
||||
if (!root) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return root->findChild<typename T::Config*>(tokens.front());
|
||||
template <class T> typename T::Config* getConfig(std::string jobPath = "") const {
|
||||
return dynamic_cast<typename T::Config*>(getJobConfig(jobPath));
|
||||
}
|
||||
|
||||
Q_INVOKABLE bool isTask() const override { return true; }
|
||||
|
|
|
@ -164,7 +164,7 @@ public:
|
|||
|
||||
void run(const ContextPointer& jobContext) override {
|
||||
jobContext->jobConfig = std::static_pointer_cast<Config>(Concept::_config);
|
||||
if (jobContext->jobConfig->alwaysEnabled || jobContext->jobConfig->isEnabled()) {
|
||||
if (jobContext->jobConfig->isEnabled()) {
|
||||
jobRun(_data, jobContext, _input.get<I>(), _output.edit<O>());
|
||||
}
|
||||
jobContext->jobConfig.reset();
|
||||
|
@ -340,7 +340,7 @@ public:
|
|||
|
||||
void run(const ContextPointer& jobContext) override {
|
||||
auto config = std::static_pointer_cast<C>(Concept::_config);
|
||||
if (config->alwaysEnabled || config->enabled) {
|
||||
if (config->isEnabled()) {
|
||||
for (auto job : TaskConcept::_jobs) {
|
||||
job.run(jobContext);
|
||||
if (jobContext->taskFlow.doAbortTask()) {
|
||||
|
|
|
@ -99,6 +99,121 @@ function job_print_functor(printout, showProps, showInOuts, maxDepth) {
|
|||
}
|
||||
}
|
||||
|
||||
// Use this function to create a functor that will build a tree datastructure of the Job visited
|
||||
|
||||
function job_tree_model_array_functor(jobTreeArray, newNodeFunctor) {
|
||||
var jobsRoot;
|
||||
var numJobs = 0;
|
||||
var jobTreePath = []
|
||||
if (newNodeFunctor === undefined) newNodeFunctor = function (node) {}
|
||||
|
||||
return function (job, depth, index) {
|
||||
var id = numJobs
|
||||
var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": ""}
|
||||
if (depth == 0) {
|
||||
newNodeFunctor(newItem)
|
||||
jobTreeArray.push(newItem)
|
||||
numJobs++
|
||||
jobsRoot = jobTreeArray[0].subNode;
|
||||
} else {
|
||||
if (jobTreePath.length < depth) {
|
||||
var node = jobsRoot;
|
||||
var path;
|
||||
for (var n = 0; n < jobTreePath.length; n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name
|
||||
node = node[jobTreePath[n]].subNode
|
||||
}
|
||||
|
||||
newNodeFunctor(newItem)
|
||||
node.push((newItem))
|
||||
numJobs++
|
||||
jobTreePath.push(0);
|
||||
} else if (jobTreePath.length >= depth) {
|
||||
var node = jobsRoot;
|
||||
for (var n = 0; n < (depth - 1); n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node[jobTreePath[n]].name
|
||||
node = node[jobTreePath[n]].subNode
|
||||
}
|
||||
|
||||
newNodeFunctor(newItem)
|
||||
node.push((newItem))
|
||||
numJobs++
|
||||
jobTreePath[depth-1] = index;
|
||||
while (jobTreePath.length > depth) {
|
||||
jobTreePath.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function job_tree_model_functor(jobTreeModel, maxLevel, newNodeFunctor) {
|
||||
var jobsRoot;
|
||||
var numJobs = 0;
|
||||
var jobTreePath = []
|
||||
if (newNodeFunctor === undefined) newNodeFunctor = function (node) {}
|
||||
|
||||
return function (job, depth, index) {
|
||||
var id = numJobs
|
||||
var newItem = {"name": job.objectName, "level": depth, "index": index, "id": id, "subNode": [], "path": "", "init": (depth < maxLevel), "ud": {}}
|
||||
if (depth == 0) {
|
||||
newNodeFunctor(newItem)
|
||||
jobTreeModel.append(newItem)
|
||||
numJobs++
|
||||
jobsRoot = jobTreeModel.get(0).subNode;
|
||||
} else {
|
||||
if (jobTreePath.length < depth) {
|
||||
var node = jobsRoot;
|
||||
var path;
|
||||
for (var n = 0; n < jobTreePath.length; n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
|
||||
node = node.get(jobTreePath[n]).subNode
|
||||
}
|
||||
|
||||
newNodeFunctor(newItem)
|
||||
node.append((newItem))
|
||||
numJobs++
|
||||
jobTreePath.push(0);
|
||||
} else if (jobTreePath.length >= depth) {
|
||||
var node = jobsRoot;
|
||||
for (var n = 0; n < (depth - 1); n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
|
||||
node = node.get(jobTreePath[n]).subNode
|
||||
}
|
||||
|
||||
newNodeFunctor(newItem)
|
||||
node.append((newItem))
|
||||
numJobs++
|
||||
jobTreePath[depth-1] = index;
|
||||
while (jobTreePath.length > depth) {
|
||||
jobTreePath.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Traverse the jobTreenode data structure created above
|
||||
function job_traverseTreeNode(root, functor, depth) {
|
||||
if (root.subNode.length) {
|
||||
depth++;
|
||||
for (var i = 0; i <root.subNode.length; i++) {
|
||||
var sub = root.subNode[i];
|
||||
if (functor(sub, depth, i)) {
|
||||
job_traverseTreeNode(sub, functor, depth, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function job_traverseTreeNodeRoot(root, functor) {
|
||||
if (functor(root, 0, 0)) {
|
||||
job_traverseTreeNode(root, functor, 0)
|
||||
}
|
||||
}
|
||||
// Expose functions for regular js including this files through the 'Jet' object
|
||||
/*Jet = {}
|
||||
Jet.task_traverse = task_traverse
|
||||
|
|
|
@ -19,56 +19,23 @@ import "../jet.js" as Jet
|
|||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi;}
|
||||
color: hifi.colors.baseGray;
|
||||
color: Qt.rgba(hifi.colors.baseGray.r, hifi.colors.baseGray.g, hifi.colors.baseGray.b, 0.8);
|
||||
id: root;
|
||||
|
||||
property var rootConfig : Workload
|
||||
property var myArray : []
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
var message = ""
|
||||
var maxDepth = 5;
|
||||
|
||||
var jobTreePath = []
|
||||
var jobsRoot;
|
||||
|
||||
var functor = function (job, depth, index) {
|
||||
var newItem = {"name": job.objectName, "level": depth, "index": index, "subNode": [], "init": depth < maxDepth, "path": ""}
|
||||
if (depth == 0) {
|
||||
jobsModel.append(newItem)
|
||||
jobsRoot = jobsModel.get(0).subNode;
|
||||
} else {
|
||||
if (jobTreePath.length < depth) {
|
||||
var node = jobsRoot;
|
||||
var path;
|
||||
for (var n = 0; n < jobTreePath.length; n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
|
||||
node = node.get(jobTreePath[n]).subNode
|
||||
}
|
||||
node.append(newItem)
|
||||
jobTreePath.push(0);
|
||||
} else if (jobTreePath.length >= depth) {
|
||||
var node = jobsRoot;
|
||||
for (var n = 0; n < (depth - 1); n++) {
|
||||
newItem.path += (n > 0 ? "." : "") + node.get(jobTreePath[n]).name
|
||||
node = node.get(jobTreePath[n]).subNode
|
||||
}
|
||||
node.append(newItem)
|
||||
jobTreePath[depth-1] = index;
|
||||
while (jobTreePath.length > depth) {
|
||||
jobTreePath.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var functor = Jet.job_tree_model_functor(jobsModel, 3, function(node) {
|
||||
node["cpuT"] = 0.0
|
||||
})
|
||||
Jet.task_traverseTree(rootConfig, functor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ListModel {
|
||||
id: jobsModel
|
||||
property var engineJobItemModel : []
|
||||
}
|
||||
|
||||
Component {
|
||||
|
@ -77,30 +44,46 @@ Rectangle {
|
|||
id: objRecursiveColumn
|
||||
clip: true
|
||||
visible: model.init
|
||||
|
||||
MouseArea {
|
||||
width: objRow.implicitWidth
|
||||
height: objRow.implicitHeight
|
||||
onDoubleClicked: {
|
||||
for(var i = 1; i < parent.children.length - 1; ++i) {
|
||||
parent.children[i].visible = !parent.children[i].visible
|
||||
}
|
||||
|
||||
function switchFold() {
|
||||
for(var i = 1; i < children.length - 1; ++i) {
|
||||
children[i].visible = !children[i].visible
|
||||
}
|
||||
Row {
|
||||
id: objRow
|
||||
Item {
|
||||
height: 1
|
||||
width: model.level * 15
|
||||
}
|
||||
|
||||
Row {
|
||||
id: objRow
|
||||
Item {
|
||||
height: 1
|
||||
width: model.level * 15
|
||||
}
|
||||
|
||||
HifiControls.CheckBox {
|
||||
id: objCheck
|
||||
property var config: root.rootConfig.getConfig(model.path + "." + model.name);
|
||||
text: " "
|
||||
checked: root.rootConfig.getConfig(model.path + "." + model.name).enabled
|
||||
onCheckedChanged: { root.rootConfig.getConfig(model.path + "." + model.name).enabled = checked }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: objLabel.implicitWidth
|
||||
height: objLabel.implicitHeight
|
||||
onDoubleClicked: {
|
||||
parent.parent.switchFold()
|
||||
}
|
||||
HifiControls.CheckBox {
|
||||
property var config: root.rootConfig.getConfig(model.path + "." + model.name);
|
||||
|
||||
HifiControls.Label {
|
||||
id: objLabel
|
||||
colorScheme: (root.rootConfig.getConfig(model.path + "." + model.name) ? hifi.colorSchemes.dark : hifi.colorSchemes.light)
|
||||
text: (objRecursiveColumn.children.length > 2 ?
|
||||
objRecursiveColumn.children[1].visible ?
|
||||
qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name + " ms=" + config.cpuRunTime.toFixed(2)
|
||||
checked: config.enabled
|
||||
qsTr("- ") : qsTr("+ ") : qsTr(" ")) + model.name
|
||||
+ " id=" + model.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: subNode
|
||||
delegate: objRecursiveDelegate
|
||||
|
|
265
scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml
Normal file
265
scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml
Normal file
|
@ -0,0 +1,265 @@
|
|||
//
|
||||
// jet/TaskTimeFrameView.qml
|
||||
//
|
||||
// Created by Sam Gateau, 2018/06/15
|
||||
// Copyright 2018 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
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
import "qrc:///qml/styles-uit"
|
||||
import "qrc:///qml/controls-uit" as HifiControls
|
||||
|
||||
import "../jet.js" as Jet
|
||||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi;}
|
||||
color: Qt.rgba(hifi.colors.baseGray.r, hifi.colors.baseGray.g, hifi.colors.baseGray.b, 0.8);
|
||||
id: root;
|
||||
|
||||
property var rootConfig : Workload
|
||||
|
||||
property var jobsTree
|
||||
property var jobsArray
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!jobsTree) { jobsTree = new Array(); }
|
||||
if (!jobsArray) { jobsArray = new Array(); }
|
||||
|
||||
var tfunctor = Jet.job_tree_model_array_functor(jobsTree, function(node) {
|
||||
var job = { "fullpath": (node.path + "." + node.name), "cpuT": 0.0, "depth": node.level, "name": node.name }
|
||||
jobsArray.push(job)
|
||||
})
|
||||
Jet.task_traverseTree(rootConfig, tfunctor);
|
||||
|
||||
for (var j = 0; j <jobsArray.length; j++) {
|
||||
jobsArray[j].cpuT = Render.getConfig(jobsArray[j].fullpath).cpuRunTime
|
||||
// print("job" + j + ": " + jobsArray[j].cpuT)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onDestruction: {
|
||||
myCanvasTimer.stop();
|
||||
console.log("stopping timer!!!!");
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: myCanvasTimer
|
||||
interval: 100; running: true; repeat: true
|
||||
onTriggered: pullFreshValues()
|
||||
}
|
||||
|
||||
function pullFreshValues() {
|
||||
|
||||
for (var j = 0; j <jobsArray.length; j++) {
|
||||
jobsArray[j].cpuT = Render.getConfig(jobsArray[j].fullpath).cpuRunTime
|
||||
// jobsArray[j].cpuT = root.rootConfig.getConfig(jobsArray[j].fullpath).cpuRunTime
|
||||
}
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
|
||||
|
||||
property var frameScale : 10
|
||||
Row {
|
||||
id: myHeaderRow
|
||||
anchors.top:parent.top
|
||||
anchors.left:parent.left
|
||||
anchors.right:parent.right
|
||||
|
||||
|
||||
HifiControls.Button {
|
||||
id: myTimerPlayPause
|
||||
text: (myCanvasTimer.running ? "||" : "|>")
|
||||
height: 24
|
||||
width: 24
|
||||
onClicked: {
|
||||
print("list of highlight styles")
|
||||
myCanvasTimer.running = !myCanvasTimer.running
|
||||
}
|
||||
}
|
||||
}
|
||||
Canvas {
|
||||
id: mycanvas
|
||||
anchors.top:myHeaderRow.bottom
|
||||
anchors.bottom:parent.bottom
|
||||
anchors.left:parent.left
|
||||
anchors.right:parent.right
|
||||
|
||||
property var frameDuration: 10
|
||||
property var frameViewBegin: 0
|
||||
property var frameViewRange: width
|
||||
|
||||
function reset() {
|
||||
frameViewBegin = 0
|
||||
frameViewRange = width
|
||||
}
|
||||
|
||||
function checkView() {
|
||||
if (frameViewBegin > width * 0.9) {
|
||||
frameViewBegin = width * 0.9
|
||||
} else if (frameViewBegin + frameViewRange < width * 0.1) {
|
||||
frameViewBegin = width * 0.1 -frameViewRange
|
||||
}
|
||||
}
|
||||
|
||||
function drag(deltaX) {
|
||||
frameViewBegin -= deltaX
|
||||
checkView()
|
||||
}
|
||||
|
||||
function pivotScale(pivotX, deltaX) {
|
||||
var newRange = frameViewRange + 2 * deltaX
|
||||
if (newRange <= 1) {
|
||||
newRange = 2;
|
||||
}
|
||||
frameViewBegin = pivotX - frameViewRange * (pivotX - frameViewBegin) / newRange
|
||||
frameViewRange = newRange
|
||||
print( "pivot= " + pivotX + " deltaX= " + (deltaX))
|
||||
checkView()
|
||||
}
|
||||
|
||||
|
||||
onPaint: {
|
||||
// print("mycanvasOnPaint " + jobsArray.length)
|
||||
var lineHeight = 12;
|
||||
|
||||
function getXFromTime(t) {
|
||||
return (t / mycanvas.frameDuration) * mycanvas.frameViewRange - (mycanvas.frameViewBegin)
|
||||
}
|
||||
function getWFromDuration(d) {
|
||||
return (d / mycanvas.frameDuration) * mycanvas.frameViewRange
|
||||
}
|
||||
function displayBackground(ctx) {
|
||||
ctx.fillStyle = Qt.rgba(0, 0, 0, root.backgroundOpacity);
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
ctx.strokeStyle= "grey";
|
||||
ctx.lineWidth="2";
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, lineHeight + 1);
|
||||
ctx.lineTo(width, lineHeight + 1);
|
||||
ctx.moveTo(0, height);
|
||||
ctx.lineTo(width, height);
|
||||
|
||||
var x0 = getXFromTime(0)
|
||||
ctx.moveTo(x0, 0);
|
||||
ctx.lineTo(x0, height);
|
||||
|
||||
x0 = getXFromTime(5)
|
||||
ctx.moveTo(x0, 0);
|
||||
ctx.lineTo(x0, height);
|
||||
|
||||
x0 = getXFromTime(10)
|
||||
ctx.moveTo(x0, 0);
|
||||
ctx.lineTo(x0, height);
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function drawJob(ctx, depth, index, duration, timeOffset) {
|
||||
//print(root.jobsArray[index].cpuT)
|
||||
ctx.fillStyle = ( depth % 2 ? ( index % 2 ? "blue" : "yellow") : ( index % 2 ? "green" : "red"))
|
||||
ctx.fillRect(getXFromTime(timeOffset), lineHeight * 2 * depth,getWFromDuration(duration), lineHeight);
|
||||
|
||||
if (depth,getWFromDuration(duration) >= width * 0.1) {
|
||||
ctx.fillStyle = "grey";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText( root.jobsArray[index].name, getXFromTime(timeOffset + duration * 0.5), lineHeight * 2 * depth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.font="12px Verdana";
|
||||
|
||||
displayBackground(ctx);
|
||||
if (jobsArray.length > 0) {
|
||||
mycanvas.frameDuration = Math.max(jobsArray[0].cpuT, 1)
|
||||
var rangeStack =new Array()
|
||||
rangeStack.push( { "b": 0.0, "e": mycanvas.frameDuration } )
|
||||
|
||||
drawJob(ctx, 0, 0, jobsArray[0].cpuT, 0)
|
||||
|
||||
for (var i = 1; i <jobsArray.length; i++) {
|
||||
var lastDepth = rangeStack.length - 1;
|
||||
var depth = jobsArray[i].depth;
|
||||
var timeOffset = 0.0
|
||||
var duration = jobsArray[i].cpuT;
|
||||
|
||||
if (depth > lastDepth) {
|
||||
timeOffset = rangeStack[lastDepth].b
|
||||
while(rangeStack.length <= depth) {
|
||||
rangeStack.push( { "b": timeOffset, "e": timeOffset + duration } )
|
||||
}
|
||||
|
||||
} else {
|
||||
if (depth < lastDepth) {
|
||||
while(rangeStack.length != (depth + 1)) {
|
||||
rangeStack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
timeOffset = rangeStack[depth].e
|
||||
rangeStack[depth].b = timeOffset
|
||||
rangeStack[depth].e = timeOffset + duration
|
||||
}
|
||||
if (duration > 0.0) {
|
||||
drawJob(ctx, depth, i, duration, timeOffset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: hitbox
|
||||
anchors.fill: mycanvas
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
property var pivotX
|
||||
property var dragPos
|
||||
onPressed: {
|
||||
dragPos = { "x":mouse.x, "y":mouse.y }
|
||||
pivotX = mouse.x
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (dragPos !== undefined) {
|
||||
var delta = mouse.x - dragPos.x
|
||||
|
||||
if (mouse.buttons & Qt.LeftButton) {
|
||||
mycanvas.drag(delta)
|
||||
}
|
||||
|
||||
if (mouse.buttons & Qt.RightButton) {
|
||||
mycanvas.pivotScale(pivotX, delta)
|
||||
}
|
||||
|
||||
dragPos.x = mouse.x
|
||||
dragPos.y = mouse.y
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
dragPos = undefined
|
||||
}
|
||||
|
||||
onWheel: {
|
||||
mycanvas.pivotScale(wheel.x, mycanvas.frameViewRange * 0.02 * (wheel.angleDelta.y / 120.0))
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
|
||||
onDoubleClicked: {
|
||||
mycanvas.reset()
|
||||
mycanvas.requestPaint()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
TaskList 1.0 TaskList.qml
|
||||
TaskViewList 1.0 TaskViewList.qml
|
||||
TaskTimeFrameView 1.0 TaskTimeFrameView.qml
|
||||
|
|
|
@ -1,13 +1,57 @@
|
|||
function openEngineTaskView() {
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('engineInspector.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Render Engine',
|
||||
source: qml,
|
||||
width: 300,
|
||||
height: 400
|
||||
(function() {
|
||||
var TABLET_BUTTON_NAME = "Inspector";
|
||||
var QMLAPP_URL = Script.resolvePath("./engineInspector.qml");
|
||||
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
|
||||
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
text: TABLET_BUTTON_NAME,
|
||||
icon: ICON_URL,
|
||||
activeIcon: ACTIVE_ICON_URL
|
||||
});
|
||||
window.setPosition(200, 50);
|
||||
//window.closed.connect(function() { Script.stop(); });
|
||||
}
|
||||
openEngineTaskView();
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
killWindow()
|
||||
button.clicked.disconnect(onClicked);
|
||||
tablet.removeButton(button);
|
||||
});
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
|
||||
var onScreen = false;
|
||||
var window;
|
||||
|
||||
function onClicked() {
|
||||
if (onScreen) {
|
||||
killWindow()
|
||||
} else {
|
||||
createWindow()
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
var qml = Script.resolvePath(QMLAPP_URL);
|
||||
window = new OverlayWindow({
|
||||
title: 'Render Engine Inspector',
|
||||
source: qml,
|
||||
width: 250,
|
||||
height: 500
|
||||
});
|
||||
window.setPosition(200, 50);
|
||||
window.closed.connect(killWindow);
|
||||
onScreen = true
|
||||
button.editProperties({isActive: true});
|
||||
}
|
||||
|
||||
function killWindow() {
|
||||
if (window !== undefined) {
|
||||
window.closed.disconnect(killWindow);
|
||||
window.close()
|
||||
window = undefined
|
||||
}
|
||||
onScreen = false
|
||||
button.editProperties({isActive: false})
|
||||
}
|
||||
}());
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// deferredLighting.qml
|
||||
// EngineInspector.qml
|
||||
//
|
||||
// Created by Sam Gateau on 6/6/2016
|
||||
// Created by Sam Gateau on 06/07/2018
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -18,13 +18,13 @@ import "../lib/jet/qml" as Jet
|
|||
|
||||
Item {
|
||||
HifiConstants { id: hifi;}
|
||||
id: render;
|
||||
id: root;
|
||||
anchors.fill: parent
|
||||
|
||||
property var mainViewTask: Render.getConfig("RenderMainView")
|
||||
property var rootConfig: Render.getConfig("")
|
||||
|
||||
Jet.TaskListView {
|
||||
rootConfig: Render
|
||||
anchors.fill: render
|
||||
rootConfig: root.rootConfig
|
||||
anchors.fill: root
|
||||
}
|
||||
}
|
59
scripts/developer/utilities/render/engineProfiler.js
Normal file
59
scripts/developer/utilities/render/engineProfiler.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
|
||||
(function() {
|
||||
var TABLET_BUTTON_NAME = "Profiler";
|
||||
var QMLAPP_URL = Script.resolvePath("./engineProfiler.qml");
|
||||
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
|
||||
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
text: TABLET_BUTTON_NAME,
|
||||
icon: ICON_URL,
|
||||
activeIcon: ACTIVE_ICON_URL
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
killWindow()
|
||||
button.clicked.disconnect(onClicked);
|
||||
tablet.removeButton(button);
|
||||
});
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
|
||||
var onScreen = false;
|
||||
var window;
|
||||
|
||||
function onClicked() {
|
||||
if (onScreen) {
|
||||
killWindow()
|
||||
} else {
|
||||
createWindow()
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
var qml = Script.resolvePath(QMLAPP_URL);
|
||||
window = Desktop.createWindow(Script.resolvePath(QMLAPP_URL), {
|
||||
title: 'Render Engine Profiler',
|
||||
flags: Desktop.ALWAYS_ON_TOP,
|
||||
presentationMode: Desktop.PresentationMode.NATIVE,
|
||||
size: {x: 500, y: 100}
|
||||
});
|
||||
window.setPosition(200, 50);
|
||||
window.closed.connect(killWindow);
|
||||
onScreen = true
|
||||
button.editProperties({isActive: true});
|
||||
}
|
||||
|
||||
function killWindow() {
|
||||
if (window !== undefined) {
|
||||
window.closed.disconnect(killWindow);
|
||||
window.close()
|
||||
window = undefined
|
||||
}
|
||||
onScreen = false
|
||||
button.editProperties({isActive: false})
|
||||
}
|
||||
}());
|
||||
|
31
scripts/developer/utilities/render/engineProfiler.qml
Normal file
31
scripts/developer/utilities/render/engineProfiler.qml
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// EngineProfiler.qml
|
||||
//
|
||||
// Created by Sam Gateau on 06/07/2018
|
||||
// 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.7
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import "qrc:///qml/styles-uit"
|
||||
import "qrc:///qml/controls-uit" as HifiControls
|
||||
|
||||
import "../lib/jet/qml" as Jet
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi;}
|
||||
id: root;
|
||||
anchors.fill: parent
|
||||
|
||||
property var rootConfig: Render.getConfig("")
|
||||
|
||||
|
||||
Jet.TaskTimeFrameView {
|
||||
rootConfig: root.rootConfig
|
||||
anchors.fill: root
|
||||
}
|
||||
}
|
|
@ -615,7 +615,9 @@ function notificationPollCallbackHistory(historyArray) {
|
|||
ui.notificationDisplayBanner(message);
|
||||
} else {
|
||||
for (var i = 0; i < notificationCount; i++) {
|
||||
message = '"' + (historyArray[i].message) + '" ' +
|
||||
var historyMessage = historyArray[i].message;
|
||||
var sanitizedHistoryMessage = historyMessage.replace(/<\/?[^>]+(>|$)/g, "");
|
||||
message = '"' + sanitizedHistoryMessage + '" ' +
|
||||
"Open INVENTORY to see all activity.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue