Rendering Engine 0.2.0
Modular Graphics Rendering Engine | v0.2.0
Loading...
Searching...
No Matches
vulkan_render_resources.cpp
Go to the documentation of this file.
2#include "vulkan_renderer.hpp"
6#include "image_data_gpu.hpp"
7#include "material.hpp"
8#include "mesh_data_gpu.hpp"
9#include "texture_cache.hpp"
10
11#include <stdexcept>
12
13namespace rendering_engine
14{
15
17 :
18 mRenderer(renderer),
19 bHasCustomMaterialVariables(false)
20{
21 mRenderer->RegisterObserver(this);
22}
23
25{
26 mRenderer->UnregisterObserver(this);
27}
28
29void VulkanRenderResources::Initialize(Material* material, MeshDataGpu* meshData, TextureCache* textureCache)
30{
31 mMaterial = material;
32 mMeshData = meshData;
33 mTextureCache = textureCache;
34
36}
37
38void VulkanRenderResources::SubmitResources(Transformations2D& transformations, const PackedMaterialData& materialParameters)
39{
40 UpdateTransformations(transformations);
41 UpdateMaterialParameters(materialParameters);
43}
44
45void VulkanRenderResources::SubmitResources(Transformations3D& transformations, const PackedMaterialData& materialParameters)
46{
47 UpdateTransformations(transformations);
48 UpdateMaterialParameters(materialParameters);
50}
51
53{
54 auto logicalDevice = mRenderer->GetLogicalDevice();
55
56 vkDestroyDescriptorPool(logicalDevice, mDescriptorPool, nullptr);
57
58 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
59 {
60 vkDestroyBuffer(logicalDevice, mTransformationBuffers[i], nullptr);
61 vkFreeMemory(logicalDevice, mTransformationBuffersMemory[i], nullptr);
62
63 if (!mMaterialParametersBuffers.empty())
64 {
65 vkDestroyBuffer(logicalDevice, mMaterialParametersBuffers[i], nullptr);
66 vkFreeMemory(logicalDevice, mMaterialParametersMemory[i], nullptr);
67 }
68 }
69}
70
75
80
82{
83 if (!mMaterial)
84 {
85 // Log error message, as without initialized material rendering is not possible.
86 return;
87 }
88 VulkanMaterialResources* materialResources = static_cast<VulkanMaterialResources*>(mMaterial->GetMaterialRenderResources());
89 mGraphicsPipeline = materialResources->GetPipeline();
90 mPipelineLayout = materialResources->GetPipelineLayout();
91
92 VulkanMeshResources* meshResources = static_cast<VulkanMeshResources*>(mMeshData->GetMeshRenderResources());
93 mVertexBuffer = meshResources->GetVertexBuffer();
94 mIndexBuffer = meshResources->GetIndexBuffer();
95
99}
100
102{
103 VkDeviceSize transformationBufferSize;
104 if (mMaterial->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
105 {
106 transformationBufferSize = sizeof(Transformations2D);
107 }
108 if (mMaterial->GetMaterialSettings().materialDomain == MaterialDomain::Surface3D)
109 {
110 transformationBufferSize = sizeof(Transformations3D);
111 }
112
113 mTransformationBuffers.resize(MAX_FRAMES_IN_FLIGHT);
114 mTransformationBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
115
116 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
117 {
118 mRenderer->CreateBuffer(transformationBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
119 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
120 mTransformationBuffers[i], mTransformationBuffersMemory[i]);
121 }
122
123 auto materialParameters = mMaterial->PackMaterialParameters();
124 if (materialParameters.buffer.empty())
125 {
126 return;
127 }
128
129 VkDeviceSize matVarBufferSize = materialParameters.buffer.size();
130 mMaterialParametersBuffers.resize(MAX_FRAMES_IN_FLIGHT);
131 mMaterialParametersMemory.resize(MAX_FRAMES_IN_FLIGHT);
132
133 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
134 {
135 mRenderer->CreateBuffer(matVarBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
136 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
137 mMaterialParametersBuffers[i], mMaterialParametersMemory[i]);
138 }
139}
140
142{
143 const uint32_t maxFramesInFlight = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
144 std::vector<VkDescriptorPoolSize> poolSizes;
145
146 VkDescriptorPoolSize tranformationPool;
147 tranformationPool.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
148 tranformationPool.descriptorCount = maxFramesInFlight;
149
150 poolSizes.push_back(tranformationPool);
151
152 auto materialParameters = mMaterial->PackMaterialParameters();
153 if (!materialParameters.buffer.empty())
154 {
155 VkDescriptorPoolSize materialParameterPool;
156 materialParameterPool.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
157 materialParameterPool.descriptorCount = maxFramesInFlight;
158
159 poolSizes.push_back(materialParameterPool);
160 }
161
162 for (const auto& texture : mMaterial->GetTextures())
163 {
164 (void)texture;
165 VkDescriptorPoolSize textureSamplerPool;
166 textureSamplerPool.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
167 textureSamplerPool.descriptorCount = maxFramesInFlight;
168
169 poolSizes.push_back(textureSamplerPool);
170 }
171
172 VkDescriptorPoolCreateInfo poolInfo{};
173 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
174 poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
175 poolInfo.pPoolSizes = poolSizes.data();
176 poolInfo.maxSets = maxFramesInFlight;
177
178 if (vkCreateDescriptorPool(mRenderer->GetLogicalDevice(), &poolInfo, nullptr, &mDescriptorPool) != VK_SUCCESS)
179 {
180 throw std::runtime_error("failed to create descriptor pool!");
181 }
182}
183
185{
186 // By local convention of this engine, bindings will be numbered:
187 // Bindings i = 0, i < n, there n - total number of bindings
188 // Binding i - transformations matrices of types according to material domain (2D or 3D)
189 // Binding i++ - cunstom parameter variable of material, if any. All variables will be
190 // serialized and packed in a single binding
191 // Binding i++ - textures sampler, if any. One texture per binding.
192
193 const uint32_t maxFramesInFlight = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
194
195 VulkanMaterialResources* materialResources = static_cast<VulkanMaterialResources*>(mMaterial->GetMaterialRenderResources());
196 auto descriptorSetLayout = materialResources->GetDescriptorSetLayout();
197 std::vector<VkDescriptorSetLayout> layouts(maxFramesInFlight, descriptorSetLayout);
198 VkDescriptorSetAllocateInfo allocInfo{};
199 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
200 allocInfo.descriptorPool = mDescriptorPool;
201 allocInfo.descriptorSetCount = maxFramesInFlight;
202 allocInfo.pSetLayouts = layouts.data();
203
204 mDescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
205 VkResult result = vkAllocateDescriptorSets(mRenderer->GetLogicalDevice(), &allocInfo, mDescriptorSets.data());
206 if (result != VK_SUCCESS)
207 {
208 throw std::runtime_error("failed to allocate descriptor sets! Error: " + std::to_string(result));
209 }
210
211 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
212 {
213 unsigned int dstBinding = 0;
214 std::vector<VkWriteDescriptorSet> descriptorWrites;
215
216 // Transfotmations descriptor set
217 VkDescriptorBufferInfo transformationBufferInfo{};
218 transformationBufferInfo.buffer = mTransformationBuffers[i];
219 transformationBufferInfo.offset = 0;
220 if (mMaterial->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
221 {
222 transformationBufferInfo.range = sizeof(Transformations2D);
223 }
224 if (mMaterial->GetMaterialSettings().materialDomain == MaterialDomain::Surface3D)
225 {
226 transformationBufferInfo.range = sizeof(Transformations3D);
227 }
228 VkWriteDescriptorSet transformationsDescSet;
229 transformationsDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
230 transformationsDescSet.pNext = nullptr;
231 transformationsDescSet.dstSet = mDescriptorSets[i];
232 transformationsDescSet.dstBinding = dstBinding;
233 transformationsDescSet.dstArrayElement = 0;
234 transformationsDescSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
235 transformationsDescSet.descriptorCount = 1;
236 transformationsDescSet.pBufferInfo = &transformationBufferInfo;
237 descriptorWrites.push_back(transformationsDescSet);
238
239 // Custom material parameters descriptor set
240 auto materialParameters = mMaterial->PackMaterialParameters();
241 if (!materialParameters.buffer.empty())
242 {
243 ++dstBinding;
244 VkDescriptorBufferInfo matVarBufferInfo{};
245 matVarBufferInfo.buffer = mMaterialParametersBuffers[i];
246 matVarBufferInfo.offset = 0;
247 matVarBufferInfo.range = materialParameters.buffer.size();
248
249 VkWriteDescriptorSet matVarDescSet;
250 matVarDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
251 matVarDescSet.pNext = nullptr;
252 matVarDescSet.dstSet = mDescriptorSets[i];
253 matVarDescSet.dstBinding = dstBinding;
254 matVarDescSet.dstArrayElement = 0;
255 matVarDescSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
256 matVarDescSet.descriptorCount = 1;
257 matVarDescSet.pBufferInfo = &matVarBufferInfo;
258 descriptorWrites.push_back(matVarDescSet);
259 }
260
261 // Custom texture image data descriptor set
262 for (const auto& texture : mMaterial->GetTextures())
263 {
264 ++dstBinding;
265 auto imageData = mTextureCache->GetTextureResources(texture);
266 VulkanTextureResources* textureResources = static_cast<VulkanTextureResources*>(imageData->GetTextureRenderResources());
267 VkDescriptorImageInfo imageInfo{};
268 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
269 imageInfo.imageView = textureResources->GetVkImageView();
270 imageInfo.sampler = textureResources->GetVkSampler();
271
272 VkWriteDescriptorSet imageDescSet;
273 imageDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
274 imageDescSet.pNext = nullptr;
275 imageDescSet.dstSet = mDescriptorSets[i];
276 imageDescSet.dstBinding = dstBinding;
277 imageDescSet.dstArrayElement = 0;
278 imageDescSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
279 imageDescSet.descriptorCount = 1;
280 imageDescSet.pImageInfo = &imageInfo;
281
282 descriptorWrites.push_back(imageDescSet);
283 }
284
285 vkUpdateDescriptorSets(mRenderer->GetLogicalDevice(), static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
286 }
287}
288
290{
291 auto device = mRenderer->GetLogicalDevice();
292 auto frame = mRenderer->GetCurrentFrame();
293
294 // Update transformations
295 void* dataTransform;
296 vkMapMemory(device, mTransformationBuffersMemory[frame], 0, sizeof(Transformations2D), 0, &dataTransform);
297 memcpy(dataTransform, &transformations, sizeof(transformations));
298 vkUnmapMemory(device, mTransformationBuffersMemory[frame]);
299}
300
302{
303 auto device = mRenderer->GetLogicalDevice();
304 auto frame = mRenderer->GetCurrentFrame();
305
306 // Flip Y-axis for Vulkan clip space
307 transformations.proj[1][1] *= -1;
308 // Update transformations
309 void* dataTransform;
310 vkMapMemory(device, mTransformationBuffersMemory[frame], 0, sizeof(Transformations3D), 0, &dataTransform);
311 memcpy(dataTransform, &transformations, sizeof(transformations));
312 vkUnmapMemory(device, mTransformationBuffersMemory[frame]);
313}
314
316{
317 auto device = mRenderer->GetLogicalDevice();
318 auto frame = mRenderer->GetCurrentFrame();
319
320 // Update custom variables
321 if (!materialParameters.buffer.empty())
322 {
323 void* dataCustom;
324 vkMapMemory(device, mMaterialParametersMemory[frame], 0, materialParameters.buffer.size(), 0, &dataCustom);
325 memcpy(dataCustom, materialParameters.buffer.data(), materialParameters.buffer.size());
326 vkUnmapMemory(device, mMaterialParametersMemory[frame]);
327 }
328}
329
331{
332 auto commandBuffers = mRenderer->GetComandBuffers();
333 auto frame = mRenderer->GetCurrentFrame();
334
335 VkBuffer vertexBuffer[] = { mVertexBuffer };
336 VkDeviceSize offsets[] = { 0 };
337
338 vkCmdBindPipeline(commandBuffers[frame], VK_PIPELINE_BIND_POINT_GRAPHICS, mGraphicsPipeline);
339
340 /*If dynamicState in pipeline is used then vkCmdSetViewport and vkCmdSetScissor per draw call*/
341 //VkViewport viewport{};
342 //viewport.x = 0.0f;
343 //viewport.y = 0.0f;
344 //viewport.width = static_cast<float>(mRenderer->GetSwapChainExtent().width);
345 //viewport.height = static_cast<float>(mRenderer->GetSwapChainExtent().height);
346 //viewport.minDepth = 0.0f;
347 //viewport.maxDepth = 1.0f;
348 //vkCmdSetViewport(commandBuffers[frame], 0, 1, &viewport);
349
350 //VkRect2D scissor{};
351 //scissor.offset = { 0, 0 };
352 //scissor.extent = mRenderer->GetSwapChainExtent();
353 //vkCmdSetScissor(commandBuffers[frame], 0, 1, &scissor);
354
355 vkCmdBindVertexBuffers(commandBuffers[frame], 0, 1, vertexBuffer, offsets);
356 vkCmdBindIndexBuffer(commandBuffers[frame], mIndexBuffer, 0, VK_INDEX_TYPE_UINT32);
357 vkCmdBindDescriptorSets(commandBuffers[frame], VK_PIPELINE_BIND_POINT_GRAPHICS,
358 mPipelineLayout, 0, 1, &mDescriptorSets[frame], 0, nullptr);
359 vkCmdDrawIndexed(commandBuffers[frame], static_cast<uint32_t>(mMeshData->GetIndices().size()), 1, 0, 0, 0);
360}
361
362
363
364} // namespace rendering_engine
Represents a material instance with parameter values, texture bindings, and rendering configuration.
Definition material.hpp:30
Manages mesh data in RAM and GPU, including upload and release operations.
Manages texture loading, GPU uploading, and caching for reuse.
Vulkan-specific implementation of material render resources.
VkPipeline GetPipeline() const
Gets the Vulkan graphics pipeline used by the material.
VkPipelineLayout GetPipelineLayout() const
Gets the Vulkan pipeline layout used by the material.
VkDescriptorSetLayout GetDescriptorSetLayout() const
Gets the Vulkan descriptor set layout for the material.
Vulkan implementation of the mesh GPU resource interface.
VkBuffer GetIndexBuffer() const
Get the Vulkan index buffer handle.
VkBuffer GetVertexBuffer() const
Get the Vulkan vertex buffer handle.
void AcquireResources()
Allocates and initializes all GPU buffers, descriptor sets, and pipelines for this drawable.
void OnRenderResourcesRebuild() override
Renderer callback: re-upload or recreate all GPU resources (used after device reset/rebuild).
void OnRenderResourcesRelease() override
Renderer callback: release all GPU resources (used during device loss/reset).
void DrawIndexed()
Issues a Vulkan draw command for the currently bound indexed mesh.
VulkanRenderResources(VulkanRenderer *renderer)
Constructor.
void Shutdown() override
Releases all allocated GPU resources for this object.
void UpdateTransformations(Transformations2D &transformations)
void Initialize(Material *material, MeshDataGpu *meshData, TextureCache *textureCache) override
Initializes GPU-side resources using provided material, mesh, and texture cache.
void SubmitResources(Transformations2D &transformations, const PackedMaterialData &materialParameters) override
Updates GPU resources and issues a draw call for a 2D object.
void UpdateMaterialParameters(const PackedMaterialData &materialParameters)
Vulkan-based implementation of the IRenderer interface.
Vulkan-specific implementation of ITextureRenderResources.
VkImageView GetVkImageView() const
Returns the Vulkan image view associated with this texture resource.
VkSampler GetVkSampler() const
Returns the Vulkan sampler associated with this texture resource.
const int MAX_FRAMES_IN_FLIGHT
Number of frames that can be processed simultaneously (double buffering).
Contains the raw buffer data and layout metadata of packed material parameters.
Contains transformation matrices for 2D rendering.
Contains model, view, and projection matrices for 3D rendering.
glm::mat4 proj
Projection transformation matrix.