#pragma once

/*
	VulkanFramework
	by John Ryland
	Copyright (c) 2023
*/

////////////////////////////////////////////////////////////////////////////////////
//	Vulkan Device

#include <vulkan/vulkan.h>

namespace Vulkan {

class Device
{
public:
    Device();
    virtual ~Device();

    Device& operator=(const Device& other) = delete;

    virtual void Create(const char** extensions, uint32_t extensionsCount);
    virtual void Destroy();

    virtual void CheckResult(VkResult err, const char* message = "");
    virtual uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
    virtual VkFormat FindFormat(VkFormat* candidateFormats, size_t size, VkFormatFeatureFlags properties);
    virtual void DumpPhysicalDeviceExtensions();

    struct SingleTimeCommand
    {
        ~SingleTimeCommand();
        Device*          m_owner;
        VkCommandBuffer  m_commandBuffer;
    };
    SingleTimeCommand BeginSingleTimeCommands();

    VkAllocationCallbacks*   m_allocator;
    VkInstance               m_instance;
    VkDebugReportCallbackEXT m_debugReport;
    VkDevice                 m_device;
    uint32_t                 m_graphicsQueueFamily;
    VkQueue                  m_graphicsQueue;
    VkPhysicalDevice         m_physicalDevice;
    VkDescriptorPool         m_descriptorPool;
    VkDescriptorSetLayout    m_descriptorSetLayout;
    VkCommandPool            m_commandPool;

protected:
    virtual void CreateInstance(const char** extensions, uint32_t extensionsCount, bool enableDebug = false, bool enableValidationLayers = false);
    virtual void SelectGPU();
    virtual void SelectGraphicsQueueFamily();
    virtual void CreateLogicalDevice();
    virtual void CreateDescriptorPool();
    virtual void CreateDescriptorSetLayout();
    virtual void CreateCommandPool();
};

} // Vulkan namespace
