~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/opengl/texture.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2005 Novell, Inc.
3
 
 *
4
 
 * Permission to use, copy, modify, distribute, and sell this software
5
 
 * and its documentation for any purpose is hereby granted without
6
 
 * fee, provided that the above copyright notice appear in all copies
7
 
 * and that both that copyright notice and this permission notice
8
 
 * appear in supporting documentation, and that the name of
9
 
 * Novell, Inc. not be used in advertising or publicity pertaining to
10
 
 * distribution of the software without specific, written prior permission.
11
 
 * Novell, Inc. makes no representations about the suitability of this
12
 
 * software for any purpose. It is provided "as is" without express or
13
 
 * implied warranty.
14
 
 *
15
 
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17
 
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18
 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19
 
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20
 
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21
 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 
 *
23
 
 * Author: David Reveman <davidr@novell.com>
24
 
 */
25
 
 
26
 
#ifdef HAVE_CONFIG_H
27
 
#  include <config.h>
28
 
#endif
29
 
 
30
 
#include <compiz.h>
31
 
 
32
 
#include <stdio.h>
33
 
#include <stdlib.h>
34
 
#include <string.h>
35
 
 
36
 
#include <core/core.h>
37
 
#include <opengl/texture.h>
38
 
#include <privatetexture.h>
39
 
#include "privates.h"
40
 
 
41
 
std::map<Damage, TfpTexture*> boundPixmapTex;
42
 
 
43
 
static GLTexture::Matrix _identity_matrix = {
44
 
    1.0f, 0.0f,
45
 
    0.0f, 1.0f,
46
 
    0.0f, 0.0f
47
 
};
48
 
 
49
 
GLTexture::List::List () :
50
 
    std::vector<GLTexture *> (0)
51
 
{
52
 
}
53
 
 
54
 
GLTexture::List::List (unsigned int size) :
55
 
    std::vector<GLTexture *> (size)
56
 
{
57
 
    for (unsigned int i = 0; i < size; i++)
58
 
        at (i) = NULL;
59
 
}
60
 
 
61
 
GLTexture::List::List (const GLTexture::List &c)
62
 
{
63
 
    resize (c.size ());
64
 
    for (unsigned int i = 0; i < c.size (); i++)
65
 
    {
66
 
        at (i) = c[i];
67
 
        GLTexture::incRef (c[i]);
68
 
    }
69
 
}
70
 
 
71
 
GLTexture::List::~List ()
72
 
{
73
 
    foreach (GLTexture *t, *this)
74
 
        GLTexture::decRef (t);
75
 
}
76
 
 
77
 
GLTexture::List &
78
 
GLTexture::List::operator= (const GLTexture::List &c)
79
 
{
80
 
    this->clear ();
81
 
    resize (c.size ());
82
 
    for (unsigned int i = 0; i < c.size (); i++)
83
 
    {
84
 
        at (i) = c[i];
85
 
        GLTexture::incRef (c[i]);
86
 
    }
87
 
    return *this;
88
 
}
89
 
 
90
 
void
91
 
GLTexture::List::clear ()
92
 
{
93
 
    foreach (GLTexture *t, *this)
94
 
        GLTexture::decRef (t);
95
 
    std::vector <GLTexture *>::clear ();
96
 
}
97
 
 
98
 
GLTexture::GLTexture () :
99
 
    CompRect (0, 0, 0, 0),
100
 
    priv (new PrivateTexture (this))
101
 
{
102
 
}
103
 
 
104
 
GLTexture::~GLTexture ()
105
 
{
106
 
    if (priv)
107
 
        delete priv;
108
 
}
109
 
 
110
 
PrivateTexture::PrivateTexture (GLTexture *texture) :
111
 
    texture (texture),
112
 
    name (0),
113
 
    target (GL_TEXTURE_2D),
114
 
    filter (GL_NEAREST),
115
 
    wrap   (GL_CLAMP_TO_EDGE),
116
 
    matrix (_identity_matrix),
117
 
    mipmap  (true),
118
 
    mipmapSupport (false),
119
 
    initial (true),
120
 
    refCount (1)
121
 
{
122
 
    glGenTextures (1, &name);
123
 
}
124
 
 
125
 
PrivateTexture::~PrivateTexture ()
126
 
{
127
 
    if (name)
128
 
    {
129
 
        glDeleteTextures (1, &name);
130
 
    }
131
 
}
132
 
 
133
 
GLuint
134
 
GLTexture::name () const
135
 
{
136
 
    return priv->name;
137
 
}
138
 
 
139
 
