LCOV - code coverage report
Current view: top level - xenolith/backend/vkgui - XLVkGuiApplication.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 178 18.5 %
Date: 2024-05-12 00:16:13 Functions: 7 26 26.9 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLVkLoop.h"
      24             : #include "XLVkGuiPlatform.h"
      25             : #include "platform/linux/XLVkGuiViewImpl.h"
      26             : #include "XLVkGuiApplication.h"
      27             : #include "XLPlatform.h"
      28             : 
      29             : #include "XLScene.h"
      30             : 
      31             : #if MODULE_XENOLITH_RENDERER_BASIC2D
      32             : 
      33             : #include "XL2dScene.h"
      34             : #include "XL2dLabel.h"
      35             : #include "XL2dSceneContent.h"
      36             : 
      37             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      38             : 
      39             : class BootstrapScene : public basic2d::Scene2d {
      40             : public:
      41           0 :         virtual ~BootstrapScene() = default;
      42             : 
      43             :         virtual bool init(Application *, const core::FrameContraints &constraints) override;
      44             : 
      45             :         virtual void onContentSizeDirty() override;
      46             : 
      47             : protected:
      48             :         using Scene::init;
      49             : 
      50             :         basic2d::Label *_helloWorldLabel = nullptr;
      51             : };
      52             : 
      53           0 : bool BootstrapScene::init(Application *app, const core::FrameContraints &constraints) {
      54           0 :         if (!Scene2d::init(app, constraints)) {
      55           0 :                 return false;
      56             :         }
      57             : 
      58           0 :         auto content = Rc<basic2d::SceneContent2d>::create();
      59             : 
      60           0 :         _helloWorldLabel = content->addChild(Rc<basic2d::Label>::create());
      61           0 :         _helloWorldLabel->setString("Hello World");
      62           0 :         _helloWorldLabel->setAnchorPoint(Anchor::Middle);
      63             : 
      64           0 :         setContent(content);
      65             : 
      66           0 :         auto color = Color4F::WHITE;
      67           0 :         color.a = 0.5f;
      68             : 
      69           0 :         auto light = Rc<basic2d::SceneLight>::create(basic2d::SceneLightType::Ambient, Vec2(0.0f, 0.3f), 1.5f, color);
      70           0 :         auto ambient = Rc<basic2d::SceneLight>::create(basic2d::SceneLightType::Ambient, Vec2(0.0f, 0.0f), 1.5f, color);
      71             : 
      72           0 :         content->setGlobalLight(Color4F::WHITE);
      73           0 :         content->removeAllLights();
      74           0 :         content->addLight(move(light));
      75           0 :         content->addLight(move(ambient));
      76             : 
      77           0 :         filesystem::mkdir(filesystem::cachesPath<Interface>());
      78             : 
      79           0 :         return true;
      80           0 : }
      81             : 
      82           0 : void BootstrapScene::onContentSizeDirty() {
      83           0 :         Scene2d::onContentSizeDirty();
      84             : 
      85           0 :         _helloWorldLabel->setPosition(_content->getContentSize() / 2.0f);
      86           0 : }
      87             : 
      88             : }
      89             : 
      90             : #endif
      91             : 
      92             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      93             : 
      94          10 : GuiApplication::~GuiApplication() { }
      95             : 
      96          10 : bool GuiApplication::init(CommonInfo &&appInfo, Rc<core::Instance> &&instance) {
      97          10 :         if (instance) {
      98           0 :                 if (Application::init(move(appInfo), move(instance))) {
      99           0 :                         return true;
     100             :                 }
     101             :         } else {
     102          10 :                 auto inst = vk::platform::createInstance([&] (vk::platform::VulkanInstanceData &data, const vk::platform::VulkanInstanceInfo &info) {
     103          10 :                         data.applicationName = appInfo.applicationName;
     104          10 :                         data.applicationVersion = appInfo.applicationVersion;
     105          10 :                         data.checkPresentationSupport = vk::platform::checkPresentationSupport;
     106          10 :                         return vk::platform::initInstance(data, info);
     107          10 :                 });
     108          10 :                 if (Application::init(move(appInfo), move(inst))) {
     109          10 :                         return true;
     110             :                 }
     111          10 :         }
     112           0 :         return false;
     113             : }
     114             : 
     115           0 : bool GuiApplication::init(CommonInfo &&appInfo, const Callback<bool(VulkanInstanceData &, const VulkanInstanceInfo &)> &cb) {
     116           0 :         auto instance = vk::platform::createInstance([&] (VulkanInstanceData &data, const VulkanInstanceInfo &info) {
     117           0 :                 if (cb(data, info)) {
     118           0 :                         data.applicationName = appInfo.applicationName;
     119           0 :                         data.applicationVersion = appInfo.applicationVersion;
     120           0 :                         return true;
     121             :                 }
     122           0 :                 return false;
     123           0 :         });
     124             : 
     125           0 :         if (Application::init(move(appInfo), move(instance))) {
     126           0 :                 return true;
     127             :         }
     128             : 
     129           0 :         return false;
     130           0 : }
     131             : 
     132          10 : void GuiApplication::run(const CallbackInfo &cb, uint32_t threadCount, TimeInterval ival) {
     133          10 :         core::LoopInfo info;
     134             : 
     135          10 :         run(cb, move(info), threadCount, ival);
     136          10 : }
     137             : 
     138          10 : void GuiApplication::run(const CallbackInfo &cb, core::LoopInfo &&info, uint32_t threadCount, TimeInterval ival) {
     139          10 :         if (!info.platformData) {
     140          10 :                 auto data = Rc<LoopData>::alloc();
     141          10 :                 data->deviceSupportCallback = [] (const vk::DeviceInfo &dev) {
     142          20 :                         return dev.supportsPresentation() &&
     143          10 :                                         std::find(dev.availableExtensions.begin(), dev.availableExtensions.end(),
     144          30 :                                                         String(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) != dev.availableExtensions.end();
     145          10 :                 };
     146          10 :                 data->deviceExtensionsCallback = [] (const vk::DeviceInfo &dev) -> Vector<StringView> {
     147          10 :                         Vector<StringView> ret;
     148          10 :                         ret.emplace_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
     149          10 :                         return ret;
     150          10 :                 };
     151          10 :                 info.platformData = data;
     152          10 :         }
     153             : 
     154          10 :         Application::run(cb, move(info), threadCount, ival);
     155          10 : }
     156             : 
     157             : XL_DECLARE_EVENT_CLASS(BootstrapApplication, onSwapchainConfig);
     158             : 
     159           0 : bool BootstrapApplication::init(ViewCommandLineData &&data, void *native) {
     160           0 :         _data = move(data);
     161             : 
     162           0 :         Application::CommonInfo info({
     163           0 :                 .bundleName = _data.bundleName,
     164           0 :                 .applicationName = _data.applicationName,
     165           0 :                 .applicationVersion = _data.applicationVersion,
     166           0 :                 .userAgent = _data.userAgent,
     167           0 :                 .locale = _data.userLanguage,
     168             :                 .nativeHandle = native
     169           0 :         });
     170             : 
     171           0 :         _storageParams = Value({
     172           0 :                 pair("driver", Value("sqlite")),
     173           0 :                 pair("dbname", Value(filesystem::cachesPath<Interface>("root.sqlite"))),
     174           0 :                 pair("serverName", Value("RootStorage"))
     175           0 :         });
     176             : 
     177           0 :         return GuiApplication::init(move(info));
     178           0 : }
     179             : 
     180           0 : void BootstrapApplication::run(Function<void()> &&initCb) {
     181           0 :         if (_storageParams.getString("driver") == "sqlite") {
     182           0 :                 auto path = _storageParams.getString("dbname");
     183           0 :                 filesystem::mkdir(filepath::root(filepath::root(path)));
     184           0 :                 filesystem::mkdir(filepath::root(path));
     185           0 :         }
     186             : 
     187             : #if MODULE_XENOLITH_RESOURCES_STORAGE
     188           0 :         _storageServer = Rc<storage::Server>::create(static_cast<Application *>(this), _storageParams);
     189             : 
     190           0 :         if (!_storageServer) {
     191           0 :                 log::error("Application", "Fail to create storage server");
     192             :         }
     193             : 
     194           0 :         addExtension(Rc<storage::Server>(_storageServer));
     195             : #endif
     196             : 
     197             : #if MODULE_XENOLITH_RESOURCES_NETWORK
     198           0 :         _networkController = Rc<network::Controller>::alloc(static_cast<Application *>(this), "Root");
     199           0 :         addExtension(Rc<network::Controller>(_networkController));
     200             : #endif
     201             : 
     202             : #if MODULE_XENOLITH_RESOURCES_ASSETS
     203           0 :         _assetLibrary = Rc<storage::AssetLibrary>::create(static_cast<Application *>(this), _networkController, Value({
     204           0 :                 pair("driver", Value("sqlite")),
     205           0 :                 pair("dbname", Value(filesystem::cachesPath<Interface>("assets.sqlite"))),
     206           0 :                 pair("serverName", Value("AssetStorage"))
     207           0 :         }));
     208           0 :         addExtension(Rc<storage::AssetLibrary>(_assetLibrary));
     209             : #endif
     210             : 
     211             :         GuiApplication::CallbackInfo callbacks({
     212           0 :                 .initCallback = [&] (const Application &) {
     213           0 :                         GuiApplication::addView(ViewInfo{
     214           0 :                                 .name = _data.applicationName,
     215           0 :                                 .bundleId = _data.bundleName,
     216           0 :                                 .rect = URect(UVec2{0, 0}, _data.screenSize),
     217             :                                 .decoration = _data.viewDecoration,
     218           0 :                                 .density = _data.density,
     219           0 :                                 .selectConfig = [this] (xenolith::View &view, const core::SurfaceInfo &info) -> core::SwapchainConfig {
     220           0 :                                         return selectConfig(static_cast<View &>(view), info);
     221             :                                 },
     222           0 :                                 .onCreated = [this] (xenolith::View &view, const core::FrameContraints &constraints) {
     223           0 :                                         auto scene = createSceneForView(static_cast<View &>(view), constraints);
     224           0 :                                         view.getDirector()->runScene(move(scene));
     225           0 :                                 },
     226           0 :                                 .onClosed = [this] (xenolith::View &view) {
     227           0 :                                         finalizeView(static_cast<View &>(view));
     228           0 :                                         end();
     229           0 :                                 }
     230             :                         });
     231           0 :                         if (initCb) {
     232           0 :                                 initCb();
     233             :                         }
     234           0 :                 },
     235           0 :                 .updateCallback = [&] (const Application &, const UpdateTime &time) { }
     236           0 :         });
     237             : 
     238           0 :         GuiApplication::run(callbacks);
     239             : 
     240             : #if MODULE_XENOLITH_RESOURCES_ASSETS
     241           0 :         _assetLibrary = nullptr;
     242             : #endif
     243             : 
     244             : #if MODULE_XENOLITH_RESOURCES_NETWORK
     245           0 :         _networkController = nullptr;
     246             : #endif
     247             : 
     248             : #if MODULE_XENOLITH_RESOURCES_STORAGE
     249           0 :         _storageServer = nullptr;
     250             : #endif
     251           0 : }
     252             : 
     253           0 : void BootstrapApplication::setPreferredPresentMode(core::PresentMode mode) {
     254           0 :         std::unique_lock<Mutex> lock(_configMutex);
     255           0 :         _preferredPresentMode = mode;
     256           0 : }
     257             : 
     258           0 : Rc<Scene> BootstrapApplication::createSceneForView(vk::View &view, const core::FrameContraints &constraints) {
     259             : #if MODULE_XENOLITH_RENDERER_BASIC2D
     260           0 :         return Rc<BootstrapScene>::create(this, constraints);
     261             : #else
     262             :         return nullptr;
     263             : #endif
     264             : }
     265             : 
     266           0 : void BootstrapApplication::finalizeView(vk::View &view) {
     267             : 
     268           0 : }
     269             : 
     270           0 : core::SwapchainConfig BootstrapApplication::selectConfig(vk::View &, const core::SurfaceInfo &info) {
     271           0 :         std::unique_lock<Mutex> lock(_configMutex);
     272           0 :         core::SwapchainConfig ret;
     273           0 :         ret.extent = info.currentExtent;
     274           0 :         ret.imageCount = std::max(uint32_t(3), info.minImageCount);
     275             : 
     276           0 :         ret.presentMode = info.presentModes.front();
     277           0 :         if (_preferredPresentMode != core::PresentMode::Unsupported) {
     278           0 :                 for (auto &it : info.presentModes) {
     279           0 :                         if (it == _preferredPresentMode) {
     280           0 :                                 ret.presentMode = it;
     281           0 :                                 break;
     282             :                         }
     283             :                 }
     284             :         }
     285             : 
     286           0 :         if (std::find(info.presentModes.begin(), info.presentModes.end(), core::PresentMode::Immediate) != info.presentModes.end()) {
     287           0 :                 ret.presentModeFast = core::PresentMode::Immediate;
     288             :         }
     289             : 
     290           0 :         auto it = info.formats.begin();
     291           0 :         while (it != info.formats.end()) {
     292           0 :                 if (it->first != xenolith::platform::getCommonFormat()) {
     293           0 :                         ++ it;
     294             :                 } else {
     295           0 :                         break;
     296             :                 }
     297             :         }
     298             : 
     299           0 :         if (it == info.formats.end()) {
     300           0 :                 ret.imageFormat = info.formats.front().first;
     301           0 :                 ret.colorSpace = info.formats.front().second;
     302             :         } else {
     303           0 :                 ret.imageFormat = it->first;
     304           0 :                 ret.colorSpace = it->second;
     305             :         }
     306             : 
     307           0 :         if ((info.supportedCompositeAlpha & core::CompositeAlphaFlags::Opaque) != core::CompositeAlphaFlags::None) {
     308           0 :                 ret.alpha = core::CompositeAlphaFlags::Opaque;
     309           0 :         } else if ((info.supportedCompositeAlpha & core::CompositeAlphaFlags::Inherit) != core::CompositeAlphaFlags::None) {
     310           0 :                 ret.alpha = core::CompositeAlphaFlags::Inherit;
     311             :         }
     312             : 
     313           0 :         ret.transfer = (info.supportedUsageFlags & core::ImageUsage::TransferDst) != core::ImageUsage::None;
     314             : 
     315           0 :         if (ret.presentMode == core::PresentMode::Mailbox) {
     316           0 :                 ret.imageCount = std::max(uint32_t(3), ret.imageCount);
     317             :         }
     318             : 
     319           0 :         ret.transform = info.currentTransform;
     320             : 
     321           0 :         performOnMainThread([this, info, ret] {
     322           0 :                 _surfaceInfo = info;
     323           0 :                 _swapchainConfig = ret;
     324             : 
     325           0 :                 onSwapchainConfig(this);
     326           0 :         });
     327             : 
     328           0 :         return ret;
     329           0 : }
     330             : 
     331             : }

Generated by: LCOV version 1.14