Add Device::Tick for periodic work
diff --git a/src/backend/common/Device.cpp b/src/backend/common/Device.cpp
index f95e588..ce5ba62 100644
--- a/src/backend/common/Device.cpp
+++ b/src/backend/common/Device.cpp
@@ -130,6 +130,10 @@
         return new TextureBuilder(this);
     }
 
+    void DeviceBase::Tick() {
+        TickImpl();
+    }
+
     void DeviceBase::CopyBindGroups(uint32_t start, uint32_t count, BindGroupBase* source, BindGroupBase* target) {
         // TODO(cwallez@chromium.org): update state tracking then call the backend
     }
diff --git a/src/backend/common/Device.h b/src/backend/common/Device.h
index 6938f53..e4f9902 100644
--- a/src/backend/common/Device.h
+++ b/src/backend/common/Device.h
@@ -30,7 +30,6 @@
             ~DeviceBase();
 
             void HandleError(const char* message);
-            void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata);
 
             // Used by autogenerated code, returns itself
             DeviceBase* GetDevice();
@@ -52,6 +51,8 @@
             virtual TextureBase* CreateTexture(TextureBuilder* builder) = 0;
             virtual TextureViewBase* CreateTextureView(TextureViewBuilder* builder) = 0;
 
+            virtual void TickImpl() = 0;
+
             // Many NXT objects are completely immutable once created which means that if two
             // builders are given the same arguments, they can return the same object. Reusing
             // objects will help make comparisons between objects by a single pointer comparison.
@@ -86,7 +87,9 @@
             ShaderModuleBuilder* CreateShaderModuleBuilder();
             TextureBuilder* CreateTextureBuilder();
 
+            void Tick();
             void CopyBindGroups(uint32_t start, uint32_t count, BindGroupBase* source, BindGroupBase* target);
+            void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata);
 
         private:
             // The object caches aren't exposed in the header as they would require a lot of
diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp
index ec9a087..847f759 100644
--- a/src/backend/d3d12/D3D12Backend.cpp
+++ b/src/backend/d3d12/D3D12Backend.cpp
@@ -99,7 +99,7 @@
         this->renderTargetDescriptor = renderTargetDescriptor;
     }
 
-    void Device::Tick() {
+    void Device::TickImpl() {
         // Execute any pending commands
         ASSERT_SUCCESS(pendingCommandList->Close());
         ID3D12CommandList* commandLists[] = { pendingCommandList.Get() };
diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h
index 50fdb29..b27cf9c 100644
--- a/src/backend/d3d12/D3D12Backend.h
+++ b/src/backend/d3d12/D3D12Backend.h
@@ -105,6 +105,8 @@
             TextureBase* CreateTexture(TextureBuilder* builder) override;
             TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
 
+            void TickImpl() override;
+
             ComPtr<ID3D12Device> GetD3D12Device();
             ComPtr<ID3D12CommandQueue> GetCommandQueue();
             ComPtr<ID3D12CommandAllocator> GetPendingCommandAllocator();
@@ -114,7 +116,6 @@
 
             void SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor);
 
-            void Tick();
             uint64_t GetSerial() const;
             void IncrementSerial();
 
diff --git a/src/backend/metal/MetalBackend.h b/src/backend/metal/MetalBackend.h
index cdfdd4a..f0f582d 100644
--- a/src/backend/metal/MetalBackend.h
+++ b/src/backend/metal/MetalBackend.h
@@ -114,6 +114,8 @@
             TextureBase* CreateTexture(TextureBuilder* builder) override;
             TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
 
+            void TickImpl() override;
+
             void SetNextDrawable(id<CAMetalDrawable> drawable);
             void Present();
 
diff --git a/src/backend/metal/MetalBackend.mm b/src/backend/metal/MetalBackend.mm
index 878218c..e406bbf 100644
--- a/src/backend/metal/MetalBackend.mm
+++ b/src/backend/metal/MetalBackend.mm
@@ -114,6 +114,9 @@
         return new TextureView(this, builder);
     }
 
+    void Device::TickImpl() {
+    }
+
     void Device::SetNextDrawable(id<CAMetalDrawable> drawable) {
         [currentDrawable release];
         currentDrawable = drawable;
diff --git a/src/backend/null/NullBackend.cpp b/src/backend/null/NullBackend.cpp
index 1fda445..0e0ff38 100644
--- a/src/backend/null/NullBackend.cpp
+++ b/src/backend/null/NullBackend.cpp
@@ -89,6 +89,9 @@
         return new TextureViewBase(builder);
     }
 
+    void Device::TickImpl() {
+    }
+
     void Device::AddPendingOperation(std::unique_ptr<PendingOperation> operation) {
         pendingOperations.emplace_back(std::move(operation));
     }
diff --git a/src/backend/null/NullBackend.h b/src/backend/null/NullBackend.h
index b93845d..d2ebf72 100644
--- a/src/backend/null/NullBackend.h
+++ b/src/backend/null/NullBackend.h
@@ -107,6 +107,8 @@
             TextureBase* CreateTexture(TextureBuilder* builder) override;
             TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
 
+            void TickImpl() override;
+
             void AddPendingOperation(std::unique_ptr<PendingOperation> operation);
             std::vector<std::unique_ptr<PendingOperation>> AcquirePendingOperations();
 
diff --git a/src/backend/opengl/OpenGLBackend.cpp b/src/backend/opengl/OpenGLBackend.cpp
index 695a447..829587c 100644
--- a/src/backend/opengl/OpenGLBackend.cpp
+++ b/src/backend/opengl/OpenGLBackend.cpp
@@ -97,6 +97,9 @@
         return new TextureView(this, builder);
     }
 
+    void Device::TickImpl() {
+    }
+
     void Device::Reference() {
     }
 
diff --git a/src/backend/opengl/OpenGLBackend.h b/src/backend/opengl/OpenGLBackend.h
index 2cac947..8bf77b6 100644
--- a/src/backend/opengl/OpenGLBackend.h
+++ b/src/backend/opengl/OpenGLBackend.h
@@ -97,6 +97,8 @@
             TextureBase* CreateTexture(TextureBuilder* builder) override;
             TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
 
+            void TickImpl() override;
+
             // NXT API
             void Reference();
             void Release();