56 {GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
58 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
59 {GL_RGB8, GL_BGR, GL_UNSIGNED_SHORT_5_6_5_REV},
63 {GL_RGB5, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
65 {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE},
66 {GL_RGB4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
67 {GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
68 {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE},
70 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
71 {GL_RGB10, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV},
72 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV},
73 {GL_RGB10, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV},
74 {GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV},
75 {GL_R8, GL_RED, GL_UNSIGNED_BYTE},
76 {GL_R8, GL_RED, GL_UNSIGNED_BYTE},
77 {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT},
79 {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT},
80 {GL_R16, GL_RED, GL_UNSIGNED_SHORT},
94 d->m_texture = textureId;
95 d->m_scale.setWidth(1.0 /
size.width());
96 d->m_scale.setHeight(1.0 /
size.height());
98 d->m_canUseMipmaps = levels > 1;
99 d->m_mipLevels = levels;
100 d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
102 d->m_textureToBufferTransform = transform;
116 glGenTextures(1, &
d->m_texture);
117 return d->m_texture != GL_NONE;
123 , m_internalFormat(0)
124 , m_filter(GL_NEAREST)
125 , m_wrapMode(GL_REPEAT)
126 , m_canUseMipmaps(false)
127 , m_markedDirty(false)
128 , m_filterChanged(true)
129 , m_wrapModeChanged(false)
132 , m_unnormalizeActive(0)
133 , m_normalizeActive(0)
171void GLTexturePrivate::cleanup()
176 glDeleteFramebuffers(1, &
s_fbo);
183 return GL_NONE ==
d->m_texture;
202 if (image.isNull() ||
isNull()) {
206 Q_ASSERT(
d->m_owning);
210 QImage::Format uploadFormat;
212 const QImage::Format index = image.format();
215 && !(
formatTable[index].
type == GL_UNSIGNED_SHORT && !
d->s_supportsTexture16Bit)) {
218 uploadFormat = index;
221 type = GL_UNSIGNED_INT_8_8_8_8_REV;
222 uploadFormat = QImage::Format_ARGB32_Premultiplied;
225 if (
d->s_supportsARGB32) {
226 glFormat = GL_BGRA_EXT;
227 type = GL_UNSIGNED_BYTE;
228 uploadFormat = QImage::Format_ARGB32_Premultiplied;
231 type = GL_UNSIGNED_BYTE;
232 uploadFormat = QImage::Format_RGBA8888_Premultiplied;
235 bool useUnpack =
d->s_supportsUnpack && image.format() == uploadFormat && !src.isNull();
240 Q_ASSERT(im.depth() % 8 == 0);
241 glPixelStorei(GL_UNPACK_ROW_LENGTH, im.bytesPerLine() / (im.depth() / 8));
242 glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.x());
243 glPixelStorei(GL_UNPACK_SKIP_ROWS, src.y());
248 im = image.copy(src);
250 if (im.format() != uploadFormat) {
251 im.convertTo(uploadFormat);
255 int width = image.width();
256 int height = image.height();
264 glTexSubImage2D(
d->m_target, 0, offset.x(), offset.y(),
width,
height, glFormat,
type, im.constBits());
269 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
270 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
271 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
277 Q_ASSERT(
d->m_texture);
279 glBindTexture(
d->m_target,
d->m_texture);
281 if (
d->m_markedDirty) {
284 if (
d->m_filterChanged) {
285 GLenum minFilter = GL_NEAREST;
286 GLenum magFilter = GL_NEAREST;
288 switch (
d->m_filter) {
290 minFilter = magFilter = GL_NEAREST;
294 minFilter = magFilter = GL_LINEAR;
297 case GL_NEAREST_MIPMAP_NEAREST:
298 case GL_NEAREST_MIPMAP_LINEAR:
299 magFilter = GL_NEAREST;
300 minFilter =
d->m_canUseMipmaps ?
d->m_filter : GL_NEAREST;
303 case GL_LINEAR_MIPMAP_NEAREST:
304 case GL_LINEAR_MIPMAP_LINEAR:
305 magFilter = GL_LINEAR;
306 minFilter =
d->m_canUseMipmaps ?
d->m_filter : GL_LINEAR;
310 glTexParameteri(
d->m_target, GL_TEXTURE_MIN_FILTER, minFilter);
311 glTexParameteri(
d->m_target, GL_TEXTURE_MAG_FILTER, magFilter);
313 d->m_filterChanged =
false;
315 if (
d->m_wrapModeChanged) {
316 glTexParameteri(
d->m_target, GL_TEXTURE_WRAP_S,
d->m_wrapMode);
317 glTexParameteri(
d->m_target, GL_TEXTURE_WRAP_T,
d->m_wrapMode);
318 d->m_wrapModeChanged =
false;
324 if (
d->m_canUseMipmaps &&
d->s_supportsFramebufferObjects) {
325 glGenerateMipmap(
d->m_target);
331 glBindTexture(
d->m_target, 0);
341 const auto rotatedSize =
d->m_textureToBufferTransform.map(
size());
342 render(QRectF(QPoint(), rotatedSize), region, targetSize, hardwareClipping);
345void GLTexture::render(
const QRectF &source,
const QRegion ®ion,
const QSizeF &targetSize,
bool hardwareClipping)
347 if (targetSize.isEmpty()) {
351 const QSize destinationSize = targetSize.toSize();
352 if (targetSize !=
d->m_cachedSize ||
d->m_cachedSource != source ||
d->m_cachedContentTransform !=
d->m_textureToBufferTransform) {
353 d->m_cachedSize = destinationSize;
354 d->m_cachedSource = source;
355 d->m_cachedContentTransform =
d->m_textureToBufferTransform;
357 const float texWidth = (
target() == GL_TEXTURE_RECTANGLE_ARB) ?
width() : 1.0f;
358 const float texHeight = (
target() == GL_TEXTURE_RECTANGLE_ARB) ?
height() : 1.0f;
360 const QSize rotatedSize =
d->m_textureToBufferTransform.map(
size());
362 QMatrix4x4 textureMat;
363 textureMat.translate(texWidth / 2, texHeight / 2);
365 textureMat.scale(1, -1);
366 textureMat *=
d->m_textureToBufferTransform.toMatrix();
367 textureMat.translate(-texWidth / 2, -texHeight / 2);
368 textureMat.scale(texWidth / rotatedSize.width(), texHeight / rotatedSize.height());
370 const QPointF p1 = textureMat.map(QPointF(source.x(), source.y()));
371 const QPointF p2 = textureMat.map(QPointF(source.x(), source.y() + source.height()));
372 const QPointF p3 = textureMat.map(QPointF(source.x() + source.width(), source.y()));
373 const QPointF p4 = textureMat.map(QPointF(source.x() + source.width(), source.y() + source.height()));
378 const std::array<GLVertex2D, 4> data{
381 .texcoord = QVector2D(p1),
384 .
position = QVector2D(0, destinationSize.height()),
385 .texcoord = QVector2D(p2),
388 .
position = QVector2D(destinationSize.width(), 0),
389 .texcoord = QVector2D(p3),
392 .
position = QVector2D(destinationSize.width(), destinationSize.height()),
393 .texcoord = QVector2D(p4),
396 d->m_vbo->setVertices(data);
399 d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping);
420 return d->m_internalFormat;
425 Q_ASSERT(
d->m_owning);
432 GLuint previousFramebuffer = 0;
433 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING,
reinterpret_cast<GLint *
>(&previousFramebuffer));
437 glClearColor(0, 0, 0, 0);
438 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
d->m_texture, 0);
439 glClear(GL_COLOR_BUFFER_BIT);
441 glBindFramebuffer(GL_FRAMEBUFFER, previousFramebuffer);
445 std::vector<uint32_t> buffer(
size, 0);
448 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
width(),
height(),
449 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer.data());
451 const GLenum
format =
d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
452 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
width(),
height(),
453 format, GL_UNSIGNED_BYTE, buffer.data());
462 return d->m_markedDirty;
469 d->m_filterChanged =
true;
475 if (mode !=
d->m_wrapMode) {
476 d->m_wrapMode = mode;
477 d->m_wrapModeChanged =
true;
483 d->m_markedDirty =
true;
497 if (
m_target == GL_TEXTURE_RECTANGLE_ARB) {
517 if (
d->m_textureToBufferTransform != transform) {
518 d->m_textureToBufferTransform = transform;
525 return d->m_textureToBufferTransform;
531 const GLuint swizzle[] = {red, green, blue, alpha};
532 glTexParameteriv(
d->m_target, GL_TEXTURE_SWIZZLE_RGBA, (
const GLint *)swizzle);
534 glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_R, red);
535 glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_G, green);
536 glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_B, blue);
537 glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_A, alpha);
543 return d->m_size.width();
548 return d->m_size.height();
553 return d->m_matrix[
type];
573 if (
target() != GL_TEXTURE_2D) {
576 QImage ret(
size(), QImage::Format_RGBA8888_Premultiplied);
581 glReadPixels(0, 0,
width(),
height(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ret.bits());
584 GLint currentTextureBinding;
585 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤tTextureBinding);
586 if (GLuint(currentTextureBinding) !=
texture()) {
587 glBindTexture(GL_TEXTURE_2D,
texture());
589 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ret.bits());
590 if (GLuint(currentTextureBinding) !=
texture()) {
591 glBindTexture(GL_TEXTURE_2D, currentTextureBinding);
607 qCWarning(KWIN_OPENGL,
"generating OpenGL texture handle failed");
610 glBindTexture(GL_TEXTURE_2D,
texture);
616 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1);
618 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
nullptr);
625 glTexImage2D(GL_TEXTURE_2D, 0,
format,
size.width(),
size.height(), 0,
626 format, GL_UNSIGNED_BYTE,
nullptr);
631 glBindTexture(GL_TEXTURE_2D, 0);
637 if (image.isNull()) {
643 qCWarning(KWIN_OPENGL,
"generating OpenGL texture handle failed");
646 glBindTexture(GL_TEXTURE_2D,
texture);
654 const QImage::Format index = image.format();
663 im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
666 type = GL_UNSIGNED_INT_8_8_8_8_REV;
670 glTexStorage2D(GL_TEXTURE_2D, 1,
internalFormat, im.width(), im.height());
671 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, im.width(), im.height(),
674 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
675 glTexImage2D(GL_TEXTURE_2D, 0,
internalFormat, im.width(), im.height(), 0,
682 const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
683 glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, im.width(), im.height(),
684 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.constBits());
686 const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
687 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(), im.height(),
688 0, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
691 glBindTexture(GL_TEXTURE_2D, 0);
697 return upload(pixmap.toImage());
OpenGL framebuffer object.
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
const std::unique_ptr< GLTexturePrivate > d
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
OutputTransform contentTransform() const
void setContentTransform(OutputTransform transform)
static bool supportsFormatRG()
void setFilter(GLenum filter)
static std::unique_ptr< GLTexture > createNonOwningWrapper(GLuint textureId, GLenum internalFormat, const QSize &size)
GLenum internalFormat() const
void setSize(const QSize &size)
void update(const QImage &image, const QPoint &offset=QPoint(0, 0), const QRect &src=QRect())
void setSwizzle(GLenum red, GLenum green, GLenum blue, GLenum alpha)
static std::unique_ptr< GLTexture > upload(const QImage &image)
void clear()
Make the texture fully transparent.
QMatrix4x4 matrix(TextureCoordinateType type) const
void render(const QSizeF &size)
static bool framebufferObjectSupported()
void setWrapMode(GLenum mode)
static bool supportsSwizzle()
static bool s_supportsTexture16Bit
static bool s_supportsTextureFormatRG
static bool s_supportsARGB32
static bool s_supportsTextureSwizzle
static bool s_supportsTextureStorage
static bool s_supportsFramebufferObjects
virtual ~GLTexturePrivate()
static bool s_supportsUnpack
OutputTransform m_textureToBufferTransform
@ Static
No changes to data.
KWIN_EXPORT QRect infiniteRegion()
bool hasGLVersion(int major, int minor, int release)
struct KWin::@10 formatTable[]
bool hasGLExtension(const QByteArray &extension)
@ UnnormalizedCoordinates