merged master and resolved application conflict

This commit is contained in:
amerhifi 2019-05-13 12:09:50 -07:00
commit 71d534c97d
57 changed files with 1004 additions and 331 deletions

View file

@ -195,8 +195,6 @@
#include "scripting/RefreshRateScriptingInterface.h"
#include <platform.h>
#include <nlohmann/json.hpp>
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h"
@ -247,11 +245,8 @@
#include "webbrowser/WebBrowserSuggestionsEngine.h"
#include <DesktopPreviewProvider.h>
#include <nlohmann/json.hpp>
#include "AboutUtil.h"
#include <DisableDeferred.h>
#if defined(Q_OS_WIN)
#include <VersionHelpers.h>
@ -1035,7 +1030,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_sampleSound(nullptr)
{
initPlatform();
auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
@ -2510,18 +2504,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
pauseUntilLoginDetermined();
}
void Application::initPlatform() {
platform::create();
platform::enumeratePlatform();
const nlohmann::json test = platform::getGraphics(0);
const nlohmann::json test1 = platform::getProcessor(0);
const nlohmann::json test2 = platform::getMemory(0);
//const nlohmann::json* test3 = platform::getDisplay(0);
}
void Application::updateVerboseLogging() {
auto menu = Menu::getInstance();
if (!menu) {
@ -3045,7 +3027,7 @@ void Application::initializeDisplayPlugins() {
void Application::initializeRenderEngine() {
// FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread.
DeadlockWatchdogThread::withPause([&] {
_graphicsEngine.initializeRender(DISABLE_DEFERRED);
_graphicsEngine.initializeRender();
DependencyManager::get<Keyboard>()->registerKeyboardHighlighting();
});
}
@ -6722,7 +6704,7 @@ void Application::updateRenderArgs(float deltaTime) {
}
appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), lodManager->getLODAngleHalfTan(), RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE);
appRenderArgs._renderArgs._scene = getMain3DScene();
{

View file

@ -272,10 +272,10 @@ public:
}
};
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) {
const auto cachedArg = task.addJob<SecondaryCameraJob>("SecondaryCamera");
task.addJob<RenderViewTask>("RenderSecondView", cullFunctor, isDeferred, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
task.addJob<RenderViewTask>("RenderSecondView", cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1);
task.addJob<EndSecondaryCameraFrame>("EndSecondaryCamera", cachedArg);
}

View file

@ -65,7 +65,7 @@ public:
using JobModel = render::Task::Model<SecondaryCameraRenderTask, Config>;
SecondaryCameraRenderTask() {}
void configure(const Config& config) {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor);
};
#endif

View file

@ -65,15 +65,15 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext);
}
void GraphicsEngine::initializeRender(bool disableDeferred) {
void GraphicsEngine::initializeRender() {
// Set up the render engine
render::CullFunctor cullFunctor = LODManager::shouldRender;
_renderEngine->addJob<UpdateSceneTask>("UpdateScene");
#ifndef Q_OS_ANDROID
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !disableDeferred);
_renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor);
#endif
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !disableDeferred, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0);
_renderEngine->load();
_renderEngine->registerScene(_renderScene);

View file

@ -44,7 +44,7 @@ public:
~GraphicsEngine();
void initializeGPU(GLWidget*);
void initializeRender(bool disableDeferred);
void initializeRender();
void startup();
void shutdown();

View file

@ -22,7 +22,7 @@ namespace render {
PerformanceTimer perfTimer("worldBox");
auto& batch = *args->_batch;
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, false, false, true, args->_renderMethod == Args::RenderMethod::FORWARD);
WorldBoxRenderData::renderWorldBox(args, batch);
}
}

View file

@ -20,8 +20,7 @@ const float ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_W
const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA { false };
const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_DRAWINFRONT { false };
gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::_parabolaPipeline { nullptr };
gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::_transparentParabolaPipeline { nullptr };
std::map<std::pair<bool, bool>, gpu::PipelinePointer> ParabolaPointer::RenderState::ParabolaRenderItem::_parabolaPipelines;
ParabolaPointer::ParabolaPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover,
const PointerTriggers& triggers, bool faceAvatar, bool followNormal, float followNormalStrength, bool centerEndY, bool lockEnd, bool distanceScaleEnd,
@ -401,33 +400,34 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
_bound = AABox(min, max - min);
}
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
auto state = std::make_shared<gpu::State>();
gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline(bool forward) const {
if (_parabolaPipelines.empty()) {
using namespace shader::render_utils::program;
static const std::vector<std::tuple<bool, bool, uint32_t>> keys = {
std::make_tuple(false, false, parabola), std::make_tuple(false, true, forward_parabola), std::make_tuple(true, false, parabola_translucent)/*, std::make_tuple(true, true, forward_parabola_translucent)*/
};
for (auto& key : keys) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
if (std::get<0>(key)) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
state->setBlendFunction(std::get<0>(key),
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMaskDrawShape(*state);
state->setCullMode(gpu::State::CULL_NONE);
_parabolaPipeline = gpu::Pipeline::create(program, state);
_parabolaPipelines[{std::get<0>(key), std::get<1>(key)}] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state);
}
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola_translucent);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
state->setCullMode(gpu::State::CULL_NONE);
_transparentParabolaPipeline = gpu::Pipeline::create(program, state);
}
// The forward opaque/translucent pipelines are the same for now
_parabolaPipelines[{ true, true }] = _parabolaPipelines[{ false, true}];
}
return (_parabolaData.color.a < 1.0f ? _transparentParabolaPipeline : _parabolaPipeline);
return _parabolaPipelines[{ _parabolaData.color.a < 1.0f, forward }];
}
void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) {
@ -441,7 +441,7 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args)
transform.setTranslation(_origin);
batch.setModelTransform(transform);
batch.setPipeline(getParabolaPipeline());
batch.setPipeline(getParabolaPipeline(args->_renderMethod == render::Args::RenderMethod::FORWARD));
const int MAX_SECTIONS = 100;
if (glm::length2(_parabolaData.acceleration) < EPSILON) {

View file

@ -26,9 +26,8 @@ public:
bool isVisibleInSecondaryCamera, bool drawInFront, bool enabled);
~ParabolaRenderItem() {}
static gpu::PipelinePointer _parabolaPipeline;
static gpu::PipelinePointer _transparentParabolaPipeline;
const gpu::PipelinePointer getParabolaPipeline();
static std::map<std::pair<bool, bool>, gpu::PipelinePointer> _parabolaPipelines;
gpu::PipelinePointer getParabolaPipeline(bool forward) const;
void render(RenderArgs* args);
render::Item::Bound& editBound() { return _bound; }

View file

@ -145,6 +145,7 @@ void GameWorkloadRenderItem::setAllViews(const workload::Views& views) {
}
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
// FIXME: this needs a forward pipeline, or to only write to one output
if (!_drawAllProxiesPipeline) {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadProxy);
auto state = std::make_shared<gpu::State>();
@ -162,6 +163,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
// FIXME: this needs a forward pipeline, or to only write to one output
if (!_drawAllViewsPipeline) {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadView);
auto state = std::make_shared<gpu::State>();

View file

@ -779,7 +779,7 @@ void Avatar::render(RenderArgs* renderArgs) {
pointerTransform.setTranslation(position);
pointerTransform.setRotation(rotation);
batch.setModelTransform(pointerTransform);
geometryCache->bindSimpleProgram(batch);
geometryCache->bindSimpleProgram(batch, false, false, true, false, false, true, renderArgs->_renderMethod == render::Args::FORWARD);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _leftPointerGeometryID);
}
}
@ -803,7 +803,7 @@ void Avatar::render(RenderArgs* renderArgs) {
pointerTransform.setTranslation(position);
pointerTransform.setRotation(rotation);
batch.setModelTransform(pointerTransform);
geometryCache->bindSimpleProgram(batch);
geometryCache->bindSimpleProgram(batch, false, false, true, false, false, true, renderArgs->_renderMethod == render::Args::FORWARD);
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _rightPointerGeometryID);
}
}
@ -829,7 +829,7 @@ void Avatar::render(RenderArgs* renderArgs) {
auto& frustum = renderArgs->getViewFrustum();
auto textPosition = getDisplayNamePosition();
if (frustum.pointIntersectsFrustum(textPosition)) {
renderDisplayName(batch, frustum, textPosition);
renderDisplayName(batch, frustum, textPosition, renderArgs->_renderMethod == render::Args::FORWARD);
}
}
}
@ -1034,7 +1034,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& view, const g
return result;
}
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const {
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition, bool forward) const {
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
bool shouldShowReceiveStats = showReceiveStats && !isMyAvatar();
@ -1090,7 +1090,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
{
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect");
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, true, true);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, true, true, true, forward);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
bevelDistance, backgroundColor, _nameRectGeometryID);
}
@ -1103,7 +1103,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
batch.setModelTransform(textTransform);
{
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText");
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor, glm::vec2(-1.0f), forward);
}
}
}

