Louvre  v2.4.0-1
C++ library for Wayland compositors
Public Types | Public Member Functions | List of all members
LOutput Class Reference

A display rendering interface. More...

+ Inheritance diagram for LOutput:

Public Types

enum  State
 Output state. More...
 
enum  SubPixel
 Subpixel geometry. More...
 
- Public Types inherited from LFactoryObject
enum class  Type : Int32
 Base factory object types. More...
 

Public Member Functions

 LOutput (const void *params) noexcept
 Constructor of the LOutput class. More...
 
 ~LOutput ()
 Destructor of the LOutput class. More...
 
State state () const noexcept
 Gets the current state of the LOutput. More...
 
LPainterpainter () const noexcept
 Gets access to the associated LPainter. More...
 
LSessionLockRolesessionLockRole () const noexcept
 Session Lock Surface. More...
 
const std::list< LExclusiveZone * > exclusiveZones () const noexcept
 Retrieves all exclusive zones assigned to this output. More...
 
const LRectavailableGeometry () const noexcept
 Retrieves the rect within the output that is not occupied by exclusive zones. More...
 
const LMarginsexclusiveEdges () const noexcept
 Gets the sum of the space occupied by exclusive zones for each edge. More...
 
LFramebufferframebuffer () const noexcept
 Returns a pointer to the associated framebuffer. More...
 
LTransform transform () const noexcept
 Gets the framebuffer transformation. More...
 
void setTransform (LTransform transform) noexcept
 Sets the framebuffer transform. More...
 
Int32 currentBuffer () const noexcept
 Returns the index of the current buffer. More...
 
UInt32 buffersCount () const noexcept
 Returns the count of available buffers. More...
 
LTexturebufferTexture (UInt32 bufferIndex) noexcept
 Access the texture of a specific buffer. More...
 
bool hasBufferDamageSupport () const noexcept
 Checks if the output supports buffer damage tracking. More...
 
void setBufferDamage (const LRegion *damage) noexcept
 Specifies the damage generated during the last painGL() event. More...
 
const LRegionbufferDamage () const noexcept
 Retrieves the damage region set by setBufferDamage(). More...
 
SubPixel subPixel () const noexcept
 Gets the layout of RGB subpixels for a single pixel on a display. More...
 
bool hasVSyncControlSupport () const noexcept
 Checks if VSync control is supported for this output. More...
 
bool vSyncEnabled () const noexcept
 Checks if VSync is enabled (enabled by default). More...
 
bool enableVSync (bool enabled) noexcept
 Turns VSync on or off. More...
 
Int32 refreshRateLimit () const noexcept
 Gets the refresh rate limit in Hz when VSync is disabled. More...
 
void setRefreshRateLimit (Int32 hz) noexcept
 Sets the refresh rate limit in Hz when VSync is disabled. More...
 
UInt32 gammaSize () const noexcept
 Gets the size of the gamma table. More...
 
bool setGamma (const LGammaTable *gamma) noexcept
 Sets the gamma correction table for the output. More...
 
const std::vector< LOutputMode * > & modes () const noexcept
 Available modes. More...
 
const LOutputModepreferredMode () const noexcept
 Gets the preferred mode. More...
 
const LOutputModecurrentMode () const noexcept
 Gets the current mode. More...
 
void setMode (const LOutputMode *mode) noexcept
 Sets the output mode. More...
 
void setScale (Float32 scale) noexcept
 Sets the output scale factor. More...
 
Float32 scale () const noexcept
 Retrieves the current output scale factor. More...
 
Float32 fractionalScale () const noexcept
 Gets the same scale set with setScale(). More...
 
bool usingFractionalScale () const noexcept
 Checks if the scale factor set with setScale() is fractional. More...
 
bool fractionalOversamplingEnabled () const noexcept
 Checks if oversampling is enabled. More...
 
void enableFractionalOversampling (bool enabled) noexcept
 Toggles oversampling for fractional scales. More...
 
void repaint () noexcept
 Unlocks the rendering thread. More...
 
bool needsFullRepaint () const noexcept
 Indicates that the entire output needs repainting. More...
 
Int32 dpi () noexcept
 Gets the dots per inch (DPI) of the output. More...
 
const LRectrect () const noexcept
 Gets the output rect. More...
 
const LPointpos () const noexcept
 Gets the output position. More...
 
void setPos (const LPoint &pos) noexcept
 Set the position of the output. More...
 
const LSizesize () const noexcept
 Gets the output size in surface units. More...
 
const LSizesizeB () const noexcept
 Gets the output size in buffer units. More...
 
const LSizerealBufferSize () const noexcept
 Retrieves the real destination buffer size. More...
 
const LSizephysicalSize () const noexcept
 Gets the physical dimensions of the output. More...
 
const std::vector< LScreenshotRequest * > & screenshotRequests () const noexcept
 Screen capture requests. More...
 
LContentType contentType () const noexcept
 The content type hint set with setContentType(). More...
 
void setContentType (LContentType type) noexcept
 Sets the content type hint. More...
 
const char * name () const noexcept
 Gets the output name. More...
 
const char * model () const noexcept
 Gets the output model name. More...
 
const char * manufacturer () const noexcept
 Gets the manufacturer name of the output. More...
 
const char * description () const noexcept
 Gets the description of the output. More...
 
const std::thread::id & threadId () const noexcept
 Gets the ID of the rendering thread. More...
 
- Public Member Functions inherited from LFactoryObject
Type factoryObjectType () const noexcept
 Gets the base factory object type. More...
 