GLenum
140
 
GLTexture::target () const
141
 
{
142
 
    return priv->target;
143
 
}
144
 
 
145
 
const GLTexture::Matrix &
146
 
GLTexture::matrix () const
147
 
{
148
 
    return priv->matrix;
149
 
}
150
 
 
151
 
bool
152
 
GLTexture::mipmap () const
153
 
{
154
 
    return priv->mipmap & priv->mipmapSupport;
155
 
}
156
 
 
157
 
GLenum
158
 
GLTexture::filter () const
159
 
{
160
 
    return priv->filter;
161
 
}
162
 
 
163
 
void
164
 
GLTexture::enable (GLTexture::Filter filter)
165
 
{
166
 
    GLScreen *gs = GLScreen::get (screen);
167
 
    glEnable (priv->target);
168
 
    glBindTexture (priv->target, priv->name);
169
 
 
170
 
    if (filter == Fast)
171
 
    {
172
 
        if (priv->filter != GL_NEAREST)
173
 
        {
174
 
            glTexParameteri (priv->target,
175
 
                             GL_TEXTURE_MIN_FILTER,
176
 
                             GL_NEAREST);
177
 
            glTexParameteri (priv->target,
178
 
                             GL_TEXTURE_MAG_FILTER,
179
 
                             GL_NEAREST);
180
 
 
181
 
            priv->filter = GL_NEAREST;
182
 
        }
183
 
    }
184
 
    else if (priv->filter != gs->textureFilter ())
185
 
    {
186
 
        if (gs->textureFilter () == GL_LINEAR_MIPMAP_LINEAR)
187
 
        {
188
 
            if (GL::textureNonPowerOfTwo && GL::fbo && priv->mipmap)
189
 
            {
190
 
                glTexParameteri (priv->target,
191
 
                                 GL_TEXTURE_MIN_FILTER,
192
 
                                 GL_LINEAR_MIPMAP_LINEAR);
193
 
 
194
 
                if (priv->filter != GL_LINEAR)
195
 
                    glTexParameteri (priv->target,
196
 
                                     GL_TEXTURE_MAG_FILTER,
197
 
                                     GL_LINEAR);
198
 
 
199
 
                priv->filter = GL_LINEAR_MIPMAP_LINEAR;
200
 
            }
201
 
            else if (priv->filter != GL_LINEAR)
202
 
            {
203
 
                glTexParameteri (priv->target,
204
 
                                 GL_TEXTURE_MIN_FILTER,
205
 
                                 GL_LINEAR);
206
 
                glTexParameteri (priv->target,
207
 
                                 GL_TEXTURE_MAG_FILTER,
208
 
                                 GL_LINEAR);
209
 
 
210
 
                priv->filter = GL_LINEAR;
211
 
            }
212
 
        }
213
 
        else
214
 
        {
215
 
            glTexParameteri (priv->target,
216
 
                             GL_TEXTURE_MIN_FILTER,
217
 
                             gs->textureFilter ());
218
 
            glTexParameteri (priv->target,
219
 
                             GL_TEXTURE_MAG_FILTER,
220
 
                             gs->textureFilter ());
221
 
 
222
 
            priv->filter = gs->textureFilter ();
223
 
        }
224
 
    }
225
 
 
226
 
    if (priv->filter == GL_LINEAR_MIPMAP_LINEAR)
227
 
    {
228
 
        if (priv->initial)
229
 
        {
230
 
            (*GL::generateMipmap) (priv->target);
231
 
            priv->initial = false;
232
 
        }
233
 
    }
234
 
}
235
 
 
236
 
void
237
 
GLTexture::disable ()
238
 
{
239
 
    glBindTexture (priv->target, 0);
240
 
    glDisable (priv->target);
241
 
}
242
 
 
243
 
void
244
 
GLTexture::setData (GLenum target, Matrix &m, bool mipmap)
245
 
{
246
 
    priv->target = target;
247
 
    priv->matrix = m;
248
 
    priv->mipmapSupport = mipmap;
249
 
}
250
 
 
251
 
void
252
 
GLTexture::setMipmap (bool enable)
253
 
{
254
 
    priv->mipmap = enable;
255
 
}
256
 
 
257
 
void
258
 
GLTexture::setFilter (GLenum filter)
259
 
