SilverLining
SilverLining::ThreadCameraStreamData Class Reference

This class is the main interface to thread safe rendering with SilverLining. More...

#include <ThreadCameraStreamData.h>

Inheritance diagram for SilverLining::ThreadCameraStreamData:
Collaboration diagram for SilverLining::ThreadCameraStreamData:

Public Member Functions

 ThreadCameraStreamData (bool rightHanded, double unitScale, bool deferred)
 constructor
 
virtual ~ThreadCameraStreamData ()
 destructor
 
const CameraGetCamera (void) const
 These are the only public methods you need to use to render multiple views using multiple threads with/without command lists.
 
CameraGetCamera (void)
 get the associated camera (non-const)
 
int Initialize (int rendererType, bool rightHanded, void *environment, bool avoidStalls)
 Initialize the ThreadCameraStreamData (call first)
 
int Initialize (int rendererType, bool rightHanded, void *environment, bool avoidStalls, const SL_VECTOR(unsigned int)&userShaders)
 OpenGL-only variant of ThreadCameraStreamData::Initialize() that takes in a list of user-compiled shader objects that will be linked into all subsequently linked shader program objects.
 
void Initialize (const Atmosphere &atmosphere)
 Initialize the ThreadCameraStreamData for a given Atmosphere object (call 2nd)
 
bool IsInitialized (void) const
 Whether initialized.
 
void ExecuteStream (void)
 For OpenGL: Execute the command list for this object.
 
void SetStream (void *stream, int frameIndex=-1)
 Set the current command buffer that we are recording to (only for Vulkan renderer).
 
void SetRandomNumberGenerator (RandomNumberGenerator *rng)
 Some effects (like lightning) need to be synchronized across multiple views.
 
RandomNumberGeneratorGetRandomNumberGenerator () const
 Get the random number generator.
 
void SetEnvironmentMapFormat (ColorFormat format)
 Vulkan only.
 
void SetUseShadowMap (bool val)
 Vulkan only.
 
void SettingsChanged (void *environment)
 Vulkan only.
 
void SetUserData (const void *userPointer, TcsUserData *userData)
 !
 
TcsUserDataGetUserData (const void *userPointer)
 get a user pointer and the user data associated with it, if it exists null otherwise
 
bool UserDataExists (const void *userPointer) const
 whether user data exists for a user pointer
 
void EraseUserData (const void *userPointer)
 erase user data associated with this layer (just erases the entry)
 
void SetCloudLayerTcsUserData (const CloudLayer *cloudLayer, TcsUserData *userData)
 These are named variations of the 3 functions above.
 
TcsUserDataGetCloudLayerTcsUserData (const CloudLayer *cloudLayer)
 get the name with userDataName as the key
 
bool CloudLayerTcsUserDataExists (const CloudLayer *cloudLayer)
 exists?
 
void EraseCloudLayerTcsUserData (const CloudLayer *cloudLayer)
 erase user data associated with this layer (just erases the entry)
 
Renderer * GetRenderer (void)
 internal. do not use directly
 
const Renderer * GetRenderer (void) const
 internal. do not use directly
 
const BillboardRenderingParameters * GetBillboardRenderingParams (void) const
 internal. Do not use directly. Get the parameters, const version
 
BillboardRenderingParameters * GetBillboardRenderingParams (void)
 internal. Do not use directly. Get the parameters, non-const version
 
const MetaballRenderingParameters * GetMetaballRenderingParams (void) const
 internal. Do not use directly. Get the parameters, const version
 
MetaballRenderingParameters * GetMetaballRenderingParams (void)
 internal. Do not use directly. Get the parameters, non-const version
 
const BillboardRenderer * GetBillboardRenderer (void) const
 internal. Do not use directly. Get the billboard renderer, const version
 
BillboardRenderer * GetBillboardRenderer (void)
 internal. Do not use directly. Get the billboard renderer, non-const version
 