- Public Member Functions inherited from LObject
 LObject (const LObject &) noexcept
 Copy constructor. More...
 
LObjectoperator= (const LObject &) noexcept
 Assignment operator (each object has its own individual LWeak reference count). More...
 
void setUserData (UIntPtr data) const noexcept
 Store an unsigned integer value/pointer. More...
 
UIntPtr userData () const noexcept
 Retrieves the stored unsigned integer value/pointer. More...
 

Virtual Methods

virtual void initializeGL ()
 Initialize Event. More...
 
virtual void paintGL ()
 Paint Event. More...
 
virtual void resizeGL ()
 Resize Event. More...
 
virtual void moveGL ()
 Move Event. More...
 
virtual void uninitializeGL ()
 Uninitialize Event. More...
 
virtual void setGammaRequest (LClient *client, const LGammaTable *gamma)
 Set gamma table request. More...
 
virtual void availableGeometryChanged ()
 Notifies a change in availableGeometry(). More...
 
bool setCustomScanoutBuffer (LTexture *texture) noexcept
 Sets a custom scanout buffer for a single frame. More...
 

Additional Inherited Members

- Protected Member Functions inherited from LObject
 LObject () noexcept=default
 Constructor of the LObject class. More...
 
virtual ~LObject () noexcept
 Destructor of the LObject class. More...
 
void notifyDestruction () noexcept
 Notifies the object destruction. More...
 

Detailed Description

A display rendering interface.

The LOutput class is responsible for rendering content to a display. It is typically associated with a physical screen, but could also represent a toplevel window within Wayland desktop, depending on the selected graphic backend.

Lifetime

During compositor initialization, the graphic backend creates an LOutput for each available display through LCompositor::createObjectRequest().
These can be accessed via the LSeat::outputs() vector.

After the compositor has been initialized, the number of available outputs can change. These changes are notified through the LSeat::outputPlugged() and LSeat::outputUnplugged() events.

Initialization

By default, all outputs are uninitialized. To initialize an output, use LCompositor::addOutput(), as done in the default implementation of LCompositor::initialized() and LSeat::outputPlugged().

When an output is successfully initialized, it is added to LCompositor::outputs() and a new output-specific rendering thread and shared OpenGL context are created, triggering the initializeGL() event.

Uninitialization

To uninitialize an output, use LCompositor::removeOutput(). This will invoke the uninitializeGL() event, destroy the rendering thread and OpenGL context and remove the output from LCompositor::outputs().

Note
Outputs are also automatically uninitialized following an LSeat::outputUnplugged() event.

Rendering

The rendering thread loop remains blocked until repaint() is called, which unlocks the thread and asynchronously triggers the paintGL() event.

All painting operations must occur exclusively within a paintGL() event, as rendering elsewhere will not be visible on the screen.

Calling repaint() multiple times will only unlock the thread once. After or during a paintGL() event, repaint() must be called again to unlock the thread once more.

Multithreading

In Louvre, even if there is a main thread and each initialized LOutput has its own rendering thread, no single block of user code executes in parallel (unless you create custom threads, of course). For instance, all xxxGL() events never overlap with other events or requests being handled in separate threads.

You may be wondering why the need to use rendering threads then?

The answer is that calling rendering functions (in this case OpenGL functions) takes almost no time (except for glFinish()). Rendering commands are queued and processed later together with a page flip. For instance, if your monitor has a 60 Hz refresh rate (approximately 16 ms period), a paintGL() call may take 1 ms to be processed while the presentation on screen could take up to 15 ms (with V-Sync on). However, during those 15 ms, the main thread or other rendering threads can continue working. This allows Louvre compositors to maintain a constant high refresh rate compared to single-threaded designs.

Painting

Each output has its own OpenGL context and its own instance of LPainter, accessible via painter().

You can use LPainter methods to render colored rectangles or textures, use OpenGL directly with your own shaders/programs, or rely on the LScene class.
LScene can render views optimally by considering surface damage, opaque regions, and other factors to significantly improve performance.

Modes

Each LOutput has at least one mode. An LOutputMode contains information about the resolution and refresh rate at which the output can operate.

You can access the modes of an output using modes() and set the desired one with setMode().

By default, outputs use the preferredMode(), which typically has the highest refresh rate and resolution.

If you change an output's mode or scale while it is initialized, the resizeGL() event is triggered.

Arrangement

Outputs, like surfaces, can be positioned within the compositor-global coordinate space similarly to how a system settings panel operates.

You can adjust the position of an output using setPos(). This will later trigger the moveGL() event if the position changes.

Note
To enable LCursor to transition across different LOutputs, ensure that the outputs are closely arranged side by side.

Scaling

Many screens nowadays are HiDPI, so it is commonly required to apply a scaling factor to prevent content from appearing tiny on the screen.
By default, all outputs have a scaling factor of 1, meaning no scaling is applied. To assign the scale factor use setScale(), which modifies the size returned by size() (same as rect().size()).

In Louvre, you typically need to deal with two type of units: buffer units and surface units.

In buffer units, the scale factor is not taken into account, and the dimensions always have maximum granularity.
For example, if a screen has a resolution of 2000x1000px, its size in buffer units would be the same: 2000x1000px, which is returned by sizeB().
However, the compositor-global coordinate space uses surface units, which is equal to the buffer size divided by the applied scale factor.
Therefore, if a scale factor of 2 applied to the screen, its size in surface units would be 1000x500, which is returned by size() and rect().size().

Note
Use surface units (pos() and size() or rect()) when arranging outputs.

