bool WKCACFLayerRenderer::resetDevice(ResetReason reason) { ASSERT(m_d3dDevice); ASSERT(m_renderContext); HRESULT hr = m_d3dDevice->TestCooperativeLevel(); if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) { // The device cannot be reset at this time. Try again soon. m_mustResetLostDeviceBeforeRendering = true; return false; } m_mustResetLostDeviceBeforeRendering = false; if (reason == LostDevice && hr == D3D_OK) { // The device wasn't lost after all. return true; } // We can reset the device. // We have to purge the CARenderOGLContext whenever we reset the IDirect3DDevice9 in order to // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>. CARenderOGLPurge(m_renderer); D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); hr = m_d3dDevice->Reset(¶meters); // TestCooperativeLevel told us the device may be reset now, so we should // not be told here that the device is lost. ASSERT(hr != D3DERR_DEVICELOST); initD3DGeometry(); return true; }
void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) { ASSERT(m_d3dDevice); // Flush the root layer to the render tree. WKCACFContextFlusher::shared().flushAllContexts(); CGRect bounds = this->bounds(); CFTimeInterval t = CACurrentMediaTime(); // Give the renderer some space to use. This needs to be valid until the // CARenderUpdateFinish() call below. char space[4096]; CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds); if (!u) return; CARenderContextLock(m_renderContext); CARenderUpdateAddContext(u, m_renderContext); CARenderContextUnlock(m_renderContext); for (size_t i = 0; i < dirtyRects.size(); ++i) CARenderUpdateAddRect(u, &dirtyRects[i]); HRESULT err = S_OK; do { CGSRegionObj rgn = CARenderUpdateCopyRegion(u); if (!rgn) break; // FIXME: don't need to clear dirty region if layer tree is opaque. Vector<D3DRECT, 64> rects; CGSRegionEnumeratorObj e = CGSRegionEnumerator(rgn); for (const CGRect* r = CGSNextRect(e); r; r = CGSNextRect(e)) { D3DRECT rect; rect.x1 = r->origin.x; rect.x2 = rect.x1 + r->size.width; rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); rect.y2 = rect.y1 + r->size.height; rects.append(rect); } CGSReleaseRegionEnumerator(e); CGSReleaseRegion(rgn); if (rects.isEmpty()) break; m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); m_d3dDevice->BeginScene(); CARenderOGLRender(m_renderer, u); m_d3dDevice->EndScene(); err = m_d3dDevice->Present(0, 0, 0, 0); if (err == D3DERR_DEVICELOST) { // Lost device situation. CARenderOGLPurge(m_renderer); resetDevice(); CARenderUpdateAddRect(u, &bounds); } } while (err == D3DERR_DEVICELOST); CARenderUpdateFinish(u); #ifndef NDEBUG if (m_printTree) m_rootLayer->printTree(); #endif }