Changeset a3cefaa in opengl-game


Ignore:
Timestamp:
May 17, 2021, 4:06:33 PM (3 years ago)
Author:
Dmitry Portnoy <dportnoy@…>
Branches:
feature/imgui-sdl
Children:
1abebc1
Parents:
996dd3e
Message:

Move SSBO resizing and pipeline recreation checks out of addObject() and into updateScene() so that those operations are only done at most once per pipeline per frame, using vkUpdateDescriptorSets() instead of recreating the whole graphics pipeline, and create a VulkanBuffer class for managing data related to uniform buffers and shader storage buffers, move objectCapacity and numObjects out of GraphicsPipeline_vulkan and use VulkanBuffer to manage them instead

Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • VulkanGame.vcxproj

    r996dd3e ra3cefaa  
    181181    <ClInclude Include="StackWalker.h" />
    182182    <ClInclude Include="utils.hpp" />
     183    <ClInclude Include="vulkan-buffer.hpp" />
    183184    <ClInclude Include="vulkan-game.hpp" />
    184185    <ClInclude Include="vulkan-utils.hpp" />
  • VulkanGame.vcxproj.filters

    r996dd3e ra3cefaa  
    8686      <Filter>gui\imgui</Filter>
    8787    </ClInclude>
     88    <ClInclude Include="vulkan-buffer.hpp" />
    8889  </ItemGroup>
    8990  <ItemGroup>
  • graphics-pipeline_vulkan.hpp

    r996dd3e ra3cefaa  
    3636   public:
    3737      string vertShaderFile, fragShaderFile;
    38 
    39       // Both of these are only used for managing the SSBO, so move them out as well
    40       size_t objectCapacity;
    41       size_t numObjects;
    4238
    4339      GraphicsPipeline_Vulkan();
     
    4844      GraphicsPipeline_Vulkan(VkPrimitiveTopology topology, VkPhysicalDevice physicalDevice, VkDevice device,
    4945         VkRenderPass renderPass, Viewport viewport, vector<VkImage>& swapChainImages,
    50          size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity);
     46         size_t vertexCapacity, size_t indexCapacity);
    5147      ~GraphicsPipeline_Vulkan();
    5248
     
    6460      void addDescriptorInfo(VkDescriptorType type, VkShaderStageFlags stageFlags, VkDescriptorImageInfo* imageData);
    6561
    66       void updateDescriptorInfo(uint32_t index, vector<VkDescriptorBufferInfo>* bufferData);
     62      void updateDescriptorInfo(uint32_t index, vector<VkDescriptorBufferInfo>* bufferData,
     63                                vector<VkImage>& swapChainImages);
    6764      // TODO: Maybe make an analogous one for updating image info
    6865
     
    128125// into the constructor. That way, I can also put relevant cleanup code into the destructor
    129126template<class VertexType>
    130 GraphicsPipeline_Vulkan<VertexType>::GraphicsPipeline_Vulkan(
    131       VkPrimitiveTopology topology, VkPhysicalDevice physicalDevice, VkDevice device,
    132       VkRenderPass renderPass, Viewport viewport, vector<VkImage>& swapChainImages,
    133       size_t vertexCapacity, size_t indexCapacity, size_t objectCapacity) {
    134    this->topology = topology;
    135    this->physicalDevice = physicalDevice;
    136    this->device = device;
    137    this->renderPass = renderPass;
     127GraphicsPipeline_Vulkan<VertexType>::GraphicsPipeline_Vulkan(VkPrimitiveTopology topology,
     128                                                             VkPhysicalDevice physicalDevice, VkDevice device,
     129                                                             VkRenderPass renderPass, Viewport viewport,
     130                                                             vector<VkImage>& swapChainImages, size_t vertexCapacity,
     131                                                             size_t indexCapacity)
     132                                                            : topology(topology)
     133                                                            , physicalDevice(physicalDevice)
     134                                                            , device(device)
     135                                                            , renderPass(renderPass) {
     136   // This is a member of the base GraphicsPipeline class
     137   // It currently is not used for the OpenGL pipeline. Either figure out why (since OpenGL certainly has the concept of
     138   // viewports) and use it there too and add viewport the the base class constructor, or create a second base class
     139   // constructor which takes the viewport
    138140   this->viewport = viewport;
    139141
     
    158160      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
    159161      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
    160 
    161    this->numObjects = 0;
    162    this->objectCapacity = objectCapacity;
    163162}
    164163
     
    204203template<class VertexType>
    205204void GraphicsPipeline_Vulkan<VertexType>::updateDescriptorInfo(uint32_t index,
    206                                                                          vector<VkDescriptorBufferInfo>* bufferData) {
     205                                                               vector<VkDescriptorBufferInfo>* bufferData,
     206                                                               vector<VkImage>& swapChainImages) {
    207207   this->descriptorInfoList[index].bufferDataList = bufferData;
     208
     209   // TODO: This code was mostly copied from createDescriptorSets. I should make some common function they both use
     210   // for updating descriptor sets
     211   for (size_t i = 0; i < swapChainImages.size(); i++) {
     212      VkWriteDescriptorSet descriptorWrite = {};
     213
     214      descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     215      descriptorWrite.dstSet = this->descriptorSets[i];
     216      descriptorWrite.dstBinding = index;
     217      descriptorWrite.dstArrayElement = 0;
     218      descriptorWrite.descriptorType = this->descriptorInfoList[index].type;
     219      descriptorWrite.descriptorCount = 1;
     220      descriptorWrite.pBufferInfo = nullptr;
     221      descriptorWrite.pImageInfo = nullptr;
     222      descriptorWrite.pTexelBufferView = nullptr;
     223
     224      // This method is only intended for updated descriptor sets of type VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
     225      // but I'm leaving that in here for completeness
     226      switch (descriptorWrite.descriptorType) {
     227         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
     228         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
     229         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
     230            descriptorWrite.pBufferInfo = &(*this->descriptorInfoList[index].bufferDataList)[i];
     231            break;
     232         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
     233            descriptorWrite.pImageInfo = this->descriptorInfoList[index].imageData;
     234            break;
     235         default:
     236            throw runtime_error("Unknown descriptor type: " + to_string(descriptorWrite.descriptorType));
     237      }
     238
     239      if (bufferData->size() != swapChainImages.size()) {
     240         cout << "ALERT ALERT ALERT: SIZE MISMATCH!!!!!!!" << endl;
     241      }
     242
     243      vkUpdateDescriptorSets(this->device, 1, &descriptorWrite, 0, nullptr);
     244   }
    208245}
    209246
  • sdl-game.cpp

    r996dd3e ra3cefaa  
    7070                     , gui(nullptr)
    7171                     , window(nullptr)
     72                     , objects_modelPipeline()
    7273                     , score(0)
    7374                     , fps(0.0f) {
     
    8788
    8889   initVulkan();
     90
     91   VkPhysicalDeviceProperties deviceProperties;
     92   vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
     93
     94   objects_modelPipeline = VulkanBuffer<SSBO_ModelObject>(10, deviceProperties.limits.minUniformBufferOffsetAlignment);
    8995
    9096   initImGuiOverlay();
     
    131137      }, {
    132138         mat4(1.0f)
    133       }, storageBuffers_modelPipeline, false);
    134 
    135    updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare->ssbo);
     139      }, storageBuffers_modelPipeline);
     140
     141   objects_modelPipeline.numObjects++;
    136142
    137143   texturedSquare->model_base =
     
    152158      }, {
    153159         mat4(1.0f)
    154       }, storageBuffers_modelPipeline, false);
    155 
    156    updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare->ssbo);
     160      }, storageBuffers_modelPipeline);
     161
     162   objects_modelPipeline.numObjects++;
    157163
    158164   texturedSquare->model_base =
     
    263269   modelPipeline = GraphicsPipeline_Vulkan<ModelVertex>(
    264270      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
    265       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 16, 24, 10);
    266 
    267    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_ModelObject),
     271      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 16, 24);
     272
     273   createBufferSet(objects_modelPipeline.capacity * sizeof(SSBO_ModelObject),
    268274      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    269275      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    376382                        }, {
    377383                           mat4(1.0f)
    378                         }, storageBuffers_modelPipeline, true);
    379 
    380                   updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare.ssbo);
     384                        }, storageBuffers_modelPipeline);
     385
     386                  objects_modelPipeline.numObjects++;
    381387
    382388                  texturedSquare.model_base =
     
    446452
    447453void VulkanGame::updateScene() {
    448    // TODO: These two for loops could probably be combined into one
    449 
     454   // Rotate the textured squares
    450455   for (SceneObject<ModelVertex, SSBO_ModelObject>& model : this->modelObjects) {
    451456      model.model_transform =
     
    455460   }
    456461
    457    // TODO: Instead, update entire sections (up to 64k) of the dynamic ubo if some objects there have changed
    458    // Also, update the objects modelMat and center in the loop above instead of here
     462   // TODO: Probably move the resizing to the VulkanBuffer class
     463   if (objects_modelPipeline.numObjects > objects_modelPipeline.capacity) {
     464      resizeStorageBufferSet(storageBuffers_modelPipeline, objects_modelPipeline, modelPipeline, resourceCommandPool,
     465                             graphicsQueue);
     466   }
     467
    459468   for (size_t i = 0; i < modelObjects.size(); i++) {
    460469      if (modelObjects[i].modified) {
    461          // TODO: Think about changing the SSBO-related code to also use a contiguous array
    462          // to store the data on the cpu side instead of storing it per-object
    463          // Then, I could also copy it to the GPU in one go
    464          // Also, double-check if the alignment restrictions also hold for SSBOs
    465 
    466470         updateObject(modelObjects, modelPipeline, i);
    467471         updateStorageBuffer(storageBuffers_modelPipeline, i, modelObjects[i].ssbo);
     
    845849   return VulkanUtils::findSupportedFormat(
    846850      physicalDevice,
    847       { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
     851      { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT },
    848852      VK_IMAGE_TILING_OPTIMAL,
    849853      VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
  • sdl-game.hpp

    r996dd3e ra3cefaa  
    2121#include "consts.hpp"
    2222#include "vulkan-utils.hpp"
     23#include "vulkan-buffer.hpp"
    2324#include "graphics-pipeline_vulkan.hpp"
    2425#include "game-gui-sdl.hpp"
     
    7778// Also, probably better to make this a vector of structs where each struct
    7879// has a VkBuffer, VkDeviceMemory, and VkDescriptorBufferInfo
     80// TODO: Maybe change the structure here since VkDescriptorBufferInfo already stores a reference to the VkBuffer
    7981struct StorageBufferSet {
    8082   vector<VkBuffer> buffers;
     
    219221
    220222      StorageBufferSet storageBuffers_modelPipeline;
     223      VulkanBuffer<SSBO_ModelObject> objects_modelPipeline;
    221224
    222225      // TODO: Maybe make the ubo objects part of the pipeline class since there's only one ubo
     
    296299      // TODO: Remove the need for templating, which is only there so a GraphicsPupeline_Vulkan can be passed in
    297300      template<class VertexType, class SSBOType>
    298       void resizeStorageBufferSet(StorageBufferSet& set, VkCommandPool commandPool, VkQueue graphicsQueue,
    299                                   GraphicsPipeline_Vulkan<VertexType>& pipeline);
     301      void resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
     302                                  GraphicsPipeline_Vulkan<VertexType>& pipeline,
     303                                  VkCommandPool commandPool, VkQueue graphicsQueue);
    300304
    301305      template<class SSBOType>
     
    308312                                                   GraphicsPipeline_Vulkan<VertexType>& pipeline,
    309313                                                   const vector<VertexType>& vertices, vector<uint16_t> indices,
    310                                                    SSBOType ssbo, StorageBufferSet& storageBuffers,
    311                                                    bool pipelinesCreated);
     314                                                   SSBOType ssbo, StorageBufferSet& storageBuffers);
    312315
    313316      template<class VertexType>
     
    344347
    345348template<class VertexType, class SSBOType>
    346 void VulkanGame::resizeStorageBufferSet(StorageBufferSet& set, VkCommandPool commandPool, VkQueue graphicsQueue,
    347                                         GraphicsPipeline_Vulkan<VertexType>& pipeline) {
    348    pipeline.objectCapacity *= 2;
    349    VkDeviceSize bufferSize = pipeline.objectCapacity * sizeof(SSBOType);
     349void VulkanGame::resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
     350                                        GraphicsPipeline_Vulkan<VertexType>& pipeline,
     351                                        VkCommandPool commandPool, VkQueue graphicsQueue) {
     352   size_t numObjects = buffer.numObjects < buffer.capacity ? buffer.numObjects : buffer.capacity;
     353
     354   do {
     355      buffer.capacity *= 2;
     356   } while (buffer.capacity < buffer.numObjects);
     357
     358   VkDeviceSize bufferSize = buffer.capacity * sizeof(SSBOType);
    350359
    351360   for (size_t i = 0; i < set.buffers.size(); i++) {
     
    359368
    360369      VulkanUtils::copyBuffer(device, commandPool, set.buffers[i], newStorageBuffer,
    361          0, 0, pipeline.numObjects * sizeof(SSBOType), graphicsQueue);
     370         0, 0, numObjects * sizeof(SSBOType), graphicsQueue);
    362371
    363372      vkDestroyBuffer(device, set.buffers[i], nullptr);
     
    371380      set.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
    372381   }
     382
     383   // Assume the SSBO is always the 2nd binding
     384   // TODO: Figure out a way to make this more flexible
     385   pipeline.updateDescriptorInfo(1, &set.infoSet, swapChainImages);
    373386}
    374387
     
    384397// and to change the model matrix later by setting model_transform and then calling updateObject()
    385398// Figure out a better way to allow the model matrix to be set during object creation
    386 
    387 // TODO: Maybe return a reference to the object from this method if I decide that updating it
    388 // immediately after creation is a good idea (such as setting model_base)
    389 // Currently, model_base is set like this in a few places and the radius is set for asteroids
    390 // to account for scaling
    391399template<class VertexType, class SSBOType>
    392400SceneObject<VertexType, SSBOType>& VulkanGame::addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
    393401                                                         GraphicsPipeline_Vulkan<VertexType>& pipeline,
    394402                                                         const vector<VertexType>& vertices, vector<uint16_t> indices,
    395                                                          SSBOType ssbo, StorageBufferSet& storageBuffers,
    396                                                          bool pipelinesCreated) {
     403                                                         SSBOType ssbo, StorageBufferSet& storageBuffers) {
    397404   // TODO: Use the model field of ssbo to set the object's model_base
    398405   // currently, the passed in model is useless since it gets overridden in updateObject() anyway
     
    415422
    416423   pipeline.addObject(obj.vertices, obj.indices, resourceCommandPool, graphicsQueue);
    417 
    418    // TODO: Probably move the resizing to the VulkanBuffer class
    419    // First, try moving this out of addObject
    420    bool resizeStorageBuffer = pipeline.numObjects == pipeline.objectCapacity;
    421 
    422    if (resizeStorageBuffer) {
    423       resizeStorageBufferSet<VertexType, SSBOType>(storageBuffers, resourceCommandPool, graphicsQueue, pipeline);
    424       pipeline.cleanup();
    425 
    426       // Assume the SSBO is always the 2nd binding
    427       // TODO: Figure out a way to make this more flexible
    428       pipeline.updateDescriptorInfo(1, &storageBuffers.infoSet);
    429    }
    430 
    431    pipeline.numObjects++;
    432 
    433    // TODO: Figure out why I am destroying and recreating the ubos when the swap chain is recreated,
    434    // but am reusing the same ssbos. Maybe I don't need to recreate the ubos.
    435 
    436    if (pipelinesCreated) {
    437       // TODO: See if I can avoid doing this when recreating the pipeline
    438       vkDeviceWaitIdle(device);
    439 
    440       for (uint32_t i = 0; i < swapChainImageCount; i++) {
    441          vkFreeCommandBuffers(device, commandPools[i], 1, &commandBuffers[i]);
    442       }
    443 
    444       // TODO: The pipeline recreation only has to be done once per frame where at least
    445       // one SSBO is resized.
    446       // Refactor the logic to check for any resized SSBOs after all objects for the frame
    447       // are created and then recreate each of the corresponding pipelines only once per frame
    448 
    449       // TODO: Also, verify if I actually need to recreate all of these, or maybe just the descriptor sets, for instance
    450 
    451       if (resizeStorageBuffer) {
    452          pipeline.createPipeline(pipeline.vertShaderFile, pipeline.fragShaderFile);
    453          pipeline.createDescriptorPool(swapChainImages);
    454          pipeline.createDescriptorSets(swapChainImages);
    455       }
    456 
    457       createCommandBuffers();
    458    }
    459424
    460425   return obj;
  • vulkan-game.cpp

    r996dd3e ra3cefaa  
    7777                     , gui(nullptr)
    7878                     , window(nullptr)
     79                     , objects_modelPipeline()
     80                     , objects_shipPipeline()
     81                     , objects_asteroidPipeline()
     82                     , objects_laserPipeline()
     83                     , objects_explosionPipeline()
    7984                     , score(0)
    8085                     , fps(0.0f) {
     
    102107   initVulkan();
    103108
     109   VkPhysicalDeviceProperties deviceProperties;
     110   vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
     111
     112   objects_modelPipeline = VulkanBuffer<SSBO_ModelObject>(10, deviceProperties.limits.minUniformBufferOffsetAlignment);
     113   objects_shipPipeline = VulkanBuffer<SSBO_ModelObject>(10, deviceProperties.limits.minUniformBufferOffsetAlignment);
     114   objects_asteroidPipeline = VulkanBuffer<SSBO_Asteroid>(10, deviceProperties.limits.minUniformBufferOffsetAlignment);
     115   objects_laserPipeline = VulkanBuffer<SSBO_Laser>(2, deviceProperties.limits.minUniformBufferOffsetAlignment);
     116   objects_explosionPipeline = VulkanBuffer<SSBO_Explosion>(2, deviceProperties.limits.minUniformBufferOffsetAlignment);
     117
    104118   initImGuiOverlay();
    105119
     
    131145
    132146   SceneObject<ModelVertex, SSBO_ModelObject>* texturedSquare = nullptr;
     147
     148   // TODO: Ideally, avoid having to make the squares as modified upon creation
    133149
    134150   texturedSquare = &addObject(modelObjects, modelPipeline,
     
    145161         }, {
    146162            mat4(1.0f)
    147          }, storageBuffers_modelPipeline, false);
    148 
    149    updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare->ssbo);
     163         }, storageBuffers_modelPipeline);
     164
     165   objects_modelPipeline.numObjects++;
    150166
    151167   texturedSquare->model_base =
     
    166182         }, {
    167183            mat4(1.0f)
    168          }, storageBuffers_modelPipeline, false);
    169 
    170    updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare->ssbo);
     184         }, storageBuffers_modelPipeline);
     185
     186   objects_modelPipeline.numObjects++;
    171187
    172188   texturedSquare->model_base =
     
    428444      }, {
    429445         mat4(1.0f)
    430       }, storageBuffers_shipPipeline, false);
    431 
    432    updateStorageBuffer(storageBuffers_shipPipeline, shipPipeline.numObjects - 1, ship.ssbo);
     446      }, storageBuffers_shipPipeline);
     447
     448   objects_shipPipeline.numObjects++;
    433449
    434450   ship.model_base =
     
    600616   modelPipeline = GraphicsPipeline_Vulkan<ModelVertex>(
    601617      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
    602       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 24, 24, 10);
    603 
    604    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_ModelObject),
     618      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 24, 24);
     619
     620   createBufferSet(objects_modelPipeline.capacity * sizeof(SSBO_ModelObject),
    605621      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    606622      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    610626   shipPipeline = GraphicsPipeline_Vulkan<ModelVertex>(
    611627      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
    612       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 138, 138, 10);
    613 
    614    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_ModelObject),
     628      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 138, 138);
     629
     630   createBufferSet(objects_shipPipeline.capacity * sizeof(SSBO_ModelObject),
    615631      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    616632      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    620636   asteroidPipeline = GraphicsPipeline_Vulkan<ModelVertex>(
    621637      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
    622       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 24, 36, 10);
    623 
    624    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_Asteroid),
     638      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 24, 36);
     639
     640   createBufferSet(objects_asteroidPipeline.capacity * sizeof(SSBO_Asteroid),
    625641      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    626642      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    630646   laserPipeline = GraphicsPipeline_Vulkan<LaserVertex>(
    631647      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
    632       { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 8, 18, 2);
    633 
    634    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_Laser),
     648      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 8, 18);
     649
     650   createBufferSet(objects_laserPipeline.capacity * sizeof(SSBO_Laser),
    635651      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    636652      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    641657      VK_PRIMITIVE_TOPOLOGY_POINT_LIST, physicalDevice, device, renderPass,
    642658      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height },
    643       swapChainImages, EXPLOSION_PARTICLE_COUNT, EXPLOSION_PARTICLE_COUNT, 2);
    644 
    645    createBufferSet(modelPipeline.objectCapacity * sizeof(SSBO_Explosion),
     659      swapChainImages, EXPLOSION_PARTICLE_COUNT, EXPLOSION_PARTICLE_COUNT);
     660
     661   createBufferSet(objects_explosionPipeline.capacity * sizeof(SSBO_Explosion),
    646662      VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    647663      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     
    768784                           }, {
    769785                              mat4(1.0f)
    770                            }, storageBuffers_modelPipeline, true);
    771 
    772                   updateStorageBuffer(storageBuffers_modelPipeline, modelPipeline.numObjects - 1, texturedSquare.ssbo);
     786                           }, storageBuffers_modelPipeline);
     787
     788                  objects_modelPipeline.numObjects++;
    773789
    774790                  texturedSquare.model_base =
     
    929945// where it will run just once per frame
    930946void VulkanGame::updateScene() {
     947   // Rotate the textured squares
    931948   for (SceneObject<ModelVertex, SSBO_ModelObject>& model : this->modelObjects) {
    932949      model.model_transform =
     
    10501067                  10.0f,
    10511068                  false
    1052                }, storageBuffers_asteroidPipeline, true);
    1053 
    1054       updateStorageBuffer(storageBuffers_asteroidPipeline, asteroidPipeline.numObjects - 1, asteroid.ssbo);
     1069               }, storageBuffers_asteroidPipeline);
     1070
     1071      objects_asteroidPipeline.numObjects++;
    10551072
    10561073      // This accounts for the scaling in model_base.
     
    10771094   }
    10781095
     1096   // TODO: Probably move the resizing to the VulkanBuffer class
     1097   if (objects_modelPipeline.numObjects > objects_modelPipeline.capacity) {
     1098      resizeStorageBufferSet(storageBuffers_modelPipeline, objects_modelPipeline, modelPipeline, resourceCommandPool,
     1099                             graphicsQueue);
     1100   }
     1101
     1102   for (size_t i = 0; i < modelObjects.size(); i++) {
     1103      if (modelObjects[i].modified) {
     1104         updateObject(modelObjects, modelPipeline, i);
     1105         updateStorageBuffer(storageBuffers_modelPipeline, i, modelObjects[i].ssbo);
     1106      }
     1107   }
     1108
     1109   // TODO: Probably move the resizing to the VulkanBuffer class
     1110   if (objects_shipPipeline.numObjects > objects_shipPipeline.capacity) {
     1111      resizeStorageBufferSet(storageBuffers_shipPipeline, objects_shipPipeline, shipPipeline, resourceCommandPool,
     1112                             graphicsQueue);
     1113   }
     1114
    10791115   for (size_t i = 0; i < shipObjects.size(); i++) {
    10801116      if (shipObjects[i].modified) {
     
    10841120   }
    10851121
    1086    for (size_t i = 0; i < modelObjects.size(); i++) {
    1087       if (modelObjects[i].modified) {
    1088          updateObject(modelObjects, modelPipeline, i);
    1089          updateStorageBuffer(storageBuffers_modelPipeline, i, modelObjects[i].ssbo);
    1090       }
     1122   // TODO: Probably move the resizing to the VulkanBuffer class
     1123   if (objects_asteroidPipeline.numObjects > objects_asteroidPipeline.capacity) {
     1124      resizeStorageBufferSet(storageBuffers_asteroidPipeline, objects_asteroidPipeline, asteroidPipeline,
     1125                             resourceCommandPool, graphicsQueue);
    10911126   }
    10921127
     
    10981133   }
    10991134
     1135   // TODO: Probably move the resizing to the VulkanBuffer class
     1136   if (objects_laserPipeline.numObjects > objects_laserPipeline.capacity) {
     1137      resizeStorageBufferSet(storageBuffers_laserPipeline, objects_laserPipeline, laserPipeline, resourceCommandPool,
     1138                             graphicsQueue);
     1139   }
     1140
    11001141   for (size_t i = 0; i < laserObjects.size(); i++) {
    11011142      if (laserObjects[i].modified) {
     
    11031144         updateStorageBuffer(storageBuffers_laserPipeline, i, laserObjects[i].ssbo);
    11041145      }
     1146   }
     1147
     1148   // TODO: Probably move the resizing to the VulkanBuffer class
     1149   if (objects_explosionPipeline.numObjects > objects_explosionPipeline.capacity) {
     1150      resizeStorageBufferSet(storageBuffers_explosionPipeline, objects_explosionPipeline, explosionPipeline,
     1151                             resourceCommandPool, graphicsQueue);
    11051152   }
    11061153
     
    15251572   return VulkanUtils::findSupportedFormat(
    15261573      physicalDevice,
    1527       { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
     1574      { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT },
    15281575      VK_IMAGE_TILING_OPTIMAL,
    15291576      VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
     
    19291976         color,
    19301977         false
    1931       }, storageBuffers_laserPipeline, true);
    1932 
    1933    updateStorageBuffer(storageBuffers_laserPipeline, laserPipeline.numObjects - 1, laser.ssbo);
     1978      }, storageBuffers_laserPipeline);
     1979
     1980   objects_laserPipeline.numObjects++;
    19341981
    19351982   float xAxisRotation = asin(ray.y / length);
     
    21412188         duration,
    21422189         false
    2143       }, storageBuffers_explosionPipeline, true);
    2144 
    2145    updateStorageBuffer(storageBuffers_explosionPipeline, explosionPipeline.numObjects - 1, explosion.ssbo);
     2190      }, storageBuffers_explosionPipeline);
     2191
     2192   objects_explosionPipeline.numObjects++;
    21462193
    21472194   explosion.model_base = model_mat;
  • vulkan-game.hpp

    r996dd3e ra3cefaa  
    2222
    2323#include "consts.hpp"
     24#include "utils.hpp"
     25#include "vulkan-utils.hpp"
     26#include "vulkan-buffer.hpp"
    2427#include "graphics-pipeline_vulkan.hpp"
    2528#include "game-gui-sdl.hpp"
    26 #include "utils.hpp"
    27 #include "vulkan-utils.hpp"
    2829
    2930using namespace glm;
     
    101102// Also, probably better to make this a vector of structs where each struct
    102103// has a VkBuffer, VkDeviceMemory, and VkDescriptorBufferInfo
     104// TODO: Maybe change the structure here since VkDescriptorBufferInfo already stores a reference to the VkBuffer
    103105struct StorageBufferSet {
    104106   vector<VkBuffer> buffers;
     
    316318
    317319      StorageBufferSet storageBuffers_modelPipeline;
     320      VulkanBuffer<SSBO_ModelObject> objects_modelPipeline;
     321
    318322      StorageBufferSet storageBuffers_shipPipeline;
     323      VulkanBuffer<SSBO_ModelObject> objects_shipPipeline;
     324
    319325      StorageBufferSet storageBuffers_asteroidPipeline;
     326      VulkanBuffer<SSBO_Asteroid> objects_asteroidPipeline;
     327
    320328      StorageBufferSet storageBuffers_laserPipeline;
     329      VulkanBuffer<SSBO_Laser> objects_laserPipeline;
     330
    321331      StorageBufferSet storageBuffers_explosionPipeline;
     332      VulkanBuffer<SSBO_Explosion> objects_explosionPipeline;
    322333
    323334      // TODO: Maybe make the ubo objects part of the pipeline class since there's only one ubo
     
    443454      // TODO: Remove the need for templating, which is only there so a GraphicsPupeline_Vulkan can be passed in
    444455      template<class VertexType, class SSBOType>
    445       void resizeStorageBufferSet(StorageBufferSet& set, VkCommandPool commandPool, VkQueue graphicsQueue,
    446                                   GraphicsPipeline_Vulkan<VertexType>& pipeline);
     456      void resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
     457                                  GraphicsPipeline_Vulkan<VertexType>& pipeline,
     458                                  VkCommandPool commandPool, VkQueue graphicsQueue);
    447459
    448460      template<class SSBOType>
     
    455467                                                   GraphicsPipeline_Vulkan<VertexType>& pipeline,
    456468                                                   const vector<VertexType>& vertices, vector<uint16_t> indices,
    457                                                    SSBOType ssbo, StorageBufferSet& storageBuffers,
    458                                                    bool pipelinesCreated);
     469                                                   SSBOType ssbo, StorageBufferSet& storageBuffers);
    459470
    460471      template<class VertexType>
     
    511522
    512523template<class VertexType, class SSBOType>
    513 void VulkanGame::resizeStorageBufferSet(StorageBufferSet& set, VkCommandPool commandPool, VkQueue graphicsQueue,
    514                                         GraphicsPipeline_Vulkan<VertexType>& pipeline) {
    515    pipeline.objectCapacity *= 2;
    516    VkDeviceSize bufferSize = pipeline.objectCapacity * sizeof(SSBOType);
     524void VulkanGame::resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
     525                                        GraphicsPipeline_Vulkan<VertexType>& pipeline,
     526                                        VkCommandPool commandPool, VkQueue graphicsQueue) {
     527   size_t numObjects = buffer.numObjects < buffer.capacity ? buffer.numObjects : buffer.capacity;
     528
     529   do {
     530      buffer.capacity *= 2;
     531   } while (buffer.capacity < buffer.numObjects);
     532
     533   VkDeviceSize bufferSize = buffer.capacity * sizeof(SSBOType);
    517534
    518535   for (size_t i = 0; i < set.buffers.size(); i++) {
     
    526543
    527544      VulkanUtils::copyBuffer(device, commandPool, set.buffers[i], newStorageBuffer,
    528          0, 0, pipeline.numObjects * sizeof(SSBOType), graphicsQueue);
     545         0, 0, numObjects * sizeof(SSBOType), graphicsQueue);
    529546
    530547      vkDestroyBuffer(device, set.buffers[i], nullptr);
     
    538555      set.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
    539556   }
     557
     558   // Assume the SSBO is always the 2nd binding
     559   // TODO: Figure out a way to make this more flexible
     560   pipeline.updateDescriptorInfo(1, &set.infoSet, swapChainImages);
    540561}
    541562
     
    551572// and to change the model matrix later by setting model_transform and then calling updateObject()
    552573// Figure out a better way to allow the model matrix to be set during object creation
    553 
    554 // TODO: Maybe return a reference to the object from this method if I decide that updating it
    555 // immediately after creation is a good idea (such as setting model_base)
    556 // Currently, model_base is set like this in a few places and the radius is set for asteroids
    557 // to account for scaling
    558574template<class VertexType, class SSBOType>
    559575SceneObject<VertexType, SSBOType>& VulkanGame::addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
    560576                                                         GraphicsPipeline_Vulkan<VertexType>& pipeline,
    561577                                                         const vector<VertexType>& vertices, vector<uint16_t> indices,
    562                                                          SSBOType ssbo, StorageBufferSet& storageBuffers,
    563                                                          bool pipelinesCreated) {
     578                                                         SSBOType ssbo, StorageBufferSet& storageBuffers) {
    564579   // TODO: Use the model field of ssbo to set the object's model_base
    565580   // currently, the passed in model is useless since it gets overridden in updateObject() anyway
     
    582597
    583598   pipeline.addObject(obj.vertices, obj.indices, resourceCommandPool, graphicsQueue);
    584 
    585    // TODO: Probably move the resizing to the VulkanBuffer class
    586    // First, try moving this out of addObject
    587    bool resizeStorageBuffer = pipeline.numObjects == pipeline.objectCapacity;
    588 
    589    if (resizeStorageBuffer) {
    590       resizeStorageBufferSet<VertexType, SSBOType>(storageBuffers, resourceCommandPool, graphicsQueue, pipeline);
    591       pipeline.cleanup();
    592 
    593       // Assume the SSBO is always the 2nd binding
    594       // TODO: Figure out a way to make this more flexible
    595       pipeline.updateDescriptorInfo(1, &storageBuffers.infoSet);
    596    }
    597 
    598    pipeline.numObjects++;
    599 
    600    // TODO: Figure out why I am destroying and recreating the ubos when the swap chain is recreated,
    601    // but am reusing the same ssbos. Maybe I don't need to recreate the ubos.
    602 
    603    if (pipelinesCreated) {
    604       // TODO: See if I can avoid doing this when recreating the pipeline
    605       vkDeviceWaitIdle(device);
    606 
    607       for (uint32_t i = 0; i < swapChainImageCount; i++) {
    608          vkFreeCommandBuffers(device, commandPools[i], 1, &commandBuffers[i]);
    609       }
    610 
    611       // TODO: The pipeline recreation only has to be done once per frame where at least
    612       // one SSBO is resized.
    613       // Refactor the logic to check for any resized SSBOs after all objects for the frame
    614       // are created and then recreate each of the corresponding pipelines only once per frame
    615 
    616       // TODO: Also, verify if I actually need to recreate all of these, or maybe just the descriptor sets, for instance
    617 
    618       if (resizeStorageBuffer) {
    619          pipeline.createPipeline(pipeline.vertShaderFile, pipeline.fragShaderFile);
    620          pipeline.createDescriptorPool(swapChainImages);
    621          pipeline.createDescriptorSets(swapChainImages);
    622       }
    623 
    624       createCommandBuffers();
    625    }
    626599
    627600   return obj;
Note: See TracChangeset for help on using the changeset viewer.