SpiecsEngine
 
Loading...
Searching...
No Matches
Material.cpp
Go to the documentation of this file.
1/**
2* @file Material.cpp.
3* @brief The Material Class Implementation.
4* @author Spices.
5*/
6
7#include "Pchheader.h"
8#include "Material.h"
9#include "Render/Vulkan/VulkanRenderBackend.h"
10#include "Core/Reflect/TypeReflect.h"
11#include "Render/Renderer/DescriptorSetManager/DescriptorSetManager.h"
12#include "Render/Renderer/RendererManager.h"
13#include "Core/Library/StringLibrary.h"
14#include "Render/Renderer/Renderer.h"
15#include "Render/Renderer/DescriptorSetManager/BindLessTextureManager.h"
16#include "Resources/Shader/Shader.h"
17
18namespace Spices {
19
20 Material::Material(const std::string& materialPath)
21 : m_MaterialPath(materialPath)
22 , m_IsDrawWindow(false)
23 , m_AlreadyBuild(false)
24 {
26
27 /**
28 * @breif Call Dserialize() while in Constructor.
29 */
31 }
32
34 {
36
37 /**
38 * @brief UnLoad ShaderModule.
39 */
40 for (auto& pair : m_Shaders)
41 {
42 for (int i = 0; i < pair.second.size(); i++)
43 {
44 std::stringstream ss;
45 ss << pair.first << "." << pair.second[i];
46
47 ResourcePool<Shader>::UnLoad(ss.str());
48 }
49 }
50
51 }
52
54 {
56
57 if (m_MaterialPath.empty())
58 {
59 SPICES_CORE_INFO("Please do not do that!");
60 }
61 }
62
64 {
66
67 if (m_MaterialPath.empty())
68 {
69 SPICES_CORE_WARN("Material::m_MaterialPath is empty.");
70 return;
71 }
72
74 }
75
77 {
79
80 if (m_Shaders.find(stage) == m_Shaders.end())
81 {
82 std::stringstream ss;
83 ss << "Material: " << m_MaterialPath << " : Not find sush shader: " << stage;
84
85 SPICES_CORE_WARN(ss.str());
86 }
87
88 return m_Shaders[stage];
89 }
90
91 void Material::PushToShaderPath(const std::string& name, const std::string& shader)
92 {
94
95 std::unique_lock<std::mutex> lock(m_Mutex);
96
97 m_Shaders[name].push_back(shader);
98 m_DefaultShaders[name].push_back(shader);
99 }
100
101 void Material::PushToTextureParams(const std::string& name, const TextureParam& texture)
102 {
104
105 std::unique_lock<std::mutex> lock(m_Mutex);
106
107 m_TextureParams.push_back(name, texture);
108 m_DefaultTextureParams.push_back(name, texture);
109 }
110
111 void Material::PushToConstParams(const std::string& name, const ConstantParam& param)
112 {
114
115 std::unique_lock<std::mutex> lock(m_Mutex);
116
117 m_ConstantParams.push_back(name, {param, param});
118 }
119
121 {
123
124 if (m_MaterialParameterBuffer == nullptr)
125 {
126 SPICES_CORE_ERROR("Bad access to material buffer address.")
127
128 return 0;
129 }
130 else
131 {
132 return m_MaterialParameterBuffer->GetAddress();
133 }
134 }
135
136 void Material::BuildMaterial(bool isAutoRegistry)
137 {
139
140 std::unique_lock<std::mutex> lock(m_Mutex);
141
142 /**
143 * @brief Registry to renderer if already build.
144 */
145 {
146 SPICES_PROFILE_ZONEN("BuildMaterial::RegistryToRenderer");
147
148 if (m_AlreadyBuild)
149 {
150 /**
151 * @brief Create PipelineLayout.
152 */
153 {
154 std::vector<std::string> sv = StringLibrary::SplitString(m_MaterialPath, '.');
155 auto renderer = RendererManager::GetRenderer(sv[0]);
156 renderer->RegistryMaterial(m_MaterialPath, sv[1]);
157 }
158
159 return;
160 }
161
162 m_AlreadyBuild = true;
163 }
164
165 /**
166 * @brief Registry ShaderModule.
167 */
168 {
169 SPICES_PROFILE_ZONEN("BuildMaterial::Registry ShaderModule");
170
171 for (auto& pair : m_Shaders)
172 {
173 for (int i = 0; i < pair.second.size(); i++)
174 {
175 std::stringstream ss;
176 ss << pair.second[i] << "." << pair.first;
177
178 ResourcePool<Shader>::Load<Shader>(ss.str(), pair.second[i], pair.first);
179 }
180 }
181 }
182
183 /**
184 * @brief If ReBuild, need clear old descripotrset first.
185 */
186 {
187 SPICES_PROFILE_ZONEN("BuildMaterial::Clean Up old descripotrset");
188
189 m_MaterialParameterBuffer = nullptr;
190 m_Buffermemoryblocks = scl::runtime_memory_block();
191 }
192
193 /**
194 * @brief Iter the constantParams and fill it's data to memoryblock.
195 */
196 {
197 SPICES_PROFILE_ZONEN("BuildMaterial::Build Local ConstantParameter Block");
198
199 m_ConstantParams.for_each([&](const std::string& k, const ConstantParams& v) {
200 m_Buffermemoryblocks.add_element(k, v.value.paramType);
201 return false;
202 });
203
204 m_Buffermemoryblocks.build();
205 }
206
207 /**
208 * @brief Return if not valid textureParameter or constantParameter.
209 */
210 uint64_t size = m_TextureParams.size() * sizeof(int) + m_Buffermemoryblocks.get_bytes();
211 if (size == 0)
212 {
213 if (isAutoRegistry)
214 {
215 const std::vector<std::string> sv = StringLibrary::SplitString(m_MaterialPath, '.');
216 auto renderer = RendererManager::GetRenderer(sv[0]);
217 renderer->RegistryMaterial(m_MaterialPath, sv[1]);
218 }
219
220 return;
221 }
222
223 /**
224 * @brief Create Material Parameter to store all address and index.
225 */
226 {
227 SPICES_PROFILE_ZONEN("BuildMaterial::Create Material Parameter Buffer");
228
229 m_MaterialParameterBuffer = std::make_unique<VulkanBuffer>(
230 VulkanRenderBackend::GetState(),
231 "MaterialParameterBuffer",
232 size,
233 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
234 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
235 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
236 );
237 }
238
239 /**
240 * @brief Registry texture to both ResourcePool, BindLessTextureManager, DescriptorSetManager and MaterialParameterBuffer.
241 */
242 {
243 SPICES_PROFILE_ZONEN("BuildMaterial::Registry texture");
244
245 int tindex = 0;
246 m_TextureParams.for_each([&](const std::string& k, TextureParam& v) {
247
248 /**
249 * @brief Only work with Texture2D now.
250 * @todo more type support, reflection.
251 */
252 if (v.textureType == "Texture2D")
253 {
254 if(v.texturePath == "")
255 {
256 v.index = -1;
257 }
258 else
259 {
260 const std::shared_ptr<Texture> texture = ResourcePool<Texture>::Load<Texture2D>(v.texturePath, v.texturePath);
261 v.index = BindLessTextureManager::Registry(v.texturePath);
262
263 const auto descriptorSet = DescriptorSetManager::Registry("PreRenderer", SpicesShader::BINDLESS_TEXTURE_SET);
264
265 /**
266 * @brief Instance a VkWriteDescriptorSet.
267 */
268 VkWriteDescriptorSet write {};
269 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
270 write.dstBinding = SpicesShader::BINDLESS_TEXTURE_BINDING;
271 write.dstSet = descriptorSet->Get();
272 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
273 write.pImageInfo = texture->GetResource<VulkanImage>()->GetImageInfo();
274 write.descriptorCount = 1;
275 write.dstArrayElement = v.index;
276
277 /**
278 * @brief Update DescriptorSet.
279 */
280 vkUpdateDescriptorSets(VulkanRenderBackend::GetState().m_Device, 1, &write, 0, nullptr);
281 }
282
283 m_MaterialParameterBuffer->WriteToBuffer(&v.index, sizeof(int), tindex * sizeof(int));
284 m_MaterialParameterBuffer->Flush();
285 }
286
287 /**
288 * @brief Not supported format.
289 */
290 else
291 {
292 SPICES_CORE_ERROR("Material::BuildMaterial(): Invalid textureType.");
293 }
294
295 tindex++;
296 return false;
297 });
298 }
299
300 /**
301 * @brief Create ConstantParameter Buffer .
302 */
303 {
304 SPICES_PROFILE_ZONEN("BuildMaterial::Add ConstantParameter Buffer");
305
306 m_Buffermemoryblocks.for_each([&](const std::string& name, void* pt) {
307 ConstantParam& ref = m_ConstantParams.find_value(name)->value;
308 size_t size = m_TextureParams.size() * sizeof(int) + m_Buffermemoryblocks.item_location(name);
309
310 /**
311 * @brief Fill in data to memory block.
312 */
313 if (ref.paramType == "float4")
314 {
315 *static_cast<glm::vec4*>(pt) = std::any_cast<glm::vec4>(ref.paramValue);
316 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec4), size);
317 m_MaterialParameterBuffer->Flush();
318 }
319 else if (ref.paramType == "float3")
320 {
321 *static_cast<glm::vec3*>(pt) = std::any_cast<glm::vec3>(ref.paramValue);
322 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec3), size);
323 m_MaterialParameterBuffer->Flush();
324 }
325 else if (ref.paramType == "float2")
326 {
327 *static_cast<glm::vec2*>(pt) = std::any_cast<glm::vec2>(ref.paramValue);
328 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec2), size);
329 m_MaterialParameterBuffer->Flush();
330 }
331 else if (ref.paramType == "float")
332 {
333 *static_cast<float*>(pt) = std::any_cast<float>(ref.paramValue);
334 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(float), size);
335 m_MaterialParameterBuffer->Flush();
336 }
337 else if (ref.paramType == "int")
338 {
339 *static_cast<int*>(pt) = std::any_cast<int>(ref.paramValue);
340 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(int), size);
341 m_MaterialParameterBuffer->Flush();
342 }
343 else if (ref.paramType == "bool")
344 {
345 *static_cast<bool*>(pt) = std::any_cast<bool>(ref.paramValue);
346 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(bool), size);
347 m_MaterialParameterBuffer->Flush();
348 }
349 else
350 {
351 SPICES_CORE_ERROR("Material::BuildMaterial(): Invalid paramType.")
352 }
353
354 return false;
355 });
356 }
357
358 /**
359 * @brief Create PipelineLayout.
360 */
361 if (isAutoRegistry)
362 {
363 std::vector<std::string> sv = StringLibrary::SplitString(m_MaterialPath, '.');
364 auto renderer = RendererManager::GetRenderer(sv[0]);
365 renderer->RegistryMaterial(m_MaterialPath, sv[1]);
366 }
367 }
368
370 {
372
373 std::unique_lock<std::mutex> lock(m_Mutex);
374
375 /**
376 * @brief Registry ShaderModule.
377 */
378 {
379 SPICES_PROFILE_ZONEN("BuildMaterial::Registry ShaderModule");
380
381 for (auto& pair : m_Shaders)
382 {
383 for (int i = 0; i < pair.second.size(); i++)
384 {
385 std::stringstream ss;
386 ss << pair.first << "." << pair.second[i];
387
388 ResourcePool<Shader>::Load<Shader>(ss.str(), pair.second[i], pair.first);
389 }
390 }
391 }
392
393 /**
394 * @brief Iter the constantParams and fill it's data to memoryblock.
395 */
396 {
397 SPICES_PROFILE_ZONEN("BuildMaterial::Build Local ConstantParameter Block");
398
399 m_Buffermemoryblocks = scl::runtime_memory_block();
400
401 m_ConstantParams.for_each([&](const std::string& k, const ConstantParams& v) {
402 m_Buffermemoryblocks.add_element(k, v.value.paramType);
403 return false;
404 });
405
406 m_Buffermemoryblocks.build();
407 }
408
409 /**
410 * @brief Registry texture to both ResourcePool, BindLessTextureManager, DescriptorSetManager and MaterialParameterBuffer.
411 */
412 {
413 SPICES_PROFILE_ZONEN("BuildMaterial::Registry texture");
414
415 int tindex = 0;
416 m_TextureParams.for_each([&](const std::string& k, TextureParam& v) {
417
418 /**
419 * @brief Only work with Texture2D now.
420 * @todo more type support, reflection.
421 */
422 if (v.textureType == "Texture2D")
423 {
424 if (v.texturePath == "")
425 {
426 v.index = -1;
427 }
428 else
429 {
430 std::shared_ptr<Texture> texture = ResourcePool<Texture>::Load<Texture2D>(v.texturePath, v.texturePath);
431 v.index = BindLessTextureManager::Registry(v.texturePath);
432
433 auto descriptorSet = DescriptorSetManager::Registry("PreRenderer", SpicesShader::BINDLESS_TEXTURE_SET);
434
435 /**
436 * @brief Instance a VkWriteDescriptorSet.
437 */
438 VkWriteDescriptorSet write {};
439 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
440 write.dstBinding = SpicesShader::BINDLESS_TEXTURE_BINDING;
441 write.dstSet = descriptorSet->Get();
442 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
443 write.pImageInfo = texture->GetResource<VulkanImage>()->GetImageInfo();
444 write.descriptorCount = 1;
445 write.dstArrayElement = v.index;
446
447 /**
448 * @brief Update DescriptorSet.
449 */
450 vkUpdateDescriptorSets(VulkanRenderBackend::GetState().m_Device, 1, &write, 0, nullptr);
451 }
452
453 m_MaterialParameterBuffer->WriteToBuffer(&v.index, sizeof(int), tindex * sizeof(int));
454 m_MaterialParameterBuffer->Flush();
455 }
456
457 /**
458 * @brief Not supported format.
459 */
460 else
461 {
462 SPICES_CORE_ERROR("Material::BuildMaterial(): Invalid textureType.")
463 }
464
465 tindex++;
466 return false;
467 });
468 }
469
470 /**
471 * @brief Create ConstantParameter Buffer .
472 */
473 {
474 SPICES_PROFILE_ZONEN("BuildMaterial::Add ConstantParameter Buffer");
475
476 m_Buffermemoryblocks.for_each([&](const std::string& name, void* pt) {
477 ConstantParam& ref = m_ConstantParams.find_value(name)->value;
478 size_t size = m_TextureParams.size() * sizeof(int) + m_Buffermemoryblocks.item_location(name);
479
480 /**
481 * @brief Fill in data to memory block.
482 */
483 if (ref.paramType == "float4")
484 {
485 *static_cast<glm::vec4*>(pt) = std::any_cast<glm::vec4>(ref.paramValue);
486 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec4), size);
487 m_MaterialParameterBuffer->Flush();
488 }
489 else if (ref.paramType == "float3")
490 {
491 *static_cast<glm::vec3*>(pt) = std::any_cast<glm::vec3>(ref.paramValue);
492 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec3), size);
493 m_MaterialParameterBuffer->Flush();
494 }
495 else if (ref.paramType == "float2")
496 {
497 *static_cast<glm::vec2*>(pt) = std::any_cast<glm::vec2>(ref.paramValue);
498 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(glm::vec2), size);
499 m_MaterialParameterBuffer->Flush();
500 }
501 else if (ref.paramType == "float")
502 {
503 *static_cast<float*>(pt) = std::any_cast<float>(ref.paramValue);
504 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(float), size);
505 m_MaterialParameterBuffer->Flush();
506 }
507 else if (ref.paramType == "int")
508 {
509 *static_cast<int*>(pt) = std::any_cast<int>(ref.paramValue);
510 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(int), size);
511 m_MaterialParameterBuffer->Flush();
512 }
513 else if (ref.paramType == "bool")
514 {
515 *static_cast<bool*>(pt) = std::any_cast<bool>(ref.paramValue);
516 m_MaterialParameterBuffer->WriteToBuffer(pt, sizeof(bool), size);
517 m_MaterialParameterBuffer->Flush();
518 }
519 else
520 {
521 SPICES_CORE_ERROR("Material::BuildMaterial(): Invalid paramType.")
522 }
523
524 return false;
525 });
526 }
527 }
528}
#define SPICES_PROFILE_ZONEN(...)
#define SPICES_PROFILE_ZONE
static bool Load(const std::string &fileName, Material *outMaterial)
Public called API, it is entrance.
This enum defines tree types of material file.
void BuildMaterial(bool isAutoRegistry=true)
This interface need to be overwritten by specific material. It defines how we build texture and descr...
Definition Material.cpp:136
void PushToTextureParams(const std::string &name, const TextureParam &texture)
Push item to ShaderPath.
Definition Material.cpp:101
const std::vector< std::string > & GetShaderPath(const std::string &stage)
Get material shader path.
Definition Material.cpp:76
bool m_AlreadyBuild
True if this material already build a buffer.
Definition Material.h:252
void UpdateMaterial()
Update material data to buffer.
Definition Material.cpp:369
void Deserialize()
Deserialize the data from a disk file(.material) to this class.
Definition Material.cpp:63
void PushToShaderPath(const std::string &name, const std::string &shader)
Push item to ShaderPath.
Definition Material.cpp:91
void PushToConstParams(const std::string &name, const ConstantParam &param)
Push item to ConstParams.
Definition Material.cpp:111
uint64_t GetMaterialParamsAddress() const
Get material parameter address on GPU.
Definition Material.cpp:120
bool m_IsDrawWindow
True if this material needs to draw a window.
Definition Material.h:247
Material(const std::string &materialPath)
Constructor Function. Deserialize immediately. Usually call it.
Definition Material.cpp:20
virtual ~Material()
Destructor Function.
Definition Material.cpp:33
std::string m_MaterialPath
Definition Material.h:206
void Serialize()
Serialize this class data to a disk file(.material).
Definition Material.cpp:53
Material Class. This class contains a branch of parameter and shader, also descriptor.
Definition Material.h:62
This struct's data is defined from .material file.
Definition Material.h:37
This struct's data is defined from .material file.
Definition Material.h:27