1 // Copyright 2021 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef DRAW_TESTER_HPP_
16 #define DRAW_TESTER_HPP_
17
18 #include "Framebuffer.hpp"
19 #include "Image.hpp"
20 #include "Swapchain.hpp"
21 #include "Util.hpp"
22 #include "VulkanTester.hpp"
23 #include "Window.hpp"
24
25 enum class Multisample
26 {
27 False,
28 True
29 };
30
31 class DrawTester : public VulkanTester
32 {
33 public:
34 using ThisType = DrawTester;
35
36 DrawTester(Multisample multisample = Multisample::False);
37 ~DrawTester();
38
39 void initialize();
40 void renderFrame();
41 void show();
42
43 /////////////////////////
44 // Hooks
45 /////////////////////////
46
47 // Called from prepareVertices.
48 // Callback may call tester.addVertexBuffer() from this function.
49 void onCreateVertexBuffers(std::function<void(ThisType &tester)> callback);
50
51 // Called from createGraphicsPipeline.
52 // Callback must return vector of DescriptorSetLayoutBindings for which a DescriptorSetLayout
53 // will be created and stored in this->descriptorSetLayout.
54 void onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> callback);
55
56 // Called from createGraphicsPipeline.
57 // Callback should call tester.createShaderModule() and return the result.
58 void onCreateVertexShader(std::function<vk::ShaderModule(ThisType &tester)> callback);
59
60 // Called from createGraphicsPipeline.
61 // Callback should call tester.createShaderModule() and return the result.
62 void onCreateFragmentShader(std::function<vk::ShaderModule(ThisType &tester)> callback);
63
64 // Called from createCommandBuffers.
65 // Callback may create resources (tester.addImage, tester.addSampler, etc.), and make sure to
66 // call tester.device().updateDescriptorSets.
67 void onUpdateDescriptorSet(std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> callback);
68
69 /////////////////////////
70 // Resource Management
71 /////////////////////////
72
73 // Call from doCreateFragmentShader()
74 vk::ShaderModule createShaderModule(const char *glslSource, EShLanguage glslLanguage);
75
76 // Call from doCreateVertexBuffers()
77 template<typename VertexType>
addVertexBuffer(VertexType * vertexBufferData,size_t vertexBufferDataSize,std::vector<vk::VertexInputAttributeDescription> inputAttributes)78 void addVertexBuffer(VertexType *vertexBufferData, size_t vertexBufferDataSize, std::vector<vk::VertexInputAttributeDescription> inputAttributes)
79 {
80 addVertexBuffer(vertexBufferData, vertexBufferDataSize, sizeof(VertexType), std::move(inputAttributes));
81 }
82
83 template<typename T>
84 struct Resource
85 {
86 size_t id;
87 T &obj;
88 };
89
90 template<typename... Args>
addImage(Args &&...args)91 Resource<Image> addImage(Args &&... args)
92 {
93 images.emplace_back(std::make_unique<Image>(std::forward<Args>(args)...));
94 return { images.size() - 1, *images.back() };
95 }
96
getImageById(size_t id)97 Image &getImageById(size_t id)
98 {
99 return *images[id].get();
100 }
101
addSampler(const vk::SamplerCreateInfo & samplerCreateInfo)102 Resource<vk::Sampler> addSampler(const vk::SamplerCreateInfo &samplerCreateInfo)
103 {
104 auto sampler = device.createSampler(samplerCreateInfo);
105 samplers.push_back(sampler);
106 return { samplers.size() - 1, samplers.back() };
107 }
108
getSamplerById(size_t id)109 vk::Sampler &getSamplerById(size_t id)
110 {
111 return samplers[id];
112 }
113
114 private:
115 void createSynchronizationPrimitives();
116 void createCommandBuffers(vk::RenderPass renderPass);
117 void prepareVertices();
118 void createFramebuffers(vk::RenderPass renderPass);
119 vk::RenderPass createRenderPass(vk::Format colorFormat);
120 vk::Pipeline createGraphicsPipeline(vk::RenderPass renderPass);
121 void addVertexBuffer(void *vertexBufferData, size_t vertexBufferDataSize, size_t vertexSize, std::vector<vk::VertexInputAttributeDescription> inputAttributes);
122
123 struct Hook
124 {
__anoncf6d42890102DrawTester::Hook125 std::function<void(ThisType &tester)> createVertexBuffers = [](auto &) {};
__anoncf6d42890202DrawTester::Hook126 std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> createDescriptorSetLayout = [](auto &) { return std::vector<vk::DescriptorSetLayoutBinding>{}; };
__anoncf6d42890302DrawTester::Hook127 std::function<vk::ShaderModule(ThisType &tester)> createVertexShader = [](auto &) { return vk::ShaderModule{}; };
__anoncf6d42890402DrawTester::Hook128 std::function<vk::ShaderModule(ThisType &tester)> createFragmentShader = [](auto &) { return vk::ShaderModule{}; };
__anoncf6d42890502DrawTester::Hook129 std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> updateDescriptorSet = [](auto &, auto &, auto &) {};
130 } hooks;
131
132 const vk::Extent2D windowSize = { 1280, 720 };
133 const bool multisample;
134
135 std::unique_ptr<Window> window;
136 std::unique_ptr<Swapchain> swapchain;
137
138 vk::RenderPass renderPass; // Owning handle
139 std::vector<std::unique_ptr<Framebuffer>> framebuffers;
140 uint32_t currentFrameBuffer = 0;
141
142 struct VertexBuffer
143 {
144 vk::Buffer buffer; // Owning handle
145 vk::DeviceMemory memory; // Owning handle
146
147 vk::VertexInputBindingDescription inputBinding;
148 std::vector<vk::VertexInputAttributeDescription> inputAttributes;
149 vk::PipelineVertexInputStateCreateInfo inputState;
150
151 uint32_t numVertices = 0;
152 } vertices;
153
154 vk::DescriptorSetLayout descriptorSetLayout; // Owning handle
155 vk::PipelineLayout pipelineLayout; // Owning handle
156 vk::Pipeline pipeline; // Owning handle
157
158 vk::Semaphore presentCompleteSemaphore; // Owning handle
159 vk::Semaphore renderCompleteSemaphore; // Owning handle
160 std::vector<vk::Fence> waitFences; // Owning handles
161
162 vk::CommandPool commandPool; // Owning handle
163 vk::DescriptorPool descriptorPool; // Owning handle
164
165 // Resources
166 std::vector<std::unique_ptr<Image>> images;
167 std::vector<vk::Sampler> samplers; // Owning handles
168
169 std::vector<vk::CommandBuffer> commandBuffers; // Owning handles
170 };
171
onCreateVertexBuffers(std::function<void (ThisType & tester)> callback)172 inline void DrawTester::onCreateVertexBuffers(std::function<void(ThisType &tester)> callback)
173 {
174 hooks.createVertexBuffers = std::move(callback);
175 }
176
onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding> (ThisType & tester)> callback)177 inline void DrawTester::onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> callback)
178 {
179 hooks.createDescriptorSetLayout = std::move(callback);
180 }
181
onCreateVertexShader(std::function<vk::ShaderModule (ThisType & tester)> callback)182 inline void DrawTester::onCreateVertexShader(std::function<vk::ShaderModule(ThisType &tester)> callback)
183 {
184 hooks.createVertexShader = std::move(callback);
185 }
186
onCreateFragmentShader(std::function<vk::ShaderModule (ThisType & tester)> callback)187 inline void DrawTester::onCreateFragmentShader(std::function<vk::ShaderModule(ThisType &tester)> callback)
188 {
189 hooks.createFragmentShader = std::move(callback);
190 }
191
onUpdateDescriptorSet(std::function<void (ThisType & tester,vk::CommandPool & commandPool,vk::DescriptorSet & descriptorSet)> callback)192 inline void DrawTester::onUpdateDescriptorSet(std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> callback)
193 {
194 hooks.updateDescriptorSet = std::move(callback);
195 }
196
197 #endif // DRAW_TESTER_HPP_
198