const CloudRenderingParameters * GetCloudRenderingParams (void) const
 internal. Do not use directly. Get the parameters, const version
 
CloudRenderingParameters * GetCloudRenderingParams (void)
 internal. Do not use directly. Get the parameters, non-const version
 
const CumulusCloudRenderingParameters * GetCumulusCloudRenderingParams (void) const
 internal. Do not use directly. Get the parameters, const version
 
CumulusCloudRenderingParameters * GetCumulusCloudRenderingParams (void)
 internal. Do not use directly. Get the parameters, non-const version
 
const LuminanceMapper * GetLuminanceMappper (void) const
 internal. Do not use directly. Get the parameters, const version
 
LuminanceMapper * GetLuminanceMappper (void)
 internal. Do not use directly. Get the parameters, non-const version
 
bool GetIsDrawingEnvMap () const
 internal. Do not use directly. Whether drawing env map currently
 
void SetIsDrawingEnvMap (bool val)
 internal. Do not use directly. Set drawing env map to true/false
 
bool GetIsDrawingShadowMap () const
 internal. Do not use directly. Whether drawing shadow map currently
 
void SetIsDrawingShadowMap (bool val)
 internal. Do not use directly. Set drawing shadow map to true/false
 
bool GetSortByScreenDepth (void) const
 internal. Do not use directly. Get sort screen depth
 
void SetSortByScreenDepth (bool val)
 internal. Do not use directly. Set sort screen depth
 
const BillboardShader * GetBillboardShader (void) const
 internal. do not use!
 
const BillboardShader * GetBillboardShaderInstanced (void) const
 internal. do not use!
 
void ReloadShaders (void)
 internal. do not use!
 
void Shutdown (void)
 internal. do not use!
 
void DeviceLost (void)
 internal. do not use!
 
void DeviceReset (void)
 internal. do not use!
 
void FrameStarted ()
 internal. do not use!
 
void SetContext ()
 internal. do not use!
 
void ReloadBillboardShader (void)
 internal. do not use!
 
const SkyShaders * GetSkyShaders (bool simpleShader) const
 internal. do not use!
 
void ReloadSkyShaders (void)
 internal. do not use!
 
const StratocumulusShaders * GetStratocumulusShaders (void) const
 internal. do not use!
 
void ReloadStratocumulusShaders (void)
 internal. do not use!
 
const FlareShader * GetFlareShader (void) const
 internal. do not use!
 
const CirrusShader * GetCirrusShader (void) const
 internal. do not use!
 
void ReloadCirrusShader (void)
 internal. do not use!
 
const StratusShader * GetStratusShader (void) const
 internal. do not use!
 
void ReloadStratusShader (void)
 internal. do not use!
 
const StarShader * GetStarShader (void) const
 internal. do not use!
 
void ReloadStarShader (void)
 internal. do not use!
 
const GlareShader * GetGlareShader (void) const
 internal. do not use!
 
GlareShader * GetGlareShader (void)
 internal. do not use!
 
const AtmosphereFromSpaceShader * GetAtmosphereFromSpaceShader (bool doShadow) const
 internal. do not use!
 
bool GetDeferred (void) const
 get whether internal stream/context is a deferred stream call before initialize!
 
CrepuscularRays * GetCrepuscularRays (void)
 internal. do not use!
 
const CrepuscularRays * GetCrepuscularRays (void) const
 internal. do not use!
 
Sky * GetSky (void)
 internal. do not use!
 
const Sky * GetSky (void) const
 internal. do not use!
 
LensFlare * GetLensFlare (void)
 internal. do not use!
 
const LensFlare * GetLensFlare (void) const
 internal. do not use!
 
bool GetIsDrawingSky (void) const
 internal. do not use!
 
bool GetIsDrawingObjects (void) const
 internal. do not use!
 
void SetIsDrawingSky (bool val)
 internal. do not use!
 
void SetIsDrawingObjects (bool val)
 internal. do not use!
 
void SetForceImmediate (bool val)
 internal. do not use!
 
