-1

I have a Vulkan project, that uses a model manager based on the one written by my professor. In this model manager, I have the Model.h #includeing both a Mesh.h, an #include to vulkan/vulkan.h, and an #include to Texture.h. Externally, they all have references to a static, global instance of my wrapper for the rendering portion of my engine. During my google searches, I've come to the initial conclusion that I have a circular dependency. I was hoping someone could point it out for me.

Model.h

#pragma once

#include <vector>
#include <vulkan/vulkan.h>

#include "Texture.h"
#include "Mesh.h"

struct Model
{
    uint8_t                             _inuse;
    uint32_t                            _refcount;
    TextLine                            filename;
    Mesh                                *mesh; //C4430 & C2143
    Texture                             *texture; //C4430 & C2143
    VkDescriptorPool                    descriptorPool;
    std::vector<VkDescriptorSet>        descriptorSets;
    uint32_t                            descriptorSetCount;

void DrawModel(Model *model, uint32_t bufferFrame, VkCommandBuffer 
     commandBuffer);
};

class Model_Manager
{
private:
    std::vector<Model>      model_list;
    uint32_t                modelMax;

public:

    uint32_t                swapchainLength;
    VkDevice                logDevice;
    VkPhysicalDevice        physDevice;
    VkDescriptorSetLayout   descriptorSetLayout;

    void Model_ManagerInit(uint32_t maxModels, uint32_t chainLength, 
         VkDevice device, VkPhysicalDevice physicalDevice);

    Model* NewModel();
    Model* GetModelByFilename(char *filename);
    Model LoadModel(char * filename);
    void DeleteModel(Model *model);

    VkDescriptorSetLayout* GetModelDescriptorSetLayout(){ return 
&descriptorSetLayout; }

    static void CreateDescriptorPool(Model *model, VkDevice device);
    static void CreateDescriptorSets(Model *model);
    static void CreateDescriptorSetLayout(Model *model, VkDevice device);
    static void ModelSetup(Model *model, VkDevice lDevice);
};

extern Model_Manager modelManager;

Texture.h

#pragma once

#include <vector>

#include "gf3d_text.h"
#include "Vulkan_Graphics.h"

struct Texture
{
    uint8_t             _inuse;
    uint32_t            _refcount;
    TextLine            filename;
    VkImage             textureImage;
    VkDeviceMemory      textureImageMemory;
    VkImageView         textureImageView;
    VkSampler           textureSampler;
    };


class Texture_Manager
{ 
private:
    uint32_t                textureMax;
    VkDevice                logDevice;

public:
    std::vector<Texture>    textureList;

    void Texture_ManagerInit(uint32_t maxTextures, VkDevice lDevice);

    static Texture* LoadTexture(char *filename);
    static Texture* GetTextureByFilename(char * filename);
    static void CopyBufferToImage(VkBuffer buffer, VkImage image, uint32_t 
width, uint32_t height);
    static Texture* NewTexture();
    static void CreateTextureSampler(Texture *tex, VkDevice device);
    static void DeleteTexture(Texture *tex, VkDevice device);
};

extern Texture_Manager textureManager;

Mesh.h

#pragma once

#include "gf3d_text.h"
#include "Vulkan_Graphics.h"

struct Vertex
{
    glm::vec3 vertex;
    glm::vec3 normal;
    glm::vec2 texel;
};

struct Face
{
    uint32_t  verts[3];
};

struct Mesh
{
    TextLine        filename;
    uint32_t        _refCount;
    uint8_t         _inuse;
    uint32_t        vertexCount;
    VkBuffer        buffer;
    VkDeviceMemory  bufferMemory;
    uint32_t        faceCount;
    VkBuffer        faceBuffer;
    VkDeviceMemory  faceBufferMemory;

    void MeshRender(Mesh *mesh, VkCommandBuffer commandBuffer, VkDescriptorSet 
*descSet);
};

class Mesh_Wrapper
{
   private:
     std::vector<Mesh>                  mesh_list;
     uint32_t                           maxMeshes;
     VkVertexInputAttributeDescription  attributeDescriptions[3];
     VkVertexInputBindingDescription        bindingDescription;
     std::vector<Command>               stagingCommandBuffer;
     VkDevice                           logDevice;
     VkPhysicalDevice                   physDevice;

public:
     Mesh_Wrapper();
     ~Mesh_Wrapper();

     void Mesh_WrapperInit(uint32_t meshCount, VkDevice logDevice, 
VkPhysicalDevice physDevice);

    Mesh* NewMesh();
    void DeleteMesh(Mesh* mesh);

    Mesh* LoadMesh(char *filename);
    Mesh* GetMeshByFilename(char *filename);


    VkVertexInputAttributeDescription* GetAttributeDescriptions(uint32_t 
  *count);
    VkVertexInputBindingDescription* GetBindDescription();

    static Mesh* LoadMesh(char * filename, Mesh_Wrapper *mWrapper);
    static void CreateVertexBufferFromVertices(Mesh *mesh, Vertex *vertices, 
uint32_t vcount, Face *faces, uint32_t fcount);
    static void SetupFaceBuffers(Mesh *mesh, Face *faces, uint32_t fcount);
};

extern Mesh_Wrapper meshManager;

Vulkan_Graphics.h

#pragma once

#include <vulkan/vulkan.h>
#include <iostream>
#include <glm/glm.hpp>

#include "Pipeline_Wrapper.h"
#include "GLFW_Wrapper.h"
#include "Extensions_Manager.h"
#include "Swapchain_Wrapper.h"
#include "Queue_Wrapper.h"
#include "Commands_Wrapper.h"
#include "Mesh.h"
#include "Texture.h"
#include "Model.h"

