Implement drawing very basic textures

With this commit you can draw very simple textures.
The following code will showcase it:

```lua
function love.run()
    local data = love.image.newImageData(40, 40)
    for i = 0,39 do
        for j=0,39 do
            if i <= 20 then
                if j <= 20 then
                    data:setPixel(i, j, 1, 0, 0, 1)
                else
                    data:setPixel(i, j, 0, 1, 0, 1)
                end
            else
                if j <= 20 then
                    data:setPixel(i, j, 0, 0, 1, 1)
                else
                    data:setPixel(i, j, 1, 1, 1, 1)
                end
            end
        end
    end

    local texture
    texture = love.graphics.newTexture(data)

    return function()
        love.event.pump()
        for name, a,b,c,d,e,f in love.event.poll() do
            if name == "quit" then
                if not love.quit or not love.quit() then
                    return a or 0
                end
            end
            love.handlers[name](a,b,c,d,e,f)
        end

        love.graphics.origin()
        love.graphics.clear()

        love.graphics.draw(texture, 50, 500)

        love.graphics.present()
    end
end
```
This commit is contained in:
niki
2022-06-11 20:33:44 +02:00
parent 6c19e8c10a
commit acf0474cc8
4 changed files with 75 additions and 21 deletions
+7 -1
View File
@@ -436,20 +436,25 @@ static const char vulkan_vert[] = R"(
#version 450
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec2 iTexCoords;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 texCoords;
layout(binding = 0) uniform LoveUniforms {
float windowWidth;
float windowHeight;
} loveUniforms;
void main() {
gl_Position = vec4(
2 * inPosition.x / loveUniforms.windowWidth - 1,
2 * inPosition.y / loveUniforms.windowHeight - 1,
0.0, 1.0);
fragColor = vec4(1, 1, 1, 1);
texCoords = iTexCoords;
}
)";
@@ -457,13 +462,14 @@ static const char vulkan_pixel[] = R"(
#version 450
layout(location = 0) in vec4 fragColor;
layout(location = 1) in vec2 texCoords;
layout(location = 0) out vec4 outColor;
layout(binding = 1) uniform sampler2D texSampler;
void main() {
outColor = fragColor * texture(texSampler, vec2(0, 0));
outColor = fragColor * texture(texSampler, texCoords);
}
)";
+55 -16
View File
@@ -205,7 +205,6 @@ namespace love {
createUniformBuffers();
createDefaultTexture();
createDescriptorPool();
createDescriptorSets();
createSyncObjects();
startRecordingGraphicsCommands();
@@ -282,11 +281,24 @@ namespace love {
std::vector<VkBuffer> buffers;
std::vector<VkDeviceSize> offsets;
// vertices
buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle());
offsets.push_back((VkDeviceSize)0);
vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets.at(currentFrame), 0, nullptr);
vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, 1, buffers.data(), offsets.data());
// tex coords
buffers.push_back((VkBuffer)cmd.buffers->info[1].buffer->getHandle());
offsets.push_back((VkDeviceSize)0);
if (cmd.texture == nullptr) {
setTexture(standardTexture);
}
else {
setTexture(cmd.texture);
}
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());
vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, VK_INDEX_TYPE_UINT16);
vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), 1, 0, 0, 0);
}
@@ -298,6 +310,15 @@ namespace love {
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) {
auto it = textureToDescriptorSetsMap.find(currentTexture);
if (it == textureToDescriptorSetsMap.end()) {
textureToDescriptorSetsMap[currentTexture] = createDescriptorSets(currentTexture);
}
return &textureToDescriptorSetsMap.at(currentTexture)[currentFrame];
}
VkCommandBuffer Graphics::beginSingleTimeCommands() {
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -876,7 +897,7 @@ namespace love {
}
}
void Graphics::createDescriptorSets() {
std::vector<VkDescriptorSet> Graphics::createDescriptorSets(graphics::Texture* texture) {
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
@@ -884,26 +905,28 @@ namespace love {
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data();
descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
std::vector<VkDescriptorSet> newDescriptorSets;
newDescriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(device, &allocInfo, newDescriptorSets.data()) != VK_SUCCESS) {
throw love::Exception("failed to allocate descriptor sets");
}
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = (VkBuffer) uniformBuffers.at(i)->getHandle();
bufferInfo.buffer = (VkBuffer)uniformBuffers.at(i)->getHandle();
bufferInfo.offset = 0;
bufferInfo.range = sizeof(Shader::UniformBufferObject);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
Texture* vkTexture = (Texture*)standardTexture;
Texture* vkTexture = (Texture*)texture;
imageInfo.imageView = vkTexture->getImageView();
imageInfo.sampler = vkTexture->getSampler();
std::array<VkWriteDescriptorSet, 2> descriptorWrite{};
descriptorWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite[0].dstSet = descriptorSets[i];
descriptorWrite[0].dstSet = newDescriptorSets[i];
descriptorWrite[0].dstBinding = 0;
descriptorWrite[0].dstArrayElement = 0;
descriptorWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -911,7 +934,7 @@ namespace love {
descriptorWrite[0].pBufferInfo = &bufferInfo;
descriptorWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite[1].dstSet = descriptorSets[i];
descriptorWrite[1].dstSet = newDescriptorSets[i];
descriptorWrite[1].dstBinding = 1;
descriptorWrite[1].dstArrayElement = 0;
descriptorWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@@ -920,6 +943,8 @@ namespace love {
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
}
return newDescriptorSets;
}
void Graphics::createGraphicsPipeline() {
@@ -934,17 +959,30 @@ namespace love {
vertexBindingDescription.stride = 2 * sizeof(float); // just position for now
vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
// todo later
VkVertexInputAttributeDescription positionInputAttributeDescription;
positionInputAttributeDescription.binding = 0;
positionInputAttributeDescription.location = 0;
positionInputAttributeDescription.format = VK_FORMAT_R32G32_SFLOAT;
positionInputAttributeDescription.offset = 0;
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &positionInputAttributeDescription;
VkVertexInputBindingDescription texCoordsBindingDescription;
texCoordsBindingDescription.binding = 1;
texCoordsBindingDescription.stride = 3 * sizeof(float); // 2 floats for texture coordinates, 1 float for color
texCoordsBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription texCoordsInputAttributeDescription;
texCoordsInputAttributeDescription.binding = 1;
texCoordsInputAttributeDescription.location = 1;
texCoordsInputAttributeDescription.format = VK_FORMAT_R32G32_SFLOAT;
texCoordsInputAttributeDescription.offset = 0;
std::vector<VkVertexInputBindingDescription> bindingDescriptions = { vertexBindingDescription, texCoordsBindingDescription };
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions = { positionInputAttributeDescription, texCoordsInputAttributeDescription };
vertexInputInfo.vertexBindingDescriptionCount = bindingDescriptions.size();
vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.data();
vertexInputInfo.vertexAttributeDescriptionCount = vertexInputAttributeDescriptions.size();
vertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions.data();
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
@@ -1119,6 +1157,7 @@ namespace love {
void Graphics::cleanup() {
vkDeviceWaitIdle(device);
cleanupSwapChain();
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
@@ -1149,6 +1188,7 @@ namespace love {
}
vkDestroySwapchainKHR(device, swapChain, nullptr);
uniformBuffers.clear();
textureToDescriptorSetsMap.clear();
}
void Graphics::recreateSwapChain() {
@@ -1163,7 +1203,6 @@ namespace love {
createFramebuffers();
createUniformBuffers();
createDescriptorPool();
createDescriptorSets();
createCommandBuffers();
startRecordingGraphicsCommands();
}
+11 -2
View File
@@ -96,6 +96,16 @@ namespace love {
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; }
private:
graphics::Texture* currentTexture;
void setTexture(graphics::Texture* texture) {
currentTexture = texture;
}
VkDescriptorSet* getDescriptorSet(int currentFrame);
std::unordered_map<graphics::Texture*, std::vector<VkDescriptorSet>> textureToDescriptorSetsMap;
// vulkan specific member functions and variables
struct QueueFamilyIndices {
@@ -133,7 +143,7 @@ namespace love {
void createDescriptorSetLayout();
void createUniformBuffers();
void createDescriptorPool();
void createDescriptorSets();
std::vector<VkDescriptorSet> createDescriptorSets(graphics::Texture* texture);
void createGraphicsPipeline();
void createFramebuffers();
void createCommandPool();
@@ -170,7 +180,6 @@ namespace love {
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
std::vector<std::unique_ptr<StreamBuffer>> uniformBuffers;
VkDescriptorPool descriptorPool;
std::vector<VkDescriptorSet> descriptorSets;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences;
+2 -2
View File
@@ -22,12 +22,12 @@ namespace love {
rect.w = sliceData->getWidth();
rect.h = sliceData->getHeight();
uploadByteData(PIXELFORMAT_BGRA8_UNORM, dataPtr, size, 0, 0, rect);
uploadByteData(PIXELFORMAT_RGBA8_UNORM, dataPtr, size, 0, 0, rect);
}
else {
uint8 defaultPixel[] = { 255, 255, 255, 255 };
Rect rect = { 0, 0, 1, 1 };
uploadByteData(PIXELFORMAT_BGRA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
}
createTextureImageView();
createTextureSampler();