mirror of
https://github.com/love2d/love.git
synced 2026-08-20 12:40:20 +02:00
allow drawing more than one texture
This commit is contained in:
@@ -17,6 +17,15 @@
|
|||||||
namespace love {
|
namespace love {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
namespace vulkan {
|
namespace vulkan {
|
||||||
|
static VkIndexType getVulkanIndexBufferType(IndexDataType type) {
|
||||||
|
switch (type) {
|
||||||
|
case INDEX_UINT16: return VK_INDEX_TYPE_UINT16;
|
||||||
|
case INDEX_UINT32: return VK_INDEX_TYPE_UINT32;
|
||||||
|
default:
|
||||||
|
throw love::Exception("unknown Index Data type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<const char*> validationLayers = {
|
const std::vector<const char*> validationLayers = {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
};
|
};
|
||||||
@@ -171,11 +180,12 @@ namespace love {
|
|||||||
else if (result != VK_SUCCESS) {
|
else if (result != VK_SUCCESS) {
|
||||||
throw love::Exception("failed to present swap chain image");
|
throw love::Exception("failed to present swap chain image");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "present" << std::endl;
|
||||||
|
|
||||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
std::cout << "present" << std::endl;
|
updatedBatchedDrawBuffers();
|
||||||
|
|
||||||
startRecordingGraphicsCommands();
|
startRecordingGraphicsCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,18 +217,23 @@ namespace love {
|
|||||||
createDescriptorPool();
|
createDescriptorPool();
|
||||||
createSyncObjects();
|
createSyncObjects();
|
||||||
startRecordingGraphicsCommands();
|
startRecordingGraphicsCommands();
|
||||||
|
currentFrame = 0;
|
||||||
|
|
||||||
created = true;
|
created = true;
|
||||||
|
|
||||||
if (batchedDrawState.vb[0] == nullptr)
|
batchedDrawBuffers.clear();
|
||||||
{
|
batchedDrawBuffers.reserve(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
|
batchedDrawBuffers.emplace_back();
|
||||||
// Initial sizes that should be good enough for most cases. It will
|
// Initial sizes that should be good enough for most cases. It will
|
||||||
// resize to fit if needed, later.
|
// resize to fit if needed, later.
|
||||||
batchedDrawState.vb[0] = new StreamBuffer(vmaAllocator, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
batchedDrawBuffers[i].vertexBuffer1 = new StreamBuffer(vmaAllocator, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||||
batchedDrawState.vb[1] = new StreamBuffer(vmaAllocator, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
batchedDrawBuffers[i].vertexBuffer2 = new StreamBuffer(vmaAllocator, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||||
batchedDrawState.indexBuffer = new StreamBuffer(vmaAllocator, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
batchedDrawBuffers[i].indexBuffer = new StreamBuffer(vmaAllocator, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatedBatchedDrawBuffers();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,10 +285,10 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::unSetMode() {
|
void Graphics::unSetMode() {
|
||||||
|
std::cout << "unSetMode ";
|
||||||
|
|
||||||
created = false;
|
created = false;
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
std::cout << "unSetMode ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::draw(const DrawIndexedCommand& cmd) {
|
void Graphics::draw(const DrawIndexedCommand& cmd) {
|
||||||
@@ -284,11 +299,11 @@ namespace love {
|
|||||||
|
|
||||||
// vertices
|
// vertices
|
||||||
buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle());
|
buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle());
|
||||||
offsets.push_back((VkDeviceSize)0);
|
offsets.push_back((VkDeviceSize)cmd.buffers->info[0].offset);
|
||||||
|
|
||||||
// tex coords
|
// tex coords
|
||||||
buffers.push_back((VkBuffer)cmd.buffers->info[1].buffer->getHandle());
|
buffers.push_back((VkBuffer)cmd.buffers->info[1].buffer->getHandle());
|
||||||
offsets.push_back((VkDeviceSize)0);
|
offsets.push_back((VkDeviceSize)cmd.buffers->info[1].offset);
|
||||||
|
|
||||||
if (cmd.texture == nullptr) {
|
if (cmd.texture == nullptr) {
|
||||||
setTexture(standardTexture);
|
setTexture(standardTexture);
|
||||||
@@ -299,7 +314,7 @@ namespace love {
|
|||||||
|
|
||||||
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr);
|
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 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, VK_INDEX_TYPE_UINT16);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +325,15 @@ namespace love {
|
|||||||
|
|
||||||
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
||||||
|
|
||||||
|
void Graphics::updatedBatchedDrawBuffers() {
|
||||||
|
batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1;
|
||||||
|
batchedDrawState.vb[0]->nextFrame();
|
||||||
|
batchedDrawState.vb[1] = batchedDrawBuffers[currentFrame].vertexBuffer2;
|
||||||
|
batchedDrawState.vb[1]->nextFrame();
|
||||||
|
batchedDrawState.indexBuffer = batchedDrawBuffers[currentFrame].indexBuffer;
|
||||||
|
batchedDrawState.indexBuffer->nextFrame();
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
|
VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
|
||||||
auto it = textureToDescriptorSetsMap.find(currentTexture);
|
auto it = textureToDescriptorSetsMap.find(currentTexture);
|
||||||
if (it == textureToDescriptorSetsMap.end()) {
|
if (it == textureToDescriptorSetsMap.end()) {
|
||||||
@@ -890,7 +914,8 @@ namespace love {
|
|||||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
||||||
poolInfo.pPoolSizes = poolSizes.data();
|
poolInfo.pPoolSizes = poolSizes.data();
|
||||||
poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
// FIXME: When using more than 128 textures at once we will run out of memory.
|
||||||
|
poolInfo.maxSets = 128 * static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
|
||||||
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
|
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
|
||||||
throw love::Exception("failed to create descriptor pool");
|
throw love::Exception("failed to create descriptor pool");
|
||||||
@@ -908,8 +933,20 @@ namespace love {
|
|||||||
std::vector<VkDescriptorSet> newDescriptorSets;
|
std::vector<VkDescriptorSet> newDescriptorSets;
|
||||||
|
|
||||||
newDescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
newDescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
if (vkAllocateDescriptorSets(device, &allocInfo, newDescriptorSets.data()) != VK_SUCCESS) {
|
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, newDescriptorSets.data());
|
||||||
throw love::Exception("failed to allocate descriptor sets");
|
if (result != VK_SUCCESS) {
|
||||||
|
switch (result) {
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||||
|
throw love::Exception("failed to allocate descriptor sets: out of host memory");
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||||
|
throw love::Exception("failed to allocate descriptor sets: out of device memory");
|
||||||
|
case VK_ERROR_FRAGMENTED_POOL:
|
||||||
|
throw love::Exception("failed to allocate descriptor sets: fragmented pool");
|
||||||
|
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
||||||
|
throw love::Exception("failed to allocate descriptor sets: out of pool memory");
|
||||||
|
default:
|
||||||
|
throw love::Exception("failed to allocate descriptor sets");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
@@ -1157,7 +1194,6 @@ namespace love {
|
|||||||
void Graphics::cleanup() {
|
void Graphics::cleanup() {
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
|
||||||
cleanupSwapChain();
|
cleanupSwapChain();
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
@@ -1176,6 +1212,8 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::cleanupSwapChain() {
|
void Graphics::cleanupSwapChain() {
|
||||||
|
std::cout << "cleanupSwapChain ";
|
||||||
|
|
||||||
for (size_t i = 0; i < swapChainFramBuffers.size(); i++) {
|
for (size_t i = 0; i < swapChainFramBuffers.size(); i++) {
|
||||||
vkDestroyFramebuffer(device, swapChainFramBuffers[i], nullptr);
|
vkDestroyFramebuffer(device, swapChainFramBuffers[i], nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,23 @@ namespace love {
|
|||||||
|
|
||||||
std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap;
|
std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap;
|
||||||
|
|
||||||
|
struct BatchedDrawBuffers {
|
||||||
|
StreamBuffer* vertexBuffer1;
|
||||||
|
StreamBuffer* vertexBuffer2;
|
||||||
|
StreamBuffer* indexBuffer;
|
||||||
|
|
||||||
|
~BatchedDrawBuffers() {
|
||||||
|
delete vertexBuffer1;
|
||||||
|
delete vertexBuffer2;
|
||||||
|
delete indexBuffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// we need an arrow 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();
|
||||||
|
|
||||||
// vulkan specific member functions and variables
|
// vulkan specific member functions and variables
|
||||||
|
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StreamBuffer::StreamBuffer(VmaAllocator allocator, BufferUsage mode, size_t size)
|
StreamBuffer::StreamBuffer(VmaAllocator allocator, BufferUsage mode, size_t size)
|
||||||
: love::graphics::StreamBuffer(mode, size) {
|
: love::graphics::StreamBuffer(mode, size), allocator(allocator) {
|
||||||
VkBufferCreateInfo bufferInfo{};
|
VkBufferCreateInfo bufferInfo{};
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
bufferInfo.size = getSize();
|
bufferInfo.size = getSize();
|
||||||
@@ -29,24 +29,29 @@ namespace love {
|
|||||||
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; // always mapped
|
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; // always mapped
|
||||||
|
|
||||||
vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo);
|
vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo);
|
||||||
|
|
||||||
|
usedGPUMemory = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamBuffer::~StreamBuffer() {
|
StreamBuffer::~StreamBuffer() {
|
||||||
// vmaDestroyBuffer(allocator, buffer, allocation);
|
// vmaDestroyBuffer(allocator, buffer, allocation);
|
||||||
// vmaDestroyAllocator(allocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) {
|
love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) {
|
||||||
(void)minsize;
|
(void)minsize;
|
||||||
return love::graphics::StreamBuffer::MapInfo((uint8*) allocInfo.pMappedData, getSize());
|
return love::graphics::StreamBuffer::MapInfo((uint8*) allocInfo.pMappedData + usedGPUMemory, getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t StreamBuffer::unmap(size_t usedSize) {
|
size_t StreamBuffer::unmap(size_t usedSize) {
|
||||||
return usedSize;
|
return usedGPUMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamBuffer::markUsed(size_t usedSize) {
|
void StreamBuffer::markUsed(size_t usedSize) {
|
||||||
(void)usedSize;
|
usedGPUMemory += usedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamBuffer::nextFrame() {
|
||||||
|
usedGPUMemory = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ namespace love {
|
|||||||
size_t unmap(size_t usedSize) override;
|
size_t unmap(size_t usedSize) override;
|
||||||
void markUsed(size_t usedSize) override;
|
void markUsed(size_t usedSize) override;
|
||||||
|
|
||||||
|
void nextFrame() override;
|
||||||
|
|
||||||
ptrdiff_t getHandle() const override {
|
ptrdiff_t getHandle() const override {
|
||||||
return (ptrdiff_t) buffer;
|
return (ptrdiff_t) buffer;
|
||||||
}
|
}
|
||||||
@@ -28,6 +30,8 @@ namespace love {
|
|||||||
VmaAllocationInfo allocInfo;
|
VmaAllocationInfo allocInfo;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
|
size_t usedGPUMemory;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user