diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7080602a22..0c654e9196 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2276,7 +2276,8 @@ Application::~Application() { // shutdown render engine _main3DScene = nullptr; _renderEngine = nullptr; - _infinityEngine = nullptr; + + _gameWorkload.shutdown(); DependencyManager::destroy(); @@ -2399,6 +2400,8 @@ void Application::initializeGL() { DependencyManager::get()->initializeShapePipelines(); }); + _gameWorkload.startup(getEntities()->getWorkloadSpace(), _main3DScene); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->setObjectName("MainThreadContext"); _offscreenContext->create(_glWidget->qglContext()); @@ -4166,7 +4169,7 @@ void Application::idle() { } { - _infinityEngine->run(); + _gameWorkload._engine->run(); } { PerformanceTimer perfTimer("update"); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0435425d5f..8028dc8c68 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -69,7 +69,8 @@ #include "ui/OverlayConductor.h" #include "ui/overlays/Overlays.h" #include "UndoStackScriptingInterface.h" -#include "workload/Engine.h" + +#include "workload/GameWorkload.h" #include #include @@ -613,7 +614,8 @@ private: render::ScenePointer _main3DScene{ new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) }; render::EnginePointer _renderEngine{ new render::Engine() }; gpu::ContextPointer _gpuContext; // initialized during window creation - workload::EnginePointer _infinityEngine{ new workload::Engine() }; + + GameWorkload _gameWorkload; mutable QMutex _renderArgsMutex{ QMutex::Recursive }; struct AppRenderArgs { diff --git a/interface/src/workload/GameWorkload.cpp b/interface/src/workload/GameWorkload.cpp new file mode 100644 index 0000000000..0113e0568d --- /dev/null +++ b/interface/src/workload/GameWorkload.cpp @@ -0,0 +1,38 @@ +// +// GameWorkload.cpp +// +// Created by Sam Gateau on 2/16/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 "GameWorkload.h" +#include "GameWorkloadRenderer.h" + +GameWorkloadContext::GameWorkloadContext(const workload::SpacePointer& space, const render::ScenePointer& scene) : WorkloadContext(space), _scene(scene) { +} + +GameWorkloadContext::~GameWorkloadContext() { +} + + +GameWorkload::GameWorkload() { +} + +GameWorkload::~GameWorkload() { + shutdown(); +} + +void GameWorkload::startup(const workload::SpacePointer& space, const render::ScenePointer& scene) { + _engine.reset(new workload::Engine(std::make_shared(space, scene))); + + _engine->addJob("SpaceToRender"); +} + +void GameWorkload::shutdown() { + _engine.reset(); +} + + + diff --git a/interface/src/workload/GameWorkload.h b/interface/src/workload/GameWorkload.h new file mode 100644 index 0000000000..fe48d0fe92 --- /dev/null +++ b/interface/src/workload/GameWorkload.h @@ -0,0 +1,37 @@ +// +// GameWorkload.h +// +// Created by Sam Gateau on 2/16/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_GameWorkload_h +#define hifi_GameWorkload_h + +#include "workload/Space.h" +#include "workload/Engine.h" + +#include "render/Scene.h" + +class GameWorkloadContext : public workload::WorkloadContext { +public: + GameWorkloadContext(const workload::SpacePointer& space, const render::ScenePointer& scene); + virtual ~GameWorkloadContext(); + + render::ScenePointer _scene; +}; + +class GameWorkload { +public: + GameWorkload(); + ~GameWorkload(); + + void startup(const workload::SpacePointer& space, const render::ScenePointer& scene); + void shutdown(); + + workload::EnginePointer _engine; +}; + +#endif \ No newline at end of file diff --git a/interface/src/workload/GameWorkloadRenderer.cpp b/interface/src/workload/GameWorkloadRenderer.cpp new file mode 100644 index 0000000000..99a784a511 --- /dev/null +++ b/interface/src/workload/GameWorkloadRenderer.cpp @@ -0,0 +1,128 @@ +// +// GameWorkloadRender.cpp +// +// Created by Sam Gateau on 2/20/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 "GameWorkloadRenderer.h" + +#include +#include + + +#include "render-utils/drawWorkloadProxy_vert.h" +#include "render-utils/drawWorkloadProxy_frag.h" + +void GameSpaceToRender::run(const workload::WorkloadContextPointer& runContext, Outputs& outputs) { + auto gameWorkloadContext = std::dynamic_pointer_cast(runContext); + if (!gameWorkloadContext) { + return; + } + + auto scene = gameWorkloadContext->_scene; + + // Valid space, let's display its content + render::Transaction transaction; + if (!render::Item::isValidID(_spaceRenderItemID)) { + _spaceRenderItemID = scene->allocateID(); + auto renderItem = std::make_shared(); + renderItem->editBound().expandedContains(glm::vec3(0.0f), 32000.0f); + transaction.resetItem(_spaceRenderItemID, std::make_shared(std::make_shared())); + scene->enqueueTransaction(transaction); + } + + + auto space = gameWorkloadContext->_space; + if (!space) { + return; + } + + std::vector proxies(space->getNumAllocatedProxies()); + + space->copyProxyValues(proxies.data(), (uint32_t) proxies.size()); + + transaction.updateItem(_spaceRenderItemID, [proxies](GameWorkloadRenderItem& item) { + item.setAllProxies(proxies); + }); + scene->enqueueTransaction(transaction); +} + +namespace render { + template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload) { + auto builder = ItemKey::Builder().opaqueShape().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1); + return builder.build(); + } + template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload) { + if (payload) { + return payload->getBound(); + } + return Item::Bound(); + } + template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args) { + if (payload) { + payload->render(args); + } + } +} + + + +void GameWorkloadRenderItem::setAllProxies(const std::vector& proxies) { + static const uint32_t sizeOfProxy = sizeof(workload::Space::Proxy); + if (!_allProxiesBuffer) { + _allProxiesBuffer = std::make_shared(sizeOfProxy); + } + + _allProxiesBuffer->setData(proxies.size() * sizeOfProxy, (const gpu::Byte*) proxies.data()); + _numAllProxies = (uint32_t) proxies.size(); +} + +const gpu::PipelinePointer GameWorkloadRenderItem::getPipeline() { + if (!_drawAllProxiesPipeline) { + auto vs = drawWorkloadProxy_vert::getShader(); + auto ps = drawWorkloadProxy_frag::getShader(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + auto state = std::make_shared(); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + _drawAllProxiesPipeline = gpu::Pipeline::create(program, state); + } + return _drawAllProxiesPipeline; +} + +void GameWorkloadRenderItem::render(RenderArgs* args) { + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + // Setup projection + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // Bind program + batch.setPipeline(getPipeline()); + + batch.setResourceBuffer(0, _allProxiesBuffer); + + static const int NUM_VERTICES_PER_QUAD = 4; + batch.draw(gpu::LINES, NUM_VERTICES_PER_QUAD * _numAllProxies, 0); + }); + +} + + + diff --git a/interface/src/workload/GameWorkloadRenderer.h b/interface/src/workload/GameWorkloadRenderer.h new file mode 100644 index 0000000000..969c85a195 --- /dev/null +++ b/interface/src/workload/GameWorkloadRenderer.h @@ -0,0 +1,64 @@ +// +// GameWorkloadRender.h +// +// Created by Sam Gateau on 2/20/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_GameWorkloadRenderer_h +#define hifi_GameWorkloadRenderer_h + +#include "GameWorkload.h" + +class GameSpaceToRender { +public: + using Outputs = render::Transaction; + using JobModel = workload::Job::ModelO; + + GameSpaceToRender() {} + void run(const workload::WorkloadContextPointer& renderContext, Outputs& outputs); + +protected: + render::ItemID _spaceRenderItemID{ render::Item::INVALID_ITEM_ID }; +}; + + +class GameWorkloadRenderItem { +public: + using Payload = render::Payload; + using Pointer = Payload::DataPointer; + + GameWorkloadRenderItem() {} + ~GameWorkloadRenderItem() {} + void render(RenderArgs* args); + + render::Item::Bound& editBound() { _needUpdate = true; return _bound; } + const render::Item::Bound& getBound() { return _bound; } + + void setVisible(bool visible) { _isVisible = visible; } + bool isVisible() const { return _isVisible; } + + void setAllProxies(const std::vector& proxies); + +protected: + render::Item::Bound _bound; + + gpu::BufferPointer _allProxiesBuffer; + uint32_t _numAllProxies{ 0 }; + + gpu::PipelinePointer _drawAllProxiesPipeline; + const gpu::PipelinePointer getPipeline(); + + bool _needUpdate{ true }; + bool _isVisible{ true }; +}; + +namespace render { + template <> const ItemKey payloadGetKey(const GameWorkloadRenderItem::Pointer& payload); + template <> const Item::Bound payloadGetBound(const GameWorkloadRenderItem::Pointer& payload); + template <> void payloadRender(const GameWorkloadRenderItem::Pointer& payload, RenderArgs* args); +} + +#endif \ No newline at end of file diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 879dd709e8..eecd21e5ac 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -281,7 +281,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r if (entity->getSpaceIndex() == -1) { std::unique_lock lock(_spaceLock); workload::Space::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius()); - int32_t spaceIndex = _space.createProxy(sphere); + int32_t spaceIndex = _space->createProxy(sphere); entity->setSpaceIndex(spaceIndex); connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection); } @@ -428,7 +428,7 @@ void EntityTreeRenderer::update(bool simulate) { } { // update proxies in the workload::Space std::unique_lock lock(_spaceLock); - _space.updateProxies(_spaceUpdates); + _space->updateProxies(_spaceUpdates); _spaceUpdates.clear(); } { // flush final EntityTree references to removed entities @@ -442,7 +442,7 @@ void EntityTreeRenderer::update(bool simulate) { disconnect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate); deadProxies.push_back(spaceIndex); } - _space.deleteProxies(deadProxies); + _space->deleteProxies(deadProxies); } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f034353347..5840dc6832 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -120,6 +120,9 @@ public: static void setRenderDebugHullsOperator(std::function renderDebugHullsOperator) { _renderDebugHullsOperator = renderDebugHullsOperator; } static bool shouldRenderDebugHulls() { return _renderDebugHullsOperator(); } + // Access the workload Space + const workload::SpacePointer getWorkloadSpace() const { return _space; } + signals: void enterEntity(const EntityItemID& entityItemID); void leaveEntity(const EntityItemID& entityItemID); @@ -266,7 +269,7 @@ private: static std::function _renderDebugHullsOperator; mutable std::mutex _spaceLock; - workload::Space _space; + workload::SpacePointer _space{ new workload::Space() }; std::vector _spaceUpdates; }; diff --git a/libraries/render-utils/src/drawWorkloadProxy.slf b/libraries/render-utils/src/drawWorkloadProxy.slf new file mode 100644 index 0000000000..84c47d0933 --- /dev/null +++ b/libraries/render-utils/src/drawWorkloadProxy.slf @@ -0,0 +1,28 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// drawItemBounds.frag +// fragment shader +// +// Created by Sam Gateau on 6/29/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +in vec4 varColor; +in vec2 varTexcoord; +out vec4 outFragColor; + +void main(void) { + float var = step(fract(varTexcoord.x * varTexcoord.y * 1.0), 0.5); + + if (varColor.a == 0.0) { + outFragColor = vec4(mix(vec3(0.0), varColor.xyz, var), mix(0.0, 1.0, var)); + + } else { + outFragColor = vec4(mix(vec3(1.0), varColor.xyz, var), varColor.a); + } + +} diff --git a/libraries/render-utils/src/drawWorkloadProxy.slv b/libraries/render-utils/src/drawWorkloadProxy.slv new file mode 100644 index 0000000000..0bb2b795bd --- /dev/null +++ b/libraries/render-utils/src/drawWorkloadProxy.slv @@ -0,0 +1,102 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// drawItemBounds.slv +// vertex shader +// +// Created by Sam Gateau on 6/29/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include gpu/Color.slh@> +<$declareColorWheel()$> + +uniform vec4 inColor; + + +struct ItemBound { + vec4 id_boundPos; + vec4 boundDim_s; +}; + +#if defined(GPU_GL410) +uniform samplerBuffer ssbo0Buffer; +ItemBound getItemBound(int i) { + int offset = 2 * i; + ItemBound bound; + bound.id_boundPos = texelFetch(ssbo0Buffer, offset); + bound.boundDim_s = texelFetch(ssbo0Buffer, offset + 1); + return bound; +} +#else +layout(std140) buffer ssbo0Buffer { + ItemBound bounds[]; +}; +ItemBound getItemBound(int i) { + ItemBound bound = bounds[i]; + return bound; +} +#endif + + + +out vec4 varColor; +out vec2 varTexcoord; + +void main(void) { + const vec4 UNIT_BOX[8] = vec4[8]( + vec4(0.0, 0.0, 0.0, 0.0), + vec4(1.0, 0.0, 0.0, 1.0), + vec4(0.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 2.0), + vec4(0.0, 0.0, 1.0, 1.0), + vec4(1.0, 0.0, 1.0, 2.0), + vec4(0.0, 1.0, 1.0, 2.0), + vec4(1.0, 1.0, 1.0, 3.0) + ); + const int UNIT_BOX_LINE_INDICES[24] = int[24]( + 0, 1, + 1, 3, + 3, 2, + 2, 0, + 4, 5, + 5, 7, + 7, 6, + 6, 4, + 2, 6, + 3, 7, + 0, 4, + 1, 5 + ); + + int boundID = gl_VertexID / 24; + int vertexID = gl_VertexID - boundID * 24; + + vec4 cubeVec = UNIT_BOX[UNIT_BOX_LINE_INDICES[vertexID]]; + + ItemBound bound = getItemBound(boundID); + vec3 boundPos = bound.id_boundPos.yzw; + vec3 boundDim = bound.boundDim_s.xyz; + + vec4 pos = vec4(boundPos + boundDim * cubeVec.xyz, 1.0); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, pos, gl_Position)$> + + if (inColor.w < 0.0) { + varColor = vec4(colorWheel(float(boundID)/(-inColor.w)), 1.0); + } else { + varColor = vec4(colorWheel(float(inColor.w)), 1.0); + } + varTexcoord = vec2(cubeVec.w, length(boundDim)); + +} \ No newline at end of file diff --git a/libraries/workload/src/workload/Engine.cpp b/libraries/workload/src/workload/Engine.cpp index ba3e7706ca..ab4634cb97 100644 --- a/libraries/workload/src/workload/Engine.cpp +++ b/libraries/workload/src/workload/Engine.cpp @@ -38,7 +38,7 @@ namespace workload { } }; - WorkloadContext::WorkloadContext() : task::JobContext(trace_workload()) {} + WorkloadContext::WorkloadContext(const SpacePointer& space) : task::JobContext(trace_workload()), _space(space) {} using EngineModel = Task::Model; @@ -54,8 +54,8 @@ namespace workload { } }; - Engine::Engine() : Task("Engine", EngineModel::create()), - _context(std::make_shared()) { + Engine::Engine(const WorkloadContextPointer& context) : Task("Engine", EngineModel::create()), + _context(context) { } } // namespace workload diff --git a/libraries/workload/src/workload/Engine.h b/libraries/workload/src/workload/Engine.h index 7a4a5d428f..08abe23e35 100644 --- a/libraries/workload/src/workload/Engine.h +++ b/libraries/workload/src/workload/Engine.h @@ -20,6 +20,8 @@ #include +#include "Space.h" + namespace workload { // How to make an Engine under the task::Task paradigm... @@ -27,8 +29,10 @@ namespace workload { // (1) Derive class C from task::JobContext class WorkloadContext : public task::JobContext { public: - WorkloadContext(); + WorkloadContext(const SpacePointer& space); virtual ~WorkloadContext() {} + + SpacePointer _space; }; using WorkloadContextPointer = std::shared_ptr; @@ -56,15 +60,15 @@ namespace workload { // (5) Engine derives from task::Task and will run all the Job's class Engine : public Task { public: - Engine(); + Engine(const WorkloadContextPointer& context = std::make_shared()); ~Engine() = default; // (6) The Engine's Context is passed to its Jobs when they are run() - void run() { assert(_context); Task::run(_context); } + void run() { assert(_context); run(_context); } protected: // (6) Again, the Engine's Context is passed to its Jobs when they are run() - void run(const WorkloadContextPointer& context) override { assert(_context); Task::run(_context); } + void run(const WorkloadContextPointer& context) override { assert(_context); Task::run(_context); } private: WorkloadContextPointer _context; diff --git a/libraries/workload/src/workload/Space.cpp b/libraries/workload/src/workload/Space.cpp index 3e8b61992e..e9745e0916 100644 --- a/libraries/workload/src/workload/Space.cpp +++ b/libraries/workload/src/workload/Space.cpp @@ -13,7 +13,7 @@ // #include "Space.h" - +#include #include #include @@ -101,6 +101,15 @@ void Space::deleteProxy(int32_t proxyId) { } } +uint32_t Space::copyProxyValues(Proxy* proxies, uint32_t numDestProxies) { + + auto numCopied = std::min(numDestProxies, (uint32_t)_proxies.size()); + memcpy(proxies, _proxies.data(), numCopied * sizeof(Proxy)); + + return numCopied; +} + + // private void Space::updateProxy(int32_t proxyId, const Space::Sphere& newSphere) { if (proxyId > -1 && proxyId < (int32_t)_proxies.size()) { diff --git a/libraries/workload/src/workload/Space.h b/libraries/workload/src/workload/Space.h index f071c658a7..ee06383288 100644 --- a/libraries/workload/src/workload/Space.h +++ b/libraries/workload/src/workload/Space.h @@ -15,9 +15,11 @@ #ifndef hifi_workload_Space_h #define hifi_workload_Space_h +#include #include #include + namespace workload { class Space { @@ -33,6 +35,7 @@ public: class Proxy { public: + Proxy() : sphere(0.0f) {} Proxy(const Sphere& s) : sphere(s) {} Sphere sphere; uint8_t region { REGION_UNKNOWN }; @@ -66,9 +69,12 @@ public: void setViews(const std::vector& views); uint32_t getNumObjects() const { return (uint32_t)(_proxies.size() - _freeIndices.size()); } + uint32_t getNumAllocatedProxies() const { return (uint32_t)(_proxies.size()); } void categorizeAndGetChanges(std::vector& changes); + uint32_t copyProxyValues(Proxy* proxies, uint32_t numDestProxies); + private: void deleteProxy(int32_t proxyId); void updateProxy(int32_t proxyId, const Sphere& sphere); @@ -78,6 +84,7 @@ private: std::vector _freeIndices; }; +using SpacePointer = std::shared_ptr; using Classifications = std::vector; } // namespace workload