Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
VulkanMaterial.cpp
1/*
2Copyright (C) 2017-2021,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#include <fstream>
17#include <ostream>
18#include <regex>
19#include <array>
20#include <utility>
21#include <cassert>
23#include "aeongames/ProtoBufUtils.hpp"
24#ifdef _MSC_VER
25#pragma warning( push )
26#pragma warning( disable : PROTOBUF_WARNINGS )
27#endif
28#include "material.pb.h"
29#include "pipeline.pb.h"
30#ifdef _MSC_VER
31#pragma warning( pop )
32#endif
33#include "aeongames/AeonEngine.hpp"
34#include "aeongames/CRC.hpp"
35#include "aeongames/Material.hpp"
36#include "aeongames/Vector2.hpp"
37#include "aeongames/Vector3.hpp"
38#include "aeongames/Vector4.hpp"
39#include "aeongames/Mesh.hpp"
41#include "VulkanMaterial.hpp"
42#include "VulkanTexture.hpp"
43#include "VulkanRenderer.hpp"
44#include "VulkanUtilities.hpp"
45
46namespace AeonGames
47{
48 VulkanMaterial::VulkanMaterial ( VulkanRenderer& aVulkanRenderer, const Material& aMaterial ) :
49 mVulkanRenderer { aVulkanRenderer },
50 mMaterial { &aMaterial },
51 mUniformBuffer { mVulkanRenderer }
52 {
53 if ( mVkDescriptorPool != VK_NULL_HANDLE || mUniformDescriptorSet != VK_NULL_HANDLE || mSamplerDescriptorSet != VK_NULL_HANDLE )
54 {
55 std::cout << LogLevel::Error << "VulkanMaterial: Already initialized." << std::endl;
56 throw std::runtime_error ( "VulkanMaterial: Already initialized." );
57 }
58
59 std::vector<VkDescriptorPoolSize> descriptor_pool_sizes{};
60 descriptor_pool_sizes.reserve ( 2 );
61
62 if ( mMaterial->GetUniformBuffer().size() > 0 )
63 {
64 descriptor_pool_sizes.push_back ( {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1} );
65 }
66 if ( mMaterial->GetSamplers().size() > 0 )
67 {
68 descriptor_pool_sizes.push_back ( {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, static_cast<uint32_t> ( mMaterial->GetSamplers().size() ) } );
69 }
70
71 if ( !descriptor_pool_sizes.empty() )
72 {
73 mVkDescriptorPool = CreateDescriptorPool ( mVulkanRenderer.GetDevice(), descriptor_pool_sizes );
74 }
75
76 std::vector<VkWriteDescriptorSet> write_descriptor_sets{};
77 write_descriptor_sets.reserve ( mMaterial->GetSamplers().size() + ( ( mMaterial->GetUniformBuffer().size() ? 1 : 0 ) ) );
78
79 if ( mMaterial->GetUniformBuffer().size() > 0 )
80 {
81 VkDescriptorSetLayoutBinding descriptor_set_layout_binding
82 {
83 .binding = 0,
84 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
85 .descriptorCount = 1,
86 .stageFlags = VK_SHADER_STAGE_ALL,
87 .pImmutableSamplers = nullptr
88 };
89 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info
90 {
91 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
92 .pNext = nullptr,
93 .flags = 0,
94 .bindingCount = 1,
95 .pBindings = &descriptor_set_layout_binding
96 };
97
98 VkDescriptorSetAllocateInfo descriptor_set_allocate_info{};
99 descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
100 descriptor_set_allocate_info.descriptorPool = mVkDescriptorPool;
101 descriptor_set_allocate_info.descriptorSetCount = 1;
102 descriptor_set_allocate_info.pSetLayouts = &mVulkanRenderer.GetDescriptorSetLayout ( descriptor_set_layout_create_info );
103 if ( VkResult result = vkAllocateDescriptorSets ( mVulkanRenderer.GetDevice(), &descriptor_set_allocate_info, &mUniformDescriptorSet ) )
104 {
105 std::ostringstream stream;
106 stream << "Allocate Descriptor Set failed: ( " << GetVulkanResultString ( result ) << " )";
107 std::cout << LogLevel::Error << stream.str() << std::endl;
108 throw std::runtime_error ( stream.str().c_str() );
109 }
110 mUniformBuffer.Initialize (
111 mMaterial->GetUniformBuffer().size(),
112 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
113 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
114 mMaterial->GetUniformBuffer().data() );
115 VkDescriptorBufferInfo descriptor_buffer_info
116 {
117 mUniformBuffer.GetBuffer(),
118 0,
119 mMaterial->GetUniformBuffer().size()
120 };
121 write_descriptor_sets.emplace_back();
122 auto& write_descriptor_set = write_descriptor_sets.back();
123 write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
124 write_descriptor_set.pNext = nullptr;
125 write_descriptor_set.dstSet = mUniformDescriptorSet;
126 write_descriptor_set.dstBinding = 0;
127 write_descriptor_set.dstArrayElement = 0;
128 write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
129 write_descriptor_set.descriptorCount = 1;
130 write_descriptor_set.pBufferInfo = &descriptor_buffer_info;
131 write_descriptor_set.pImageInfo = nullptr;
132 write_descriptor_set.pTexelBufferView = nullptr;
133 }
134
135 if ( mMaterial->GetSamplers().size() > 0 )
136 {
137 std::vector<VkDescriptorSetLayoutBinding> descriptor_set_layout_bindings{};
138 descriptor_set_layout_bindings.reserve ( mMaterial->GetSamplers().size() );
139 for ( uint32_t i = 0; i < mMaterial->GetSamplers().size(); ++i )
140 {
141 descriptor_set_layout_bindings.push_back (
142 VkDescriptorSetLayoutBinding
143 {
144 .binding = i,
145 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
146 .descriptorCount = 1,
147 .stageFlags = VK_SHADER_STAGE_ALL,
148 .pImmutableSamplers = nullptr
149 } );
150 }
151 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info
152 {
153 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
154 .pNext = nullptr,
155 .flags = 0,
156 .bindingCount = static_cast<uint32_t> ( descriptor_set_layout_bindings.size() ),
157 .pBindings = descriptor_set_layout_bindings.data()
158 };
159
160 VkDescriptorSetAllocateInfo descriptor_set_allocate_info{};
161 descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
162 descriptor_set_allocate_info.descriptorPool = mVkDescriptorPool;
163 descriptor_set_allocate_info.descriptorSetCount = 1;
164 descriptor_set_allocate_info.pSetLayouts = &mVulkanRenderer.GetDescriptorSetLayout ( descriptor_set_layout_create_info );
165 if ( VkResult result = vkAllocateDescriptorSets ( mVulkanRenderer.GetDevice(), &descriptor_set_allocate_info, &mSamplerDescriptorSet ) )
166 {
167 std::ostringstream stream;
168 stream << "Allocate Descriptor Set failed: ( " << GetVulkanResultString ( result ) << " )";
169 std::cout << LogLevel::Error << stream.str() << std::endl;
170 throw std::runtime_error ( stream.str().c_str() );
171 }
172
173 for ( uint32_t i = 0; i < mMaterial->GetSamplers().size(); ++i )
174 {
175 write_descriptor_sets.emplace_back();
176 auto& write_descriptor_set = write_descriptor_sets.back();
177 write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
178 write_descriptor_set.pNext = nullptr;
179 // Note that the descriptor set does not change, we are setting multiple bindings on a single descriptor set.
180 write_descriptor_set.dstSet = mSamplerDescriptorSet;
181 write_descriptor_set.dstBinding = i;
182 write_descriptor_set.dstArrayElement = 0;
183 write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
184 write_descriptor_set.descriptorCount = 1;
185 write_descriptor_set.pBufferInfo = nullptr;
186 write_descriptor_set.pImageInfo = mVulkanRenderer.GetTextureDescriptorImageInfo ( *std::get<1> ( mMaterial->GetSamplers() [i] ).Get<Texture>() );
187 write_descriptor_set.pTexelBufferView = nullptr;
188 }
189 }
190 if ( !write_descriptor_sets.empty() )
191 {
192 vkUpdateDescriptorSets ( mVulkanRenderer.GetDevice(), static_cast<uint32_t> ( write_descriptor_sets.size() ), write_descriptor_sets.data(), 0, nullptr );
193 }
194 }
195
196 void VulkanMaterial::Finalize ()
197 {
198 // Finalize Descriptor Pool
199 if ( mVkDescriptorPool != VK_NULL_HANDLE )
200 {
201 vkDestroyDescriptorPool ( mVulkanRenderer.GetDevice(), mVkDescriptorPool, nullptr );
202 }
203 mUniformBuffer.Finalize();
204 }
205
206 VulkanMaterial::~VulkanMaterial()
207 {
208 Finalize ();
209 }
210
212 mVulkanRenderer{aVulkanMaterial.mVulkanRenderer},
213 mMaterial{aVulkanMaterial.mMaterial},
214 mUniformBuffer{std::move ( aVulkanMaterial.mUniformBuffer ) }
215 {
216 std::swap ( mVkDescriptorPool, aVulkanMaterial.mVkDescriptorPool );
217 std::swap ( mUniformDescriptorSet, aVulkanMaterial.mUniformDescriptorSet );
218 std::swap ( mSamplerDescriptorSet, aVulkanMaterial.mSamplerDescriptorSet );
219 }
220
221 void VulkanMaterial::Bind ( VkCommandBuffer aVkCommandBuffer, const VulkanPipeline& aPipeline ) const
222 {
223 if ( uint32_t material_set_index = aPipeline.GetDescriptorSetIndex ( Mesh::BindingLocations::MATERIAL ); material_set_index != std::numeric_limits<uint32_t>::max() )
224 {
225 vkCmdBindDescriptorSets ( aVkCommandBuffer,
226 VK_PIPELINE_BIND_POINT_GRAPHICS,
227 aPipeline.GetPipelineLayout(),
228 material_set_index,
229 1,
230 &mUniformDescriptorSet, 0, nullptr );
231 }
232 if ( uint32_t sampler_set_index = aPipeline.GetDescriptorSetIndex ( Mesh::BindingLocations::SAMPLERS ); sampler_set_index != std::numeric_limits<uint32_t>::max() )
233 {
234 vkCmdBindDescriptorSets ( aVkCommandBuffer,
235 VK_PIPELINE_BIND_POINT_GRAPHICS,
236 aPipeline.GetPipelineLayout(),
237 sampler_set_index,
238 1,
239 &mSamplerDescriptorSet, 0, nullptr );
240 }
241 }
242}
Defines log severity levels and stream output for the AeonGames engine.
Provides the DLL_PROTOBUF export/import macro for protobuf wrapper classes.
Header for the 3D vector class.
Header for the 4D vector class.
Represents a surface material with uniform properties and texture samplers.
Definition Material.hpp:38
@ SAMPLERS
Samplers binding.
Definition Mesh.hpp:74
@ MATERIAL
Material binding.
Definition Mesh.hpp:72
Represents a 2D texture image resource.
Definition Texture.hpp:33
void Finalize()
Release the Vulkan buffer and its device memory.
VulkanMaterial(VulkanRenderer &aVulkanRenderer, const Material &aMaterial)
Construct from a renderer and material resource.
void Bind(VkCommandBuffer aVkCommandBuffer, const VulkanPipeline &aVulkanPipeline) const
Bind material descriptor sets to a command buffer for the given pipeline.
Vulkan graphics pipeline with descriptor set and push constant reflection.
uint32_t GetDescriptorSetIndex(uint32_t hash) const
Get the descriptor set index for a given hash.
const VkPipelineLayout GetPipelineLayout() const
Get the Vulkan pipeline layout handle.
Vulkan rendering backend implementing the Renderer interface.
const VkDevice & GetDevice() const
Get the logical device handle.
<- This is here just for the literals
Definition AABB.hpp:31
VkDescriptorPool CreateDescriptorPool(const VkDevice &aVkDevice, const std::vector< VkDescriptorPoolSize > &aVkDescriptorPoolSizes)
Create a Vulkan descriptor pool from the given pool sizes.
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
@ Error
Error conditions.
Definition LogLevel.hpp:33
STL namespace.