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 #include <functional>
26 #include <memory>
27
28 enum class Multisample
29 {
30 False,
31 True
32 };
33
34 class DrawTester : public VulkanTester
35 {
36 public:
37 using ThisType = DrawTester;
38
39 DrawTester(Multisample multisample = Multisample::False);
40 ~DrawTester();
41
42 void initialize();
43 void renderFrame();
44 void show();
45
46 /////////////////////////
47 // Hooks
48 /////////////////////////
49
50 // Called from prepareVertices.
51 // Callback may call tester.addVertexBuffer() from this function.
52 void onCreateVertexBuffers(std::function<void(ThisType &tester)> callback);
53
54 // Called from createGraphicsPipeline.
55 // Callback must return vector of DescriptorSetLayoutBindings for which a DescriptorSetLayout
56 // will be created and stored in this->descriptorSetLayout.
57 void onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> callback);
58
59 // Called from createGraphicsPipeline.
60 // Callback should call tester.createShaderModule() and return the result.
61 void onCreateVertexShader(std::function<vk::ShaderModule(ThisType &tester)> callback);
62
63 // Called from createGraphicsPipeline.
64 // Callback should call tester.createShaderModule() and return the result.
65 void onCreateFragmentShader(std::function<vk::ShaderModule(ThisType &tester)> callback);
66
67 // Called from createCommandBuffers.
68 // Callback may create resources (tester.addImage, tester.addSampler, etc.), and make sure to
69 // call tester.device().updateDescriptorSets.
70 void onUpdateDescriptorSet(std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> callback);
71
72 /////////////////////////
73 // Resource Management
74 /////////////////////////
75
76 // Call from doCreateFragmentShader()
77 vk::ShaderModule createShaderModule(const char *glslSource, EShLanguage glslLanguage);
78
79 // Call from doCreateVertexBuffers()
80 template<typename VertexType>
addVertexBuffer(VertexType * vertexBufferData,size_t vertexBufferDataSize,std::vector<vk::VertexInputAttributeDescription> inputAttributes)81 void addVertexBuffer(VertexType *vertexBufferData, size_t vertexBufferDataSize, std::vector<vk::VertexInputAttributeDescription> inputAttributes)
82 {
83 addVertexBuffer(vertexBufferData, vertexBufferDataSize, sizeof(VertexType), std::move(inputAttributes));
84 }
85
86 template<typename T>
87 struct Resource
88 {
89 size_t id;
90 T &obj;
91 };
92
93 template<typename... Args>
addImage(Args &&...args)94 Resource<Image> addImage(Args &&...args)
95 {
96 images.emplace_back(std::make_unique<Image>(std::forward<Args>(args)...));
97 return { images.size() - 1, *images.back() };
98 }
99
getImageById(size_t id)100 Image &getImageById(size_t id)
101 {
102 return *images[id].get();
103 }
104
addSampler(const vk::SamplerCreateInfo & samplerCreateInfo)105 Resource<vk::Sampler> addSampler(const vk::SamplerCreateInfo &samplerCreateInfo)
106 {
107 auto sampler = device.createSampler(samplerCreateInfo);
108 samplers.push_back(sampler);
109 return { samplers.size() - 1, samplers.back() };
110 }
111
getSamplerById(size_t id)112 vk::Sampler &getSamplerById(size_t id)
113 {
114 return samplers[id];
115 }
116
117 private:
118 void createSynchronizationPrimitives();
119 void createCommandBuffers(vk::RenderPass renderPass);
120 void prepareVertices();
121 void createFramebuffers(vk::RenderPass renderPass);
122 vk::RenderPass createRenderPass(vk::Format colorFormat);
123 vk::Pipeline createGraphicsPipeline(vk::RenderPass renderPass);
124 void addVertexBuffer(void *vertexBufferData, size_t vertexBufferDataSize, size_t vertexSize, std::vector<vk::VertexInputAttributeDescription> inputAttributes);
125
126 struct Hook
127 {
__anone820d3f80102DrawTester::Hook128 std::function<void(ThisType &tester)> createVertexBuffers = [](auto &) {};
__anone820d3f80202DrawTester::Hook129 std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> createDescriptorSetLayout = [](auto &) { return std::vector<vk::DescriptorSetLayoutBinding>{}; };
__anone820d3f80302DrawTester::Hook130 std::function<vk::ShaderModule(ThisType &tester)> createVertexShader = [](auto &) { return vk::ShaderModule{}; };
__anone820d3f80402DrawTester::Hook131 std::function<vk::ShaderModule(ThisType &tester)> createFragmentShader = [](auto &) { return vk::ShaderModule{}; };
__anone820d3f80502DrawTester::Hook132 std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> updateDescriptorSet = [](auto &, auto &, auto &) {};
133 } hooks;
134
135 const vk::Extent2D windowSize = { 1280, 720 };
136 const bool multisample;
137
138 std::unique_ptr<Window> window;
139 std::unique_ptr<Swapchain> swapchain;
140
141 vk::RenderPass renderPass; // Owning handle
142 std::vector<std::unique_ptr<Framebuffer>> framebuffers;
143 uint32_t currentFrameBuffer = 0;
144
145 struct VertexBuffer
146 {
147 vk::Buffer buffer; // Owning handle
148 vk::DeviceMemory memory; // Owning handle
149
150 vk::VertexInputBindingDescription inputBinding;
151 std::vector<vk::VertexInputAttributeDescription> inputAttributes;
152 vk::PipelineVertexInputStateCreateInfo inputState;
153
154 uint32_t numVertices = 0;
155 } vertices;
156
157 vk::DescriptorSetLayout descriptorSetLayout; // Owning handle
158 vk::PipelineLayout pipelineLayout; // Owning handle
159 vk::Pipeline pipeline; // Owning handle
160
161 vk::Semaphore presentCompleteSemaphore; // Owning handle
162 vk::Semaphore renderCompleteSemaphore; // Owning handle
163 std::vector<vk::Fence> waitFences; // Owning handles
164
165 vk::CommandPool commandPool; // Owning handle
166 vk::DescriptorPool descriptorPool; // Owning handle
167
168 // Resources
169 std::vector<std::unique_ptr<Image>> images;
170 std::vector<vk::Sampler> samplers; // Owning handles
171
172 std::vector<vk::CommandBuffer> commandBuffers; // Owning handles
173 };
174
onCreateVertexBuffers(std::function<void (ThisType & tester)> callback)175 inline void DrawTester::onCreateVertexBuffers(std::function<void(ThisType &tester)> callback)
176 {
177 hooks.createVertexBuffers = std::move(callback);
178 }
179
onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding> (ThisType & tester)> callback)180 inline void DrawTester::onCreateDescriptorSetLayouts(std::function<std::vector<vk::DescriptorSetLayoutBinding>(ThisType &tester)> callback)
181 {
182 hooks.createDescriptorSetLayout = std::move(callback);
183 }
184
onCreateVertexShader(std::function<vk::ShaderModule (ThisType & tester)> callback)185 inline void DrawTester::onCreateVertexShader(std::function<vk::ShaderModule(ThisType &tester)> callback)
186 {
187 hooks.createVertexShader = std::move(callback);
188 }
189
onCreateFragmentShader(std::function<vk::ShaderModule (ThisType & tester)> callback)190 inline void DrawTester::onCreateFragmentShader(std::function<vk::ShaderModule(ThisType &tester)> callback)
191 {
192 hooks.createFragmentShader = std::move(callback);
193 }
194
onUpdateDescriptorSet(std::function<void (ThisType & tester,vk::CommandPool & commandPool,vk::DescriptorSet & descriptorSet)> callback)195 inline void DrawTester::onUpdateDescriptorSet(std::function<void(ThisType &tester, vk::CommandPool &commandPool, vk::DescriptorSet &descriptorSet)> callback)
196 {
197 hooks.updateDescriptorSet = std::move(callback);
198 }
199
200 #endif // DRAW_TESTER_HPP_
201