typedef struct
{
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
}UniformBufferObject;

class Vulkan_Graphics
{
private:
    VkInstance                      vkInstance;

    Command                         *graphicsCommandPool;

    VkDebugUtilsMessengerEXT        callback;
    VkSurfaceKHR                    surface;

    uint32_t                        deviceCount;
    VkPhysicalDevice                *devices;
    bool                            logicalDeviceCreated;

    VkQueue                         graphicsQueue;
    VkQueue                         presentQueue;
    VkQueue                         transferQueue;

    VkDeviceQueueCreateInfo         *queueCreateInfo;
    VkPhysicalDeviceFeatures        deviceFeatures;

    VkSemaphore                     imageAvailableSemaphore;
    VkSemaphore                     renderFinishedSemaphore;

    std::vector<VkLayerProperties>  validationAvailableLayers;
    std::vector<const char*>        validationInstanceLayerNames;
    std::vector<const char*>        validationDeviceLayerNames;

    std::vector<VkBuffer>           uniformBuffers;
    std::vector<VkDeviceMemory>     uniformBuffersMemory;
    uint32_t                        uniformBufferCount;

   void CreateVulkanInstance();
    void CreateLogicalDevice();

    void CreateSemaphores();

    void CreateUniformBuffer();

    void SetupDebugCallback();

    bool CheckValidationLayerSupport();

    void PickPhysicalDevice();

    VkDeviceCreateInfo GetDeviceInfo(bool validation);

    VkPhysicalDevice GetPhysicalDevice(){ return physicalDevice; }

    bool IsDeviceSuitable(VkPhysicalDevice device);

public:
   GLFW_Wrapper                 *glfwWrapper;
    Commands_Wrapper                *cmdWrapper;
    Extensions_Manager              *extManager;
    Queue_Wrapper                   *queueWrapper;
    Swapchain_Wrapper               *swapchainWrapper;
    Pipeline_Wrapper                *pipeWrapper;

    UniformBufferObject             ubo;

    Pipeline                        *currentPipe;

    VkPhysicalDevice                physicalDevice;
    VkDevice                        logicalDevice;

    Vulkan_Graphics(GLFW_Wrapper *glfwWrapper, bool enableValidation);
    ~Vulkan_Graphics();

    Command* GetGraphicsPool(){ return graphicsCommandPool; }
    Pipeline* GetCurrentPipe(){ return currentPipe; }
    VkQueue GetGraphicsQueue(){ return graphicsQueue; }

    VkFramebuffer VRenderBegin();
    void VRenderEnd();

    uint32_t BeginDrawFrame();
    void EndDrawFrame(uint32_t imageIndex);
    Command* GetGraphicsCommandPool(){ return graphicsCommandPool; }

    VkBuffer GetUniformBufferByIndex(uint32_t index);

    static int CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, 
VkMemoryPropertyFlags properties, VkBuffer * buffer, VkDeviceMemory * 
bufferMemory);
    static uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags 
properties, VkPhysicalDevice physicalDevice);
    static VkImageView CreateImageView(VkImage image, VkFormat format, VkDevice 
logDevice);
    static void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, 
VkDeviceSize size, VkDevice lDevice, VkPhysicalDevice physDevice);

};

extern Vulkan_Graphics vGraphics;
Ian Rosenberg
  • 53
  • 2
  • 10
  • It's hard to say without seeing the contents of `"Vulkan_Graphics.h"`. – R Sahu Nov 19 '18 at 21:16
  • What exactly is the issue here? Do you get compilation errors? –  Nov 19 '18 at 22:05
  • Yes, I get four errors, two regarding inclusion of Mesh in Model and the other two about inclusion of Texture in Model. The two errors are: C2143: syntax error : missing ';' before '*' c:\users\ian\desktop\vulkan-laptop\vulkan-laptop\vulkan-laptop\include\model.h error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\users\ian\desktop\vulkan-laptop\vulkan-laptop\vulkan-laptop\include\model.h 17 1 Vulkan-Laptop – Ian Rosenberg Nov 19 '18 at 22:11
  • `Mesh.h` should not include `Vulkan_Graphics.h` if `Vulkan_Graphics.h` includes `Mesh.h` – drescherjm Nov 19 '18 at 23:34

2 Answers2

2

I can't honestly tell you whether or where you have a circular dependency, but the fact that you have .h files including other .h files makes it a definite possibility. I can tell you how to avoid it though.

When you declare a pointer or reference to a class, you don't need the full class definition; a forward declaration will do. In your Model.h it is unnecessary to include Texture.h and Mesh.h. Replace them with forward declarations:

struct Texture;
struct Mesh;

You will need to make sure those headers get included in the source file where you actually try to use those pointers.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

you have a circular dependency on your files which is supposed to be broken by the #pragma once statement. The statement guarantees that an include file is included only once in the compilation. So, if Mesh.h was include in Model.h, and the Mesh.h was compiled first, then it will not be compiled again though it gets included in your Vulkan_Graphics.h.

The problem though is that this pragma is not the standard one and might not be supported by some compilers. So, the standard way of protecting your file from multiple includes and from possibility of causing circular dependencies, is to protect it with guard macros, i.e.

#ifndef MY_HEADER_FILE
#define MY_HEADER_FILE
... header file contents ...
#endif

The disadvantage is that you have to make sure that the macro name is unique across all compilation files, usually file name is used as a template for it.

Serge
  • 11,616
  • 3
  • 18
  • 28
  • The error codes quoted in the question indicate that they're using Microsoft Visual C++, which definitely supports `#pragma once`. So a different explanation is required. – Mark Ransom Nov 19 '18 at 22:16