D3D12 vertex and index buffers with resource transitions
diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt
index a9b2552..6177535 100644
--- a/src/backend/CMakeLists.txt
+++ b/src/backend/CMakeLists.txt
@@ -216,10 +216,14 @@
     SetPIC(d3d12_autogen)
 
     list(APPEND BACKEND_SOURCES
+        ${D3D12_DIR}/BufferD3D12.cpp
+        ${D3D12_DIR}/BufferD3D12.h
         ${D3D12_DIR}/CommandBufferD3D12.cpp
         ${D3D12_DIR}/CommandBufferD3D12.h
         ${D3D12_DIR}/D3D12Backend.cpp
         ${D3D12_DIR}/D3D12Backend.h
+        ${D3D12_DIR}/InputStateD3D12.cpp
+        ${D3D12_DIR}/InputStateD3D12.h
         ${D3D12_DIR}/PipelineD3D12.cpp
         ${D3D12_DIR}/PipelineD3D12.h
         ${D3D12_DIR}/PipelineLayoutD3D12.cpp
diff --git a/src/backend/d3d12/BufferD3D12.cpp b/src/backend/d3d12/BufferD3D12.cpp
new file mode 100644
index 0000000..d837cba
--- /dev/null
+++ b/src/backend/d3d12/BufferD3D12.cpp
@@ -0,0 +1,163 @@
+// Copyright 2017 The NXT Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "BufferD3D12.h"
+
+#include "D3D12Backend.h"
+
+namespace backend {
+namespace d3d12 {
+
+    namespace {
+        D3D12_RESOURCE_STATES D3D12BufferUsage(nxt::BufferUsageBit usage) {
+            D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_COMMON;
+
+            if (usage & nxt::BufferUsageBit::TransferSrc) {
+                resourceState |= D3D12_RESOURCE_STATE_COPY_SOURCE;
+            }
+            if (usage & nxt::BufferUsageBit::TransferDst) {
+                resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
+            }
+            if (usage & (nxt::BufferUsageBit::Vertex | nxt::BufferUsageBit::Uniform)) {
+                resourceState |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+            }
+            if (usage & nxt::BufferUsageBit::Index) {
+                resourceState |= D3D12_RESOURCE_STATE_INDEX_BUFFER;
+            }
+            if (usage & nxt::BufferUsageBit::Storage) {
+                resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+            }
+
+            return resourceState;
+        }
+    }
+
+    Buffer::Buffer(Device* device, BufferBuilder* builder)
+        : BufferBase(builder), device(device) {
+
+        D3D12_RESOURCE_DESC resourceDescriptor;
+        resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+        resourceDescriptor.Alignment = 0;
+        resourceDescriptor.Width = GetSize();
+        resourceDescriptor.Height = 1;
+        resourceDescriptor.DepthOrArraySize = 1;
+        resourceDescriptor.MipLevels = 1;
+        resourceDescriptor.Format = DXGI_FORMAT_UNKNOWN;
+        resourceDescriptor.SampleDesc.Count = 1;
+        resourceDescriptor.SampleDesc.Quality = 0;
+        resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+        resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+        {
+            D3D12_HEAP_PROPERTIES heapProperties;
+            heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
+            heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+            heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+            heapProperties.CreationNodeMask = 0;
+            heapProperties.VisibleNodeMask = 0;
+
+            ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
+                &heapProperties,
+                D3D12_HEAP_FLAG_NONE,
+                &resourceDescriptor,
+                D3D12_RESOURCE_STATE_GENERIC_READ,
+                nullptr,
+                IID_PPV_ARGS(&uploadResource)
+            ));
+        }
+
+        {
+            D3D12_HEAP_PROPERTIES heapProperties;
+            heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
+            heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+            heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+            heapProperties.CreationNodeMask = 0;
+            heapProperties.VisibleNodeMask = 0;
+
+            ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
+                &heapProperties,
+                D3D12_HEAP_FLAG_NONE,
+                &resourceDescriptor,
+                D3D12BufferUsage(GetUsage()),
+                nullptr,
+                IID_PPV_ARGS(&resource)
+            ));
+        }
+    }
+
+    ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() {
+        return resource;
+    }
+
+    bool Buffer::GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
+        D3D12_RESOURCE_STATES stateBefore = D3D12BufferUsage(currentUsage);
+        D3D12_RESOURCE_STATES stateAfter = D3D12BufferUsage(targetUsage);
+
+        if (stateBefore == stateAfter) {
+            return false;
+        }
+
+        barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+        barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+        barrier->Transition.pResource = resource.Get();
+        barrier->Transition.StateBefore = stateBefore;
+        barrier->Transition.StateAfter = stateAfter;
+        barrier->Transition.Subresource = 0;
+
+        return true;
+    }
+
+    D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const {
+        return resource->GetGPUVirtualAddress();
+    }
+
+    void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
+        uint32_t begin = start * sizeof(uint32_t);
+        uint32_t end = (start + count) * sizeof(uint32_t);
+
+        uint8_t* mappedResource = nullptr;
+
+        D3D12_RANGE readRange;
+        readRange.Begin = 0;
+        readRange.End = 0;
+
+        ASSERT_SUCCESS(uploadResource->Map(0, &readRange, reinterpret_cast<void**>(&mappedResource)));
+        memcpy(&mappedResource[begin], data, end - begin);
+
+        D3D12_RANGE writeRange;
+        writeRange.Begin = begin;
+        writeRange.End = end;
+
+        uploadResource->Unmap(0, &writeRange);
+
+        device->GetPendingCommandList()->CopyBufferRegion(resource.Get(), begin, uploadResource.Get(), begin, end - begin);
+    }
+
+    void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
+        // TODO(cwallez@chromium.org): Implement Map Read for the null backend
+    }
+
+    void Buffer::UnmapImpl() {
+        // TODO(cwallez@chromium.org): Implement Map Read for the null backend
+    }
+
+    void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
+        D3D12_RESOURCE_BARRIER barrier;
+        if (GetResourceTransitionBarrier(currentUsage, targetUsage, &barrier)) {
+            device->GetPendingCommandList()->ResourceBarrier(1, &barrier);
+        }
+    }
+
+}
+}
diff --git a/src/backend/d3d12/BufferD3D12.h b/src/backend/d3d12/BufferD3D12.h
new file mode 100644
index 0000000..6ff12e7
--- /dev/null
+++ b/src/backend/d3d12/BufferD3D12.h
@@ -0,0 +1,51 @@
+// Copyright 2017 The NXT Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BACKEND_D3D12_BUFFERD3D12_H_
+#define BACKEND_D3D12_BUFFERD3D12_H_
+
+#include "common/Buffer.h"
+
+#include "d3d12_platform.h"
+
+namespace backend {
+namespace d3d12 {
+
+    class Device;
+
+    class Buffer : public BufferBase {
+        public:
+            Buffer(Device* device, BufferBuilder* builder);
+
+            ComPtr<ID3D12Resource> GetD3D12Resource();
+            D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
+            bool GetResourceTransitionBarrier(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
+
+        private:
+            Device* device;
+            ComPtr<ID3D12Resource> uploadResource;
+            ComPtr<ID3D12Resource> resource;
+
+            // NXT API
+            void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
+            void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
+            void UnmapImpl() override;
+            void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) override;
+
+    };
+
+}
+}
+
+#endif // BACKEND_D3D12_BUFFERD3D12_H_
diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp
index 95306a6..1d5ebd8 100644
--- a/src/backend/d3d12/CommandBufferD3D12.cpp
+++ b/src/backend/d3d12/CommandBufferD3D12.cpp
@@ -16,156 +16,212 @@
 
 #include "common/Commands.h"
 #include "D3D12Backend.h"
+#include "BufferD3D12.h"
+#include "InputStateD3D12.h"
 #include "PipelineD3D12.h"
 #include "PipelineLayoutD3D12.h"
 
 namespace backend {
 namespace d3d12 {
 
-      CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
-          : CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
-      }
+    namespace {
+        DXGI_FORMAT DXGIIndexFormat(nxt::IndexFormat format) {
+            switch (format) {
+                case nxt::IndexFormat::Uint16:
+                    return DXGI_FORMAT_R16_UINT;
+                case nxt::IndexFormat::Uint32:
+                    return DXGI_FORMAT_R32_UINT;
+            }
+        }
+    }
 
-      CommandBuffer::~CommandBuffer() {
-          FreeCommands(&commands);
-      }
+    CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder)
+        : CommandBufferBase(builder), device(device), commands(builder->AcquireCommands()) {
+    }
 
-      void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
-          Command type;
-          Pipeline* lastPipeline = nullptr;
+    CommandBuffer::~CommandBuffer() {
+        FreeCommands(&commands);
+    }
 
-          RenderPass* currentRenderPass = nullptr;
-          Framebuffer* currentFramebuffer = nullptr;
+    void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
+        Command type;
+        Pipeline* lastPipeline = nullptr;
 
-          while(commands.NextCommandId(&type)) {
-              switch (type) {
-                  case Command::AdvanceSubpass:
-                      {
-                          commands.NextCommand<AdvanceSubpassCmd>();
-                      }
-                      break;
+        RenderPass* currentRenderPass = nullptr;
+        Framebuffer* currentFramebuffer = nullptr;
 
-                  case Command::BeginRenderPass:
-                      {
-                          BeginRenderPassCmd* beginRenderPassCmd = commands.NextCommand<BeginRenderPassCmd>();
-                          currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
-                          currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
+        while(commands.NextCommandId(&type)) {
+            switch (type) {
+                case Command::AdvanceSubpass:
+                    {
+                        commands.NextCommand<AdvanceSubpassCmd>();
+                    }
+                    break;
 
-                          float width = (float) currentFramebuffer->GetWidth();
-                          float height = (float) currentFramebuffer->GetHeight();
-                          D3D12_VIEWPORT viewport = { 0.f, 0.f, width, height, 0.f, 1.f };
-                          D3D12_RECT scissorRect = { 0.f, 0.f, width, height };
-                          commandList->RSSetViewports(1, &viewport);
-                          commandList->RSSetScissorRects(1, &scissorRect);
-                          commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr);
-                      }
-                      break;
+                case Command::BeginRenderPass:
+                    {
+                        BeginRenderPassCmd* beginRenderPassCmd = commands.NextCommand<BeginRenderPassCmd>();
+                        currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
+                        currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
 
-                  case Command::CopyBufferToBuffer:
-                      {
-                          CopyBufferToBufferCmd* copy = commands.NextCommand<CopyBufferToBufferCmd>();
-                      }
-                      break;
+                        float width = (float) currentFramebuffer->GetWidth();
+                        float height = (float) currentFramebuffer->GetHeight();
+                        D3D12_VIEWPORT viewport = { 0.f, 0.f, width, height, 0.f, 1.f };
+                        D3D12_RECT scissorRect = { 0.f, 0.f, width, height };
+                        commandList->RSSetViewports(1, &viewport);
+                        commandList->RSSetScissorRects(1, &scissorRect);
+                        commandList->OMSetRenderTargets(1, &device->GetCurrentRenderTargetDescriptor(), FALSE, nullptr);
+                    }
+                    break;
+                case Command::CopyBufferToBuffer:
+                    {
+                        CopyBufferToBufferCmd* copy = commands.NextCommand<CopyBufferToBufferCmd>();
+                    }
+                    break;
 
-                  case Command::CopyBufferToTexture:
-                      {
-                          CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
-                      }
-                      break;
+                case Command::CopyBufferToTexture:
+                    {
+                        CopyBufferToTextureCmd* copy = commands.NextCommand<CopyBufferToTextureCmd>();
+                    }
+                    break;
 
-                  case Command::Dispatch:
-                      {
-                          DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
+                case Command::Dispatch:
+                    {
+                        DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
 
-                          ASSERT(lastPipeline->IsCompute());
-                          commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
-                      }
-                      break;
+                        ASSERT(lastPipeline->IsCompute());
+                        commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
+                    }
+                    break;
 
-                  case Command::DrawArrays:
-                      {
-                          DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
+                case Command::DrawArrays:
+                    {
+                        DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
 
-                          commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
-                          commandList->DrawInstanced(
-                              draw->vertexCount,
-                              draw->instanceCount,
-                              draw->firstVertex,
-                              draw->firstInstance
-                          );
-                      }
-                      break;
+                        commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+                        commandList->DrawInstanced(
+                            draw->vertexCount,
+                            draw->instanceCount,
+                            draw->firstVertex,
+                            draw->firstInstance
+                        );
+                    }
+                    break;
 
-                  case Command::DrawElements:
-                      {
-                          DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
-                      }
-                      break;
+                case Command::DrawElements:
+                    {
+                        DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
 
-                  case Command::EndRenderPass:
-                      {
-                          EndRenderPassCmd* cmd = commands.NextCommand<EndRenderPassCmd>();
-                      }
-                      break;
+                        commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+                        commandList->DrawIndexedInstanced(
+                            draw->indexCount,
+                            draw->instanceCount,
+                            draw->firstIndex,
+                            0,
+                            draw->firstInstance
+                        );
+                    }
+                    break;
 
-                  case Command::SetPipeline:
-                      {
-                          SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
-                          lastPipeline = ToBackend(cmd->pipeline).Get();
-                          PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout());
+                case Command::EndRenderPass:
+                    {
+                        EndRenderPassCmd* cmd = commands.NextCommand<EndRenderPassCmd>();
+                    }
+                    break;
 
-                          // TODO
-                          if (lastPipeline->IsCompute()) {
-                          } else {
-                              commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get());
-                              commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get());
-                          }
-                      }
-                      break;
+                case Command::SetPipeline:
+                    {
+                        SetPipelineCmd* cmd = commands.NextCommand<SetPipelineCmd>();
+                        lastPipeline = ToBackend(cmd->pipeline).Get();
+                        PipelineLayout* pipelineLayout = ToBackend(lastPipeline->GetLayout());
 
-                  case Command::SetPushConstants:
-                      {
-                          SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
-                      }
-                      break;
+                        // TODO
+                        if (lastPipeline->IsCompute()) {
+                        } else {
+                            commandList->SetGraphicsRootSignature(pipelineLayout->GetRootSignature().Get());
+                            commandList->SetPipelineState(lastPipeline->GetRenderPipelineState().Get());
+                        }
+                    }
+                    break;
 
-                  case Command::SetStencilReference:
+                case Command::SetPushConstants:
+                    {
+                        SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
+                    }
+                    break;
+
+                case Command::SetStencilReference:
                     {
                         SetStencilReferenceCmd* cmd = commands.NextCommand<SetStencilReferenceCmd>();
                     }
                     break;
 
-                  case Command::SetBindGroup:
-                      {
-                          SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
-                      }
-                      break;
+                case Command::SetBindGroup:
+                    {
+                        SetBindGroupCmd* cmd = commands.NextCommand<SetBindGroupCmd>();
+                    }
+                    break;
 
-                  case Command::SetIndexBuffer:
-                      {
-                          SetIndexBufferCmd* cmd = commands.NextCommand<SetIndexBufferCmd>();
-                      }
-                      break;
+                case Command::SetIndexBuffer:
+                    {
+                        SetIndexBufferCmd* cmd = commands.NextCommand<SetIndexBufferCmd>();
 
-                  case Command::SetVertexBuffers:
-                      {
-                          SetVertexBuffersCmd* cmd = commands.NextCommand<SetVertexBuffersCmd>();
-                      }
-                      break;
+                        Buffer* buffer = ToBackend(cmd->buffer.Get());
+                        D3D12_INDEX_BUFFER_VIEW bufferView;
+                        bufferView.BufferLocation = buffer->GetVA() + cmd->offset;
+                        bufferView.SizeInBytes = buffer->GetSize() - cmd->offset;
+                        bufferView.Format = DXGIIndexFormat(cmd->format);
 
-                  case Command::TransitionBufferUsage:
-                      {
-                          TransitionBufferUsageCmd* cmd = commands.NextCommand<TransitionBufferUsageCmd>();
-                      }
-                      break;
+                        commandList->IASetIndexBuffer(&bufferView);
+                    }
+                    break;
 
-                  case Command::TransitionTextureUsage:
-                      {
-                          TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
-                      }
-                      break;
-              }
-          }
-      }
+                case Command::SetVertexBuffers:
+                    {
+                        SetVertexBuffersCmd* cmd = commands.NextCommand<SetVertexBuffersCmd>();
+                        auto buffers = commands.NextData<Ref<BufferBase>>(cmd->count);
+                        auto offsets = commands.NextData<uint32_t>(cmd->count);
+
+                        auto inputState = ToBackend(lastPipeline->GetInputState());
+
+                        std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexInputs> d3d12BufferViews;
+                        for (uint32_t i = 0; i < cmd->count; ++i) {
+                            auto input = inputState->GetInput(cmd->startSlot + i);
+                            Buffer* buffer = ToBackend(buffers[i].Get());
+                            d3d12BufferViews[i].BufferLocation = buffer->GetVA() + offsets[i];
+                            d3d12BufferViews[i].StrideInBytes = input.stride;
+                            d3d12BufferViews[i].SizeInBytes = buffer->GetSize() - offsets[i];
+                        }
+
+                        commandList->IASetVertexBuffers(cmd->startSlot, cmd->count, d3d12BufferViews.data());
+                    }
+                    break;
+
+                case Command::TransitionBufferUsage:
+                    {
+                        TransitionBufferUsageCmd* cmd = commands.NextCommand<TransitionBufferUsageCmd>();
+
+                        Buffer* buffer = ToBackend(cmd->buffer.Get());
+
+                        D3D12_RESOURCE_BARRIER barrier;
+                        if (buffer->GetResourceTransitionBarrier(buffer->GetUsage(), cmd->usage, &barrier)) {
+                            commandList->ResourceBarrier(1, &barrier);
+                        }
+
+                        buffer->UpdateUsageInternal(cmd->usage);
+                    }
+                    break;
+
+                case Command::TransitionTextureUsage:
+                    {
+                        TransitionTextureUsageCmd* cmd = commands.NextCommand<TransitionTextureUsageCmd>();
+
+                        Texture* texture = ToBackend(cmd->texture.Get());
+                        texture->UpdateUsageInternal(cmd->usage);
+                    }
+                    break;
+            }
+        }
+    }
 }
 }
diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp
index 6900bb9..5e9a142 100644
--- a/src/backend/d3d12/D3D12Backend.cpp
+++ b/src/backend/d3d12/D3D12Backend.cpp
@@ -14,7 +14,9 @@
 
 #include "D3D12Backend.h"
 
+#include "BufferD3D12.h"
 #include "CommandBufferD3D12.h"
+#include "InputStateD3D12.h"
 #include "PipelineD3D12.h"
 #include "PipelineLayoutD3D12.h"
 #include "QueueD3D12.h"
@@ -51,6 +53,15 @@
         queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
         queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
         ASSERT_SUCCESS(d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)));
+
+        ASSERT_SUCCESS(d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pendingCommandAllocator)));
+        ASSERT_SUCCESS(d3d12Device->CreateCommandList(
+            0,
+            D3D12_COMMAND_LIST_TYPE_DIRECT,
+            pendingCommandAllocator.Get(),
+            nullptr,
+            IID_PPV_ARGS(&pendingCommandList)
+        ));
     }
 
     Device::~Device() {
@@ -64,6 +75,14 @@
         return commandQueue;
     }
 
+    ComPtr<ID3D12CommandAllocator> Device::GetPendingCommandAllocator() {
+        return pendingCommandAllocator;
+    }
+
+    ComPtr<ID3D12GraphicsCommandList> Device::GetPendingCommandList() {
+        return pendingCommandList;
+    }
+
     D3D12_CPU_DESCRIPTOR_HANDLE Device::GetCurrentRenderTargetDescriptor() {
         return renderTargetDescriptor;
     }
@@ -139,26 +158,6 @@
         : BindGroupLayoutBase(builder), device(device) {
     }
 
-    // Buffer
-
-    Buffer::Buffer(Device* device, BufferBuilder* builder)
-        : BufferBase(builder), device(device) {
-    }
-
-    void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
-    }
-
-    void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
-        // TODO(cwallez@chromium.org): Implement Map Read for the null backend
-    }
-
-    void Buffer::UnmapImpl() {
-        // TODO(cwallez@chromium.org): Implement Map Read for the null backend
-    }
-
-    void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
-    }
-
     // BufferView
 
     BufferView::BufferView(Device* device, BufferViewBuilder* builder)
@@ -177,12 +176,6 @@
         : FramebufferBase(builder), device(device) {
     }
 
-    // InputState
-
-    InputState::InputState(Device* device, InputStateBuilder * builder)
-        : InputStateBase(builder), device(device) {
-    }
-
     // RenderPass
 
     RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h
index 8e1e193..cc0cd02 100644
--- a/src/backend/d3d12/D3D12Backend.h
+++ b/src/backend/d3d12/D3D12Backend.h
@@ -106,6 +106,8 @@
 
             ComPtr<ID3D12Device> GetD3D12Device();
             ComPtr<ID3D12CommandQueue> GetCommandQueue();
+            ComPtr<ID3D12CommandAllocator> GetPendingCommandAllocator();
+            ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
             D3D12_CPU_DESCRIPTOR_HANDLE GetCurrentRenderTargetDescriptor();
 
             void SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor);
@@ -117,6 +119,8 @@
         private:
             ComPtr<ID3D12Device> d3d12Device;
             ComPtr<ID3D12CommandQueue> commandQueue;
+            ComPtr<ID3D12CommandAllocator> pendingCommandAllocator;
+            ComPtr<ID3D12GraphicsCommandList> pendingCommandList;
             D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor;
     };
 
@@ -137,19 +141,6 @@
             Device* device;
     };
 
-    class Buffer : public BufferBase {
-        public:
-            Buffer(Device* device, BufferBuilder* builder);
-
-        private:
-            void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
-            void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
-            void UnmapImpl() override;
-            void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) override;
-
-            Device* device;
-    };
-
     class BufferView : public BufferViewBase {
         public:
             BufferView(Device* device, BufferViewBuilder* builder);
@@ -174,14 +165,6 @@
             Device* device;
     };
 
-    class InputState : public InputStateBase {
-        public:
-            InputState(Device* device, InputStateBuilder* builder);
-
-        private:
-            Device* device;
-    };
-
     class RenderPass : public RenderPassBase {
         public:
             RenderPass(Device* device, RenderPassBuilder* builder);
diff --git a/src/backend/d3d12/GeneratedCodeIncludes.h b/src/backend/d3d12/GeneratedCodeIncludes.h
index f2e322f..0f776b9 100644
--- a/src/backend/d3d12/GeneratedCodeIncludes.h
+++ b/src/backend/d3d12/GeneratedCodeIncludes.h
@@ -13,7 +13,9 @@
 // limitations under the License.
 
 #include "D3D12Backend.h"
+#include "BufferD3D12.h"
 #include "CommandBufferD3D12.h"
+#include "InputStateD3D12.h"
 #include "PipelineD3D12.h"
 #include "PipelineLayoutD3D12.h"
 #include "QueueD3D12.h"
diff --git a/src/backend/d3d12/InputStateD3D12.cpp b/src/backend/d3d12/InputStateD3D12.cpp
new file mode 100644
index 0000000..e0abcb0
--- /dev/null
+++ b/src/backend/d3d12/InputStateD3D12.cpp
@@ -0,0 +1,82 @@
+// Copyright 2017 The NXT Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "InputStateD3D12.h"
+
+namespace backend {
+namespace d3d12 {
+
+    static DXGI_FORMAT VertexFormatType(nxt::VertexFormat format) {
+        switch (format) {
+            case nxt::VertexFormat::FloatR32G32B32A32:
+                return DXGI_FORMAT_R32G32B32A32_FLOAT;
+            case nxt::VertexFormat::FloatR32G32B32:
+                return DXGI_FORMAT_R32G32B32_FLOAT;
+            case nxt::VertexFormat::FloatR32G32:
+                return DXGI_FORMAT_R32G32_FLOAT;
+        }
+    }
+
+    static D3D12_INPUT_CLASSIFICATION InputStepModeFunction(nxt::InputStepMode mode) {
+        switch (mode) {
+            case nxt::InputStepMode::Vertex:
+                return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
+            case nxt::InputStepMode::Instance:
+                return D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
+        }
+    }
+
+    InputState::InputState(Device* device, InputStateBuilder* builder)
+        : InputStateBase(builder), device(device) {
+
+        const auto& attributesSetMask = GetAttributesSetMask();
+
+        size_t count = 0;
+        for (size_t i = 0; i < attributesSetMask.size(); ++i) {
+            if (!attributesSetMask[i]) {
+                continue;
+            }
+
+            D3D12_INPUT_ELEMENT_DESC& inputElementDescriptor = inputElementDescriptors[count++];
+
+            const AttributeInfo& attribute = GetAttribute(i);
+
+            // If the HLSL semantic is TEXCOORDN the SemanticName should be "TEXCOORD" and the SemanticIndex N
+            inputElementDescriptor.SemanticName = "TEXCOORD";
+            inputElementDescriptor.SemanticIndex = i;
+            inputElementDescriptor.Format = VertexFormatType(attribute.format);
+            inputElementDescriptor.InputSlot = attribute.bindingSlot;
+
+            const InputInfo& input = GetInput(attribute.bindingSlot);
+
+            inputElementDescriptor.AlignedByteOffset = attribute.offset;
+            inputElementDescriptor.InputSlotClass = InputStepModeFunction(input.stepMode);
+            if (inputElementDescriptor.InputSlotClass == D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA) {
+                inputElementDescriptor.InstanceDataStepRate = 0;
+            } else {
+                inputElementDescriptor.InstanceDataStepRate = 1;
+            }
+        }
+
+        inputLayoutDescriptor.pInputElementDescs = inputElementDescriptors;
+        inputLayoutDescriptor.NumElements = count;
+
+    }
+
+    const D3D12_INPUT_LAYOUT_DESC& InputState::GetD3D12InputLayoutDescriptor() const {
+        return inputLayoutDescriptor;
+    }
+
+}
+}
diff --git a/src/backend/d3d12/InputStateD3D12.h b/src/backend/d3d12/InputStateD3D12.h
new file mode 100644
index 0000000..5dc2187
--- /dev/null
+++ b/src/backend/d3d12/InputStateD3D12.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The NXT Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BACKEND_D3D12_INPUTSTATED3D12_H_
+#define BACKEND_D3D12_INPUTSTATED3D12_H_
+
+#include "common/InputState.h"
+
+#include "d3d12_platform.h"
+
+namespace backend {
+namespace d3d12 {
+
+    class Device;
+
+    class InputState : public InputStateBase {
+        public:
+            InputState(Device* device, InputStateBuilder* builder);
+
+            const D3D12_INPUT_LAYOUT_DESC& GetD3D12InputLayoutDescriptor() const;
+
+        private:
+            Device* device;
+            D3D12_INPUT_LAYOUT_DESC inputLayoutDescriptor;
+            D3D12_INPUT_ELEMENT_DESC inputElementDescriptors[kMaxVertexAttributes];
+    };
+
+}
+}
+
+#endif // BACKEND_D3D12_INPUTSTATED3D12_H_
diff --git a/src/backend/d3d12/PipelineD3D12.cpp b/src/backend/d3d12/PipelineD3D12.cpp
index be9562a..afcd3ae 100644
--- a/src/backend/d3d12/PipelineD3D12.cpp
+++ b/src/backend/d3d12/PipelineD3D12.cpp
@@ -15,6 +15,7 @@
 #include "PipelineD3D12.h"
 
 #include "D3D12Backend.h"
+#include "InputStateD3D12.h"
 #include "ShaderModuleD3D12.h"
 #include "PipelineLayoutD3D12.h"
 
@@ -115,6 +116,9 @@
                 }
             }
 
+            InputState* inputState = ToBackend(GetInputState());
+            descriptor.InputLayout = inputState->GetD3D12InputLayoutDescriptor();
+
             descriptor.pRootSignature = ToBackend(GetLayout())->GetRootSignature().Get();
 
             descriptor.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
diff --git a/src/backend/d3d12/QueueD3D12.cpp b/src/backend/d3d12/QueueD3D12.cpp
index 7e8582f..4a5ef0f 100644
--- a/src/backend/d3d12/QueueD3D12.cpp
+++ b/src/backend/d3d12/QueueD3D12.cpp
@@ -31,7 +31,6 @@
             nullptr,
             IID_PPV_ARGS(&commandList)
         ));
-        ASSERT_SUCCESS(commandList->Close());
 
         ASSERT_SUCCESS(device->GetD3D12Device()->CreateFence(fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
         fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
@@ -39,10 +38,22 @@
     }
 
     void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) {
-        // TODO(enga@google.com): This will stall on the previous submit because
+        ComPtr<ID3D12CommandAllocator> pendingCommandAllocator = device->GetPendingCommandAllocator();
+        ComPtr<ID3D12GraphicsCommandList> pendingCommandList = device->GetPendingCommandList();
+        ASSERT_SUCCESS(pendingCommandList->Close());
+
+        for (uint32_t i = 0; i < numCommands; ++i) {
+            commands[i]->FillCommands(commandList);
+        }
+        ASSERT_SUCCESS(commandList->Close());
+
+        ID3D12CommandList* commandLists[] = { pendingCommandList.Get(), commandList.Get() };
+        device->GetCommandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+        // TODO(enga@google.com): This will stall on the submit because
         // the commands must finish exeuting before the ID3D12CommandAllocator is reset.
         // This should be fixed / optimized by using multiple command allocators.
-        const uint64_t currentFence = fenceValue++;
+        const uint64_t currentFence = ++fenceValue;
         ASSERT_SUCCESS(device->GetCommandQueue()->Signal(fence.Get(), fenceValue));
 
         if (fence->GetCompletedValue() < currentFence) {
@@ -51,16 +62,9 @@
         }
 
         ASSERT_SUCCESS(commandAllocator->Reset());
+        ASSERT_SUCCESS(pendingCommandAllocator->Reset());
+        ASSERT_SUCCESS(pendingCommandList->Reset(pendingCommandAllocator.Get(), NULL));
         ASSERT_SUCCESS(commandList->Reset(commandAllocator.Get(), NULL));
-
-        for (uint32_t i = 0; i < numCommands; ++i) {
-            commands[i]->FillCommands(commandList);
-        }
-
-        ASSERT_SUCCESS(commandList->Close());
-
-        ID3D12CommandList* commandLists[] = { commandList.Get() };
-        device->GetCommandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
     }
 
 }