HoviTron Video Pipeline
VulkanWrapper.cpp
1/* ----------------------
2* Copyright 2023 Université Libre de Bruxelles(ULB), Universidad Politécnica de Madrid(UPM), CREAL, Deutsches Zentrum für Luft - und Raumfahrt(DLR)
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at < http://www.apache.org/licenses/LICENSE-2.0>
7
8* Unless required by applicable law or agreed to in writing, software
9* distributed under the License is distributed on an "AS IS" BASIS,
10* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11* See the License for the specific language governing permissionsand
12* limitations under the License.
13---------------------- */
14
15
16#include "VulkanWrapper.h"
17#include "../WindowAbstract.h"
18//#include "../NoWindow.h"
19#include "Shader.h"
20#include <iostream>
21#include <fstream>
23#include "InputProvider.h"
24
25#include <nlohmann/json.hpp>
26
27using json = nlohmann::json;
28
29#ifdef __ANDROID__
30static const char* kTAG = "renderPass";
31#define LOGI(...) \
32 ((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__))
33#endif
34
35#ifdef __ANDROID__
36VulkanWrapper::VulkanWrapper(WindowAbstract* window, android_app* appAndroid) :context(window), renderPass(&context, this), drawing(&context,&renderPass, window, this), multiviewSetup(window->useOpenXR())
37{
38 this->window = window;
39 window->setWrapper(this);
40 this->appAndroid = appAndroid;
41}
42#else
43VulkanWrapper::VulkanWrapper(WindowAbstract* window, PipelineMode pmode) :
44 context(window),
45 renderPass([&]()->VulkanRenderPassAbstract*{
46 switch (pmode) {
47 default:
48 return new VulkanRenderPass(&context, this);
49 }
50 }()),
51 drawing(&context, renderPass.get(), window, this),
52 multiviewSetup(window->useOpenXR())
53{
54 this->window = window;
55 window->setWrapper(this);
56
57}
58#endif
59
60#ifdef HVT_UDP_CONTROL
61void VulkanWrapper::init(unsigned short port)
62{
63#else
65{
66#endif
67
68 window->initWindow();
69#ifdef __ANDROID__
71#else
73#endif
74 if (!context.isInitialized()) {
75 D(PRINT("====context======="));
77 }
78 D(PRINT("===continue window initialisation==="));
79 window->continueInit();
80 //set the number of attachment to
81 attachmentSize = window->getAttachmentSize();
82 int viewNum = window->getViewNumber();
83
84#ifdef HVT_UDP_CONTROL
85 params.init(viewNum, window, this, port);
86 this->port = port;
87#else
88 params.init(viewNum, window, this);
89#endif // DEBUG
90
91 D(PRINT("Size of attachment = %d", attachmentSize));
92}
93
95 return renderPass->getSupportedDepthFormats();
96}
97
98void VulkanWrapper::endInit(InputProvider * inputProvider, StartingPosition startingPt){
99 this->inputProvider = inputProvider;
100 auto input = inputProvider->enumerateStreamsParameters();
101 assert(input.size() >= 1);
102
103 correctionVectorRotation.resize(input.size());
104 correctionVectorTranslation.resize(input.size());
105 correctionPrincipalPt.resize(input.size());
106 correctionFocal.resize(input.size());
107
108
109 streamFrameInfos.resize(input.size());
110 cameraActivation.resize(input.size(),true);
111
112 float maxD = input[0].farDepth;
113 float minD = input[0].nearDepth;
114 for (const auto & in : input) {
115 maxD = in.farDepth > maxD ? in.farDepth : maxD;
116 minD = in.nearDepth > minD ? in.nearDepth : minD;
117 }
118 params.max_depth = maxD;
119 params.min_depth = minD;
120
121
122 D(PRINT("=====renderpass======"));
123 renderPass->init(inputProvider);
124 D(PRINT("=====drawing======"));
125 drawing.init(inputProvider);
126
127 if (startingPt == StartingPosition::Average) {
129 }
130 else {
132 }
133}
134
135
137{
138
139 std::cout << "Save correction of rotation to disk at " << fileN << std::endl;
140 std::ofstream stream(fileN, std::ifstream::out);
141
142 assert(correctionVectorRotation.size() == correctionVectorTranslation.size());
143 assert(correctionVectorTranslation.size() == correctionPrincipalPt.size());
144 assert(correctionPrincipalPt.size() == correctionFocal.size());
145
146
147 json j;
148 for (int id = 0; id < correctionVectorRotation.size(); id ++ ) {
149 //j["camera"][id] = json::array();
150 j["camera"][id]["id"] = id;
151
152 //j["camera"][id]["correction"] = json::object();
153 auto r = correctionVectorRotation[id];
154 j["camera"][id]["correction"]["rotation"] = { r.x,r.y,r.z };
155 auto t = correctionVectorTranslation[id];
156 j["camera"][id]["correction"]["translation"] = {t.x,t.y,t.z};
157 auto p = correctionPrincipalPt[id];
158 j["camera"][id]["correction"]["principalPt"] = json::array({p.x,p.y});
159 auto f = correctionFocal[id];
160 j["camera"][id]["correction"]["focal"] = json::array({f.x,f.y});
161
162 //j["camera"][id]["current"] = json::array();
163 auto ro = streamFrameInfos[id].extrinsics.rotation;
164 j["camera"][id]["current"]["rotation"] = {ro.x,ro.y,ro.z};
165 auto to = streamFrameInfos[id].extrinsics.position;
166 j["camera"][id]["current"]["translation"] = { to.x,to.y,to.z };
167
168 //-------- TODO case with equirectangular
169 if (streamFrameInfos[id].intrinsics.index() == 0) {
170 auto po = std::get<InputProvider::PerspectiveIntrinsics>(streamFrameInfos[id].intrinsics).principle;
171 j["camera"][id]["current"]["principalPt"] = json::array({ po.x,po.y });
172 auto fo = std::get<InputProvider::PerspectiveIntrinsics>(streamFrameInfos[id].intrinsics).focals;
173 j["camera"][id]["current"]["focal"] = json::array({ fo.x,fo.y });
174 }
175
176 }
177 stream << j.dump(4);
178
179 stream.close();
180}
181
183{
184
185 std::ifstream stream(fileN, std::ifstream::out);
186
187 json j;
188 std::cout << "load correction of rotation to disk at " << fileN << std::endl;
189 if (stream.is_open()) {
190 j << stream;
191
192 for (auto& cam : j["camera"]) {
193 int id = cam["id"];
194 auto r = j["camera"][id]["correction"]["rotation"];
195 correctionVectorRotation[id] = { r[0],r[1],r[2] };
196 auto t = j["camera"][id]["correction"]["translation"];
197 correctionVectorTranslation[id] = { t[0],t[1],t[2] };
198 auto p = j["camera"][id]["correction"]["principalPt"];
199 correctionPrincipalPt[id] = { p[0],p[1] };
200 auto f = j["camera"][id]["correction"]["focal"];
201 correctionFocal[id] = { f[0],f[1] };
202 }
203 }
204 else {
205 std::cout << "No save file found" << std::endl;
206 }
207}
208
210{
211 return cameraActivation;
212}
213
215{
216
217 assert( i < cameraActivation.size() );
218
219 if (!cameraActivation[i] || renderPass->inputImage > 1 ) {
220#ifdef HVT_UDP_CONTROL
221
222 mutexAct.lock();
223#endif // HVT_UDP_CONTROL
224
225 requestChange = true;
226 cameraActivation[i] = !cameraActivation[i];
227#ifdef HVT_UDP_CONTROL
228 mutexAct.unlock();
229#endif
230 }
231 else {
232 //we don't need to desactivate all the camera
233 //always let one activated
234 std::cout << "Impossible to desactivate camera " << i << " :there must always be one camera active" << std::endl;
235 }
236}
237
238void VulkanWrapper::setCameraActivation(std::vector<bool> activation)
239{
240
241 assert(activation.size() == cameraActivation.size());
242
243 bool valid = false;
244 for (auto a : activation) {
245 valid += a;
246 }
247
248 if (valid) {
249#ifdef HVT_UDP_CONTROL
250 mutexAct.lock();
251#endif
252 requestChange = true;
253 cameraActivation = activation;
254#ifdef HVT_UDP_CONTROL
255 mutexAct.unlock();
256#endif
257 }
258 else {
259 PRINT("Invalid activation vector. At least one camera should be activated");
260 }
261}
262
264{
265
266 window->mainLoop(&drawing);
267 context.device.waitIdle();
268}
269
271{
272
273 if(drawing.isInitialized()) {
274 drawing.cleanup();
275 }
276
277 //pipeline.cleanUp();
278 if(renderPass->isInitialized()){
279 renderPass->cleanUp();
280 }
281 /*
282 if (!window->isSwapChainNeeded()) {
283 static_cast<NoWindow*>(window)->cleanUpRessources();
284 }*/
285 window->cleanUp();
286
287}
288
290{
291#ifdef __ANDROID__
292 LOGI("recreate swapchain");
293#else
294 std::cout << ("recreation swapchain !") << std::endl;
295#endif
296 window->checkForCorrectSize();
297 //could be better TODO -> https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation
298 context.device.waitIdle();
299 //cleanUp
300 cleanUp();
301 //init
302#ifdef HVT_UDP_CONTROL
303 init(port);
304#else
305 init();
306#endif
307
308}
309
310void VulkanWrapper::updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation)
311{
312
313 params.updateSpaceTransform(translation,rotation);
314
315}
316
318 context.device.waitIdle();
319}
320void VulkanWrapper::createImageCall(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Image& image, vk::DeviceMemory& imageMemory)
321{
322 createImage(context.device,context.physicalDevice,width,height,format,tiling,usage,properties,image,imageMemory);
323}
324void VulkanWrapper::createBufferCall(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer& buffer, vk::DeviceMemory& bufferMemory)
325{
326 createBuffer(size, usage, properties, buffer, bufferMemory, context.device, context.physicalDevice);
327}
328void VulkanWrapper::copyMemory(VkDeviceSize & size, vk::DeviceMemory& memory, unsigned char* dataToCopy)
329{
330 void* data;
331 context.device.mapMemory(memory, 0, size, {}, &data);
332 memcpy(dataToCopy, data, static_cast<size_t>(size));
333 context.device.unmapMemory(memory);
334}
335
336void VulkanWrapper::destroyImageAndMemory(std::vector<vk::Image>& vectorImage, std::vector<vk::DeviceMemory>& vectorMemory)
337{
338 //delete image
339 for (auto const& image : vectorImage) {
340 context.device.destroyImage(image);
341 }
342 //delete attachement memory
343 for (auto const& mem : vectorMemory) {
344 context.device.freeMemory(mem);
345 }
346}
347
348void VulkanWrapper::destroyBufferAndMemory(std::vector<vk::Buffer>& vectorBuffer, std::vector<vk::DeviceMemory>& vectorMemory)
349{
350 //delete image
351 for (auto const& buf : vectorBuffer) {
352 context.device.destroyBuffer(buf);
353 }
354 //delete attachement memory
355 for (auto const& mem : vectorMemory) {
356 context.device.freeMemory(mem);
357 }
358}
359
361{
362 return window->isDepthRecquired();
363}
364
365void VulkanWrapper::setBlendingFactor(float blendingfactor)
366{
367 params.blendingFactor = blendingfactor;
368}
369
370void VulkanWrapper::setTriangleThreshold(float triangleThreshold)
371{
372 assert(triangleThreshold > 0);
373 params.pixelThreshold = triangleThreshold;
374}
375
377{
378 assert(params.virtualViewDef.size() > 0);
379 if (params.virtualViewDef.size() == 1) {
380 return false;
381 }
382 else {
383 auto ref = params.virtualViewDef[0];
384 for (auto & v : params.virtualViewDef) {
385 if (v[0] != ref[0] || v[1] != ref[1]) {
386 return true;
387 }
388 }
389 return false;
390 }
391
392}
393
395{
396 return &context;
397}
398
400{
401 return window->getSwapchainExtent(view);
402}
403
405{
406 /*if (window->isIndepFromWindowDimension()) {
407 //return VirtualView [0]
408 auto size = app->getConfig().params_virtual[0].getSize();
409 return vk::Extent2D(size.width,size.height);
410 }
411 else { */
412 //return the size of the first swapchain
413 //return window->swapChainExtent[0];
414 //}
415 vk::Extent2D max = {0,0};
416 for (int i = 0; i < window->getViewNumber(); i++) {
417 auto ext = window->getSwapchainExtent(i);
418 if (max.width < ext.width) {
419 max.width = ext.width;
420 }
421 if (max.height < ext.height) {
422 max.height = ext.height;
423 }
424 }
425 return max;
426}
427
429{
430 return window->getSwapchainFormat(view);//window->swapChainImageFormat[view];
431}
432
434{
435 return window->getDepthSwapchainFormat(view);
436}
437
439{
440 auto res = vk::ImageLayout::eColorAttachmentOptimal;
441 if (!window->useOpenXR() && !window->isIndepFromWindowDimension()) {
442 res = vk::ImageLayout::ePresentSrcKHR;
443 }
444 return res;
445}
446
448{
449 return window->getAttachmentSize();
450}
451
453{
454 return window->getViewNumber();
455}
456
457void VulkanWrapper::setAverageInputPosition(std::vector<InputProvider::StreamFrameInfo>& frameInfo)
458{
459 glm::vec3 averagePos = {0,0,0};
460 glm::vec3 averageRot = {0,0,0};
461 const int numInput = frameInfo.size();
462
463 for (auto f : frameInfo) {
464 averagePos += f.extrinsics.position;
465 //averageRot += f.extrinsics.rotation;
466 }
467 averagePos /= numInput;
468 //averageRot /= numInput;
469
470 //convert from OMAF to the coordinate system used by virtual parameters
471 auto conversion = glm::transpose(params.conversionToOMAF);
472 auto pos = conversion * averagePos;
473
474 params.setStartingPt(pos, averageRot);
475 //params.startingRotation = conversion * averageRot * glm::transpose(conversion) ;
476
478}
479
480void VulkanWrapper::addDeltaToStartingPoint(glm::vec3 dPos, glm::vec3 dRot)
481{
482 auto R = glmEulerAnglesDegreeToRotationMatrixNotOMAF(params.getStartingRotation());
483 auto dR = glmEulerAnglesDegreeToRotationMatrixNotOMAF(dRot);
484
485 auto pos = params.getStartingPosition() + glm::transpose(R)* dPos;
486 auto rot = glm::transpose(R) * dRot * R;
487
488 params.setStartingPt(pos,rot);
489
490
491}
492
493void VulkanWrapper::setCorrectionRotation(int camId, glm::vec3 rotationCorrection)
494{
495 if (camId < correctionVectorRotation.size()) {
496 correctionVectorRotation[camId] += rotationCorrection;
497 }
498 else {
499 PRINT("Camera %i does not exist, only %i camera are availables", camId, (int) correctionVectorRotation.size());
500 }
501}
502
503void VulkanWrapper::setCorrectionTranslation(int camId, glm::vec3 translationCorrection)
504{
505 if (camId < correctionVectorTranslation.size()) {
506 correctionVectorTranslation[camId] += translationCorrection;
507 }
508 else {
509 PRINT("Camera %i does not exist, only %i camera are availables", camId, (int)correctionVectorTranslation.size());
510 }
511}
512
513void VulkanWrapper::setCorrectionFocal(int camId, glm::vec2 focals)
514{
515 if (camId < correctionFocal.size()) {
516 correctionFocal[camId] += focals;
517 }
518 else {
519 PRINT("Camera %i does not exist, only %i camera are availables", camId, (int)correctionFocal.size());
520 }
521}
522
523void VulkanWrapper::setCorrectionPrincipalPt(int camId, glm::vec2 principalPt)
524{
525 if (camId < correctionFocal.size()) {
526 correctionPrincipalPt[camId] += principalPt;
527 }
528 else {
529 PRINT("Camera %i does not exist, only %i camera are availables", camId, (int)correctionPrincipalPt.size());
530 }
531}
532
533void VulkanWrapper::setScaleFactor(float scaleFactor)
534{
535 assert(scaleFactor > 0);
536 params.scaleFactor = scaleFactor;
537}
538
539const std::vector<glm::vec3> VulkanWrapper::getCorrectionVectorRotation()
540{
541 return correctionVectorRotation;
542}
543
544const std::vector<InputProvider::StreamFrameInfo> VulkanWrapper::getFramesInfo(int view)
545{
546 if (requestChange) {
547 context.device.waitIdle();
548#ifdef HVT_UDP_CONTROL
549 mutexAct.lock();
550#endif
551 drawing.cleanup();
552 renderPass->cleanUp();
553 renderPass->init(inputProvider);
554 drawing.init(inputProvider);
555 requestChange = false;
556#ifdef HVT_UDP_CONTROL
557 mutexAct.unlock();
558#endif
559 }
560 inputProvider->acquireStreamsFrames(params.getVirtualExtrinsics(view), streamFrameInfos);
562 setAverageInputPosition(streamFrameInfos);
563 }
564
565 assert(correctionVectorRotation.size() == streamFrameInfos.size());
566
567 for (int i = 0; i < correctionVectorRotation.size(); i++) {
568 streamFrameInfos[i].extrinsics.rotation += correctionVectorRotation[i];
569 streamFrameInfos[i].extrinsics.position += correctionVectorTranslation[i];
570
571 if (streamFrameInfos[i].intrinsics.index() == 0) {
572 std::get<InputProvider::PerspectiveIntrinsics>(streamFrameInfos[i].intrinsics).focals += correctionFocal[i];
573 std::get<InputProvider::PerspectiveIntrinsics>(streamFrameInfos[i].intrinsics).principle += correctionPrincipalPt[i];
574 }
575
576 }
577
578 return streamFrameInfos;
579}
580
581
582
583#ifdef USE_OPENXR
584XrGraphicsBindingVulkan2KHR VulkanWrapper::getGraphicsBinding() {
585 XrGraphicsBindingVulkan2KHR m_graphicsBinding{XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR};
586 m_graphicsBinding.instance = context.instance;
587 m_graphicsBinding.physicalDevice = context.physicalDevice;
588 m_graphicsBinding.device = context.device;
589 m_graphicsBinding.queueFamilyIndex = context.queueFamilyIndex;
590 m_graphicsBinding.queueIndex = 0;
591 return m_graphicsBinding;
592}
593
594
595void VulkanWrapper::endCleanUp() {
598 }
599}
600
601#endif
602
603void VulkanWrapper::updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation, glm::vec4 fov, int view) {
604
605 params.updateSpaceTransform(translation, rotation, fov, view);
606}
Contains the class that loads the SPIR-V shaders from files.
Class that contains helper functions for Vulkan.
file that contains the VulkanWrapper class that manages the classes related to Vulkan code and ease t...
Abstract interface around getting source views parameters and data.
Definition: InputProvider.h:35
void setStartingPt(glm::vec3 startPos, glm::vec3 startRot)
const InputProvider::Extrinsics getVirtualExtrinsics(int view)
const glm::mat3x3 conversionToOMAF
const glm::vec3 getStartingPosition()
const glm::vec3 getStartingRotation()
std::vector< glm::vec2 > virtualViewDef
void updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation)
void init(int view, WindowAbstract *window, VulkanWrapper *wraps)
void loadShaders()
Definition: Shader.cpp:68
static ShadersList & getInstance()
Definition: Shader.cpp:99
class that manages tasks related to Vulkan context (Vulkan Instance, Vulkan Physical device,...
Definition: VulkanContext.h:59
vk::PhysicalDevice physicalDevice
Definition: VulkanContext.h:85
vk::Instance instance
Definition: VulkanContext.h:83
uint32_t queueFamilyIndex
Definition: VulkanContext.h:95
vk::Device device
Definition: VulkanContext.h:87
void init(InputProvider *inputProvider)
An abstract class that contains a common base of code for the class that inherit from it.
Class that manage the renderPass containing the synthesis and blending steps.
void loadConfigurationsFromDisk()
const std::vector< InputProvider::StreamFrameInfo > getFramesInfo(int view)
bool isDepthOutputRecquired()
void copyMemory(VkDeviceSize &size, vk::DeviceMemory &memory, unsigned char *dataToCopy)
void setCorrectionTranslation(int camId, glm::vec3 translationCorrection)
void destroyBufferAndMemory(std::vector< vk::Buffer > &vectorBuffer, std::vector< vk::DeviceMemory > &vectorMemory)
void recreateSwapChain()
void setScaleFactor(float scaleFactor)
void addDeltaToStartingPoint(glm::vec3 dPos, glm::vec3 dRot)
void saveConfigurationsToDisk()
void setTriangleThreshold(float triangleThreshold)
void setCorrectionFocal(int camId, glm::vec2 focals)
vk::Extent2D getRenderOutputExtent()
void endInit(InputProvider *input, StartingPosition startingPt=StartingPosition::Average)
std::vector< vk::Format > getRenderPassSupportedDepthFormats() const
void createImageCall(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Image &image, vk::DeviceMemory &imageMemory)
bool requireAverageInputPosition
void setCorrectionPrincipalPt(int camId, glm::vec2 principalPt)
void setAverageInputPosition(std::vector< InputProvider::StreamFrameInfo > &frameInfo)
vk::Extent2D getSwapchainExtend(int view=0)
VulkanContext context
void setBlendingFactor(float blendingfactor)
const std::vector< glm::vec3 > getCorrectionVectorRotation()
bool isUsingDifferentViewSize()
void destroyImageAndMemory(std::vector< vk::Image > &vectorImage, std::vector< vk::DeviceMemory > &vectorMemory)
void updateSpaceTransform(glm::vec3 translation, glm::vec3 rotation)
vk::Format getDepthSwapchainFormat(int view=0)
void createBufferCall(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer &buffer, vk::DeviceMemory &bufferMemory)
vk::Format getSwapchainFormat(int view=0)
RenderingParameters params
std::vector< bool > getCameraActivation()
VulkanContext * getContext()
void setCameraActivation(std::vector< bool > activation)
void toggleCamera(int i)
vk::ImageLayout getLayoutAfterRenderpass()
void setCorrectionRotation(int camId, glm::vec3 rotationCorrection)
VulkanWrapper(WindowAbstract *window, PipelineMode pmode)
Abstraction of the way of the result is displayed (screen or HMD).
virtual const bool useOpenXR()
virtual void cleanUp()=0
virtual vk::Extent2D getSwapchainExtent(int view)
void setWrapper(VulkanWrapper *wraps)
virtual vk::Format getDepthSwapchainFormat(int view)
bool isIndepFromWindowDimension()
virtual void checkForCorrectSize()=0
virtual void continueInit()=0
virtual vk::Format getSwapchainFormat(int view)
virtual bool isDepthRecquired()
virtual void initWindow()=0
virtual void mainLoop(VulkanDrawing *vulkanDrawing)=0