Revision control
Copy as Markdown
// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "renderviewjobutils_p.h"
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/qgraphicsapifilter.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/qshaderdata.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/effect_p.h>
#include <Qt3DRender/private/renderpassfilternode_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/techniquefilternode_p.h>
#include <Qt3DRender/private/renderstatenode_p.h>
#include <Qt3DRender/private/renderstates_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
using namespace Qt3DCore;
/*!
\internal
Searches the best matching Technique from \a effect specified.
*/
Technique *findTechniqueForEffect(NodeManagers *manager,
const TechniqueFilter *techniqueFilter,
Effect *effect)
{
if (!effect)
return nullptr;
std::vector<Technique*> matchingTechniques;
const bool hasInvalidTechniqueFilter = (techniqueFilter == nullptr || techniqueFilter->filters().isEmpty());
// Iterate through the techniques in the effect
const auto techniqueIds = effect->techniques();
for (const QNodeId &techniqueId : techniqueIds) {
Technique *technique = manager->techniqueManager()->lookupResource(techniqueId);
// Should be valid, if not there likely a problem with node addition/destruction changes
Q_ASSERT(technique);
// Check if the technique is compatible with the rendering API
// If no techniqueFilter is present, we return the technique as it satisfies OpenGL version
if (technique->isCompatibleWithRenderer() && (hasInvalidTechniqueFilter || technique->isCompatibleWithFilters(techniqueFilter->filters())))
matchingTechniques.push_back(technique);
}
if (matchingTechniques.size() == 0) // We failed to find a suitable technique to use :(
return nullptr;
if (matchingTechniques.size() == 1)
return matchingTechniques.front();
// Several compatible techniques, return technique with highest major and minor version
Technique* highest = matchingTechniques.front();
GraphicsApiFilterData filter = *highest->graphicsApiFilter();
for (auto it = matchingTechniques.cbegin() + 1; it < matchingTechniques.cend(); ++it) {
if (filter < *(*it)->graphicsApiFilter()) {
filter = *(*it)->graphicsApiFilter();
highest = *it;
}
}
return highest;
}
RenderPassList findRenderPassesForTechnique(NodeManagers *manager,
const RenderPassFilter *passFilter,
Technique *technique)
{
Q_ASSERT(manager);
Q_ASSERT(technique);
RenderPassList passes;
const auto passIds = technique->renderPasses();
for (const QNodeId &passId : passIds) {
RenderPass *renderPass = manager->renderPassManager()->lookupResource(passId);
if (renderPass && renderPass->isEnabled()) {
bool foundMatch = (!passFilter || passFilter->filters().size() == 0);
// A pass filter is present so we need to check for matching criteria
if (!foundMatch && renderPass->filterKeys().size() >= passFilter->filters().size()) {
// Iterate through the filter criteria and look for render passes with criteria that satisfy them
const auto filterKeyIds = passFilter->filters();
for (const QNodeId &filterKeyId : filterKeyIds) {
foundMatch = false;
FilterKey *filterFilterKey = manager->filterKeyManager()->lookupResource(filterKeyId);
const auto passFilterKeyIds = renderPass->filterKeys();
for (const QNodeId &passFilterKeyId : passFilterKeyIds) {
FilterKey *passFilterKey = manager->filterKeyManager()->lookupResource(passFilterKeyId);
if ((foundMatch = (*passFilterKey == *filterFilterKey)))
break;
}
if (!foundMatch) {
// No match for criterion in any of the render pass' criteria
break;
}
}
}
if (foundMatch) {
// Found a renderpass that satisfies our needs. Add it in order
passes << renderPass;
}
}
}
return passes;
}
ParameterInfoList::const_iterator findParamInfo(ParameterInfoList *params, const int nameId)
{
const ParameterInfoList::const_iterator end = params->cend();
ParameterInfoList::const_iterator it = std::lower_bound(params->cbegin(), end, nameId);
if (it != end && it->nameId != nameId)
return end;
return it;
}
void addParametersForIds(ParameterInfoList *params, ParameterManager *manager,
const Qt3DCore::QNodeIdVector ¶meterIds)
{
for (const QNodeId ¶mId : parameterIds) {
const HParameter parameterHandle = manager->lookupHandle(paramId);
const Parameter *param = manager->data(parameterHandle);
ParameterInfoList::iterator it = std::lower_bound(params->begin(), params->end(), param->nameId());
if (it == params->end() || it->nameId != param->nameId())
params->insert(it, ParameterInfo(param->nameId(), parameterHandle));
}
}
void parametersFromMaterialEffectTechnique(ParameterInfoList *infoList,
ParameterManager *manager,
Material *material,
Effect *effect,
Technique *technique)
{
// The parameters are taken in the following priority order:
//
// 1) Material
// 2) Effect
// 3) Technique
//
// That way a user can override defaults in Effect's and Techniques on a
// object manner and a Technique can override global defaults from the Effect.
parametersFromParametersProvider(infoList, manager, material);
parametersFromParametersProvider(infoList, manager, effect);
parametersFromParametersProvider(infoList, manager, technique);
}
// Only add states with types we don't already have
void addStatesToRenderStateSet(RenderStateSet *stateSet,
const QList<Qt3DCore::QNodeId> stateIds,
RenderStateManager *manager)
{
for (const Qt3DCore::QNodeId &stateId : stateIds) {
RenderStateNode *node = manager->lookupResource(stateId);
if (node && node->isEnabled() && stateSet->canAddStateOfType(node->type())) {
stateSet->addState(node->impl());
}
}
}
ParameterInfo::ParameterInfo(const int nameId, const HParameter &handle)
: nameId(nameId)
, handle(handle)
{}
bool ParameterInfo::operator<(const ParameterInfo &other) const noexcept
{
return nameId < other.nameId;
}
bool ParameterInfo::operator<(const int otherNameId) const noexcept
{
return nameId < otherNameId;
}
int findIdealNumberOfWorkers(int elementCount, int packetSize, int maxJobCount)
{
if (elementCount == 0 || packetSize == 0)
return 0;
return std::min(std::max(elementCount / packetSize, 1), maxJobCount);
}
std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities, const std::vector<Entity *> &subset)
{
std::vector<Entity *> intersection;
intersection.reserve(qMin(entities.size(), subset.size()));
std::set_intersection(entities.begin(), entities.end(),
subset.begin(), subset.end(),
std::back_inserter(intersection));
return intersection;
}
} // namespace Render
} // namespace Qt3DRender
QT_END_NAMESPACE