{
260
 
    glBindTexture (priv->target, priv->name);
261
 
 
262
 
    priv->filter = filter;
263
 
 
264
 
    glTexParameteri (priv->target, GL_TEXTURE_MIN_FILTER, filter);
265
 
    glTexParameteri (priv->target, GL_TEXTURE_MAG_FILTER, filter);
266
 
 
267
 
    glBindTexture (priv->target, 0);
268
 
}
269
 
 
270
 
void
271
 
GLTexture::setWrap (GLenum wrap)
272
 
{
273
 
    glBindTexture (priv->target, priv->name);
274
 
 
275
 
    priv->wrap = GL_CLAMP_TO_EDGE;
276
 
 
277
 
    glTexParameteri (priv->target, GL_TEXTURE_WRAP_S, wrap);
278
 
    glTexParameteri (priv->target, GL_TEXTURE_WRAP_T, wrap);
279
 
 
280
 
    glBindTexture (priv->target, 0);
281
 
}
282
 
 
283
 
GLTexture::List
284
 
PrivateTexture::loadImageData (const char   *image,
285
 
                               unsigned int width,
286
 
                               unsigned int height,
287
 
                               GLenum       format,
288
 
                               GLenum       type)
289
 
{
290
 
#warning Add support for multiple textures
291
 
    if ((int) width > GL::maxTextureSize || (int) height > GL::maxTextureSize)
292
 
        return GLTexture::List ();
293
 
 
294
 
    GLTexture::List rv (1);
295
 
    GLTexture *t = new GLTexture ();
296
 
    rv[0] = t;
297
 
 
298
 
    GLTexture::Matrix matrix = _identity_matrix;
299
 
    GLint             internalFormat;
300
 
    GLenum            target;
301
 
    bool              mipmap;
302
 
 
303
 
 
304
 
    if (GL::textureNonPowerOfTwo ||
305
 
        (POWER_OF_TWO (width) && POWER_OF_TWO (height)))
306
 
    {
307
 
        target = GL_TEXTURE_2D;
308
 
        matrix.xx = 1.0f / width;
309
 
        matrix.yy = 1.0f / height;
310
 
        matrix.y0 = 0.0f;
311
 
        mipmap = true;
312
 
    }
313
 
    else
314
 
    {
315
 
        target = GL_TEXTURE_RECTANGLE_NV;
316
 
        matrix.xx = 1.0f;
317
 
        matrix.yy = 1.0f;
318
 
        matrix.y0 = 0.0f;
319
 
        mipmap = false;
320
 
    }
321
 
 
322
 
    t->setData (target, matrix, mipmap);
323
 
    t->setGeometry (0, 0, width, height);
324
 
 
325
 
    glBindTexture (target, t->name ());
326
 
 
327
 
    internalFormat =
328
 
        (GLScreen::get(screen)->getOption ("texture_compression")->value ().b ()
329
 
        && GL::textureCompression ? GL_COMPRESSED_RGBA_ARB : GL_RGBA);
330
 
 
331
 
    glTexImage2D (target, 0, internalFormat, width, height, 0,
332
 
                  format, type, image);
333
 
 
334
 
    t->setFilter (GL_NEAREST);
335
 
    t->setWrap (GL_CLAMP_TO_EDGE);
336
 
 
337
 
    return rv;
338
 
}
339
 
 
340
 
GLTexture::List
341
 
GLTexture::imageBufferToTexture (const char *image,
342
 
                                 CompSize   size)
343
 
