1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "sampler.h"
16
17 #include <scene/ext/intf_ecs_context.h>
18 #include <scene/ext/intf_render_resource.h>
19
20 #include <3d/ecs/components/render_handle_component.h>
21 #include <render/device/intf_gpu_resource_manager.h>
22
23 SCENE_BEGIN_NAMESPACE()
24
25 static constexpr BASE_NS::string_view MAG_FILTER_PROPERTY = "MagFilter";
26 static constexpr BASE_NS::string_view MIN_FILTER_PROPERTY = "MinFilter";
27 static constexpr BASE_NS::string_view MIP_MAP_MODE_PROPERTY = "MipMapMode";
28 static constexpr BASE_NS::string_view ADDRESS_MODE_U_PROPERTY = "AddressModeU";
29 static constexpr BASE_NS::string_view ADDRESS_MODE_V_PROPERTY = "AddressModeV";
30 static constexpr BASE_NS::string_view ADDRESS_MODE_W_PROPERTY = "AddressModeW";
31 static constexpr BASE_NS::string_view DEFAULT_SAMPLER_NAME = "CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT";
32
33 template<typename T, typename U>
SetSamplerValue(META_NS::IProperty * p,const U & f,bool setToDefault=false)34 bool SetSamplerValue(META_NS::IProperty* p, const U& f, bool setToDefault = false)
35 {
36 if (p) {
37 auto value = META_NS::Any<T>(static_cast<T>(f));
38 if (!setToDefault) {
39 p->SetValue(value);
40 } else if (auto sp = interface_cast<META_NS::IStackProperty>(p)) {
41 sp->SetDefaultValue(value);
42 }
43 return true;
44 }
45 return false;
46 }
47
48 template<typename T, typename U>
InitializeSamplerValue(META_NS::IProperty * p,const U & value,const U & defaultValue,bool setValue)49 bool InitializeSamplerValue(META_NS::IProperty* p, const U& value, const U& defaultValue, bool setValue)
50 {
51 auto success = SetSamplerValue<T, U>(p, defaultValue, true); // Set default
52 if (setValue) {
53 success &= SetSamplerValue<T, U>(p, value, false); // Set value if required
54 }
55 return success;
56 }
57
58 template<typename T, typename U>
GetSamplerValue(const META_NS::IProperty * p,U & value)59 bool GetSamplerValue(const META_NS::IProperty* p, U& value)
60 {
61 if (p && p->IsValueSet()) {
62 // Value has been set
63 T v {};
64 p->GetValue().GetValue(v);
65 if (value != static_cast<U>(v)) {
66 value = static_cast<U>(v);
67 return true;
68 }
69 }
70 return false;
71 }
72
ResetSamplerProperty(META_NS::IProperty * p)73 bool ResetSamplerProperty(META_NS::IProperty* p)
74 {
75 if (p && p->IsValueSet()) {
76 p->ResetValue();
77 return true;
78 }
79 return false;
80 }
81
GetExistingProperty(BASE_NS::string_view name)82 META_NS::IProperty* Sampler::GetExistingProperty(BASE_NS::string_view name)
83 {
84 return GetProperty(name, META_NS::MetadataQuery::EXISTING).get();
85 }
86
GetExistingProperty(BASE_NS::string_view name) const87 const META_NS::IProperty* Sampler::GetExistingProperty(BASE_NS::string_view name) const
88 {
89 return GetProperty(name, META_NS::MetadataQuery::EXISTING).get();
90 }
91
NotifyChanged()92 void Sampler::NotifyChanged()
93 {
94 // Only notify if we don't have a set operation in progress
95 if (CanNotifyChanged()) {
96 // Since some property changed our sampler handle is not valid anymore, we need to create a new one next time
97 // GetHandleFromSampler is called
98 sampler_ = {};
99 if (auto ev = EventOnResourceChanged(META_NS::MetadataQuery::EXISTING)) {
100 META_NS::Invoke<META_NS::IOnChanged>(ev);
101 }
102 }
103 }
104
CanNotifyChanged()105 bool Sampler::CanNotifyChanged()
106 {
107 CORE_NS::UniqueLock lock(transaction_);
108 if (!setting_) {
109 return true; // No transaction ongoing so can notify
110 }
111 // Set flag that we had a changed event during transaction
112 changedDuringTransaction_ = true;
113 return false;
114 }
115
StartTransaction()116 void Sampler::StartTransaction()
117 {
118 CORE_NS::UniqueLock lock(transaction_);
119 setting_++;
120 }
121
EndTransaction(bool changed)122 void Sampler::EndTransaction(bool changed)
123 {
124 bool shouldNotify = false;
125 {
126 CORE_NS::UniqueLock lock(transaction_);
127 setting_--;
128 if (!setting_) {
129 // Transaction ended
130 shouldNotify = changed && changedDuringTransaction_;
131 changedDuringTransaction_ = false;
132 }
133 }
134 if (shouldNotify) {
135 NotifyChanged();
136 }
137 }
138
ResetObject()139 void Sampler::ResetObject()
140 {
141 auto task = [&]() -> bool {
142 StartTransaction();
143 bool changed = ResetSamplerProperty(GetExistingProperty(MAG_FILTER_PROPERTY));
144 changed |= ResetSamplerProperty(GetExistingProperty(MIN_FILTER_PROPERTY));
145 changed |= ResetSamplerProperty(GetExistingProperty(MIP_MAP_MODE_PROPERTY));
146 changed |= ResetSamplerProperty(GetExistingProperty(ADDRESS_MODE_U_PROPERTY));
147 changed |= ResetSamplerProperty(GetExistingProperty(ADDRESS_MODE_V_PROPERTY));
148 changed |= ResetSamplerProperty(GetExistingProperty(ADDRESS_MODE_W_PROPERTY));
149 EndTransaction(false); // Delay notification about change
150 return changed;
151 };
152 auto scene = scene_.lock();
153 auto changed = scene ? scene->AddTask(task).GetResult() : task();
154 if (changed) {
155 NotifyChanged();
156 }
157 }
158
SetScene(const IInternalScene::Ptr & scene)159 void Sampler::SetScene(const IInternalScene::Ptr& scene)
160 {
161 scene_ = scene;
162 }
163
OnPropertyChanged(const META_NS::IProperty &)164 void Sampler::OnPropertyChanged(const META_NS::IProperty&)
165 {
166 NotifyChanged();
167 }
168
OnMetadataConstructed(const META_NS::StaticMetadata & m,CORE_NS::IInterface & i)169 void Sampler::OnMetadataConstructed(const META_NS::StaticMetadata& m, CORE_NS::IInterface& i)
170 {
171 if (!sampler_.handle || !scene_.lock()) {
172 // Don't even try to set the values if we are in non-initialized state
173 return;
174 }
175 if (auto p = interface_cast<META_NS::IProperty>(&i)) {
176 const auto& desc = sampler_.descriptor;
177 const auto& defaultDesc = sampler_.isDefault ? sampler_.descriptor : GetDefaultSampler().descriptor;
178 const auto usingDefault = sampler_.isDefault;
179 BASE_NS::string_view name(m.name);
180 if (name == MAG_FILTER_PROPERTY) {
181 InitializeSamplerValue<SamplerFilter>(p, desc.magFilter, defaultDesc.magFilter, !usingDefault);
182 } else if (name == MIN_FILTER_PROPERTY) {
183 InitializeSamplerValue<SamplerFilter>(p, desc.minFilter, defaultDesc.minFilter, !usingDefault);
184 } else if (name == MIP_MAP_MODE_PROPERTY) {
185 InitializeSamplerValue<SamplerFilter>(p, desc.mipMapMode, defaultDesc.mipMapMode, !usingDefault);
186 } else if (name == ADDRESS_MODE_U_PROPERTY) {
187 InitializeSamplerValue<SamplerAddressMode>(p, desc.addressModeU, defaultDesc.addressModeU, !usingDefault);
188 } else if (name == ADDRESS_MODE_V_PROPERTY) {
189 InitializeSamplerValue<SamplerAddressMode>(p, desc.addressModeV, defaultDesc.addressModeV, !usingDefault);
190 } else if (name == ADDRESS_MODE_W_PROPERTY) {
191 InitializeSamplerValue<SamplerAddressMode>(p, desc.addressModeW, defaultDesc.addressModeW, !usingDefault);
192 }
193 }
194 }
195
GetDefaultSampler() const196 Sampler::SamplerInfo Sampler::GetDefaultSampler() const
197 {
198 SamplerInfo info;
199 if (auto scene = scene_.lock()) {
200 auto& mgr = scene->GetRenderContext().GetDevice().GetGpuResourceManager();
201 info.handle = mgr.GetSamplerHandle(DEFAULT_SAMPLER_NAME);
202 info.descriptor = mgr.GetSamplerDescriptor(info.handle);
203 info.isDefault = true;
204 }
205 return info;
206 }
207
GetSamplerHandle(const SamplerInfo & info) const208 RENDER_NS::RenderHandleReference Sampler::GetSamplerHandle(const SamplerInfo& info) const noexcept
209 {
210 return info.isDefault ? RENDER_NS::RenderHandleReference {} : info.handle;
211 }
212
UpdateSamplerFromHandle(RENDER_NS::IRenderContext & context,const RENDER_NS::RenderHandleReference & handle)213 bool Sampler::UpdateSamplerFromHandle(
214 RENDER_NS::IRenderContext& context, const RENDER_NS::RenderHandleReference& handle)
215 {
216 if (sampler_.handle && handle.GetHandle() == sampler_.handle.GetHandle()) {
217 // Same
218 return false;
219 }
220 if (handle) {
221 // Valid handle
222 if (handle.GetHandleType() != RENDER_NS::RenderHandleType::GPU_SAMPLER) {
223 CORE_LOG_E("Sampler requires GPU_SAMPLER handle");
224 return false;
225 }
226 sampler_.handle = handle;
227 sampler_.descriptor = context.GetDevice().GetGpuResourceManager().GetSamplerDescriptor(handle);
228 sampler_.isDefault = false;
229 } else {
230 // Null handle, initialize from engine default sampler
231 sampler_ = GetDefaultSampler();
232 }
233 auto& desc = sampler_.descriptor;
234
235 // Update properties we have initialized
236 StartTransaction();
237 bool changed = SetSamplerValue<SamplerFilter>(GetExistingProperty(MAG_FILTER_PROPERTY), desc.magFilter);
238 changed |= SetSamplerValue<SamplerFilter>(GetExistingProperty(MIN_FILTER_PROPERTY), desc.minFilter);
239 changed |= SetSamplerValue<SamplerFilter>(GetExistingProperty(MIP_MAP_MODE_PROPERTY), desc.mipMapMode);
240 changed |= SetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_U_PROPERTY), desc.addressModeU);
241 changed |= SetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_V_PROPERTY), desc.addressModeV);
242 changed |= SetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_W_PROPERTY), desc.addressModeW);
243 EndTransaction(changed);
244 return false;
245 }
246
GetHandleFromSampler(RENDER_NS::IRenderContext & context) const247 RENDER_NS::RenderHandleReference Sampler::GetHandleFromSampler(RENDER_NS::IRenderContext& context) const
248 {
249 if (sampler_.handle) {
250 // We already have a handle
251 return GetSamplerHandle(sampler_);
252 }
253 // No handle, create a new sampler based on our own property values, using the default sampler as base, replacing
254 // values from it from our internal property values
255 auto info = GetDefaultSampler();
256 auto& desc = info.descriptor;
257 auto isset = GetSamplerValue<SamplerFilter>(GetExistingProperty(MAG_FILTER_PROPERTY), desc.magFilter);
258 isset |= GetSamplerValue<SamplerFilter>(GetExistingProperty(MIN_FILTER_PROPERTY), desc.minFilter);
259 isset |= GetSamplerValue<SamplerFilter>(GetExistingProperty(MIP_MAP_MODE_PROPERTY), desc.mipMapMode);
260 isset |= GetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_U_PROPERTY), desc.addressModeU);
261 isset |= GetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_V_PROPERTY), desc.addressModeV);
262 isset |= GetSamplerValue<SamplerAddressMode>(GetExistingProperty(ADDRESS_MODE_W_PROPERTY), desc.addressModeW);
263
264 // If nothing changed from the default sampler's descriptor just use the default, otherwise create a new one
265 sampler_.isDefault = !isset;
266 sampler_.handle = sampler_.isDefault ? info.handle : context.GetDevice().GetGpuResourceManager().Create(desc);
267 sampler_.descriptor = BASE_NS::move(desc);
268 return GetSamplerHandle(sampler_);
269 }
270
271 SCENE_END_NAMESPACE()
272