diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f5d599b5d3..76d701f0e3 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1175,13 +1175,22 @@ void OctreeServer::aboutToFinish() { if (_jurisdictionSender) { _jurisdictionSender->terminating(); } + + QSet nodesToShutdown; - // force a shutdown of all of our OctreeSendThreads - at this point it has to be impossible for a - // linkedDataCreateCallback to be called for a new node - nodeList->eachNode([this](const SharedNodePointer& node) { + // Force a shutdown of all of our OctreeSendThreads. + // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node + nodeList->eachNode([&nodesToShutdown](const SharedNodePointer& node) { + nodesToShutdown << node; + }); + + // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. + // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically + // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. + for (auto& node : nodesToShutdown) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); - }); + } if (_persistThread) { _persistThread->aboutToFinish(); diff --git a/examples/FlockOfbirds.js b/examples/FlockOfbirds.js index 0e8c6d4731..8b5088a268 100644 --- a/examples/FlockOfbirds.js +++ b/examples/FlockOfbirds.js @@ -10,15 +10,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -// The area over which the birds will fly -var lowerCorner = { x: 1, y: 1, z: 1 }; -var upperCorner = { x: 10, y: 10, z: 10 }; +// The rectangular area in the domain where the flock will fly +var lowerCorner = { x: 0, y: 0, z: 0 }; +var upperCorner = { x: 10, y: 10, z: 10 }; var STARTING_FRACTION = 0.25; var NUM_BIRDS = 50; +var UPDATE_INTERVAL = 0.016; var playSounds = true; var SOUND_PROBABILITY = 0.001; +var STARTING_LIFETIME = (1.0 / SOUND_PROBABILITY) * UPDATE_INTERVAL * 10; var numPlaying = 0; var BIRD_SIZE = 0.08; var BIRD_MASTER_VOLUME = 0.1; @@ -35,6 +36,10 @@ var ALIGNMENT_FORCE = 1.5; var COHESION_FORCE = 1.0; var MAX_COHESION_VELOCITY = 0.5; +var followBirds = true; +var AVATAR_FOLLOW_RATE = 0.001; +var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0; +var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005; var floor = false; var MAKE_FLOOR = false; @@ -43,6 +48,9 @@ var averagePosition = { x: 0, y: 0, z: 0 }; var birdsLoaded = false; +var oldAvatarOrientation; +var oldAvatarPosition; + var birds = []; var playing = []; @@ -115,8 +123,9 @@ function updateBirds(deltaTime) { birds[i].audioId = Audio.playSound(birds[i].sound, options); } numPlaying++; - // Change size - Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions)}); + // Change size, and update lifetime to keep bird alive + Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions), + lifetime: properties.ageInSeconds + STARTING_LIFETIME}); } else if (birds[i].audioId) { // If bird is playing a chirp @@ -166,10 +175,24 @@ function updateBirds(deltaTime) { if (birdVelocitiesCounted > 0) { averageVelocity = Vec3.multiply(1.0 / birdVelocitiesCounted, sumVelocity); //print(Vec3.length(averageVelocity)); + if (followBirds) { + MyAvatar.motorVelocity = averageVelocity; + MyAvatar.motorTimescale = AVATAR_FOLLOW_VELOCITY_TIMESCALE; + var polarAngles = Vec3.toPolar(Vec3.normalize(averageVelocity)); + if (!isNaN(polarAngles.x) && !isNaN(polarAngles.y)) { + var birdDirection = Quat.fromPitchYawRollRadians(polarAngles.x, polarAngles.y + Math.PI, polarAngles.z); + MyAvatar.orientation = Quat.mix(MyAvatar.orientation, birdDirection, AVATAR_FOLLOW_ORIENTATION_RATE); + } + } } if (birdPositionsCounted > 0) { averagePosition = Vec3.multiply(1.0 / birdPositionsCounted, sumPosition); + // If Following birds, update position + if (followBirds) { + MyAvatar.position = Vec3.sum(Vec3.multiply(AVATAR_FOLLOW_RATE, MyAvatar.position), Vec3.multiply(1.0 - AVATAR_FOLLOW_RATE, averagePosition)); + } } + } // Connect a call back that happens every frame @@ -183,11 +206,14 @@ Script.scriptEnding.connect(function() { if (floor) { Entities.deleteEntity(floor); } + MyAvatar.orientation = oldAvatarOrientation; + MyAvatar.position = oldAvatarPosition; }); function loadBirds(howMany) { - while (!Entities.serversExist() || !Entities.canRez()) { - } + oldAvatarOrientation = MyAvatar.orientation; + oldAvatarPosition = MyAvatar.position; + var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw"]; /* Here are more sounds/species you can use , "mexicanWhipoorwill.raw", @@ -247,6 +273,7 @@ function loadBirds(howMany) { velocity: { x: 0, y: -0.1, z: 0 }, linearDamping: LINEAR_DAMPING, collisionsWillMove: true, + lifetime: STARTING_LIFETIME, color: colors[whichBird] }), audioId: false, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a862fb84fb..600b67812d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -9,11 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "Application.h" -#include -#include -#include +#include #include #include @@ -63,6 +61,7 @@ #include #include +#include #include #include #include @@ -92,13 +91,13 @@ #include #include #include +#include #include #include #include #include #include -#include "Application.h" #include "AudioClient.h" #include "DiscoverabilityManager.h" #include "InterfaceVersion.h" @@ -268,6 +267,8 @@ bool setupEssentials(int& argc, char** argv) { auto audioScope = DependencyManager::set(); auto deferredLightingEffect = DependencyManager::set(); auto textureCache = DependencyManager::set(); + auto framebufferCache = DependencyManager::set(); + auto animationCache = DependencyManager::set(); auto ddeFaceTracker = DependencyManager::set(); auto modelBlender = DependencyManager::set(); @@ -771,6 +772,7 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -804,33 +806,8 @@ void Application::initializeGL() { } #endif - #ifdef WIN32 - GLenum err = glewInit(); - if (GLEW_OK != err) { - /* Problem: glewInit failed, something is seriously wrong. */ - qCDebug(interfaceapp, "Error: %s\n", glewGetErrorString(err)); - } - qCDebug(interfaceapp, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); - - if (wglewGetExtension("WGL_EXT_swap_control")) { - int swapInterval = wglGetSwapIntervalEXT(); - qCDebug(interfaceapp, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); - } - #endif - - - qCDebug(interfaceapp) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); - qCDebug(interfaceapp) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); - qCDebug(interfaceapp) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); - qCDebug(interfaceapp) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); - -#if defined(Q_OS_LINUX) - // TODO: Write the correct code for Linux... - /* if (wglewGetExtension("WGL_EXT_swap_control")) { - int swapInterval = wglGetSwapIntervalEXT(); - qCDebug(interfaceapp, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); - }*/ -#endif + // Where the gpuContext is created and where the TRUE Backend is created and assigned + _gpuContext = std::make_shared(new gpu::GLBackend()); initDisplay(); qCDebug(interfaceapp, "Initialized Display."); @@ -929,8 +906,9 @@ void Application::paintGL() { _offscreenContext->makeCurrent(); auto lodManager = DependencyManager::get(); - gpu::Context context(new gpu::GLBackend()); - RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), + + + RenderArgs renderArgs(_gpuContext, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); @@ -942,17 +920,16 @@ void Application::paintGL() { PerformanceWarning warn(showWarnings, "Application::paintGL()"); resizeGL(); + { 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 QSize size = qApp->getDeviceSize(); - renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); + renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); } - glEnable(GL_LINE_SMOOTH); - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); @@ -1000,8 +977,7 @@ void Application::paintGL() { } // Sync up the View Furstum with the camera - // FIXME: it's happening again in the updateSHadow and it shouldn't, this should be the place - _myCamera.loadViewFrustum(_viewFrustum); + loadViewFrustum(_myCamera, _viewFrustum); renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; @@ -1015,19 +991,15 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/clear"); doInBatch(&renderArgs, [&](gpu::Batch& batch) { - batch.setFramebuffer(textureCache->getPrimaryFramebuffer()); + auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); + batch.setFramebuffer(primaryFbo); // clear the normal and specular buffers batch.clearFramebuffer( gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_DEPTH, - vec4(vec3(0), 1), 1.0, 0.0, true); - batch.clearColorFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | - gpu::Framebuffer::BUFFER_COLOR1 | - gpu::Framebuffer::BUFFER_COLOR2, - vec4(vec3(0), 1)); + vec4(vec3(0), 1), 1.0, 0.0); }); } @@ -1048,7 +1020,9 @@ void Application::paintGL() { displaySide(&renderArgs, eyeCamera); if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; renderRearViewMirror(&renderArgs, _mirrorViewRect); + renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE; } }, [&] { r.moveLeft(r.width()); @@ -1065,7 +1039,9 @@ void Application::paintGL() { displaySide(&renderArgs, _myCamera); if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; renderRearViewMirror(&renderArgs, _mirrorViewRect); + renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE; } } } @@ -1107,8 +1083,10 @@ void Application::paintGL() { GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); #endif _offscreenContext->doneCurrent(); + // Switches to the display plugin context displayPlugin->preDisplay(); + // Ensure all operations from the previous context are complete before we try to read the fbo #ifdef Q_OS_MAC #else // FIXME? make the sync a parameter to preDisplay and let the plugin manage this @@ -1954,6 +1932,13 @@ void Application::idle() { } double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0; if (timeSinceLastUpdate > targetFramePeriod) { + + { + static const int IDLE_EVENT_PROCESS_MAX_TIME_MS = 2; + PerformanceTimer perfTimer("processEvents"); + processEvents(QEventLoop::AllEvents, IDLE_EVENT_PROCESS_MAX_TIME_MS); + } + _lastTimeUpdated.start(); { PerformanceTimer perfTimer("update"); @@ -1986,12 +1971,19 @@ void Application::idle() { _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); _idleLoopStdev.reset(); } - } - // After finishing all of the above work, ensure the idle timer is set to the proper interval, - // depending on whether we're throttling or not - idleTimer->start(getActiveDisplayPlugin()->isThrottled() ? THROTTLED_IDLE_TIMER_DELAY : 0); - } + + // depending on whether we're throttling or not. + // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in + // perpetuity and not expect events to get backed up. + + static const int IDLE_TIMER_DELAY_MS = 0; + int desiredInterval = _glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + + if (idleTimer->interval() != desiredInterval) { + idleTimer->start(desiredInterval); + } + } // check for any requested background downloads. emit checkBackgroundDownloads(); @@ -3207,7 +3199,7 @@ PickRay Application::computePickRay(float x, float y) const { } QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) { - auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); + auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer)); // clear the alpha channel so the background is transparent @@ -3400,10 +3392,6 @@ namespace render { model::Skybox::render(batch, *(Application::getInstance()->getDisplayViewFrustum()), *skybox); } } - // FIX ME - If I don't call this renderBatch() here, then the atmosphere and skybox don't render, but it - // seems like these payloadRender() methods shouldn't be doing this. We need to investigate why the engine - // isn't rendering our batch - gpu::GLBackend::renderBatch(batch, true); } } @@ -3605,11 +3593,11 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // set the bounds of rear mirror view gpu::Vec4i viewport; if (billboard) { - QSize size = DependencyManager::get()->getFrameBufferSize(); + QSize size = DependencyManager::get()->getFrameBufferSize(); viewport = gpu::Vec4i(region.x(), size.height() - region.y() - region.height(), region.width(), region.height()); } else { // if not rendering the billboard, the region is in device independent coordinates; must convert to device - QSize size = DependencyManager::get()->getFrameBufferSize(); + QSize size = DependencyManager::get()->getFrameBufferSize(); float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; viewport = gpu::Vec4i(x, size.height() - y - height, width, height); diff --git a/interface/src/Application.h b/interface/src/Application.h index 1241f1b573..ceaa194d24 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,7 @@ #include "UndoStackScriptingInterface.h" #include "DisplayPlugins.h" #include "InputPlugins.h" + #include "render/Engine.h" class QGLWidget; @@ -84,7 +84,9 @@ class MainWindow; class Node; class ScriptEngine; class GlWindow; - +namespace gpu { + class Context; +} static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SVO_EXTENSION = ".svo"; static const QString SVO_JSON_EXTENSION = ".svo.json"; @@ -328,6 +330,8 @@ public: render::ScenePointer getMain3DScene() const { return _main3DScene; } + gpu::ContextPointer getGPUContext() const { return _gpuContext; } + signals: /// Fired when we're simulating; allows external parties to hook in. @@ -482,6 +486,7 @@ private: glm::vec3 getSunDirection(); void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard = false); + void setMenuShortcutsEnabled(bool enabled); static void attachNewHeadToNode(Node *newNode); @@ -633,6 +638,7 @@ private: render::ScenePointer _main3DScene{ new render::Scene() }; render::EnginePointer _renderEngine{ new render::Engine() }; + gpu::ContextPointer _gpuContext; // initialized during window creation Overlays _overlays; ApplicationOverlay _applicationOverlay; diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index da61926399..ebfddee38c 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -169,7 +169,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { points.resize(limit); for (size_t star = 0; star < limit; ++star) { points[star].position = vec4(fromPolar(randPolar()), 1); - float size = frand() * 5.0f + 0.5f; + float size = frand() * 2.5f + 0.5f; if (frand() < STAR_COLORIZATION) { vec3 color(frand() / 2.0f + 0.5f, frand() / 2.0f + 0.5f, frand() / 2.0f + 0.5f); points[star].colorAndSize = vec4(color, size); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4db3327f69..e3e4bbc5d3 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -316,15 +316,14 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); } auto& batch = *renderArgs->_batch; - if (postLighting && - glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { + if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); @@ -414,9 +413,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo : GLOW_FROM_AVERAGE_LOUDNESS; // render body - renderBody(renderArgs, frustum, postLighting, glowLevel); + renderBody(renderArgs, frustum, glowLevel); - if (!postLighting && renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { + if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { // add local lights const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; @@ -431,21 +430,17 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo } } - if (postLighting) { - bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); - bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); - bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); - - if (renderSkeleton) { - _skeletonModel.renderJointCollisionShapes(0.7f); - } - - if (renderHead && shouldRenderHead(renderArgs)) { - getHead()->getFaceModel().renderJointCollisionShapes(0.7f); - } - if (renderBounding && shouldRenderHead(renderArgs)) { - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); - } + bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); + bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); + bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); + if (renderSkeleton) { + _skeletonModel.renderJointCollisionShapes(0.7f); + } + if (renderHead && shouldRenderHead(renderArgs)) { + getHead()->getFaceModel().renderJointCollisionShapes(0.7f); + } + if (renderBounding && shouldRenderHead(renderArgs)) { + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); } // Stack indicator spheres @@ -569,24 +564,20 @@ void Avatar::fixupModelsInScene() { scene->enqueuePendingChanges(pendingChanges); } -void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { fixupModelsInScene(); { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - if (postLighting || renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) { - // render the billboard until both models are loaded - renderBillboard(renderArgs); - } + // render the billboard until both models are loaded + renderBillboard(renderArgs); return; } - if (postLighting) { - getHand()->render(renderArgs, false); - } + getHand()->render(renderArgs, false); } - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ae99317541..253c94b0b3 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -81,8 +81,7 @@ public: void init(); void simulate(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, - bool postLighting = false); + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); @@ -235,7 +234,7 @@ protected: Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const; void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f); virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 22f623b4a8..d8b4bf703b 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -297,7 +297,7 @@ void Head::relaxLean(float deltaTime) { _deltaLeanForward *= relaxationFactor; } -void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting) { +void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum) { if (_renderLookatVectors) { renderLookatVectors(renderArgs, _leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition()); } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index d7a8462693..f6283c93ea 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -33,7 +33,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting); + void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b23c737bfe..8d8e9a7996 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -389,13 +389,13 @@ void MyAvatar::updateFromTrackers(float deltaTime) { // virtual -void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { +void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { // don't render if we've been asked to disable local rendering if (!_shouldRender) { return; // exit early } - Avatar::render(renderArgs, cameraPosition, postLighting); + Avatar::render(renderArgs, cameraPosition); // don't display IK constraints in shadow mode if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && @@ -1281,7 +1281,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); } -void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until all models are loaded @@ -1291,7 +1291,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo // Render head so long as the camera isn't inside it if (shouldRenderHead(renderArgs)) { - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } getHand()->render(renderArgs, true); } @@ -1590,8 +1590,8 @@ void MyAvatar::maybeUpdateBillboard() { return; } } - gpu::Context context(new gpu::GLBackend()); - RenderArgs renderArgs(&context); + + RenderArgs renderArgs(qApp->getGPUContext()); QImage image = qApp->renderAvatarBillboard(&renderArgs); _billboard.clear(); QBuffer buffer(&_billboard); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4f494c6ead..a45b1e0acc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -59,8 +59,8 @@ public: // This is so the correct camera can be used for rendering. void updateSensorToWorldMatrix(); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f) override; + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; // setters diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 540de18d87..0bf18ff956 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "Application.h" @@ -790,31 +791,34 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha const int BALL_SUBDIVISIONS = 10; #if 0 if (_shapes.isEmpty()) { - // the bounding shape has not been propery computed + // the bounding shape has not been properly computed // so no need to render it return; } - // draw a blue sphere at the capsule endpoint + auto geometryCache = DependencyManager::get(); + auto deferredLighting = DependencyManager::get(); + Transform transform; // = Transform(); + + // draw a blue sphere at the capsule end point glm::vec3 endPoint; _boundingShape.getEndPoint(endPoint); endPoint = endPoint + _translation; - Transform transform = Transform(); transform.setTranslation(endPoint); batch.setModelTransform(transform); - auto geometryCache = DependencyManager::get(); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); - // draw a yellow sphere at the capsule startpoint + // draw a yellow sphere at the capsule start point glm::vec3 startPoint; _boundingShape.getStartPoint(startPoint); startPoint = startPoint + _translation; glm::vec3 axis = endPoint - startPoint; - Transform axisTransform = Transform(); - axisTransform.setTranslation(-axis); - batch.setModelTransform(axisTransform); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + transform.setTranslation(startPoint); + batch.setModelTransform(transform); + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index f77beb165e..fb465094cd 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -272,8 +272,8 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int gpu::Batch batch; geometryCache->useSimpleDrawPipeline(batch); - batch._glDisable(GL_DEPTH_TEST); - batch._glDisable(GL_CULL_FACE); + //batch._glDisable(GL_DEPTH_TEST); + //batch._glDisable(GL_CULL_FACE); //batch._glBindTexture(GL_TEXTURE_2D, texture); //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index ae09aa0b10..532fea23dc 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -49,7 +49,6 @@ private: gpu::TexturePointer _overlayDepthTexture; gpu::TexturePointer _overlayColorTexture; gpu::FramebufferPointer _overlayFramebuffer; - }; #endif // hifi_ApplicationOverlay_h diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index b2843230f3..d26ecc5c67 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -91,6 +91,7 @@ void BillboardOverlay::render(RenderArgs* args) { if (batch) { Transform transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); + transform.setRotation(rotation); batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 4eb0976e3c..484c772c71 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -134,7 +134,7 @@ protected: friend class Shader; }; - +typedef std::shared_ptr ContextPointer; }; diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 50f42ed4fb..5a1504d25c 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -1,19 +1,21 @@ -// -// Framebuffer.h -// libraries/gpu/src/gpu -// -// Created by Sam Gateau on 4/12/2015. -// Copyright 2014 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_gpu_Framebuffer_h -#define hifi_gpu_Framebuffer_h - -#include "Texture.h" +// +// Framebuffer.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 4/12/2015. +// Copyright 2014 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_gpu_Framebuffer_h +#define hifi_gpu_Framebuffer_h + +#include "Texture.h" #include +class QImage; + namespace gpu { typedef Element Format; @@ -130,7 +132,9 @@ public: void resize( uint16 width, uint16 height, uint16 samples = 1 ); static const uint32 MAX_NUM_RENDER_BUFFERS = 8; - static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } + static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } + + void getImage(QImage* result) const; protected: SwapchainPointer _swapchain; @@ -151,10 +155,10 @@ protected: // Non exposed Framebuffer(const Framebuffer& framebuffer) {} Framebuffer() {} - - // This shouldn't be used by anything else than the Backend class with the proper casting. - mutable GPUObject* _gpuObject = NULL; - void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } GPUObject* getGPUObject() const { return _gpuObject; } friend class Backend; }; @@ -162,4 +166,4 @@ typedef std::shared_ptr FramebufferPointer; } -#endif \ No newline at end of file +#endif diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index adebee2f20..721be0f402 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -8,6 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include "GPULogging.h" #include "GLBackendShared.h" #include @@ -89,6 +90,36 @@ GLBackend::GLBackend() : _pipeline(), _output() { + static std::once_flag once; + std::call_once(once, [] { + qCDebug(gpulogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION)); + qCDebug(gpulogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)); + qCDebug(gpulogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR)); + qCDebug(gpulogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER)); + +#ifdef WIN32 + GLenum err = glewInit(); + if (GLEW_OK != err) { + /* Problem: glewInit failed, something is seriously wrong. */ + qCDebug(gpulogging, "Error: %s\n", glewGetErrorString(err)); + } + qCDebug(gpulogging, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + + if (wglewGetExtension("WGL_EXT_swap_control")) { + int swapInterval = wglGetSwapIntervalEXT(); + qCDebug(gpulogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + } +#endif + +#if defined(Q_OS_LINUX) + // TODO: Write the correct code for Linux... + /* if (wglewGetExtension("WGL_EXT_swap_control")) { + int swapInterval = wglGetSwapIntervalEXT(); + qCDebug(gpulogging, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF")); + }*/ +#endif + }); + initInput(); initTransform(); } @@ -113,6 +144,7 @@ void GLBackend::render(Batch& batch) { } void GLBackend::renderBatch(Batch& batch, bool syncCache) { + qCDebug(gpulogging) << "GLBackend::renderBatch : Deprecated call, don;t do it!!!"; GLBackend backend; if (syncCache) { backend.syncCache(); @@ -166,6 +198,8 @@ void GLBackend::syncCache() { syncTransformStateCache(); syncPipelineStateCache(); syncInputStateCache(); + + glEnable(GL_LINE_SMOOTH); } void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 60c01a815c..b3e905bf21 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -447,7 +447,6 @@ protected: typedef void (GLBackend::*CommandCall)(Batch&, uint32); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; - }; diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index d16ab5c047..100ad28053 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -10,7 +10,7 @@ // #include "Texture.h" -#include + #include #include diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 74b0304ace..cfe7abd4db 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -43,9 +43,18 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector& poin const float MIN_MARGIN = 0.01f; glm::vec3 diagonal = maxCorner - minCorner; - float minDimension = glm::min(diagonal[0], diagonal[1]); - minDimension = glm::min(minDimension, diagonal[2]); - margin = glm::min(glm::max(0.5f * minDimension, MIN_MARGIN), margin); + float smallestDimension = glm::min(diagonal[0], diagonal[1]); + smallestDimension = glm::min(smallestDimension, diagonal[2]); + const float MIN_DIMENSION = 2.0f * MIN_MARGIN + 0.001f; + if (smallestDimension < MIN_DIMENSION) { + for (int i = 0; i < 3; ++i) { + if (diagonal[i] < MIN_DIMENSION) { + diagonal[i] = MIN_DIMENSION; + } + } + smallestDimension = MIN_DIMENSION; + } + margin = glm::min(glm::max(0.5f * smallestDimension, MIN_MARGIN), margin); hull->setMargin(margin); // add the points, correcting for margin diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a2ab26ca0c..e6f2b520c7 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -23,6 +23,7 @@ #include "GeometryCache.h" #include "RenderUtil.h" #include "TextureCache.h" +#include "FramebufferCache.h" #include "simple_vert.h" @@ -215,8 +216,6 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu } void DeferredLightingEffect::prepare(RenderArgs* args) { - - auto textureCache = DependencyManager::get(); gpu::Batch batch; // clear the normal and specular buffers @@ -228,29 +227,31 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { args->_context->render(batch); } +gpu::FramebufferPointer _copyFBO; + void DeferredLightingEffect::render(RenderArgs* args) { gpu::Batch batch; // perform deferred lighting, rendering to free fbo - auto textureCache = DependencyManager::get(); + auto framebufferCache = DependencyManager::get(); - QSize framebufferSize = textureCache->getFrameBufferSize(); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); // binding the first framebuffer - auto freeFBO = DependencyManager::get()->getSecondaryFramebuffer(); - batch.setFramebuffer(freeFBO); + _copyFBO = framebufferCache->getFramebuffer(); + batch.setFramebuffer(_copyFBO); batch.setViewportTransform(args->_viewport); - batch.clearColorFramebuffer(freeFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - batch.setResourceTexture(0, textureCache->getPrimaryColorTexture()); + batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); - batch.setResourceTexture(1, textureCache->getPrimaryNormalTexture()); + batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture()); - batch.setResourceTexture(2, textureCache->getPrimarySpecularTexture()); + batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture()); - batch.setResourceTexture(3, textureCache->getPrimaryDepthTexture()); + batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); float sMin = args->_viewport.x / (float)framebufferSize.width(); float sWidth = args->_viewport.z / (float)framebufferSize.width(); @@ -267,7 +268,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); if (shadowsEnabled) { - batch.setResourceTexture(4, textureCache->getShadowFramebuffer()->getDepthStencilBuffer()); + batch.setResourceTexture(4, framebufferCache->getShadowFramebuffer()->getDepthStencilBuffer()); program = _directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; @@ -294,7 +295,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { } batch.setPipeline(program); } - batch._glUniform1f(locations->shadowScale, 1.0f / textureCache->getShadowFramebuffer()->getWidth()); + batch._glUniform1f(locations->shadowScale, 1.0f / framebufferCache->getShadowFramebuffer()->getWidth()); } else { if (useSkyboxCubemap) { @@ -535,17 +536,16 @@ void DeferredLightingEffect::render(RenderArgs* args) { // End of the Lighting pass } + void DeferredLightingEffect::copyBack(RenderArgs* args) { gpu::Batch batch; - auto textureCache = DependencyManager::get(); - QSize framebufferSize = textureCache->getFrameBufferSize(); + auto framebufferCache = DependencyManager::get(); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); - auto freeFBO = DependencyManager::get()->getSecondaryFramebuffer(); - - batch.setFramebuffer(textureCache->getPrimaryFramebuffer()); + batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer()); batch.setPipeline(_blitLightBuffer); - batch.setResourceTexture(0, freeFBO->getRenderBuffer(0)); + batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0)); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); @@ -567,6 +567,7 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) { args->_context->syncCache(); args->_context->render(batch); + framebufferCache->releaseFramebuffer(_copyFBO); } void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp new file mode 100644 index 0000000000..c7cb6451f7 --- /dev/null +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -0,0 +1,128 @@ +// +// FramebufferCache.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 8/6/13. +// Copyright 2013 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 "FramebufferCache.h" + +#include + +#include + +#include +#include +#include +#include +#include "RenderUtilsLogging.h" + +static QQueue _cachedFramebuffers; + +FramebufferCache::FramebufferCache() { +} + +FramebufferCache::~FramebufferCache() { + _cachedFramebuffers.clear(); +} + +void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { + //If the size changed, we need to delete our FBOs + if (_frameBufferSize != frameBufferSize) { + _frameBufferSize = frameBufferSize; + _primaryFramebuffer.reset(); + _primaryDepthTexture.reset(); + _primaryColorTexture.reset(); + _primaryNormalTexture.reset(); + _primarySpecularTexture.reset(); + _cachedFramebuffers.clear(); + } +} + +void FramebufferCache::createPrimaryFramebuffer() { + _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + + auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _frameBufferSize.width(); + auto height = _frameBufferSize.height(); + + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + + _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); + _primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture); + _primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture); + + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); + _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); + + _primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); +} + +gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { + if (!_primaryFramebuffer) { + createPrimaryFramebuffer(); + } + return _primaryFramebuffer; +} + + + +gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() { + if (!_primaryDepthTexture) { + createPrimaryFramebuffer(); + } + return _primaryDepthTexture; +} + +gpu::TexturePointer FramebufferCache::getPrimaryColorTexture() { + if (!_primaryColorTexture) { + createPrimaryFramebuffer(); + } + return _primaryColorTexture; +} + +gpu::TexturePointer FramebufferCache::getPrimaryNormalTexture() { + if (!_primaryNormalTexture) { + createPrimaryFramebuffer(); + } + return _primaryNormalTexture; +} + +gpu::TexturePointer FramebufferCache::getPrimarySpecularTexture() { + if (!_primarySpecularTexture) { + createPrimaryFramebuffer(); + } + return _primarySpecularTexture; +} + +gpu::FramebufferPointer FramebufferCache::getFramebuffer() { + if (_cachedFramebuffers.isEmpty()) { + _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); + } + gpu::FramebufferPointer result = _cachedFramebuffers.front(); + _cachedFramebuffers.pop_front(); + return result; +} + + +void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebuffer) { + if (QSize(framebuffer->getSize().x, framebuffer->getSize().y) == _frameBufferSize) { + _cachedFramebuffers.push_back(framebuffer); + } +} + +gpu::FramebufferPointer FramebufferCache::getShadowFramebuffer() { + if (!_shadowFramebuffer) { + const int SHADOW_MAP_SIZE = 2048; + _shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE)); + } + return _shadowFramebuffer; +} diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h new file mode 100644 index 0000000000..ca01a470d9 --- /dev/null +++ b/libraries/render-utils/src/FramebufferCache.h @@ -0,0 +1,64 @@ +// +// Created by Bradley Austin Davis on 2015/07/20 +// 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 +// + +#ifndef hifi_FramebufferCache_h +#define hifi_FramebufferCache_h + +#include + +#include +#include + +namespace gpu { +class Batch; +} + +/// Stores cached textures, including render-to-texture targets. +class FramebufferCache : public Dependency { + SINGLETON_DEPENDENCY + +public: + /// Sets the desired texture resolution for the framebuffer objects. + void setFrameBufferSize(QSize frameBufferSize); + const QSize& getFrameBufferSize() const { return _frameBufferSize; } + + /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is + /// used for scene rendering. + gpu::FramebufferPointer getPrimaryFramebuffer(); + + gpu::TexturePointer getPrimaryDepthTexture(); + gpu::TexturePointer getPrimaryColorTexture(); + gpu::TexturePointer getPrimaryNormalTexture(); + gpu::TexturePointer getPrimarySpecularTexture(); + + /// Returns the framebuffer object used to render shadow maps; + gpu::FramebufferPointer getShadowFramebuffer(); + + /// Returns a free framebuffer with a single color attachment for temp or intra-frame operations + gpu::FramebufferPointer getFramebuffer(); + // TODO add sync functionality to the release, so we don't reuse a framebuffer being read from + /// Releases a free framebuffer back for reuse + void releaseFramebuffer(const gpu::FramebufferPointer& framebuffer); + +private: + FramebufferCache(); + virtual ~FramebufferCache(); + + void createPrimaryFramebuffer(); + + gpu::FramebufferPointer _primaryFramebuffer; + gpu::TexturePointer _primaryDepthTexture; + gpu::TexturePointer _primaryColorTexture; + gpu::TexturePointer _primaryNormalTexture; + gpu::TexturePointer _primarySpecularTexture; + + gpu::FramebufferPointer _shadowFramebuffer; + QSize _frameBufferSize{ 100, 100 }; +}; + +#endif // hifi_FramebufferCache_h diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index ddfcc1589c..f86d15079d 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -9,6 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TextureCache.h" + +#include + +#include +#include + #include #include #include @@ -19,21 +26,10 @@ #include #include -#include -#include #include "RenderUtilsLogging.h" -#include "TextureCache.h" - -#include - -TextureCache::TextureCache() : - _permutationNormalTexture(0), - _whiteTexture(0), - _blueTexture(0), - _frameBufferSize(100, 100) -{ +TextureCache::TextureCache() { const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE); } @@ -41,23 +37,6 @@ TextureCache::TextureCache() : TextureCache::~TextureCache() { } -void TextureCache::setFrameBufferSize(QSize frameBufferSize) { - //If the size changed, we need to delete our FBOs - if (_frameBufferSize != frameBufferSize) { - _frameBufferSize = frameBufferSize; - - _primaryFramebuffer.reset(); - _primaryDepthTexture.reset(); - _primaryColorTexture.reset(); - _primaryNormalTexture.reset(); - _primarySpecularTexture.reset(); - - _secondaryFramebuffer.reset(); - - _tertiaryFramebuffer.reset(); - } -} - // use fixed table of permutations. Could also make ordered list programmatically // and then shuffle algorithm. For testing, this ensures consistent behavior in each run. // this list taken from Ken Perlin's Improved Noise reference implementation (orig. in Java) at @@ -175,113 +154,6 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type return texture; } -void TextureCache::createPrimaryFramebuffer() { - _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - - auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _frameBufferSize.width(); - auto height = _frameBufferSize.height(); - - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - - _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); - _primaryFramebuffer->setRenderBuffer(1, _primaryNormalTexture); - _primaryFramebuffer->setRenderBuffer(2, _primarySpecularTexture); - - - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); - - _primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); -} - -gpu::FramebufferPointer TextureCache::getPrimaryFramebuffer() { - if (!_primaryFramebuffer) { - createPrimaryFramebuffer(); - } - return _primaryFramebuffer; -} - -gpu::TexturePointer TextureCache::getPrimaryDepthTexture() { - if (!_primaryDepthTexture) { - createPrimaryFramebuffer(); - } - return _primaryDepthTexture; -} - -gpu::TexturePointer TextureCache::getPrimaryColorTexture() { - if (!_primaryColorTexture) { - createPrimaryFramebuffer(); - } - return _primaryColorTexture; -} - -gpu::TexturePointer TextureCache::getPrimaryNormalTexture() { - if (!_primaryNormalTexture) { - createPrimaryFramebuffer(); - } - return _primaryNormalTexture; -} - -gpu::TexturePointer TextureCache::getPrimarySpecularTexture() { - if (!_primarySpecularTexture) { - createPrimaryFramebuffer(); - } - return _primarySpecularTexture; -} - -GLuint TextureCache::getPrimaryDepthTextureID() { - return gpu::GLBackend::getTextureID(getPrimaryDepthTexture()); -} - -void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular) { - gpu::Batch batch; - setPrimaryDrawBuffers(batch, color, normal, specular); - gpu::GLBackend::renderBatch(batch); -} - -void TextureCache::setPrimaryDrawBuffers(gpu::Batch& batch, bool color, bool normal, bool specular) { - GLenum buffers[3]; - int bufferCount = 0; - if (color) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; - } - if (normal) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; - } - if (specular) { - buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; - } - batch._glDrawBuffers(bufferCount, buffers); -} - -gpu::FramebufferPointer TextureCache::getSecondaryFramebuffer() { - if (!_secondaryFramebuffer) { - _secondaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height())); - } - return _secondaryFramebuffer; -} - -gpu::FramebufferPointer TextureCache::getTertiaryFramebuffer() { - if (!_tertiaryFramebuffer) { - _tertiaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height())); - } - return _tertiaryFramebuffer; -} - -gpu::FramebufferPointer TextureCache::getShadowFramebuffer() { - if (!_shadowFramebuffer) { - const int SHADOW_MAP_SIZE = 2048; - _shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE)); - - _shadowTexture = _shadowFramebuffer->getDepthStencilBuffer(); - } - return _shadowFramebuffer; -} - /// Returns a texture version of an image file gpu::TexturePointer TextureCache::getImageTexture(const QString& path) { QImage image = QImage(path).mirrored(false, true); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 6b4fff4f6b..8f60382e9b 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -13,8 +13,6 @@ #define hifi_TextureCache_h #include -#include - #include #include @@ -39,10 +37,6 @@ class TextureCache : public ResourceCache, public Dependency { SINGLETON_DEPENDENCY public: - /// Sets the desired texture resolution for the framebuffer objects. - void setFrameBufferSize(QSize frameBufferSize); - const QSize& getFrameBufferSize() const { return _frameBufferSize; } - /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and /// the second, a set of random unit vectors to be used as noise gradients. @@ -67,33 +61,6 @@ public: NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false, const QByteArray& content = QByteArray()); - /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is - /// used for scene rendering. - gpu::FramebufferPointer getPrimaryFramebuffer(); - - gpu::TexturePointer getPrimaryDepthTexture(); - gpu::TexturePointer getPrimaryColorTexture(); - gpu::TexturePointer getPrimaryNormalTexture(); - gpu::TexturePointer getPrimarySpecularTexture(); - - /// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering. - uint32_t getPrimaryDepthTextureID(); - - /// Enables or disables draw buffers on the primary framebuffer. Note: the primary framebuffer must be bound. - void setPrimaryDrawBuffers(bool color, bool normal = false, bool specular = false); - void setPrimaryDrawBuffers(gpu::Batch& batch, bool color, bool normal = false, bool specular = false); - - /// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full - /// screen effects. - gpu::FramebufferPointer getSecondaryFramebuffer(); - - /// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full - /// screen effects. - gpu::FramebufferPointer getTertiaryFramebuffer(); - - /// Returns the framebuffer object used to render shadow maps; - gpu::FramebufferPointer getShadowFramebuffer(); - protected: virtual QSharedPointer createResource(const QUrl& url, @@ -110,23 +77,7 @@ private: gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; - QHash > _dilatableNetworkTextures; - - gpu::TexturePointer _primaryDepthTexture; - gpu::TexturePointer _primaryColorTexture; - gpu::TexturePointer _primaryNormalTexture; - gpu::TexturePointer _primarySpecularTexture; - gpu::FramebufferPointer _primaryFramebuffer; - void createPrimaryFramebuffer(); - - gpu::FramebufferPointer _secondaryFramebuffer; - gpu::FramebufferPointer _tertiaryFramebuffer; - - gpu::FramebufferPointer _shadowFramebuffer; - gpu::TexturePointer _shadowTexture; - - QSize _frameBufferSize; }; /// A simple object wrapper for an OpenGL texture. diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 604cb46731..7a5daf7a17 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -80,7 +80,7 @@ public: RENDER_DEBUG_SIMULATION_OWNERSHIP = 2, }; - RenderArgs(gpu::Context* context = nullptr, + RenderArgs(std::shared_ptr context = nullptr, OctreeRenderer* renderer = nullptr, ViewFrustum* viewFrustum = nullptr, float sizeScale = 1.0f, @@ -102,7 +102,7 @@ public: _shouldRender(shouldRender) { } - gpu::Context* _context = nullptr; + std::shared_ptr _context = nullptr; OctreeRenderer* _renderer = nullptr; ViewFrustum* _viewFrustum = nullptr; glm::ivec4 _viewport{ 0, 0, 1, 1 }; diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 916cdf8659..d581f12473 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OffscreenUi.h" -#include #include #include #include