~compiz-team/compiz/0.9.11

« back to all changes in this revision

Viewing changes to plugins/opengl/src/screen.cpp

  • Committer: CI Train Bot
  • Author(s): Stephen M. Webb
  • Date: 2015-01-22 14:51:41 UTC
  • mfrom: (3869.1.2 lp-269904-trusty)
  • Revision ID: ci-train-bot@canonical.com-20150122145141-m6fpm6djd2s54try
Use the GL_EXT_x11_sync_object OpenGL extension to synchronize updates with X11 to avoid unrefreshed parts of the screen on Nvidia hardware. Fixes: #269904
Approved by: Christopher Townsend

Show diffs side-by-side

added added

removed removed

Lines of Context:
68
68
 
69
69
using namespace compiz::opengl;
70
70
 
 
71
/**
 
72
 * The number of X11 sync objects to create.
 
73
 */
 
74
static const size_t NUM_X11_SYNCS = 16;
 
75
 
 
76
/**
 
77
 * The maximum time to wait for a sync object, in nanoseconds.
 
78
 */
 
79
static const GLuint64 MAX_SYNC_WAIT_TIME = 1000000000ull; // One second
 
80
 
71
81
namespace GL {
72
82
    #ifdef USE_GLES
73
83
    EGLCreateImageKHRProc  createImage;
170
180
    GLBindRenderbufferProc bindRenderbuffer = NULL;
171
181
    GLRenderbufferStorageProc renderbufferStorage = NULL;
172
182
 
 
183
    GLFenceSyncProc      fenceSync = NULL;
 
184
    GLDeleteSyncProc     deleteSync = NULL;
 
185
    GLClientWaitSyncProc clientWaitSync = NULL;
 
186
    GLWaitSyncProc       waitSync = NULL;
 
187
    GLGetSyncivProc      getSynciv = NULL;
 
188
 
 
189
    GLImportSyncProc importSync = NULL;
 
190
 
173
191
    bool  textureFromPixmap = true;
174
192
    bool  textureRectangle = false;
175
193
    bool  textureNonPowerOfTwo = false;
188
206
    GLint maxTextureUnits = 1;
189
207
    bool  bufferAge = false;
190
208
 
 
209
    bool sync = false;
 
210
    bool xToGLSync = false;
 
211
 
191
212
    bool canDoSaturated = false;
192
213
    bool canDoSlightlySaturated = false;
193
214
 
1054
1075
    if (strstr (glExtensions, "GL_ARB_texture_compression"))
1055
1076
        GL::textureCompression = true;
1056
1077
 
 
1078
    if (strstr (glExtensions, "GL_ARB_sync"))
 
1079
    {
 
1080
        GL::fenceSync = (GL::GLFenceSyncProc)
 
1081
            getProcAddress ("glFenceSync");
 
1082
        GL::deleteSync = (GL::GLDeleteSyncProc)
 
1083
            getProcAddress ("glDeleteSync");
 
1084
        GL::clientWaitSync = (GL::GLClientWaitSyncProc)
 
1085
            getProcAddress ("glClientWaitSync");
 
1086
        GL::waitSync = (GL::GLWaitSyncProc)
 
1087
            getProcAddress ("glWaitSync");
 
1088
        GL::getSynciv = (GL::GLGetSyncivProc)
 
1089
            getProcAddress ("glGetSynciv");
 
1090
 
 
1091
        if (GL::fenceSync      &&
 
1092
            GL::deleteSync     &&
 
1093
            GL::clientWaitSync &&
 
1094
            GL::waitSync       &&
 
1095
            GL::getSynciv)
 
1096
            GL::sync = true;
 
1097
    }
 
1098
 
 
1099
    if (strstr (glExtensions, "GL_EXT_x11_sync_object"))
 
1100
    {
 
1101
        GL::importSync = (GL::GLImportSyncProc)
 
1102
            getProcAddress ("glImportSyncEXT");
 
1103
 
 
1104
        if (GL::importSync)
 
1105
            GL::xToGLSync = true;
 
1106
    }
 
1107
 
1057
1108
    glClearColor (0.0, 0.0, 0.0, 1.0);
1058
1109
    glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1059
1110
    glEnable (GL_CULL_FACE);
1257
1308
            getProcAddress ("glXSwapIntervalSGI");
1258
1309
    }
1259
1310
 
 
1311
    priv->initXToGLSyncs ();
 
1312
 
1260
1313
    fbConfigs = (*GL::getFBConfigs) (dpy, s->screenNum (), &nElements);
1261
1314
 
1262
1315
    GL::stencilBuffer = false;
1411
1464
 
1412
1465
GLScreen::~GLScreen ()
1413
1466
{
 
1467
    // Must occur before context is destroyed.
 
1468
    priv->destroyXToGLSyncs ();
 
1469
 
1414
1470
    if (priv->hasCompositing)
1415
1471
        CompositeScreen::get (screen)->unregisterPaintHandler ();
1416
1472
 
1471
1527
    glVersion (NULL),
1472
1528
    postprocessingRequired (false),
1473
1529
    prevRegex (),
1474
 
    prevBlacklisted (false)
 
1530
    prevBlacklisted (false),
 
1531
    currentSyncNum (0),
 
1532
    currentSync (0),
 
1533
    warmupSyncs (0)
1475
1534
{
1476
1535
    ScreenInterface::setHandler (screen);
1477
1536
    CompositeScreenInterface::setHandler (cScreen);
1563
1622
                 * be recopying the root window pixmap all the time
1564
1623
                 * which is no good, so don't do that */
1565
1624
            }
 
1625
            else if (event->type == screen->syncEvent () + XSyncAlarmNotify)
 
1626
            {
 
1627
                XSyncAlarmNotifyEvent *ae =
 
1628
                    reinterpret_cast<XSyncAlarmNotifyEvent*>(event);
 
1629
                std::map<XSyncAlarm, XToGLSync*>::iterator it =
 
1630
                    alarmToSync.find (ae->alarm);
 
1631
 
 
1632
                if (it != alarmToSync.end ())
 
1633
                    it->second->handleEvent (ae);
 
1634
            }
1566
1635
            break;
1567
1636
    }
1568
1637
}
2026
2095
{
2027
2096
}
2028
2097
 
 
2098
bool
 
2099
PrivateGLScreen::syncObjectsInitialized () const
 
2100
{
 
2101
    return !xToGLSyncs.empty ();
 
2102
}
 
2103
 
 
2104
bool
 
2105
PrivateGLScreen::syncObjectsEnabled ()
 
2106
{
 
2107
    return GL::sync && GL::xToGLSync && optionGetEnableX11Sync ();
 
2108
}
 
2109
 
 
2110
void
 
2111
PrivateGLScreen::initXToGLSyncs ()
 
2112
{
 
2113
    assert (!syncObjectsInitialized ());
 
2114
    assert (xToGLSyncs.empty ());
 
2115
    assert (alarmToSync.empty ());
 
2116
 
 
2117
    if (syncObjectsEnabled () && !syncObjectsInitialized ())
 
2118
    {
 
2119
        xToGLSyncs.resize (NUM_X11_SYNCS, NULL);
 
2120
 
 
2121
        foreach (XToGLSync*& sync, xToGLSyncs)
 
2122
        {
 
2123
            sync = new XToGLSync ();
 
2124
            alarmToSync[sync->alarm ()] = sync;
 
2125
        }
 
2126
 
 
2127
        currentSyncNum = 0;
 
2128
        currentSync = xToGLSyncs[0];
 
2129
        warmupSyncs = 0;
 
2130
    }
 
2131
}
 
2132
 
 
2133
void
 
2134
PrivateGLScreen::destroyXToGLSyncs ()
 
2135
{
 
2136
    if (syncObjectsInitialized ())
 
2137
    {
 
2138
        foreach (XToGLSync* sync, xToGLSyncs)
 
2139
            delete sync;
 
2140
        xToGLSyncs.resize (0);
 
2141
    }
 
2142
    alarmToSync.clear ();
 
2143
    currentSyncNum = 0;
 
2144
    currentSync = NULL;
 
2145
    warmupSyncs = 0;
 
2146
}
 
2147
 
 
2148
void
 
2149
PrivateGLScreen::updateXToGLSyncs ()
 