Let's look at an example to make these concepts clearer:

Let's assume you have two displays, one with a resolution of 1000x500px and another with 2000x1000px (double the resolution), but both with a physical size of 22''. This means that the space occupied by 1px on the blue screen accommodates 4px on the pink screen.

If you were to see them in real life, side by side they would look like this:

If you assign the same scaling factor of 1 to both screens, their sizes in surface units would be the same as in buffer units.
Therefore, from the compositor-global coordinate space point of view they would be arranged like this:

And if you were to see them in real life, they would look like the following. In the pink screen, everything would appear tiny, half the size of the blue screen. And as you can see, if you were to drag an application window from one screen to another, it would look somewhat odd.

Now, let's imagine that you assign a scaling factor of 2 to the pink screen. In this case, the compositor-global coordiante space would look as follows:

And therefore, if you were to see them in real life now, the UI elements dimensions would appear consistently.

Therefore, in summary, the size of a screen in surface units is determined by dividing its buffer size by the applied scale factor.

Fractional Scaling

Louvre also supports fractional scaling, albeit with some differences compared to integer scaling. For instance, if you assign a scale factor of 1.5 using setScale() to the pink screen, the resulting applied scale (obtained with scale()) will be ceil(1.5) = 2. However, the buffer dimensions of the screen will simulate being 2/1.5 times larger than its current mode (rounded), resulting in 2668 x 1334 for this case. Consequently, its size in surface coordinates would be 2668 x 1334 divided by 2. As a result, the compositor-global coordinate space would appear as follows:

This creates the illusion of rendering on a larger screen, the result of which is actually scaled to the real size, allowing for the desired scaling effect.
Rendering using fractional scaling, however, can introduce undesired visual effects like aliasing, especially noticeable when moving elements with textures containing fine details. For this reason, Louvre offers the option to render using oversampling, where all the screen content is rendered into a larger buffer, and then that rendered buffer is scaled down to the actual screen framebuffer. This method almost completely eliminates aliasing but has the disadvantage of consuming more computational power, potentially decreasing performance. Without oversampling the content is directly rendered on the screen, making it efficient but retaining aliasing artifacts.
Louvre allows you to toggle oversampling on and off instantly at any time using enableFractionalOversampling(). For example, you could enable it when displaying a desktop with floating windows and disable it when displaying a fullscreen window.

Note
Oversampling is not required and is always disabled when using non-fractional scales. Therefore, as a recommendation, if your monitor supports multiple modes() with various resolutions, it is preferable to select one of those modes instead of using fractional scaling.

Clients supporting the fractional scaling protocol are instructed to scale their buffers directly to the fractional scale.
On the other hand, clients lacking support for the protocol are advised to use ceil(fractional scale), ensuring a consistently high-detail appearance.

Transforms

Louvre supports applying transforms to outputs with setTransform().

Let's imagine that you physically rotate the pink monitor 90° clockwise while maintaining the same normal transform on both. What you would see is the following:

Given that you rotated the screen 90° clockwise, it is necessary to apply a transform that rotates the screen 90° counter-clockwise (LTransform::Rotated90). If you apply this to the pink screen, then you would see the following:

Note that when applying a transformation containing a 90° or 270° rotation to an output, the components of sizeB(), size() and rect().size() are swapped (their width becomes the height, and the height becomes the width). The compositor-global coordiante space is structured in such a way that you can continue rendering in the same manner as if the screens were in their normal transform state. Therefore, there's no need to worry about rotating or flipping the elements you draw unless you decide not to use LPainter or LScene for rendering.

VSync

All outputs have VSync enabled by default. Disabling VSync may not always be supported, refer to hasVSyncControlSupport().

VSync can be toggled using enableVSync(). When VSync is disabled, Louvre limits the frame rate to double the refresh rate of the currentMode() by default. This setting can be changed with setRefreshRateLimit().

Clients using the Tearing Protocol can indicate their preference for each individual surface.
See LSurface::preferVSync() and LSurface::preferVSyncChanged() for more details.

Member Enumeration Documentation

◆ State

enum State

Output state.

See also
state()
Enumerator
PendingInitialize 

Output is pending initialization.

PendingUninitialize 

Output is pending uninitialization.

Initialized 

Output is initialized and active.

Uninitialized 

Output is uninitialized.

ChangingMode 

Output is in the process of changing display mode.

Suspended 

Output is suspended.

◆ SubPixel

enum SubPixel

Subpixel geometry.

This enumeration provides information about how the physical pixels on an output are laid out.

See also
subPixel()
Enumerator
Unknown 

Unknown geometry.

None 

No specific geometry.

HorizontalRGB 

Horizontal RGB layout.

HorizontalBGR 

Horizontal BGR layout.

VerticalRGB 

Vertical RGB layout.

VerticalBGR 

Vertical BGR layout.

Constructor & Destructor Documentation

◆ LOutput()

LOutput ( const void *  params)
noexcept

Constructor of the LOutput class.

Parameters
paramsInternal parameters provided in LCompositor::createObjectRequest().

◆ ~LOutput()

~LOutput ( )

Destructor of the LOutput class.

Invoked after LCompositor::onAnticipatedObjectDestruction().

Member Function Documentation

◆ state()

LOutput::State state ( ) const
noexcept

Gets the current state of the LOutput.

This method returns the current state of the output.

◆ painter()

LPainter * painter ( ) const
noexcept

Gets access to the associated LPainter.

This method provides access to the LPainter associated with this output.

◆ sessionLockRole()