bool GetForceImmediate (void) const
 internal. do not use!
 
const PrecipitationShaders * GetPrecipitationShaders (void) const
 internal. do not use!
 
PrecipitationShaders * GetPrecipitationShaders (void)
 internal. do not use!
 
void SetUpAndRightVector (const Vector3 &upVector, const Vector3 &rightVector)
 Helper function to set up the up and right vector on the Camera of this tcs data.
 
const PrecipitationManager * GetPrecipitationManager (void) const
 internal. do not use!
 
PrecipitationManager * GetPrecipitationManager (void)
 internal. do not use!
 
void InitializePrecipitationManager (const Atmosphere &atmosphere)
 internal. do not use!
 
bool GetPrecipitationEnabled (void) const
 internal. do not use!
 
const ShadowMap * GetOrCreateShadowMap (const Atmosphere &atmosphere) const
 internal. do not use!
 
ShadowMap * GetOrCreateShadowMap (const Atmosphere &atmosphere)
 internal. do not use!
 
const ShadowMap * GetShadowMapObject (void) const
 internal. do not use!
 
int GetShadowMapDim () const
 internal. do not use!
 
void DeleteShadowMap (void)
 internal. do not use!
 
void DeleteEnvironmentMaps (void)
 internal. do not use!
 
const TextureManager * GetTextureManager (void) const
 internal. do not use!
 
void setCreateTextures (bool create)
 internal. do not use!
 
bool GetEnvironmentMap (EnvironmentMap *&environmentMap, Atmosphere &atmosphere, void *&texture, int facesToRender=6, bool floatingPoint=false, CameraHandle cameraID=0, bool drawClouds=true, bool drawSunAndMoon=true, bool geocentricMode=false)
 internal. do not use!
 
bool DrawIndirect () const
 internal. do not use!
 
void SetInfraRedMode (bool bInfraRed)
 set infra red mode
 
bool GetInfraRedMode () const
 whether infra red model
 
void SetTime (const LocalTime &pTime, unsigned long timerMilliseconds)
 internal. do not use!
 
const LocalTimeGetTime (unsigned long timerMilliseconds)
 internal. do not use!
 
void SetLocation (const Location &_location)
 internal. do not use!
 
const LocationGetLocation () const
 internal. do not use!
 
LocationGetLocation ()
 internal. do not use!
 
void SetBaseTimeMS (unsigned long val)
 internal. do not use!
 
unsigned long GetBaseTimeMS (void) const
 internal. do not use!
 
void EnableTimePassage (bool enabled, long relightFrequencyMS, unsigned long timerMilliseconds)
 internal. do not use!
 
LocalTimeGetTime ()
 internal. These are used for serialization only
 
bool GetHDREnabled () const
 internal helper
 
const float * GetStratusMieLookupPixels (int &width)
 internal.
 
const unsigned char * GetStratusNoisePixels (int &width, int &height)
 internal.
 
std::ostream & log (LogLevel level)
 logging //!
 

Protected Member Functions

void CreateStratusMieLookupPixels (void)
 internal
 

Detailed Description

This class is the main interface to thread safe rendering with SilverLining.

The class represents the concept of thread local storage: https://en.wikipedia.org/wiki/Thread-local_storage

The 'thread' part of the name represents each separate thread (and hence each instance of this class) that we wish to render from in a thread safe fashion.

The 'camera' part of the name represents each view(e.g. window/offscreen view) that you wish to render from in a thread safe fashion in the corresponding thread.

This typically also corresponds to an OpenGL context (you can share OpenGL contexts or not) or an immediate/deferred DirectX context.

The 'stream' part of the name represents the command stream (OpenGL/Vulkan) or the immediate/deferred context commands (DX 11, 11.1) being generated for a given thread, view.

As an example, to render 3 views (one main view, and 2 offscreen views).

