Changeset 59682 in webkit


Ignore:
Timestamp:
May 18, 2010 12:32:46 PM (14 years ago)
Author:
Adam Roben
Message:

Fix a crash when a page that uses accelerated compositing loads soon after the computer wakes from sleep

The set-up:

For a short time after waking from sleep, IDirect3D9::CreateDevice
will fail. This caused WKCACFLayerRenderer::createRenderer to fail,
and meant that WKCACFLayerRenderer never allocated a root layer.
WebView wouldn't notice that createRenderer failed, and would go ahead
and try to use the root layer anyway, resulting in a crash.

The fix:

We now allocate the root layer (and all the other members of
WKCACFLayerRenderer that aren't dependent on having an
IDirect3DDevice9) in WKCACFLayerRenderer's constructor. This way the
layers will always be present, even when creating the D3D device
fails.

There are two remaining problems:

1) This results in slightly more memory usage in the case where

CreateDevice fails.

2) Once we get into this bad state, the WebView doesn't repaint

until we navigate somewhere else.

(2) is covered by
<http://webkit.org/b/39297>/<rdar://problem/7997431>. We'll fix it by
retrying CreateDevice later in hopes that it will succeed after more
time has passed. This will in turn fix (1). (We should never end up in
a case where CreateDevice fails forever because we already did some
preliminary checks in acceleratedCompositingAvailable().)

Fixes <http://webkit.org/b/39295> <rdar://problem/7971319> Crash
(preceded by assertion) in WKCACFLayerRenderer::setNeedsDisplay when
computer wakes from sleep on particular page

Reviewed by John Sullivan.

  • manual-tests/crash-after-wake-from-sleep.html: Added. This

is the Poster Circle demo from webkit.org/blog, but modified to
automatically reload every 5 seconds and with instructions to put the
computer to sleep and wake it up again.

  • platform/graphics/win/WKCACFLayerRenderer.cpp:

(WebCore::WKCACFLayerRenderer::WKCACFLayerRenderer): Moved code to
initialize m_context, m_renderContext, and m_*Layer here...
(WebCore::WKCACFLayerRenderer::createRenderer): ...from here.

