mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-10 22:58:45 +02:00
Merge branch 'brown' of https://github.com/samcake/hifi into brown
This commit is contained in:
commit
fc7e2edc51
58 changed files with 1231 additions and 656 deletions
|
@ -33,6 +33,7 @@
|
||||||
#include <SoundCache.h>
|
#include <SoundCache.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Deck.h>
|
#include <recording/Deck.h>
|
||||||
#include <recording/Recorder.h>
|
#include <recording/Recorder.h>
|
||||||
#include <recording/Frame.h>
|
#include <recording/Frame.h>
|
||||||
|
@ -53,7 +54,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
||||||
|
|
||||||
Agent::Agent(ReceivedMessage& message) :
|
Agent::Agent(ReceivedMessage& message) :
|
||||||
ThreadedAssignment(message),
|
ThreadedAssignment(message),
|
||||||
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
|
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES)
|
||||||
|
{
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||||
|
|
||||||
ResourceManager::init();
|
ResourceManager::init();
|
||||||
|
@ -64,12 +66,16 @@ Agent::Agent(ReceivedMessage& message) :
|
||||||
DependencyManager::set<SoundCache>();
|
DependencyManager::set<SoundCache>();
|
||||||
DependencyManager::set<AudioScriptingInterface>();
|
DependencyManager::set<AudioScriptingInterface>();
|
||||||
DependencyManager::set<AudioInjectorManager>();
|
DependencyManager::set<AudioInjectorManager>();
|
||||||
|
|
||||||
DependencyManager::set<recording::Deck>();
|
DependencyManager::set<recording::Deck>();
|
||||||
DependencyManager::set<recording::Recorder>();
|
DependencyManager::set<recording::Recorder>();
|
||||||
DependencyManager::set<RecordingScriptingInterface>();
|
DependencyManager::set<recording::ClipCache>();
|
||||||
|
|
||||||
DependencyManager::set<ScriptCache>();
|
DependencyManager::set<ScriptCache>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
|
||||||
|
|
||||||
|
DependencyManager::set<RecordingScriptingInterface>();
|
||||||
|
|
||||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||||
|
|
||||||
packetReceiver.registerListenerForTypes(
|
packetReceiver.registerListenerForTypes(
|
||||||
|
@ -327,6 +333,8 @@ void Agent::executeScript() {
|
||||||
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
||||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||||
|
|
||||||
|
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine.get());
|
||||||
|
|
||||||
// setup an Avatar for the script to use
|
// setup an Avatar for the script to use
|
||||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||||
|
|
||||||
|
@ -470,6 +478,8 @@ void Agent::executeScript() {
|
||||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||||
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
||||||
|
|
||||||
|
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||||
|
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,8 +763,19 @@ void Agent::aboutToFinish() {
|
||||||
|
|
||||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||||
DependencyManager::destroy<AudioInjectorManager>();
|
DependencyManager::destroy<AudioInjectorManager>();
|
||||||
|
|
||||||
|
// destroy all other created dependencies
|
||||||
|
DependencyManager::destroy<ScriptCache>();
|
||||||
DependencyManager::destroy<ScriptEngines>();
|
DependencyManager::destroy<ScriptEngines>();
|
||||||
|
|
||||||
|
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||||
|
DependencyManager::destroy<SoundCache>();
|
||||||
|
DependencyManager::destroy<AudioScriptingInterface>();
|
||||||
|
|
||||||
|
DependencyManager::destroy<recording::Deck>();
|
||||||
|
DependencyManager::destroy<recording::Recorder>();
|
||||||
|
DependencyManager::destroy<recording::ClipCache>();
|
||||||
|
|
||||||
emit stopAvatarAudioTimer();
|
emit stopAvatarAudioTimer();
|
||||||
_avatarAudioTimerThread.quit();
|
_avatarAudioTimerThread.quit();
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,6 @@ class Agent : public ThreadedAssignment {
|
||||||
public:
|
public:
|
||||||
Agent(ReceivedMessage& message);
|
Agent(ReceivedMessage& message);
|
||||||
|
|
||||||
void setIsAvatar(bool isAvatar);
|
|
||||||
bool isAvatar() const { return _isAvatar; }
|
|
||||||
|
|
||||||
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
||||||
|
|
||||||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||||
|
@ -66,6 +63,9 @@ public slots:
|
||||||
void run() override;
|
void run() override;
|
||||||
void playAvatarSound(SharedSoundPointer avatarSound);
|
void playAvatarSound(SharedSoundPointer avatarSound);
|
||||||
|
|
||||||
|
void setIsAvatar(bool isAvatar);
|
||||||
|
bool isAvatar() const { return _isAvatar; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void requestScript();
|
void requestScript();
|
||||||
void scriptRequestFinished();
|
void scriptRequestFinished();
|
||||||
|
|
|
@ -118,6 +118,7 @@
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
#include <UserActivityLogger.h>
|
#include <UserActivityLogger.h>
|
||||||
#include <UsersScriptingInterface.h>
|
#include <UsersScriptingInterface.h>
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Deck.h>
|
#include <recording/Deck.h>
|
||||||
#include <recording/Recorder.h>
|
#include <recording/Recorder.h>
|
||||||
#include <shared/StringHelpers.h>
|
#include <shared/StringHelpers.h>
|
||||||
|
@ -467,6 +468,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<StatTracker>();
|
DependencyManager::set<StatTracker>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
||||||
DependencyManager::set<Preferences>();
|
DependencyManager::set<Preferences>();
|
||||||
|
DependencyManager::set<recording::ClipCache>();
|
||||||
DependencyManager::set<recording::Deck>();
|
DependencyManager::set<recording::Deck>();
|
||||||
DependencyManager::set<recording::Recorder>();
|
DependencyManager::set<recording::Recorder>();
|
||||||
DependencyManager::set<AddressManager>();
|
DependencyManager::set<AddressManager>();
|
||||||
|
@ -1884,9 +1886,9 @@ void Application::initializeGL() {
|
||||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||||
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
||||||
_renderEngine->addJob<RenderForwardTask>("Forward", items.get<RenderFetchCullSortTask::Output>());
|
_renderEngine->addJob<RenderForwardTask>("Forward", items);
|
||||||
} else {
|
} else {
|
||||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items.get<RenderFetchCullSortTask::Output>());
|
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||||
}
|
}
|
||||||
_renderEngine->load();
|
_renderEngine->load();
|
||||||
_renderEngine->registerScene(_main3DScene);
|
_renderEngine->registerScene(_main3DScene);
|
||||||
|
@ -5439,6 +5441,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
// AvatarManager has some custom types
|
// AvatarManager has some custom types
|
||||||
AvatarManager::registerMetaTypes(scriptEngine);
|
AvatarManager::registerMetaTypes(scriptEngine);
|
||||||
|
|
||||||
|
// give the script engine to the RecordingScriptingInterface for its callbacks
|
||||||
|
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
|
||||||
|
|
||||||
if (property(hifi::properties::TEST).isValid()) {
|
if (property(hifi::properties::TEST).isValid()) {
|
||||||
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
#include "AddressManager.h"
|
#include "AddressManager.h"
|
||||||
#include <Rig.h>
|
#include <Rig.h>
|
||||||
|
|
||||||
|
#include "ZoneRenderer.h"
|
||||||
|
|
||||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||||
AbstractScriptingServicesInterface* scriptingServices) :
|
AbstractScriptingServicesInterface* scriptingServices) :
|
||||||
_wantScripts(wantScripts),
|
_wantScripts(wantScripts),
|
||||||
|
@ -266,6 +268,9 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_layeredZones.apply();
|
_layeredZones.apply();
|
||||||
|
|
||||||
|
applyLayeredZones();
|
||||||
|
|
||||||
didUpdate = true;
|
didUpdate = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -343,6 +348,30 @@ void EntityTreeRenderer::forceRecheckEntities() {
|
||||||
_avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
_avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityTreeRenderer::applyLayeredZones() {
|
||||||
|
// from the list of zones we are going to build a selection list the Render Item corresponding to the zones
|
||||||
|
// in the expected layered order and update the scene with it
|
||||||
|
auto scene = _viewState->getMain3DScene();
|
||||||
|
if (scene) {
|
||||||
|
render::Transaction transaction;
|
||||||
|
render::ItemIDs list;
|
||||||
|
|
||||||
|
for (auto& zone : _layeredZones) {
|
||||||
|
auto id = std::dynamic_pointer_cast<RenderableZoneEntityItem>(zone.zone)->getRenderItemID();
|
||||||
|
list.push_back(id);
|
||||||
|
}
|
||||||
|
render::Selection selection("RankedZones", list);
|
||||||
|
transaction.resetSelection(selection);
|
||||||
|
|
||||||
|
scene->enqueueTransaction(transaction);
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "EntityTreeRenderer::applyLayeredZones(), Unexpected null scene, possibly during application shutdown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
auto scene = DependencyManager::get<SceneScriptingInterface>();
|
||||||
|
|
|
@ -150,6 +150,7 @@ private:
|
||||||
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||||
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
|
||||||
bool applySkyboxAndHasAmbient();
|
bool applySkyboxAndHasAmbient();
|
||||||
|
bool applyLayeredZones();
|
||||||
|
|
||||||
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false, const bool unloadFirst = false);
|
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false, const bool unloadFirst = false);
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
|
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
|
||||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
|
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::Transaction& transaction) override;
|
||||||
|
|
||||||
|
render::ItemID getRenderItemID() const { return _myMetaItem; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
||||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
|
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error = std::string());
|
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject, std::string& error);
|
||||||
#else
|
#else
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error = std::string());
|
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, std::string& error);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error = std::string());
|
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -421,6 +421,8 @@ protected:
|
||||||
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||||
};
|
};
|
||||||
ElementResource getFormatFromGLUniform(GLenum gltype);
|
ElementResource getFormatFromGLUniform(GLenum gltype);
|
||||||
|
static const GLint UNUSED_SLOT {-1};
|
||||||
|
static bool isUnusedSlot(GLint binding) { return (binding == UNUSED_SLOT); }
|
||||||
virtual int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
virtual int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
||||||
virtual int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
virtual int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
||||||
|
|
|
@ -331,11 +331,6 @@ int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slot
|
||||||
return uniformsCount;
|
return uniformsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GLint UNUSED_SLOT = -1;
|
|
||||||
bool isUnusedSlot(GLint binding) {
|
|
||||||
return (binding == UNUSED_SLOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||||
GLint buffersCount = 0;
|
GLint buffersCount = 0;
|
||||||
|
|
||||||
|
@ -393,9 +388,9 @@ int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet&
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the binding is 0, or the binding maps to an already used binding
|
// If the binding is 0, or the binding maps to an already used binding
|
||||||
if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) {
|
if (info.binding == 0 || !isUnusedSlot(uniformBufferSlotMap[info.binding])) {
|
||||||
// If no binding was assigned then just do it finding a free slot
|
// If no binding was assigned then just do it finding a free slot
|
||||||
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot);
|
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), GLBackend::isUnusedSlot);
|
||||||
if (slotIt != uniformBufferSlotMap.end()) {
|
if (slotIt != uniformBufferSlotMap.end()) {
|
||||||
info.binding = slotIt - uniformBufferSlotMap.begin();
|
info.binding = slotIt - uniformBufferSlotMap.begin();
|
||||||
glUniformBlockBinding(glprogram, info.index, info.binding);
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
@ -518,30 +513,5 @@ void GLBackend::makeProgramBindings(ShaderObject& shaderObject) {
|
||||||
if (!linked) {
|
if (!linked) {
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||||
}
|
}
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
|
||||||
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
|
||||||
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,25 +82,6 @@ int GL41Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssboCount;
|
return ssboCount;
|
||||||
|
|
||||||
/*glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount);
|
|
||||||
if (ssboCount > 0) {
|
|
||||||
GLint maxNameLength = 0;
|
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxNameLength);
|
|
||||||
std::vector<GLchar> nameBytes(maxNameLength);
|
|
||||||
|
|
||||||
for (GLint b = 0; b < ssboCount; b++) {
|
|
||||||
GLint length;
|
|
||||||
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data());
|
|
||||||
|
|
||||||
std::string bufferName(nameBytes.data());
|
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - " << bufferName.c_str();
|
|
||||||
|
|
||||||
static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
|
||||||
resourceBuffers.insert(Shader::Slot(bufferName, b, element, -1));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
return ssboCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
||||||
|
@ -110,77 +91,16 @@ void GL41Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
GLuint glprogram = shaderObject.glprogram;
|
||||||
GLint loc = -1;
|
GLint loc = -1;
|
||||||
|
|
||||||
//Check for gpu specific attribute slotBindings
|
GLBackend::makeProgramBindings(shaderObject);
|
||||||
loc = glGetAttribLocation(glprogram, "inPosition");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::POSITION) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inNormal");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inColor");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::COLOR) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTexCoord0");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTangent");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTexCoord1");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link again to take into account the assigned attrib location
|
|
||||||
glLinkProgram(glprogram);
|
|
||||||
|
|
||||||
GLint linked = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
|
||||||
if (!linked) {
|
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
|
||||||
}
|
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
// now assign the ubo binding, then DON't relink!
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
//Check for gpu specific uniform slotBindings
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
|
||||||
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
glProgramUniform1i(glprogram, loc, GL41Backend::TRANSFORM_OBJECT_SLOT);
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
shaderObject.transformObjectSlot = GL41Backend::TRANSFORM_OBJECT_SLOT;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
|
|
|
@ -38,15 +38,9 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!batch._objects.empty()) {
|
if (!batch._objects.empty()) {
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _transform._objectBuffer);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sysmem.getSize(), sysmem.readData(), GL_STREAM_DRAW);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
#else
|
|
||||||
glBindBuffer(GL_TEXTURE_BUFFER, _transform._objectBuffer);
|
glBindBuffer(GL_TEXTURE_BUFFER, _transform._objectBuffer);
|
||||||
glBufferData(GL_TEXTURE_BUFFER, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_DYNAMIC_DRAW);
|
glBufferData(GL_TEXTURE_BUFFER, batch._objects.size() * sizeof(Batch::TransformObject), batch._objects.data(), GL_DYNAMIC_DRAW);
|
||||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!batch._namedData.empty()) {
|
if (!batch._namedData.empty()) {
|
||||||
|
@ -64,15 +58,11 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
glActiveTexture(GL_TEXTURE0 + GL41Backend::TRANSFORM_OBJECT_SLOT);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer);
|
|
||||||
#else
|
|
||||||
glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT);
|
|
||||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||||
if (!batch._objects.empty()) {
|
if (!batch._objects.empty()) {
|
||||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
|
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
CHECK_GL_ERROR();
|
CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#define INCREMENTAL_TRANSFER 0
|
#define INCREMENTAL_TRANSFER 0
|
||||||
#define THREADED_TEXTURE_BUFFERING 1
|
#define THREADED_TEXTURE_BUFFERING 1
|
||||||
|
#define GPU_SSBO_TRANSFORM_OBJECT 1
|
||||||
|
|
||||||
namespace gpu { namespace gl45 {
|
namespace gpu { namespace gl45 {
|
||||||
|
|
||||||
|
@ -30,6 +31,13 @@ class GL45Backend : public GLBackend {
|
||||||
friend class Context;
|
friend class Context;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
|
static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot
|
||||||
|
#else
|
||||||
|
static const GLint TRANSFORM_OBJECT_SLOT { 31 }; // TBO binding slot
|
||||||
|
#endif
|
||||||
|
|
||||||
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
||||||
GL45Backend() : Parent() {}
|
GL45Backend() : Parent() {}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,93 @@ using namespace gpu::gl45;
|
||||||
|
|
||||||
// GLSL version
|
// GLSL version
|
||||||
std::string GL45Backend::getBackendShaderHeader() const {
|
std::string GL45Backend::getBackendShaderHeader() const {
|
||||||
return std::string("#version 450 core");
|
const char header[] =
|
||||||
|
R"GLSL(#version 450 core
|
||||||
|
#define GPU_GL450
|
||||||
|
)GLSL"
|
||||||
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
|
R"GLSL(#define GPU_SSBO_TRANSFORM_OBJECT 1)GLSL"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
return std::string(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||||
|
GLint buffersCount = 0;
|
||||||
|
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount);
|
||||||
|
|
||||||
|
// fast exit
|
||||||
|
if (buffersCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint maxNumResourceBufferSlots = 0;
|
||||||
|
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots);
|
||||||
|
std::vector<GLint> resourceBufferSlotMap(maxNumResourceBufferSlots, -1);
|
||||||
|
|
||||||
|
struct ResourceBlockInfo {
|
||||||
|
using Vector = std::vector<ResourceBlockInfo>;
|
||||||
|
const GLuint index{ 0 };
|
||||||
|
const std::string name;
|
||||||
|
GLint binding{ -1 };
|
||||||
|
GLint size{ 0 };
|
||||||
|
|
||||||
|
static std::string getName(GLuint glprogram, GLuint i) {
|
||||||
|
static const GLint NAME_LENGTH = 256;
|
||||||
|
GLint length = 0;
|
||||||
|
GLchar nameBuffer[NAME_LENGTH];
|
||||||
|
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer);
|
||||||
|
return std::string(nameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
|
||||||
|
GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE};
|
||||||
|
glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResourceBlockInfo::Vector resourceBlocks;
|
||||||
|
resourceBlocks.reserve(buffersCount);
|
||||||
|
for (int i = 0; i < buffersCount; i++) {
|
||||||
|
resourceBlocks.push_back(ResourceBlockInfo(glprogram, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
auto requestedBinding = slotBindings.find(info.name);
|
||||||
|
if (requestedBinding != slotBindings.end()) {
|
||||||
|
info.binding = (*requestedBinding)._location;
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
resourceBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
if (slotBindings.count(info.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the binding is -1, or the binding maps to an already used binding
|
||||||
|
if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) {
|
||||||
|
// If no binding was assigned then just do it finding a free slot
|
||||||
|
auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), GLBackend::isUnusedSlot);
|
||||||
|
if (slotIt != resourceBufferSlotMap.end()) {
|
||||||
|
info.binding = slotIt - resourceBufferSlotMap.begin();
|
||||||
|
glUniformBlockBinding(glprogram, info.index, info.binding);
|
||||||
|
} else {
|
||||||
|
// This should never happen, an active ssbo cannot find an available slot among the max available?!
|
||||||
|
info.binding = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceBufferSlotMap[info.binding] = info.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& info : resourceBlocks) {
|
||||||
|
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
||||||
|
resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
|
||||||
|
}
|
||||||
|
return buffersCount;
|
||||||
|
/*
|
||||||
GLint ssboCount = 0;
|
GLint ssboCount = 0;
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount);
|
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount);
|
||||||
if (ssboCount > 0) {
|
if (ssboCount > 0) {
|
||||||
|
@ -28,15 +111,25 @@ int GL45Backend::makeResourceBufferSlots(GLuint glprogram, const Shader::Binding
|
||||||
for (GLint b = 0; b < ssboCount; b++) {
|
for (GLint b = 0; b < ssboCount; b++) {
|
||||||
GLint length;
|
GLint length;
|
||||||
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data());
|
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data());
|
||||||
|
|
||||||
std::string bufferName(nameBytes.data());
|
std::string bufferName(nameBytes.data());
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - " << bufferName.c_str();
|
|
||||||
|
GLenum props = GL_BUFFER_BINDING;
|
||||||
|
GLint binding = -1;
|
||||||
|
glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, b, 1, &props, 1, nullptr, &binding);
|
||||||
|
|
||||||
|
auto requestedBinding = slotBindings.find(std::string(bufferName));
|
||||||
|
if (requestedBinding != slotBindings.end()) {
|
||||||
|
if (binding != (*requestedBinding)._location) {
|
||||||
|
binding = (*requestedBinding)._location;
|
||||||
|
glShaderStorageBlockBinding(glprogram, b, binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
||||||
resourceBuffers.insert(Shader::Slot(bufferName, b, element, -1));
|
resourceBuffers.insert(Shader::Slot(bufferName, binding, element, -1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ssboCount;
|
return ssboCount;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
||||||
|
@ -46,75 +139,22 @@ void GL45Backend::makeProgramBindings(gl::ShaderObject& shaderObject) {
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
GLuint glprogram = shaderObject.glprogram;
|
||||||
GLint loc = -1;
|
GLint loc = -1;
|
||||||
|
|
||||||
//Check for gpu specific attribute slotBindings
|
GLBackend::makeProgramBindings(shaderObject);
|
||||||
loc = glGetAttribLocation(glprogram, "inPosition");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::POSITION) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inNormal");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inColor");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::COLOR) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTexCoord0");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTangent");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inTexCoord1");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
|
|
||||||
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
|
|
||||||
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link again to take into account the assigned attrib location
|
|
||||||
glLinkProgram(glprogram);
|
|
||||||
|
|
||||||
GLint linked = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
|
||||||
if (!linked) {
|
|
||||||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
|
||||||
}
|
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
// now assign the ubo binding, then DON't relink!
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
//Check for gpu specific uniform slotBindings
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
glShaderStorageBlockBinding(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT);
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
glProgramUniform1i(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT);
|
||||||
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,10 @@ void GL45Backend::initTransform() {
|
||||||
_transform._objectBuffer = transformBuffers[0];
|
_transform._objectBuffer = transformBuffers[0];
|
||||||
_transform._cameraBuffer = transformBuffers[1];
|
_transform._cameraBuffer = transformBuffers[1];
|
||||||
_transform._drawCallInfoBuffer = transformBuffers[2];
|
_transform._drawCallInfoBuffer = transformBuffers[2];
|
||||||
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
|
#else
|
||||||
glCreateTextures(GL_TEXTURE_BUFFER, 1, &_transform._objectBufferTexture);
|
glCreateTextures(GL_TEXTURE_BUFFER, 1, &_transform._objectBufferTexture);
|
||||||
|
#endif
|
||||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||||
while (_transform._cameraUboSize < cameraSize) {
|
while (_transform._cameraUboSize < cameraSize) {
|
||||||
_transform._cameraUboSize += _uboAlignment;
|
_transform._cameraUboSize += _uboAlignment;
|
||||||
|
@ -53,10 +56,10 @@ void GL45Backend::transferTransformState(const Batch& batch) const {
|
||||||
glNamedBufferData(_transform._drawCallInfoBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW);
|
glNamedBufferData(_transform._drawCallInfoBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GL45Backend::TRANSFORM_OBJECT_SLOT, _transform._objectBuffer);
|
||||||
#else
|
#else
|
||||||
glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT);
|
glActiveTexture(GL_TEXTURE0 + GL45Backend::TRANSFORM_OBJECT_SLOT);
|
||||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||||
glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer);
|
glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,12 +30,6 @@ class QDebug;
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
enum ReservedSlot {
|
enum ReservedSlot {
|
||||||
|
|
||||||
#ifdef GPU_SSBO_DRAW_CALL_INFO
|
|
||||||
TRANSFORM_OBJECT_SLOT = 14,
|
|
||||||
#else
|
|
||||||
TRANSFORM_OBJECT_SLOT = 31,
|
|
||||||
#endif
|
|
||||||
TRANSFORM_CAMERA_SLOT = 15,
|
TRANSFORM_CAMERA_SLOT = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -119,15 +119,14 @@ struct TransformObject {
|
||||||
|
|
||||||
layout(location=15) in ivec2 _drawCallInfo;
|
layout(location=15) in ivec2 _drawCallInfo;
|
||||||
|
|
||||||
<@if FALSE @>
|
#if defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||||
// Disable SSBOs for now
|
|
||||||
layout(std140) buffer transformObjectBuffer {
|
layout(std140) buffer transformObjectBuffer {
|
||||||
TransformObject _object[];
|
TransformObject _object[];
|
||||||
};
|
};
|
||||||
TransformObject getTransformObject() {
|
TransformObject getTransformObject() {
|
||||||
return _object[_drawCallInfo.x];
|
return _object[_drawCallInfo.x];
|
||||||
}
|
}
|
||||||
<@else@>
|
#else
|
||||||
uniform samplerBuffer transformObjectBuffer;
|
uniform samplerBuffer transformObjectBuffer;
|
||||||
|
|
||||||
TransformObject getTransformObject() {
|
TransformObject getTransformObject() {
|
||||||
|
@ -145,7 +144,8 @@ TransformObject getTransformObject() {
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
<@endif@>
|
#endif
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
|
||||||
QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
||||||
if (!networkAccessManagers.hasLocalData()) {
|
if (!networkAccessManagers.hasLocalData()) {
|
||||||
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *networkAccessManagers.localData();
|
return *networkAccessManagers.localData();
|
||||||
|
|
|
@ -5,8 +5,12 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "ClipCache.h"
|
#include "ClipCache.h"
|
||||||
#include "impl/PointerClip.h"
|
#include "impl/PointerClip.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
NetworkClipLoader::NetworkClipLoader(const QUrl& url) :
|
NetworkClipLoader::NetworkClipLoader(const QUrl& url) :
|
||||||
|
@ -21,18 +25,28 @@ void NetworkClip::init(const QByteArray& clipData) {
|
||||||
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
||||||
_clip->init(data);
|
_clip->init(data);
|
||||||
finishedLoading(true);
|
finishedLoading(true);
|
||||||
|
emit clipLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipCache& ClipCache::instance() {
|
ClipCache::ClipCache(QObject* parent) :
|
||||||
static ClipCache _instance;
|
ResourceCache(parent)
|
||||||
return _instance;
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
||||||
return ResourceCache::getResource(url, QUrl(), nullptr).staticCast<NetworkClipLoader>();
|
if (QThread::currentThread() != thread()) {
|
||||||
|
NetworkClipLoaderPointer result;
|
||||||
|
QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getResource(url).staticCast<NetworkClipLoader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
||||||
|
qCDebug(recordingLog) << "Loading recording at" << url;
|
||||||
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
|
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,26 +30,34 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkClipLoader : public Resource {
|
class NetworkClipLoader : public Resource {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NetworkClipLoader(const QUrl& url);
|
NetworkClipLoader(const QUrl& url);
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
ClipPointer getClip() { return _clip; }
|
ClipPointer getClip() { return _clip; }
|
||||||
bool completed() { return _failedToLoad || isLoaded(); }
|
bool completed() { return _failedToLoad || isLoaded(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void clipLoaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const NetworkClip::Pointer _clip;
|
const NetworkClip::Pointer _clip;
|
||||||
};
|
};
|
||||||
|
|
||||||
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
|
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
|
||||||
|
|
||||||
class ClipCache : public ResourceCache {
|
class ClipCache : public ResourceCache, public Dependency {
|
||||||
public:
|
Q_OBJECT
|
||||||
static ClipCache& instance();
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
public slots:
|
||||||
NetworkClipLoaderPointer getClipLoader(const QUrl& url);
|
NetworkClipLoaderPointer getClipLoader(const QUrl& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClipCache(QObject* parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
#include <render/CullTask.h>
|
#include <render/CullTask.h>
|
||||||
|
#include <render/FilterTask.h>
|
||||||
#include <render/SortTask.h>
|
#include <render/SortTask.h>
|
||||||
#include <render/DrawTask.h>
|
#include <render/DrawTask.h>
|
||||||
#include <render/DrawStatus.h>
|
#include <render/DrawStatus.h>
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
#include "FramebufferCache.h"
|
#include "FramebufferCache.h"
|
||||||
#include "HitEffect.h"
|
#include "HitEffect.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
#include "ZoneRenderer.h"
|
||||||
|
|
||||||
#include "AmbientOcclusionEffect.h"
|
#include "AmbientOcclusionEffect.h"
|
||||||
#include "AntialiasingEffect.h"
|
#include "AntialiasingEffect.h"
|
||||||
|
@ -48,7 +50,9 @@ using namespace render;
|
||||||
extern void initOverlay3DPipelines(render::ShapePlumber& plumber);
|
extern void initOverlay3DPipelines(render::ShapePlumber& plumber);
|
||||||
extern void initDeferredPipelines(render::ShapePlumber& plumber);
|
extern void initDeferredPipelines(render::ShapePlumber& plumber);
|
||||||
|
|
||||||
RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
|
||||||
|
auto items = input.get<Input>();
|
||||||
|
|
||||||
// Prepare the ShapePipelines
|
// Prepare the ShapePipelines
|
||||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
initDeferredPipelines(*shapePlumber);
|
initDeferredPipelines(*shapePlumber);
|
||||||
|
@ -65,129 +69,130 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
||||||
|
|
||||||
// Filter the non antialiaased overlays
|
// Filter the non antialiaased overlays
|
||||||
const int LAYER_NO_AA = 3;
|
const int LAYER_NO_AA = 3;
|
||||||
const auto nonAAOverlays = addJob<FilterItemLayer>("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA);
|
const auto nonAAOverlays = task.addJob<FilterLayeredItems>("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA);
|
||||||
|
|
||||||
// Prepare deferred, generate the shared Deferred Frame Transform
|
// Prepare deferred, generate the shared Deferred Frame Transform
|
||||||
const auto deferredFrameTransform = addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform");
|
const auto deferredFrameTransform = task.addJob<GenerateDeferredFrameTransform>("DeferredFrameTransform");
|
||||||
const auto lightingModel = addJob<MakeLightingModel>("LightingModel");
|
const auto lightingModel = task.addJob<MakeLightingModel>("LightingModel");
|
||||||
|
|
||||||
|
|
||||||
// GPU jobs: Start preparing the primary, deferred and lighting buffer
|
// GPU jobs: Start preparing the primary, deferred and lighting buffer
|
||||||
const auto primaryFramebuffer = addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
|
const auto primaryFramebuffer = task.addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
|
||||||
|
|
||||||
const auto opaqueRangeTimer = addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
|
const auto opaqueRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
|
||||||
|
|
||||||
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying();
|
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying();
|
||||||
const auto prepareDeferredOutputs = addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
|
const auto prepareDeferredOutputs = task.addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
|
||||||
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
|
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
|
||||||
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
|
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
|
||||||
|
|
||||||
// Render opaque objects in DeferredBuffer
|
// Render opaque objects in DeferredBuffer
|
||||||
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
|
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
|
||||||
addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
|
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
|
||||||
|
|
||||||
// Once opaque is all rendered create stencil background
|
// Once opaque is all rendered create stencil background
|
||||||
addJob<DrawStencilDeferred>("DrawOpaqueStencil", deferredFramebuffer);
|
task.addJob<DrawStencilDeferred>("DrawOpaqueStencil", deferredFramebuffer);
|
||||||
|
|
||||||
addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
|
task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
|
||||||
|
|
||||||
|
|
||||||
// Opaque all rendered
|
// Opaque all rendered
|
||||||
|
|
||||||
// Linear Depth Pass
|
// Linear Depth Pass
|
||||||
const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying();
|
const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying();
|
||||||
const auto linearDepthPassOutputs = addJob<LinearDepthPass>("LinearDepth", linearDepthPassInputs);
|
const auto linearDepthPassOutputs = task.addJob<LinearDepthPass>("LinearDepth", linearDepthPassInputs);
|
||||||
const auto linearDepthTarget = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(0);
|
const auto linearDepthTarget = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(0);
|
||||||
|
|
||||||
// Curvature pass
|
// Curvature pass
|
||||||
const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
||||||
const auto surfaceGeometryPassOutputs = addJob<SurfaceGeometryPass>("SurfaceGeometry", surfaceGeometryPassInputs);
|
const auto surfaceGeometryPassOutputs = task.addJob<SurfaceGeometryPass>("SurfaceGeometry", surfaceGeometryPassInputs);
|
||||||
const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(0);
|
const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(0);
|
||||||
const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(1);
|
const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(1);
|
||||||
const auto midCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(2);
|
const auto midCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(2);
|
||||||
const auto lowCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(3);
|
const auto lowCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(3);
|
||||||
|
|
||||||
// Simply update the scattering resource
|
// Simply update the scattering resource
|
||||||
const auto scatteringResource = addJob<SubsurfaceScattering>("Scattering");
|
const auto scatteringResource = task.addJob<SubsurfaceScattering>("Scattering");
|
||||||
|
|
||||||
// AO job
|
// AO job
|
||||||
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
|
||||||
const auto ambientOcclusionOutputs = addJob<AmbientOcclusionEffect>("AmbientOcclusion", ambientOcclusionInputs);
|
const auto ambientOcclusionOutputs = task.addJob<AmbientOcclusionEffect>("AmbientOcclusion", ambientOcclusionInputs);
|
||||||
const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(0);
|
const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(0);
|
||||||
const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(1);
|
const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(1);
|
||||||
|
|
||||||
|
|
||||||
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
||||||
addJob<DrawLight>("DrawLight", lights);
|
task.addJob<DrawLight>("DrawLight", lights);
|
||||||
|
|
||||||
// Light Clustering
|
// Light Clustering
|
||||||
// Create the cluster grid of lights, cpu job for now
|
// Create the cluster grid of lights, cpu job for now
|
||||||
const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying();
|
const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying();
|
||||||
const auto lightClusters = addJob<LightClusteringPass>("LightClustering", lightClusteringPassInputs);
|
const auto lightClusters = task.addJob<LightClusteringPass>("LightClustering", lightClusteringPassInputs);
|
||||||
|
|
||||||
|
|
||||||
// DeferredBuffer is complete, now let's shade it into the LightingBuffer
|
// DeferredBuffer is complete, now let's shade it into the LightingBuffer
|
||||||
const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
||||||
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).hasVarying();
|
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).hasVarying();
|
||||||
|
|
||||||
addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
|
task.addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
|
||||||
|
|
||||||
// Use Stencil and draw background in Lighting buffer to complete filling in the opaque
|
// Use Stencil and draw background in Lighting buffer to complete filling in the opaque
|
||||||
const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
|
const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying();
|
||||||
addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
|
task.addJob<DrawBackgroundDeferred>("DrawBackgroundDeferred", backgroundInputs);
|
||||||
|
|
||||||
|
|
||||||
// Render transparent objects forward in LightingBuffer
|
// Render transparent objects forward in LightingBuffer
|
||||||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();
|
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();
|
||||||
addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||||
|
|
||||||
// LIght Cluster Grid Debuging job
|
// LIght Cluster Grid Debuging job
|
||||||
{
|
{
|
||||||
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying();
|
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying();
|
||||||
addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
task.addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto toneAndPostRangeTimer = addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
|
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
|
||||||
|
|
||||||
// Lighting Buffer ready for tone mapping
|
// Lighting Buffer ready for tone mapping
|
||||||
const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer));
|
const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer));
|
||||||
addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
|
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
|
||||||
|
|
||||||
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
||||||
addJob<DrawBounds>("DrawMetaBounds", metas);
|
task.addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||||
addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||||
addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||||
|
|
||||||
|
task.addJob<ZoneRendererTask>("ZoneRenderer", opaques);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlays
|
// Overlays
|
||||||
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying();
|
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying();
|
||||||
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying();
|
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying();
|
||||||
addJob<DrawOverlay3D>("DrawOverlay3DOpaque", overlayOpaquesInputs, true);
|
task.addJob<DrawOverlay3D>("DrawOverlay3DOpaque", overlayOpaquesInputs, true);
|
||||||
addJob<DrawOverlay3D>("DrawOverlay3DTransparent", overlayTransparentsInputs, false);
|
task.addJob<DrawOverlay3D>("DrawOverlay3DTransparent", overlayTransparentsInputs, false);
|
||||||
|
|
||||||
{ // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer
|
{ // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer
|
||||||
addJob<DrawBounds>("DrawOverlayOpaqueBounds", overlayOpaques);
|
task.addJob<DrawBounds>("DrawOverlayOpaqueBounds", overlayOpaques);
|
||||||
addJob<DrawBounds>("DrawOverlayTransparentBounds", overlayTransparents);
|
task.addJob<DrawBounds>("DrawOverlayTransparentBounds", overlayTransparents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugging stages
|
// Debugging stages
|
||||||
{
|
{
|
||||||
// Debugging Deferred buffer job
|
// Debugging Deferred buffer job
|
||||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
|
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
|
||||||
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
task.addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
||||||
|
|
||||||
const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
||||||
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying();
|
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying();
|
||||||
addJob<DebugSubsurfaceScattering>("DebugScattering", debugSubsurfaceScatteringInputs);
|
task.addJob<DebugSubsurfaceScattering>("DebugScattering", debugSubsurfaceScatteringInputs);
|
||||||
|
|
||||||
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
|
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
|
||||||
addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
|
task.addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
|
||||||
|
|
||||||
|
|
||||||
// Scene Octree Debugging job
|
// Scene Octree Debugging job
|
||||||
{
|
{
|
||||||
addJob<DrawSceneOctree>("DrawSceneOctree", spatialSelection);
|
task.addJob<DrawSceneOctree>("DrawSceneOctree", spatialSelection);
|
||||||
addJob<DrawItemSelection>("DrawItemSelection", spatialSelection);
|
task.addJob<DrawItemSelection>("DrawItemSelection", spatialSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status icon rendering job
|
// Status icon rendering job
|
||||||
|
@ -195,22 +200,22 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
||||||
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
||||||
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
||||||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath, NetworkTexture::STRICT_TEXTURE);
|
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath, NetworkTexture::STRICT_TEXTURE);
|
||||||
addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
|
task.addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// AA job to be revisited
|
// AA job to be revisited
|
||||||
addJob<Antialiasing>("Antialiasing", primaryFramebuffer);
|
task.addJob<Antialiasing>("Antialiasing", primaryFramebuffer);
|
||||||
|
|
||||||
// Draw 2DWeb non AA
|
// Draw 2DWeb non AA
|
||||||
const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying();
|
const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying();
|
||||||
addJob<DrawOverlay3D>("Draw2DWebSurfaces", nonAAOverlaysInputs, false);
|
task.addJob<DrawOverlay3D>("Draw2DWebSurfaces", nonAAOverlaysInputs, false);
|
||||||
|
|
||||||
addJob<EndGPURangeTimer>("ToneAndPostRangeTimer", toneAndPostRangeTimer);
|
task.addJob<EndGPURangeTimer>("ToneAndPostRangeTimer", toneAndPostRangeTimer);
|
||||||
|
|
||||||
// Blit!
|
// Blit!
|
||||||
addJob<Blit>("Blit", primaryFramebuffer);
|
task.addJob<Blit>("Blit", primaryFramebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeginGPURangeTimer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) {
|
void BeginGPURangeTimer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) {
|
||||||
|
|
|
@ -192,11 +192,14 @@ public:
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderDeferredTask : public render::Task {
|
class RenderDeferredTask {
|
||||||
public:
|
public:
|
||||||
using JobModel = Model<RenderDeferredTask>;
|
using Input = RenderFetchCullSortTask::Output;
|
||||||
|
using JobModel = render::Task::ModelI<RenderDeferredTask, Input>;
|
||||||
|
|
||||||
RenderDeferredTask(RenderFetchCullSortTask::Output items);
|
RenderDeferredTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderDeferredTask_h
|
#endif // hifi_RenderDeferredTask_h
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
using namespace render;
|
using namespace render;
|
||||||
extern void initForwardPipelines(ShapePlumber& plumber);
|
extern void initForwardPipelines(ShapePlumber& plumber);
|
||||||
|
|
||||||
RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) {
|
void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
|
||||||
|
auto items = input.get<Input>();
|
||||||
|
|
||||||
// Prepare the ShapePipelines
|
// Prepare the ShapePipelines
|
||||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
initForwardPipelines(*shapePlumber);
|
initForwardPipelines(*shapePlumber);
|
||||||
|
@ -44,17 +46,17 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) {
|
||||||
const auto background = items[RenderFetchCullSortTask::BACKGROUND];
|
const auto background = items[RenderFetchCullSortTask::BACKGROUND];
|
||||||
const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION];
|
const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION];
|
||||||
|
|
||||||
const auto framebuffer = addJob<PrepareFramebuffer>("PrepareFramebuffer");
|
const auto framebuffer = task.addJob<PrepareFramebuffer>("PrepareFramebuffer");
|
||||||
|
|
||||||
addJob<Draw>("DrawOpaques", opaques, shapePlumber);
|
task.addJob<Draw>("DrawOpaques", opaques, shapePlumber);
|
||||||
addJob<Stencil>("Stencil");
|
task.addJob<Stencil>("Stencil");
|
||||||
addJob<DrawBackground>("DrawBackground", background);
|
task.addJob<DrawBackground>("DrawBackground", background);
|
||||||
|
|
||||||
// Bounds do not draw on stencil buffer, so they must come last
|
// Bounds do not draw on stencil buffer, so they must come last
|
||||||
addJob<DrawBounds>("DrawBounds", opaques);
|
task.addJob<DrawBounds>("DrawBounds", opaques);
|
||||||
|
|
||||||
// Blit!
|
// Blit!
|
||||||
addJob<Blit>("Blit", framebuffer);
|
task.addJob<Blit>("Blit", framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext,
|
void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext,
|
||||||
|
|
|
@ -16,11 +16,14 @@
|
||||||
#include <render/RenderFetchCullSortTask.h>
|
#include <render/RenderFetchCullSortTask.h>
|
||||||
#include "LightingModel.h"
|
#include "LightingModel.h"
|
||||||
|
|
||||||
class RenderForwardTask : public render::Task {
|
class RenderForwardTask {
|
||||||
public:
|
public:
|
||||||
using JobModel = Model<RenderForwardTask>;
|
using Input = RenderFetchCullSortTask::Output;
|
||||||
|
using JobModel = render::Task::ModelI<RenderForwardTask, Input>;
|
||||||
|
|
||||||
RenderForwardTask(RenderFetchCullSortTask::Output items);
|
RenderForwardTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrepareFramebuffer {
|
class PrepareFramebuffer {
|
||||||
|
|
|
@ -90,7 +90,7 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) {
|
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
|
||||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
||||||
|
|
||||||
// Prepare the ShapePipeline
|
// Prepare the ShapePipeline
|
||||||
|
@ -115,28 +115,28 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) {
|
||||||
skinProgram, state);
|
skinProgram, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto cachedMode = addJob<RenderShadowSetup>("Setup");
|
const auto cachedMode = task.addJob<RenderShadowSetup>("Setup");
|
||||||
|
|
||||||
// CPU jobs:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||||
const auto shadowSelection = addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);
|
const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);
|
||||||
const auto culledShadowSelection = addJob<CullSpatialSelection>("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter);
|
const auto culledShadowSelection = task.addJob<CullSpatialSelection>("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter);
|
||||||
|
|
||||||
// Sort
|
// Sort
|
||||||
const auto sortedPipelines = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
|
const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
|
||||||
const auto sortedShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
|
const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
|
||||||
|
|
||||||
// GPU jobs: Render to shadow map
|
// GPU jobs: Render to shadow map
|
||||||
addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
||||||
|
|
||||||
addJob<RenderShadowTeardown>("Teardown", cachedMode);
|
task.addJob<RenderShadowTeardown>("Teardown", cachedMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowTask::configure(const Config& configuration) {
|
void RenderShadowTask::configure(const Config& configuration) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);
|
DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.enabled);
|
||||||
// This is a task, so must still propogate configure() to its Jobs
|
// This is a task, so must still propogate configure() to its Jobs
|
||||||
Task::configure(configuration);
|
// Task::configure(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowSetup::run(const SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, Output& output) {
|
void RenderShadowSetup::run(const SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, Output& output) {
|
||||||
|
|
|
@ -41,12 +41,13 @@ signals:
|
||||||
void dirty();
|
void dirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderShadowTask : public render::Task {
|
class RenderShadowTask {
|
||||||
public:
|
public:
|
||||||
using Config = RenderShadowTaskConfig;
|
using Config = RenderShadowTaskConfig;
|
||||||
using JobModel = Model<RenderShadowTask, Config>;
|
using JobModel = render::Task::Model<RenderShadowTask, Config>;
|
||||||
|
|
||||||
RenderShadowTask(render::CullFunctor shouldRender);
|
RenderShadowTask() {}
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender);
|
||||||
|
|
||||||
void configure(const Config& configuration);
|
void configure(const Config& configuration);
|
||||||
};
|
};
|
||||||
|
|
27
libraries/render-utils/src/ZoneRenderer.cpp
Normal file
27
libraries/render-utils/src/ZoneRenderer.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// ZoneRenderer.cpp
|
||||||
|
// render/src/render-utils
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 4/4/2017.
|
||||||
|
// Copyright 2017 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 "ZoneRenderer.h"
|
||||||
|
|
||||||
|
#include <render/FilterTask.h>
|
||||||
|
#include <render/DrawTask.h>
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" };
|
||||||
|
|
||||||
|
void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& ouput) {
|
||||||
|
|
||||||
|
const auto zoneItems = task.addJob<render::SelectSortItems>("FilterZones", input, ZONES_SELECTION.c_str());
|
||||||
|
|
||||||
|
// just draw them...
|
||||||
|
task.addJob<DrawBounds>("DrawZones", zoneItems);
|
||||||
|
}
|
||||||
|
|
52
libraries/render-utils/src/ZoneRenderer.h
Normal file
52
libraries/render-utils/src/ZoneRenderer.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// ZoneRenderer.h
|
||||||
|
// render/src/render-utils
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 4/4/2017.
|
||||||
|
// Copyright 2017 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_ZoneRenderer_h
|
||||||
|
#define hifi_ZoneRenderer_h
|
||||||
|
|
||||||
|
#include "render/Engine.h"
|
||||||
|
|
||||||
|
class ZoneRendererConfig : public render::Task::Config {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
|
||||||
|
public:
|
||||||
|
|
||||||
|
ZoneRendererConfig() : render::Task::Config(false) {}
|
||||||
|
|
||||||
|
int maxDrawn { -1 };
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dirty();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZoneRendererTask {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const render::Selection::Name ZONES_SELECTION;
|
||||||
|
|
||||||
|
|
||||||
|
using Inputs = render::ItemBounds;
|
||||||
|
using Config = ZoneRendererConfig;
|
||||||
|
using JobModel = render::Task::ModelI<ZoneRendererTask, Inputs, Config>;
|
||||||
|
|
||||||
|
ZoneRendererTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||||
|
|
||||||
|
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _maxDrawn; // initialized by Config
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
#include <OctreeUtils.h>
|
#include <OctreeUtils.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <ViewFrustum.h>
|
|
||||||
#include <gpu/Context.h>
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
@ -306,19 +304,3 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
||||||
|
|
||||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
|
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FilterItemLayer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
|
|
||||||
// Clear previous values
|
|
||||||
outItems.clear();
|
|
||||||
|
|
||||||
// For each item, filter it into one bucket
|
|
||||||
for (auto itemBound : inItems) {
|
|
||||||
auto& item = scene->getItem(itemBound.id);
|
|
||||||
if (item.getLayer() == _keepLayer) {
|
|
||||||
outItems.emplace_back(itemBound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -109,85 +109,6 @@ namespace render {
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& inSelection, ItemBounds& outItems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& inSelection, ItemBounds& outItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilterItemSelectionConfig : public Job::Config {
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(int numItems READ getNumItems)
|
|
||||||
public:
|
|
||||||
int numItems{ 0 };
|
|
||||||
int getNumItems() { return numItems; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class FilterItemSelection {
|
|
||||||
public:
|
|
||||||
using Config = FilterItemSelectionConfig;
|
|
||||||
using JobModel = Job::ModelIO<FilterItemSelection, ItemBounds, ItemBounds, Config>;
|
|
||||||
|
|
||||||
FilterItemSelection() {}
|
|
||||||
FilterItemSelection(const ItemFilter& filter) :
|
|
||||||
_filter(filter) {}
|
|
||||||
|
|
||||||
ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() };
|
|
||||||
|
|
||||||
void configure(const Config& config);
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MultiFilterItemConfig : public Job::Config {
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(int numItems READ getNumItems)
|
|
||||||
public:
|
|
||||||
int numItems{ 0 };
|
|
||||||
int getNumItems() { return numItems; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <int NUM_FILTERS>
|
|
||||||
class MultiFilterItem {
|
|
||||||
public:
|
|
||||||
using ItemFilterArray = std::array<ItemFilter, NUM_FILTERS>;
|
|
||||||
using ItemBoundsArray = VaryingArray<ItemBounds, NUM_FILTERS>;
|
|
||||||
using Config = MultiFilterItemConfig;
|
|
||||||
using JobModel = Job::ModelIO<MultiFilterItem, ItemBounds, ItemBoundsArray, Config>;
|
|
||||||
|
|
||||||
MultiFilterItem() {}
|
|
||||||
MultiFilterItem(const ItemFilterArray& filters) :
|
|
||||||
_filters(filters) {}
|
|
||||||
|
|
||||||
ItemFilterArray _filters;
|
|
||||||
|
|
||||||
void configure(const Config& config) {}
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBoundsArray& outItems) {
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
|
|
||||||
// Clear previous values
|
|
||||||
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
|
||||||
outItems[i].template edit<ItemBounds>().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each item, filter it into one bucket
|
|
||||||
for (auto itemBound : inItems) {
|
|
||||||
auto& item = scene->getItem(itemBound.id);
|
|
||||||
auto itemKey = item.getKey();
|
|
||||||
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
|
||||||
if (_filters[i].test(itemKey)) {
|
|
||||||
outItems[i].template edit<ItemBounds>().emplace_back(itemBound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class FilterItemLayer {
|
|
||||||
public:
|
|
||||||
using JobModel = Job::ModelIO<FilterItemLayer, ItemBounds, ItemBounds>;
|
|
||||||
|
|
||||||
FilterItemLayer() {}
|
|
||||||
FilterItemLayer(int keepLayer) :
|
|
||||||
_keepLayer(keepLayer) {}
|
|
||||||
|
|
||||||
int _keepLayer { 0 };
|
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_CullTask_h;
|
#endif // hifi_render_CullTask_h;
|
|
@ -148,8 +148,7 @@ const gpu::PipelinePointer DrawBounds::getPipeline() {
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
_cornerLocation = program->getUniforms().findLocation("inBoundPos");
|
_colorLocation = program->getUniforms().findLocation("inColor");
|
||||||
_scaleLocation = program->getUniforms().findLocation("inBoundDim");
|
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||||
|
@ -166,7 +165,7 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
const Inputs& items) {
|
const Inputs& items) {
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
auto numItems = items.size();
|
uint32_t numItems = (uint32_t) items.size();
|
||||||
if (numItems == 0) {
|
if (numItems == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -192,19 +191,9 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
|
|
||||||
// Bind program
|
// Bind program
|
||||||
batch.setPipeline(getPipeline());
|
batch.setPipeline(getPipeline());
|
||||||
// assert(_cornerLocation >= 0);
|
|
||||||
// assert(_scaleLocation >= 0);
|
|
||||||
|
|
||||||
// Render bounds
|
|
||||||
/* for (const auto& item : items) {
|
|
||||||
batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner()));
|
|
||||||
batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale()));
|
|
||||||
|
|
||||||
static const int NUM_VERTICES_PER_CUBE = 24;
|
|
||||||
batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
glm::vec4 color(glm::vec3(0.0f), -(float) numItems);
|
||||||
|
batch._glUniform4fv(_colorLocation, 1, (const float*)(&color));
|
||||||
batch.setResourceBuffer(0, _drawBuffer);
|
batch.setResourceBuffer(0, _drawBuffer);
|
||||||
|
|
||||||
static const int NUM_VERTICES_PER_CUBE = 24;
|
static const int NUM_VERTICES_PER_CUBE = 24;
|
||||||
|
|
|
@ -52,7 +52,7 @@ class DrawBounds {
|
||||||
public:
|
public:
|
||||||
class Config : public render::JobConfig {
|
class Config : public render::JobConfig {
|
||||||
public:
|
public:
|
||||||
Config() : JobConfig(false) {}
|
Config(bool enabled = false) : JobConfig(enabled) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using Inputs = render::ItemBounds;
|
using Inputs = render::ItemBounds;
|
||||||
|
@ -65,9 +65,9 @@ public:
|
||||||
private:
|
private:
|
||||||
const gpu::PipelinePointer getPipeline();
|
const gpu::PipelinePointer getPipeline();
|
||||||
gpu::PipelinePointer _boundsPipeline;
|
gpu::PipelinePointer _boundsPipeline;
|
||||||
int _cornerLocation { -1 };
|
|
||||||
int _scaleLocation { -1 };
|
|
||||||
gpu::BufferPointer _drawBuffer;
|
gpu::BufferPointer _drawBuffer;
|
||||||
|
|
||||||
|
int _colorLocation { -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,22 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
Engine::Engine() :
|
class EngineTask {
|
||||||
|
public:
|
||||||
|
|
||||||
|
using JobModel = Task::Model<EngineTask>;
|
||||||
|
|
||||||
|
EngineTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const Varying& in, Varying& out) {
|
||||||
|
task.addJob<EngineStats>("Stats");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Engine::Engine() : Task("Engine", EngineTask::JobModel::create()),
|
||||||
_sceneContext(std::make_shared<SceneContext>()),
|
_sceneContext(std::make_shared<SceneContext>()),
|
||||||
_renderContext(std::make_shared<RenderContext>()) {
|
_renderContext(std::make_shared<RenderContext>())
|
||||||
addJob<EngineStats>("Stats");
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::load() {
|
void Engine::load() {
|
||||||
|
|
113
libraries/render/src/render/FilterTask.cpp
Normal file
113
libraries/render/src/render/FilterTask.cpp
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
//
|
||||||
|
// FilterTask.cpp
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/2/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "FilterTask.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <OctreeUtils.h>
|
||||||
|
#include <PerfStat.h>
|
||||||
|
#include <ViewFrustum.h>
|
||||||
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
void FilterLayeredItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
|
||||||
|
// Clear previous values
|
||||||
|
outItems.clear();
|
||||||
|
|
||||||
|
// For each item, filter it into one bucket
|
||||||
|
for (auto itemBound : inItems) {
|
||||||
|
auto& item = scene->getItem(itemBound.id);
|
||||||
|
if (item.getLayer() == _keepLayer) {
|
||||||
|
outItems.emplace_back(itemBound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliceItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
outItems.clear();
|
||||||
|
std::static_pointer_cast<Config>(renderContext->jobConfig)->setNumItems((int)inItems.size());
|
||||||
|
|
||||||
|
if (_rangeOffset < 0) return;
|
||||||
|
|
||||||
|
int maxItemNum = std::min(_rangeOffset + _rangeLength, (int)inItems.size());
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = _rangeOffset; i < maxItemNum; i++) {
|
||||||
|
outItems.emplace_back(inItems[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
auto selection = sceneContext->_scene->getSelection(_name);
|
||||||
|
const auto& selectedItems = selection.getItems();
|
||||||
|
outItems.clear();
|
||||||
|
|
||||||
|
if (!selectedItems.empty()) {
|
||||||
|
outItems.reserve(selectedItems.size());
|
||||||
|
|
||||||
|
for (auto src : inItems) {
|
||||||
|
if (selection.contains(src.id)) {
|
||||||
|
outItems.emplace_back(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
|
auto selection = sceneContext->_scene->getSelection(_name);
|
||||||
|
const auto& selectedItems = selection.getItems();
|
||||||
|
outItems.clear();
|
||||||
|
|
||||||
|
if (!selectedItems.empty()) {
|
||||||
|
struct Pair { int src; int dst; };
|
||||||
|
std::vector<Pair> indices;
|
||||||
|
indices.reserve(selectedItems.size());
|
||||||
|
|
||||||
|
// Collect
|
||||||
|
for (int srcIndex = 0; ((std::size_t) srcIndex < inItems.size()) && (indices.size() < selectedItems.size()) ; srcIndex++ ) {
|
||||||
|
int index = selection.find(inItems[srcIndex].id);
|
||||||
|
if (index != Selection::NOT_FOUND) {
|
||||||
|
indices.emplace_back( Pair{ srcIndex, index } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then sort
|
||||||
|
if (!indices.empty()) {
|
||||||
|
std::sort(indices.begin(), indices.end(), [] (Pair a, Pair b) {
|
||||||
|
return (a.dst < b.dst);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& pair: indices) {
|
||||||
|
outItems.emplace_back(inItems[pair.src]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetaToSubItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemIDs& outItems) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
|
||||||
|
// Now we have a selection of items to render
|
||||||
|
outItems.clear();
|
||||||
|
|
||||||
|
for (auto idBound : inItems) {
|
||||||
|
auto& item = scene->getItem(idBound.id);
|
||||||
|
|
||||||
|
item.fetchMetaSubItems(outItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
147
libraries/render/src/render/FilterTask.h
Normal file
147
libraries/render/src/render/FilterTask.h
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
//
|
||||||
|
// FilterTask.h
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/2/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_render_FilterTask_h
|
||||||
|
#define hifi_render_FilterTask_h
|
||||||
|
|
||||||
|
#include "Engine.h"
|
||||||
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class MultiFilterItemsConfig : public Job::Config {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int numItems READ getNumItems)
|
||||||
|
public:
|
||||||
|
int numItems{ 0 };
|
||||||
|
int getNumItems() { return numItems; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter inbound of items into multiple buckets defined from the job's Filter array
|
||||||
|
template <int NUM_FILTERS>
|
||||||
|
class MultiFilterItems {
|
||||||
|
public:
|
||||||
|
using ItemFilterArray = std::array<ItemFilter, NUM_FILTERS>;
|
||||||
|
using ItemBoundsArray = VaryingArray<ItemBounds, NUM_FILTERS>;
|
||||||
|
using Config = MultiFilterItemsConfig;
|
||||||
|
using JobModel = Job::ModelIO<MultiFilterItems, ItemBounds, ItemBoundsArray, Config>;
|
||||||
|
|
||||||
|
MultiFilterItems() {}
|
||||||
|
MultiFilterItems(const ItemFilterArray& filters) :
|
||||||
|
_filters(filters) {}
|
||||||
|
|
||||||
|
ItemFilterArray _filters;
|
||||||
|
|
||||||
|
void configure(const Config& config) {}
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBoundsArray& outItems) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
|
||||||
|
// Clear previous values
|
||||||
|
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
||||||
|
outItems[i].template edit<ItemBounds>().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each item, filter it into one bucket
|
||||||
|
for (auto itemBound : inItems) {
|
||||||
|
auto& item = scene->getItem(itemBound.id);
|
||||||
|
auto itemKey = item.getKey();
|
||||||
|
for (size_t i = 0; i < NUM_FILTERS; i++) {
|
||||||
|
if (_filters[i].test(itemKey)) {
|
||||||
|
outItems[i].template edit<ItemBounds>().emplace_back(itemBound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter the items belonging to the job's keep layer
|
||||||
|
class FilterLayeredItems {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<FilterLayeredItems, ItemBounds, ItemBounds>;
|
||||||
|
|
||||||
|
FilterLayeredItems() {}
|
||||||
|
FilterLayeredItems(int keepLayer) :
|
||||||
|
_keepLayer(keepLayer) {}
|
||||||
|
|
||||||
|
int _keepLayer { 0 };
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SliceItems job config defining the slice range
|
||||||
|
class SliceItemsConfig : public Job::Config {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int rangeOffset MEMBER rangeOffset)
|
||||||
|
Q_PROPERTY(int rangeLength MEMBER rangeLength)
|
||||||
|
Q_PROPERTY(int numItems READ getNumItems NOTIFY dirty())
|
||||||
|
int numItems { 0 };
|
||||||
|
public:
|
||||||
|
int rangeOffset{ -1 };
|
||||||
|
int rangeLength{ 1 };
|
||||||
|
int getNumItems() { return numItems; }
|
||||||
|
void setNumItems(int n) { numItems = n; emit dirty(); }
|
||||||
|
signals:
|
||||||
|
void dirty();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep items in the job slice (defined from config)
|
||||||
|
class SliceItems {
|
||||||
|
public:
|
||||||
|
using Config = SliceItemsConfig;
|
||||||
|
using JobModel = Job::ModelIO<SliceItems, ItemBounds, ItemBounds, Config>;
|
||||||
|
|
||||||
|
SliceItems() {}
|
||||||
|
int _rangeOffset{ -1 };
|
||||||
|
int _rangeLength{ 1 };
|
||||||
|
|
||||||
|
void configure(const Config& config) {
|
||||||
|
_rangeOffset = config.rangeOffset;
|
||||||
|
_rangeLength = config.rangeLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep items belonging to the job selection
|
||||||
|
class SelectItems {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<SelectItems, ItemBounds, ItemBounds>;
|
||||||
|
|
||||||
|
std::string _name;
|
||||||
|
SelectItems(const Selection::Name& name) : _name(name) {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Same as SelectItems but reorder the output to match the selection order
|
||||||
|
class SelectSortItems {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<SelectSortItems, ItemBounds, ItemBounds>;
|
||||||
|
|
||||||
|
std::string _name;
|
||||||
|
SelectSortItems(const Selection::Name& name) : _name(name) {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
// From meta-Items, generate the sub-items
|
||||||
|
class MetaToSubItems {
|
||||||
|
public:
|
||||||
|
using JobModel = Job::ModelIO<MetaToSubItems, ItemBounds, ItemIDs>;
|
||||||
|
|
||||||
|
MetaToSubItems() {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemIDs& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_render_FilterTask_h;
|
|
@ -12,21 +12,22 @@
|
||||||
#include "RenderFetchCullSortTask.h"
|
#include "RenderFetchCullSortTask.h"
|
||||||
|
|
||||||
#include "CullTask.h"
|
#include "CullTask.h"
|
||||||
|
#include "FilterTask.h"
|
||||||
#include "SortTask.h"
|
#include "SortTask.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) {
|
void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) {
|
||||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
||||||
|
|
||||||
// CPU jobs:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||||
const auto spatialSelection = addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
|
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
|
||||||
const auto culledSpatialSelection = addJob<CullSpatialSelection>("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter);
|
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter);
|
||||||
|
|
||||||
// Overlays are not culled
|
// Overlays are not culled
|
||||||
const auto nonspatialSelection = addJob<FetchNonspatialItems>("FetchOverlaySelection");
|
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchOverlaySelection");
|
||||||
|
|
||||||
// Multi filter visible items into different buckets
|
// Multi filter visible items into different buckets
|
||||||
const int NUM_SPATIAL_FILTERS = 4;
|
const int NUM_SPATIAL_FILTERS = 4;
|
||||||
|
@ -36,34 +37,34 @@ RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) {
|
||||||
const int LIGHT_BUCKET = 2;
|
const int LIGHT_BUCKET = 2;
|
||||||
const int META_BUCKET = 3;
|
const int META_BUCKET = 3;
|
||||||
const int BACKGROUND_BUCKET = 2;
|
const int BACKGROUND_BUCKET = 2;
|
||||||
MultiFilterItem<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
|
MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
|
||||||
ItemFilter::Builder::opaqueShape(),
|
ItemFilter::Builder::opaqueShape(),
|
||||||
ItemFilter::Builder::transparentShape(),
|
ItemFilter::Builder::transparentShape(),
|
||||||
ItemFilter::Builder::light(),
|
ItemFilter::Builder::light(),
|
||||||
ItemFilter::Builder::meta()
|
ItemFilter::Builder::meta()
|
||||||
} };
|
} };
|
||||||
MultiFilterItem<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
|
MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
|
||||||
ItemFilter::Builder::opaqueShape(),
|
ItemFilter::Builder::opaqueShape(),
|
||||||
ItemFilter::Builder::transparentShape(),
|
ItemFilter::Builder::transparentShape(),
|
||||||
ItemFilter::Builder::background()
|
ItemFilter::Builder::background()
|
||||||
} };
|
} };
|
||||||
const auto filteredSpatialBuckets =
|
const auto filteredSpatialBuckets =
|
||||||
addJob<MultiFilterItem<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)
|
task.addJob<MultiFilterItems<NUM_SPATIAL_FILTERS>>("FilterSceneSelection", culledSpatialSelection, spatialFilters)
|
||||||
.get<MultiFilterItem<NUM_SPATIAL_FILTERS>::ItemBoundsArray>();
|
.get<MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemBoundsArray>();
|
||||||
const auto filteredNonspatialBuckets =
|
const auto filteredNonspatialBuckets =
|
||||||
addJob<MultiFilterItem<NUM_NON_SPATIAL_FILTERS>>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters)
|
task.addJob<MultiFilterItems<NUM_NON_SPATIAL_FILTERS>>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters)
|
||||||
.get<MultiFilterItem<NUM_NON_SPATIAL_FILTERS>::ItemBoundsArray>();
|
.get<MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemBoundsArray>();
|
||||||
|
|
||||||
// Extract opaques / transparents / lights / overlays
|
// Extract opaques / transparents / lights / overlays
|
||||||
const auto opaques = addJob<DepthSortItems>("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
const auto opaques = task.addJob<DepthSortItems>("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
||||||
const auto transparents = addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
const auto transparents = task.addJob<DepthSortItems>("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
||||||
const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
|
const auto lights = filteredSpatialBuckets[LIGHT_BUCKET];
|
||||||
const auto metas = filteredSpatialBuckets[META_BUCKET];
|
const auto metas = filteredSpatialBuckets[META_BUCKET];
|
||||||
|
|
||||||
const auto overlayOpaques = addJob<DepthSortItems>("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
const auto overlayOpaques = task.addJob<DepthSortItems>("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]);
|
||||||
const auto overlayTransparents = addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
const auto overlayTransparents = task.addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
|
||||||
const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
|
const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
|
||||||
|
|
||||||
setOutput(Output{{
|
output = Varying(Output{{
|
||||||
opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }});
|
opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
#include "CullTask.h"
|
#include "CullTask.h"
|
||||||
|
|
||||||
class RenderFetchCullSortTask : public render::Task {
|
class RenderFetchCullSortTask {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Buckets {
|
enum Buckets {
|
||||||
|
@ -34,9 +34,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
using Output = std::array<render::Varying, Buckets::NUM_BUCKETS>;
|
using Output = std::array<render::Varying, Buckets::NUM_BUCKETS>;
|
||||||
using JobModel = ModelO<RenderFetchCullSortTask>;
|
using JobModel = render::Task::ModelO<RenderFetchCullSortTask, Output>;
|
||||||
|
|
||||||
RenderFetchCullSortTask(render::CullFunctor cullFunctor);
|
RenderFetchCullSortTask() {}
|
||||||
|
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderFetchCullSortTask_h
|
#endif // hifi_RenderFetchCullSortTask_h
|
||||||
|
|
|
@ -18,8 +18,8 @@ using namespace render;
|
||||||
|
|
||||||
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
|
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||||
if (payload) {
|
if (payload) {
|
||||||
_resetItems.push_back(id);
|
_resetItems.emplace_back(id);
|
||||||
_resetPayloads.push_back(payload);
|
_resetPayloads.emplace_back(payload);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!";
|
qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!";
|
||||||
removeItem(id);
|
removeItem(id);
|
||||||
|
@ -27,12 +27,16 @@ void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::removeItem(ItemID id) {
|
void Transaction::removeItem(ItemID id) {
|
||||||
_removedItems.push_back(id);
|
_removedItems.emplace_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
|
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
|
||||||
_updatedItems.push_back(id);
|
_updatedItems.emplace_back(id);
|
||||||
_updateFunctors.push_back(functor);
|
_updateFunctors.emplace_back(functor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transaction::resetSelection(const Selection& selection) {
|
||||||
|
_resetSelections.emplace_back(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transaction::merge(const Transaction& transaction) {
|
void Transaction::merge(const Transaction& transaction) {
|
||||||
|
@ -41,8 +45,10 @@ void Transaction::merge(const Transaction& transaction) {
|
||||||
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
|
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
|
||||||
_updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end());
|
_updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end());
|
||||||
_updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end());
|
_updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end());
|
||||||
|
_resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Scene::Scene(glm::vec3 origin, float size) :
|
Scene::Scene(glm::vec3 origin, float size) :
|
||||||
_masterSpatialTree(origin, size)
|
_masterSpatialTree(origin, size)
|
||||||
{
|
{
|
||||||
|
@ -112,6 +118,13 @@ void Scene::processTransactionQueue() {
|
||||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||||
_numAllocatedItems.exchange(maxID);
|
_numAllocatedItems.exchange(maxID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (consolidatedTransaction.touchTransactions()) {
|
||||||
|
std::unique_lock<std::mutex> lock(_selectionsMutex);
|
||||||
|
|
||||||
|
// resets and potential NEW items
|
||||||
|
resetSelections(consolidatedTransaction._resetSelections);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
|
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
|
||||||
|
@ -202,3 +215,25 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
|
||||||
updateFunctor++;
|
updateFunctor++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THis fucntion is thread safe
|
||||||
|
Selection Scene::getSelection(const Selection::Name& name) const {
|
||||||
|
std::unique_lock<std::mutex> lock(_selectionsMutex);
|
||||||
|
auto found = _selections.find(name);
|
||||||
|
if (found == _selections.end()) {
|
||||||
|
return Selection();
|
||||||
|
} else {
|
||||||
|
return (*found).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::resetSelections(const Selections& selections) {
|
||||||
|
for (auto selection : selections) {
|
||||||
|
auto found = _selections.find(selection.getName());
|
||||||
|
if (found == _selections.end()) {
|
||||||
|
_selections.insert(SelectionMap::value_type(selection.getName(), selection));
|
||||||
|
} else {
|
||||||
|
(*found).second = selection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
#include "SpatialTree.h"
|
#include "SpatialTree.h"
|
||||||
|
#include "Selection.h"
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ public:
|
||||||
Transaction() {}
|
Transaction() {}
|
||||||
~Transaction() {}
|
~Transaction() {}
|
||||||
|
|
||||||
|
// Item transactions
|
||||||
void resetItem(ItemID id, const PayloadPointer& payload);
|
void resetItem(ItemID id, const PayloadPointer& payload);
|
||||||
void removeItem(ItemID id);
|
void removeItem(ItemID id);
|
||||||
|
|
||||||
|
@ -43,14 +45,22 @@ public:
|
||||||
void updateItem(ItemID id, const UpdateFunctorPointer& functor);
|
void updateItem(ItemID id, const UpdateFunctorPointer& functor);
|
||||||
void updateItem(ItemID id) { updateItem(id, nullptr); }
|
void updateItem(ItemID id) { updateItem(id, nullptr); }
|
||||||
|
|
||||||
|
// Selection transactions
|
||||||
|
void resetSelection(const Selection& selection);
|
||||||
|
|
||||||
void merge(const Transaction& transaction);
|
void merge(const Transaction& transaction);
|
||||||
|
|
||||||
|
// Checkers if there is work to do when processing the transaction
|
||||||
|
bool touchTransactions() const { return !_resetSelections.empty(); }
|
||||||
|
|
||||||
ItemIDs _resetItems;
|
ItemIDs _resetItems;
|
||||||
Payloads _resetPayloads;
|
Payloads _resetPayloads;
|
||||||
ItemIDs _removedItems;
|
ItemIDs _removedItems;
|
||||||
ItemIDs _updatedItems;
|
ItemIDs _updatedItems;
|
||||||
UpdateFunctors _updateFunctors;
|
UpdateFunctors _updateFunctors;
|
||||||
|
|
||||||
|
Selections _resetSelections;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
typedef std::queue<Transaction> TransactionQueue;
|
typedef std::queue<Transaction> TransactionQueue;
|
||||||
|
@ -81,6 +91,10 @@ public:
|
||||||
// Process the pending transactions queued
|
// Process the pending transactions queued
|
||||||
void processTransactionQueue();
|
void processTransactionQueue();
|
||||||
|
|
||||||
|
// Access a particular selection (empty if doesn't exist)
|
||||||
|
// Thread safe
|
||||||
|
Selection getSelection(const Selection::Name& name) const;
|
||||||
|
|
||||||
// This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues
|
// This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues
|
||||||
|
|
||||||
// Access a particular item form its ID
|
// Access a particular item form its ID
|
||||||
|
@ -114,6 +128,17 @@ protected:
|
||||||
void removeItems(const ItemIDs& ids);
|
void removeItems(const ItemIDs& ids);
|
||||||
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
|
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
|
||||||
|
|
||||||
|
|
||||||
|
// The Selection map
|
||||||
|
mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method
|
||||||
|
SelectionMap _selections;
|
||||||
|
|
||||||
|
void resetSelections(const Selections& selections);
|
||||||
|
// More actions coming to selections soon:
|
||||||
|
// void removeFromSelection(const Selection& selection);
|
||||||
|
// void appendToSelection(const Selection& selection);
|
||||||
|
// void mergeWithSelection(const Selection& selection);
|
||||||
|
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
68
libraries/render/src/render/Selection.cpp
Normal file
68
libraries/render/src/render/Selection.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// Selection.cpp
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 4/4/2017.
|
||||||
|
// Copyright 2017 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 "Selection.h"
|
||||||
|
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
|
||||||
|
Selection::~Selection() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection::Selection() :
|
||||||
|
_name(),
|
||||||
|
_items()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection::Selection(const Selection& selection) :
|
||||||
|
_name(selection._name),
|
||||||
|
_items(selection._items)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection& Selection::operator= (const Selection& selection) {
|
||||||
|
_name = (selection._name);
|
||||||
|
_items = (selection._items);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection::Selection(Selection&& selection) :
|
||||||
|
_name(selection._name),
|
||||||
|
_items(selection._items)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Selection& Selection::operator= (Selection&& selection) {
|
||||||
|
_name = (selection._name);
|
||||||
|
_items = (selection._items);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection::Selection(const Name& name, const ItemIDs& items) :
|
||||||
|
_name(name),
|
||||||
|
_items(items)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int Selection::find(ItemID id) const {
|
||||||
|
int index = 0;
|
||||||
|
for (auto selected : _items) {
|
||||||
|
if (selected == id) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
54
libraries/render/src/render/Selection.h
Normal file
54
libraries/render/src/render/Selection.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
//
|
||||||
|
// Selection.h
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 4/4/2017.
|
||||||
|
// Copyright 2017 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_render_Selection_h
|
||||||
|
#define hifi_render_Selection_h
|
||||||
|
|
||||||
|
#include "Item.h"
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class Selection {
|
||||||
|
public:
|
||||||
|
using Name = std::string;
|
||||||
|
|
||||||
|
~Selection();
|
||||||
|
Selection();
|
||||||
|
Selection(const Selection& selection);
|
||||||
|
Selection& operator = (const Selection& selection);
|
||||||
|
Selection(Selection&& selection);
|
||||||
|
Selection& operator = (Selection&& selection);
|
||||||
|
|
||||||
|
Selection(const Name& name, const ItemIDs& items);
|
||||||
|
|
||||||
|
const Name& getName() const { return _name; }
|
||||||
|
|
||||||
|
const ItemIDs& getItems() const { return _items; }
|
||||||
|
|
||||||
|
bool isEmpty() const { return _items.empty(); }
|
||||||
|
|
||||||
|
// Test if the ID is in the selection, return the index or -1 if not present
|
||||||
|
static const int NOT_FOUND{ -1 };
|
||||||
|
|
||||||
|
int find(ItemID id) const;
|
||||||
|
bool contains(ItemID id) const { return find(id) > NOT_FOUND; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Name _name;
|
||||||
|
ItemIDs _items;
|
||||||
|
};
|
||||||
|
using Selections = std::vector<Selection>;
|
||||||
|
|
||||||
|
using SelectionMap = std::map<const Selection::Name, Selection>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,12 +15,42 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::string& name) {
|
||||||
|
childConfig->setParent(this);
|
||||||
|
childConfig->setObjectName(name.c_str());
|
||||||
|
|
||||||
|
// Connect loaded->refresh
|
||||||
|
QObject::connect(childConfig.get(), SIGNAL(loaded()), this, SLOT(refresh()));
|
||||||
|
static const char* DIRTY_SIGNAL = "dirty()";
|
||||||
|
if (childConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||||
|
// Connect dirty->refresh if defined
|
||||||
|
QObject::connect(childConfig.get(), SIGNAL(dirty()), this, SLOT(refresh()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskConfig::transferChildrenConfigs(QConfigPointer source) {
|
||||||
|
if (!source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Transfer children to the new configuration
|
||||||
|
auto children = source->children();
|
||||||
|
for (auto& child : children) {
|
||||||
|
child->setParent(this);
|
||||||
|
QObject::connect(child, SIGNAL(loaded()), this, SLOT(refresh()));
|
||||||
|
static const char* DIRTY_SIGNAL = "dirty()";
|
||||||
|
if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||||
|
// Connect dirty->refresh if defined
|
||||||
|
QObject::connect(child, SIGNAL(dirty()), this, SLOT(refresh()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TaskConfig::refresh() {
|
void TaskConfig::refresh() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "refresh", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(this, "refresh", Qt::BlockingQueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_task->configure(*this);
|
_task->applyConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,6 +301,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Job;
|
class Job;
|
||||||
|
class JobConcept;
|
||||||
class Task;
|
class Task;
|
||||||
class JobNoIO {};
|
class JobNoIO {};
|
||||||
|
|
||||||
|
@ -415,6 +416,8 @@ signals:
|
||||||
class TaskConfig : public JobConfig {
|
class TaskConfig : public JobConfig {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
using QConfigPointer = std::shared_ptr<QObject>;
|
||||||
|
|
||||||
using Persistent = PersistentConfig<TaskConfig>;
|
using Persistent = PersistentConfig<TaskConfig>;
|
||||||
|
|
||||||
TaskConfig() = default ;
|
TaskConfig() = default ;
|
||||||
|
@ -428,12 +431,15 @@ public:
|
||||||
return findChild<typename T::Config*>(name);
|
return findChild<typename T::Config*>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void connectChildConfig(QConfigPointer childConfig, const std::string& name);
|
||||||
|
void transferChildrenConfigs(QConfigPointer source);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Task;
|
friend Task;
|
||||||
Task* _task;
|
JobConcept* _task;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
|
template <class T, class C> void jobConfigure(T& data, const C& configuration) {
|
||||||
|
@ -458,57 +464,14 @@ template <class T, class I, class O> void jobRun(T& data, const SceneContextPoin
|
||||||
data.run(sceneContext, renderContext, input, output);
|
data.run(sceneContext, renderContext, input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
class GPUJobConfig : public JobConfig {
|
// The guts of a job
|
||||||
Q_OBJECT
|
class JobConcept {
|
||||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
|
||||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
|
||||||
|
|
||||||
double _msGPURunTime { 0.0 };
|
|
||||||
double _msBatchRunTime { 0.0 };
|
|
||||||
public:
|
|
||||||
using Persistent = PersistentConfig<GPUJobConfig>;
|
|
||||||
|
|
||||||
GPUJobConfig() = default;
|
|
||||||
GPUJobConfig(bool enabled) : JobConfig(enabled) {}
|
|
||||||
|
|
||||||
// Running Time measurement on GPU and for Batch execution
|
|
||||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
|
||||||
double getGPURunTime() const { return _msGPURunTime; }
|
|
||||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class GPUTaskConfig : public TaskConfig {
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
|
||||||
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
|
||||||
|
|
||||||
double _msGPURunTime { 0.0 };
|
|
||||||
double _msBatchRunTime { 0.0 };
|
|
||||||
public:
|
|
||||||
|
|
||||||
using Persistent = PersistentConfig<GPUTaskConfig>;
|
|
||||||
|
|
||||||
|
|
||||||
GPUTaskConfig() = default;
|
|
||||||
GPUTaskConfig(bool enabled) : TaskConfig(enabled) {}
|
|
||||||
|
|
||||||
// Running Time measurement on GPU and for Batch execution
|
|
||||||
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
|
||||||
double getGPURunTime() const { return _msGPURunTime; }
|
|
||||||
double getBatchRunTime() const { return _msBatchRunTime; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class Job {
|
|
||||||
public:
|
public:
|
||||||
using Config = JobConfig;
|
using Config = JobConfig;
|
||||||
using QConfigPointer = std::shared_ptr<QObject>;
|
using QConfigPointer = std::shared_ptr<QObject>;
|
||||||
using None = JobNoIO;
|
|
||||||
|
|
||||||
// The guts of a job
|
JobConcept(QConfigPointer config) : _config(config) {}
|
||||||
class Concept {
|
virtual ~JobConcept() = default;
|
||||||
public:
|
|
||||||
Concept(QConfigPointer config) : _config(config) {}
|
|
||||||
virtual ~Concept() = default;
|
|
||||||
|
|
||||||
virtual const Varying getInput() const { return Varying(); }
|
virtual const Varying getInput() const { return Varying(); }
|
||||||
virtual const Varying getOutput() const { return Varying(); }
|
virtual const Varying getOutput() const { return Varying(); }
|
||||||
|
@ -518,13 +481,20 @@ public:
|
||||||
|
|
||||||
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
|
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
|
void setCPURunTime(double mstime) { std::static_pointer_cast<Config>(_config)->setCPURunTime(mstime); }
|
||||||
|
|
||||||
QConfigPointer _config;
|
QConfigPointer _config;
|
||||||
|
|
||||||
friend class Job;
|
friend class Job;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Job {
|
||||||
|
public:
|
||||||
|
using Concept = JobConcept;
|
||||||
|
using Config = JobConfig;
|
||||||
|
using QConfigPointer = std::shared_ptr<QObject>;
|
||||||
|
using None = JobNoIO;
|
||||||
using ConceptPointer = std::shared_ptr<Concept>;
|
using ConceptPointer = std::shared_ptr<Concept>;
|
||||||
|
|
||||||
template <class T, class C = Config, class I = None, class O = None> class Model : public Concept {
|
template <class T, class C = Config, class I = None, class O = None> class Model : public Concept {
|
||||||
|
@ -541,11 +511,20 @@ public:
|
||||||
const Varying getOutput() const override { return _output; }
|
const Varying getOutput() const override { return _output; }
|
||||||
|
|
||||||
template <class... A>
|
template <class... A>
|
||||||
Model(const Varying& input, A&&... args) :
|
Model(const Varying& input, QConfigPointer config, A&&... args) :
|
||||||
Concept(std::make_shared<C>()), _data(Data(std::forward<A>(args)...)), _input(input), _output(Output()) {
|
Concept(config),
|
||||||
|
_data(Data(std::forward<A>(args)...)),
|
||||||
|
_input(input),
|
||||||
|
_output(Output()) {
|
||||||
applyConfiguration();
|
applyConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class... A>
|
||||||
|
static std::shared_ptr<Model> create(const Varying& input, A&&... args) {
|
||||||
|
return std::make_shared<Model>(input, std::make_shared<C>(), std::forward<A>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void applyConfiguration() override {
|
void applyConfiguration() override {
|
||||||
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
||||||
}
|
}
|
||||||
|
@ -585,125 +564,180 @@ public:
|
||||||
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ConceptPointer _concept;
|
ConceptPointer _concept;
|
||||||
std::string _name = "";
|
std::string _name = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
// A task is a specialized job to run a collection of other jobs
|
// A task is a specialized job to run a collection of other jobs
|
||||||
// It is defined with JobModel = Task::Model<T>
|
// It can be created on any type T by aliasing the type JobModel in the class T
|
||||||
class Task {
|
// using JobModel = Task::Model<T>
|
||||||
|
// The class T is expected to have a "build" method acting as a constructor.
|
||||||
|
// The build method is where child Jobs can be added internally to the task
|
||||||
|
// where the input of the task can be setup to feed the child jobs
|
||||||
|
// and where the output of the task is defined
|
||||||
|
class Task : public Job {
|
||||||
public:
|
public:
|
||||||
using Config = TaskConfig;
|
using Config = TaskConfig;
|
||||||
using QConfigPointer = Job::QConfigPointer;
|
using QConfigPointer = Job::QConfigPointer;
|
||||||
|
using None = Job::None;
|
||||||
|
using Concept = Job::Concept;
|
||||||
|
using Jobs = std::vector<Job>;
|
||||||
|
|
||||||
template <class T, class C = Config> class Model : public Job::Concept {
|
Task(std::string name, ConceptPointer concept) : Job(name, concept) {}
|
||||||
|
|
||||||
|
class TaskConcept : public Concept {
|
||||||
|
public:
|
||||||
|
Varying _input;
|
||||||
|
Varying _output;
|
||||||
|
Jobs _jobs;
|
||||||
|
|
||||||
|
const Varying getInput() const override { return _input; }
|
||||||
|
const Varying getOutput() const override { return _output; }
|
||||||
|
|
||||||
|
TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {}
|
||||||
|
|
||||||
|
// Create a new job in the container's queue; returns the job's output
|
||||||
|
template <class NT, class... NA> const Varying addJob(std::string name, const Varying& input, NA&&... args) {
|
||||||
|
_jobs.emplace_back(name, (NT::JobModel::create(input, std::forward<NA>(args)...)));
|
||||||
|
|
||||||
|
// Conect the child config to this task's config
|
||||||
|
std::static_pointer_cast<TaskConfig>(getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name);
|
||||||
|
|
||||||
|
return _jobs.back().getOutput();
|
||||||
|
}
|
||||||
|
template <class NT, class... NA> const Varying addJob(std::string name, NA&&... args) {
|
||||||
|
const auto input = Varying(typename NT::JobModel::Input());
|
||||||
|
return addJob<NT>(name, input, std::forward<NA>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class C = Config, class I = None, class O = None> class TaskModel : public TaskConcept {
|
||||||
public:
|
public:
|
||||||
using Data = T;
|
using Data = T;
|
||||||
using Config = C;
|
using Input = I;
|
||||||
using Input = Job::None;
|
using Output = O;
|
||||||
|
|
||||||
Data _data;
|
Data _data;
|
||||||
|
|
||||||
const Varying getOutput() const override { return _data._output; }
|
TaskModel(const Varying& input, QConfigPointer config) :
|
||||||
|
TaskConcept(input, config),
|
||||||
|
_data(Data()) {}
|
||||||
|
|
||||||
template <class... A>
|
template <class... A>
|
||||||
Model(const Varying& input, A&&... args) :
|
static std::shared_ptr<TaskModel> create(const Varying& input, A&&... args) {
|
||||||
Concept(nullptr), _data(Data(std::forward<A>(args)...)) {
|
auto model = std::make_shared<TaskModel>(input, std::make_shared<C>());
|
||||||
|
// std::static_pointer_cast<C>(model->_config)->_task = model.get();
|
||||||
|
|
||||||
|
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
|
||||||
|
|
||||||
// Recreate the Config to use the templated type
|
// Recreate the Config to use the templated type
|
||||||
_data.template createConfiguration<C>();
|
model->createConfiguration();
|
||||||
_config = _data.getConfiguration();
|
model->applyConfiguration();
|
||||||
applyConfiguration();
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... A>
|
||||||
|
static std::shared_ptr<TaskModel> create(A&&... args) {
|
||||||
|
const auto input = Varying(Input());
|
||||||
|
return create(input, std::forward<A>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createConfiguration() {
|
||||||
|
// A brand new config
|
||||||
|
auto config = std::make_shared<C>();
|
||||||
|
// Make sure we transfer the former children configs to the new config
|
||||||
|
config->transferChildrenConfigs(_config);
|
||||||
|
// swap
|
||||||
|
_config = config;
|
||||||
|
// Capture this
|
||||||
|
std::static_pointer_cast<C>(_config)->_task = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QConfigPointer& getConfiguration() override {
|
||||||
|
if (!_config) {
|
||||||
|
createConfiguration();
|
||||||
|
}
|
||||||
|
return _config;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyConfiguration() override {
|
void applyConfiguration() override {
|
||||||
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
jobConfigure(_data, *std::static_pointer_cast<C>(_config));
|
||||||
|
for (auto& job : _jobs) {
|
||||||
|
job.applyConfiguration();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) override {
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) override {
|
||||||
auto config = std::static_pointer_cast<Config>(_config);
|
auto config = std::static_pointer_cast<C>(_config);
|
||||||
if (config->alwaysEnabled || config->enabled) {
|
if (config->alwaysEnabled || config->enabled) {
|
||||||
for (auto job : _data._jobs) {
|
for (auto job : _jobs) {
|
||||||
job.run(sceneContext, renderContext);
|
job.run(sceneContext, renderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <class T, class C = Config> using ModelO = Model<T, C>;
|
template <class T, class C = Config> using Model = TaskModel<T, C, None, None>;
|
||||||
|
template <class T, class I, class C = Config> using ModelI = TaskModel<T, C, I, None>;
|
||||||
|
template <class T, class O, class C = Config> using ModelO = TaskModel<T, C, None, O>;
|
||||||
|
template <class T, class I, class O, class C = Config> using ModelIO = TaskModel<T, C, I, O>;
|
||||||
|
|
||||||
using Jobs = std::vector<Job>;
|
// Create a new job in the Task's queue; returns the job's output
|
||||||
|
|
||||||
// Create a new job in the container's queue; returns the job's output
|
|
||||||
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
|
template <class T, class... A> const Varying addJob(std::string name, const Varying& input, A&&... args) {
|
||||||
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(input, std::forward<A>(args)...));
|
return std::static_pointer_cast<TaskConcept>( _concept)->addJob<T>(name, input, std::forward<A>(args)...);
|
||||||
QConfigPointer config = _jobs.back().getConfiguration();
|
|
||||||
config->setParent(getConfiguration().get());
|
|
||||||
config->setObjectName(name.c_str());
|
|
||||||
|
|
||||||
// Connect loaded->refresh
|
|
||||||
QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh()));
|
|
||||||
static const char* DIRTY_SIGNAL = "dirty()";
|
|
||||||
if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
|
||||||
// Connect dirty->refresh if defined
|
|
||||||
QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _jobs.back().getOutput();
|
|
||||||
}
|
}
|
||||||
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
|
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
|
||||||
const auto input = Varying(typename T::JobModel::Input());
|
const auto input = Varying(typename T::JobModel::Input());
|
||||||
return addJob<T>(name, input, std::forward<A>(args)...);
|
return std::static_pointer_cast<TaskConcept>( _concept)->addJob<T>(name, input, std::forward<A>(args)...);
|
||||||
}
|
|
||||||
|
|
||||||
template <class O> void setOutput(O&& output) {
|
|
||||||
_output = Varying(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class C> void createConfiguration() {
|
|
||||||
auto config = std::make_shared<C>();
|
|
||||||
if (_config) {
|
|
||||||
// Transfer children to the new configuration
|
|
||||||
auto children = _config->children();
|
|
||||||
for (auto& child : children) {
|
|
||||||
child->setParent(config.get());
|
|
||||||
QObject::connect(child, SIGNAL(loaded()), config.get(), SLOT(refresh()));
|
|
||||||
static const char* DIRTY_SIGNAL = "dirty()";
|
|
||||||
if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
|
||||||
// Connect dirty->refresh if defined
|
|
||||||
QObject::connect(child, SIGNAL(dirty()), config.get(), SLOT(refresh()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_config = config;
|
|
||||||
std::static_pointer_cast<Config>(_config)->_task = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Config> getConfiguration() {
|
std::shared_ptr<Config> getConfiguration() {
|
||||||
if (!_config) {
|
return std::static_pointer_cast<Config>(_concept->getConfiguration());
|
||||||
createConfiguration<Config>();
|
|
||||||
}
|
|
||||||
return std::static_pointer_cast<Config>(_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure(const QObject& configuration) {
|
|
||||||
for (auto& job : _jobs) {
|
|
||||||
job.applyConfiguration();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
|
||||||
for (auto job : _jobs) {
|
|
||||||
job.run(sceneContext, renderContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <class T, class C> friend class Model;
|
};
|
||||||
|
|
||||||
QConfigPointer _config;
|
// Versions of the COnfig integrating a gpu & batch timer
|
||||||
Jobs _jobs;
|
class GPUJobConfig : public JobConfig {
|
||||||
Varying _output;
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||||
|
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||||
|
|
||||||
|
double _msGPURunTime { 0.0 };
|
||||||
|
double _msBatchRunTime { 0.0 };
|
||||||
|
public:
|
||||||
|
using Persistent = PersistentConfig<GPUJobConfig>;
|
||||||
|
|
||||||
|
GPUJobConfig() = default;
|
||||||
|
GPUJobConfig(bool enabled) : JobConfig(enabled) {}
|
||||||
|
|
||||||
|
// Running Time measurement on GPU and for Batch execution
|
||||||
|
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||||
|
double getGPURunTime() const { return _msGPURunTime; }
|
||||||
|
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUTaskConfig : public TaskConfig {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(double gpuRunTime READ getGPURunTime)
|
||||||
|
Q_PROPERTY(double batchRunTime READ getBatchRunTime)
|
||||||
|
|
||||||
|
double _msGPURunTime { 0.0 };
|
||||||
|
double _msBatchRunTime { 0.0 };
|
||||||
|
public:
|
||||||
|
|
||||||
|
using Persistent = PersistentConfig<GPUTaskConfig>;
|
||||||
|
|
||||||
|
|
||||||
|
GPUTaskConfig() = default;
|
||||||
|
GPUTaskConfig(bool enabled) : TaskConfig(enabled) {}
|
||||||
|
|
||||||
|
// Running Time measurement on GPU and for Batch execution
|
||||||
|
void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; }
|
||||||
|
double getGPURunTime() const { return _msGPURunTime; }
|
||||||
|
double getBatchRunTime() const { return _msBatchRunTime; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
<@include gpu/Color.slh@>
|
<@include gpu/Color.slh@>
|
||||||
<$declareColorWheel()$>
|
<$declareColorWheel()$>
|
||||||
|
|
||||||
uniform vec3 inBoundPos;
|
uniform vec4 inColor;
|
||||||
uniform vec3 inBoundDim;
|
|
||||||
uniform ivec4 inCellLocation;
|
|
||||||
|
|
||||||
|
|
||||||
struct ItemBound {
|
struct ItemBound {
|
||||||
|
@ -93,9 +91,11 @@ void main(void) {
|
||||||
TransformObject obj = getTransformObject();
|
TransformObject obj = getTransformObject();
|
||||||
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
||||||
|
|
||||||
bool subcell = bool((inCellLocation.z));
|
if (inColor.w < 0.0) {
|
||||||
float cellDepth = float(inCellLocation.w);
|
varColor = vec4(colorWheel(float(boundID)/(-inColor.w)), 1.0);
|
||||||
varColor = vec4(colorWheel(fract(cellDepth / 5.0)), 1.0 - float(subcell));
|
} else {
|
||||||
|
varColor = vec4(colorWheel(float(inColor.w)), 1.0);
|
||||||
|
}
|
||||||
varTexcoord = vec2(cubeVec.w, length(boundDim));
|
varTexcoord = vec2(cubeVec.w, length(boundDim));
|
||||||
|
|
||||||
}
|
}
|
|
@ -52,32 +52,49 @@ float RecordingScriptingInterface::playerLength() const {
|
||||||
return _player->length();
|
return _player->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordingScriptingInterface::loadRecording(const QString& url) {
|
void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) {
|
||||||
using namespace recording;
|
auto clipLoader = DependencyManager::get<recording::ClipCache>()->getClipLoader(url);
|
||||||
|
|
||||||
auto loader = ClipCache::instance().getClipLoader(url);
|
// hold a strong pointer to the loading clip so that it has a chance to load
|
||||||
if (!loader) {
|
_clipLoaders.insert(clipLoader);
|
||||||
qWarning() << "Clip failed to load from " << url;
|
|
||||||
return false;
|
auto weakClipLoader = clipLoader.toWeakRef();
|
||||||
|
|
||||||
|
// when clip loaded, call the callback with the URL and success boolean
|
||||||
|
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this,
|
||||||
|
[this, weakClipLoader, url, callback]() mutable {
|
||||||
|
|
||||||
|
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||||
|
qCDebug(scriptengine) << "Loaded recording from" << url;
|
||||||
|
|
||||||
|
_player->queueClip(clipLoader->getClip());
|
||||||
|
|
||||||
|
if (callback.isFunction()) {
|
||||||
|
QScriptValueList args { true, url };
|
||||||
|
callback.call(_scriptEngine->globalObject(), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loader->isLoaded()) {
|
// drop our strong pointer to this clip so it is cleaned up
|
||||||
QEventLoop loop;
|
_clipLoaders.remove(clipLoader);
|
||||||
QObject::connect(loader.data(), &Resource::loaded, &loop, &QEventLoop::quit);
|
}
|
||||||
QObject::connect(loader.data(), &Resource::failed, &loop, &QEventLoop::quit);
|
});
|
||||||
loop.exec();
|
|
||||||
|
// when clip load fails, call the callback with the URL and failure boolean
|
||||||
|
connect(clipLoader.data(), &recording::NetworkClipLoader::failed, this, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable {
|
||||||
|
qCDebug(scriptengine) << "Failed to load recording from" << url;
|
||||||
|
|
||||||
|
if (callback.isFunction()) {
|
||||||
|
QScriptValueList args { false, url };
|
||||||
|
callback.call(_scriptEngine->currentContext()->thisObject(), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loader->isLoaded()) {
|
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||||
qWarning() << "Clip failed to load from " << url;
|
// drop out strong pointer to this clip so it is cleaned up
|
||||||
return false;
|
_clipLoaders.remove(clipLoader);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
_player->queueClip(loader->getClip());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RecordingScriptingInterface::startPlaying() {
|
void RecordingScriptingInterface::startPlaying() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Forward.h>
|
#include <recording/Forward.h>
|
||||||
#include <recording/Frame.h>
|
#include <recording/Frame.h>
|
||||||
|
|
||||||
|
class QScriptEngine;
|
||||||
class QScriptValue;
|
class QScriptValue;
|
||||||
|
|
||||||
class RecordingScriptingInterface : public QObject, public Dependency {
|
class RecordingScriptingInterface : public QObject, public Dependency {
|
||||||
|
@ -26,8 +28,10 @@ class RecordingScriptingInterface : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
RecordingScriptingInterface();
|
RecordingScriptingInterface();
|
||||||
|
|
||||||
|
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool loadRecording(const QString& url);
|
void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
|
||||||
|
|
||||||
void startPlaying();
|
void startPlaying();
|
||||||
void pausePlayer();
|
void pausePlayer();
|
||||||
|
@ -79,6 +83,9 @@ protected:
|
||||||
Flag _useAttachments { false };
|
Flag _useAttachments { false };
|
||||||
Flag _useSkeletonModel { false };
|
Flag _useSkeletonModel { false };
|
||||||
recording::ClipPointer _lastClip;
|
recording::ClipPointer _lastClip;
|
||||||
|
|
||||||
|
QScriptEngine* _scriptEngine;
|
||||||
|
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RecordingScriptingInterface_h
|
#endif // hifi_RecordingScriptingInterface_h
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#define SINGLETON_DEPENDENCY \
|
#define SINGLETON_DEPENDENCY \
|
||||||
friend class DependencyManager;
|
friend class ::DependencyManager;
|
||||||
|
|
||||||
class Dependency {
|
class Dependency {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -769,7 +769,7 @@ bool similarStrings(const QString& stringA, const QString& stringB) {
|
||||||
|
|
||||||
void disableQtBearerPoll() {
|
void disableQtBearerPoll() {
|
||||||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
||||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
|
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit();
|
||||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,9 +196,10 @@ public:
|
||||||
std::string vsSource = HMD_REPROJECTION_VERT;
|
std::string vsSource = HMD_REPROJECTION_VERT;
|
||||||
std::string fsSource = HMD_REPROJECTION_FRAG;
|
std::string fsSource = HMD_REPROJECTION_FRAG;
|
||||||
GLuint vertexShader { 0 }, fragmentShader { 0 };
|
GLuint vertexShader { 0 }, fragmentShader { 0 };
|
||||||
::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader);
|
std::string error;
|
||||||
::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader);
|
::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader, error);
|
||||||
_program = ::gl::compileProgram({ { vertexShader, fragmentShader } });
|
::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader, error);
|
||||||
|
_program = ::gl::compileProgram({ { vertexShader, fragmentShader } }, error);
|
||||||
glDeleteShader(vertexShader);
|
glDeleteShader(vertexShader);
|
||||||
glDeleteShader(fragmentShader);
|
glDeleteShader(fragmentShader);
|
||||||
qDebug() << "Rebuild proigram";
|
qDebug() << "Rebuild proigram";
|
||||||
|
|
|
@ -138,7 +138,13 @@ Agent.isAvatar = true;
|
||||||
Agent.isListeningToAudioStream = true;
|
Agent.isListeningToAudioStream = true;
|
||||||
Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored
|
Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored
|
||||||
|
|
||||||
Recording.loadRecording(RECORDING_URL);
|
Recording.loadRecording(RECORDING_URL, function(success) {
|
||||||
|
if (success) {
|
||||||
|
Script.update.connect(update);
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + RECORDING_URL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
count = 300; // This is necessary to wait for the audio mixer to connect
|
count = 300; // This is necessary to wait for the audio mixer to connect
|
||||||
function update(event) {
|
function update(event) {
|
||||||
|
@ -179,5 +185,3 @@ function update(event) {
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
|
||||||
|
|
|
@ -20,7 +20,13 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
Avatar.scale = 1.0;
|
Avatar.scale = 1.0;
|
||||||
Agent.isAvatar = true;
|
Agent.isAvatar = true;
|
||||||
|
|
||||||
Recording.loadRecording(recordingFile);
|
Recording.loadRecording(recordingFile, function(success) {
|
||||||
|
if (success) {
|
||||||
|
Script.update.connect(update);
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + recordingFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
count = 300; // This is necessary to wait for the audio mixer to connect
|
count = 300; // This is necessary to wait for the audio mixer to connect
|
||||||
function update(event) {
|
function update(event) {
|
||||||
|
@ -44,5 +50,3 @@ function update(event) {
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
|
||||||
|
|
|
@ -42,10 +42,15 @@ var playRecording = function() {
|
||||||
Recording.setPlayerLoop(false);
|
Recording.setPlayerLoop(false);
|
||||||
Recording.setPlayerTime(STARTING_TIME);
|
Recording.setPlayerTime(STARTING_TIME);
|
||||||
Recording.setPlayerAudioOffset(AUDIO_OFFSET);
|
Recording.setPlayerAudioOffset(AUDIO_OFFSET);
|
||||||
Recording.loadRecording(CLIP_URL);
|
Recording.loadRecording(CLIP_URL, function(success) {
|
||||||
|
if (success) {
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
isPlaying = true;
|
isPlaying = true;
|
||||||
isPlayable = false; // Set this true again after the cooldown period
|
isPlayable = false; // Set this true again after the cooldown period
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + CLIP_URL);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.update.connect(function(deltaTime) {
|
Script.update.connect(function(deltaTime) {
|
||||||
|
|
|
@ -10,9 +10,15 @@ Agent.isAvatar = true;
|
||||||
|
|
||||||
Script.setTimeout(function () {
|
Script.setTimeout(function () {
|
||||||
Avatar.position = origin;
|
Avatar.position = origin;
|
||||||
Recording.loadRecording("d:/hifi.rec");
|
Recording.loadRecording("d:/hifi.rec", function(success) {
|
||||||
|
if (success) {
|
||||||
Recording.setPlayerLoop(true);
|
Recording.setPlayerLoop(true);
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}, millisecondsToWaitBeforeStarting);
|
}, millisecondsToWaitBeforeStarting);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,18 @@ function update(deltaTime) {
|
||||||
if (!subscribed) {
|
if (!subscribed) {
|
||||||
Messages.subscribe(PLAYBACK_CHANNEL);
|
Messages.subscribe(PLAYBACK_CHANNEL);
|
||||||
subscribed = true;
|
subscribed = true;
|
||||||
Recording.loadRecording(clip_url);
|
Recording.loadRecording(clip_url, function(success) {
|
||||||
|
if (success) {
|
||||||
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||||
Recording.setPlayerUseDisplayName(useDisplayName);
|
Recording.setPlayerUseDisplayName(useDisplayName);
|
||||||
Recording.setPlayerUseAttachments(useAttachments);
|
Recording.setPlayerUseAttachments(useAttachments);
|
||||||
Recording.setPlayerUseHeadModel(false);
|
Recording.setPlayerUseHeadModel(false);
|
||||||
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
||||||
Agent.isAvatar = true;
|
Agent.isAvatar = true;
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + clip_url);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,15 @@ function getAction(channel, message, senderID) {
|
||||||
|
|
||||||
case SHOW:
|
case SHOW:
|
||||||
print("Show");
|
print("Show");
|
||||||
Recording.loadRecording(clip_url);
|
Recording.loadRecording(clip_url, function(success) {
|
||||||
|
if (success) {
|
||||||
Agent.isAvatar = true;
|
Agent.isAvatar = true;
|
||||||
Recording.setPlayerTime(0.0);
|
Recording.setPlayerTime(0.0);
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
Recording.stopPlaying();
|
Recording.stopPlaying();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIDE:
|
case HIDE:
|
||||||
|
|
|
@ -281,8 +281,13 @@ function mousePressEvent(event) {
|
||||||
if (!Recording.isRecording() && !Recording.isPlaying()) {
|
if (!Recording.isRecording() && !Recording.isPlaying()) {
|
||||||
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
|
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
|
||||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||||
Recording.loadRecording(recordingFile);
|
Recording.loadRecording(recordingFile, function(success) {
|
||||||
|
if (success) {
|
||||||
setDefaultPlayerOptions();
|
setDefaultPlayerOptions();
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + recordingFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (Recording.playerLength() > 0) {
|
if (Recording.playerLength() > 0) {
|
||||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||||
|
|
|
@ -13,7 +13,7 @@ var qml = Script.resolvePath('deferredLighting.qml');
|
||||||
var window = new OverlayWindow({
|
var window = new OverlayWindow({
|
||||||
title: 'Lighting',
|
title: 'Lighting',
|
||||||
source: qml,
|
source: qml,
|
||||||
width: 400, height:280,
|
width: 400, height:350,
|
||||||
});
|
});
|
||||||
window.setPosition(Window.innerWidth - 420, 50);
|
window.setPosition(Window.innerWidth - 420, 50);
|
||||||
window.closed.connect(function() { Script.stop(); });
|
window.closed.connect(function() { Script.stop(); });
|
||||||
|
|
|
@ -189,6 +189,11 @@ Column {
|
||||||
checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"]
|
checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"]
|
||||||
onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked }
|
onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked }
|
||||||
}
|
}
|
||||||
|
CheckBox {
|
||||||
|
text: "Zones"
|
||||||
|
checked: Render.getConfig("DrawZones")["enabled"]
|
||||||
|
onCheckedChanged: { Render.getConfig("ZoneRenderer")["enabled"] = checked; Render.getConfig("DrawZones")["enabled"] = checked; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -543,9 +543,9 @@ public:
|
||||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||||
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
||||||
_renderEngine->addJob<RenderForwardTask>("RenderForwardTask", items.get<RenderFetchCullSortTask::Output>());
|
_renderEngine->addJob<RenderForwardTask>("RenderForwardTask", items);
|
||||||
} else {
|
} else {
|
||||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items.get<RenderFetchCullSortTask::Output>());
|
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||||
}
|
}
|
||||||
_renderEngine->load();
|
_renderEngine->load();
|
||||||
_renderEngine->registerScene(_main3DScene);
|
_renderEngine->registerScene(_main3DScene);
|
||||||
|
|
Loading…
Reference in a new issue