Below are then the steps you follow to render everything in a thread safe fashion:

  • Instantiate 3 objects of this class. This has to be done where the OpenGL/DirectX context is active, and the atmosphere has already been created & initialized.
  • Set up the initial up and right vectors on the camera of each object by getting the camera associated with this ThreadCameraStreamData (or tcsData for short), the same as the atmosphere and also set up the view port of the camera (the size of the render target being rendered to).
  • Initialize each object by first calling the first variant of the Initialize function that takes the renderer type. This must match the atmosphere renderer type that you initialized the atmosphere type with. The last parameter is important.
  • Then, you initialize each object by first calling the second variant of the Initialize function that takes the atmosphere that you wish to render in a thread safe fashion.
    • You must optionally also set up the render target (an fbo in the case of OpenGL32) if the tcsData in question, is going to be used to render into an offscreen view.
  • Next, you set up the individual cloud layers that will get rendered for each thread/camera (view)/stream:
    • Create a cloud layer.
    • Set up the cloud layer(s):
      • Any methods that do not take the optional tcsData need be called once after creation.
      • Any methods that take the optional tcsData parameter need to be called with each tcsData (so in our case, 3 different sets of calls for each layer).
      • Add the layer to the AtmosphericConditions like usual.
  • Following this, you can render like you normally do with a few changes:

A few notes:

  • This basic flow for rendering with ThreadCameraStreamData is all very similar to the existing steps/flow/API to render with SilverLining, and to that end we have also tried to minimize changes to the API and retained the existing API/way as much as possible. So, existing applications should work the same.
  • We recommend, however, that you use this interface/setup/flow to do all SilverLining rendering going forward. Specifically, we recommend manipulating multiple views and passing the view/projection matrices using instances of this class (by getting the camera) even if you don't require multi-threading. This way you decouple the data (Atmosphere) from the view in question and lend yourself easily to render/manipulate multiple views/channels/windows (including adding/removing windows/channels via instantiating/deleting the associated tcsData) in a versatile & straightforward way.
  • All the public interfaces now take an optional void* data parameter that pertains to a pointer of an object of this class representing the thread/camera (view) /stream/ in question.
  • This includes:

So make sure to pass the pointer to the object of the thread/camera(view)/stream in question in the same order/position/context of which thread/camera(view)/stream is in question.

  • These are the only functions you need to use on ThreadCameraStreamData:
    • The 2 initialization functions
    • GetCamera (and subsequently manipulate the view/projection)
    • ExecuteStream (see section on deferred rendering)

Multi-Threading:

  • Using this interface with these steps inherently makes silverlining completely thread safe for rendering each thread/camera (view)/stream. So in our example, you could render all 3 views simultaneously in a thread safe fashion. We did not have support for this before and users typically had to instantiate multiple atmospheres, etc to work around it.
  • However, you should not use this method to render using multiple OpenGL contexts, in multiple threads and switching them. Your performance will not improve, and in most cases degrade slightly, because the GPU will still serialize the calls internally and switching contexts (at least in OpenGL is expensive):
  • This brings us to the next point, deferred rendering.

Deferred Rendering:

  • A key observation of any rendering is that the actual work of generating commands for the GPU to execute and then actually executing them on the GPU can effectively be decoupled.
  • Therefore, the command list generation for each different view can proceed in completely different threads. After all command lists for each view are generated, they can be rapidly executed on the GPU on the main thread.
  • This is where the last parameter to the ThreadCameraStreamData constructor comes into play. By passing deferred = true, you indicate that you wish to render (execute a stream/command list), after you have generate or 'collected' the draw calls.
  • With that parameter set to true, you can call DrawSky/DrawObjects in each thread simultaneously/concurrently like usual with an important difference: This doesn't do any actual OpenGL/DX drawing, but simply does generation of drawing commands or 'command lists'.
  • The rendering context need not be active or current where you make these calls.
  • Following this, you 'execute' the command lists generated by each of the threads, in the main thread where the rendering context is active.
  • You do this by calling ThreadCameraStreamData::ExecuteStream for each of the tcsData objects associated with the threads.
  • This is all very similar to the way Sundog has support for multi-threaded in our Triton SDK: https://sundog-soft.com/2018/02/using-triton-4-0s-multi-threaded-rendering/
  • There are a few more interesting bits of general information (GPUs, multi-threading) there that are applicable to SilverLining as well, so its worthwhile reading that post.
  • The sequence of calls now for our example with 3 views is now:
  • There is a fully self-contained OpenGLMultiThreadedSample that illustrates all the above concepts & the API.

