1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "renderviewjobutils_p.h"
5#include <Qt3DRender/private/renderlogging_p.h>
6
7#include <Qt3DRender/qgraphicsapifilter.h>
8#include <Qt3DRender/private/sphere_p.h>
9#include <Qt3DRender/qshaderdata.h>
10
11#include <Qt3DRender/private/nodemanagers_p.h>
12#include <Qt3DRender/private/managers_p.h>
13#include <Qt3DRender/private/effect_p.h>
14#include <Qt3DRender/private/renderpassfilternode_p.h>
15#include <Qt3DRender/private/techniquemanager_p.h>
16#include <Qt3DRender/private/techniquefilternode_p.h>
17#include <Qt3DRender/private/renderstatenode_p.h>
18#include <Qt3DRender/private/renderstates_p.h>
19#include <Qt3DRender/private/renderstateset_p.h>
20
21QT_BEGIN_NAMESPACE
22
23using namespace Qt3DCore;
24
25namespace Qt3DRender {
26namespace Render {
27
28/*!
29 \internal
30 Searches the best matching Technique from \a effect specified.
31*/
32Technique *findTechniqueForEffect(NodeManagers *manager,
33 const TechniqueFilter *techniqueFilter,
34 Effect *effect)
35{
36 if (!effect)
37 return nullptr;
38
39 std::vector<Technique*> matchingTechniques;
40 const bool hasInvalidTechniqueFilter = (techniqueFilter == nullptr || techniqueFilter->filters().isEmpty());
41
42 // Iterate through the techniques in the effect
43 const auto techniqueIds = effect->techniques();
44 for (const QNodeId &techniqueId : techniqueIds) {
45 Technique *technique = manager->techniqueManager()->lookupResource(id: techniqueId);
46
47 // Should be valid, if not there likely a problem with node addition/destruction changes
48 Q_ASSERT(technique);
49
50 // Check if the technique is compatible with the rendering API
51 // If no techniqueFilter is present, we return the technique as it satisfies OpenGL version
52 if (technique->isCompatibleWithRenderer() && (hasInvalidTechniqueFilter || technique->isCompatibleWithFilters(filterKeyIds: techniqueFilter->filters())))
53 matchingTechniques.push_back(x: technique);
54 }
55
56 if (matchingTechniques.size() == 0) // We failed to find a suitable technique to use :(
57 return nullptr;
58
59 if (matchingTechniques.size() == 1)
60 return matchingTechniques.front();
61
62 // Several compatible techniques, return technique with highest major and minor version
63 Technique* highest = matchingTechniques.front();
64 GraphicsApiFilterData filter = *highest->graphicsApiFilter();
65 for (auto it = matchingTechniques.cbegin() + 1; it < matchingTechniques.cend(); ++it) {
66 if (filter < *(*it)->graphicsApiFilter()) {
67 filter = *(*it)->graphicsApiFilter();
68 highest = *it;
69 }
70 }
71 return highest;
72}
73
74
75RenderPassList findRenderPassesForTechnique(NodeManagers *manager,
76 const RenderPassFilter *passFilter,
77 Technique *technique)
78{
79 Q_ASSERT(manager);
80 Q_ASSERT(technique);
81
82 RenderPassList passes;
83 const auto passIds = technique->renderPasses();
84 for (const QNodeId &passId : passIds) {
85 RenderPass *renderPass = manager->renderPassManager()->lookupResource(id: passId);
86
87 if (renderPass && renderPass->isEnabled()) {
88 bool foundMatch = (!passFilter || passFilter->filters().size() == 0);
89
90 // A pass filter is present so we need to check for matching criteria
91 if (!foundMatch && renderPass->filterKeys().size() >= passFilter->filters().size()) {
92
93 // Iterate through the filter criteria and look for render passes with criteria that satisfy them
94 const auto filterKeyIds = passFilter->filters();
95 for (const QNodeId &filterKeyId : filterKeyIds) {
96 foundMatch = false;
97 FilterKey *filterFilterKey = manager->filterKeyManager()->lookupResource(id: filterKeyId);
98
99 const auto passFilterKeyIds = renderPass->filterKeys();
100 for (const QNodeId &passFilterKeyId : passFilterKeyIds) {
101 FilterKey *passFilterKey = manager->filterKeyManager()->lookupResource(id: passFilterKeyId);
102 if ((foundMatch = (*passFilterKey == *filterFilterKey)))
103 break;
104 }
105
106 if (!foundMatch) {
107 // No match for criterion in any of the render pass' criteria
108 break;
109 }
110 }
111 }
112
113 if (foundMatch) {
114 // Found a renderpass that satisfies our needs. Add it in order
115 passes << renderPass;
116 }
117 }
118 }
119
120 return passes;
121}
122
123
124ParameterInfoList::const_iterator findParamInfo(ParameterInfoList *params, const int nameId)
125{
126 const ParameterInfoList::const_iterator end = params->cend();
127 ParameterInfoList::const_iterator it = std::lower_bound(first: params->cbegin(), last: end, val: nameId);
128 if (it != end && it->nameId != nameId)
129 return end;
130 return it;
131}
132
133void addParametersForIds(ParameterInfoList *params, ParameterManager *manager,
134 const Qt3DCore::QNodeIdVector &parameterIds)
135{
136 for (const QNodeId &paramId : parameterIds) {
137 const HParameter parameterHandle = manager->lookupHandle(id: paramId);
138 const Parameter *param = manager->data(handle: parameterHandle);
139 ParameterInfoList::iterator it = std::lower_bound(first: params->begin(), last: params->end(), val: param->nameId());
140 if (it == params->end() || it->nameId != param->nameId())
141 params->insert(before: it, t: ParameterInfo(param->nameId(), parameterHandle));
142 }
143}
144
145void parametersFromMaterialEffectTechnique(ParameterInfoList *infoList,
146 ParameterManager *manager,
147 Material *material,
148 Effect *effect,
149 Technique *technique)
150{
151 // The parameters are taken in the following priority order:
152 //
153 // 1) Material
154 // 2) Effect
155 // 3) Technique
156 //
157 // That way a user can override defaults in Effect's and Techniques on a
158 // object manner and a Technique can override global defaults from the Effect.
159 parametersFromParametersProvider(infoList, manager, provider: material);
160 parametersFromParametersProvider(infoList, manager, provider: effect);
161 parametersFromParametersProvider(infoList, manager, provider: technique);
162}
163
164// Only add states with types we don't already have
165void addStatesToRenderStateSet(RenderStateSet *stateSet,
166 const QList<Qt3DCore::QNodeId> stateIds,
167 RenderStateManager *manager)
168{
169 for (const Qt3DCore::QNodeId &stateId : stateIds) {
170 RenderStateNode *node = manager->lookupResource(id: stateId);
171 if (node && node->isEnabled() && stateSet->canAddStateOfType(type: node->type())) {
172 stateSet->addState(state: node->impl());
173 }
174 }
175}
176
177ParameterInfo::ParameterInfo(const int nameId, const HParameter &handle)
178 : nameId(nameId)
179 , handle(handle)
180{}
181
182bool ParameterInfo::operator<(const ParameterInfo &other) const noexcept
183{
184 return nameId < other.nameId;
185}
186
187bool ParameterInfo::operator<(const int otherNameId) const noexcept
188{
189 return nameId < otherNameId;
190}
191
192int findIdealNumberOfWorkers(int elementCount, int packetSize, int maxJobCount)
193{
194 if (elementCount == 0 || packetSize == 0)
195 return 0;
196 return std::min(a: std::max(a: elementCount / packetSize, b: 1), b: maxJobCount);
197}
198
199std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities, const std::vector<Entity *> &subset)
200{
201 std::vector<Entity *> intersection;
202 intersection.reserve(n: qMin(a: entities.size(), b: subset.size()));
203 std::set_intersection(first1: entities.begin(), last1: entities.end(),
204 first2: subset.begin(), last2: subset.end(),
205 result: std::back_inserter(x&: intersection));
206
207 return intersection;
208}
209
210} // namespace Render
211} // namespace Qt3DRender
212
213QT_END_NAMESPACE
214

source code of qt3d/src/render/jobs/renderviewjobutils.cpp