LSessionLockRole * sessionLockRole ( ) const
noexcept

Session Lock Surface.

When a client requests to lock the user session (see LSessionLockManager), it creates an LSessionLockRole surface for each initialized output whith a size equals to the output size().

If the session is locked and there is no LSessionLockRole assigned to this output, the compositor should still avoid rendering any user-related content.

Returns
An instance of the LSessionLockRole associated with this output if the session is locked, or nullptr if the session is not locked or the locking client didn't create one.

◆ exclusiveZones()

const std::list< LExclusiveZone * > exclusiveZones ( ) const
noexcept

Retrieves all exclusive zones assigned to this output.

The order of the list determines how zones anchored to the same edge are stacked. Zones listed first are positioned closer to the output's edge. Additionally, the order affects their predominance: zones listed later adjust their space to avoid occluding those listed earlier.

Returns
A list of pointers to LExclusiveZone objects.
See also
LExclusiveZone::setOutput()

◆ availableGeometry()

const LRect & availableGeometry ( ) const
noexcept

Retrieves the rect within the output that is not occupied by exclusive zones.

The available geometry defines the space within an output where, for example, LToplevelRole surfaces should be constrained to prevent occluding UI elements like a panel.

The rect is in output-local surface coordinates.

See also
exclusiveZones()
Returns
A rect representing the available geometry.

◆ exclusiveEdges()

const LMargins & exclusiveEdges ( ) const
noexcept

Gets the sum of the space occupied by exclusive zones for each edge.

This function provides margins that represent the total area taken up by the exclusive zones along each edge of the output.

See also
exclusiveZones()
availableGeometry()
Returns
LMargins object representing the exclusive edges.

◆ framebuffer()

LFramebuffer * framebuffer ( ) const
noexcept

Returns a pointer to the associated framebuffer.

See also
LPainter::bindFramebuffer()
Returns
A pointer to the LFramebuffer instance associated with the output.

◆ transform()

LTransform transform ( ) const
noexcept

Gets the framebuffer transformation.

This method returns the current framebuffer transformation applied with setTransform().

The default value is LTransform::Normal.

Returns
The framebuffer transformation.

◆ setTransform()

void setTransform ( LTransform  transform)
noexcept

Sets the framebuffer transform.

This method sets the output transform, allowing you to adjust the orientation/flipping of the output.
If the specified transform includes a 90 or 270-degree rotation, the width and height of the output are swapped accordingly.

Parameters
transformThe framebuffer transformation to apply.

◆ currentBuffer()

Int32 currentBuffer ( ) const
noexcept

Returns the index of the current buffer.

Compositors commonly employ double or triple buffering. This involves rendering to one buffer while displaying another, prventing visual artifacts like tearing.

Returns
The current buffer index. Alternates between [0], [0, 1] or [0, 1, 2] depending on the graphic backend configuration.

◆ buffersCount()

UInt32 buffersCount ( ) const
noexcept

Returns the count of available buffers.

This method returns the number of buffers used by the output. It can be 1, 2 or 3 depending on the graphic backend configuration.

◆ bufferTexture()

LTexture * bufferTexture ( UInt32  bufferIndex)
noexcept

Access the texture of a specific buffer.

This method allows access to the texture associated with a particular buffer index.

Parameters
bufferIndexThe index of the buffer for which the texture is to be accessed.
Returns
A pointer to the texture associated with the specified buffer index, or nullptr if texture access is not supported.
Warning
Some hardware/backends may not support accessing outputs textures, so you should always check if nullptr is returned.

◆ hasBufferDamageSupport()

bool hasBufferDamageSupport ( ) const
noexcept

Checks if the output supports buffer damage tracking.

Some graphic backends/hardware can benefit from knowing which regions of the framebuffer have changed within a paintGL() event.

This method indicates whether buffer damage support is available.

See also
setBufferDamage() and bufferDamage()
Returns
true if the graphical backend supports buffer damage tracking, false otherwise.

◆ setBufferDamage()

void setBufferDamage ( const LRegion damage)
noexcept

Specifies the damage generated during the last painGL() event.

The bufferDamage() is automatically reset just before the subsequent paintGL() event.

Note
Although calling this method is not mandatory, it can significantly enhance performance, especially on certain graphic backends/hardware or when the output scale is fractional and oversampling is enabled. If never invoked, the entire output is considered damaged.

When using LScene for rendering, damage calculation is handled automatically with this method being called inside LScene::handlePaintGL().

Parameters
damageThe damaged region of the output in compositor-global coordinates. Providing an empty region indicates no damage, while passing nullptr implies the entire output is damaged.

◆ bufferDamage()

const LRegion & bufferDamage ( ) const
noexcept

Retrieves the damage region set by setBufferDamage().

Before each paintGL() event, the compositor automatically clears the damage region and marks the entire output as damaged by adding rect().

Returns
The damage region in compositor-global coordiantes.

◆ subPixel()

LOutput::SubPixel subPixel ( ) const
noexcept

Gets the layout of RGB subpixels for a single pixel on a display.

The layout of subpixels can impact the display of elements like fonts.

◆ hasVSyncControlSupport()

bool hasVSyncControlSupport ( ) const
noexcept

Checks if VSync control is supported for this output.

See also
enableVSync()
Returns
true if VSync control is supported, false if VSync is always enabled.

◆ vSyncEnabled()

bool vSyncEnabled ( ) const
noexcept

Checks if VSync is enabled (enabled by default).

See also
enableVSync()
Returns
true if VSync is enabled, false otherwise.

◆ enableVSync()

bool enableVSync ( bool  enabled)
noexcept

Turns VSync on or off.

Parameters
enabledtrue to enable VSync, false to disable.
Returns
true if VSync was successfully enabled or disabled, false if VSync control is not supported (see hasVSyncControlSupport()).

◆ refreshRateLimit()

Int32 refreshRateLimit ( ) const
noexcept

Gets the refresh rate limit in Hz when VSync is disabled.

A value less than 0 indicates the limit is disabled.
A value equal to 0 indicates the limit is double the current output mode refresh rate (the default).
Any other positive value represents the limit in Hz.

See also
setRefreshRateLimit()
Returns
The refresh rate limit when VSync is disabled.

◆ setRefreshRateLimit()

void setRefreshRateLimit ( Int32  hz)
noexcept

Sets the refresh rate limit in Hz when VSync is disabled.

A value less than 0 indicates the limit is disabled.
A value equal to 0 indicates the limit is double the current output mode refresh rate (the default).
Any other positive value represents the limit in Hz.

Parameters
hzThe refresh rate limit in Hz when VSync is disabled.

◆ gammaSize()

UInt32 gammaSize ( ) const
noexcept

Gets the size of the gamma table.

Note
This method can only be called while the output is initialized. If called when not initialized, it returns 0. If the output doesn't support gamma correction, this method also returns 0.
Returns
The size of the gamma correction table.
See also
setGamma() and setGammaRequest()
LGammaTable

◆ setGamma()

bool setGamma ( const LGammaTable gamma)
noexcept

Sets the gamma correction table for the output.

This method allows to set the gamma correction table for the output.

Note
This method can only be called while the output is initialized. Louvre automatically sets a linear gamma table when the output is initialized.
Parameters
gammaA pointer to the LGammaTable with a size matching gammaSize(). Passing nullptr restores the default table (linear).
Returns
true if the gamma correction table was successfully set, false otherwise.

◆ modes()

const std::vector< LOutputMode * > & modes ( ) const
noexcept

Available modes.

This method returns a vector containing all the available output modes for the LOutput instance.

See also
setMode()
Returns
A vector of pointers to LOutputMode instances representing the available modes of the output.

◆ preferredMode()

const LOutputMode * preferredMode ( ) const
noexcept

Gets the preferred mode.

This method returns the preferred mode for the output. It is generally the mode with the highest refresh rate and resolution.

Set by default. See setMode().

◆ currentMode()

const LOutputMode * currentMode ( ) const
noexcept

Gets the current mode.

This method returns the current output mode set with setMode().

◆ setMode()

void setMode ( const LOutputMode mode)
noexcept

Sets the output mode.

Use this method to assign a mode to the output, which must be one of the available modes listed in modes().
If the mode changes and the output is already initialized the resizeGL() event is triggered.

Note
Calling this method from any of the GL events is not allowed, as it could potentially lead to a deadlock. In such cases, the method is simply ignored to prevent issues.

◆ setScale()

void setScale ( Float32  scale)
noexcept

Sets the output scale factor.

Use this method to adjust the scale factor of the output. By default, outputs have a scale factor of 1.
Increasing the scale factor, such as setting it to 2, is often suitable for high-definition displays (when dpi() >= 200). It's common for clients to adapt their surface scales to match the scale of the output where they are displayed.
If the scale changes and the output is already initialized, the resizeGL() event will be triggered.

Note
Starting from Louvre version 1.2, fractional scales are now supported, see the Scaling Section.
Parameters
scaleThe desired scale factor to set.
See also
See an example of its use in the default implementation of LCompositor::initialized().

◆ scale()

Float32 scale ( ) const
noexcept

Retrieves the current output scale factor.

This method returns the current scale factor assigned to the output using setScale(). The default scale factor is 1.

If the assigned scale is fractional this value is equal to ceil(scale).

See also
fractionalScale()

◆ fractionalScale()

Float32 fractionalScale ( ) const
noexcept

Gets the same scale set with setScale().

Set to 1.f by default.

Returns
The fractional scale value.

◆ usingFractionalScale()

bool usingFractionalScale ( ) const
noexcept

Checks if the scale factor set with setScale() is fractional.

Returns
true if the scale factor is fractional, false otherwise.

◆ fractionalOversamplingEnabled()

bool fractionalOversamplingEnabled ( ) const
noexcept

Checks if oversampling is enabled.

Oversampling is enabled by default when a fractional scale is set using setScale().
It is always disabled when using an integer scale. You can disable oversampling using enableFractionalOversampling().

Returns
true if oversampling is enabled, false otherwise.

◆ enableFractionalOversampling()

void enableFractionalOversampling ( bool  enabled)
noexcept

Toggles oversampling for fractional scales.

Note
Oversampling is always turned off for integer scales. You can instantly turn oversampling on or off when using a fractional scale.
Parameters
enabledtrue to enable oversampling for fractional scales, false to disable.

◆ repaint()

void repaint ( )
noexcept

Unlocks the rendering thread.

Calling this method unlocks the output rendering thread, triggering a subsequent paintGL() event.
Regardless of the number of repaint() calls within the same frame, paintGL() is invoked only once.
To unlock the rendering thread again, repaint() must be called within or after a paintGL() event.

◆ needsFullRepaint()

bool needsFullRepaint ( ) const
noexcept

Indicates that the entire output needs repainting.

This hint from the graphic backend suggests that the entire output should be repainted, possibly because it doesn't support damage tracking or for other reasons.

Note
This is automatically managed by LScene.

◆ dpi()

Int32 dpi ( )
noexcept

Gets the dots per inch (DPI) of the output.

This method calculates and returns the dots per inch (DPI) of the output, considering its physical dimensions and the resolution provided by its current mode.

◆ rect()

const LRect & rect ( ) const
noexcept

Gets the output rect.

This method provides the position and size of the output in compositor-global coordinates (pos(), size()).

◆ pos()

const LPoint & pos ( ) const
noexcept

Gets the output position.

This method retrieves the position of the output in compositor-global coordinates assigned with setPos().
It is equivalent to the position given by the rect().

◆ setPos()

void setPos ( const LPoint pos)
noexcept

Set the position of the output.

This method allows you to assign the position of the output in compositor-global coordinates, with the upper-left corner as the origin.
If the position changes while the output is initialized, the moveGL() event is triggered.

Parameters
posThe new position of the output in compositor-global coordinates.

◆ size()

const LSize & size ( ) const
noexcept

Gets the output size in surface units.

This method provides the size of the output in surface units, based on its current mode and scale factor.
It is equivalent to the size given by the rect().

◆ sizeB()

const LSize & sizeB ( ) const
noexcept

Gets the output size in buffer units.

This method returns the size of the output in buffer units, based on its current mode.

◆ realBufferSize()

const LSize & realBufferSize ( ) const
noexcept

Retrieves the real destination buffer size.

This method returns the size in pixels of the destination framebuffer during a paintGL() event.
Unlike sizeB(), the width and height are not swapped if transform() includes a 90° rotation.
Additionally, when using oversampling and a fractional scale, it returns the actual size of the intermediary "oversampled" framebuffer, rather than the "fake" buffer size provided by sizeB().

Note
This method is only useful if you are not using LPainter or LScene for rendering.

◆ physicalSize()

const LSize & physicalSize ( ) const
noexcept

Gets the physical dimensions of the output.

This method retrieves the physical dimensions of the output in millimeters.

Note
In some cases, such as when the compositor is running inside a virtual machine, the physical size may be (0,0).

◆ screenshotRequests()

const std::vector< LScreenshotRequest * > & screenshotRequests ( ) const
noexcept

Screen capture requests.

This vector contains all LScreenshotRequest s that should be handled during a paintGL() event.

◆ contentType()

LContentType contentType ( ) const
noexcept

The content type hint set with setContentType().

◆ setContentType()

void setContentType ( LContentType  type)
noexcept

Sets the content type hint.

This hint is used by some hardware displays to properly adapt to the type of content being displayed.
For example, if the LContentTypeGame flag is set, a TV connected through an HDMI port may adapt to reduce latency.

The default value is LContentTypeNone.

Clients using the Content Type Hint protocol can also specify the type of content a given LSurface is displaying.

See also
LSurface::contentType() and LSurface::contentTypeChanged().
Parameters
typeThe content type hint to be set.

◆ name()

const char * name ( ) const
noexcept

Gets the output name.

This method retrieves the name of the output provided by the graphic backend, such as "HDMI-A-2."

Note
Output names are always unique, even if they belong to different GPUs.

◆ model()

const char * model ( ) const
noexcept

Gets the output model name.

This method retrieves the model name of the output provided by the graphic backend.

◆ manufacturer()

const char * manufacturer ( ) const
noexcept

Gets the manufacturer name of the output.

This method retrieves the manufacturer name of the output provided by the graphic backend.

◆ description()

const char * description ( ) const
noexcept

Gets the description of the output.

This method retrieves the description of the output provided by the graphic backend.

◆ threadId()

const std::thread::id & threadId ( ) const
noexcept

Gets the ID of the rendering thread.

This method retrieves the ID of the output rendering thread.

◆ initializeGL()

virtual void initializeGL ( )
virtual

Initialize Event.

The initializeGL() event is invoked after the output is properly initialized.

Note
Avoid performing painting operations here, as they won't be visible on the screen. See the paintGL() event.

Default Implementation

{
painter()->setClearColor(1.f, 1.f, 1.f, 1.f);
}
virtual void initializeGL()
Initialize Event.
LPainter * painter() const noexcept
Gets access to the associated LPainter.
Definition: LOutput.cpp:398
void setClearColor(Float32 r, Float32 g, Float32 b, Float32 a) noexcept
Sets the clear color.
Definition: LPainter.cpp:806

◆ paintGL()

virtual void paintGL ( )
virtual

Paint Event.

The paintGL() event is invoked after unlocking the rendering thread with repaint().
All rendering operations performed here will be displayed later on screen after the backend performs a page flip.

Default Implementation

{
const bool sessionLocked { sessionLockManager()->state() != LSessionLockManager::Unlocked };
const LRect availGeo { pos() + availableGeometry().pos(), availableGeometry().size() };
LPainter::TextureParams params;
LRect currentRect;
LPainter *p { painter() };
if (seat()->dnd()->icon())
seat()->dnd()->icon()->surface()->raise();
static const auto surfaceShouldBeSkipped = [](LSurface *s, LOutput *output, bool sessionLocked) -> bool
{
// An unmapped surface usually indicates it doesn't have a buffer
if (!s->mapped())
return true;
// Should be displayed, for example, as a thumbnail in a panel instead
if (s->minimized())
return true;
// Use LCursor instead for rendering the cursor
if (s->cursorRole())
{
// But let the client update it
s->requestNextFrame();
return true;
}
// Layer or screen lock surfaces should be displayed only on their exclusive output or not at all
if ((s->layerRole() && s->layerRole()->exclusiveOutput() != output) ||
(s->sessionLock() && s->sessionLock()->exclusiveOutput() != output))
return true;
// Other roles with a different exclusive output, e.g. maximized or fullscreen toplevels
if (s->role() && s->role()->exclusiveOutput() && s->role()->exclusiveOutput() != output)
return true;
// If the session is locked only surfaces from the locking client should be displayed
if (sessionLocked && s->client() != sessionLockManager()->client())
return true;
return false;
};
static const auto surfaceShouldBeClippedToAvailableGeometry = [](LSurface *s) -> bool
{
// Popups are usually constrained to the entire output rect instead
if (s->popup())
return false;
// Fullscreen toplevels should not be clipped
if (s->toplevel() && !s->toplevel()->fullscreen())
return true;
// Toplevels or subsurfaces child of a non fullscreen toplevel
if (s->subsurface() || s->toplevel())
{
const LSurface *topmostParent { s->topmostParent() };
if (topmostParent && topmostParent->toplevel() && !topmostParent->toplevel()->fullscreen())
return true;
}
return false;
};
// Draw every surface
for (LSurface *s : compositor()->surfaces())
{
if (surfaceShouldBeSkipped(s, this, sessionLocked))
continue;
// Current surface rect
currentRect.setPos(s->rolePos());
currentRect.setSize(s->size());
// Calc which outputs intersect the surface
for (LOutput *o : compositor()->outputs())
{
if (o->rect().intersects(currentRect))
s->sendOutputEnterEvent(o);
else
s->sendOutputLeaveEvent(o);
}
params.srcRect = s->srcRect();
params.dstSize = s->size();
params.srcScale = s->bufferScale();
params.srcTransform = s->bufferTransform();
params.texture = s->texture();
params.pos = currentRect.pos();
// Bind the surface texture
p->bindTextureMode(params);
// Clip to available geometry
if (surfaceShouldBeClippedToAvailableGeometry(s))
// If the intersected area is zero
if (currentRect.clip(availGeo))
continue;
// Draw the surface
p->drawRect(currentRect);
// Notify the client it can now render a new surface frame
s->requestNextFrame();
}
}
LSurface * surface() const noexcept
Returns the surface that has acquired the role provided in the constructor.
Definition: LBaseSurfaceRole.h:117
const std::list< LSurface * > & surfaces() const noexcept
Gets a list of all surfaces created by clients.
Definition: LCompositor.cpp:546
const std::vector< LOutput * > & outputs() const noexcept
Gets a vector of all initialized outputs.
Definition: LCompositor.cpp:556
LDNDIconRole * icon() const noexcept
Drag & drop session icon.
Definition: LDND.cpp:118
virtual void paintGL()
Paint Event.
const LPoint & pos() const noexcept
Gets the output position.
Definition: LOutput.cpp:358
const LRect & availableGeometry() const noexcept
Retrieves the rect within the output that is not occupied by exclusive zones.
Definition: LOutput.cpp:52
LOutput(const void *params) noexcept
Constructor of the LOutput class.
Definition: LOutput.cpp:25
void clearScreen() noexcept
Clear the framebuffer.
Definition: LPainter.cpp:834
constexpr const LPointTemplate< T > & pos() const noexcept
2D vector given by the (x,y) components of the rectangle
Definition: LRect.h:128
constexpr const LPointTemplate< T > & size() const noexcept
2D vector given by the (w,h) components of the rectangle
Definition: LRect.h:131
LDND * dnd() const noexcept
Access to the drag & drop session manager.
Definition: LSeat.h:129
LClient * client() const noexcept
Gets the client locking the session.
Definition: LSessionLockManager.cpp:27
State state() const noexcept
Gets the current state of the session.
Definition: LSessionLockManager.h:58
@ Unlocked
Definition: LSessionLockManager.h:27
void raise()
Raises the surface within its current layer.
Definition: LSurface.cpp:553
LCompositor * compositor() noexcept
Gets the static LCompositor instance.
Definition: LCompositor.cpp:34
LSessionLockManager * sessionLockManager() noexcept
Gets the compositor's session lock manager.
Definition: LCompositor.cpp:49
LSeat * seat() noexcept
Gets the compositor's seat.
Definition: LCompositor.cpp:39
LRectTemplate< Int32 > LRect
4D vector of 32 bits integers
Definition: LNamespaces.h:250

◆ resizeGL()

virtual void resizeGL ( )
virtual

Resize Event.

The resizeGL() event is invoked when the output scale or mode changes.

Note
Avoid performing painting operations here, as they won't be visible on the screen. See the paintGL() event.

Default Implementation

{
}
void repaint() noexcept
Unlocks the rendering thread.
Definition: LOutput.cpp:305
virtual void resizeGL()
Resize Event.

◆ moveGL()

virtual void moveGL ( )
virtual

Move Event.

This event is triggered when the output's position changes, see setPos().

Note
Avoid performing painting operations here, as they won't be visible on the screen. See the paintGL() event.

Default Implementation

{
}
virtual void moveGL()
Move Event.

◆ uninitializeGL()

virtual void uninitializeGL ( )
virtual

Uninitialize Event.

The uninitializeGL() event is invoked after the output is removed from the compositor with LCompositor::removeOutput() or when the output is unplugged, see LSeat::outputUnplugged().
Here you should free your shaders, programs, textures, etc.

Note
Avoid performing painting operations here, as they won't be visible on the screen. See the paintGL() event.

Default Implementation