2150
{
 
2151
    const std::vector<XToGLSync*>::size_type numSyncs = xToGLSyncs.size ();
 
2152
 
 
2153
    if (numSyncs)
 
2154
    {
 
2155
        if (warmupSyncs >= numSyncs / 2)
 
2156
        {
 
2157
            const std::vector<XToGLSync*>::size_type resetSyncIdx =
 
2158
                (currentSyncNum + (numSyncs / 2)) % numSyncs;
 
2159
 
 
2160
            XToGLSync* syncToReset = xToGLSyncs[resetSyncIdx];
 
2161
 
 
2162
            GLenum status = syncToReset->checkUpdateFinished (0);
 
2163
            if (status == GL_TIMEOUT_EXPIRED)
 
2164
            {
 
2165
                status = syncToReset->checkUpdateFinished (MAX_SYNC_WAIT_TIME);
 
2166
            }
 
2167
 
 
2168
            if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
 
2169
            {
 
2170
                // This should never happen. If there was an error somewhere,
 
2171
                // then we don't want to risk a hang here, so just destroy the
 
2172
                // sync objects. We'll recreate them again in the next call to
 
2173
                // prepareDrawing.
 
2174
                compLogMessage ("opengl", CompLogLevelError, "Timed out waiting for sync object.");
 
2175
                destroyXToGLSyncs ();
 
2176
                return;
 
2177
            }
 
2178
 
 
2179
            syncToReset->reset ();
 
2180
        }
 
2181
        else
 
2182
        {
 
2183
            warmupSyncs++;
 
2184
        }
 
2185
 
 
2186
        currentSyncNum++;
 
2187
        currentSyncNum %= numSyncs;
 
2188
 
 
2189
        currentSync = xToGLSyncs[currentSyncNum];
 
2190
    }
 
2191
}
 
2192
 
2029
2193
#ifndef USE_GLES
2030
2194
 
2031
2195
void
2199
2363
            glClear (GL_COLOR_BUFFER_BIT);
2200
2364
    }
2201
2365
 
 
2366
    if (currentSync)
 
2367
        currentSync->insertWait ();
 
2368
 
2202
2369
    // Disable everything that we don't usually need and could slow us down
2203
2370
    glDisable (GL_BLEND);
2204
2371
    glDisable (GL_STENCIL_TEST);
2352
2519
    doubleBuffer.render (paintRegion, fullscreen);
2353
2520
 
2354
2521
    lastMask = mask;
 
2522
 
 
2523
    updateXToGLSyncs ();
2355
2524
}
2356
2525
 
2357
2526
unsigned int
2448
2617
        updateFrameProvider ();
2449
2618
        CompositeScreen::get (screen)->damageScreen ();
2450
2619
    }
 
2620
 
 
2621
    // Check if the option to use sync objects has been enabled or disabled.
 
2622
    if (syncObjectsEnabled () && !syncObjectsInitialized ())
 
2623
    {
 
2624
        initXToGLSyncs ();
 
2625
    }
 
2626
    else if (!syncObjectsEnabled () && syncObjectsInitialized ())
 
2627
    {
 
2628
        destroyXToGLSyncs ();
 
2629
    }
 
2630
 
 
2631
    if (currentSync)
 
2632
    {
 
2633
        if (!currentSync->isReady ())
 
2634
        {
 
2635
            for (std::vector<XToGLSync*>::size_type i = xToGLSyncs.size () / 2; i > 0; i--)
 
2636
            {
 
2637
                // try to check next sync
 
2638
                updateXToGLSyncs ();
 
2639
 
 
2640
                // method updateXToGLSync may disable syncs
 
2641
                if (!currentSync)
 
2642
                    break;
 
2643
 
 
2644
                if (currentSync->isReady ())
 
2645
                    break;
 
2646
            }
 
2647
        }
 
2648
    }
 
2649
 
 
2650
    if (currentSync)
 
2651
    {
 
2652
        if (!currentSync->isReady ())
 
2653
        {
 
2654
            // If this happens, then we must have missed an event or update
 
2655
            // somewhere. Destroy and recreate the sync objects to put us back
 
2656
            // into a good state.
 
2657
            destroyXToGLSyncs ();
 
2658
            initXToGLSyncs ();
 
2659
        }
 
2660
    }
 
2661
 
 
2662
    if (currentSync)
 
2663
    {
 
2664
        // Tell the server to trigger the fence object after all rendering has
 
2665
        // completed.
 
2666
        assert (currentSync->isReady ());
 
2667
        currentSync->trigger ();
 
2668
    }
2451
2669
}
2452
2670
 
2453
2671
bool