View file

@ -694,7 +694,7 @@ protected:
glm::vec3 getDisplayNamePosition() const;
Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition, bool forward) const;
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
virtual void fixupModelsInScene(const render::ScenePointer& scene);

View file

@ -591,7 +591,7 @@ void EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QSet<EntityItemI
if (contains) {
// if this entity is a zone and visible, add it to our layered zones
if (isZone && entity->getVisible() && renderableIdForEntity(entity) != render::Item::INVALID_ITEM_ID) {
_layeredZones.emplace(std::dynamic_pointer_cast<ZoneEntityItem>(entity));
_layeredZones.emplace_back(std::dynamic_pointer_cast<ZoneEntityItem>(entity));
}
if ((!hasScript && isZone) || scriptHasLoaded) {
@ -600,6 +600,7 @@ void EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QSet<EntityItemI
}
}
_layeredZones.sort();
if (!_layeredZones.equals(oldLayeredZones)) {
applyLayeredZones();
}
@ -1187,66 +1188,73 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
if (auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(getTree()->findEntityByEntityItemID(id))) {
_layeredZones.update(zone, _avatarPosition, this);
applyLayeredZones();
if (_layeredZones.update(zone, _avatarPosition, this)) {
applyLayeredZones();
}
}
}
bool EntityTreeRenderer::LayeredZones::clearDomainAndNonOwnedZones(const QUuid& sessionUUID) {
bool zonesChanged = false;
auto it = c.begin();
while (it != c.end()) {
auto it = begin();
while (it != end()) {
auto zone = it->zone.lock();
if (!zone || !(zone->isLocalEntity() || (zone->isAvatarEntity() && zone->getOwningAvatarID() == sessionUUID))) {
zonesChanged = true;
it = c.erase(it);
it = erase(it);
} else {
it++;
}
}
if (zonesChanged) {
std::make_heap(c.begin(), c.end(), comp);
sort();
}
return zonesChanged;
}
std::pair<bool, bool> EntityTreeRenderer::LayeredZones::getZoneInteractionProperties() const {
auto it = c.cbegin();
while (it != c.cend()) {
for (auto it = cbegin(); it != cend(); it++) {
auto zone = it->zone.lock();
if (zone && zone->isDomainEntity()) {
return { zone->getFlyingAllowed(), zone->getGhostingAllowed() };
}
it++;
}
return { true, true };
}
void EntityTreeRenderer::LayeredZones::remove(const std::shared_ptr<ZoneEntityItem>& zone) {
auto it = c.begin();
while (it != c.end()) {
if (it->zone.lock() == zone) {
break;
}
it++;
}
if (it != c.end()) {
c.erase(it);
std::make_heap(c.begin(), c.end(), comp);
}
}
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer) {
bool EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer) {
// When a zone's position or visibility changes, we call this method
// In order to resort our zones, we first remove the changed zone, and then re-insert it if necessary
remove(zone);
bool needsResort = false;
{
auto it = begin();
while (it != end()) {
if (it->zone.lock() == zone) {
break;
}
it++;
}
if (it != end()) {
erase(it);
needsResort = true;
}
}
// Only call contains if the zone is rendering
if (zone->isVisible() && entityTreeRenderer->renderableIdForEntity(zone) != render::Item::INVALID_ITEM_ID && zone->contains(position)) {
emplace(zone);
emplace_back(zone);
needsResort = true;
}
if (needsResort) {
sort();
}
return needsResort;
}
bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const {
@ -1254,9 +1262,9 @@ bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const {
return false;
}
auto it = c.cbegin();
auto otherIt = other.c.cbegin();
while (it != c.cend()) {
auto it = cbegin();
auto otherIt = other.cbegin();
while (it != cend()) {
if (*it != *otherIt) {
return false;
}
@ -1268,15 +1276,13 @@ bool EntityTreeRenderer::LayeredZones::equals(const LayeredZones& other) const {
}
void EntityTreeRenderer::LayeredZones::appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const {
auto it = c.cbegin();
while (it != c.cend()) {
for (auto it = cbegin(); it != cend(); it++) {
if (it->zone.lock()) {
auto id = entityTreeRenderer->renderableIdForEntityId(it->id);
if (id != render::Item::INVALID_ITEM_ID) {
list.push_back(id);
}
}
it++;
}
}

View file

@ -213,24 +213,24 @@ private:
public:
LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : zone(zone), id(zone->getID()), volume(zone->getVolumeEstimate()) {}
bool operator>(const LayeredZone& r) const { return volume > r.volume; }
bool operator==(const LayeredZone& r) const { return zone.lock() == r.zone.lock(); }
// We need to sort on volume AND id so that different clients sort zones with identical volumes the same way
bool operator<(const LayeredZone& r) const { return volume < r.volume || (volume == r.volume && id < r.id); }
bool operator==(const LayeredZone& r) const { return zone.lock() && zone.lock() == r.zone.lock(); }
bool operator!=(const LayeredZone& r) const { return !(*this == r); }
bool operator>=(const LayeredZone& r) const { return (*this > r) || (*this == r); }
bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
std::weak_ptr<ZoneEntityItem> zone;
QUuid id;
float volume;
};
class LayeredZones : public std::priority_queue<LayeredZone, std::vector<LayeredZone>, std::greater<LayeredZone>> {
class LayeredZones : public std::vector<LayeredZone> {
public:
void clear() { *this = LayeredZones(); }
bool clearDomainAndNonOwnedZones(const QUuid& sessionUUID);
void sort() { std::sort(begin(), end(), std::less<LayeredZone>()); }
bool equals(const LayeredZones& other) const;
void remove(const std::shared_ptr<ZoneEntityItem>& zone);
void update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer);
bool update(std::shared_ptr<ZoneEntityItem> zone, const glm::vec3& position, EntityTreeRenderer* entityTreeRenderer);
void appendRenderIDs(render::ItemIDs& list, EntityTreeRenderer* entityTreeRenderer) const;
std::pair<bool, bool> getZoneInteractionProperties() const;

View file

@ -261,15 +261,17 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
Transform transform;
bool hasTickMarks;
glm::vec4 tickProperties;
bool forward;
withReadLock([&] {
transform = _renderTransform;
hasTickMarks = _ringProperties.getHasTickMarks();
tickProperties = glm::vec4(_ringProperties.getMajorTickMarksAngle(), _ringProperties.getMajorTickMarksLength(),
_ringProperties.getMinorTickMarksAngle(), _ringProperties.getMinorTickMarksLength());
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
});
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
geometryCache->bindSimpleProgram(batch, false, isTransparent(), false, wireframe, true, true, _renderLayer != RenderLayer::WORLD);
geometryCache->bindSimpleProgram(batch, false, isTransparent(), false, wireframe, true, true, forward);
batch.setModelTransform(transform);

View file

@ -113,11 +113,13 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
glm::vec4 color;
glm::vec3 dimensions;
Transform renderTransform;
bool forward;
withReadLock([&] {
color = glm::vec4(toGlm(_color), _alpha);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
dimensions = _dimensions;
renderTransform = _renderTransform;
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
});
if (!_visible) {
@ -153,5 +155,5 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
minorGridRowDivisions, minorGridColDivisions, MINOR_GRID_EDGE,
majorGridRowDivisions, majorGridColDivisions, MAJOR_GRID_EDGE,
color, _geometryId);
color, forward, _geometryId);
}

View file

@ -55,7 +55,8 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
transform.setRotation(modelTransform.getRotation());
batch.setModelTransform(transform);
if (_linePoints.size() > 1) {
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, false, false, true,
_renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
}
}

View file

@ -1522,7 +1522,7 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
model = _model;
});
if (model) {
model->renderDebugMeshBoxes(batch);
model->renderDebugMeshBoxes(batch, args->_renderMethod == Args::RenderMethod::FORWARD);
}
#endif
}

View file