{
344
 
#if IMAGE_BYTE_ORDER == MSBFirst
345
 
    return PrivateTexture::loadImageData (image, size.width (), size.height (),
346
 
                                          GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
347
 
#else
348
 
    return PrivateTexture::loadImageData (image, size.width (), size.height (),
349
 
                                          GL_BGRA, GL_UNSIGNED_BYTE);
350
 
#endif
351
 
}
352
 
 
353
 
GLTexture::List
354
 
GLTexture::imageDataToTexture (const char *image,
355
 
                               CompSize   size,
356
 
                               GLenum     format,
357
 
                               GLenum     type)
358
 
{
359
 
    return PrivateTexture::loadImageData (image, size.width (), size.height (),
360
 
                                          format, type);
361
 
}
362
 
 
363
 
 
364
 
GLTexture::List
365
 
GLTexture::readImageToTexture (CompString &imageFileName,
366
 
                               CompSize   &size)
367
 
{
368
 
    void *image = NULL;
369
 
 
370
 
    if (!screen->readImageFromFile (imageFileName, size, image) || !image)
371
 
        return GLTexture::List ();
372
 
 
373
 
    GLTexture::List rv =
374
 
        GLTexture::imageBufferToTexture ((char *)image, size);
375
 
 
376
 
    free (image);
377
 
 
378
 
    return rv;
379
 
}
380
 
 
381
 
void
382
 
GLTexture::decRef (GLTexture *tex)
383
 
{
384
 
    tex->priv->refCount--;
385
 
    if (tex->priv->refCount <= 0)
386
 
        delete tex;
387
 
}
388
 
 
389
 
void
390
 
GLTexture::incRef (GLTexture *tex)
391
 
{
392
 
    tex->priv->refCount++;
393
 
}
394
 
 
395
 
GLTexture::List
396
 
GLTexture::bindPixmapToTexture (Pixmap pixmap,
397
 
                                int    width,
398
 
                                int    height,
399
 
                                int    depth)
400
 
{
401
 
    GLTexture::List rv;
402
 
 
403
 
    foreach (BindPixmapProc &proc, GLScreen::get (screen)->priv->bindPixmap)
404
 
    {
405
 
        if (!proc.empty ())
406
 
            rv = proc (pixmap, width, height, depth);
407
 
        if (rv.size ())
408
 
            return rv;
409
 
    }
410
 
    return GLTexture::List ();
411
 
}
412
 
 
413
 
TfpTexture::TfpTexture () :
414
 
    pixmap (0),
415
 
    damaged (true),
416
 
    damage (None)
417
 
{
418
 
}
419
 
 
420
 
TfpTexture::~TfpTexture ()
421
 
{
422
 
    if (pixmap)
423
 
    {
424
 
        glEnable (target ());
425
 
 
426
 
        glBindTexture (target (), name ());
427
 
 
428
 
        (*GL::releaseTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT);
429
 
 
430
 
        glBindTexture (target (), 0);
431
 
        glDisable (target ());
432
 
 
433
 
        glXDestroyGLXPixmap (screen->dpy (), pixmap);
434
 
 
435
 
        boundPixmapTex.erase (damage);
436
 
        XDamageDestroy (screen->dpy (), damage);
437
 
    }
438
 
}
439
 
 
440
 
GLTexture::List
441
 
TfpTexture::bindPixmapToTexture (Pixmap pixmap,
442
 
                                 int    width,
443
 
                                 int    height,
444
 
                                 int    depth)
445
 
{
446
 
    if ((int) width > GL::maxTextureSize || (int) height > GL::maxTextureSize ||
447
 
        !GL::textureFromPixmap)
448
 
        return GLTexture::List ();
449
 
 
450
 
    GLTexture::List   rv (1);
451
 
    TfpTexture        *tex = NULL;
452
 
    unsigned int      target = 0;
453
 
    GLenum            texTarget = GL_TEXTURE_2D;
454
 
    GLXPixmap         glxPixmap = None;
455
 
    GLTexture::Matrix matrix = _identity_matrix;
456
 
    bool              mipmap = false;
457
 
    GLFBConfig        *config =
458
 
        GLScreen::get (screen)->glxPixmapFBConfig (depth);
459
 
    int               attribs[7], i = 0;
460
 
 
461
 
    if (!config->fbConfig)
462
 
    {
463
 
        compLogMessage ("core", CompLogLevelWarn,
464
 
                        "No GLXFBConfig for depth %d",
465
 
                        depth);
466
 
 
467
 
        return GLTexture::List ();
468
 
    }
469
 
 
470
 
    attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
471
 
    attribs[i++] = config->textureFormat;
472
 
    attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
473
 
    attribs[i++] = config->mipmap;
474
 
 
475
 
    /* If no texture target is specified in the fbconfig, or only the
476
 
       TEXTURE_2D target is specified and GL_texture_non_power_of_two
477
 
       is not supported, then allow the server to choose the texture target. */
478
 
    if (config->textureTargets & GLX_TEXTURE_2D_BIT_EXT &&
479
 
       (GL::textureNonPowerOfTwo ||
480
 
       (POWER_OF_TWO (width) && POWER_OF_TWO (height))))
481
 
        target = GLX_TEXTURE_2D_EXT;
482
 
    else if (config->textureTargets & GLX_TEXTURE_RECTANGLE_BIT_EXT)
483
 
        target = GLX_TEXTURE_RECTANGLE_EXT;
484
 
 
485
 
    /* Workaround for broken texture from pixmap implementations, 
486
 
       that don't advertise any texture target in the fbconfig. */
487
 
    if (!target)
488
 
    {
489
 
        if (!(config->textureTargets & GLX_TEXTURE_2D_BIT_EXT))
490
 
            target = GLX_TEXTURE_RECTANGLE_EXT;
491
 
        else if (!(config->textureTargets & GLX_TEXTURE_RECTANGLE_BIT_EXT))
492
 
            target = GLX_TEXTURE_2D_EXT;
493
 
    }
494
 
 
495
 
    if (target)
496
 
    {
497
 
        attribs[i++] = GLX_TEXTURE_TARGET_EXT;
498
 
        attribs[i++] = target;
499
 
    }
500
 
 
501
 
    attribs[i++] = None;
502
 
 
503
 
    glxPixmap = (*GL::createPixmap) (screen->dpy (), config->fbConfig,
504
 
                                     pixmap, attribs);
505
 
 
506
 
    if (!glxPixmap)
507
 
    {
508
 
        compLogMessage ("core", CompLogLevelWarn,
509
 
                        "glXCreatePixmap failed");
510
 
 
511
 
        return GLTexture::List ();
512
 
    }
513
 
 
514
 
    if (!target)
515
 
        (*GL::queryDrawable) (screen->dpy (), glxPixmap,
516
 
                              GLX_TEXTURE_TARGET_EXT, &target);
517
 
 
518
 
    switch (target) {
519
 
        case GLX_TEXTURE_2D_EXT:
520
 
            texTarget = GL_TEXTURE_2D;
521
 
 
522
 
            matrix.xx = 1.0f / width;
523
 
            if (config->yInverted)
524
 
            {
525
 
                matrix.yy = 1.0f / height;
526
 
                matrix.y0 = 0.0f;
527
 
            }
528
 
            else
529
 
            {
530
 
                matrix.yy = -1.0f / height;
531
 
                matrix.y0 = 1.0f;
532
 
            }
533
 
            mipmap = config->mipmap;
534
 
            break;
535
 
        case GLX_TEXTURE_RECTANGLE_EXT:
536
 
            texTarget = GL_TEXTURE_RECTANGLE_ARB;
537
 
 
538
 
            matrix.xx = 1.0f;
539
 
            if (config->yInverted)
540
 
            {
541
 
                matrix.yy = 1.0f;
542
 
                matrix.y0 = 0;
543
 
            }
544
 
            else
545
 
            {
546
 
                matrix.yy = -1.0f;
547
 
                matrix.y0 = height;
548
 
            }
549
 
            mipmap = false;
550
 
            break;
551
 
        default:
552
 
            compLogMessage ("core", CompLogLevelWarn,
553
 
                            "pixmap 0x%x can't be bound to texture",
554
 
                            (int) pixmap);
555
 
 
556
 
            glXDestroyGLXPixmap (screen->dpy (), glxPixmap);
557
 
            glxPixmap = None;
558
 
 
559
 
            return GLTexture::List ();
560
 
    }
561
 
 
562
 
    tex = new TfpTexture ();
563
 
    tex->setData (texTarget, matrix, mipmap);
564
 
    tex->setGeometry (0, 0, width, height);
565
 
    tex->pixmap = glxPixmap;
566
 
 
567
 
    rv[0] = tex;
568
 
 
569
 
    glBindTexture (texTarget, tex->name ());
570
 
 
571
 
 
572
 
    (*GL::bindTexImage) (screen->dpy (), glxPixmap, GLX_FRONT_LEFT_EXT, NULL);
573
 
 
574
 
    tex->setFilter (GL_NEAREST);
575
 
    tex->setWrap (GL_CLAMP_TO_EDGE);
576
 
 
577
 
    glBindTexture (texTarget, 0);
578
 
 
579
 
    tex->damage = XDamageCreate (screen->dpy (), pixmap,
580
 
                                 XDamageReportRawRectangles);
581
 
    boundPixmapTex[tex->damage] = tex;
582
 
 
583
 
    return rv;
584
 
}
585
 
 
586
 
void
587
 
TfpTexture::enable (GLTexture::Filter filter)
588
 
{
589
 
    glEnable (target ());
590
 
    glBindTexture (target (), name ());
591
 
 
592
 
    if (damaged && pixmap)
593
 
    {
594
 
        (*GL::releaseTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT);
595
 
        (*GL::bindTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT, NULL);
596
 
    }
597
 
 
598
 
    GLTexture::enable (filter);
599
 
 
600
 
    if (this->filter () == GL_LINEAR_MIPMAP_LINEAR)
601
 
    {
602
 
        if (damaged)
603
 
        {
604
 
            (*GL::generateMipmap) (target ());
605
 
        }
606
 
    }
607
 
    damaged = false;
608
 
}