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  
16  #include "render_data_store_post_process.h"
17  
18  #include <cinttypes>
19  #include <cstdint>
20  
21  #include <base/containers/fixed_string.h>
22  #include <base/math/matrix.h>
23  #include <render/datastore/render_data_store_render_pods.h>
24  #include <render/device/intf_shader_manager.h>
25  #include <render/intf_render_context.h>
26  
27  #include "datastore/render_data_store_manager.h"
28  #include "datastore/render_data_store_pod.h"
29  #include "loader/json_util.h"
30  #include "util/log.h"
31  
32  using namespace BASE_NS;
33  using namespace CORE_NS;
34  
35  RENDER_BEGIN_NAMESPACE()
36  namespace {
37  constexpr string_view RENDER_DATA_STORE_POST_PROCESS_TYPE_NAME { RenderDataStorePostProcess::TYPE_NAME };
38  constexpr string_view RENDER_DATA_STORE_POD_NAME { RenderDataStorePod::TYPE_NAME };
39  
40  constexpr string_view CUSTOM_PROPERTIES = "customProperties";
41  constexpr string_view GLOBAL_FACTOR = "globalFactor";
42  constexpr string_view CUSTOM_PROPERTY_DATA = "data";
43  
44  constexpr uint32_t SIZE_OF_FLOAT { sizeof(float) };
45  constexpr uint32_t SIZE_OF_VEC2 { sizeof(Math::Vec2) };
46  constexpr uint32_t SIZE_OF_VEC3 { sizeof(Math::Vec3) };
47  constexpr uint32_t SIZE_OF_VEC4 { sizeof(Math::Vec4) };
48  constexpr uint32_t SIZE_OF_MAT3X3 { sizeof(Math::Mat3X3) };
49  constexpr uint32_t SIZE_OF_MAT4X4 { sizeof(Math::Mat4X4) };
50  
51  constexpr uint32_t ALIGNMENT_OF_FLOAT { sizeof(float) };
52  constexpr uint32_t ALIGNMENT_OF_VEC2 { sizeof(float) * 2U };
53  constexpr uint32_t ALIGNMENT_OF_VEC3 { sizeof(float) * 4U };
54  constexpr uint32_t ALIGNMENT_OF_VEC4 { sizeof(float) * 4U };
55  constexpr uint32_t ALIGNMENT_OF_MAT3X3 { sizeof(float) * 4U * 3U };
56  constexpr uint32_t ALIGNMENT_OF_MAT4X4 { sizeof(float) * 4U * 4U };
57  
58  constexpr uint32_t MAX_LOCAL_DATA_BYTE_SIZE { PostProcessConstants::USER_LOCAL_FACTOR_BYTE_SIZE };
59  constexpr uint32_t MAX_GLOBAL_FACTOR_BYTE_SIZE { sizeof(Math::Vec4) };
60  
61  constexpr string_view TAA_SHADER_NAME { "rendershaders://shader/fullscreen_taa.shader" };
62  constexpr string_view FXAA_SHADER_NAME { "rendershaders://shader/fullscreen_fxaa.shader" };
63  constexpr string_view DOF_SHADER_NAME { "rendershaders://shader/depth_of_field.shader" };
64  constexpr string_view MB_SHADER_NAME { "rendershaders://shader/fullscreen_motion_blur.shader" };
65  
GetAlignment(uint32_t value,uint32_t align)66  inline constexpr uint32_t GetAlignment(uint32_t value, uint32_t align)
67  {
68      if (align == 0) {
69          return value;
70      } else {
71          return ((value + align - 1U) / align) * align;
72      }
73  }
74  
AppendValues(const uint32_t maxByteSize,const string_view type,const json::value * value,uint32_t & offset,uint8_t * data)75  void AppendValues(
76      const uint32_t maxByteSize, const string_view type, const json::value* value, uint32_t& offset, uint8_t* data)
77  {
78      if (type == "vec4") {
79          if ((offset + ALIGNMENT_OF_VEC4) <= maxByteSize) {
80              Math::Vec4* val = reinterpret_cast<Math::Vec4*>(data + offset);
81              FromJson(*value, *val);
82              offset = GetAlignment(offset + SIZE_OF_VEC4, ALIGNMENT_OF_VEC4);
83          }
84      } else if (type == "uvec4") {
85          if ((offset + ALIGNMENT_OF_VEC4) <= maxByteSize) {
86              Math::UVec4* val = reinterpret_cast<Math::UVec4*>(data + offset);
87              FromJson(*value, *val);
88              offset = GetAlignment(offset + SIZE_OF_VEC4, ALIGNMENT_OF_VEC4);
89          }
90      } else if (type == "ivec4") {
91          if ((offset + ALIGNMENT_OF_VEC4) <= maxByteSize) {
92              Math::UVec4* val = reinterpret_cast<Math::UVec4*>(data + offset);
93              FromJson(*value, *val);
94              offset = GetAlignment(offset + SIZE_OF_VEC4, ALIGNMENT_OF_VEC4);
95          }
96      } else if (type == "vec3") {
97          if ((offset + ALIGNMENT_OF_VEC3) <= maxByteSize) {
98              Math::Vec3* val = reinterpret_cast<Math::Vec3*>(data + offset);
99              FromJson(*value, *val);
100              offset = GetAlignment(offset + SIZE_OF_VEC3, ALIGNMENT_OF_VEC3);
101          }
102      } else if (type == "uvec3") {
103          if ((offset + ALIGNMENT_OF_VEC3) <= maxByteSize) {
104              Math::UVec3* val = reinterpret_cast<Math::UVec3*>(data + offset);
105              FromJson(*value, *val);
106              offset = GetAlignment(offset + SIZE_OF_VEC3, ALIGNMENT_OF_VEC3);
107          }
108      } else if (type == "ivec3") {
109          if ((offset + ALIGNMENT_OF_VEC3) <= maxByteSize) {
110              Math::UVec3* val = reinterpret_cast<Math::UVec3*>(data + offset);
111              FromJson(*value, *val);
112              offset = GetAlignment(offset + SIZE_OF_VEC3, ALIGNMENT_OF_VEC3);
113          }
114      } else if (type == "vec2") {
115          if ((offset + ALIGNMENT_OF_VEC2) <= maxByteSize) {
116              Math::Vec2* val = reinterpret_cast<Math::Vec2*>(data + offset);
117              FromJson(*value, *val);
118              offset = GetAlignment(offset + SIZE_OF_VEC2, ALIGNMENT_OF_VEC2);
119          }
120      } else if (type == "uvec2") {
121          if ((offset + ALIGNMENT_OF_VEC2) <= maxByteSize) {
122              Math::UVec2* val = reinterpret_cast<Math::UVec2*>(data + offset);
123              FromJson(*value, *val);
124              offset = GetAlignment(offset + SIZE_OF_VEC2, ALIGNMENT_OF_VEC2);
125          }
126      } else if (type == "ivec2") {
127          if ((offset + ALIGNMENT_OF_VEC2) <= maxByteSize) {
128              Math::UVec2* val = reinterpret_cast<Math::UVec2*>(data + offset);
129              FromJson(*value, *val);
130              offset = GetAlignment(offset + SIZE_OF_VEC2, ALIGNMENT_OF_VEC2);
131          }
132      } else if (type == "float") {
133          if ((offset + ALIGNMENT_OF_FLOAT) <= maxByteSize) {
134              float* val = reinterpret_cast<float*>(data + offset);
135              FromJson(*value, *val);
136              offset = GetAlignment(offset + SIZE_OF_FLOAT, ALIGNMENT_OF_FLOAT);
137          }
138      } else if (type == "uint") {
139          if ((offset + ALIGNMENT_OF_FLOAT) <= maxByteSize) {
140              uint32_t* val = reinterpret_cast<uint32_t*>(data + offset);
141              FromJson(*value, *val);
142              offset = GetAlignment(offset + SIZE_OF_FLOAT, ALIGNMENT_OF_FLOAT);
143          }
144      } else if (type == "int") {
145          if ((offset + ALIGNMENT_OF_FLOAT) <= maxByteSize) {
146              int32_t* val = reinterpret_cast<int32_t*>(data + offset);
147              FromJson(*value, *val);
148              offset = GetAlignment(offset + SIZE_OF_FLOAT, ALIGNMENT_OF_FLOAT);
149          }
150      } else if (type == "mat3x3") {
151          if ((offset + ALIGNMENT_OF_MAT3X3) <= maxByteSize) {
152              Math::Mat3X3* val = reinterpret_cast<Math::Mat3X3*>(data + offset);
153              FromJson(*value, *val);
154              offset = GetAlignment(offset + SIZE_OF_MAT3X3, ALIGNMENT_OF_MAT3X3);
155          }
156      } else if (type == "mat4x4") {
157          if ((offset + ALIGNMENT_OF_MAT4X4) <= maxByteSize) {
158              Math::Mat4X4* val = reinterpret_cast<Math::Mat4X4*>(data + offset);
159              FromJson(*value, *val);
160              offset = GetAlignment(offset + SIZE_OF_MAT4X4, ALIGNMENT_OF_MAT4X4);
161          }
162      } else {
163          PLUGIN_LOG_W("RENDER_VALIDATION: Invalid property type only int, uint, float, and XvecX variants, and mat3x3 "
164                       "and mat4x4 supported");
165      }
166      // NOTE: does not handle invalid types
167  }
168  } // namespace
169  
RenderDataStorePostProcess(const IRenderContext & renderContext,const string_view name)170  RenderDataStorePostProcess::RenderDataStorePostProcess(const IRenderContext& renderContext, const string_view name)
171      : renderContext_(renderContext), name_(name)
172  {}
173  
~RenderDataStorePostProcess()174  RenderDataStorePostProcess::~RenderDataStorePostProcess() {}
175  
Create(const string_view name)176  void RenderDataStorePostProcess::Create(const string_view name)
177  {
178      const auto lock = std::lock_guard(mutex_);
179  
180      if (!allPostProcesses_.contains(name)) {
181          CreateFromPod(name);
182      } else {
183          PLUGIN_LOG_I("Render data store post process with name (%s) already created.", name.data());
184      }
185  }
186  
Create(const string_view name,const string_view ppName,const RenderHandleReference & shader)187  void RenderDataStorePostProcess::Create(
188      const string_view name, const string_view ppName, const RenderHandleReference& shader)
189  {
190      const auto lock = std::lock_guard(mutex_);
191  
192      if (!allPostProcesses_.contains(name)) {
193          CreateFromPod(name);
194      }
195  
196      if (auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.end()) {
197          auto& postProcesses = iter->second.postProcesses;
198          const uint32_t ppCount = static_cast<uint32_t>(postProcesses.size());
199          uint32_t ppIndex = ~0u;
200          for (uint32_t idx = 0; idx < ppCount; ++idx) {
201              if (postProcesses[idx].name == ppName) {
202                  ppIndex = idx;
203                  break;
204              }
205          }
206  
207          if (ppIndex < ppCount) {
208              // does not set variables
209              GetShaderProperties(shader, postProcesses[ppIndex].variables);
210              SetGlobalFactorsImpl(postProcesses[ppIndex].variables, ppIndex, iter->second);
211          } else {
212              PostProcess pp;
213              pp.id = static_cast<uint32_t>(postProcesses.size());
214              pp.name = ppName;
215              pp.shader = shader;
216              pp.variables = {}; // default variables, overwritten with shader default properties
217              GetShaderProperties(shader, pp.variables);
218              postProcesses.push_back(move(pp));
219              SetGlobalFactorsImpl(postProcesses[pp.id].variables, pp.id, iter->second);
220          }
221      } else {
222          PLUGIN_LOG_E("Post process creation error (name: %s, ppName: %s)", name.data(), ppName.data());
223      }
224  }
225  
Destroy(const string_view name)226  void RenderDataStorePostProcess::Destroy(const string_view name)
227  {
228      const auto lock = std::lock_guard(mutex_);
229  
230      if ((!name.empty()) && allPostProcesses_.contains(name)) {
231          allPostProcesses_.erase(name);
232          if (IRenderDataStorePod* dataStorePod = static_cast<IRenderDataStorePod*>(
233                  renderContext_.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_POD_NAME));
234              dataStorePod) {
235              dataStorePod->DestroyPod(RENDER_DATA_STORE_POST_PROCESS_TYPE_NAME, name);
236          }
237      } else {
238          PLUGIN_LOG_I("Post process not found: %s", name.data());
239      }
240  }
241  
Destroy(const string_view name,const string_view ppName)242  void RenderDataStorePostProcess::Destroy(const string_view name, const string_view ppName)
243  {
244      const auto lock = std::lock_guard(mutex_);
245  
246      if (auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.end()) {
247          for (auto ppIter = iter->second.postProcesses.begin(); ppIter != iter->second.postProcesses.end(); ++ppIter) {
248              if (ppIter->name == ppName) {
249                  iter->second.postProcesses.erase(ppIter);
250                  break;
251              }
252          }
253      }
254  }
255  
Contains(const string_view name) const256  bool RenderDataStorePostProcess::Contains(const string_view name) const
257  {
258      const auto lock = std::lock_guard(mutex_);
259  
260      return allPostProcesses_.contains(name);
261  }
262  
Contains(const string_view name,const string_view ppName) const263  bool RenderDataStorePostProcess::Contains(const string_view name, const string_view ppName) const
264  {
265      const auto lock = std::lock_guard(mutex_);
266  
267      if (const auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.cend()) {
268          for (const auto& ref : iter->second.postProcesses) {
269              if (ref.name == ppName) {
270                  return true;
271              }
272          }
273      }
274      return false;
275  }
276  
Set(const string_view name,const string_view ppName,const PostProcess::Variables & vars)277  void RenderDataStorePostProcess::Set(
278      const string_view name, const string_view ppName, const PostProcess::Variables& vars)
279  {
280      const auto lock = std::lock_guard(mutex_);
281  
282      if (auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.end()) {
283          auto& postProcesses = iter->second.postProcesses;
284          const uint32_t ppCount = static_cast<uint32_t>(postProcesses.size());
285          for (uint32_t idx = 0; idx < ppCount; ++idx) {
286              if (postProcesses[idx].name == ppName) {
287                  SetImpl(vars, idx, iter->second);
288                  break;
289              }
290          }
291      }
292  }
293  
Set(const string_view name,const array_view<PostProcess::Variables> vars)294  void RenderDataStorePostProcess::Set(const string_view name, const array_view<PostProcess::Variables> vars)
295  {
296      const auto lock = std::lock_guard(mutex_);
297  
298      if (auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.end()) {
299          const auto& postProcesses = iter->second.postProcesses;
300          const uint32_t ppCount =
301              Math::min(static_cast<uint32_t>(vars.size()), static_cast<uint32_t>(postProcesses.size()));
302          for (uint32_t idx = 0; idx < ppCount; ++idx) {
303              SetImpl(vars[idx], idx, iter->second);
304          }
305      }
306  }
307  
GetGlobalFactors(const string_view name) const308  RenderDataStorePostProcess::GlobalFactors RenderDataStorePostProcess::GetGlobalFactors(const string_view name) const
309  {
310      const auto lock = std::lock_guard(mutex_);
311  
312      if (auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.end()) {
313          return iter->second.globalFactors;
314      } else {
315          return {};
316      }
317  }
318  
Get(const string_view name) const319  vector<RenderDataStorePostProcess::PostProcess> RenderDataStorePostProcess::Get(const string_view name) const
320  {
321      const auto lock = std::lock_guard(mutex_);
322  
323      if (const auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.cend()) {
324          return iter->second.postProcesses;
325      }
326      return {};
327  }
328  
Get(const string_view name,const string_view ppName) const329  RenderDataStorePostProcess::PostProcess RenderDataStorePostProcess::Get(
330      const string_view name, const string_view ppName) const
331  {
332      const auto lock = std::lock_guard(mutex_);
333  
334      if (const auto iter = allPostProcesses_.find(name); iter != allPostProcesses_.cend()) {
335          for (const auto& ref : iter->second.postProcesses) {
336              if (ppName == ref.name) {
337                  return ref;
338              }
339          }
340      }
341      return {};
342  }
343  
CreateFromPod(const string_view name)344  void RenderDataStorePostProcess::CreateFromPod(const string_view name)
345  {
346      // create base post process render data store
347      if (IRenderDataStorePod* dataStorePod = static_cast<IRenderDataStorePod*>(
348              renderContext_.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_POD_NAME));
349          dataStorePod) {
350          PLUGIN_STATIC_ASSERT(
351              countof(PostProcessConstants::POST_PROCESS_NAMES) == PostProcessConstants::POST_PROCESS_COUNT);
352          auto& postProcessRef = allPostProcesses_[name];
353          // NOTE: needs to fetch the post process "properties" from shader custom properties
354          if (const auto arrView = dataStorePod->Get(name); arrView.size_bytes() == sizeof(PostProcessConfiguration)) {
355              // populate with built-in data and copy
356              PostProcessConfiguration ppConfig = *((const PostProcessConfiguration*)arrView.data());
357              FillDefaultPostProcessData(ppConfig, postProcessRef);
358          } else {
359              // create new
360              PostProcessConfiguration ppConfig;
361              dataStorePod->CreatePod(RENDER_DATA_STORE_POST_PROCESS_TYPE_NAME, name, arrayviewU8(ppConfig));
362              FillDefaultPostProcessData(ppConfig, postProcessRef);
363          }
364      }
365  }
366  
SetImpl(const PostProcess::Variables & vars,const uint32_t ppIndex,PostProcessStack & ppStack)367  void RenderDataStorePostProcess::SetImpl(
368      const PostProcess::Variables& vars, const uint32_t ppIndex, PostProcessStack& ppStack)
369  {
370      auto& postProcesses = ppStack.postProcesses;
371      PLUGIN_ASSERT(ppIndex < static_cast<uint32_t>(postProcesses.size()));
372      postProcesses[ppIndex].variables = vars;
373      SetGlobalFactorsImpl(vars, ppIndex, ppStack);
374  }
375  
SetGlobalFactorsImpl(const PostProcess::Variables & vars,const uint32_t ppIndex,PostProcessStack & ppStack)376  void RenderDataStorePostProcess::SetGlobalFactorsImpl(
377      const PostProcess::Variables& vars, const uint32_t ppIndex, PostProcessStack& ppStack)
378  {
379      PLUGIN_ASSERT(ppIndex < static_cast<uint32_t>(ppStack.postProcesses.size()));
380      // NOTE: does not copy vars
381      auto& globalFactors = ppStack.globalFactors;
382      if (ppIndex < PostProcessConstants::GLOBAL_FACTOR_COUNT) {
383          globalFactors.factors[ppIndex] = vars.factor;
384          globalFactors.enableFlags = (uint32_t(vars.enabled) << ppIndex);
385      } else if (vars.userFactorIndex < PostProcessConstants::USER_GLOBAL_FACTOR_COUNT) {
386          globalFactors.userFactors[vars.userFactorIndex] = vars.factor;
387      }
388  }
389  
FillDefaultPostProcessData(const PostProcessConfiguration & ppConfig,PostProcessStack & ppStack)390  void RenderDataStorePostProcess::FillDefaultPostProcessData(
391      const PostProcessConfiguration& ppConfig, PostProcessStack& ppStack)
392  {
393      const IShaderManager& shaderMgr = renderContext_.GetDevice().GetShaderManager();
394      auto FillBuiltInData = [&](const uint32_t idx, const uint32_t factorIndex, const uint32_t userFactorIndex,
395                                 const Math::Vec4& factor, const string_view shaderName) {
396          PostProcess pp;
397          pp.id = idx;
398          pp.name = PostProcessConstants::POST_PROCESS_NAMES[pp.id];
399          pp.factorIndex = factorIndex;
400          pp.shader = shaderName.empty() ? RenderHandleReference {} : shaderMgr.GetShaderHandle(shaderName);
401          auto& vars = pp.variables;
402          vars.userFactorIndex = userFactorIndex;
403          vars.enabled = false;
404          vars.factor = factor;
405          ClearToValue(vars.customPropertyData, sizeof(vars.customPropertyData), 0x0, sizeof(vars.customPropertyData));
406          return pp;
407      };
408  
409      constexpr uint32_t defUserIdx { ~0u };
410      ppStack.postProcesses.push_back(FillBuiltInData(PostProcessConstants::RENDER_TONEMAP,
411          PostProcessConstants::RENDER_TONEMAP, defUserIdx, PostProcessConversionHelper::GetFactorTonemap(ppConfig), {}));
412      ppStack.postProcesses.push_back(
413          FillBuiltInData(PostProcessConstants::RENDER_VIGNETTE, PostProcessConstants::RENDER_VIGNETTE, defUserIdx,
414              PostProcessConversionHelper::GetFactorVignette(ppConfig), {}));
415      ppStack.postProcesses.push_back(FillBuiltInData(PostProcessConstants::RENDER_DITHER,
416          PostProcessConstants::RENDER_DITHER, defUserIdx, PostProcessConversionHelper::GetFactorDither(ppConfig), {}));
417      ppStack.postProcesses.push_back(
418          FillBuiltInData(PostProcessConstants::RENDER_COLOR_CONVERSION, PostProcessConstants::RENDER_COLOR_CONVERSION,
419              defUserIdx, PostProcessConversionHelper::GetFactorColorConversion(ppConfig), {}));
420      ppStack.postProcesses.push_back(
421          FillBuiltInData(PostProcessConstants::RENDER_COLOR_FRINGE_BIT, PostProcessConstants::RENDER_COLOR_FRINGE_BIT,
422              defUserIdx, PostProcessConversionHelper::GetFactorFringe(ppConfig), {}));
423  
424      ppStack.postProcesses.push_back(FillBuiltInData(
425          PostProcessConstants::RENDER_EMPTY_5, PostProcessConstants::RENDER_EMPTY_5, defUserIdx, {}, {}));
426      ppStack.postProcesses.push_back(FillBuiltInData(
427          PostProcessConstants::RENDER_EMPTY_6, PostProcessConstants::RENDER_EMPTY_6, defUserIdx, {}, {}));
428      ppStack.postProcesses.push_back(FillBuiltInData(
429          PostProcessConstants::RENDER_EMPTY_7, PostProcessConstants::RENDER_EMPTY_7, defUserIdx, {}, {}));
430  
431      ppStack.postProcesses.push_back(FillBuiltInData(PostProcessConstants::RENDER_BLUR,
432          PostProcessConfiguration::INDEX_BLUR, defUserIdx, PostProcessConversionHelper::GetFactorBlur(ppConfig), {}));
433      ppStack.postProcesses.push_back(FillBuiltInData(PostProcessConstants::RENDER_BLOOM,
434          PostProcessConfiguration::INDEX_BLOOM, defUserIdx, PostProcessConversionHelper::GetFactorBloom(ppConfig), {}));
435      ppStack.postProcesses.push_back(
436          FillBuiltInData(PostProcessConstants::RENDER_FXAA, PostProcessConfiguration::INDEX_FXAA, defUserIdx,
437              PostProcessConversionHelper::GetFactorFxaa(ppConfig), FXAA_SHADER_NAME));
438      ppStack.postProcesses.push_back(
439          FillBuiltInData(PostProcessConstants::RENDER_TAA, PostProcessConfiguration::INDEX_TAA, defUserIdx,
440              PostProcessConversionHelper::GetFactorTaa(ppConfig), TAA_SHADER_NAME));
441      {
442          auto& pp = ppStack.postProcesses.emplace_back();
443          pp.id = PostProcessConstants::RENDER_DOF;
444          pp.name = PostProcessConstants::POST_PROCESS_NAMES[pp.id];
445          pp.factorIndex = PostProcessConfiguration::INDEX_DOF;
446          pp.shader = shaderMgr.GetShaderHandle(DOF_SHADER_NAME);
447          auto& vars = pp.variables;
448          vars.userFactorIndex = defUserIdx;
449          vars.enabled = false;
450          auto factors = PostProcessConversionHelper::GetFactorDof(ppConfig);
451          CloneData(vars.customPropertyData, sizeof(vars.customPropertyData), &factors, sizeof(factors));
452          factors = PostProcessConversionHelper::GetFactorDof2(ppConfig);
453          CloneData(vars.customPropertyData + sizeof(factors), sizeof(vars.customPropertyData) - sizeof(factors),
454              &factors, sizeof(factors));
455      }
456  
457      ppStack.postProcesses.push_back(
458          FillBuiltInData(PostProcessConstants::RENDER_MOTION_BLUR, PostProcessConstants::RENDER_MOTION_BLUR, defUserIdx,
459              PostProcessConversionHelper::GetFactorMotionBlur(ppConfig), MB_SHADER_NAME));
460  
461      // fill global built-in factors
462      PLUGIN_ASSERT(PostProcessConstants::POST_PROCESS_COUNT == static_cast<uint32_t>(ppStack.postProcesses.size()));
463      for (size_t idx = 0; idx < ppStack.postProcesses.size(); ++idx) {
464          ppStack.globalFactors.factors[idx] = ppStack.postProcesses[idx].variables.factor;
465      }
466  }
467  
GetShaderProperties(const RenderHandleReference & shader,IRenderDataStorePostProcess::PostProcess::Variables & vars)468  void RenderDataStorePostProcess::GetShaderProperties(
469      const RenderHandleReference& shader, IRenderDataStorePostProcess::PostProcess::Variables& vars)
470  {
471      if (shader) {
472          const IShaderManager& shaderMgr = renderContext_.GetDevice().GetShaderManager();
473          if (const json::value* metaJson = shaderMgr.GetMaterialMetadata(shader); metaJson && metaJson->is_array()) {
474              for (const auto& ref : metaJson->array_) {
475                  if (const auto globalFactor = ref.find(GLOBAL_FACTOR); globalFactor && globalFactor->is_array()) {
476                      // process global factor "array", vec4
477                      uint32_t offset = 0;
478                      for (const auto& propRef : globalFactor->array_) {
479                          if (propRef.is_object()) {
480                              string_view type;
481                              const json::value* value = nullptr;
482                              for (const auto& dataObject : propRef.object_) {
483                                  if (dataObject.key == "type" && dataObject.value.is_string()) {
484                                      type = dataObject.value.string_;
485                                  } else if (dataObject.key == "value") {
486                                      value = &dataObject.value;
487                                  }
488                              }
489                              uint8_t* factorData = reinterpret_cast<uint8_t*>(&vars.factor);
490                              AppendValues(MAX_GLOBAL_FACTOR_BYTE_SIZE, type, value, offset, factorData);
491                          }
492                      }
493                  } else if (const auto customProps = ref.find(CUSTOM_PROPERTIES);
494                             customProps && customProps->is_array()) {
495                      // process custom properties i.e. local factors
496                      for (const auto& propRef : customProps->array_) {
497                          uint32_t offset = 0;
498                          if (const auto customData = propRef.find(CUSTOM_PROPERTY_DATA);
499                              customData && customData->is_array()) {
500                              if (offset >= MAX_LOCAL_DATA_BYTE_SIZE) {
501                                  break;
502                              }
503  
504                              for (const auto& dataValue : customData->array_) {
505                                  if (dataValue.is_object()) {
506                                      string_view type;
507                                      const json::value* value = nullptr;
508                                      for (const auto& dataObject : dataValue.object_) {
509                                          if (dataObject.key == "type" && dataObject.value.is_string()) {
510                                              type = dataObject.value.string_;
511                                          } else if (dataObject.key == "value") {
512                                              value = &dataObject.value;
513                                          }
514                                      }
515                                      AppendValues(
516                                          MAX_LOCAL_DATA_BYTE_SIZE, type, value, offset, vars.customPropertyData);
517                                  }
518                              }
519                          }
520                      }
521                  }
522              }
523          }
524      }
525  }
526  
527  // for plugin / factory interface
Create(IRenderContext & renderContext,char const * name)528  IRenderDataStore* RenderDataStorePostProcess::Create(IRenderContext& renderContext, char const* name)
529  {
530      // engine not used
531      return new RenderDataStorePostProcess(renderContext, name);
532  }
533  
Destroy(IRenderDataStore * aInstance)534  void RenderDataStorePostProcess::Destroy(IRenderDataStore* aInstance)
535  {
536      delete static_cast<RenderDataStorePostProcess*>(aInstance);
537  }
538  RENDER_END_NAMESPACE()
539