vulkan: implement getRendererInfo

This commit is contained in:
niki
2022-07-10 19:13:10 +02:00
parent 565455c3ea
commit ef08282f0d
4 changed files with 153 additions and 116 deletions
+44 -18
View File
@@ -48,7 +48,16 @@ namespace love {
return "love.graphics.vulkan"; return "love.graphics.vulkan";
} }
Graphics::Graphics() { const VkDevice Graphics::getDevice() const {
return device;
}
const VkPhysicalDevice Graphics::getPhysicalDevice() const {
return physicalDevice;
}
const VmaAllocator Graphics::getVmaAllocator() const {
return vmaAllocator;
} }
Graphics::~Graphics() { Graphics::~Graphics() {
@@ -294,6 +303,19 @@ namespace love {
created = false; created = false;
cleanup(); cleanup();
} }
Graphics::RendererInfo Graphics::getRendererInfo() const {
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
Graphics::RendererInfo info;
info.device = deviceProperties.deviceName;
info.vendor = Vulkan::getVendorName(deviceProperties.vendorID);
info.version = Vulkan::getVulkanApiVersion(deviceProperties.apiVersion);
info.name = "Vulkan";
return info;
}
void Graphics::draw(const DrawIndexedCommand& cmd) { void Graphics::draw(const DrawIndexedCommand& cmd) {
std::cout << "drawIndexed "; std::cout << "drawIndexed ";
@@ -356,12 +378,8 @@ namespace love {
bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
std::cout << "isPixelFormatSupported "; std::cout << "isPixelFormatSupported ";
switch (format) {
case PIXELFORMAT_LA8_UNORM: return true;
return false;
default:
return true;
}
} }
void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) { void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
@@ -431,6 +449,10 @@ namespace love {
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS // END IMPLEMENTATION OVERRIDDEN FUNCTIONS
void Graphics::setTexture(graphics::Texture* texture) {
currentTexture = texture;
}
void Graphics::updatedBatchedDrawBuffers() { void Graphics::updatedBatchedDrawBuffers() {
batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1; batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1;
batchedDrawState.vb[0]->nextFrame(); batchedDrawState.vb[0]->nextFrame();
@@ -456,7 +478,7 @@ namespace love {
graphics::StreamBuffer* Graphics::getUniformBuffer() { graphics::StreamBuffer* Graphics::getUniformBuffer() {
auto data = getCurrentBuiltinUniformData(); auto data = getCurrentBuiltinUniformData();
for (auto it : uniformBufferMap) { for (auto &it : uniformBufferMap) {
if (it.first == data) { if (it.first == data) {
return it.second; return it.second;
} }
@@ -556,7 +578,7 @@ namespace love {
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //todo, get this version from somewhere else? appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //todo, get this version from somewhere else?
appInfo.pEngineName = "LOVE Engine"; appInfo.pEngineName = "LOVE Engine";
appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV); appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
appInfo.apiVersion = VK_API_VERSION_1_0; appInfo.apiVersion = VK_API_VERSION_1_3;
VkInstanceCreateInfo createInfo{}; VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
@@ -682,6 +704,12 @@ namespace love {
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
score += 1000; score += 1000;
} }
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
score += 100;
}
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
score += 10;
}
// definitely needed // definitely needed
@@ -710,7 +738,7 @@ namespace love {
return score; return score;
} }
Graphics::QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) {
QueueFamilyIndices indices; QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0; uint32_t queueFamilyCount = 0;
@@ -761,16 +789,12 @@ namespace love {
VkPhysicalDeviceFeatures deviceFeatures{}; VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.samplerAnisotropy = VK_TRUE; deviceFeatures.samplerAnisotropy = VK_TRUE;
VkPhysicalDeviceFeatures2 deviceFeatures2{};
deviceFeatures2.features.robustBufferAccess = VK_TRUE;
deviceFeatures2.pNext = nullptr;
VkDeviceCreateInfo createInfo{}; VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data(); createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.pEnabledFeatures = &deviceFeatures; createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.pNext = &deviceFeatures2; createInfo.pNext = nullptr;
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
@@ -804,7 +828,9 @@ namespace love {
allocatorCreateInfo.instance = instance; allocatorCreateInfo.instance = instance;
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator); if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) {
throw love::Exception("failed to create vma allocator");
}
} }
void Graphics::createSurface() { void Graphics::createSurface() {
@@ -815,7 +841,7 @@ namespace love {
} }
} }
Graphics::SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) { SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) {
SwapChainSupportDetails details; SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
@@ -1416,7 +1442,7 @@ namespace love {
quadIndexBuffer->unmap(size); quadIndexBuffer->unmap(size);
} }
bool operator==(const Graphics::GraphicsPipelineConfiguration& first, const Graphics::GraphicsPipelineConfiguration& other) { bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other) {
if (first.vertexInputAttributeDescriptions.size() != other.vertexInputAttributeDescriptions.size()) { if (first.vertexInputAttributeDescriptions.size() != other.vertexInputAttributeDescriptions.size()) {
return false; return false;
} }
+78 -98
View File
@@ -19,25 +19,61 @@
namespace love { namespace love {
namespace graphics { namespace graphics {
namespace vulkan { namespace vulkan {
struct GraphicsPipelineConfiguration {
std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other);
};
struct DecriptorSetConfiguration {
graphics::Texture* texture;
graphics::StreamBuffer* buffer;
bool operator==(const DecriptorSetConfiguration& conf2) {
return this->texture == conf2.texture && this->buffer == conf2.buffer;
}
};
struct BatchedDrawBuffers {
StreamBuffer* vertexBuffer1;
StreamBuffer* vertexBuffer2;
StreamBuffer* indexBuffer;
StreamBuffer* constantColorBuffer;
~BatchedDrawBuffers() {
delete vertexBuffer1;
delete vertexBuffer2;
delete indexBuffer;
delete constantColorBuffer;
}
};
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
class Graphics final : public love::graphics::Graphics { class Graphics final : public love::graphics::Graphics {
public: public:
Graphics(); Graphics() = default;
virtual ~Graphics(); virtual ~Graphics();
const char* getName() const override; const char* getName() const override;
const VkDevice getDevice() const;
const VkDevice getDevice() const { const VkPhysicalDevice getPhysicalDevice() const;
return device; const VmaAllocator getVmaAllocator() const;
}
const VkPhysicalDevice getPhysicalDevice() const {
return physicalDevice;
}
const VmaAllocator getVmaAllocator() const {
return vmaAllocator;
}
// implementation for virtual functions // implementation for virtual functions
love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override { love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override {
@@ -69,7 +105,7 @@ namespace love {
bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override;
Renderer getRenderer() const override { std::cout << "getRenderer "; return RENDERER_VULKAN; } Renderer getRenderer() const override { std::cout << "getRenderer "; return RENDERER_VULKAN; }
bool usesGLSLES() const override { std::cout << "usesGLSES "; return false; } bool usesGLSLES() const override { std::cout << "usesGLSES "; return false; }
RendererInfo getRendererInfo() const override { std::cout << "getRendererInfo "; return {}; } RendererInfo getRendererInfo() const override;
void draw(const DrawCommand& cmd) override { std::cout << "draw "; } void draw(const DrawCommand& cmd) override { std::cout << "draw "; }
void draw(const DrawIndexedCommand& cmd) override; void draw(const DrawIndexedCommand& cmd) override;
void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override; void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override;
@@ -80,22 +116,6 @@ namespace love {
VkCommandBuffer beginSingleTimeCommands(); VkCommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(VkCommandBuffer); void endSingleTimeCommands(VkCommandBuffer);
struct GraphicsPipelineConfiguration {
std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other);
};
struct DecriptorSetConfiguration {
graphics::Texture* texture;
graphics::StreamBuffer* buffer;
bool operator==(const DecriptorSetConfiguration& conf2) {
return this->texture == conf2.texture && this->buffer == conf2.buffer;
}
};
void setShader(Shader*); void setShader(Shader*);
protected: protected:
@@ -114,58 +134,6 @@ namespace love {
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; } void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; }
private: private:
graphics::Texture* currentTexture;
void setTexture(graphics::Texture* texture) {
currentTexture = texture;
}
VkDescriptorSet* getDescriptorSet(int currentFrame);
graphics::StreamBuffer* getUniformBuffer();
std::vector<std::pair<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
struct BatchedDrawBuffers {
StreamBuffer* vertexBuffer1;
StreamBuffer* vertexBuffer2;
StreamBuffer* indexBuffer;
StreamBuffer* constantColorBuffer;
~BatchedDrawBuffers() {
delete vertexBuffer1;
delete vertexBuffer2;
delete indexBuffer;
delete constantColorBuffer;
}
};
// we need an array of draw buffers, since the frames are being rendered asynchronously
// and we can't (or shouldn't) update the contents of the buffers while they're still in flight / being rendered.
std::vector<BatchedDrawBuffers> batchedDrawBuffers;
void updatedBatchedDrawBuffers();
void createVulkanVertexFormat(VertexAttributes vertexAttributes, bool& useConstantVertexColor, GraphicsPipelineConfiguration& configuration);
StreamBuffer* quadIndexBuffer = nullptr;
// vulkan specific member functions and variables
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
void createVulkanInstance(); void createVulkanInstance();
bool checkValidationSupport(); bool checkValidationSupport();
void pickPhysicalDevice(); void pickPhysicalDevice();
@@ -201,37 +169,49 @@ namespace love {
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration);
graphics::StreamBuffer* createUniformBufferFromData(graphics::Shader::BuiltinUniformData); graphics::StreamBuffer* createUniformBufferFromData(graphics::Shader::BuiltinUniformData);
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
void setTexture(graphics::Texture* texture);
void updatedBatchedDrawBuffers();
VkDescriptorSet* getDescriptorSet(int currentFrame);
graphics::StreamBuffer* getUniformBuffer();
void createVulkanVertexFormat(VertexAttributes vertexAttributes, bool& useConstantVertexColor, GraphicsPipelineConfiguration& configuration);
VkInstance instance; VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device; VkDevice device = VK_NULL_HANDLE;
VkQueue graphicsQueue; VkQueue graphicsQueue = VK_NULL_HANDLE;
VkQueue presentQueue; VkQueue presentQueue = VK_NULL_HANDLE;
VkSurfaceKHR surface; VkSurfaceKHR surface = VK_NULL_HANDLE;
VkSwapchainKHR swapChain; VkSwapchainKHR swapChain = VK_NULL_HANDLE;
std::vector<VkImage> swapChainImages; std::vector<VkImage> swapChainImages;
VkFormat swapChainImageFormat; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
VkExtent2D swapChainExtent; VkExtent2D swapChainExtent = VkExtent2D();
std::vector<VkImageView> swapChainImageViews; std::vector<VkImageView> swapChainImageViews;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkRenderPass renderPass; VkRenderPass renderPass = VK_NULL_HANDLE;
VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE; VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE;
std::vector<std::pair<GraphicsPipelineConfiguration, VkPipeline>> graphicsPipelines; // FIXME improve performance by using a hash map std::vector<std::pair<GraphicsPipelineConfiguration, VkPipeline>> graphicsPipelines; // FIXME improve performance by using a hash map
std::vector<VkFramebuffer> swapChainFramBuffers; std::vector<VkFramebuffer> swapChainFramBuffers;
VkCommandPool commandPool; VkCommandPool commandPool = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> commandBuffers; std::vector<VkCommandBuffer> commandBuffers;
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
std::vector<VkSemaphore> imageAvailableSemaphores; std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores; std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences; std::vector<VkFence> inFlightFences;
std::vector<VkFence> imagesInFlight; std::vector<VkFence> imagesInFlight;
size_t currentFrame = 0; size_t currentFrame = 0;
uint32_t imageIndex; uint32_t imageIndex = 0;
bool framebufferResized = false; bool framebufferResized = false;
VmaAllocator vmaAllocator; VmaAllocator vmaAllocator = VK_NULL_HANDLE;
graphics::Texture* standardTexture; graphics::Texture* standardTexture = nullptr;
// we need an array of draw buffers, since the frames are being rendered asynchronously
// and we can't (or shouldn't) update the contents of the buffers while they're still in flight / being rendered.
std::vector<BatchedDrawBuffers> batchedDrawBuffers;
StreamBuffer* quadIndexBuffer = nullptr;
graphics::Texture* currentTexture = nullptr;
std::vector<std::pair<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
}; };
} }
} }
+29
View File
@@ -1,5 +1,8 @@
#include "Vulkan.h" #include "Vulkan.h"
#include <sstream>
namespace love { namespace love {
namespace graphics { namespace graphics {
namespace vulkan { namespace vulkan {
@@ -257,6 +260,32 @@ namespace love {
return textureFormat; return textureFormat;
} }
// values taken from https://pcisig.com/membership/member-companies
// as specified at https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
std::string Vulkan::getVendorName(uint32_t vendorId) {
switch (vendorId) {
case 4318:
return "Nvidia";
case 8086:
return "Intel";
case 4130:
return "Advanced Micro Devices";
default:
return "unknown";
}
}
std::string Vulkan::getVulkanApiVersion(uint32_t version) {
std::stringstream ss;
ss << VK_API_VERSION_VARIANT(version)
<< "." << VK_API_VERSION_MAJOR(version)
<< "." << VK_API_VERSION_MINOR(version)
<< "." << VK_API_VERSION_PATCH(version);
return ss.str();
}
} }
} }
} }
+2
View File
@@ -20,6 +20,8 @@ namespace love {
public: public:
static VkFormat getVulkanVertexFormat(DataFormat format); static VkFormat getVulkanVertexFormat(DataFormat format);
static TextureFormat getTextureFormat(PixelFormat); static TextureFormat getTextureFormat(PixelFormat);
static std::string getVendorName(uint32_t vendorId);
static std::string getVulkanApiVersion(uint32_t apiVersion);
}; };
} }
} }