@ -19,15 +19,12 @@
#include <PerfStat.h>
#include <shaders/Shaders.h>
#include <DisableDeferred.h>
#include "paintStroke_Shared.slh"
using namespace render;
using namespace render::entities;
gpu::PipelinePointer PolyLineEntityRenderer::_pipeline = nullptr;
gpu::PipelinePointer PolyLineEntityRenderer::_glowPipeline = nullptr;
std::map<std::pair<render::Args::RenderMethod, bool>, gpu::PipelinePointer> PolyLineEntityRenderer::_pipelines;
static const QUrl DEFAULT_POLYLINE_TEXTURE = PathUtils::resourcesUrl("images/paintStroke.png");
@ -44,29 +41,24 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity)
}
}
void PolyLineEntityRenderer::buildPipeline() {
// FIXME: opaque pipeline
gpu::ShaderPointer program = gpu::Shader::createProgram(DISABLE_DEFERRED ? shader::entities_renderer::program::paintStroke_forward : shader::entities_renderer::program::paintStroke);
void PolyLineEntityRenderer::buildPipelines() {
// FIXME: opaque pipelines
static const std::vector<std::pair<render::Args::RenderMethod, bool>> keys = {
{ render::Args::DEFERRED, false }, { render::Args::DEFERRED, true }, { render::Args::FORWARD, false }, { render::Args::FORWARD, true },
};
for (auto& key : keys) {
gpu::ShaderPointer program = gpu::Shader::createProgram(key.first == render::Args::DEFERRED ? shader::entities_renderer::program::paintStroke : shader::entities_renderer::program::paintStroke_forward);
{
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setCullMode(gpu::State::CullMode::CULL_NONE);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setDepthTest(true, !key.second, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_pipeline = gpu::Pipeline::create(program, state);
}
{
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setCullMode(gpu::State::CullMode::CULL_NONE);
state->setDepthTest(true, false, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_glowPipeline = gpu::Pipeline::create(program, state);
_pipelines[key] = gpu::Pipeline::create(program, state);
}
}
@ -299,11 +291,11 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
return;
}
if (!_pipeline) {
buildPipeline();
if (_pipelines.empty()) {
buildPipelines();
}
batch.setPipeline(_glow ? _glowPipeline : _pipeline);
batch.setPipeline(_pipelines[{args->_renderMethod, _glow}]);
batch.setModelTransform(transform);
batch.setResourceTexture(0, texture);
batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);

View file

@ -37,7 +37,7 @@ protected:
virtual ShapeKey getShapeKey() override;
virtual void doRender(RenderArgs* args) override;
void buildPipeline();
static void buildPipelines();
void updateGeometry();
void updateData();
@ -58,8 +58,7 @@ protected:
size_t _numVertices;
gpu::BufferPointer _polylineDataBuffer;
gpu::BufferPointer _polylineGeometryBuffer;
static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _glowPipeline;
static std::map<std::pair<render::Args::RenderMethod, bool>, gpu::PipelinePointer> _pipelines;
};
} } // namespace

View file

@ -280,7 +280,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
render::ShapePipelinePointer pipeline;
if (renderLayer == RenderLayer::WORLD) {
if (renderLayer == RenderLayer::WORLD && args->_renderMethod != Args::RenderMethod::FORWARD) {
pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
} else {
pipeline = outColor.a < 1.0f ? geometryCache->getForwardTransparentShapePipeline() : geometryCache->getForwardOpaqueShapePipeline();

View file

@ -163,7 +163,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
Transform modelTransform;
glm::vec3 dimensions;
BillboardMode billboardMode;
bool layered;
bool forward;
withReadLock([&] {
modelTransform = _renderTransform;
dimensions = _dimensions;
@ -174,7 +174,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
textColor = EntityRenderer::calculatePulseColor(textColor, _pulseProperties, _created);
backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
layered = _renderLayer != RenderLayer::WORLD;
forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
});
// Render background
@ -187,7 +187,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
// FIXME: we need to find a better way of rendering text so we don't have to do this
if (layered) {
if (forward) {
DependencyManager::get<DeferredLightingEffect>()->setupKeyLightBatch(args, batch);
}
@ -199,7 +199,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
if (backgroundColor.a > 0.0f) {
batch.setModelTransform(transformToTopLeft);
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->bindSimpleProgram(batch, false, backgroundColor.a < 1.0f, false, false, false, true, layered);
geometryCache->bindSimpleProgram(batch, false, backgroundColor.a < 1.0f, false, false, false, true, forward);
geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID);
}
@ -210,7 +210,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
batch.setModelTransform(transformToTopLeft);
glm::vec2 bounds = glm::vec2(dimensions.x - (_leftMargin + _rightMargin), dimensions.y - (_topMargin + _bottomMargin));
_textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale, layered);
_textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale, forward);
}
}

View file

