Browse Source

some work on drawQuads (not fully working yet)

niki 3 years ago
parent
commit
7f894e5bf7

+ 29 - 41
src/modules/graphics/vulkan/Buffer.cpp

@@ -4,71 +4,59 @@
 namespace love {
 namespace love {
 	namespace graphics {
 	namespace graphics {
 		namespace vulkan {
 		namespace vulkan {
-			static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFtiler, VkMemoryPropertyFlags properties) {
-				VkPhysicalDeviceMemoryProperties memProperties;
-				vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
+			static VkBufferUsageFlags getUsageBit(BufferUsage mode) {
+				switch (mode) {
+				case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+				case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+				case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+				default:
+					throw love::Exception("unsupported BufferUsage mode");
+				}
+			}
 
 
-				for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
-					if ((typeFtiler & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
-						return i;
+			static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags) {
+				VkBufferUsageFlags vkFlags = 0;
+				for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++) {
+					BufferUsageFlags flag = static_cast<BufferUsageFlags>(1u << i);
+					if (flags & flag) {
+						vkFlags |= getUsageBit((BufferUsage)i);
 					}
 					}
 				}
 				}
-
-				throw love::Exception("failed to find suitable memory type");
+				return vkFlags;
 			}
 			}
 
 
-			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();
+			Buffer::Buffer(VmaAllocator allocator, 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) {
 
 
 				VkBufferCreateInfo bufferInfo{};
 				VkBufferCreateInfo bufferInfo{};
 				bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 				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.size = size;
+				bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags);
 				bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 				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);
+				VmaAllocationCreateInfo allocCreateInfo = {};
+				allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
+				allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
 
 
-				vkMapMemory(device, bufferMemory, 0, getSize(), 0, &mappedMemory);
-				memcpy(mappedMemory, data, size);
-				vkUnmapMemory(device, bufferMemory);
+				vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo);
 			}
 			}
 
 
 			Buffer::~Buffer() {
 			Buffer::~Buffer() {
-				vkDestroyBuffer(device, buffer, nullptr);
-				vkFreeMemory(device, bufferMemory, nullptr);
+				// fixme
 			}
 			}
 
 
 			void* Buffer::map(MapType map, size_t offset, size_t size) {
 			void* Buffer::map(MapType map, size_t offset, size_t size) {
-				vkMapMemory(device, bufferMemory, offset, size, 0, &mappedMemory);
-				return mappedMemory;
+				char* data = (char*)allocInfo.pMappedData;
+				return (void*) (data + offset);
 			}
 			}
 
 
 			bool Buffer::fill(size_t offset, size_t size, const void *data) {
 			bool Buffer::fill(size_t offset, size_t size, const void *data) {
-				memcpy(mappedMemory, data, size);
+				void* dst = (void*)((char*)allocInfo.pMappedData + offset);
+				memcpy(dst, data, size);
 				return true;
 				return true;
 			}
 			}
 
 
 			void Buffer::unmap(size_t usedoffset, size_t usedsize) {
 			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) {
 			void Buffer::copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) {

+ 5 - 7
src/modules/graphics/vulkan/Buffer.h

@@ -1,5 +1,6 @@
 #include "graphics/Buffer.h"
 #include "graphics/Buffer.h"
 #include <vulkan/vulkan.h>
 #include <vulkan/vulkan.h>
+#include "vk_mem_alloc.h"
 
 
 
 
 namespace love {
 namespace love {
@@ -7,7 +8,7 @@ namespace love {
 		namespace vulkan {
 		namespace vulkan {
 			class Buffer : public love::graphics::Buffer {
 			class Buffer : public love::graphics::Buffer {
 			public:
 			public:
-				Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
+				Buffer(VmaAllocator allocator, love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
 				virtual ~Buffer();
 				virtual ~Buffer();
 
 
 				void* map(MapType map, size_t offset, size_t size) override;
 				void* map(MapType map, size_t offset, size_t size) override;
@@ -18,18 +19,15 @@ namespace love {
 					return (ptrdiff_t) buffer;	// todo ?
 					return (ptrdiff_t) buffer;	// todo ?
 				}
 				}
 				ptrdiff_t getTexelBufferHandle() const override {
 				ptrdiff_t getTexelBufferHandle() const override {
+					throw love::Exception("unimplemented Buffer::getTexelBufferHandle");
 					return (ptrdiff_t) nullptr;	// todo ?
 					return (ptrdiff_t) nullptr;	// todo ?
 				}
 				}
 
 
 			private:
 			private:
-				VkDevice device;
-				VkPhysicalDevice physicalDevice;
-
 				// todo use a staging buffer for improved performance
 				// todo use a staging buffer for improved performance
 				VkBuffer buffer;
 				VkBuffer buffer;
-				VkDeviceMemory bufferMemory;
-
-				void* mappedMemory;
+				VmaAllocation allocation;
+				VmaAllocationInfo allocInfo;
 			};
 			};
 		}
 		}
 	}
 	}

+ 82 - 4
src/modules/graphics/vulkan/Graphics.cpp

@@ -62,7 +62,7 @@ namespace love {
 
 
 			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) {
 			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) {
 				std::cout << "newBuffer ";
 				std::cout << "newBuffer ";
-				return nullptr;
+				return new Buffer(vmaAllocator, this, settings, format, data, size, arraylength);
 			}
 			}
 
 
 			void Graphics::startRecordingGraphicsCommands() {
 			void Graphics::startRecordingGraphicsCommands() {
@@ -211,6 +211,7 @@ namespace love {
 				createCommandBuffers();
 				createCommandBuffers();
 				createUniformBuffers();
 				createUniformBuffers();
 				createDefaultTexture();
 				createDefaultTexture();
+				createQuadIndexBuffer();
 				createDescriptorPool();
 				createDescriptorPool();
 				createSyncObjects();
 				createSyncObjects();
 				startRecordingGraphicsCommands();
 				startRecordingGraphicsCommands();
@@ -308,8 +309,14 @@ namespace love {
 				createVulkanVertexFormat(*cmd.attributes, useConstantColorBuffer, configuration);
 				createVulkanVertexFormat(*cmd.attributes, useConstantColorBuffer, configuration);
 
 
 				for (uint32_t i = 0; i < 2; i++) {
 				for (uint32_t i = 0; i < 2; i++) {
-					buffers.push_back((VkBuffer)cmd.buffers->info[i].buffer->getHandle());
-					offsets.push_back((VkDeviceSize)cmd.buffers->info[i].offset);
+					if (cmd.buffers->useBits & (1u << i)) {
+						buffers.push_back((VkBuffer)cmd.buffers->info[i].buffer->getHandle());
+						offsets.push_back((VkDeviceSize)cmd.buffers->info[i].offset);
+					}
+					else {
+						buffers.push_back(VK_NULL_HANDLE);
+						offsets.push_back(0);
+					}
 				}
 				}
 
 
 				if (useConstantColorBuffer) {
 				if (useConstantColorBuffer) {
@@ -332,6 +339,61 @@ namespace love {
 				vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), 1, 0, 0, 0);
 				vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), 1, 0, 0, 0);
 			}
 			}
 
 
+			void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
+				std::cout << "drawQuads ";
+
+				const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
+				const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
+
+				std::vector<VkBuffer> bufferVector;
+				std::vector<VkDeviceSize> offsets;
+
+				bool useConstantColorBuffer;
+				GraphicsPipelineConfiguration configuration;
+				createVulkanVertexFormat(attributes, useConstantColorBuffer, configuration);
+
+				for (uint32_t i = 0; i < 2; i++) {
+					if (buffers.useBits & (1u << i)) {
+						bufferVector.push_back((VkBuffer)buffers.info[i].buffer->getHandle());
+						offsets.push_back((VkDeviceSize)buffers.info[i].offset);
+					}
+					else {
+						if (useConstantColorBuffer) {
+							bufferVector.push_back(VK_NULL_HANDLE);
+							offsets.push_back(0);
+						}
+					}
+				}
+
+				if (useConstantColorBuffer) {
+					bufferVector.push_back((VkBuffer)batchedDrawBuffers[currentFrame].constantColorBuffer->getHandle());
+					offsets.push_back((VkDeviceSize)0);
+				}
+
+				if (texture == nullptr) {
+					setTexture(standardTexture);
+				}
+				else {
+					setTexture(texture);
+				}
+
+				ensureGraphicsPipelineConfiguration(configuration);
+
+				vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr);
+				vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)quadIndexBuffer->getHandle(), 0, getVulkanIndexBufferType(INDEX_UINT16));
+				vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, bufferVector.size(), bufferVector.data(), offsets.data());
+				vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(count * 6), 1, 0, 0, 0);
+				
+				int baseVertex = start * 4;
+
+				for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) {
+					int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
+
+					// vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(quadcount * 6), 1, 0, baseVertex, 0);
+					baseVertex += quadcount * 4;
+				}
+			}
+
 			graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) {
 			graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) {
 				std::cout << "newStreamBuffer ";
 				std::cout << "newStreamBuffer ";
 				return new StreamBuffer(vmaAllocator, type, size);
 				return new StreamBuffer(vmaAllocator, type, size);
@@ -652,11 +714,16 @@ 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.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
 				createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
 				createInfo.ppEnabledExtensionNames = deviceExtensions.data();
 				createInfo.ppEnabledExtensionNames = deviceExtensions.data();
@@ -1033,7 +1100,7 @@ namespace love {
 
 
 				bool usesColor = false;
 				bool usesColor = false;
 				
 				
-				for (uint32_t i = 0; i < 32; i++) {	// change to loop like in opengl implementation ?
+				for (uint32_t i = 0; i < VertexAttributes::MAX; i++) {	// change to loop like in opengl implementation ?
 					uint32 bit = 1u << i;
 					uint32 bit = 1u << i;
 					if (allBits & bit) {
 					if (allBits & bit) {
 						if (i == ATTRIB_COLOR) {
 						if (i == ATTRIB_COLOR) {
@@ -1293,6 +1360,17 @@ namespace love {
 				standardTexture = newTexture(settings);
 				standardTexture = newTexture(settings);
 			}
 			}
 
 
+			void Graphics::createQuadIndexBuffer() {
+				if (quadIndexBuffer != nullptr)
+					return;
+
+				size_t size = sizeof(uint16) * getIndexCount(TRIANGLEINDEX_QUADS, LOVE_UINT16_MAX);
+				quadIndexBuffer = static_cast<StreamBuffer*>(newStreamBuffer(BUFFERUSAGE_INDEX, size));
+				auto map = quadIndexBuffer->map(size);
+				fillIndices(TRIANGLEINDEX_QUADS, 0, LOVE_UINT16_MAX, (uint16*)map.data);
+				quadIndexBuffer->unmap(size);
+			}
+
 			bool operator==(const Graphics::GraphicsPipelineConfiguration& first, const Graphics::GraphicsPipelineConfiguration& other) {
 			bool operator==(const Graphics::GraphicsPipelineConfiguration& first, const Graphics::GraphicsPipelineConfiguration& other) {
 				if (first.vertexInputAttributeDescriptions.size() != other.vertexInputAttributeDescriptions.size()) {
 				if (first.vertexInputAttributeDescriptions.size() != other.vertexInputAttributeDescriptions.size()) {
 					return false;
 					return false;

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

@@ -72,7 +72,7 @@ namespace love {
 				RendererInfo getRendererInfo() const override { std::cout << "getRendererInfo "; return {}; }
 				RendererInfo getRendererInfo() const override { std::cout << "getRendererInfo "; return {}; }
 				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 { std::cout << "drawQuads "; }
+				void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override;
 
 
 				GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override { return nullptr;  };
 				GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override { return nullptr;  };
 				GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) { return nullptr; }
 				GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) { return nullptr; }
@@ -87,6 +87,8 @@ namespace love {
 					friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other);
 					friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other);
 				};
 				};
 
 
+				void setShader(Shader*);
+
 			protected:
 			protected:
 				graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { 
 				graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { 
 					std::cout << "newShaderStageInternal "; 
 					std::cout << "newShaderStageInternal "; 
@@ -134,6 +136,8 @@ namespace love {
 
 
 				void createVulkanVertexFormat(VertexAttributes vertexAttributes, bool& useConstantVertexColor, GraphicsPipelineConfiguration& configuration);
 				void createVulkanVertexFormat(VertexAttributes vertexAttributes, bool& useConstantVertexColor, GraphicsPipelineConfiguration& configuration);
 
 
+				StreamBuffer* quadIndexBuffer = nullptr;
+
 				// vulkan specific member functions and variables
 				// vulkan specific member functions and variables
 
 
 				struct QueueFamilyIndices {
 				struct QueueFamilyIndices {
@@ -178,6 +182,7 @@ namespace love {
 				void createCommandBuffers();
 				void createCommandBuffers();
 				void createSyncObjects();
 				void createSyncObjects();
 				void createDefaultTexture();
 				void createDefaultTexture();
+				void createQuadIndexBuffer();
 				void cleanup();
 				void cleanup();
 				void cleanupSwapChain();
 				void cleanupSwapChain();
 				void recreateSwapChain();
 				void recreateSwapChain();

+ 13 - 4
src/modules/graphics/vulkan/Texture.cpp

@@ -1,5 +1,6 @@
 #include "Texture.h"
 #include "Texture.h"
 #include "Graphics.h"
 #include "Graphics.h"
+#include "Vulkan.h"
 
 
 // make vulkan::Graphics functions available
 // make vulkan::Graphics functions available
 #define vgfx ((Graphics*)gfx)
 #define vgfx ((Graphics*)gfx)
@@ -16,13 +17,13 @@ namespace love {
 					auto sliceData = data->get(0, 0);
 					auto sliceData = data->get(0, 0);
 					auto size = sliceData->getSize();
 					auto size = sliceData->getSize();
 					auto dataPtr = sliceData->getData();
 					auto dataPtr = sliceData->getData();
-					Rect rect;
+					Rect rect{};
 					rect.x = 0;
 					rect.x = 0;
 					rect.y = 0;
 					rect.y = 0;
 					rect.w = sliceData->getWidth();
 					rect.w = sliceData->getWidth();
 					rect.h = sliceData->getHeight();
 					rect.h = sliceData->getHeight();
 
 
-					uploadByteData(PIXELFORMAT_RGBA8_UNORM, dataPtr, size, 0, 0, rect);
+					uploadByteData(format, dataPtr, size, 0, 0, rect);
 				}
 				}
 				else {
 				else {
 					uint8 defaultPixel[] = { 255, 255, 255, 255 };
 					uint8 defaultPixel[] = { 255, 255, 255, 255 };
@@ -40,16 +41,22 @@ namespace love {
 			}
 			}
 
 
 			void Texture::createTextureImageView() {
 			void Texture::createTextureImageView() {
+				auto vulkanFormat = Vulkan::getTextureFormat(format);
+
 				VkImageViewCreateInfo viewInfo{};
 				VkImageViewCreateInfo viewInfo{};
 				viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 				viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 				viewInfo.image = textureImage;
 				viewInfo.image = textureImage;
 				viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
 				viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
-				viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+				viewInfo.format = vulkanFormat.internalFormat;
 				viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 				viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 				viewInfo.subresourceRange.baseMipLevel = 0;
 				viewInfo.subresourceRange.baseMipLevel = 0;
 				viewInfo.subresourceRange.levelCount = 1;
 				viewInfo.subresourceRange.levelCount = 1;
 				viewInfo.subresourceRange.baseArrayLayer = 0;
 				viewInfo.subresourceRange.baseArrayLayer = 0;
 				viewInfo.subresourceRange.layerCount = 1;
 				viewInfo.subresourceRange.layerCount = 1;
+				viewInfo.components.r = vulkanFormat.swizzleR;
+				viewInfo.components.g = vulkanFormat.swizzleG;
+				viewInfo.components.b = vulkanFormat.swizzleB;
+				viewInfo.components.a = vulkanFormat.swizzleA;
 
 
 				if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
 				if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
 					throw love::Exception("could not create texture image view");
 					throw love::Exception("could not create texture image view");
@@ -181,6 +188,8 @@ namespace love {
 
 
 				memcpy(allocInfo.pMappedData, data, size);
 				memcpy(allocInfo.pMappedData, data, size);
 
 
+				auto vulkanFormat = Vulkan::getTextureFormat(format);
+
 				VkImageCreateInfo imageInfo{};
 				VkImageCreateInfo imageInfo{};
 				imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 				imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 				imageInfo.imageType = VK_IMAGE_TYPE_2D;
 				imageInfo.imageType = VK_IMAGE_TYPE_2D;
@@ -189,7 +198,7 @@ namespace love {
 				imageInfo.extent.depth = 1;
 				imageInfo.extent.depth = 1;
 				imageInfo.mipLevels = 1;
 				imageInfo.mipLevels = 1;
 				imageInfo.arrayLayers = 1;
 				imageInfo.arrayLayers = 1;
-				imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
+				imageInfo.format = vulkanFormat.internalFormat;
 				imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 				imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 				imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 				imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 				imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
 				imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

+ 166 - 0
src/modules/graphics/vulkan/Vulkan.cpp

@@ -83,6 +83,172 @@ namespace love {
 					throw love::Exception("unknown data format");
 					throw love::Exception("unknown data format");
 				}
 				}
 			}
 			}
+
+			TextureFormat Vulkan::getTextureFormat(PixelFormat format) {
+				TextureFormat textureFormat{};
+
+				switch (format) {
+					case PIXELFORMAT_UNKNOWN:
+						throw love::Exception("unknown pixel format");
+					case PIXELFORMAT_NORMAL:
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;
+						break;
+					case PIXELFORMAT_HDR:
+						throw love::Exception("unimplemented pixel format: hdr");
+					case PIXELFORMAT_R8_UNORM:
+						textureFormat.internalFormat = VK_FORMAT_R8_UNORM;
+						break;
+					case PIXELFORMAT_R8_INT:
+						textureFormat.internalFormat = VK_FORMAT_R8_SINT;
+						break;
+					case PIXELFORMAT_R8_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R8_UINT;
+						break;
+					case PIXELFORMAT_R16_UNORM:
+						textureFormat.internalFormat = VK_FORMAT_R16_UNORM;
+						break;
+					case PIXELFORMAT_R16_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R16_SFLOAT;
+						break;
+					case PIXELFORMAT_R16_INT:
+						textureFormat.internalFormat = VK_FORMAT_R16_SINT;
+						break;
+					case PIXELFORMAT_R16_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R16_UINT;
+						break;
+					case PIXELFORMAT_R32_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R32_SFLOAT;
+						break;
+					case PIXELFORMAT_R32_INT:
+						textureFormat.internalFormat = VK_FORMAT_R32_SINT;
+						break;
+					case PIXELFORMAT_R32_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R32_UINT;
+						break;
+					case PIXELFORMAT_RG8_UNORM:
+						textureFormat.internalFormat = VK_FORMAT_R8G8_UNORM;
+						break;
+					case PIXELFORMAT_RG8_INT:
+						textureFormat.internalFormat = VK_FORMAT_R8G8_SINT;
+						break;
+					case PIXELFORMAT_RG8_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R8G8_UINT;
+						break;
+					case PIXELFORMAT_LA8_UNORM: // Same as RG8: but accessed as (L: L: L: A)
+						textureFormat.internalFormat = VK_FORMAT_R8G8_UNORM;
+						textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_R;
+						textureFormat.swizzleG = VK_COMPONENT_SWIZZLE_R;
+						textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R;
+						textureFormat.swizzleA = VK_COMPONENT_SWIZZLE_G;
+						break;
+					case PIXELFORMAT_RG16_UNORM:
+						textureFormat.internalFormat = VK_FORMAT_R16G16_UNORM;
+						break;
+					case PIXELFORMAT_RG16_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16_SFLOAT;
+						break;
+					case PIXELFORMAT_RG16_INT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16_SINT;
+						break;
+					case PIXELFORMAT_RG16_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16_UINT;
+						break;
+					case PIXELFORMAT_RG32_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32_SFLOAT;
+						break;
+					case PIXELFORMAT_RG32_INT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32_SINT;
+						break;
+					case PIXELFORMAT_RG32_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32_UINT;
+						break;
+					case PIXELFORMAT_RGBA8_UNORM:
+					case PIXELFORMAT_RGBA8_UNORM_sRGB:	// fixme ?
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM;
+						break;
+					case PIXELFORMAT_BGRA8_UNORM:
+					case PIXELFORMAT_BGRA8_UNORM_sRGB:	// fixme ?
+						textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM;
+						break;
+					case PIXELFORMAT_RGBA8_INT:
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT;
+						break;
+					case PIXELFORMAT_RGBA8_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UINT;
+						break;
+					case PIXELFORMAT_RGBA16_UNORM:
+						textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_UNORM;
+						break;
+					case PIXELFORMAT_RGBA16_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
+						break;
+					case PIXELFORMAT_RGBA16_INT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_SINT;
+						break;
+					case PIXELFORMAT_RGBA16_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R16G16B16A16_UINT;
+						break;
+					case PIXELFORMAT_RGBA32_FLOAT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
+						break;
+					case PIXELFORMAT_RGBA32_INT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_SINT;
+						break;
+					case PIXELFORMAT_RGBA32_UINT:
+						textureFormat.internalFormat = VK_FORMAT_R32G32B32A32_UINT;
+						break;
+					case PIXELFORMAT_RGBA4_UNORM:    // LSB->MSB: [a: b: g: r]
+					case PIXELFORMAT_RGB5A1_UNORM:   // LSB->MSB: [a: b: g: r]
+					case PIXELFORMAT_RGB565_UNORM:   // LSB->MSB: [b: g: r]
+					case PIXELFORMAT_RGB10A2_UNORM:  // LSB->MSB: [r: g: b: a]
+					case PIXELFORMAT_RG11B10_FLOAT:  // LSB->MSB: [r: g: b]
+					case PIXELFORMAT_STENCIL8:
+					case PIXELFORMAT_DEPTH16_UNORM:
+					case PIXELFORMAT_DEPTH24_UNORM:
+					case PIXELFORMAT_DEPTH32_FLOAT:
+					case PIXELFORMAT_DEPTH24_UNORM_STENCIL8:
+					case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8:
+					case PIXELFORMAT_DXT1_UNORM:
+					case PIXELFORMAT_DXT3_UNORM:
+					case PIXELFORMAT_DXT5_UNORM:
+					case PIXELFORMAT_BC4_UNORM:
+					case PIXELFORMAT_BC4_SNORM:
+					case PIXELFORMAT_BC5_UNORM:
+					case PIXELFORMAT_BC5_SNORM:
+					case PIXELFORMAT_BC6H_UFLOAT:
+					case PIXELFORMAT_BC6H_FLOAT:
+					case PIXELFORMAT_BC7_UNORM:
+					case PIXELFORMAT_PVR1_RGB2_UNORM:
+					case PIXELFORMAT_PVR1_RGB4_UNORM:
+					case PIXELFORMAT_PVR1_RGBA2_UNORM:
+					case PIXELFORMAT_PVR1_RGBA4_UNORM:
+					case PIXELFORMAT_ETC1_UNORM:
+					case PIXELFORMAT_ETC2_RGB_UNORM:
+					case PIXELFORMAT_ETC2_RGBA_UNORM:
+					case PIXELFORMAT_ETC2_RGBA1_UNORM:
+					case PIXELFORMAT_EAC_R_UNORM:
+					case PIXELFORMAT_EAC_R_SNORM:
+					case PIXELFORMAT_EAC_RG_UNORM:
+					case PIXELFORMAT_EAC_RG_SNORM:
+					case PIXELFORMAT_ASTC_4x4:
+					case PIXELFORMAT_ASTC_5x4:
+					case PIXELFORMAT_ASTC_5x5:
+					case PIXELFORMAT_ASTC_6x5:
+					case PIXELFORMAT_ASTC_6x6:
+					case PIXELFORMAT_ASTC_8x5:
+					case PIXELFORMAT_ASTC_8x6:
+					case PIXELFORMAT_ASTC_8x8:
+					case PIXELFORMAT_ASTC_10x5:
+					case PIXELFORMAT_ASTC_10x6:
+					case PIXELFORMAT_ASTC_10x8:
+					case PIXELFORMAT_ASTC_10x10:
+					case PIXELFORMAT_ASTC_12x10:
+					case PIXELFORMAT_ASTC_12x12:
+						throw love::Exception("unimplemented pixel format");
+				}
+
+				return textureFormat;
+			}
 		}
 		}
 	}
 	}
 }
 }

+ 12 - 2
src/modules/graphics/vulkan/Vulkan.h

@@ -1,15 +1,25 @@
 #ifndef LOVE_GRAPHICS_VULKAN_VULKAN_H
 #ifndef LOVE_GRAPHICS_VULKAN_VULKAN_H
 #define LOVE_GRAPHICS_VULKAN_VULKAN_H
 #define LOVE_GRAPHICS_VULKAN_VULKAN_H
 
 
-#include "Vulkan.h"
-#include "Graphics.h"
+#include "graphics/Graphics.h"
+#include "vulkan/vulkan.h"
 
 
 namespace love {
 namespace love {
 	namespace graphics {
 	namespace graphics {
 		namespace vulkan {
 		namespace vulkan {
+			struct TextureFormat {
+				VkFormat internalFormat = VK_FORMAT_UNDEFINED;
+
+				VkComponentSwizzle swizzleR = VK_COMPONENT_SWIZZLE_IDENTITY;
+				VkComponentSwizzle swizzleG = VK_COMPONENT_SWIZZLE_IDENTITY;
+				VkComponentSwizzle swizzleB = VK_COMPONENT_SWIZZLE_IDENTITY;
+				VkComponentSwizzle swizzleA = VK_COMPONENT_SWIZZLE_IDENTITY;
+			};
+
 			class Vulkan {
 			class Vulkan {
 			public:
 			public:
 				static VkFormat getVulkanVertexFormat(DataFormat format);
 				static VkFormat getVulkanVertexFormat(DataFormat format);
+				static TextureFormat getTextureFormat(PixelFormat);
 			};
 			};
 		}
 		}
 	}
 	}