Problem rendering to a texture

Hi! I’ve written a class to render to a texture. I’ve changed the render pass and framebuffer to render to the image I’ve also removed the present queue and the surface. I also removed the synchronization primitives. Here’s the code.

RenderTexture::RenderTexture(window::VkSettup& vkSettup) : RenderTarget(vkSettup), vkSettup(vkSettup), m_texture(vkSettup) {
        }
        RenderTexture::~RenderTexture() {
        }
        bool RenderTexture::create(unsigned int width, unsigned int height) {
            RenderTarget::initialize();
            m_texture.create(width, height);
            createRenderPass();
            createFramebuffers();
            createSyncObjects();
            m_size.x = width;
            m_size.y = height;
        }
        VkSurfaceKHR RenderTexture::getSurface() {
            return nullptr;
        }
        VkExtent2D RenderTexture::getSwapchainExtents() {
            VkExtent2D actualExtent = {
                static_cast<uint32_t>(m_texture.getSize().x),
                static_cast<uint32_t>(m_texture.getSize().y)
            };
            return actualExtent;
        }
        VkFormat RenderTexture::getSwapchainImageFormat() {
            return m_texture.getFormat();
        }
        std::vector<VkImage> RenderTexture::getSwapchainImages() {
            std::vector<VkImage> images;
            images.push_back(m_texture.getImage());
            return images;
        }
        size_t RenderTexture::getCurrentFrame() {
            return 0;
        }
        const int RenderTexture::getMaxFramesInFlight() {
            return 1;
        }
        const Texture& RenderTexture::getTexture() const {
            return m_texture;
        }
        sf::Vector2u RenderTexture::getSize() const {
            return m_size;
        }
        void RenderTexture::createFramebuffers() {
            swapChainFramebuffers.resize(getSwapchainImages().size());
            for (size_t i = 0; i < getSwapchainImages().size(); i++) {
                VkImageView attachments[] = {
                    m_texture.getImageView()
                };

                VkFramebufferCreateInfo framebufferInfo{};
                framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
                framebufferInfo.renderPass = renderPass;
                framebufferInfo.attachmentCount = 1;
                framebufferInfo.pAttachments = attachments;
                framebufferInfo.width = getSwapchainExtents().width;
                framebufferInfo.height = getSwapchainExtents().height;
                framebufferInfo.layers = 1;

                if (vkCreateFramebuffer(vkSettup.getDevice(), &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
                    throw core::Erreur(0, "failed to create framebuffer!", 1);
                }
            }
        }
        void RenderTexture::createRenderPass() {
            VkAttachmentDescription colorAttachment{};
            colorAttachment.format =    getSwapchainImageFormat();
            colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
            colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
            colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
            colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
            colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
            colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
            colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

            VkAttachmentReference colorAttachmentRef{};
            colorAttachmentRef.attachment = 0;
            colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

            VkSubpassDescription subpass{};
            subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
            subpass.colorAttachmentCount = 1;
            subpass.pColorAttachments = &colorAttachmentRef;

            VkRenderPassCreateInfo renderPassInfo{};
            renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
            renderPassInfo.attachmentCount = 1;
            renderPassInfo.pAttachments = &colorAttachment;
            renderPassInfo.subpassCount = 1;
            renderPassInfo.pSubpasses = &subpass;
            VkSubpassDependency dependency{};
            dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
            dependency.dstSubpass = 0;
            dependency.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
            dependency.srcAccessMask = VK_ACCESS_NONE_KHR;
            dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
            dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            renderPassInfo.dependencyCount = 1;
            renderPassInfo.pDependencies = &dependency;
            if (vkCreateRenderPass(vkSettup.getDevice(), &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
                throw core::Erreur(0, "failed to create render pass!", 1);
            }

        }
        void RenderTexture::createSyncObjects() {
            imageAvailableSemaphores.resize(getMaxFramesInFlight());
            renderFinishedSemaphores.resize(getMaxFramesInFlight());
            inFlightFences.resize(getMaxFramesInFlight());
            VkSemaphoreCreateInfo semaphoreInfo{};
            semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

            VkFenceCreateInfo fenceInfo{};
            fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
            fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;

            for (size_t i = 0; i < getMaxFramesInFlight(); i++) {
                if (vkCreateSemaphore(vkSettup.getDevice(), &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
                    vkCreateSemaphore(vkSettup.getDevice(), &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
                    vkCreateFence(vkSettup.getDevice(), &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {

                    throw core::Erreur(0, "échec de la création des objets de synchronisation pour une frame!", 1);
                }
            }
        }
        void RenderTexture::display() {
            if (getCommandBuffers().size() > 0) {
                //vkWaitForFences(vkSettup.getDevice(), 1, &inFlightFences[getCurrentFrame()], VK_TRUE, UINT64_MAX);
                VkSubmitInfo submitInfo{};
                submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;


                submitInfo.commandBufferCount = 1;
                submitInfo.pCommandBuffers = &getCommandBuffers()[getCurrentFrame()];
                //vkResetFences(vkSettup.getDevice(), 1, &inFlightFences[getCurrentFrame()]);
                if (vkQueueSubmit(vkSettup.getGraphicQueue(), 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
                    throw core::Erreur(0, "échec de l'envoi d'un command buffer!", 1);
                }
                vkDeviceWaitIdle(vkSettup.getDevice());
            }
        }

But when I want to draw to the texture the texture is empty :

When I draw on the window directly it works but when I want to draw to the render texture it fails.
Here’s the main.

int main() {    
    VkSettup vkSettup;
    RenderWindow rw(sf::VideoMode(800, 600), "test vulkan", vkSettup);
    RenderTexture rt(vkSettup);
    rt.create(800, 600);
    VertexArray va;
    va.append(Vertex(sf::Vector3f(0, 0, 0), sf::Color::Red, sf::Vector2f(0.f, 0.f)));
    va.append(Vertex(sf::Vector3f(100, 0, 0), sf::Color::Blue, sf::Vector2f(1.f, 0.f)));
    va.append(Vertex(sf::Vector3f(100, 50, 0), sf::Color::Green, sf::Vector2f(1.f, 1.f)));
    va.append(Vertex(sf::Vector3f(0, 50, 0), sf::Color::White, sf::Vector2f(0.f, 1.f)));
    va.addIndex(0);
    va.addIndex(1);
    va.addIndex(2);
    va.addIndex(2);
    va.addIndex(3);
    va.addIndex(0);
    Texture texture(vkSettup);

    texture.loadFromFile("tilesets/eau.png");
    RenderStates states;
    states.texture = &texture;
    rt.getView().move(-400, -300, 0);
    rt.draw(va, states);
    rt.display();
    VertexArray va2;
    va2.append(Vertex(sf::Vector3f(0, 0, 0), sf::Color::Red, sf::Vector2f(0.f, 0.f)));
    va2.append(Vertex(sf::Vector3f(800, 0, 0), sf::Color::Blue, sf::Vector2f(1.f, 0.f)));
    va2.append(Vertex(sf::Vector3f(800, 600, 0), sf::Color::Green, sf::Vector2f(1.f, 1.f)));
    va2.append(Vertex(sf::Vector3f(0, 600, 0), sf::Color::White, sf::Vector2f(0.f, 1.f)));
    va2.addIndex(0);
    va2.addIndex(1);
    va2.addIndex(2);
    va2.addIndex(2);
    va2.addIndex(3);
    va2.addIndex(0);
    states.texture = &rt.getTexture();
    while (true) {
        rw.draw(va2, states);
        rw.display();
    }

}

And here is the class to create the texture :

void Texture::createImage(uint32_t texWidth, uint32_t texHeight, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
            VkImageCreateInfo imageInfo{};
            imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
            imageInfo.imageType = VK_IMAGE_TYPE_2D;
            imageInfo.extent.width = static_cast<uint32_t>(texWidth);
            imageInfo.extent.height = static_cast<uint32_t>(texHeight);
            imageInfo.extent.depth = 1;
            imageInfo.mipLevels = 1;
            imageInfo.arrayLayers = 1;
            imageInfo.format = format;
            imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
            imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

            imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
            imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
            imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
            imageInfo.flags = 0; // Optionnel
            if (vkCreateImage(vkSettup.getDevice(), &imageInfo, nullptr, &textureImage) != VK_SUCCESS) {
                throw std::runtime_error("echec de la creation d'une image!");
            }
            VkMemoryRequirements memRequirements;
            vkGetImageMemoryRequirements(vkSettup.getDevice(), image, &memRequirements);

            VkMemoryAllocateInfo allocInfo{};
            allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
            allocInfo.allocationSize = memRequirements.size;
            allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);

            if (vkAllocateMemory(vkSettup.getDevice(), &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
                throw std::runtime_error("echec de l'allocation de la memoire d'une image!");
            }

            vkBindImageMemory(vkSettup.getDevice(), image, imageMemory, 0);
            m_size.x = texWidth;
            m_size.y = texHeight;
            m_format = format;
        }

Have I forgot something ?

Thanks.