@ -288,6 +288,7 @@ void Procedural::prepare(gpu::Batch& batch,
recompiledShader = true;
}
// FIXME: need to handle forward rendering
batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second);
if (_shaderDirty || _uniformsDirty) {

View file

@ -37,8 +37,6 @@
#include "DeferredLightingEffect.h"
#include <DisableDeferred.h>
namespace gr {
using graphics::slot::texture::Texture;
using graphics::slot::buffer::Buffer;
@ -115,6 +113,8 @@ static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, no
static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
std::map<std::pair<bool, bool>, gpu::PipelinePointer> GeometryCache::_gridPipelines;
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
auto geometryCache = DependencyManager::get<GeometryCache>();
@ -714,11 +714,13 @@ QHash<SimpleProgramKey, gpu::PipelinePointer> GeometryCache::_simplePrograms;
gpu::ShaderPointer GeometryCache::_simpleShader;
gpu::ShaderPointer GeometryCache::_transparentShader;
gpu::ShaderPointer GeometryCache::_unlitShader;
gpu::ShaderPointer GeometryCache::_simpleFadeShader;
gpu::ShaderPointer GeometryCache::_unlitFadeShader;
gpu::ShaderPointer GeometryCache::_forwardSimpleShader;
gpu::ShaderPointer GeometryCache::_forwardTransparentShader;
gpu::ShaderPointer GeometryCache::_forwardUnlitShader;
gpu::ShaderPointer GeometryCache::_simpleFadeShader;
gpu::ShaderPointer GeometryCache::_unlitFadeShader;
gpu::ShaderPointer GeometryCache::_forwardSimpleFadeShader;
gpu::ShaderPointer GeometryCache::_forwardUnlitFadeShader;
render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline;
render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline;
@ -740,16 +742,13 @@ render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::S
if (key.isFaded()) {
if (key.isTranslucent()) {
return _simpleTransparentFadePipeline;
}
else {
} else {
return _simpleOpaqueFadePipeline;
}
}
else {
} else {
if (key.isTranslucent()) {
return _simpleTransparentPipeline;
}
else {
} else {
return _simpleOpaquePipeline;
}
}
@ -805,6 +804,8 @@ void GeometryCache::initializeShapePipelines() {
_simpleTransparentPipeline = getShapePipeline(false, true, true, false);
_forwardSimpleOpaquePipeline = getShapePipeline(false, false, true, false, false, true);
_forwardSimpleTransparentPipeline = getShapePipeline(false, true, true, false, false, true);
// FIXME: these need forward pipelines
_simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false);
_simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false);
_simpleWirePipeline = getShapePipeline(false, false, true, true);
@ -823,11 +824,11 @@ render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool
}
render::ShapePipelinePointer GeometryCache::getFadingShapePipeline(bool textured, bool transparent, bool culled,
bool unlit, bool depthBias) {
bool unlit, bool depthBias, bool forward) {
auto fadeEffect = DependencyManager::get<FadeEffect>();
auto fadeBatchSetter = fadeEffect->getBatchSetter();
auto fadeItemSetter = fadeEffect->getItemUniformSetter();
return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true), nullptr,
return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true, true, forward), nullptr,
[fadeBatchSetter, fadeItemSetter](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args* args) {
batch.setResourceTexture(gr::Texture::MaterialAlbedo, DependencyManager::get<TextureCache>()->getWhiteTexture());
fadeBatchSetter(shapePipeline, batch, args);
@ -937,7 +938,7 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color)
void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int majorRows, int majorCols, float majorEdge, int minorRows, int minorCols, float minorEdge,
const glm::vec4& color, int id) {
const glm::vec4& color, bool forward, int id) {
Vec2FloatPair majorKey(glm::vec2(majorRows, majorCols), majorEdge);
Vec2FloatPair minorKey(glm::vec2(minorRows, minorCols), minorEdge);
Vec2FloatPairPair key(majorKey, minorKey);
@ -970,7 +971,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co
}
// Set the grid pipeline
useGridPipeline(batch, gridBuffer, color.a < 1.0f);
useGridPipeline(batch, gridBuffer, color.a < 1.0f, forward);
static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f);
static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f);
@ -2038,39 +2039,34 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
}
}
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent) {
if (!_gridPipelineOpaque || !_gridPipelineTransparent) {
void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent, bool forward) {
if (_gridPipelines.empty()) {
using namespace shader::render_utils::program;
const float DEPTH_BIAS = 0.001f;
// FIXME: need forward pipelines
{
auto program = gpu::Shader::createProgram(shader::render_utils::program::grid);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMaskDrawShape(*state);
state->setCullMode(gpu::State::CULL_NONE);
state->setDepthBias(DEPTH_BIAS);
_gridPipelineOpaque = gpu::Pipeline::create(program, state);
}
static const std::vector<std::tuple<bool, bool, uint32_t>> keys = {
std::make_tuple(false, false, grid), std::make_tuple(false, true, forward_grid), std::make_tuple(true, false, grid_translucent), std::make_tuple(true, true, forward_grid_translucent)
};
{
auto program = gpu::Shader::createProgram(shader::render_utils::program::grid_translucent);
auto state = std::make_shared<gpu::State>();
for (auto& key : keys) {
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true,
if (std::get<0>(key)) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
state->setBlendFunction(std::get<0>(key),
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
state->setCullMode(gpu::State::CULL_NONE);
state->setDepthBias(DEPTH_BIAS);
_gridPipelineTransparent = gpu::Pipeline::create(program, state);
_gridPipelines[{std::get<0>(key), std::get<1>(key)}] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state);
}
}
batch.setPipeline(transparent ? _gridPipelineTransparent : _gridPipelineOpaque);
batch.setPipeline(_gridPipelines[{ transparent, forward }]);
batch.setUniformBuffer(0, gridBuffer);
}
@ -2162,6 +2158,7 @@ void GeometryCache::bindWebBrowserProgram(gpu::Batch& batch, bool transparent) {
gpu::PipelinePointer GeometryCache::getWebBrowserProgram(bool transparent) {
static std::once_flag once;
std::call_once(once, [&]() {
// FIXME: need a forward pipeline for this
buildWebShader(shader::render_utils::program::simple_opaque_web_browser, false, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipeline);
buildWebShader(shader::render_utils::program::simple_transparent_web_browser, true, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipeline);
});
@ -2197,22 +2194,21 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
_forwardSimpleShader = gpu::Shader::createProgram(forward_simple_textured);
_forwardTransparentShader = gpu::Shader::createProgram(forward_simple_textured_transparent);
_forwardUnlitShader = gpu::Shader::createProgram(forward_simple_textured_unlit);
if (DISABLE_DEFERRED) {
_simpleShader = _forwardSimpleShader;
_transparentShader = _forwardTransparentShader;
_unlitShader = _forwardUnlitShader;
} else {
_simpleShader = gpu::Shader::createProgram(simple_textured);
_transparentShader = gpu::Shader::createProgram(simple_transparent_textured);
_unlitShader = gpu::Shader::createProgram(simple_textured_unlit);
}
_simpleShader = gpu::Shader::createProgram(simple_textured);
_transparentShader = gpu::Shader::createProgram(simple_transparent_textured);
_unlitShader = gpu::Shader::createProgram(simple_textured_unlit);
});
} else {
static std::once_flag once;
std::call_once(once, [&]() {
using namespace shader::render_utils::program;
_simpleFadeShader = gpu::Shader::createProgram(DISABLE_DEFERRED ? forward_simple_textured : simple_textured_fade);
_unlitFadeShader = gpu::Shader::createProgram(DISABLE_DEFERRED ? forward_simple_textured_unlit : simple_textured_unlit_fade);
// FIXME: these aren't right...
_forwardSimpleFadeShader = gpu::Shader::createProgram(forward_simple_textured);
_forwardUnlitFadeShader = gpu::Shader::createProgram(forward_simple_textured_unlit);
_simpleFadeShader = gpu::Shader::createProgram(simple_textured_fade);
_unlitFadeShader = gpu::Shader::createProgram(simple_textured_unlit_fade);
});
}
@ -2240,8 +2236,8 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
gpu::ShaderPointer program;
if (config.isForward()) {
program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _forwardUnlitShader) :
(config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _forwardTransparentShader : _forwardSimpleShader));
program = (config.isUnlit()) ? (config.isFading() ? _forwardUnlitFadeShader : _forwardUnlitShader) :
(config.isFading() ? _forwardSimpleFadeShader : (config.isTransparent() ? _forwardTransparentShader : _forwardSimpleShader));
} else {
program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) :
(config.isFading() ? _simpleFadeShader : (config.isTransparent() ? _transparentShader : _simpleShader));

View file

@ -266,7 +266,7 @@ public:
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int majorRows, int majorCols, float majorEdge,
int minorRows, int minorCols, float minorEdge,
const glm::vec4& color, int id);
const glm::vec4& color, bool forward, int id);
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id);
@ -400,9 +400,8 @@ private:
glm::vec4 edge;
};
using GridBuffer = gpu::BufferView;
void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered);
gpu::PipelinePointer _gridPipelineOpaque;
gpu::PipelinePointer _gridPipelineTransparent;
void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool transparent, bool forward);
static std::map<std::pair<bool, bool>, gpu::PipelinePointer> _gridPipelines;
class BatchItemDetails {
public:
@ -460,11 +459,14 @@ private:
static gpu::ShaderPointer _simpleShader;
static gpu::ShaderPointer _transparentShader;
static gpu::ShaderPointer _unlitShader;
static gpu::ShaderPointer _simpleFadeShader;
static gpu::ShaderPointer _unlitFadeShader;
static gpu::ShaderPointer _forwardSimpleShader;
static gpu::ShaderPointer _forwardTransparentShader;
static gpu::ShaderPointer _forwardUnlitShader;
static gpu::ShaderPointer _simpleFadeShader;
static gpu::ShaderPointer _unlitFadeShader;
static gpu::ShaderPointer _forwardSimpleFadeShader;
static gpu::ShaderPointer _forwardUnlitFadeShader;
static render::ShapePipelinePointer _simpleOpaquePipeline;
static render::ShapePipelinePointer _simpleTransparentPipeline;
static render::ShapePipelinePointer _forwardSimpleOpaquePipeline;
@ -483,7 +485,7 @@ private:
static render::ShapePipelinePointer getShapePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false, bool forward = false);
static render::ShapePipelinePointer getFadingShapePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false);
bool unlit = false, bool depthBias = false, bool forward = false);
};
#endif // hifi_GeometryCache_h

View file

@ -1033,7 +1033,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
_renderInfoHasTransparent = false;
}
void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
void Model::renderDebugMeshBoxes(gpu::Batch& batch, bool forward) {
int colorNdx = 0;
_mutex.lock();
@ -1042,7 +1042,7 @@ void Model::renderDebugMeshBoxes(gpu::Batch& batch) {
Transform meshToWorld(meshToWorldMatrix);
batch.setModelTransform(meshToWorld);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, true, true, forward);
for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
for (auto &partTriangleSet : meshTriangleSets) {

View file

@ -347,7 +347,7 @@ public:
const QMap<render::ItemID, render::PayloadPointer>& getRenderItems() const { return _modelMeshRenderItemsMap; }
BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; }
void renderDebugMeshBoxes(gpu::Batch& batch);
void renderDebugMeshBoxes(gpu::Batch& batch, bool forward);
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }

View file

@ -137,4 +137,16 @@ public:
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output);
};
class SetRenderMethod {
public:
using JobModel = render::Job::Model<SetRenderMethod>;
SetRenderMethod(render::Args::RenderMethod method) : _method(method) {}
void run(const render::RenderContextPointer& renderContext) { renderContext->args->_renderMethod = _method; }
protected:
render::Args::RenderMethod _method;
};
#endif // hifi_RenderDeferredTask_h

View file

@ -48,6 +48,8 @@ using namespace render;
extern void initForwardPipelines(ShapePlumber& plumber);
void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
task.addJob<SetRenderMethod>("SetRenderMethodTask", render::Args::FORWARD);
// Prepare the ShapePipelines
auto fadeEffect = DependencyManager::get<FadeEffect>();
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();

View file

@ -228,9 +228,11 @@ void initForwardPipelines(ShapePlumber& plumber) {
// Opaques
addPipeline(Key::Builder().withMaterial(), program::forward_model);
addPipeline(Key::Builder().withMaterial().withLightmap(), program::forward_model_lightmap);
addPipeline(Key::Builder().withMaterial().withUnlit(), program::forward_model_unlit);
addPipeline(Key::Builder().withMaterial().withTangents(), program::forward_model_normal_map);
addPipeline(Key::Builder().withMaterial().withTangents().withLightmap(), program::forward_model_normal_map_lightmap);
// Deformed Opaques
addPipeline(Key::Builder().withMaterial().withDeformed(), program::forward_deformed_model);
addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), program::forward_deformed_model_normal_map);