!!NOTE!!

  • Deferred rendering and bindless rendering do not work concurrently right now. Therefore, be sure to set this option to no: cumulus-draw-bindless-indirect = no in the config or programatically via Atmosphere::SetConfigOption("cumulus-draw-bindless-indirect", "no")
  • Deferred rendering does not work if with occlusion queries that are (optionally) required for lens flare. Therefore, be sure to set this option to yes: lens-flare-disable-occlusion = yes in the config or programatically via Atmosphere::SetConfigOption("lens-flare-disable-occlusion", "yes")

Constructor & Destructor Documentation

◆ ThreadCameraStreamData()

SilverLining::ThreadCameraStreamData::ThreadCameraStreamData ( bool rightHanded,
double unitScale,
bool deferred )

constructor

Parameters
rightHandedSet this the same as the initialized Atmosphere.
See also
Atmosphere::Initialize()
Parameters
unitScaleSet this the same as the initialized Atmosphere.
See also
Atmosphere::GetUnitScale(), Atmosphere::SetWorldUnits()
Parameters
deferredSet whether this tcsData uses deferred rendering.

Member Function Documentation

◆ ExecuteStream()

void SilverLining::ThreadCameraStreamData::ExecuteStream ( void )

For OpenGL: Execute the command list for this object.

See documentation above on 'deferred rendering'. For Vulkan: Execute one time/internal bookkeeping commands, if any, outside of the rendering/command buffer recording in a thread safe fashion (e.g. main thread), just before the submission of silverlining command buffers. See SilverLiningVulkanExample.

◆ GetCamera()

const Camera * SilverLining::ThreadCameraStreamData::GetCamera ( void ) const

These are the only public methods you need to use to render multiple views using multiple threads with/without command lists.

get the associated camera

◆ GetDeferred()

bool SilverLining::ThreadCameraStreamData::GetDeferred ( void ) const

get whether internal stream/context is a deferred stream call before initialize!

◆ GetRandomNumberGenerator()

RandomNumberGenerator * SilverLining::ThreadCameraStreamData::GetRandomNumberGenerator ( ) const

Get the random number generator.

See SetRandomNumberGenerator

◆ GetStratusMieLookupPixels()

const float * SilverLining::ThreadCameraStreamData::GetStratusMieLookupPixels ( int & width)

internal.

do not use! creates if necessary

◆ GetStratusNoisePixels()

const unsigned char * SilverLining::ThreadCameraStreamData::GetStratusNoisePixels ( int & width,
int & height )

internal.

do not use! creates if necessary

◆ Initialize() [1/3]

void SilverLining::ThreadCameraStreamData::Initialize ( const Atmosphere & atmosphere)

Initialize the ThreadCameraStreamData for a given Atmosphere object (call 2nd)

Parameters
environmentThe atmosphere against which this tcsData is being initialized

◆ Initialize() [2/3]

int SilverLining::ThreadCameraStreamData::Initialize ( int rendererType,
bool rightHanded,
void * environment,
bool avoidStalls )

Initialize the ThreadCameraStreamData (call first)

Parameters
rendererTypeThe renderer type. The same as the type passed in to Atmosphere::Initialize
rightHandedright handed or left handed system. The same as the type passed in to Atmosphere
environmentThe same value as the one passed in to Atmosphere::Initialize
avoidStallsIf you with to do any combination of multi-threaded rendering and deferred you need to set this config option on the Atmosphere: atmosphere->SetConfigOption("avoid-opengl-stalls", "yes"); and pass the same value (true)

