Browse Source

first draft of vulkan buffer implementation

niki 3 years ago
parent
commit
d09f834bf3

+ 2 - 0
CMakeLists.txt

@@ -578,6 +578,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_VULKAN
 	src/modules/graphics/vulkan/Shader.cpp
 	src/modules/graphics/vulkan/Shader.cpp
 	src/modules/graphics/vulkan/ShaderStage.h
 	src/modules/graphics/vulkan/ShaderStage.h
 	src/modules/graphics/vulkan/ShaderStage.cpp
 	src/modules/graphics/vulkan/ShaderStage.cpp
+	src/modules/graphics/vulkan/Buffer.h
+	src/modules/graphics/vulkan/Buffer.cpp
 )
 )
 
 
 set(LOVE_SRC_MODULE_GRAPHICS
 set(LOVE_SRC_MODULE_GRAPHICS

+ 78 - 0
src/modules/graphics/vulkan/Buffer.cpp

@@ -0,0 +1,78 @@
+#include "Buffer.h"
+#include "Graphics.h"
+
+namespace love {
+	namespace graphics {
+		namespace vulkan {
+			static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFtiler, VkMemoryPropertyFlags properties) {
+				VkPhysicalDeviceMemoryProperties memProperties;
+				vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
+
+				for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
+					if ((typeFtiler & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
+						return i;
+					}
+				}
+
+				throw love::Exception("failed to find suitable memory type");
+			}
+
+			Buffer::Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength) 
+				: love::graphics::Buffer(gfx, settings, format, size, arrayLength) {
+				auto vgfx = (Graphics*)gfx;
+				device = vgfx->getDevice();
+				auto physicalDevice = vgfx->getPhysicalDevice();
+
+				VkBufferCreateInfo bufferInfo{};
+				bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+				bufferInfo.size = getSize();
+				bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;	// todo: only vertex buffers are allowed for now
+				bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+				if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
+					throw love::Exception("failed to create buffer");
+				}
+
+				VkMemoryRequirements memRequirements;
+				vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
+
+				VkMemoryAllocateInfo allocInfo{};
+				allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+				allocInfo.allocationSize = memRequirements.size;
+				allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+				if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
+					throw love::Exception("failed to allocate vertex buffer memory");
+				}
+
+				vkBindBufferMemory(device, buffer, bufferMemory, 0);
+
+				vkMapMemory(device, bufferMemory, 0, getSize(), 0, &mappedMemory);
+				memcpy(mappedMemory, data, size);
+				vkUnmapMemory(device, bufferMemory);
+			}
+
+			Buffer::~Buffer() {
+				vkDestroyBuffer(device, buffer, nullptr);
+				vkFreeMemory(device, bufferMemory, nullptr);
+			}
+
+			void* Buffer::map(MapType map, size_t offset, size_t size) {
+				vkMapMemory(device, bufferMemory, offset, size, 0, &mappedMemory);
+				return mappedMemory;
+			}
+
+			void Buffer::fill(size_t offset, size_t size, const void *data) {
+				memcpy(mappedMemory, data, size);
+			}
+
+			void Buffer::unmap(size_t usedoffset, size_t usedsize) {
+				vkUnmapMemory(device, bufferMemory);
+			}
+
+			void Buffer::copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) {
+				throw love::Exception("not implemented yet");
+			}
+		}
+	}
+}

+ 36 - 0
src/modules/graphics/vulkan/Buffer.h

@@ -0,0 +1,36 @@
+#include "graphics/Buffer.h"
+#include <vulkan/vulkan.h>
+
+
+namespace love {
+	namespace graphics {
+		namespace vulkan {
+			class Buffer : public love::graphics::Buffer {
+			public:
+				Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
+				virtual ~Buffer();
+
+				void* map(MapType map, size_t offset, size_t size) override;
+				void unmap(size_t usedoffset, size_t usedsize) override;
+				void fill(size_t offset, size_t size, const void* data) override;
+				void copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) override;
+				ptrdiff_t getHandle() const override {
+					return (ptrdiff_t) buffer;	// todo ?
+				}
+				ptrdiff_t getTexelBufferHandle() const override {
+					return (ptrdiff_t) nullptr;	// todo ?
+				}
+
+			private:
+				VkDevice device;
+				VkPhysicalDevice physicalDevice;
+
+				// todo use a staging buffer for improved performance
+				VkBuffer buffer;
+				VkDeviceMemory bufferMemory;
+
+				void* mappedMemory;
+			};
+		}
+	}
+}

+ 5 - 0
src/modules/graphics/vulkan/Graphics.cpp

@@ -1,4 +1,5 @@
 #include "Graphics.h"
 #include "Graphics.h"
+#include "Buffer.h"
 #include "SDL_vulkan.h"
 #include "SDL_vulkan.h"
 #include "window/Window.h"
 #include "window/Window.h"
 #include "common/Exception.h"
 #include "common/Exception.h"
@@ -90,6 +91,10 @@ namespace love {
 				cleanup();
 				cleanup();
 			}
 			}
 
 
+			love::graphics::Buffer* Graphics::newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) {
+				return new Buffer(this, settings, format, data, size, arraylength);
+			}
+
 			void Graphics::present(void* screenshotCallbackdata) {
 			void Graphics::present(void* screenshotCallbackdata) {
 				vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
 				vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
 
 

+ 5 - 1
src/modules/graphics/vulkan/Graphics.h

@@ -27,9 +27,13 @@ namespace love {
 					return device;
 					return device;
 				}
 				}
 
 
+				const VkPhysicalDevice getPhysicalDevice() const {
+					return physicalDevice;
+				}
+
 				// implementation for virtual functions
 				// implementation for virtual functions
 				Texture* newTexture(const Texture::Settings& settings, const Texture::Slices* data = nullptr) override { return nullptr;  }
 				Texture* newTexture(const Texture::Settings& settings, const Texture::Slices* data = nullptr) override { return nullptr;  }
-				Buffer* newBuffer(const Buffer::Settings& settings, const std::vector<Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) override { return nullptr;  }
+				love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) override;
 				void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override {}
 				void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override {}
 				void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override {}
 				void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override {}
 				Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { return Matrix4(); }
 				Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { return Matrix4(); }