View file

@ -10,14 +10,37 @@
//
#include "RenderViewTask.h"
#include "AssembleLightingStageTask.h"
#include "RenderShadowTask.h"
#include "RenderCommonTask.h"
#include "RenderDeferredTask.h"
#include "RenderForwardTask.h"
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits, uint8_t tagMask) {
#include <RenderForward.h>
void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
task.addJob<SetRenderMethod>("SetRenderMethodTask", render::Args::DEFERRED);
const auto items = input.getN<DeferredForwardSwitchJob::Input>(0);
const auto lightingModel = input.getN<DeferredForwardSwitchJob::Input>(1);
const auto lightingStageFramesAndZones = input.getN<DeferredForwardSwitchJob::Input>(2);
// Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling
// is performed, then casters not in the view frustum will be removed, which is not what we wish.
const auto shadowTaskIn = RenderShadowTask::Input(lightingStageFramesAndZones.get<AssembleLightingStageTask::Output>().get0()[0], lightingModel).asVarying();
const auto shadowTaskOut = task.addJob<RenderShadowTask>("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask);
const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying();
task.addJob<RenderDeferredTask>("RenderDeferredTask", renderDeferredInput);
}
void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
task.addBranch<RenderShadowsAndDeferredTask>("RenderShadowsAndDeferredTask", RENDER_FORWARD ? 1 : 0, input, cullFunctor, tagBits, tagMask);
task.addBranch<RenderForwardTask>("RenderForwardTask", RENDER_FORWARD ? 0 : 1, input);
}
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) {
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor, tagBits, tagMask);
assert(items.canCast<RenderFetchCullSortTask::Output>());
// Issue the lighting model, aka the big global settings for the view
const auto lightingModel = task.addJob<MakeLightingModel>("LightingModel");
@ -25,17 +48,11 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
// Assemble the lighting stages current frames
const auto lightingStageFramesAndZones = task.addJob<AssembleLightingStageTask>("AssembleStages", items);
if (isDeferred) {
// Warning : the cull functor passed to the shadow pass should only be testing for LOD culling. If frustum culling
// is performed, then casters not in the view frustum will be removed, which is not what we wish.
const auto shadowTaskIn = RenderShadowTask::Input(lightingStageFramesAndZones.get<AssembleLightingStageTask::Output>().get0()[0], lightingModel).asVarying();
const auto shadowTaskOut = task.addJob<RenderShadowTask>("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask);
const auto renderInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying();
task.addJob<RenderDeferredTask>("RenderDeferredTask", renderInput);
} else {
#ifndef Q_OS_ANDROID
const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying();
task.addJob<DeferredForwardSwitchJob>("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask);
#else
const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying();
task.addJob<RenderForwardTask>("Forward", renderInput);
}
task.addJob<RenderForwardTask>("RenderForwardTask", renderInput);
#endif
}

View file

@ -15,6 +15,30 @@
#include <render/Engine.h>
#include <render/RenderFetchCullSortTask.h>
#include "AssembleLightingStageTask.h"
class RenderShadowsAndDeferredTask {
public:
using Input = render::VaryingSet3<RenderFetchCullSortTask::Output, LightingModelPointer, AssembleLightingStageTask::Output>;
using JobModel = render::Task::ModelI<RenderShadowsAndDeferredTask, Input>;
RenderShadowsAndDeferredTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask);
};
class DeferredForwardSwitchJob {
public:
using Input = render::VaryingSet3<RenderFetchCullSortTask::Output, LightingModelPointer, AssembleLightingStageTask::Output>;
using JobModel = render::Switch::ModelI<DeferredForwardSwitchJob, Input>;
DeferredForwardSwitchJob() {}
void configure(const render::SwitchConfig& config) {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask);
};
class RenderViewTask {
public:
@ -23,7 +47,7 @@ public:
RenderViewTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00);
};

View file

@ -67,11 +67,11 @@ float TextRenderer3D::getFontSize() const {
}
void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color,
const glm::vec2& bounds, bool layered) {
const glm::vec2& bounds, bool forward) {
// The font does all the OpenGL work
if (_font) {
_color = color;
_font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, layered);
_font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, forward);
}
}

View file

@ -38,8 +38,8 @@ public:
glm::vec2 computeExtent(const QString& str) const;
float getFontSize() const; // Pixel size
void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f),
const glm::vec2& bounds = glm::vec2(-1.0f), bool layered = false);
void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color,
const glm::vec2& bounds, bool forward);
private:
TextRenderer3D(const char* family, float pointSize, int weight = -1, bool italic = false,

View file

@ -0,0 +1,40 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gondelman on 5/9/19
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/ShaderConstants.h@>
<@include gpu/Paint.slh@>
struct Grid {
vec4 period;
vec4 offset;
vec4 edge;
};
LAYOUT(binding=0) uniform gridBuffer {
Grid grid;
};
layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0;
layout(location=GPU_ATTR_COLOR) in vec4 varColor;
layout(location=0) out vec4 _fragColor0;
void main(void) {
float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge),
paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy),
float(grid.edge.z == 0.0));
if (alpha < 0.0001) {
discard;
}
_fragColor0 = vec4(varColor.xyz, 1.0);
}

View file

@ -0,0 +1,41 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gondelman on 5/9/19
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/ShaderConstants.h@>
<@include gpu/Paint.slh@>
struct Grid {
vec4 period;
vec4 offset;
vec4 edge;
};
LAYOUT(binding=0) uniform gridBuffer {
Grid grid;
};
layout(location=GPU_ATTR_TEXCOORD0) in vec2 varTexCoord0;
layout(location=GPU_ATTR_COLOR) in vec4 varColor;
layout(location=0) out vec4 _fragColor0;
void main(void) {
float alpha = mix(paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge),
paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy),
float(grid.edge.z == 0.0));
alpha *= varColor.w;
if (alpha < 0.0001) {
discard;
}
_fragColor0 = vec4(varColor.xyz, alpha);
}

View file

@ -0,0 +1,71 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// <$_SCRIBE_FILENAME$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gateau on 2/15/2016.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<@include render-utils/ShaderConstants.h@>
<@include ForwardGlobalLight.slh@>
<$declareEvalLightmappedColor()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$>
<$declareMaterialLightmap()$>
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color;
layout(location=0) out vec4 _fragColor0;
void main(void) {
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color.rgb;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
vec3 fragNormal = normalize(_normalWS);
TransformCamera cam = getTransformCamera();
vec4 color = vec4(evalLightmappedColor(
cam._viewInverse,
1.0,
1.0,
fragNormal,
albedo,
lightmap),
opacity);
_fragColor0 = color;
}

View file

@ -0,0 +1,74 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// <$_SCRIBE_FILENAME$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gateau on 2/15/2016.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DefaultMaterials.slh@>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<@include render-utils/ShaderConstants.h@>
<@include ForwardGlobalLight.slh@>
<$declareEvalLightmappedColor()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$>
<$declareMaterialLightmap()$>
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
#define _texCoord1 _texCoord01.zw
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
layout(location=RENDER_UTILS_ATTR_TANGENT_WS) in vec3 _tangentWS;
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color;
layout(location=0) out vec4 _fragColor0;
void main(void) {
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color.rgb;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
vec3 fragPosition = _positionES.xyz;
vec3 fragNormal;
<$evalMaterialNormalLOD(fragPosition, normalTex, _normalWS, _tangentWS, fragNormal)$>
TransformCamera cam = getTransformCamera();
vec4 color = vec4(evalLightmappedColor(
cam._viewInverse,
1.0,
1.0,
fragNormal,
albedo,
lightmap),
opacity);
_fragColor0 = color;
}

View file

@ -0,0 +1,18 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gondelman on 5/9/19
// Copyright 2019 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
//
layout(location=0) in vec4 _color;
layout(location=0) out vec4 _fragColor0;
void main(void) {
_fragColor0 = _color;
}

View file

@ -1,7 +0,0 @@
layout(location=0) in vec4 _color;
layout(location=0) out vec4 _fragColor0;
void main(void) {
_fragColor0 = _color;
}

View file

@ -0,0 +1 @@
VERTEX standardTransformPNTC

View file

@ -0,0 +1 @@
VERTEX standardTransformPNTC

View file

@ -0,0 +1 @@
VERTEX model

View file

@ -0,0 +1 @@
VERTEX model_normal_map

View file

@ -0,0 +1 @@
VERTEX parabola

View file