◆ Initialize() [3/3]

int SilverLining::ThreadCameraStreamData::Initialize ( int rendererType,
bool rightHanded,
void * environment,
bool avoidStalls,
const SL_VECTOR(unsigned int)& userShaders )

OpenGL-only variant of ThreadCameraStreamData::Initialize() that takes in a list of user-compiled shader objects that will be linked into all subsequently linked shader program objects.

This allows you to inject your own shader functions into our shaders without copying the source.

Parameters
rendererTypeThe renderer type. The same as the type passed in to Atmosphere::Initialize
rightHandedright handed or left handed system. The same as the type passed in to Atmosphere
environmentThe same value as the one passed in to Atmosphere::Initialize
avoidStallsIf you with to do any combination of multi-threaded rendering and deferred you need to set this config option on the Atmosphere: atmosphere->SetConfigOption("avoid-opengl-stalls", "yes"); and pass the same value (true)
userShadersA list of user shaders, if any, to link into all shaders loaded by SilverLining.

◆ log()

std::ostream & SilverLining::ThreadCameraStreamData::log ( LogLevel level)

logging //!

internal. do not use!

◆ SetCloudLayerTcsUserData()

void SilverLining::ThreadCameraStreamData::SetCloudLayerTcsUserData ( const CloudLayer * cloudLayer,
TcsUserData * userData )

These are named variations of the 3 functions above.

set the name with userDataName as the key

◆ SetEnvironmentMapFormat()

void SilverLining::ThreadCameraStreamData::SetEnvironmentMapFormat ( ColorFormat format)

Vulkan only.

If you intend to use environment maps via ThreadCameraStreamData::GetEnvironmentMap, this needs to be specified before initializing ThreadCameraStreamData.

◆ SetRandomNumberGenerator()

void SilverLining::ThreadCameraStreamData::SetRandomNumberGenerator ( RandomNumberGenerator * rng)

Some effects (like lightning) need to be synchronized across multiple views.

Re-seeding the atmosphere random number in these cases per view doesn't quite work right for those. To avoid this, set the value of tcs-data-effects-rng-unique to yes. Then, the tcs datas will use their own internal random generators in this case (which if seeded/reset the same, will synchronize the effects across the views.

If an rng is not set via this call (and the tcs-data-effects-rng-unique is 'yes', the tcs data will use its own internal rng.

◆ SetSortByScreenDepth()

void SilverLining::ThreadCameraStreamData::SetSortByScreenDepth ( bool val)

internal. Do not use directly. Set sort screen depth

Set whether objects should be sorted by screen depth or distance from the view

◆ SetStream()

void SilverLining::ThreadCameraStreamData::SetStream ( void * stream,
int frameIndex = -1 )

Set the current command buffer that we are recording to (only for Vulkan renderer).

frameIndex is the image index/swap chain image index associated with the command buffer being recorded. If it is not provided, SilverLining has to do some extra work for internal book keeping.

◆ SettingsChanged()

void SilverLining::ThreadCameraStreamData::SettingsChanged ( void * environment)

Vulkan only.

Parameters
environmentThis must contain a pointer to a VulkanInitInfo structure, as defined in the VulkanInitInfo.h header. Only the parameters: renderPass, sampleCount, colorFormat and depthFormat are considered for the change. Other parameters are ignored.

◆ SetUserData()

void SilverLining::ThreadCameraStreamData::SetUserData ( const void * userPointer,
TcsUserData * userData )

!

!!!Do Not Use!!!! !!!!Internal methods!!!! These should not be used by application developers!! set a user pointer and the user data associated with it

◆ SetUseShadowMap()

void SilverLining::ThreadCameraStreamData::SetUseShadowMap ( bool val)

Vulkan only.

If you intend to use shadow maps via ThreadCameraStreamData::GetShadowMap, this needs to be specified before initializing ThreadCameraStreamData.


The documentation for this class was generated from the following file: