18#include "compositor.h"
70 return std::make_unique<SceneOpenGLDecorationRenderer>(impl);
75 return std::make_unique<OpenGLShadowTextureProvider>(shadow);
105 std::shared_ptr<GLTexture> texture;
106 QList<ShadowTextureProvider *> providers;
108 QHash<KDecoration2::DecorationShadow *, Data> m_cache;
119 Q_ASSERT(m_cache.isEmpty());
124 auto it = m_cache.begin();
125 while (it != m_cache.end()) {
126 auto &d = it.value();
128 auto glIt = d.providers.begin();
129 while (glIt != d.providers.end()) {
130 if (*glIt == provider) {
131 glIt = d.providers.erase(glIt);
137 if (d.providers.isEmpty()) {
138 it = m_cache.erase(it);
151 Q_ASSERT(decoShadow);
152 auto it = m_cache.find(decoShadow.get());
153 if (it != m_cache.end()) {
154 Q_ASSERT(!it.value().providers.contains(provider));
155 it.value().providers << provider;
156 return it.value().texture;
159 d.providers << provider;
164 d.texture->setFilter(GL_LINEAR);
165 d.texture->setWrapMode(GL_CLAMP_TO_EDGE);
166 m_cache.insert(decoShadow.get(), d);
201 const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) + std::max(top.width(), bottom.width()) + std::max({topRight.width(), right.width(), bottomRight.width()});
202 const int height = std::max({topLeft.height(), top.height(), topRight.height()}) + std::max(left.height(), right.height()) + std::max({bottomLeft.height(), bottom.height(), bottomRight.height()});
204 if (width == 0 || height == 0) {
208 QImage image(width, height, QImage::Format_ARGB32);
209 image.fill(Qt::transparent);
211 const int innerRectTop = std::max({topLeft.height(), top.height(), topRight.height()});
212 const int innerRectLeft = std::max({topLeft.width(), left.width(), bottomLeft.width()});
232 QImage alphaImage(image.size(), QImage::Format_Alpha8);
233 bool alphaOnly =
true;
235 for (ptrdiff_t y = 0; alphaOnly && y < image.height(); y++) {
236 const uint32_t *
const src =
reinterpret_cast<const uint32_t *
>(image.scanLine(y));
237 uint8_t *
const dst =
reinterpret_cast<uint8_t *
>(alphaImage.scanLine(y));
239 for (ptrdiff_t x = 0; x < image.width(); x++) {
240 if (src[x] & 0x00ffffff) {
244 dst[x] = qAlpha(src[x]);
257 m_texture->setFilter(GL_LINEAR);
258 m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
260 if (m_texture->internalFormat() == GL_R8) {
263 m_texture->setSwizzle(GL_ZERO, GL_ZERO, GL_ZERO, GL_RED);
276 scene->makeOpenGLContextCurrent();
280static void clamp_row(
int left,
int width,
int right,
const uint32_t *src, uint32_t *dest)
282 std::fill_n(dest, left, *src);
283 std::copy(src, src + width, dest + left);
284 std::fill_n(dest + left + width, right, *(src + width - 1));
287static void clamp_sides(
int left,
int width,
int right,
const uint32_t *src, uint32_t *dest)
289 std::fill_n(dest, left, *src);
290 std::fill_n(dest + left + width, right, *(src + width - 1));
293static void clamp(QImage &image,
const QRect &viewport)
295 Q_ASSERT(image.depth() == 32);
296 if (viewport.isEmpty()) {
301 const QRect rect = image.rect();
303 const int left = viewport.left() - rect.left();
304 const int top = viewport.top() - rect.top();
305 const int right = rect.right() - viewport.right();
306 const int bottom = rect.bottom() - viewport.bottom();
308 const int width = rect.width() - left - right;
309 const int height = rect.height() - top - bottom;
311 const uint32_t *firstRow =
reinterpret_cast<uint32_t *
>(image.scanLine(top));
312 const uint32_t *lastRow =
reinterpret_cast<uint32_t *
>(image.scanLine(top + height - 1));
314 for (
int i = 0; i < top; ++i) {
315 uint32_t *dest =
reinterpret_cast<uint32_t *
>(image.scanLine(i));
316 clamp_row(left, width, right, firstRow + left, dest);
319 for (
int i = 0; i < height; ++i) {
320 uint32_t *dest =
reinterpret_cast<uint32_t *
>(image.scanLine(top + i));
321 clamp_sides(left, width, right, dest + left, dest);
324 for (
int i = 0; i < bottom; ++i) {
325 uint32_t *dest =
reinterpret_cast<uint32_t *
>(image.scanLine(top + height + i));
326 clamp_row(left, width, right, lastRow + left, dest);
342 QRectF left, top, right, bottom;
350 const QPoint topPosition(0, 0);
351 const QPoint bottomPosition(0, topPosition.y() + topHeight + (2 *
TexturePad));
352 const QPoint leftPosition(0, bottomPosition.y() + bottomHeight + (2 *
TexturePad));
353 const QPoint rightPosition(0, leftPosition.y() + leftWidth + (2 *
TexturePad));
355 const QRect dirtyRect = region.boundingRect();
357 renderPart(top.toRect().intersected(dirtyRect), top.toRect(), topPosition,
devicePixelRatio);
358 renderPart(bottom.toRect().intersected(dirtyRect), bottom.toRect(), bottomPosition,
devicePixelRatio);
359 renderPart(left.toRect().intersected(dirtyRect), left.toRect(), leftPosition,
devicePixelRatio,
true);
360 renderPart(right.toRect().intersected(dirtyRect), right.toRect(), rightPosition,
devicePixelRatio,
true);
363void SceneOpenGLDecorationRenderer::renderPart(
const QRect &rect,
const QRect &partRect,
364 const QPoint &textureOffset,
365 qreal devicePixelRatio,
bool rotated)
367 if (!rect.isValid() || !m_texture) {
374 const QMargins padding = texturePadForPart(rect, partRect);
375 int verticalPadding = padding.top() + padding.bottom();
376 int horizontalPadding = padding.left() + padding.right();
378 QSize imageSize(toNativeSize(rect.width()), toNativeSize(rect.height()));
380 imageSize = QSize(imageSize.height(), imageSize.width());
382 QSize paddedImageSize = imageSize;
383 paddedImageSize.rheight() += verticalPadding;
384 paddedImageSize.rwidth() += horizontalPadding;
385 QImage image(paddedImageSize, QImage::Format_ARGB32_Premultiplied);
387 image.fill(Qt::transparent);
389 QRect padClip = QRect(padding.left(), padding.top(), imageSize.width(), imageSize.height());
390 QPainter painter(&image);
392 painter.scale(inverseScale, inverseScale);
393 painter.setRenderHint(QPainter::Antialiasing);
394 painter.setClipRect(padClip);
395 painter.translate(padding.left(), padding.top());
397 painter.translate(0, imageSize.height());
401 painter.translate(-rect.topLeft());
406 clamp(image, padClip);
408 QPoint dirtyOffset = (rect.topLeft() - partRect.topLeft()) *
devicePixelRatio;
409 if (padding.top() == 0) {
412 if (padding.left() == 0) {
415 m_texture->update(image, textureOffset + dirtyOffset);
418const QMargins SceneOpenGLDecorationRenderer::texturePadForPart(
419 const QRect &rect,
const QRect &partRect)
421 QMargins result = QMargins(0, 0, 0, 0);
422 if (rect.top() == partRect.top()) {
425 if (rect.bottom() == partRect.bottom()) {
428 if (rect.left() == partRect.left()) {
431 if (rect.right() == partRect.right()) {
442void SceneOpenGLDecorationRenderer::resizeTexture()
444 QRectF left, top, right, bottom;
448 size.rwidth() = toNativeSize(std::max(std::max(top.width(), bottom.width()),
449 std::max(left.height(), right.height())));
450 size.rheight() = toNativeSize(top.height()) + toNativeSize(bottom.height()) + toNativeSize(left.width()) + toNativeSize(right.width());
454 size.rwidth() =
align(size.width(), 128);
456 if (m_texture && m_texture->size() == size) {
460 if (!size.isEmpty()) {
466 m_texture->setFilter(GL_LINEAR);
467 m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
474int SceneOpenGLDecorationRenderer::toNativeSize(
int size)
const
481#include "moc_workspacescene_opengl.cpp"
WorkspaceScene * scene() const
static Compositor * self()
void resetImageSizesDirty()
static const int TexturePad
void renderToPainter(QPainter *painter, const QRect &rect)
Decoration::DecoratedClientImpl * client() const
bool areImageSizesDirty() const
qreal devicePixelRatio() const
qreal effectiveDevicePixelRatio() const
static DecorationShadowTextureCache & instance()
~DecorationShadowTextureCache()
std::shared_ptr< GLTexture > getTexture(ShadowTextureProvider *provider)
void unregister(ShadowTextureProvider *provider)
DecorationShadowTextureCache(const DecorationShadowTextureCache &)=delete
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
static bool supportsFormatRG()
static std::unique_ptr< GLTexture > upload(const QImage &image)
static bool supportsSwizzle()
The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap.
virtual std::pair< std::shared_ptr< GLTexture >, ColorDescription > textureForOutput(Output *output) const
virtual void doneCurrent()=0
bool supportsNativeFence() const
virtual bool makeCurrent()=0
OpenGLShadowTextureProvider(Shadow *shadow)
~OpenGLShadowTextureProvider() override
~SceneOpenGLDecorationRenderer() override
void render(const QRegion ®ion) override
SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client)
Class representing a Window's Shadow to be rendered by the Compositor.
bool hasDecorationShadow() const
@ ShadowElementBottomLeft
@ ShadowElementBottomRight
const QImage & shadowElement(ShadowElements element) const
QImage decorationShadowImage() const
std::weak_ptr< KDecoration2::DecorationShadow > decorationShadow() const
void layoutDecorationRects(QRectF &left, QRectF &top, QRectF &right, QRectF &bottom) const
virtual bool makeOpenGLContextCurrent()
bool makeOpenGLContextCurrent() override
std::unique_ptr< ShadowTextureProvider > createShadowTextureProvider(Shadow *shadow) override
std::unique_ptr< DecorationRenderer > createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override
WorkspaceSceneOpenGL(OpenGLBackend *backend)
std::pair< std::shared_ptr< GLTexture >, ColorDescription > textureForOutput(Output *output) const override
~WorkspaceSceneOpenGL() override
void doneOpenGLContextCurrent() override
bool animationsSupported() const override
bool supportsNativeFence() const override
T align(T value, int bytes)