Skip to content

Commit

Permalink
[SwapChain] Added IsPresentable() to SwapChain interface.
Browse files Browse the repository at this point in the history
This new function allows to detect when the native surface of a swap-chain is temporarily unavailable.
This occurs when a mobile app is paused and the native surface is destroyed, while it is later re-initialized when the app resumes.
Also moved all SwapChain interface declarations to Backend/SwapChain.inl header as for other interfaces with more than one or two functions.
  • Loading branch information
LukasBanana committed Aug 8, 2024
1 parent b78b7e3 commit 2232eb6
Show file tree
Hide file tree
Showing 34 changed files with 241 additions and 127 deletions.
42 changes: 29 additions & 13 deletions examples/Cpp/ExampleBase/ExampleBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "ImageReader.h"
#include "FileUtils.h"
#include <stdio.h>
#include <thread>

#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
Expand Down Expand Up @@ -380,13 +381,25 @@ void ExampleBase::Run()
bool fullscreen = false;
const LLGL::Extent2D initialResolution = swapChain->GetResolution();

#ifdef LLGL_MOBILE_PLATFORM
while (LLGL::Surface::ProcessEvents())
#else
#ifndef LLGL_MOBILE_PLATFORM
LLGL::Window& window = LLGL::CastTo<LLGL::Window>(swapChain->GetSurface());
while (LLGL::Surface::ProcessEvents() && !window.HasQuit() && !input.KeyDown(LLGL::Key::Escape))
#endif

while (LLGL::Surface::ProcessEvents() && !input.KeyDown(LLGL::Key::Escape))
{
#ifndef LLGL_MOBILE_PLATFORM
// On desktop platforms, we also want to quit the app if the close button has been pressed
if (window.HasQuit())
break;
#endif

// On mobile platforms, if app has paused, the swap-chain might not be presentable until the app is resumed again
if (!swapChain->IsPresentable())
{
std::this_thread::yield();
continue;
}

#ifdef LLGL_OS_ANDROID
if (input.KeyDown(LLGL::Key::BrowserBack))
ANativeActivity_finish(ExampleBase::androidApp_->activity);
Expand Down Expand Up @@ -484,17 +497,20 @@ ExampleBase::ExampleBase(const LLGL::UTF8String& title)
LLGL::RenderSystemDescriptor rendererDesc = g_Config.rendererModule;

#if defined LLGL_OS_ANDROID
LLGL::RendererConfigurationOpenGL cfgGL;
if (android_app* app = ExampleBase::androidApp_)
if (rendererDesc.moduleName == "OpenGLES3")
{
rendererDesc.androidApp = app;
cfgGL.majorVersion = 3;
cfgGL.minorVersion = 1;
rendererDesc.rendererConfig = &cfgGL;
rendererDesc.rendererConfigSize = sizeof(cfgGL);
LLGL::RendererConfigurationOpenGL cfgGL;
if (android_app* app = ExampleBase::androidApp_)
{
rendererDesc.androidApp = app;
cfgGL.majorVersion = 3;
cfgGL.minorVersion = 1;
rendererDesc.rendererConfig = &cfgGL;
rendererDesc.rendererConfigSize = sizeof(cfgGL);
}
else
throw std::invalid_argument("'android_app' state was not specified");
}
else
throw std::invalid_argument("'android_app' state was not specified");
#endif

if (g_Config.debugger)
Expand Down
1 change: 1 addition & 0 deletions include/LLGL-C/SwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <stdint.h>


LLGL_C_EXPORT bool llglIsPresentable(LLGLSwapChain swapChain);
LLGL_C_EXPORT void llglPresent(LLGLSwapChain swapChain);
LLGL_C_EXPORT uint32_t llglGetCurrentSwapIndex(LLGLSwapChain swapChain);
LLGL_C_EXPORT uint32_t llglGetNumSwapBuffers(LLGLSwapChain swapChain);
Expand Down
46 changes: 46 additions & 0 deletions include/LLGL/Backend/SwapChain.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SwapChain.inl
*
* Copyright (c) 2015 Lukas Hermanns. All rights reserved.
* Licensed under the terms of the BSD 3-Clause license (see LICENSE.txt).
*/

virtual bool IsPresentable(
void
) const override final;

virtual void Present(
void
) override final;

virtual std::uint32_t GetCurrentSwapIndex(
void
) const override final;

virtual std::uint32_t GetNumSwapBuffers(
void
) const override final;

virtual std::uint32_t GetSamples(
void
) const override final;

virtual LLGL::Format GetColorFormat(
void
) const override final;

virtual LLGL::Format GetDepthStencilFormat(
void
) const override final;

virtual const LLGL::RenderPass* GetRenderPass(
void
) const override;

virtual bool SetVsyncInterval(
std::uint32_t vsyncInterval
) override final;



// ================================================================================
22 changes: 22 additions & 0 deletions include/LLGL/SwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ class LLGL_EXPORT SwapChain : public RenderTarget

/* ----- Back Buffer ----- */

/**
\brief Returns true if this swap-chain is ready for rendering and presenting. Otherwise, the native surface or back buffer are not available.
\remarks This is mostly used for mobile platforms where the surface can be temporarily destroyed when the app is paused and later re-initialized when the app resumes.
If this is false, no rendering to this swap-chain must be performed nor can the back buffer be presented.
\remarks A safe way to handle the event of a lost native surface is to skip the entire rendering when this returns false as shown below:
\code
while (LLGL::Surface::ProcessEvents()) {
// Skip frame if swap-chain is currently not presentable
if (!swapChain->IsPresentable()) {
std::this_thread::yield();
continue;
}
// Render frame ...
// Present swap-chain back buffer
swapChain->Present();
}
\endcode
*/
virtual bool IsPresentable() const = 0;

/**
\brief Swaps the current back buffer with the front buffer to present it on the screen.
\see GetCurrentSwapIndex
Expand Down
6 changes: 0 additions & 6 deletions sources/Platform/Android/AndroidCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ bool Surface::ProcessEvents()
if (source != nullptr)
source->process(app, source);

/* Process sensor data */
/*if (ident == LOOPER_ID_USER)
{
//TODO
}*/

/* Check if we are exiting */
if (app->destroyRequested != 0)
return false;
Expand Down
8 changes: 8 additions & 0 deletions sources/Renderer/DebugLayer/DbgCommandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,14 @@ void DbgCommandBuffer::BeginRenderPass(
{
auto& swapChainDbg = LLGL_DBG_CAST(DbgSwapChain&, renderTarget);

if (!swapChainDbg.IsPresentable())
{
LLGL_DBG_ERROR(
ErrorType::InvalidState,
"cannot begin new render pass with swap chain that is not presentable"
);
}

swapChainDbg.NotifyNextRenderPass(debugger_, renderPass);

bindings_.swapChain = &swapChainDbg;
Expand Down
5 changes: 5 additions & 0 deletions sources/Renderer/DebugLayer/DbgSwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ void DbgSwapChain::SetDebugName(const char* name)
DbgSetObjectName(*this, name);
}

bool DbgSwapChain::IsPresentable() const
{
return instance.IsPresentable();
}

void DbgSwapChain::Present()
{
instance.Present();
Expand Down
15 changes: 3 additions & 12 deletions sources/Renderer/DebugLayer/DbgSwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,11 @@ class DbgSwapChain final : public SwapChain

public:

void SetDebugName(const char* name) override;

void Present() override;

std::uint32_t GetCurrentSwapIndex() const override;
std::uint32_t GetNumSwapBuffers() const override;
std::uint32_t GetSamples() const override;
#include <LLGL/Backend/SwapChain.inl>

Format GetColorFormat() const override;
Format GetDepthStencilFormat() const override;

bool SetVsyncInterval(std::uint32_t vsyncInterval) override;
public:

const RenderPass* GetRenderPass() const override;
void SetDebugName(const char* name) override;

public:

Expand Down
5 changes: 5 additions & 0 deletions sources/Renderer/Direct3D11/D3D11SwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ void D3D11SwapChain::SetDebugName(const char* name)
}
}

bool D3D11SwapChain::IsPresentable() const
{
return true; // dummy
}

void D3D11SwapChain::Present()
{
const bool tearingEnabled = (tearingSupported_ && windowedMode_ && swapChainInterval_ == 0);
Expand Down
17 changes: 4 additions & 13 deletions sources/Renderer/Direct3D11/D3D11SwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class D3D11RenderSystem;
class D3D11SwapChain final : public SwapChain
{

public:

#include <LLGL/Backend/SwapChain.inl>

public:

D3D11SwapChain(
Expand All @@ -41,19 +45,6 @@ class D3D11SwapChain final : public SwapChain

void SetDebugName(const char* name) override;

void Present() override;

std::uint32_t GetCurrentSwapIndex() const override;
std::uint32_t GetNumSwapBuffers() const override;
std::uint32_t GetSamples() const override;

Format GetColorFormat() const override;
Format GetDepthStencilFormat() const override;

const RenderPass* GetRenderPass() const override;

bool SetVsyncInterval(std::uint32_t vsyncInterval) override;

public:

// Copyies a subresource region from the backbuffer (color or depth-stencil) into the destination resource.
Expand Down
5 changes: 5 additions & 0 deletions sources/Renderer/Direct3D12/D3D12SwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ void D3D12SwapChain::SetDebugName(const char* name)
}
}

bool D3D12SwapChain::IsPresentable() const
{
return true; // dummy
}

void D3D12SwapChain::Present()
{
/* Present swap-chain with vsync interval */
Expand Down
15 changes: 3 additions & 12 deletions sources/Renderer/Direct3D12/D3D12SwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,11 @@ class D3D12SwapChain final : public SwapChain

public:

void SetDebugName(const char* name) override;

void Present() override;

std::uint32_t GetCurrentSwapIndex() const override;
std::uint32_t GetNumSwapBuffers() const override;
std::uint32_t GetSamples() const override;
#include <LLGL/Backend/SwapChain.inl>

Format GetColorFormat() const override;
Format GetDepthStencilFormat() const override;

const RenderPass* GetRenderPass() const override;
public:

bool SetVsyncInterval(std::uint32_t vsyncInterval) override;
void SetDebugName(const char* name) override;

public:

Expand Down
17 changes: 3 additions & 14 deletions sources/Renderer/Metal/MTSwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class MTSwapChain final : public SwapChain

public:

/* ----- Common ----- */
#include <LLGL/Backend/SwapChain.inl>

public:

MTSwapChain(
id<MTLDevice> device,
Expand All @@ -40,19 +42,6 @@ class MTSwapChain final : public SwapChain
const RendererInfo& rendererInfo
);

void Present() override;

std::uint32_t GetCurrentSwapIndex() const override;
std::uint32_t GetNumSwapBuffers() const override;
std::uint32_t GetSamples() const override;

Format GetColorFormat() const override;
Format GetDepthStencilFormat() const override;

const RenderPass* GetRenderPass() const override;

bool SetVsyncInterval(std::uint32_t vsyncInterval) override;

public:

// Updates the native render pass descriptor with the specified clear values. Returns null on failure.
Expand Down
5 changes: 5 additions & 0 deletions sources/Renderer/Metal/MTSwapChain.mm
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
ShowSurface();
}

bool MTSwapChain::IsPresentable() const
{
return true; //TODO
}

void MTSwapChain::Present()
{
/* Present backbuffer */
Expand Down
5 changes: 5 additions & 0 deletions sources/Renderer/Null/NullSwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ void NullSwapChain::SetDebugName(const char* name)
label_.clear();
}

bool NullSwapChain::IsPresentable() const
{
return true; // dummy
}

void NullSwapChain::Present()
{
// dummy
Expand Down
23 changes: 7 additions & 16 deletions sources/Renderer/Null/NullSwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,19 @@ class NullSwapChain final : public SwapChain

public:

NullSwapChain(
const SwapChainDescriptor& desc,
const std::shared_ptr<Surface>& surface,
const RendererInfo& rendererInfo
);
#include <LLGL/Backend/SwapChain.inl>

public:

void SetDebugName(const char* name) override;

void Present() override;

std::uint32_t GetCurrentSwapIndex() const override;
std::uint32_t GetNumSwapBuffers() const override;
std::uint32_t GetSamples() const override;

Format GetColorFormat() const override;
Format GetDepthStencilFormat() const override;

bool SetVsyncInterval(std::uint32_t vsyncInterval) override;
public:

const RenderPass* GetRenderPass() const override;
NullSwapChain(
const SwapChainDescriptor& desc,
const std::shared_ptr<Surface>& surface,
const RendererInfo& rendererInfo
);

private:

Expand Down
Loading

0 comments on commit 2232eb6

Please sign in to comment.