use different uniform buffers for each draw call

This commit is contained in:
niki
2022-06-30 18:42:49 +02:00
parent 7f894e5bf7
commit 0cea07806f
9 changed files with 118 additions and 40 deletions
+10
View File
@@ -83,6 +83,16 @@ public:
**/ **/
void operator *= (const Matrix4 &m); void operator *= (const Matrix4 &m);
static friend bool operator==(const Matrix4& first, const Matrix4& other)
{
for (int i = 0; i < 16; i++) {
if (first.e[i] != other.e[i]) {
return false;
}
}
return true;
}
/** /**
* Gets a pointer to the 16 array elements. * Gets a pointer to the 16 array elements.
* @return The array elements. * @return The array elements.
+8
View File
@@ -179,6 +179,14 @@ public:
Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s. Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s.
Vector4 screenSizeParams; Vector4 screenSizeParams;
Colorf constantColor; Colorf constantColor;
bool operator==(const BuiltinUniformData& other) {
auto first = *this;
return first.transformMatrix == other.transformMatrix && first.projectionMatrix == other.projectionMatrix
&& first.normalMatrix[0] == other.normalMatrix[0] && first.normalMatrix[1] == other.normalMatrix[1]
&& first.normalMatrix[2] == other.normalMatrix[2] && first.screenSizeParams == other.screenSizeParams
&& first.constantColor == other.constantColor;
}
}; };
// Pointer to currently active Shader. // Pointer to currently active Shader.
+2 -1
View File
@@ -32,7 +32,6 @@ namespace love {
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size; bufferInfo.size = size;
bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags); bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags);
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocCreateInfo = {}; VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
@@ -57,6 +56,8 @@ namespace love {
} }
void Buffer::unmap(size_t usedoffset, size_t usedsize) { void Buffer::unmap(size_t usedoffset, size_t usedsize) {
(void)usedoffset;
(void)usedsize;
} }
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) {
+65 -25
View File
@@ -121,8 +121,6 @@ namespace love {
endRecordingGraphicsCommands(); endRecordingGraphicsCommands();
prepareDraw(currentFrame);
if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
} }
@@ -209,7 +207,6 @@ namespace love {
createFramebuffers(); createFramebuffers();
createCommandPool(); createCommandPool();
createCommandBuffers(); createCommandBuffers();
createUniformBuffers();
createDefaultTexture(); createDefaultTexture();
createQuadIndexBuffer(); createQuadIndexBuffer();
createDescriptorPool(); createDescriptorPool();
@@ -333,12 +330,42 @@ namespace love {
ensureGraphicsPipelineConfiguration(configuration); ensureGraphicsPipelineConfiguration(configuration);
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr); auto descriptorSets = getDescriptorSet(currentFrame);
auto descriptorSet = *descriptorSets;
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSets, 0, nullptr);
vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, buffers.size(), buffers.data(), offsets.data()); vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, buffers.size(), buffers.data(), offsets.data());
vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, getVulkanIndexBufferType(cmd.indexType)); vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, getVulkanIndexBufferType(cmd.indexType));
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);
} }
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const {
std::cout << "getSizedFormat ";
switch (format) {
PIXELFORMAT_NORMAL:
if (isGammaCorrect()) {
return PIXELFORMAT_RGBA8_UNORM_sRGB;
}
else {
return PIXELFORMAT_RGBA8_UNORM;
}
case PIXELFORMAT_HDR:
return PIXELFORMAT_RGBA16_FLOAT;
default:
return format;
}
}
bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
std::cout << "isPixelFormatSupported ";
switch (format) {
case PIXELFORMAT_LA8_UNORM:
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) {
std::cout << "drawQuads "; std::cout << "drawQuads ";
@@ -416,12 +443,29 @@ namespace love {
} }
VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) { VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
auto it = textureToDescriptorSetsMap.find(currentTexture); DecriptorSetConfiguration config;
if (it == textureToDescriptorSetsMap.end()) { config.texture = currentTexture;
textureToDescriptorSetsMap[currentTexture] = createDescriptorSets(currentTexture); config.buffer = getUniformBuffer();
for (auto i = 0; i < descriptorSetsMap.size(); i++) {
if (descriptorSetsMap[i].first == config) {
return &descriptorSetsMap[i].second[currentFrame];
}
} }
auto descriptorSets = createDescriptorSets(config);
descriptorSetsMap.push_back(std::make_pair(config, descriptorSets));
return &descriptorSetsMap.back().second[currentFrame];
}
return &textureToDescriptorSetsMap.at(currentTexture)[currentFrame]; graphics::StreamBuffer* Graphics::getUniformBuffer() {
auto data = getCurrentBuiltinUniformData();
for (auto it : uniformBufferMap) {
if (it.first == data) {
return it.second;
}
}
auto buffer = createUniformBufferFromData(data);
uniformBufferMap.push_back(std::make_pair(data, buffer));
return buffer;
} }
VkCommandBuffer Graphics::beginSingleTimeCommands() { VkCommandBuffer Graphics::beginSingleTimeCommands() {
@@ -456,9 +500,7 @@ namespace love {
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
} }
void Graphics::prepareDraw(uint32_t currentImage) { graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() {
auto& buffer = uniformBuffers.at(currentImage);
love::graphics::Shader::BuiltinUniformData data; love::graphics::Shader::BuiltinUniformData data;
data.transformMatrix = getTransform(); data.transformMatrix = getTransform();
@@ -493,9 +535,16 @@ namespace love {
data.constantColor = getColor(); data.constantColor = getColor();
gammaCorrectColor(data.constantColor); gammaCorrectColor(data.constantColor);
return data;
}
graphics::StreamBuffer* Graphics::createUniformBufferFromData(graphics::Shader::BuiltinUniformData data) {
auto buffer = newStreamBuffer(BUFFERUSAGE_UNIFORM, sizeof(data));
auto mappedInfo = buffer->map(0); auto mappedInfo = buffer->map(0);
memcpy(mappedInfo.data, &data, sizeof(data)); memcpy(mappedInfo.data, &data, sizeof(data));
buffer->unmap(0); buffer->unmap(0);
return buffer;
} }
void Graphics::createVulkanInstance() { void Graphics::createVulkanInstance() {
@@ -997,14 +1046,6 @@ namespace love {
} }
} }
void Graphics::createUniformBuffers() {
VkDeviceSize bufferSize = sizeof(graphics::Shader::BuiltinUniformData);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
uniformBuffers.push_back(std::make_unique<StreamBuffer>(vmaAllocator, BUFFERUSAGE_UNIFORM, bufferSize));
}
}
void Graphics::createDescriptorPool() { void Graphics::createDescriptorPool() {
std::array<VkDescriptorPoolSize, 2> poolSizes{}; std::array<VkDescriptorPoolSize, 2> poolSizes{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -1026,7 +1067,7 @@ namespace love {
} }
} }
std::vector<VkDescriptorSet> Graphics::createDescriptorSets(graphics::Texture* texture) { std::vector<VkDescriptorSet> Graphics::createDescriptorSets(DecriptorSetConfiguration config) {
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout); std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{}; VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -1055,13 +1096,13 @@ namespace love {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{}; VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = (VkBuffer)uniformBuffers.at(i)->getHandle(); bufferInfo.buffer = (VkBuffer)config.buffer->getHandle();
bufferInfo.offset = 0; bufferInfo.offset = 0;
bufferInfo.range = sizeof(graphics::Shader::BuiltinUniformData); bufferInfo.range = sizeof(graphics::Shader::BuiltinUniformData);
VkDescriptorImageInfo imageInfo{}; VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
Texture* vkTexture = (Texture*)texture; Texture* vkTexture = (Texture*)config.texture;
imageInfo.imageView = vkTexture->getImageView(); imageInfo.imageView = vkTexture->getImageView();
imageInfo.sampler = vkTexture->getSampler(); imageInfo.sampler = vkTexture->getSampler();
@@ -1448,8 +1489,8 @@ namespace love {
vkDestroyImageView(device, swapChainImageViews[i], nullptr); vkDestroyImageView(device, swapChainImageViews[i], nullptr);
} }
vkDestroySwapchainKHR(device, swapChain, nullptr); vkDestroySwapchainKHR(device, swapChain, nullptr);
uniformBuffers.clear(); uniformBufferMap.clear();
textureToDescriptorSetsMap.clear(); descriptorSetsMap.clear();
} }
void Graphics::recreateSwapChain() { void Graphics::recreateSwapChain() {
@@ -1461,7 +1502,6 @@ namespace love {
createImageViews(); createImageViews();
createRenderPass(); createRenderPass();
createFramebuffers(); createFramebuffers();
createUniformBuffers();
createDescriptorPool(); createDescriptorPool();
createCommandBuffers(); createCommandBuffers();
startRecordingGraphicsCommands(); startRecordingGraphicsCommands();
+18 -8
View File
@@ -65,8 +65,8 @@ namespace love {
void setBlendState(const BlendState& blend) override { std::cout << "setBlendState "; } void setBlendState(const BlendState& blend) override { std::cout << "setBlendState "; }
void setPointSize(float size) override { std::cout << "setPointSize "; } void setPointSize(float size) override { std::cout << "setPointSize "; }
void setWireframe(bool enable) override { std::cout << "setWireframe "; } void setWireframe(bool enable) override { std::cout << "setWireframe "; }
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override { std::cout << "getSizedFormat "; return format; } PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override { std::cout << "isPixelFormatSupported "; return true; } 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 { std::cout << "getRendererInfo "; return {}; }
@@ -87,6 +87,15 @@ namespace love {
friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other); 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:
@@ -112,8 +121,10 @@ namespace love {
} }
VkDescriptorSet* getDescriptorSet(int currentFrame); VkDescriptorSet* getDescriptorSet(int currentFrame);
graphics::StreamBuffer* getUniformBuffer();
std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap; std::vector<std::pair<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
struct BatchedDrawBuffers { struct BatchedDrawBuffers {
StreamBuffer* vertexBuffer1; StreamBuffer* vertexBuffer1;
@@ -129,7 +140,7 @@ namespace love {
} }
}; };
// we need an arrow of draw buffers, since the frames are being rendered asynchronously // 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. // 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; std::vector<BatchedDrawBuffers> batchedDrawBuffers;
void updatedBatchedDrawBuffers(); void updatedBatchedDrawBuffers();
@@ -173,9 +184,8 @@ namespace love {
void createRenderPass(); void createRenderPass();
void createDefaultShaders(); void createDefaultShaders();
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createUniformBuffers();
void createDescriptorPool(); void createDescriptorPool();
std::vector<VkDescriptorSet> createDescriptorSets(graphics::Texture* texture); std::vector<VkDescriptorSet> createDescriptorSets(DecriptorSetConfiguration);
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
void createFramebuffers(); void createFramebuffers();
void createCommandPool(); void createCommandPool();
@@ -189,7 +199,8 @@ namespace love {
void startRecordingGraphicsCommands(); void startRecordingGraphicsCommands();
void endRecordingGraphicsCommands(); void endRecordingGraphicsCommands();
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration);
void prepareDraw(uint32_t currentImage); graphics::StreamBuffer* createUniformBufferFromData(graphics::Shader::BuiltinUniformData);
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
VkInstance instance; VkInstance instance;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
@@ -211,7 +222,6 @@ namespace love {
VkCommandPool commandPool; VkCommandPool commandPool;
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}} };
std::vector<std::unique_ptr<StreamBuffer>> uniformBuffers;
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
std::vector<VkSemaphore> imageAvailableSemaphores; std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores; std::vector<VkSemaphore> renderFinishedSemaphores;
@@ -28,7 +28,6 @@ namespace love {
VmaAllocator allocator; VmaAllocator allocator;
VmaAllocation allocation; VmaAllocation allocation;
VmaAllocationInfo allocInfo; VmaAllocationInfo allocInfo;
VkDevice device;
VkBuffer buffer; VkBuffer buffer;
size_t usedGPUMemory; size_t usedGPUMemory;
+2
View File
@@ -171,6 +171,8 @@ namespace love {
} }
void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) { void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) {
format = pixelformat;
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VmaAllocation vmaAllocation; VmaAllocation vmaAllocation;
+1 -1
View File
@@ -23,7 +23,7 @@ namespace love {
ptrdiff_t getRenderTargetHandle() const override { std::cout << "Texture::getRenderTargetHandle "; return (ptrdiff_t)0; }; ptrdiff_t getRenderTargetHandle() const override { std::cout << "Texture::getRenderTargetHandle "; return (ptrdiff_t)0; };
ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; }; ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; };
void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) override; void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) override;
void generateMipmapsInternal() override { std::cout << "Texture::generateMipmapsInternal "; }; void generateMipmapsInternal() override { std::cout << "Texture::generateMipmapsInternal "; };
+12 -4
View File
@@ -163,12 +163,20 @@ namespace love {
textureFormat.internalFormat = VK_FORMAT_R32G32_UINT; textureFormat.internalFormat = VK_FORMAT_R32G32_UINT;
break; break;
case PIXELFORMAT_RGBA8_UNORM: case PIXELFORMAT_RGBA8_UNORM:
case PIXELFORMAT_RGBA8_UNORM_sRGB: // fixme ? textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; // fixme?
textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM; break;
case PIXELFORMAT_RGBA8_UNORM_sRGB:
textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;
break; break;
case PIXELFORMAT_BGRA8_UNORM: case PIXELFORMAT_BGRA8_UNORM:
case PIXELFORMAT_BGRA8_UNORM_sRGB: // fixme ? textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM;
textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM; textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B;
textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R;
break;
case PIXELFORMAT_BGRA8_UNORM_sRGB:
textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB;
textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B;
textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R;
break; break;
case PIXELFORMAT_RGBA8_INT: case PIXELFORMAT_RGBA8_INT:
textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT; textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT;