@ -7,70 +7,202 @@
SPDX - License - Identifier : GPL - 2.0 - or - later
*/
# include "x11_windowed_egl_backend.h"
// kwin
# include "basiceglsurfacetexture_internal.h"
# include "basiceglsurfacetexture_wayland.h"
# include "x11_windowed_backend.h"
# include "x11_windowed_logging.h"
# include "x11_windowed_output.h"
// kwin libs
# include "../../drm/gbm_dmabuf.h"
# include "basiceglsurfacetexture_internal.h"
# include "basiceglsurfacetexture_wayland.h"
# include <drm_fourcc.h>
# include <kwinglplatform.h>
# include <gbm.h>
# include <xcb/dri3.h>
namespace KWin
{
X11WindowedEglPrimaryLayer : : X11WindowedEglPrimaryLayer ( X11WindowedEglBackend * backend , X11WindowedOutput * output , EGLSurface surface )
: m_eglSurface ( surface )
, m_output ( output )
, m_backend ( backend )
X11WindowedEglLayerBuffer : : X11WindowedEglLayerBuffer ( const QSize & size , uint32_t format , uint32_t depth , uint32_t bpp , const QVector < uint64_t > & modifiers , xcb_drawable_t drawable , X11WindowedEglBackend * backend )
: m_backend ( backend )
{
X11WindowedBackend * x11Backend = backend - > backend ( ) ;
m_bo = createGbmBo ( x11Backend - > gbmDevice ( ) , size , format , modifiers ) ;
if ( ! m_bo ) {
qCCritical ( KWIN_X11WINDOWED ) < < " Failed to allocate a buffer for an output layer " ;
return ;
}
const DmaBufAttributes attributes = dmaBufAttributesForBo ( m_bo ) ;
m_pixmap = xcb_generate_id ( x11Backend - > connection ( ) ) ;
if ( x11Backend - > driMajorVersion ( ) > = 1 | | x11Backend - > driMinorVersion ( ) > = 2 ) {
// xcb_dri3_pixmap_from_buffers() takes the ownership of the file descriptors.
int fds [ 4 ] = {
attributes . fd [ 0 ] . duplicate ( ) . take ( ) ,
attributes . fd [ 1 ] . duplicate ( ) . take ( ) ,
attributes . fd [ 2 ] . duplicate ( ) . take ( ) ,
attributes . fd [ 3 ] . duplicate ( ) . take ( ) ,
} ;
xcb_dri3_pixmap_from_buffers ( x11Backend - > connection ( ) , m_pixmap , drawable , attributes . planeCount ,
size . width ( ) , size . height ( ) ,
attributes . pitch [ 0 ] , attributes . offset [ 0 ] ,
attributes . pitch [ 1 ] , attributes . offset [ 1 ] ,
attributes . pitch [ 2 ] , attributes . offset [ 2 ] ,
attributes . pitch [ 3 ] , attributes . offset [ 3 ] ,
depth , bpp , attributes . modifier , fds ) ;
} else {
// xcb_dri3_pixmap_from_buffer() takes the ownership of the file descriptor.
xcb_dri3_pixmap_from_buffer ( x11Backend - > connection ( ) , m_pixmap , drawable ,
size . height ( ) * attributes . pitch [ 0 ] , size . width ( ) , size . height ( ) ,
attributes . pitch [ 0 ] , depth , bpp , attributes . fd [ 0 ] . duplicate ( ) . take ( ) ) ;
}
m_texture = backend - > importDmaBufAsTexture ( attributes ) ;
m_framebuffer = std : : make_unique < GLFramebuffer > ( m_texture . get ( ) ) ;
}
X11WindowedEglPrimaryLayer : : ~ X11WindowedEglPrimaryLayer ( )
X11WindowedEgl LayerBuff er: : ~ X11WindowedEgl LayerBuff er( )
{
eglDestroySurface ( m_backend - > eglDisplay ( ) , m_eglSurface ) ;
m_texture . reset ( ) ;
m_framebuffer . reset ( ) ;
if ( m_pixmap ) {
xcb_free_pixmap ( m_backend - > backend ( ) - > connection ( ) , m_pixmap ) ;
}
if ( m_bo ) {
gbm_bo_destroy ( m_bo ) ;
}
}
xcb_pixmap_t X11WindowedEglLayerBuffer : : pixmap ( ) const
{
return m_pixmap ;
}
std : : shared_ptr < GLTexture > X11WindowedEglLayerBuffer : : texture ( ) const
{
return m_texture ;
}
GLFramebuffer * X11WindowedEglLayerBuffer : : framebuffer ( ) const
{
return m_framebuffer . get ( ) ;
}
void X11WindowedEglPrimaryLayer : : ensureFbo ( )
int X11WindowedEglLayerBuffer : : age ( ) const
{
if ( ! m_fbo | | m_fbo - > size ( ) ! = m_output - > pixelSize ( ) ) {
m_fbo = std : : make_unique < GLFramebuffer > ( 0 , m_output - > pixelSize ( ) ) ;
return m_age ;
}
X11WindowedEglLayerSwapchain : : X11WindowedEglLayerSwapchain ( const QSize & size , uint32_t format , uint32_t depth , uint32_t bpp , const QVector < uint64_t > & modifiers , xcb_drawable_t drawable , X11WindowedEglBackend * backend )
: m_backend ( backend )
, m_size ( size )
{
for ( int i = 0 ; i < 2 ; + + i ) {
m_buffers . append ( std : : make_shared < X11WindowedEglLayerBuffer > ( size , format , depth , bpp , modifiers , drawable , backend ) ) ;
}
}
X11WindowedEglLayerSwapchain : : ~ X11WindowedEglLayerSwapchain ( )
{
}
QSize X11WindowedEglLayerSwapchain : : size ( ) const
{
return m_size ;
}
std : : shared_ptr < X11WindowedEglLayerBuffer > X11WindowedEglLayerSwapchain : : acquire ( )
{
m_index = ( m_index + 1 ) % m_buffers . count ( ) ;
return m_buffers [ m_index ] ;
}
void X11WindowedEglLayerSwapchain : : release ( std : : shared_ptr < X11WindowedEglLayerBuffer > buffer )
{
Q_ASSERT ( m_buffers [ m_index ] = = buffer ) ;
for ( qsizetype i = 0 ; i < m_buffers . count ( ) ; + + i ) {
if ( m_buffers [ i ] = = buffer ) {
m_buffers [ i ] - > m_age = 1 ;
} else if ( m_buffers [ i ] - > m_age > 0 ) {
m_buffers [ i ] - > m_age + + ;
}
}
}
X11WindowedEglPrimaryLayer : : X11WindowedEglPrimaryLayer ( X11WindowedEglBackend * backend , X11WindowedOutput * output )
: m_output ( output )
, m_backend ( backend )
{
}
std : : optional < OutputLayerBeginFrameInfo > X11WindowedEglPrimaryLayer : : beginFrame ( )
{
eglMakeCurrent ( m_backend - > eglDisplay ( ) , m_eglSurface , m_eglSurface , m_backend - > context ( ) ) ;
ensureFbo ( ) ;
eglMakeCurrent ( m_backend - > eglDisplay ( ) , EGL_NO_SURFACE , EGL_NO_SURFACE , m_backend - > context ( ) ) ;
const QSize bufferSize = m_output - > pixelSize ( ) ;
if ( ! m_swapchain | | m_swapchain - > size ( ) ! = bufferSize ) {
const uint32_t format = DRM_FORMAT_XRGB8888 ;
const QHash < uint32_t , QVector < uint64_t > > formatTable = m_backend - > backend ( ) - > driFormats ( ) ;
if ( ! formatTable . contains ( format ) ) {
return std : : nullopt ;
}
m_swapchain = std : : make_unique < X11WindowedEglLayerSwapchain > ( bufferSize , format , 24 , 32 , formatTable [ format ] , m_output - > window ( ) , m_backend ) ;
}
m_buffer = m_swapchain - > acquire ( ) ;
QRegion repaint = m_output - > exposedArea ( ) + m_output - > rect ( ) ;
m_output - > clearExposedArea ( ) ;
GLFramebuffer : : pushFramebuffer ( m_buffer - > framebuffer ( ) ) ;
return OutputLayerBeginFrameInfo {
. renderTarget = RenderTarget ( m_fbo . get ( ) ) ,
. renderTarget = RenderTarget ( m_ buffer- > framebuffer ( ) ) ,
. repaint = repaint ,
} ;
}
bool X11WindowedEglPrimaryLayer : : endFrame ( const QRegion & renderedRegion , const QRegion & damagedRegion )
{
m_lastDamage = damagedRegion ;
return true ;
}
EGLSurface X11WindowedEglPrimaryLayer : : surface ( ) const
{
return m_eglSurface ;
}
QRegion X11WindowedEglPrimaryLayer : : lastDamage ( ) const
void X11WindowedEglPrimaryLayer : : present ( )
{
return m_lastDamage ;
xcb_xfixes_region_t valid = 0 ;
xcb_xfixes_region_t update = 0 ;
uint32_t serial = 0 ;
uint32_t options = 0 ;
uint64_t targetMsc = 0 ;
xcb_present_pixmap ( m_output - > backend ( ) - > connection ( ) ,
m_output - > window ( ) ,
m_buffer - > pixmap ( ) ,
serial ,
valid ,
update ,
0 ,
0 ,
XCB_NONE ,
XCB_NONE ,
XCB_NONE ,
options ,
targetMsc ,
0 ,
0 ,
0 ,
nullptr ) ;
Q_EMIT m_output - > outputChange ( infiniteRegion ( ) ) ;
m_swapchain - > release ( m_buffer ) ;
}
GLFramebuffer * X11WindowedEglPrimaryLayer : : fbo ( ) const
std: : shared_ptr < GLTexture > X11WindowedEglPrimaryLayer : : texture ( ) const
{
return m_fbo . get ( ) ;
return m_ buffer- > texture ( ) ;
}
quint32 X11WindowedEglPrimaryLayer : : format ( ) const
@ -137,6 +269,11 @@ X11WindowedEglBackend::~X11WindowedEglBackend()
cleanup ( ) ;
}
X11WindowedBackend * X11WindowedEglBackend : : backend ( ) const
{
return m_backend ;
}
void X11WindowedEglBackend : : init ( )
{
EglOnXBackend : : init ( ) ;
@ -156,41 +293,17 @@ bool X11WindowedEglBackend::createSurfaces()
const auto & outputs = m_backend - > outputs ( ) ;
for ( const auto & output : outputs ) {
X11WindowedOutput * x11Output = static_cast < X11WindowedOutput * > ( output ) ;
EGLSurface s = createSurface ( x11Output - > window ( ) ) ;
if ( s = = EGL_NO_SURFACE ) {
return false ;
}
m_outputs [ output ] = Layers {
. primaryLayer = std : : make_unique < X11WindowedEglPrimaryLayer > ( this , x11Output , s ),
. primaryLayer = std : : make_unique < X11WindowedEglPrimaryLayer > ( this , x11Output ) ,
. cursorLayer = std : : make_unique < X11WindowedEglCursorLayer > ( this , x11Output ) ,
} ;
}
if ( m_outputs . empty ( ) ) {
return false ;
}
return true ;
}
void X11WindowedEglBackend : : present ( Output * output )
{
const auto & renderOutput = m_outputs [ output ] ;
presentSurface ( renderOutput . primaryLayer - > surface ( ) , renderOutput . primaryLayer - > lastDamage ( ) , output - > geometry ( ) ) ;
Q_EMIT output - > outputChange ( renderOutput . primaryLayer - > lastDamage ( ) ) ;
}
void X11WindowedEglBackend : : presentSurface ( EGLSurface surface , const QRegion & damage , const QRect & screenGeometry )
{
const bool fullRepaint = supportsBufferAge ( ) | | ( damage = = screenGeometry ) ;
if ( fullRepaint | | ! havePostSubBuffer ( ) ) {
// the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation)
eglSwapBuffers ( eglDisplay ( ) , surface ) ;
} else {
// a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
for ( const QRect & r : damage ) {
eglPostSubBufferNV ( eglDisplay ( ) , surface , r . left ( ) , screenGeometry . height ( ) - r . bottom ( ) - 1 , r . width ( ) , r . height ( ) ) ;
}
}
m_outputs [ output ] . primaryLayer - > present ( ) ;
}
OutputLayer * X11WindowedEglBackend : : primaryLayer ( Output * output )
@ -220,10 +333,7 @@ std::shared_ptr<GLTexture> X11WindowedEglBackend::textureForOutput(Output *outpu
return nullptr ;
}
GLFramebuffer : : pushFramebuffer ( it - > second . primaryLayer - > fbo ( ) ) ;
auto ret = AbstractEglBackend : : textureForOutput ( output ) ;
GLFramebuffer : : popFramebuffer ( ) ;
return ret ;
return it - > second . primaryLayer - > texture ( ) ;
}
} // namespace