2
0

BsLinuxRenderWindow.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "CoreThread/BsCoreThread.h"
  4. #include "Private/Linux/BsLinuxPlatform.h"
  5. #include "Private/Linux/BsLinuxWindow.h"
  6. #include "Linux/BsLinuxRenderWindow.h"
  7. #include "Linux/BsLinuxVideoModeInfo.h"
  8. #include "Math/BsMath.h"
  9. #include "Managers/BsRenderWindowManager.h"
  10. #include "Managers/BsVulkanCommandBufferManager.h"
  11. #include "BsVulkanRenderAPI.h"
  12. #include "BsVulkanDevice.h"
  13. #include "BsVulkanSwapChain.h"
  14. #include "BsVulkanQueue.h"
  15. #include <X11/Xutil.h>
  16. #define XRANDR_ROTATION_LEFT (1 << 1)
  17. #define XRANDR_ROTATION_RIGHT (1 << 3)
  18. namespace bs
  19. {
  20. LinuxRenderWindow::LinuxRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId)
  21. :RenderWindow(desc, windowId), mProperties(desc)
  22. { }
  23. void LinuxRenderWindow::getCustomAttribute(const String& name, void* data) const
  24. {
  25. if (name == "WINDOW" || name == "LINUX_WINDOW")
  26. {
  27. blockUntilCoreInitialized();
  28. getCore()->getCustomAttribute(name, data);
  29. return;
  30. }
  31. }
  32. Vector2I LinuxRenderWindow::screenToWindowPos(const Vector2I& screenPos) const
  33. {
  34. blockUntilCoreInitialized();
  35. LinuxPlatform::lockX();
  36. Vector2I pos = getCore()->_getInternal()->screenToWindowPos(screenPos);
  37. LinuxPlatform::unlockX();
  38. return pos;
  39. }
  40. Vector2I LinuxRenderWindow::windowToScreenPos(const Vector2I& windowPos) const
  41. {
  42. blockUntilCoreInitialized();
  43. LinuxPlatform::lockX();
  44. Vector2I pos = getCore()->_getInternal()->windowToScreenPos(windowPos);
  45. LinuxPlatform::unlockX();
  46. return pos;
  47. }
  48. SPtr<ct::LinuxRenderWindow> LinuxRenderWindow::getCore() const
  49. {
  50. return std::static_pointer_cast<ct::LinuxRenderWindow>(mCoreSpecific);
  51. }
  52. void LinuxRenderWindow::syncProperties()
  53. {
  54. ScopedSpinLock lock(getCore()->_getPropertiesLock());
  55. mProperties = getCore()->mSyncedProperties;
  56. }
  57. namespace ct
  58. {
  59. LinuxRenderWindow::LinuxRenderWindow(const RENDER_WINDOW_DESC& desc, UINT32 windowId, VulkanRenderAPI& renderAPI)
  60. : RenderWindow(desc, windowId), mRenderAPI(renderAPI), mRequiresNewBackBuffer(true), mWindow(nullptr)
  61. , mProperties(desc), mSyncedProperties(desc), mIsChild(false), mShowOnSwap(false)
  62. { }
  63. LinuxRenderWindow::~LinuxRenderWindow()
  64. {
  65. // Make sure to set the original desktop video mode before we exit
  66. if(mProperties.isFullScreen)
  67. setWindowed(50, 50);
  68. SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
  69. presentDevice->waitIdle();
  70. if (mWindow != nullptr)
  71. {
  72. Platform::resetNonClientAreas(*this);
  73. LinuxPlatform::lockX();
  74. bs_delete(mWindow);
  75. mWindow = nullptr;
  76. LinuxPlatform::unlockX();
  77. }
  78. mSwapChain = nullptr;
  79. vkDestroySurfaceKHR(mRenderAPI._getInstance(), mSurface, gVulkanAllocator);
  80. }
  81. void LinuxRenderWindow::initialize()
  82. {
  83. LinuxPlatform::lockX();
  84. RenderWindowProperties& props = mProperties;
  85. props.isFullScreen = mDesc.fullscreen;
  86. mIsChild = false;
  87. XVisualInfo visualInfoTempl = {};
  88. visualInfoTempl.screen = XDefaultScreen(LinuxPlatform::getXDisplay());
  89. visualInfoTempl.depth = 24;
  90. visualInfoTempl.c_class = TrueColor;
  91. int32_t numVisuals;
  92. XVisualInfo* visualInfo = XGetVisualInfo(LinuxPlatform::getXDisplay(),
  93. VisualScreenMask | VisualDepthMask | VisualClassMask, &visualInfoTempl, &numVisuals);
  94. WINDOW_DESC windowDesc;
  95. windowDesc.x = mDesc.left;
  96. windowDesc.y = mDesc.top;
  97. windowDesc.width = mDesc.videoMode.getWidth();
  98. windowDesc.height = mDesc.videoMode.getHeight();
  99. windowDesc.title = mDesc.title;
  100. windowDesc.showDecorations = mDesc.showTitleBar;
  101. windowDesc.allowResize = mDesc.allowResize;
  102. windowDesc.showOnTaskBar = !mDesc.toolWindow;
  103. windowDesc.modal = mDesc.modal;
  104. windowDesc.visualInfo = *visualInfo;
  105. windowDesc.screen = mDesc.videoMode.getOutputIdx();
  106. windowDesc.hidden = mDesc.hideUntilSwap || mDesc.hidden;
  107. NameValuePairList::const_iterator opt;
  108. opt = mDesc.platformSpecific.find("parentWindowHandle");
  109. if (opt != mDesc.platformSpecific.end())
  110. windowDesc.parent = (::Window)parseUINT64(opt->second);
  111. else
  112. windowDesc.parent = 0;
  113. mIsChild = windowDesc.parent != 0;
  114. props.isFullScreen = mDesc.fullscreen && !mIsChild;
  115. mShowOnSwap = mDesc.hideUntilSwap;
  116. props.isHidden = mDesc.hideUntilSwap || mDesc.hidden;
  117. mWindow = bs_new<LinuxWindow>(windowDesc);
  118. mWindow->_setUserData(this);
  119. props.width = mWindow->getWidth();
  120. props.height = mWindow->getHeight();
  121. props.top = mWindow->getTop();
  122. props.left = mWindow->getLeft();
  123. props.hwGamma = mDesc.gamma;
  124. props.multisampleCount = mDesc.multisampleCount;
  125. XWindowAttributes windowAttributes;
  126. XGetWindowAttributes(LinuxPlatform::getXDisplay(), mWindow->_getXWindow(), &windowAttributes);
  127. // Create Vulkan surface
  128. VkXlibSurfaceCreateInfoKHR surfaceCreateInfo;
  129. surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
  130. surfaceCreateInfo.pNext = nullptr;
  131. surfaceCreateInfo.flags = 0;
  132. surfaceCreateInfo.window = mWindow->_getXWindow();
  133. surfaceCreateInfo.dpy = LinuxPlatform::getXDisplay();
  134. // Note: I manually lock Xlib, while Vulkan spec says XInitThreads should be called, since Vulkan
  135. // surely calls Xlib under the hood as well. I've tried to guess which calls use Xlib and lock them
  136. // externally, but XInitThreads might be required if problems occur.
  137. VkInstance instance = mRenderAPI._getInstance();
  138. VkResult result = vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, gVulkanAllocator, &mSurface);
  139. assert(result == VK_SUCCESS);
  140. SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
  141. VkPhysicalDevice physicalDevice = presentDevice->getPhysical();
  142. mPresentQueueFamily = presentDevice->getQueueFamily(GQT_GRAPHICS);
  143. VkBool32 supportsPresent;
  144. vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, mPresentQueueFamily, mSurface, &supportsPresent);
  145. if(!supportsPresent)
  146. {
  147. // Note: Not supporting present only queues at the moment
  148. // Note: Also present device can only return one family of graphics queue, while there could be more (some of
  149. // which support present)
  150. BS_EXCEPT(RenderingAPIException, "Cannot find a graphics queue that also supports present operations.");
  151. }
  152. SurfaceFormat format = presentDevice->getSurfaceFormat(mSurface, mDesc.gamma);
  153. mColorFormat = format.colorFormat;
  154. mColorSpace = format.colorSpace;
  155. mDepthFormat = format.depthFormat;
  156. // Create swap chain
  157. mSwapChain = bs_shared_ptr_new<VulkanSwapChain>();
  158. mSwapChain->rebuild(presentDevice, mSurface, props.width, props.height, props.vsync, mColorFormat, mColorSpace,
  159. mDesc.depthBuffer, mDepthFormat);
  160. LinuxPlatform::unlockX(); // Calls below have their own locking mechanisms
  161. if(mDesc.fullscreen && !mIsChild)
  162. setFullscreen(mDesc.videoMode);
  163. if(mDesc.vsync && mDesc.vsyncInterval > 0)
  164. setVSync(true, mDesc.vsyncInterval);
  165. {
  166. ScopedSpinLock lock(mLock);
  167. mSyncedProperties = props;
  168. }
  169. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  170. RenderWindow::initialize();
  171. }
  172. void LinuxRenderWindow::acquireBackBuffer()
  173. {
  174. // We haven't presented the current back buffer yet, so just use that one
  175. if (!mRequiresNewBackBuffer)
  176. return;
  177. mSwapChain->acquireBackBuffer();
  178. mRequiresNewBackBuffer = false;
  179. }
  180. void LinuxRenderWindow::setFullscreen(UINT32 width, UINT32 height, float refreshRate, UINT32 monitorIdx)
  181. {
  182. THROW_IF_NOT_CORE_THREAD;
  183. VideoMode videoMode(width, height, refreshRate, monitorIdx);
  184. setFullscreen(videoMode);
  185. }
  186. void LinuxRenderWindow::setVideoMode(INT32 screen, RROutput output, RRMode mode)
  187. {
  188. ::Display* display = LinuxPlatform::getXDisplay();
  189. ::Window rootWindow = RootWindow(display, screen);
  190. XRRScreenResources* screenRes = XRRGetScreenResources (display, rootWindow);
  191. if(screenRes == nullptr)
  192. {
  193. LOGERR("XRR: Failed to retrieve screen resources. ");
  194. return;
  195. }
  196. XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screenRes, output);
  197. if(outputInfo == nullptr)
  198. {
  199. XRRFreeScreenResources(screenRes);
  200. LOGERR("XRR: Failed to retrieve output info for output: " + toString((UINT32)output));
  201. return;
  202. }
  203. XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screenRes, outputInfo->crtc);
  204. if(crtcInfo == nullptr)
  205. {
  206. XRRFreeScreenResources(screenRes);
  207. XRRFreeOutputInfo(outputInfo);
  208. LOGERR("XRR: Failed to retrieve CRTC info for output: " + toString((UINT32)output));
  209. return;
  210. }
  211. // Note: This changes the user's desktop resolution permanently, even when the app exists, make sure to revert
  212. // (Sadly there doesn't appear to be a better way)
  213. Status status = XRRSetCrtcConfig (display, screenRes, outputInfo->crtc, CurrentTime,
  214. crtcInfo->x, crtcInfo->y, mode, crtcInfo->rotation, &output, 1);
  215. if(status != Success)
  216. LOGERR("XRR: XRRSetCrtcConfig failed.");
  217. XRRFreeCrtcInfo(crtcInfo);
  218. XRRFreeOutputInfo(outputInfo);
  219. XRRFreeScreenResources(screenRes);
  220. }
  221. void LinuxRenderWindow::setFullscreen(const VideoMode& mode)
  222. {
  223. THROW_IF_NOT_CORE_THREAD;
  224. if (mIsChild)
  225. return;
  226. const LinuxVideoModeInfo& videoModeInfo =
  227. static_cast<const LinuxVideoModeInfo&>(RenderAPI::instance().getVideoModeInfo());
  228. UINT32 outputIdx = mode.getOutputIdx();
  229. if(outputIdx >= videoModeInfo.getNumOutputs())
  230. {
  231. LOGERR("Invalid output device index.")
  232. return;
  233. }
  234. const LinuxVideoOutputInfo& outputInfo =
  235. static_cast<const LinuxVideoOutputInfo&>(videoModeInfo.getOutputInfo (outputIdx));
  236. INT32 screen = outputInfo._getScreen();
  237. RROutput outputID = outputInfo._getOutputID();
  238. RRMode modeID = 0;
  239. if(!mode.isCustom())
  240. {
  241. const LinuxVideoMode& videoMode = static_cast<const LinuxVideoMode&>(mode);
  242. modeID = videoMode._getModeID();
  243. }
  244. else
  245. {
  246. LinuxPlatform::lockX();
  247. // Look for mode matching the requested resolution
  248. ::Display* display = LinuxPlatform::getXDisplay();
  249. ::Window rootWindow = RootWindow(display, screen);
  250. XRRScreenResources* screenRes = XRRGetScreenResources(display, rootWindow);
  251. if (screenRes == nullptr)
  252. {
  253. LOGERR("XRR: Failed to retrieve screen resources. ");
  254. return;
  255. }
  256. XRROutputInfo* outputInfo = XRRGetOutputInfo(display, screenRes, outputID);
  257. if (outputInfo == nullptr)
  258. {
  259. XRRFreeScreenResources(screenRes);
  260. LOGERR("XRR: Failed to retrieve output info for output: " + toString((UINT32)outputID));
  261. return;
  262. }
  263. XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(display, screenRes, outputInfo->crtc);
  264. if (crtcInfo == nullptr)
  265. {
  266. XRRFreeScreenResources(screenRes);
  267. XRRFreeOutputInfo(outputInfo);
  268. LOGERR("XRR: Failed to retrieve CRTC info for output: " + toString((UINT32)outputID));
  269. return;
  270. }
  271. bool foundMode = false;
  272. for (INT32 i = 0; i < screenRes->nmode; i++)
  273. {
  274. const XRRModeInfo& modeInfo = screenRes->modes[i];
  275. UINT32 width, height;
  276. if (crtcInfo->rotation & (XRANDR_ROTATION_LEFT | XRANDR_ROTATION_RIGHT))
  277. {
  278. width = modeInfo.height;
  279. height = modeInfo.width;
  280. }
  281. else
  282. {
  283. width = modeInfo.width;
  284. height = modeInfo.height;
  285. }
  286. float refreshRate;
  287. if (modeInfo.hTotal != 0 && modeInfo.vTotal != 0)
  288. refreshRate = (float) (modeInfo.dotClock / (double) (modeInfo.hTotal * modeInfo.vTotal));
  289. else
  290. refreshRate = 0.0f;
  291. if (width == mode.getWidth() && height == mode.getHeight())
  292. {
  293. modeID = modeInfo.id;
  294. foundMode = true;
  295. if (Math::approxEquals(refreshRate, mode.getRefreshRate()))
  296. break;
  297. }
  298. }
  299. if (!foundMode)
  300. {
  301. LinuxPlatform::unlockX();
  302. LOGERR("Unable to enter fullscreen, unsupported video mode requested.");
  303. return;
  304. }
  305. LinuxPlatform::unlockX();
  306. }
  307. LinuxPlatform::lockX();
  308. setVideoMode(screen, outputID, modeID);
  309. mWindow->_setFullscreen(true);
  310. LinuxPlatform::unlockX();
  311. RenderWindowProperties& props = mProperties;
  312. props.isFullScreen = true;
  313. props.top = 0;
  314. props.left = 0;
  315. props.width = mode.getWidth();
  316. props.height = mode.getHeight();
  317. _windowMovedOrResized();
  318. {
  319. ScopedSpinLock lock(mLock);
  320. mSyncedProperties.left = props.left;
  321. mSyncedProperties.top = props.top;
  322. mSyncedProperties.width = props.width;
  323. mSyncedProperties.height = props.height;
  324. }
  325. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  326. bs::RenderWindowManager::instance().notifyMovedOrResized(this);
  327. }
  328. void LinuxRenderWindow::setWindowed(UINT32 width, UINT32 height)
  329. {
  330. THROW_IF_NOT_CORE_THREAD;
  331. RenderWindowProperties& props = mProperties;
  332. if (!props.isFullScreen)
  333. return;
  334. // Restore old screen config
  335. const LinuxVideoModeInfo& videoModeInfo =
  336. static_cast<const LinuxVideoModeInfo&>(RenderAPI::instance().getVideoModeInfo());
  337. UINT32 outputIdx = 0; // 0 is always primary
  338. if(outputIdx >= videoModeInfo.getNumOutputs())
  339. {
  340. LOGERR("Invalid output device index.")
  341. return;
  342. }
  343. const LinuxVideoOutputInfo& outputInfo =
  344. static_cast<const LinuxVideoOutputInfo&>(videoModeInfo.getOutputInfo (outputIdx));
  345. const LinuxVideoMode& desktopVideoMode = static_cast<const LinuxVideoMode&>(outputInfo.getDesktopVideoMode());
  346. LinuxPlatform::lockX();
  347. setVideoMode(outputInfo._getScreen(), outputInfo._getOutputID(), desktopVideoMode._getModeID());
  348. mWindow->_setFullscreen(false);
  349. LinuxPlatform::unlockX();
  350. props.isFullScreen = false;
  351. props.width = width;
  352. props.height = height;
  353. _windowMovedOrResized();
  354. {
  355. ScopedSpinLock lock(mLock);
  356. mSyncedProperties.left = props.left;
  357. mSyncedProperties.top = props.top;
  358. mSyncedProperties.width = props.width;
  359. mSyncedProperties.height = props.height;
  360. }
  361. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  362. bs::RenderWindowManager::instance().notifyMovedOrResized(this);
  363. }
  364. void LinuxRenderWindow::move(INT32 left, INT32 top)
  365. {
  366. THROW_IF_NOT_CORE_THREAD;
  367. RenderWindowProperties& props = mProperties;
  368. if (!props.isFullScreen)
  369. {
  370. LinuxPlatform::lockX();
  371. mWindow->move(left, top);
  372. LinuxPlatform::unlockX();
  373. props.top = mWindow->getTop();
  374. props.left = mWindow->getLeft();
  375. {
  376. ScopedSpinLock lock(mLock);
  377. mSyncedProperties.top = props.top;
  378. mSyncedProperties.left = props.left;
  379. }
  380. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  381. }
  382. }
  383. void LinuxRenderWindow::resize(UINT32 width, UINT32 height)
  384. {
  385. THROW_IF_NOT_CORE_THREAD;
  386. RenderWindowProperties& props = mProperties;
  387. if (!props.isFullScreen)
  388. {
  389. LinuxPlatform::lockX();
  390. mWindow->resize(width, height);
  391. LinuxPlatform::unlockX();
  392. props.width = mWindow->getWidth();
  393. props.height = mWindow->getHeight();
  394. {
  395. ScopedSpinLock lock(mLock);
  396. mSyncedProperties.width = props.width;
  397. mSyncedProperties.height = props.height;
  398. }
  399. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  400. }
  401. }
  402. void LinuxRenderWindow::minimize()
  403. {
  404. THROW_IF_NOT_CORE_THREAD;
  405. LinuxPlatform::lockX();
  406. mWindow->minimize();
  407. LinuxPlatform::unlockX();
  408. }
  409. void LinuxRenderWindow::maximize()
  410. {
  411. THROW_IF_NOT_CORE_THREAD;
  412. LinuxPlatform::lockX();
  413. mWindow->maximize();
  414. LinuxPlatform::unlockX();
  415. }
  416. void LinuxRenderWindow::restore()
  417. {
  418. THROW_IF_NOT_CORE_THREAD;
  419. LinuxPlatform::lockX();
  420. mWindow->restore();
  421. LinuxPlatform::unlockX();
  422. }
  423. void LinuxRenderWindow::setVSync(bool enabled, UINT32 interval)
  424. {
  425. THROW_IF_NOT_CORE_THREAD;
  426. if(!enabled)
  427. interval = 0;
  428. SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
  429. presentDevice->waitIdle();
  430. LinuxPlatform::lockX();
  431. mSwapChain->rebuild(presentDevice, mSurface, mProperties.width, mProperties.height, enabled, mColorFormat,
  432. mColorSpace, mDesc.depthBuffer, mDepthFormat);
  433. LinuxPlatform::unlockX();
  434. mProperties.vsync = enabled;
  435. mProperties.vsyncInterval = interval;
  436. {
  437. ScopedSpinLock lock(mLock);
  438. mSyncedProperties.vsync = enabled;
  439. mSyncedProperties.vsyncInterval = interval;
  440. }
  441. bs::RenderWindowManager::instance().notifySyncDataDirty(this);
  442. }
  443. void LinuxRenderWindow::swapBuffers(UINT32 syncMask)
  444. {
  445. THROW_IF_NOT_CORE_THREAD;
  446. if (mShowOnSwap)
  447. setHidden(false);
  448. LinuxPlatform::lockX();
  449. // Get a command buffer on which we'll submit
  450. SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
  451. // Assuming present queue is always graphics
  452. assert(presentDevice->getQueueFamily(GQT_GRAPHICS) == mPresentQueueFamily);
  453. // Find an appropriate queue to execute on
  454. VulkanQueue* queue = presentDevice->getQueue(GQT_GRAPHICS, 0);
  455. UINT32 queueMask = presentDevice->getQueueMask(GQT_GRAPHICS, 0);
  456. // Ignore myself
  457. syncMask &= ~queueMask;
  458. UINT32 deviceIdx = presentDevice->getIndex();
  459. VulkanCommandBufferManager& cbm = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
  460. UINT32 numSemaphores;
  461. cbm.getSyncSemaphores(deviceIdx, syncMask, mSemaphoresTemp, numSemaphores);
  462. // Wait on present (i.e. until the back buffer becomes available), if we haven't already done so
  463. const SwapChainSurface& surface = mSwapChain->getBackBuffer();
  464. if(surface.needsWait)
  465. {
  466. mSemaphoresTemp[numSemaphores] = mSwapChain->getBackBuffer().sync;
  467. numSemaphores++;
  468. mSwapChain->notifyBackBufferWaitIssued();
  469. }
  470. queue->present(mSwapChain.get(), mSemaphoresTemp, numSemaphores);
  471. mRequiresNewBackBuffer = true;
  472. LinuxPlatform::unlockX();
  473. }
  474. void LinuxRenderWindow::copyToMemory(PixelData &dst, FrameBuffer buffer)
  475. {
  476. THROW_IF_NOT_CORE_THREAD;
  477. assert(false && "Not implemented");
  478. }
  479. void LinuxRenderWindow::getCustomAttribute(const String& name, void* data) const
  480. {
  481. if (name == "FB")
  482. {
  483. VulkanFramebuffer** fb = (VulkanFramebuffer**)data;
  484. *fb = mSwapChain->getBackBuffer().framebuffer;
  485. return;
  486. }
  487. if(name == "SC")
  488. {
  489. VulkanSwapChain** sc = (VulkanSwapChain**)data;
  490. *sc = mSwapChain.get();
  491. return;
  492. }
  493. if(name == "LINUX_WINDOW")
  494. {
  495. LinuxWindow** window = (LinuxWindow**)data;
  496. *window = mWindow;
  497. return;
  498. }
  499. if(name == "WINDOW")
  500. {
  501. ::Window* window = (::Window*)data;
  502. *window = mWindow->_getXWindow();
  503. return;
  504. }
  505. }
  506. void LinuxRenderWindow::setActive(bool state)
  507. {
  508. THROW_IF_NOT_CORE_THREAD;
  509. LinuxPlatform::lockX();
  510. if(state)
  511. mWindow->restore();
  512. else
  513. mWindow->minimize();
  514. LinuxPlatform::unlockX();
  515. RenderWindow::setActive(state);
  516. }
  517. void LinuxRenderWindow::setHidden(bool hidden)
  518. {
  519. THROW_IF_NOT_CORE_THREAD;
  520. if(!hidden)
  521. mShowOnSwap = false;
  522. LinuxPlatform::lockX();
  523. if(hidden)
  524. mWindow->hide();
  525. else
  526. mWindow->show();
  527. LinuxPlatform::unlockX();
  528. RenderWindow::setHidden(hidden);
  529. }
  530. void LinuxRenderWindow::_windowMovedOrResized()
  531. {
  532. if (!mWindow)
  533. return;
  534. RenderWindowProperties& props = mProperties;
  535. if (!props.isFullScreen) // Fullscreen is handled directly by this object
  536. {
  537. props.top = mWindow->getTop();
  538. props.left = mWindow->getLeft();
  539. props.width = mWindow->getWidth();
  540. props.height = mWindow->getHeight();
  541. }
  542. // Resize swap chain
  543. //// Need to make sure nothing is using the swap buffer before we re-create it
  544. // Note: Optionally I can detect exactly on which queues (if any) are the swap chain images used on, and only wait
  545. // on those
  546. SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
  547. presentDevice->waitIdle();
  548. // Note: This assumes that this method was called from the main message loop, which already acquires X locks,
  549. // so no need to lock here explicitly
  550. mSwapChain->rebuild(presentDevice, mSurface, props.width, props.height, props.vsync, mColorFormat, mColorSpace,
  551. mDesc.depthBuffer, mDepthFormat);
  552. }
  553. void LinuxRenderWindow::syncProperties()
  554. {
  555. ScopedSpinLock lock(mLock);
  556. mProperties = mSyncedProperties;
  557. }
  558. }}