KWin
Loading...
Searching...
No Matches
basiceglsurfacetexture_wayland.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
9#include "opengl/glshader.h"
11#include "opengl/gltexture.h"
13#include "utils/common.h"
14
16#include <epoxy/egl.h>
18
19namespace KWin
20{
21
26
31
36
38{
40 return loadDmabufTexture(m_pixmap->buffer());
41 } else if (m_pixmap->buffer()->shmAttributes()) {
42 return loadShmTexture(m_pixmap->buffer());
43 } else {
44 return false;
45 }
46}
47
48void BasicEGLSurfaceTextureWayland::destroy()
49{
51 m_bufferType = BufferType::None;
52}
53
54void BasicEGLSurfaceTextureWayland::update(const QRegion &region)
55{
57 updateDmabufTexture(m_pixmap->buffer());
58 } else if (m_pixmap->buffer()->shmAttributes()) {
59 updateShmTexture(m_pixmap->buffer(), region);
60 }
61}
62
63bool BasicEGLSurfaceTextureWayland::loadShmTexture(GraphicsBuffer *buffer)
64{
65 const GraphicsBufferView view(buffer);
66 if (Q_UNLIKELY(!view.image())) {
67 return false;
68 }
69
70 std::shared_ptr<GLTexture> texture = GLTexture::upload(*view.image());
71 if (Q_UNLIKELY(!texture)) {
72 return false;
73 }
74
75 texture->setFilter(GL_LINEAR);
76 texture->setWrapMode(GL_CLAMP_TO_EDGE);
77 texture->setContentTransform(OutputTransform::FlipY);
78
79 m_texture = {{texture}};
80
81 m_bufferType = BufferType::Shm;
82
83 return true;
84}
85
86void BasicEGLSurfaceTextureWayland::updateShmTexture(GraphicsBuffer *buffer, const QRegion &region)
87{
88 if (Q_UNLIKELY(m_bufferType != BufferType::Shm)) {
89 destroy();
90 create();
91 return;
92 }
93
94 const GraphicsBufferView view(buffer);
95 if (Q_UNLIKELY(!view.image())) {
96 return;
97 }
98
99 for (const QRect &rect : region) {
100 m_texture.planes[0]->update(*view.image(), rect.topLeft(), rect);
101 }
102}
103
104bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(GraphicsBuffer *buffer)
105{
106 auto createTexture = [this](EGLImageKHR image, const QSize &size, bool isExternalOnly) -> std::shared_ptr<GLTexture> {
107 if (Q_UNLIKELY(image == EGL_NO_IMAGE_KHR)) {
108 qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer";
109 return nullptr;
110 }
111
112 GLint target = isExternalOnly ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
113 auto texture = std::make_shared<GLTexture>(target);
114 texture->setSize(size);
115 if (!texture->create()) {
116 return nullptr;
117 }
118 texture->setWrapMode(GL_CLAMP_TO_EDGE);
119 texture->setFilter(GL_LINEAR);
120 texture->bind();
121 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image));
122 texture->unbind();
124 texture->setContentTransform(OutputTransform::FlipY);
125 }
126 return texture;
127 };
128
129 const auto attribs = buffer->dmabufAttributes();
130 if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) {
131 QList<std::shared_ptr<GLTexture>> textures;
132 Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
133
134 for (uint plane = 0; plane < itConv->plane.count(); ++plane) {
135 const auto &currentPlane = itConv->plane[plane];
136 QSize size = buffer->size();
137 size.rwidth() /= currentPlane.widthDivisor;
138 size.rheight() /= currentPlane.heightDivisor;
139
140 const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(currentPlane.format, attribs->modifier);
141 auto t = createTexture(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size), size, isExternal);
142 if (!t) {
143 return false;
144 }
145 textures << t;
146 }
147 m_texture = {textures};
148 } else {
149 const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(attribs->format, attribs->modifier);
150 auto texture = createTexture(backend()->importBufferAsImage(buffer), buffer->size(), isExternal);
151 if (!texture) {
152 return false;
153 }
154 m_texture = {{texture}};
155 }
156 m_bufferType = BufferType::DmaBuf;
157
158 return true;
159}
160
161void BasicEGLSurfaceTextureWayland::updateDmabufTexture(GraphicsBuffer *buffer)
162{
163 if (Q_UNLIKELY(m_bufferType != BufferType::DmaBuf)) {
164 destroy();
165 create();
166 return;
167 }
168
169 const GLint target = GL_TEXTURE_2D;
170 if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) {
171 Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
172 for (uint plane = 0; plane < itConv->plane.count(); ++plane) {
173 const auto &currentPlane = itConv->plane[plane];
174 QSize size = buffer->size();
175 size.rwidth() /= currentPlane.widthDivisor;
176 size.rheight() /= currentPlane.heightDivisor;
177
178 m_texture.planes[plane]->bind();
179 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size)));
180 m_texture.planes[plane]->unbind();
181 }
182 } else {
183 Q_ASSERT(m_texture.planes.count() == 1);
184 m_texture.planes[0]->bind();
185 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(backend()->importBufferAsImage(buffer)));
186 m_texture.planes[0]->unbind();
187 }
188}
189
190} // namespace KWin
EglDisplay * eglDisplayObject() const
void update(const QRegion &region) override
BasicEGLSurfaceTextureWayland(OpenGLBackend *backend, SurfacePixmap *pixmap)
bool isExternalOnly(uint32_t format, uint64_t modifier) const
static std::unique_ptr< GLTexture > upload(const QImage &image)
virtual const DmaBufAttributes * dmabufAttributes() const
virtual const ShmAttributes * shmAttributes() const
The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap.
QList< std::shared_ptr< GLTexture > > planes
OpenGLSurfaceContents m_texture
OpenGLSurfaceContents texture() const
GraphicsBuffer * buffer() const
GraphicsBufferOrigin bufferOrigin() const
void * EGLImageKHR