25 const QString visualizeOptionsString = qEnvironmentVariable(
"KWIN_SCENE_VISUALIZE");
26 if (!visualizeOptionsString.isEmpty()) {
27 const QStringList visualtizeOptions = visualizeOptionsString.split(
';');
28 m_debug.fractionalEnabled = visualtizeOptions.contains(QLatin1StringView(
"fractional"));
34 return std::make_unique<ImageItemOpenGL>(scene, parent);
51QVector4D ItemRendererOpenGL::modulate(
float opacity,
float brightness)
const
53 const float a = opacity;
54 const float rgb = opacity * brightness;
56 return QVector4D(rgb, rgb, rgb, a);
59void ItemRendererOpenGL::setBlendEnabled(
bool enabled)
61 if (enabled && !m_blendingEnabled) {
63 }
else if (!enabled && m_blendingEnabled) {
67 m_blendingEnabled = enabled;
70static OpenGLSurfaceContents bindSurfaceTexture(SurfaceItem *surfaceItem)
72 SurfacePixmap *surfacePixmap = surfaceItem->pixmap();
73 auto platformSurfaceTexture =
74 static_cast<OpenGLSurfaceTexture *
>(surfacePixmap->texture());
75 if (surfacePixmap->isDiscarded()) {
76 return platformSurfaceTexture->texture();
79 if (platformSurfaceTexture->texture().isValid()) {
80 const QRegion region = surfaceItem->damage();
81 if (!region.isEmpty()) {
82 platformSurfaceTexture->update(region);
83 surfaceItem->resetDamage();
86 if (!surfacePixmap->isValid()) {
89 if (!platformSurfaceTexture->create()) {
90 qCDebug(KWIN_OPENGL) <<
"Failed to bind window";
93 surfaceItem->resetDamage();
96 return platformSurfaceTexture->texture();
99static RenderGeometry clipQuads(
const Item *item,
const ItemRendererOpenGL::RenderContext *context)
101 const WindowQuadList quads = item->quads();
104 const QPointF worldTranslation = context->transformStack.top().map(QPointF(0., 0.));
105 const qreal scale = context->renderTargetScale;
107 RenderGeometry geometry;
108 geometry.reserve(quads.count() * 6);
111 for (
const WindowQuad &quad : std::as_const(quads)) {
112 if (context->clip !=
infiniteRegion() && !context->hardwareClipping) {
116 for (
const QRect &clipRect : std::as_const(context->clip)) {
119 const QRectF &intersected = deviceClipRect.intersected(deviceBounds);
120 if (intersected.isValid()) {
121 if (deviceBounds == intersected) {
123 geometry.appendWindowQuad(quad, scale);
127 geometry.appendSubQuad(quad, intersected, scale);
131 geometry.appendWindowQuad(quad, scale);
138void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
140 const QList<Item *> sortedChildItems = item->sortedChildItems();
143 const auto logicalPosition = QVector2D(item->position().x(), item->position().y());
144 const auto scale = context->renderTargetScale;
145 matrix.translate(
roundVector(logicalPosition * scale).toVector3D());
146 matrix *= item->transform();
147 context->transformStack.push(context->transformStack.top() * matrix);
149 context->opacityStack.push(context->opacityStack.top() * item->opacity());
151 for (Item *childItem : sortedChildItems) {
152 if (childItem->z() >= 0) {
155 if (childItem->explicitVisible()) {
156 createRenderNode(childItem, context);
162 RenderGeometry geometry = clipQuads(item, context);
164 if (
auto shadowItem = qobject_cast<ShadowItem *>(item)) {
165 if (!geometry.isEmpty()) {
166 OpenGLShadowTextureProvider *textureProvider =
static_cast<OpenGLShadowTextureProvider *
>(shadowItem->textureProvider());
167 context->renderNodes.append(RenderNode{
168 .texture = textureProvider->shadowTexture(),
169 .geometry = geometry,
170 .transformMatrix = context->transformStack.top(),
171 .opacity = context->opacityStack.top(),
175 .colorDescription = item->colorDescription(),
178 }
else if (
auto decorationItem = qobject_cast<DecorationItem *>(item)) {
179 if (!geometry.isEmpty()) {
180 auto renderer =
static_cast<const SceneOpenGLDecorationRenderer *
>(decorationItem->renderer());
181 context->renderNodes.append(RenderNode{
182 .texture = renderer->texture(),
183 .geometry = geometry,
184 .transformMatrix = context->transformStack.top(),
185 .opacity = context->opacityStack.top(),
189 .colorDescription = item->colorDescription(),
192 }
else if (
auto surfaceItem = qobject_cast<SurfaceItem *>(item)) {
193 SurfacePixmap *pixmap = surfaceItem->pixmap();
195 if (!geometry.isEmpty()) {
196 context->renderNodes.append(RenderNode{
197 .texture = bindSurfaceTexture(surfaceItem),
198 .geometry = geometry,
199 .transformMatrix = context->transformStack.top(),
200 .opacity = context->opacityStack.top(),
201 .hasAlpha = pixmap->hasAlphaChannel(),
204 .colorDescription = item->colorDescription(),
208 }
else if (
auto imageItem = qobject_cast<ImageItemOpenGL *>(item)) {
209 if (!geometry.isEmpty()) {
210 context->renderNodes.append(RenderNode{
211 .texture = imageItem->texture(),
212 .geometry = geometry,
213 .transformMatrix = context->transformStack.top(),
214 .opacity = context->opacityStack.top(),
215 .hasAlpha = imageItem->image().hasAlphaChannel(),
218 .colorDescription = item->colorDescription(),
223 for (Item *childItem : sortedChildItems) {
224 if (childItem->z() < 0) {
227 if (childItem->explicitVisible()) {
228 createRenderNode(childItem, context);
232 context->transformStack.pop();
233 context->opacityStack.pop();
239 glClearColor(0, 0, 0, 0);
240 glClear(GL_COLOR_BUFFER_BIT);
241 }
else if (!region.isEmpty()) {
242 glClearColor(0, 0, 0, 0);
243 glEnable(GL_SCISSOR_TEST);
245 const auto targetSize = renderTarget.
size();
246 for (
const QRect &r : region) {
248 glScissor(deviceRect.x(), targetSize.height() - (deviceRect.y() + deviceRect.height()), deviceRect.width(), deviceRect.height());
249 glClear(GL_COLOR_BUFFER_BIT);
252 glDisable(GL_SCISSOR_TEST);
258 if (region.isEmpty()) {
266 .renderTargetScale = viewport.
scale(),
269 renderContext.transformStack.push(QMatrix4x4());
270 renderContext.opacityStack.push(data.
opacity());
274 createRenderNode(item, &renderContext);
276 int totalVertexCount = 0;
277 for (
const RenderNode &node : std::as_const(renderContext.renderNodes)) {
278 totalVertexCount += node.geometry.count();
280 if (totalVertexCount == 0) {
301 for (
int i = 0, v = 0; i < renderContext.renderNodes.count(); i++) {
302 RenderNode &renderNode = renderContext.renderNodes[i];
304 || (std::holds_alternative<GLTexture *>(renderNode.
texture) && !std::get<GLTexture *>(renderNode.
texture))
305 || (std::holds_alternative<OpenGLSurfaceContents>(renderNode.
texture) && !std::get<OpenGLSurfaceContents>(renderNode.
texture).isValid())) {
313 if (std::holds_alternative<GLTexture *>(renderNode.
texture)) {
314 texture = std::get<GLTexture *>(renderNode.
texture);
316 texture = std::get<OpenGLSurfaceContents>(renderNode.
texture).planes.constFirst().get();
327 if (renderContext.hardwareClipping) {
328 glEnable(GL_SCISSOR_TEST);
332 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
336 if (renderContext.hardwareClipping) {
340 ShaderTraits lastTraits;
342 for (
int i = 0; i < renderContext.renderNodes.count(); i++) {
343 const RenderNode &renderNode = renderContext.renderNodes[i];
350 ShaderTraits traits = baseShaderTraits;
351 if (renderNode.
opacity != 1.0) {
357 if (!shader || traits != lastTraits) {
382 if (std::holds_alternative<GLTexture *>(renderNode.
texture)) {
383 const auto texture = std::get<GLTexture *>(renderNode.
texture);
384 glActiveTexture(GL_TEXTURE0);
388 const auto contents = std::get<OpenGLSurfaceContents>(renderNode.
texture);
389 shader->
setUniform(
"converter", contents.planes.count() > 1);
390 for (
int plane = 0; plane < contents.planes.count(); ++plane) {
391 glActiveTexture(GL_TEXTURE0 + plane);
392 contents.planes[plane]->bind();
397 renderNode.
vertexCount, renderContext.hardwareClipping);
399 if (std::holds_alternative<GLTexture *>(renderNode.
texture)) {
400 auto texture = std::get<GLTexture *>(renderNode.
texture);
401 glActiveTexture(GL_TEXTURE0);
404 const auto contents = std::get<OpenGLSurfaceContents>(renderNode.
texture);
405 for (
int plane = 0; plane < contents.planes.count(); ++plane) {
406 glActiveTexture(GL_TEXTURE0 + plane);
407 contents.planes[plane]->unbind();
415 if (m_debug.fractionalEnabled) {
416 visualizeFractional(viewport, scissorRegion, renderContext);
421 setBlendEnabled(
false);
423 if (renderContext.hardwareClipping) {
424 glDisable(GL_SCISSOR_TEST);
428void ItemRendererOpenGL::visualizeFractional(
const RenderViewport &viewport,
const QRegion ®ion,
const RenderContext &renderContext)
430 if (!m_debug.fractionalShader) {
433 QStringLiteral(
":/scene/shaders/debug_fractional.vert"),
434 QStringLiteral(
":/scene/shaders/debug_fractional.frag"));
437 if (!m_debug.fractionalShader) {
441 ShaderBinder debugShaderBinder(m_debug.fractionalShader.get());
442 m_debug.fractionalShader->setUniform(
"fractionalPrecision", 0.01f);
445 m_debug.fractionalShader->setUniform(
"screenSize", QVector2D(
float(screenSize.width()),
float(screenSize.height())));
449 for (
int i = 0; i < renderContext.renderNodes.count(); i++) {
450 const RenderNode &renderNode = renderContext.renderNodes[i];
451 if (renderNode.vertexCount == 0) {
455 setBlendEnabled(
true);
458 if (std::holds_alternative<GLTexture *>(renderNode.texture)) {
459 auto texture = std::get<GLTexture *>(renderNode.texture);
460 size = QVector2D(texture->width(), texture->height());
462 auto texture = std::get<OpenGLSurfaceContents>(renderNode.texture).planes.constFirst().get();
463 size = QVector2D(texture->width(), texture->height());
466 m_debug.fractionalShader->setUniform(
"geometrySize", size);
469 vbo->draw(region, GL_TRIANGLES, renderNode.firstVertex,
470 renderNode.vertexCount, renderContext.hardwareClipping);
const Colorimetry & colorimetry() const
const QMatrix4x4 & toXYZ() const
OpenGL framebuffer object.
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
@ ModelViewProjectionMatrix
bool setUniform(const char *name, float value)
bool setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst)
QMatrix4x4 matrix(TextureCoordinateType type) const
void draw(GLenum primitiveMode, int first, int count)
void setAttribLayout(std::span< const GLVertexAttrib > attribs, size_t stride)
static constexpr std::array GLVertex2DLayout
static GLVertexBuffer * streamingBuffer()
std::optional< std::span< T > > map(size_t count)
void setTransform(const QMatrix4x4 &transform)
void beginFrame(const RenderTarget &renderTarget, const RenderViewport &viewport) override
std::unique_ptr< ImageItem > createImageItem(Scene *scene, Item *parent=nullptr) override
void renderItem(const RenderTarget &renderTarget, const RenderViewport &viewport, Item *item, int mask, const QRegion ®ion, const WindowPaintData &data) override
void renderBackground(const RenderTarget &renderTarget, const RenderViewport &viewport, const QRegion ®ion) override
void postProcessTextureCoordinates(const QMatrix4x4 &textureMatrix)
void copy(std::span< GLVertex2D > destination)
GLFramebuffer * framebuffer() const
const ColorDescription & colorDescription() const
QRectF renderRect() const
QRectF mapToRenderTarget(const QRectF &logicalGeometry) const
@ PAINT_SCREEN_TRANSFORMED
@ PAINT_WINDOW_TRANSFORMED
std::unique_ptr< GLShader > generateShaderFromFile(ShaderTraits traits, const QString &vertexFile=QString(), const QString &fragmentFile=QString())
static ShaderManager * instance()
GLShader * pushShader(ShaderTraits traits)
QMatrix4x4 toMatrix(qreal deviceScale) const
QMatrix4x4 projectionMatrix() const
KWIN_EXPORT QRect infiniteRegion()
KWIN_EXPORT QPointF snapToPixelGridF(const QPointF &point)
KWIN_EXPORT QRectF scaledRect(const QRectF &rect, qreal scale)
@ UnnormalizedCoordinates
KWIN_EXPORT QVector2D roundVector(const QVector2D &input)
const QMatrix4x4 projectionMatrix
QMatrix4x4 transformMatrix
ColorDescription colorDescription
std::variant< GLTexture *, OpenGLSurfaceContents > texture
TextureCoordinateType coordinateType