@ -13,10 +13,13 @@
#include "FontFamilies.h"
#include "../StencilMaskPass.h"
#include "DisableDeferred.h"
static std::mutex fontMutex;
gpu::PipelinePointer Font::_deferredPipeline;
gpu::PipelinePointer Font::_forwardPipeline;
gpu::PipelinePointer Font::_transparentPipeline;
gpu::Stream::FormatPointer Font::_format;
struct TextureVertex {
glm::vec2 pos;
glm::vec2 tex;
@ -218,13 +221,10 @@ void Font::read(QIODevice& in) {
}
void Font::setupGPU() {
if (!_initialized) {
_initialized = true;
if (!_deferredPipeline) {
// Setup render pipeline
{
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::forward_sdf_text3D);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
@ -232,25 +232,11 @@ void Font::setupGPU() {
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMaskDrawShape(*state);
_layeredPipeline = gpu::Pipeline::create(program, state);
}
if (DISABLE_DEFERRED) {
_pipeline = _layeredPipeline;
} else {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMaskDrawShape(*state);
_pipeline = gpu::Pipeline::create(program, state);
_deferredPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D), state);
_forwardPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::forward_sdf_text3D), state);
}
{
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D_transparent);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
@ -258,7 +244,7 @@ void Font::setupGPU() {
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
PrepareStencil::testMask(*state);
_transparentPipeline = gpu::Pipeline::create(program, state);
_transparentPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(shader::render_utils::program::sdf_text3D_transparent), state);
}
}
@ -363,7 +349,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
}
void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool layered) {
EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool forward) {
if (str == "") {
return;
}
@ -390,7 +376,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString
}
// need the gamma corrected color here
batch.setPipeline(color.a < 1.0f ? _transparentPipeline : (layered ? _layeredPipeline : _pipeline));
batch.setPipeline(color.a < 1.0f ? _transparentPipeline : (forward ? _forwardPipeline : _deferredPipeline));
batch.setInputFormat(_format);
batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride);
batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture);

View file

@ -46,7 +46,7 @@ public:
// Render string to batch
void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str,
const glm::vec4& color, EffectType effectType,
const glm::vec2& origin, const glm::vec2& bound, bool layered);
const glm::vec2& origin, const glm::vec2& bound, bool forward);
static Pointer load(const QString& family);
@ -77,15 +77,13 @@ private:
float _descent = 0.0f;
float _spaceWidth = 0.0f;
bool _initialized = false;
// gpu structures
gpu::PipelinePointer _pipeline;
gpu::PipelinePointer _layeredPipeline;
gpu::PipelinePointer _transparentPipeline;
gpu::TexturePointer _texture;
gpu::Stream::FormatPointer _format;
gpu::BufferStreamPointer _stream;
static gpu::PipelinePointer _deferredPipeline;
static gpu::PipelinePointer _forwardPipeline;
static gpu::PipelinePointer _transparentPipeline;
static gpu::Stream::FormatPointer _format;
};
#endif

View file

@ -64,6 +64,7 @@ namespace render {
public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
enum RenderMethod { DEFERRED, FORWARD };
enum DebugFlags {
RENDER_DEBUG_NONE = 0,
RENDER_DEBUG_HULLS = 1
@ -77,6 +78,7 @@ namespace render {
float lodAngleHalfTan = 0.1f,
RenderMode renderMode = DEFAULT_RENDER_MODE,
DisplayMode displayMode = MONO,
RenderMethod renderMethod = DEFERRED,
DebugFlags debugFlags = RENDER_DEBUG_NONE,
gpu::Batch* batch = nullptr) :
_context(context),
@ -86,6 +88,7 @@ namespace render {
_lodAngleHalfTanSq(lodAngleHalfTan * lodAngleHalfTan),
_renderMode(renderMode),
_displayMode(displayMode),
_renderMethod(renderMethod),
_debugFlags(debugFlags),
_batch(batch) {
}
@ -117,6 +120,7 @@ namespace render {
RenderMode _renderMode { DEFAULT_RENDER_MODE };
DisplayMode _displayMode { MONO };
RenderMethod _renderMethod { DEFERRED };
DebugFlags _debugFlags { RENDER_DEBUG_NONE };
gpu::Batch* _batch = nullptr;

View file

@ -21,6 +21,8 @@ DependencyManager& DependencyManager::manager() {
return *instance;
}
QSharedPointer<Dependency>& DependencyManager::safeGet(size_t hashCode) {
return _instanceHash[hashCode];
QSharedPointer<Dependency> DependencyManager::safeGet(size_t hashCode) const {
QMutexLocker lock(&_instanceHashMutex);
return _instanceHash.value(hashCode);
}

View file

@ -17,6 +17,7 @@
#include <QHash>
#include <QSharedPointer>
#include <QWeakPointer>
#include <QMutex>
#include <functional>
#include <typeinfo>
@ -81,13 +82,16 @@ private:
static DependencyManager& manager();
template<typename T>
size_t getHashCode();
size_t getHashCode() const;
QSharedPointer<Dependency>& safeGet(size_t hashCode);
QSharedPointer<Dependency> safeGet(size_t hashCode) const;
QHash<size_t, QSharedPointer<Dependency>> _instanceHash;
QHash<size_t, size_t> _inheritanceHash;
mutable QMutex _instanceHashMutex;
mutable QMutex _inheritanceHashMutex;
bool _exiting { false };
};
@ -121,19 +125,23 @@ template <typename T>
bool DependencyManager::isSet() {
static size_t hashCode = manager().getHashCode<T>();
QSharedPointer<Dependency>& instance = manager().safeGet(hashCode);
QSharedPointer<Dependency> instance = manager().safeGet(hashCode);
return !instance.isNull();
}
template <typename T, typename ...Args>
QSharedPointer<T> DependencyManager::set(Args&&... args) {
static size_t hashCode = manager().getHashCode<T>();
QMutexLocker lock(&manager()._instanceHashMutex);
// clear the previous instance before constructing the new instance
auto iter = manager()._instanceHash.find(hashCode);
if (iter != manager()._instanceHash.end()) {
iter.value().clear();
}
QSharedPointer<Dependency>& instance = manager().safeGet(hashCode);
instance.clear(); // Clear instance before creation of new one to avoid edge cases
QSharedPointer<T> newInstance(new T(args...), &T::customDeleter);
QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(newInstance);
instance.swap(storedInstance);
manager()._instanceHash.insert(hashCode, newInstance);
return newInstance;
}
@ -141,12 +149,16 @@ QSharedPointer<T> DependencyManager::set(Args&&... args) {
template <typename T, typename I, typename ...Args>
QSharedPointer<T> DependencyManager::set(Args&&... args) {
static size_t hashCode = manager().getHashCode<T>();
QMutexLocker lock(&manager()._instanceHashMutex);
// clear the previous instance before constructing the new instance
auto iter = manager()._instanceHash.find(hashCode);
if (iter != manager()._instanceHash.end()) {
iter.value().clear();
}
QSharedPointer<Dependency>& instance = manager().safeGet(hashCode);
instance.clear(); // Clear instance before creation of new one to avoid edge cases
QSharedPointer<T> newInstance(new I(args...), &I::customDeleter);
QSharedPointer<Dependency> storedInstance = qSharedPointerCast<Dependency>(newInstance);
instance.swap(storedInstance);
manager()._instanceHash.insert(hashCode, newInstance);
return newInstance;
}
@ -154,9 +166,12 @@ QSharedPointer<T> DependencyManager::set(Args&&... args) {
template <typename T>
void DependencyManager::destroy() {
static size_t hashCode = manager().getHashCode<T>();
QSharedPointer<Dependency>& shared = manager().safeGet(hashCode);
QMutexLocker lock(&manager()._instanceHashMutex);
QSharedPointer<Dependency> shared = manager()._instanceHash.take(hashCode);
QWeakPointer<Dependency> weak = shared;
shared.clear();
// Check that the dependency was actually destroyed. If it wasn't, it was improperly captured somewhere
if (weak.lock()) {
qWarning() << "DependencyManager::destroy():" << typeid(T).name() << "was not properly destroyed!";
@ -167,12 +182,14 @@ template<typename Base, typename Derived>
void DependencyManager::registerInheritance() {
size_t baseHashCode = typeHash<Base>();
size_t derivedHashCode = typeHash<Derived>();
QMutexLocker lock(&manager()._inheritanceHashMutex);
manager()._inheritanceHash.insert(baseHashCode, derivedHashCode);
}
template<typename T>
size_t DependencyManager::getHashCode() {
size_t DependencyManager::getHashCode() const {
size_t hashCode = typeHash<T>();
QMutexLocker lock(&_inheritanceHashMutex);
auto derivedHashCode = _inheritanceHash.find(hashCode);
while (derivedHashCode != _inheritanceHash.end()) {

View file

@ -1,24 +0,0 @@
//
// Created by Sam Gondelman on 3/7/19.
// Copyright 2019 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_DisableDeferred_h
#define hifi_DisableDeferred_h
#include <QString>
#include <QProcess>
#if defined(USE_GLES)
static bool DISABLE_DEFERRED = true;
#else
static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" };
static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
#endif
#endif // hifi_DisableDeferred_h

View file

@ -39,7 +39,9 @@ Q_LOGGING_CATEGORY(trace_baker, "trace.baker")
#endif
static bool tracingEnabled() {
return DependencyManager::isSet<tracing::Tracer>() && DependencyManager::get<tracing::Tracer>()->isEnabled();
// Cheers, love! The cavalry's here!
auto tracer = DependencyManager::get<tracing::Tracer>();
return (tracer && tracer->isEnabled());
}
DurationBase::DurationBase(const QLoggingCategory& category, const QString& name) : _name(name), _category(category) {

View file

@ -0,0 +1,24 @@
//
// Created by Sam Gondelman on 3/7/19.
// Copyright 2019 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_RenderForward_h
#define hifi_RenderForward_h
#include <QString>
#include <QProcess>
#if defined(USE_GLES)
// This isn't necessary since android forces the forward renderer, but just in case
static bool RENDER_FORWARD = true;
#else
static const QString RENDER_FORWARD_STRING { "HIFI_RENDER_FORWARD" };
static bool RENDER_FORWARD = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD_STRING);
#endif
#endif // hifi_RenderForward_h

View file

@ -38,7 +38,7 @@ void JobConfig::setPresetList(const QJsonObject& object) {
}
}
void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::string& name) {
void JobConfig::connectChildConfig(std::shared_ptr<JobConfig> childConfig, const std::string& name) {
childConfig->setParent(this);
childConfig->setObjectName(name.c_str());
@ -52,7 +52,7 @@ void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::strin
}
}
void TaskConfig::transferChildrenConfigs(QConfigPointer source) {
void JobConfig::transferChildrenConfigs(std::shared_ptr<JobConfig> source) {
if (!source) {
return;
}
@ -70,13 +70,13 @@ void TaskConfig::transferChildrenConfigs(QConfigPointer source) {
}
}
void TaskConfig::refresh() {
void JobConfig::refresh() {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "refresh");
return;
}
_task->applyConfiguration();
_jobConcept->applyConfiguration();
}
TaskConfig* TaskConfig::getRootConfig(const std::string& jobPath, std::string& jobName) const {
@ -133,3 +133,11 @@ JobConfig* TaskConfig::getJobConfig(const std::string& jobPath) const {
return found;
}
}
void SwitchConfig::setBranch(uint8_t branch) {
if (_branch != branch) {
_branch = branch;
// We can re-use this signal here
emit dirtyEnabled();
}
}

View file

@ -154,6 +154,11 @@ public:
*/
Q_INVOKABLE virtual QObject* getSubConfig(int i) const { return nullptr; }
void connectChildConfig(std::shared_ptr<JobConfig> childConfig, const std::string& name);
void transferChildrenConfigs(std::shared_ptr<JobConfig> source);
JobConcept* _jobConcept;
public slots:
/**jsdoc
@ -162,6 +167,11 @@ public slots:
*/
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); }
/**jsdoc
* @function Render.refresh
*/
void refresh();
signals:
/**jsdoc
@ -248,18 +258,18 @@ public:
auto subs = getSubConfigs();
return ((i < 0 || i >= subs.size()) ? nullptr : subs[i]);
}
};
void connectChildConfig(QConfigPointer childConfig, const std::string& name);
void transferChildrenConfigs(QConfigPointer source);
class SwitchConfig : public JobConfig {
Q_OBJECT
Q_PROPERTY(bool branch READ getBranch WRITE setBranch NOTIFY dirtyEnabled)
JobConcept* _task;
public:
uint8_t getBranch() const { return _branch; }
void setBranch(uint8_t index);
public slots:
/**jsdoc
* @function Render.refresh
*/
void refresh();
protected:
uint8_t _branch { 0 };
};
}

View file

@ -15,6 +15,8 @@
#include "Config.h"
#include "Varying.h"
#include <unordered_map>
namespace task {
class JobConcept;
@ -175,6 +177,7 @@ public:
template <class T, class O, class C = Config> using ModelO = Model<T, C, None, O>;
template <class T, class I, class O, class C = Config> using ModelIO = Model<T, C, I, O>;
Job() {}
Job(const ConceptPointer& concept) : _concept(concept) {}
virtual ~Job() = default;
@ -244,25 +247,6 @@ public:
const Varying getOutput() const override { return _output; }
Varying& editInput() override { return _input; }
typename Jobs::iterator editJob(std::string name) {
typename Jobs::iterator jobIt;
for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) {
if (jobIt->getName() == name) {
return jobIt;
}
}
return jobIt;
}
typename Jobs::const_iterator getJob(std::string name) const {
typename Jobs::const_iterator jobIt;
for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) {
if (jobIt->getName() == name) {
return jobIt;
}
}
return jobIt;
}
TaskConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {}
// Create a new job in the container's queue; returns the job's output
@ -321,7 +305,7 @@ public:
// swap
Concept::_config = config;
// Capture this
std::static_pointer_cast<C>(Concept::_config)->_task = this;
Concept::_config->_jobConcept = this;
}
QConfigPointer& getConfiguration() override {
@ -369,8 +353,146 @@ public:
std::shared_ptr<Config> getConfiguration() {
return std::static_pointer_cast<Config>(JobType::_concept->getConfiguration());
}
};
protected:
// A Switch is a specialized job to run a collection of other jobs and switch between different branches at run time
// It can be created on any type T by aliasing the type JobModel in the class T
// using JobModel = Switch::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 branches of the switch
// where the input of the switch can be setup to feed the child jobs
// and where the output of the switch is defined
template <class JC, class TP>
class Switch : public Job<JC, TP> {
public:
using Context = JC;
using TimeProfiler = TP;
using ContextPointer = std::shared_ptr<Context>;
using Config = SwitchConfig;
using JobType = Job<JC, TP>;
using None = typename JobType::None;
using Concept = typename JobType::Concept;
using ConceptPointer = typename JobType::ConceptPointer;
using Branches = std::unordered_map<uint8_t, JobType>;
Switch(ConceptPointer concept) : JobType(concept) {}
class SwitchConcept : public Concept {
public:
Varying _input;
Varying _output;
Branches _branches;
const Varying getInput() const override { return _input; }
const Varying getOutput() const override { return _output; }
Varying& editInput() override { return _input; }
SwitchConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {}
template <class NT, class... NA> const Varying addBranch(std::string name, uint8_t index, const Varying& input, NA&&... args) {
auto& branch = _branches[index];
branch = JobType(NT::JobModel::create(name, input, std::forward<NA>(args)...));
// Conect the child config to this task's config
std::static_pointer_cast<SwitchConfig>(Concept::getConfiguration())->connectChildConfig(branch.getConfiguration(), name);
return branch.getOutput();
}
template <class NT, class... NA> const Varying addBranch(std::string name, uint8_t index, NA&&... args) {
const auto input = Varying(typename NT::JobModel::Input());
return addBranch<NT>(name, index, input, std::forward<NA>(args)...);
}
};
template <class T, class C = SwitchConfig, class I = None, class O = None> class SwitchModel : public SwitchConcept {
public:
using Data = T;
using Input = I;
using Output = O;
Data _data;
SwitchModel(const std::string& name, const Varying& input, QConfigPointer config) :
SwitchConcept(name, input, config),
_data(Data()) {
}
template <class... A>
static std::shared_ptr<SwitchModel> create(const std::string& name, const Varying& input, A&&... args) {
auto model = std::make_shared<SwitchModel>(name, input, std::make_shared<C>());
{
TimeProfiler probe("build::" + model->getName());
model->_data.build(*(model), model->_input, model->_output, std::forward<A>(args)...);
}
// Recreate the Config to use the templated type
model->createConfiguration();
model->applyConfiguration();
return model;
}
template <class... A>
static std::shared_ptr<SwitchModel> create(const std::string& name, A&&... args) {
const auto input = Varying(Input());
return create(name, 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(Concept::_config);
// swap
Concept::_config = config;
// Capture this
Concept::_config->_jobConcept = this;
}
QConfigPointer& getConfiguration() override {
if (!Concept::_config) {
createConfiguration();
}
return Concept::_config;
}
void applyConfiguration() override {
TimeProfiler probe("configure::" + JobConcept::getName());
jobConfigure(_data, *std::static_pointer_cast<C>(Concept::_config));
for (auto& branch : SwitchConcept::_branches) {
branch.second.applyConfiguration();
}
}
void run(const ContextPointer& jobContext) override {
auto config = std::static_pointer_cast<C>(Concept::_config);
if (config->isEnabled()) {
auto jobsIt = SwitchConcept::_branches.find(config->getBranch());
if (jobsIt != SwitchConcept::_branches.end()) {
jobsIt->second.run(jobContext);
}
}
}
};
template <class T, class C = SwitchConfig> using Model = SwitchModel<T, C, None, None>;
template <class T, class I, class C = SwitchConfig> using ModelI = SwitchModel<T, C, I, None>;
// TODO: Switches don't support Outputs yet
//template <class T, class O, class C = SwitchConfig> using ModelO = SwitchModel<T, C, None, O>;
//template <class T, class I, class O, class C = SwitchConfig> using ModelIO = SwitchModel<T, C, I, O>;
// Create a new job in the Switches' branches; returns the job's output
template <class T, class... A> const Varying addBranch(std::string name, uint8_t index, const Varying& input, A&&... args) {
return std::static_pointer_cast<SwitchConcept>(JobType::_concept)->template addBranch<T>(name, index, input, std::forward<A>(args)...);
}
template <class T, class... A> const Varying addBranch(std::string name, uint8_t index, A&&... args) {
const auto input = Varying(typename T::JobModel::Input());
return std::static_pointer_cast<SwitchConcept>(JobType::_concept)->template addBranch<T>(name, index, input, std::forward<A>(args)...);
}
std::shared_ptr<Config> getConfiguration() {
return std::static_pointer_cast<Config>(JobType::_concept->getConfiguration());
}
};
template <class JC, class TP>
@ -407,8 +529,10 @@ protected:
#define Task_DeclareTypeAliases(ContextType, TimeProfiler) \
using JobConfig = task::JobConfig; \
using TaskConfig = task::TaskConfig; \
using SwitchConfig = task::SwitchConfig; \
template <class T> using PersistentConfig = task::PersistentConfig<T>; \
using Job = task::Job<ContextType, TimeProfiler>; \
using Switch = task::Switch<ContextType, TimeProfiler>; \
using Task = task::Task<ContextType, TimeProfiler>; \
using Engine = task::Engine<ContextType, TimeProfiler>; \
using Varying = task::Varying; \

View file

@ -0,0 +1,218 @@
//
// Created by Anthony Thibault on May 9th 2019
// Copyright 2013-2019 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 "DependencyManagerTests.h"
#include <QtTest/QtTest>
#include <QtGui/QDesktopServices>
#include <test-utils/QTestExtensions.h>
#include <DependencyManager.h>
#include <thread>
// x macro
#define LIST_OF_CLASSES \
CLASS(A) \
CLASS(B) \
CLASS(C) \
CLASS(D) \
CLASS(E) \
CLASS(F) \
CLASS(G) \
CLASS(H) \
CLASS(I) \
CLASS(J) \
CLASS(K) \
CLASS(L) \
CLASS(M) \
CLASS(N) \
CLASS(O) \
CLASS(P) \
CLASS(Q) \
CLASS(R) \
CLASS(S) \
CLASS(T) \
CLASS(U) \
CLASS(V) \
CLASS(W) \
CLASS(X) \
CLASS(Y) \
CLASS(Z) \
CLASS(AA) \
CLASS(AB) \
CLASS(AC) \
CLASS(AD) \
CLASS(AE) \
CLASS(AF) \
CLASS(AG) \
CLASS(AH) \
CLASS(AI) \
CLASS(AJ) \
CLASS(AK) \
CLASS(AL) \
CLASS(AM) \
CLASS(AN) \
CLASS(AO) \
CLASS(AP) \
CLASS(AQ) \
CLASS(AR) \
CLASS(AS) \
CLASS(AT) \
CLASS(AU) \
CLASS(AV) \
CLASS(AW) \
CLASS(AX) \
CLASS(AY) \
CLASS(AZ) \
CLASS(BA) \
CLASS(BB) \
CLASS(BC) \
CLASS(BD) \
CLASS(BE) \
CLASS(BF) \
CLASS(BG) \
CLASS(BH) \
CLASS(BI) \
CLASS(BJ) \
CLASS(BK) \
CLASS(BL) \
CLASS(BM) \
CLASS(BN) \
CLASS(BO) \
CLASS(BP) \
CLASS(BQ) \
CLASS(BR) \
CLASS(BS) \
CLASS(BT) \
CLASS(BU) \
CLASS(BV) \
CLASS(BW) \
CLASS(BX) \
CLASS(BY) \
CLASS(BZ) \
CLASS(CA) \
CLASS(CB) \
CLASS(CC) \
CLASS(CD) \
CLASS(CE) \
CLASS(CF) \
CLASS(CG) \
CLASS(CH) \
CLASS(CI) \
CLASS(CJ) \
CLASS(CK) \
CLASS(CL) \
CLASS(CM) \
CLASS(CN) \
CLASS(CO) \
CLASS(CP) \
CLASS(CQ) \
CLASS(CR) \
CLASS(CS) \
CLASS(CT) \
CLASS(CU) \
CLASS(CV) \
CLASS(CW) \
CLASS(CX) \
CLASS(CY) \
CLASS(CZ) \
CLASS(DA) \
CLASS(DB) \
CLASS(DC) \
CLASS(DD) \
CLASS(DE) \
CLASS(DF) \
CLASS(DG) \
CLASS(DH) \
CLASS(DI) \
CLASS(DJ) \
CLASS(DK) \
CLASS(DL) \
CLASS(DM) \
CLASS(DN) \
CLASS(DO) \
CLASS(DP) \
CLASS(DQ) \
CLASS(DR) \
CLASS(DS) \
CLASS(DT) \
CLASS(DU) \
CLASS(DV) \
CLASS(DW) \
CLASS(DX) \
CLASS(DY) \
CLASS(DZ)
QTEST_MAIN(DependencyManagerTests)
#define CLASS(NAME) class NAME : public Dependency {};
LIST_OF_CLASSES
#undef CLASS
void DependencyManagerTests::testDependencyManager() {
QCOMPARE(DependencyManager::isSet<A>(), false);
DependencyManager::set<A>();
QCOMPARE(DependencyManager::isSet<A>(), true);
DependencyManager::destroy<A>();
QCOMPARE(DependencyManager::isSet<A>(), false);
}
static void addDeps() {
#define CLASS(NAME) DependencyManager::set<NAME>();
LIST_OF_CLASSES
#undef CLASS
}
static void removeDeps() {
#define CLASS(NAME) DependencyManager::destroy<NAME>();
LIST_OF_CLASSES
#undef CLASS
}
static void spamIsSet() {
for (int i = 0; i < 1000; i++) {
#define CLASS(NAME) DependencyManager::isSet<NAME>();
LIST_OF_CLASSES
#undef CLASS
}
}
static void spamGet() {
for (int i = 0; i < 10; i++) {
#define CLASS(NAME) DependencyManager::get<NAME>();
LIST_OF_CLASSES
#undef CLASS
}
}
void assertDeps(bool value) {
#define CLASS(NAME) QCOMPARE(DependencyManager::isSet<NAME>(), value);
LIST_OF_CLASSES
#undef CLASS
}
void DependencyManagerTests::testDependencyManagerMultiThreaded() {
std::thread isSetThread1(spamIsSet); // spawn new thread that checks of dpendencies are present by calling isSet()
std::thread getThread1(spamGet); // spawn new thread that checks of dpendencies are present by calling get()
addDeps();
isSetThread1.join();
getThread1.join();
assertDeps(true);
std::thread isSetThread2(spamIsSet); // spawn new thread that checks of dpendencies are present by calling isSet()
std::thread getThread2(spamGet); // spawn new thread that checks of dpendencies are present by calling get()
removeDeps();
isSetThread2.join();
getThread2.join();
assertDeps(false);
}

View file

@ -0,0 +1,21 @@
//
// Created by Anthony Thibault on May 9th 2019
// Copyright 2013-2019 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_DependencyManagerTests_h
#define hifi_DependencyManagerTests_h
#include <QtCore/QObject>
class DependencyManagerTests : public QObject {
Q_OBJECT
private slots:
void testDependencyManager();
void testDependencyManagerMultiThreaded();
};
#endif // hifi_DependencyManagerTests_h