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 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | using namespace Qt3DCore; |
24 | |
25 | namespace Qt3DRender { |
26 | namespace Render { |
27 | |
28 | /*! |
29 | \internal |
30 | Searches the best matching Technique from \a effect specified. |
31 | */ |
32 | Technique *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 | |
75 | RenderPassList 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 | |
124 | ParameterInfoList::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 | |
133 | void addParametersForIds(ParameterInfoList *params, ParameterManager *manager, |
134 | const Qt3DCore::QNodeIdVector ¶meterIds) |
135 | { |
136 | for (const QNodeId ¶mId : 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 | |
145 | void 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 |
165 | void 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 | |
177 | ParameterInfo::ParameterInfo(const int nameId, const HParameter &handle) |
178 | : nameId(nameId) |
179 | , handle(handle) |
180 | {} |
181 | |
182 | bool ParameterInfo::operator<(const ParameterInfo &other) const noexcept |
183 | { |
184 | return nameId < other.nameId; |
185 | } |
186 | |
187 | bool ParameterInfo::operator<(const int otherNameId) const noexcept |
188 | { |
189 | return nameId < otherNameId; |
190 | } |
191 | |
192 | int 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 | |
199 | std::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 | |
213 | QT_END_NAMESPACE |
214 | |