// Copyright 2021 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef DRAW_TESTER_HPP_ #define DRAW_TESTER_HPP_ #include "Framebuffer.hpp" #include "Image.hpp" #include "Swapchain.hpp" #include "Util.hpp" #include "VulkanTester.hpp" #include "Window.hpp" enum class Multisample { False, True }; class DrawTester : public VulkanTester { public: using ThisType = DrawTester; DrawTester(Multisample multisample = Multisample::False); ~DrawTester(); void initialize(); void renderFrame(); void show(); ///////////////////////// // Hooks ///////////////////////// // Called from prepareVertices. // Callback may call tester.addVertexBuffer() from this function. void onCreateVertexBuffers(std::function callback); // Called from createGraphicsPipeline. // Callback must return vector of DescriptorSetLayoutBindings for which a DescriptorSetLayout // will be created and stored in this->descriptorSetLayout. void onCreateDescriptorSetLayouts(std::function(ThisType &tester)> callback); // Called from createGraphicsPipeline. // Callback should call tester.createShaderModule() and return the result. void onCreateVertexShader(std::function callback); // Called from createGraphicsPipeline. // Callback should call tester.createShaderModule() and return the result. void onCreateFragmentShader(std::function callback); // Called from createCommandBuffers. // Callback may create resources (tester.addImage, tester.addSampler, etc.), and make sure to // call tester.device().updateDescriptorSets. void onUpdateDescriptorSet(std::function callback); ///////////////////////// // Resource Management ///////////////////////// // Call from doCreateFragmentShader() vk::ShaderModule createShaderModule(const char *glslSource, EShLanguage glslLanguage); // Call from doCreateVertexBuffers() template void addVertexBuffer(VertexType *vertexBufferData, size_t vertexBufferDataSize, std::vector inputAttributes) { addVertexBuffer(vertexBufferData, vertexBufferDataSize, sizeof(VertexType), std::move(inputAttributes)); } template struct Resource { size_t id; T &obj; }; template Resource addImage(Args &&... args) { images.emplace_back(std::make_unique(std::forward(args)...)); return { images.size() - 1, *images.back() }; } Image &getImageById(size_t id) { return *images[id].get(); } Resource addSampler(const vk::SamplerCreateInfo &samplerCreateInfo) { auto sampler = device.createSampler(samplerCreateInfo); samplers.push_back(sampler); return { samplers.size() - 1, samplers.back() }; } vk::Sampler &getSamplerById(size_t id) { return samplers[id]; } private: void createSynchronizationPrimitives(); void createCommandBuffers(vk::RenderPass renderPass); void prepareVertices(); void createFramebuffers(vk::RenderPass renderPass); vk::RenderPass createRenderPass(vk::Format colorFormat); vk::Pipeline createGraphicsPipeline(vk::RenderPass renderPass); void addVertexBuffer(void *vertexBufferData, size_t vertexBufferDataSize, size_t vertexSize, std::vector inputAttributes); struct Hook { std::function createVertexBuffers = [](auto &) {}; std::function(ThisType &tester)> createDescriptorSetLayout = [](auto &) { return std::vector{}; }; std::function createVertexShader = [](auto &) { return vk::ShaderModule{}; }; std::function createFragmentShader = [](auto &) { return vk::ShaderModule{}; }; std::function updateDescriptorSet = [](auto &, auto &, auto &) {}; } hooks; const vk::Extent2D windowSize = { 1280, 720 }; const bool multisample; std::unique_ptr window; std::unique_ptr swapchain; vk::RenderPass renderPass; // Owning handle std::vector> framebuffers; uint32_t currentFrameBuffer = 0; struct VertexBuffer { vk::Buffer buffer; // Owning handle vk::DeviceMemory memory; // Owning handle vk::VertexInputBindingDescription inputBinding; std::vector inputAttributes; vk::PipelineVertexInputStateCreateInfo inputState; uint32_t numVertices = 0; } vertices; vk::DescriptorSetLayout descriptorSetLayout; // Owning handle vk::PipelineLayout pipelineLayout; // Owning handle vk::Pipeline pipeline; // Owning handle vk::Semaphore presentCompleteSemaphore; // Owning handle vk::Semaphore renderCompleteSemaphore; // Owning handle std::vector waitFences; // Owning handles vk::CommandPool commandPool; // Owning handle vk::DescriptorPool descriptorPool; // Owning handle // Resources std::vector> images; std::vector samplers; // Owning handles std::vector commandBuffers; // Owning handles }; inline void DrawTester::onCreateVertexBuffers(std::function callback) { hooks.createVertexBuffers = std::move(callback); } inline void DrawTester::onCreateDescriptorSetLayouts(std::function(ThisType &tester)> callback) { hooks.createDescriptorSetLayout = std::move(callback); } inline void DrawTester::onCreateVertexShader(std::function callback) { hooks.createVertexShader = std::move(callback); } inline void DrawTester::onCreateFragmentShader(std::function callback) { hooks.createFragmentShader = std::move(callback); } inline void DrawTester::onUpdateDescriptorSet(std::function callback) { hooks.updateDescriptorSet = std::move(callback); } #endif // DRAW_TESTER_HPP_