File indexing completed on 2024-11-10 04:56:56
0001 /* 0002 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" 0008 #include "core/graphicsbufferview.h" 0009 #include "opengl/glshader.h" 0010 #include "opengl/glshadermanager.h" 0011 #include "opengl/gltexture.h" 0012 #include "platformsupport/scenes/opengl/abstract_egl_backend.h" 0013 #include "utils/common.h" 0014 0015 #include "abstract_egl_backend.h" 0016 #include <epoxy/egl.h> 0017 #include <utils/drm_format_helper.h> 0018 0019 namespace KWin 0020 { 0021 0022 BasicEGLSurfaceTextureWayland::BasicEGLSurfaceTextureWayland(OpenGLBackend *backend, SurfacePixmap *pixmap) 0023 : OpenGLSurfaceTextureWayland(backend, pixmap) 0024 { 0025 } 0026 0027 BasicEGLSurfaceTextureWayland::~BasicEGLSurfaceTextureWayland() 0028 { 0029 destroy(); 0030 } 0031 0032 AbstractEglBackend *BasicEGLSurfaceTextureWayland::backend() const 0033 { 0034 return static_cast<AbstractEglBackend *>(m_backend); 0035 } 0036 0037 bool BasicEGLSurfaceTextureWayland::create() 0038 { 0039 if (m_pixmap->buffer()->dmabufAttributes()) { 0040 return loadDmabufTexture(m_pixmap->buffer()); 0041 } else if (m_pixmap->buffer()->shmAttributes()) { 0042 return loadShmTexture(m_pixmap->buffer()); 0043 } else { 0044 return false; 0045 } 0046 } 0047 0048 void BasicEGLSurfaceTextureWayland::destroy() 0049 { 0050 m_texture.reset(); 0051 m_bufferType = BufferType::None; 0052 } 0053 0054 void BasicEGLSurfaceTextureWayland::update(const QRegion ®ion) 0055 { 0056 if (m_pixmap->buffer()->dmabufAttributes()) { 0057 updateDmabufTexture(m_pixmap->buffer()); 0058 } else if (m_pixmap->buffer()->shmAttributes()) { 0059 updateShmTexture(m_pixmap->buffer(), region); 0060 } 0061 } 0062 0063 bool BasicEGLSurfaceTextureWayland::loadShmTexture(GraphicsBuffer *buffer) 0064 { 0065 const GraphicsBufferView view(buffer); 0066 if (Q_UNLIKELY(!view.image())) { 0067 return false; 0068 } 0069 0070 std::shared_ptr<GLTexture> texture = GLTexture::upload(*view.image()); 0071 if (Q_UNLIKELY(!texture)) { 0072 return false; 0073 } 0074 0075 texture->setFilter(GL_LINEAR); 0076 texture->setWrapMode(GL_CLAMP_TO_EDGE); 0077 texture->setContentTransform(OutputTransform::FlipY); 0078 0079 m_texture = {{texture}}; 0080 0081 m_bufferType = BufferType::Shm; 0082 0083 return true; 0084 } 0085 0086 void BasicEGLSurfaceTextureWayland::updateShmTexture(GraphicsBuffer *buffer, const QRegion ®ion) 0087 { 0088 if (Q_UNLIKELY(m_bufferType != BufferType::Shm)) { 0089 destroy(); 0090 create(); 0091 return; 0092 } 0093 0094 const GraphicsBufferView view(buffer); 0095 if (Q_UNLIKELY(!view.image())) { 0096 return; 0097 } 0098 0099 for (const QRect &rect : region) { 0100 m_texture.planes[0]->update(*view.image(), rect.topLeft(), rect); 0101 } 0102 } 0103 0104 bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(GraphicsBuffer *buffer) 0105 { 0106 auto createTexture = [this](EGLImageKHR image, const QSize &size, bool isExternalOnly) -> std::shared_ptr<GLTexture> { 0107 if (Q_UNLIKELY(image == EGL_NO_IMAGE_KHR)) { 0108 qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer"; 0109 return nullptr; 0110 } 0111 0112 GLint target = isExternalOnly ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; 0113 auto texture = std::make_shared<GLTexture>(target); 0114 texture->setSize(size); 0115 if (!texture->create()) { 0116 return nullptr; 0117 } 0118 texture->setWrapMode(GL_CLAMP_TO_EDGE); 0119 texture->setFilter(GL_LINEAR); 0120 texture->bind(); 0121 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image)); 0122 texture->unbind(); 0123 if (m_pixmap->bufferOrigin() == GraphicsBufferOrigin::TopLeft) { 0124 texture->setContentTransform(OutputTransform::FlipY); 0125 } 0126 return texture; 0127 }; 0128 0129 const auto attribs = buffer->dmabufAttributes(); 0130 if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) { 0131 QList<std::shared_ptr<GLTexture>> textures; 0132 Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount)); 0133 0134 for (uint plane = 0; plane < itConv->plane.count(); ++plane) { 0135 const auto ¤tPlane = itConv->plane[plane]; 0136 QSize size = buffer->size(); 0137 size.rwidth() /= currentPlane.widthDivisor; 0138 size.rheight() /= currentPlane.heightDivisor; 0139 0140 const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(currentPlane.format, attribs->modifier); 0141 auto t = createTexture(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size), size, isExternal); 0142 if (!t) { 0143 return false; 0144 } 0145 textures << t; 0146 } 0147 m_texture = {textures}; 0148 } else { 0149 const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(attribs->format, attribs->modifier); 0150 auto texture = createTexture(backend()->importBufferAsImage(buffer), buffer->size(), isExternal); 0151 if (!texture) { 0152 return false; 0153 } 0154 m_texture = {{texture}}; 0155 } 0156 m_bufferType = BufferType::DmaBuf; 0157 0158 return true; 0159 } 0160 0161 void BasicEGLSurfaceTextureWayland::updateDmabufTexture(GraphicsBuffer *buffer) 0162 { 0163 if (Q_UNLIKELY(m_bufferType != BufferType::DmaBuf)) { 0164 destroy(); 0165 create(); 0166 return; 0167 } 0168 0169 const GLint target = GL_TEXTURE_2D; 0170 if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) { 0171 Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount)); 0172 for (uint plane = 0; plane < itConv->plane.count(); ++plane) { 0173 const auto ¤tPlane = itConv->plane[plane]; 0174 QSize size = buffer->size(); 0175 size.rwidth() /= currentPlane.widthDivisor; 0176 size.rheight() /= currentPlane.heightDivisor; 0177 0178 m_texture.planes[plane]->bind(); 0179 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size))); 0180 m_texture.planes[plane]->unbind(); 0181 } 0182 } else { 0183 Q_ASSERT(m_texture.planes.count() == 1); 0184 m_texture.planes[0]->bind(); 0185 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(backend()->importBufferAsImage(buffer))); 0186 m_texture.planes[0]->unbind(); 0187 } 0188 } 0189 0190 } // namespace KWin