Location:
trunk/WebCore
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r59681 r59682  
     12010-05-18  Adam Roben  <aroben@apple.com>
     2
     3        Fix a crash when a page that uses accelerated compositing loads soon
     4        after the computer wakes from sleep
     5
     6        The set-up:
     7
     8        For a short time after waking from sleep, IDirect3D9::CreateDevice
     9        will fail. This caused WKCACFLayerRenderer::createRenderer to fail,
     10        and meant that WKCACFLayerRenderer never allocated a root layer.
     11        WebView wouldn't notice that createRenderer failed, and would go ahead
     12        and try to use the root layer anyway, resulting in a crash.
     13
     14        The fix:
     15
     16        We now allocate the root layer (and all the other members of
     17        WKCACFLayerRenderer that aren't dependent on having an
     18        IDirect3DDevice9) in WKCACFLayerRenderer's constructor. This way the
     19        layers will always be present, even when creating the D3D device
     20        fails.
     21
     22        There are two remaining problems:
     23          1) This results in slightly more memory usage in the case where
     24             CreateDevice fails.
     25          2) Once we get into this bad state, the WebView doesn't repaint
     26             until we navigate somewhere else.
     27
     28        (2) is covered by
     29        <http://webkit.org/b/39297>/<rdar://problem/7997431>. We'll fix it by
     30        retrying CreateDevice later in hopes that it will succeed after more
     31        time has passed. This will in turn fix (1). (We should never end up in
     32        a case where CreateDevice fails forever because we already did some
     33        preliminary checks in acceleratedCompositingAvailable().)
     34
     35        Fixes <http://webkit.org/b/39295> <rdar://problem/7971319> Crash
     36        (preceded by assertion) in WKCACFLayerRenderer::setNeedsDisplay when
     37        computer wakes from sleep on particular page
     38
     39        Reviewed by John Sullivan.
     40
     41        * manual-tests/crash-after-wake-from-sleep.html: Added. This
     42        is the Poster Circle demo from webkit.org/blog, but modified to
     43        automatically reload every 5 seconds and with instructions to put the
     44        computer to sleep and wake it up again.
     45
     46        * platform/graphics/win/WKCACFLayerRenderer.cpp:
     47        (WebCore::WKCACFLayerRenderer::WKCACFLayerRenderer): Moved code to
     48        initialize m_context, m_renderContext, and m_*Layer here...
     49        (WebCore::WKCACFLayerRenderer::createRenderer): ...from here.
     50
    1512010-05-18  Adam Roben  <aroben@apple.com>
    252
  • trunk/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp

    r59610 r59682  
    225225WKCACFLayerRenderer::WKCACFLayerRenderer()
    226226    : m_triedToCreateD3DRenderer(false)
    227     , m_renderContext(0)
     227    , m_rootLayer(WKCACFRootLayer::create(this))
     228    , m_scrollLayer(WKCACFLayer::create(WKCACFLayer::Layer))
     229    , m_clipLayer(WKCACFLayer::create(WKCACFLayer::Layer))
     230    , m_context(AdoptCF, CACFContextCreate(0))
     231    , m_renderContext(static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())))
    228232    , m_renderer(0)
    229233    , m_hostWindow(0)
     
    234238    , m_mustResetLostDeviceBeforeRendering(false)
    235239{
    236 #ifndef NDEBUG
    237     char* printTreeFlag = getenv("CA_PRINT_TREE");
    238     m_printTree = printTreeFlag && atoi(printTreeFlag);
    239 #endif
    240 }
    241 
    242 WKCACFLayerRenderer::~WKCACFLayerRenderer()
    243 {
    244     destroyRenderer();
    245 }
    246 
    247 WKCACFLayer* WKCACFLayerRenderer::rootLayer() const
    248 {
    249     return m_rootLayer.get();
    250 }
    251 
    252 void WKCACFLayerRenderer::setScrollFrame(const IntPoint& position, const IntSize& size)
    253 {
    254     m_scrollSize = size;
    255     m_scrollPosition = position;
    256 
    257     updateScrollFrame();
    258 }
    259 
    260 void WKCACFLayerRenderer::updateScrollFrame()
    261 {
    262     CGRect frameBounds = bounds();
    263     m_clipLayer->setBounds(CGRectMake(0, 0, m_scrollSize.width(), m_scrollSize.height()));
    264     m_clipLayer->setPosition(CGPointMake(0, frameBounds.size.height));
    265     if (m_rootChildLayer) {
    266         CGRect rootBounds = m_rootChildLayer->bounds();
    267         m_scrollLayer->setBounds(rootBounds);
    268     }
    269     m_scrollLayer->setPosition(CGPointMake(-m_scrollPosition.x(), m_scrollPosition.y() + m_scrollSize.height()));
    270 }
    271 
    272 void WKCACFLayerRenderer::setRootContents(CGImageRef image)
    273 {
    274     ASSERT(m_rootLayer);
    275     m_rootLayer->setContents(image);
    276     renderSoon();
    277 }
    278 
    279 void WKCACFLayerRenderer::setRootContentsAndDisplay(CGImageRef image)
    280 {
    281     ASSERT(m_rootLayer);
    282     m_rootLayer->setContents(image);
    283     paint();
    284 }
    285 
    286 void WKCACFLayerRenderer::setRootChildLayer(WKCACFLayer* layer)
    287 {
    288     if (!m_scrollLayer)
    289         return;
    290 
    291     m_scrollLayer->removeAllSublayers();
    292     m_rootChildLayer = layer;
    293     if (layer) {
    294         m_scrollLayer->addSublayer(layer);
    295         // Adjust the scroll frame accordingly
    296         updateScrollFrame();
    297     }
    298 }
    299    
    300 void WKCACFLayerRenderer::setNeedsDisplay()
    301 {
    302     ASSERT(m_rootLayer);
    303     m_rootLayer->setNeedsDisplay(0);
    304     renderSoon();
    305 }
    306 
    307 bool WKCACFLayerRenderer::createRenderer()
    308 {
    309     if (m_triedToCreateD3DRenderer)
    310         return m_d3dDevice;
    311 
    312     m_triedToCreateD3DRenderer = true;
    313     D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
    314 
    315     if (!d3d() || !::IsWindow(m_hostWindow))
    316         return false;
    317 
    318     // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the
    319     // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero
    320     // size eventually, and then the backbuffer size will get reset.
    321     RECT rect;
    322     GetClientRect(m_hostWindow, &rect);
    323 
    324     if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) {
    325         parameters.BackBufferWidth = 1;
    326         parameters.BackBufferHeight = 1;
    327     }
    328 
    329     COMPtr<IDirect3DDevice9> device;
    330     if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &parameters, &device)))
    331         return false;
    332 
    333     // Now that we've created the IDirect3DDevice9 based on the capabilities we
    334     // got from the IDirect3D9 global object, we requery the device for its
    335     // actual capabilities. The capabilities returned by the device can
    336     // sometimes be more complete, for example when using software vertex
    337     // processing.
    338     D3DCAPS9 deviceCaps;
    339     if (FAILED(device->GetDeviceCaps(&deviceCaps)))
    340         return false;
    341 
    342     if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps))
    343         return false;
    344 
    345     m_d3dDevice = device;
    346 
    347     D3DXMATRIXA16 projection;
    348     D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f);
    349 
    350     m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection);
    351 
    352     m_context.adoptCF(CACFContextCreate(0));
    353240    windowsForContexts().set(m_context.get(), this);
    354241
    355     m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get()));
    356     m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0);
    357 
    358     // Create the root hierarchy.
    359242    // Under the root layer, we have a clipping layer to clip the content,
    360243    // that contains a scroll layer that we use for scrolling the content.
     
    366249    // Scrolling will affect only the position of the scroll layer without affecting the bounds.
    367250
    368     m_rootLayer = WKCACFRootLayer::create(this);
    369251    m_rootLayer->setName("WKCACFLayerRenderer rootLayer");
    370 
    371     m_clipLayer = WKCACFLayer::create(WKCACFLayer::Layer);
    372252    m_clipLayer->setName("WKCACFLayerRenderer clipLayer");
    373    
    374     m_scrollLayer = WKCACFLayer::create(WKCACFLayer::Layer);
    375253    m_scrollLayer->setName("WKCACFLayerRenderer scrollLayer");
    376254
     
    387265#endif
    388266
     267    if (m_context)
     268        m_rootLayer->becomeRootLayerForContext(m_context.get());
     269
     270#ifndef NDEBUG
     271    char* printTreeFlag = getenv("CA_PRINT_TREE");
     272    m_printTree = printTreeFlag && atoi(printTreeFlag);
     273#endif
     274}
     275
     276WKCACFLayerRenderer::~WKCACFLayerRenderer()
     277{
     278    destroyRenderer();
     279}
     280
     281WKCACFLayer* WKCACFLayerRenderer::rootLayer() const
     282{
     283    return m_rootLayer.get();
     284}
     285
     286void WKCACFLayerRenderer::setScrollFrame(const IntPoint& position, const IntSize& size)
     287{
     288    m_scrollSize = size;
     289    m_scrollPosition = position;
     290
     291    updateScrollFrame();
     292}
     293
     294void WKCACFLayerRenderer::updateScrollFrame()
     295{
     296    CGRect frameBounds = bounds();
     297    m_clipLayer->setBounds(CGRectMake(0, 0, m_scrollSize.width(), m_scrollSize.height()));
     298    m_clipLayer->setPosition(CGPointMake(0, frameBounds.size.height));
     299    if (m_rootChildLayer) {
     300        CGRect rootBounds = m_rootChildLayer->bounds();
     301        m_scrollLayer->setBounds(rootBounds);
     302    }
     303    m_scrollLayer->setPosition(CGPointMake(-m_scrollPosition.x(), m_scrollPosition.y() + m_scrollSize.height()));
     304}
     305
     306void WKCACFLayerRenderer::setRootContents(CGImageRef image)
     307{
     308    ASSERT(m_rootLayer);
     309    m_rootLayer->setContents(image);
     310    renderSoon();
     311}
     312
     313void WKCACFLayerRenderer::setRootContentsAndDisplay(CGImageRef image)
     314{
     315    ASSERT(m_rootLayer);
     316    m_rootLayer->setContents(image);
     317    paint();
     318}
     319
     320void WKCACFLayerRenderer::setRootChildLayer(WKCACFLayer* layer)
     321{
     322    if (!m_scrollLayer)
     323        return;
     324
     325    m_scrollLayer->removeAllSublayers();
     326    m_rootChildLayer = layer;
     327    if (layer) {
     328        m_scrollLayer->addSublayer(layer);
     329        // Adjust the scroll frame accordingly
     330        updateScrollFrame();
     331    }
     332}
     333   
     334void WKCACFLayerRenderer::setNeedsDisplay()
     335{
     336    ASSERT(m_rootLayer);
     337    m_rootLayer->setNeedsDisplay(0);
     338    renderSoon();
     339}
     340
     341bool WKCACFLayerRenderer::createRenderer()
     342{
     343    if (m_triedToCreateD3DRenderer)
     344        return m_d3dDevice;
     345
     346    m_triedToCreateD3DRenderer = true;
     347    D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
     348
     349    if (!d3d() || !::IsWindow(m_hostWindow))
     350        return false;
     351
     352    // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the
     353    // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero
     354    // size eventually, and then the backbuffer size will get reset.
     355    RECT rect;
     356    GetClientRect(m_hostWindow, &rect);
     357
     358    if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) {
     359        parameters.BackBufferWidth = 1;
     360        parameters.BackBufferHeight = 1;
     361    }
     362
     363    COMPtr<IDirect3DDevice9> device;
     364    if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &parameters, &device)))
     365        return false;
     366
     367    // Now that we've created the IDirect3DDevice9 based on the capabilities we
     368    // got from the IDirect3D9 global object, we requery the device for its
     369    // actual capabilities. The capabilities returned by the device can
     370    // sometimes be more complete, for example when using software vertex
     371    // processing.
     372    D3DCAPS9 deviceCaps;
     373    if (FAILED(device->GetDeviceCaps(&deviceCaps)))
     374        return false;
     375
     376    if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps))
     377        return false;
     378
     379    m_d3dDevice = device;
     380
     381    D3DXMATRIXA16 projection;
     382    D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f);
     383
     384    m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection);
     385
     386    m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0);
     387
    389388    if (IsWindow(m_hostWindow))
    390389        m_rootLayer->setFrame(bounds());
    391 
    392     if (m_context)
    393         m_rootLayer->becomeRootLayerForContext(m_context.get());
    394390
    395391    return true;
Note: See TracChangeset for help on using the changeset viewer.