{
/* No default implementation */
}
virtual void uninitializeGL()
Uninitialize Event.

◆ setGammaRequest()

virtual void setGammaRequest ( LClient client,
const LGammaTable gamma 
)
virtual

Set gamma table request.

Clients using the wlr gamma control protocol can request to set the gamma table for an output.

Warning
For security reasons, it is advisable to permit only authorized clients to perform such actions. See LCompositor::globalsFilter().

The gamma table (when is not nullptr) always have a size equal to gammaSize(), hence, it is not necessary to validate that.

Parameters
clientPointer to the client making the request.
gammaPointer to the LGammaTable object containing the requested gamma table or nullptr to restore the default table.

Default Implementation

void LOutput::setGammaRequest(LClient *client, const LGammaTable *gamma)
{
L_UNUSED(client)
/* Sets the client gamma table */
setGamma(gamma);
}
bool setGamma(const LGammaTable *gamma) noexcept
Sets the gamma correction table for the output.
Definition: LOutput.cpp:128
virtual void setGammaRequest(LClient *client, const LGammaTable *gamma)
Set gamma table request.

◆ availableGeometryChanged()

virtual void availableGeometryChanged ( )
virtual

Notifies a change in availableGeometry().

This event is triggered whenever one of the exclusiveZones() changes.

Default Implementation

The default implementation adjusts and reconfigures mapped LToplevelRole surfaces to prevent occlusion of the exclusive zone on each edge.

{
const LRect availGeo { pos() + availableGeometry().pos(), availableGeometry().size() };
for (LSurface *surface : compositor()->surfaces())
{
LToplevelRole *tl { surface->toplevel() };
if (tl && !tl->fullscreen())
{
const LSize toplevelExtraSize { tl->extraGeometry().left + tl->extraGeometry().right, tl->extraGeometry().top + tl->extraGeometry().bottom };
LRect toplevelRect { surface->pos(), tl->windowGeometry().size() + toplevelExtraSize };
if (compositor()->mostIntersectedOutput(toplevelRect) != this)
continue;
if (tl->maximized())
{
surface->setPos(availGeo.pos());
tl->configureSize(availGeo.size()
- toplevelExtraSize);
}
else
{
if (exclusiveEdges().right != 0 && toplevelRect.x() + toplevelRect.w() > availGeo.x() + availGeo.w())
toplevelRect.setX(availGeo.x() + availGeo.w() - toplevelRect.w());
if (exclusiveEdges().bottom != 0 && toplevelRect.y() + toplevelRect.h() > availGeo.y() + availGeo.h())
toplevelRect.setY(availGeo.y() + availGeo.h() - toplevelRect.h());
if (exclusiveEdges().left != 0 && toplevelRect.x() < availGeo.x())
toplevelRect.setX(availGeo.x());
if (exclusiveEdges().top != 0 && toplevelRect.y() < availGeo.y())
toplevelRect.setY(availGeo.y());
bool needsConfigure { false };
if (exclusiveEdges().right != 0 && toplevelRect.w() > availGeo.w())
{
toplevelRect.setW(availGeo.w());
needsConfigure = true;
}
if (exclusiveEdges().bottom != 0 && toplevelRect.h() > availGeo.h())
{
toplevelRect.setH(availGeo.h());
needsConfigure = true;
}
if (needsConfigure)
tl->configureSize(toplevelRect.size() - toplevelExtraSize);
surface->setPos(toplevelRect.pos());
}
}
}
}
virtual void availableGeometryChanged()
Notifies a change in availableGeometry().
const LMargins & exclusiveEdges() const noexcept
Gets the sum of the space occupied by exclusive zones for each edge.
Definition: LOutput.cpp:57
constexpr void setX(T x) noexcept
Assigns the value to the first component of the vector.
Definition: LPoint.h:58
LPoint LSize
2D vector of 32 bits integers
Definition: LNamespaces.h:241

◆ setCustomScanoutBuffer()

bool setCustomScanoutBuffer ( LTexture texture)
noexcept

Sets a custom scanout buffer for a single frame.

This method allows you to replace the screen framebuffer during a single frame with a custom one, such as a fullscreen surface, preventing rendering using OpenGL and thus reducing GPU consumption and latency.

Warning
This method must be called within a paintGL() event and nowhere else.

The graphic backend will check if the format is supported and if the dimensions match the current output mode. If that's the case, true is returned, and the currentBuffer() index is not updated after this frame. Also, no painting operations should be performed as they will simply not make it to the screen.

While a custom buffer is being displayed:

  • No other content will be visible, so this method should not be called if there is any overlay content such as a notification, subsurfaces, etc.
  • The hardware cursor plane can still be displayed, but if it is disabled or unsupported, calling this method should be avoided.
  • All screenshot requests will be forced to be cancelled.

The custom buffer is displayed during a single frame. To display it again, this method should be called in subsequent frames.

If not set during a frame, or nullptr is passed as texture, the internal output framebuffers are restored, the currentBuffer() index continues to update as usual and needsFullRepaint() is set to true for one frame.

Note
When setting buffers belonging to surfaces, Louvre automatically ensures they aren't updated while being displayed, which would cause undesired artifacts to be displayed. When setting your own buffers, you must take care to not update their content while being displayed. Destroying a buffer while it is being displayed is safe, the graphic backend ensures it remains alive until it is no longer in use.
Parameters
textureThe texture to scan or nullptr to restore the internal output framebuffers.
Returns
true if the buffer is going to be displayed, false if the internal output framebuffers will be displayed.