diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp
index 7e942827..a331f4cc 100644
--- a/src/d3d11/d3d11_context.cpp
+++ b/src/d3d11/d3d11_context.cpp
@@ -113,7 +113,7 @@ namespace dxvk {
 //     this->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
     
     this->VSSetShader(nullptr, nullptr, 0);
-//     this->VSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, nullptr);
+    this->VSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, nullptr);
 //     this->VSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, nullptr);
 //     this->VSSetSamplers       (0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, nullptr);
     
@@ -133,7 +133,7 @@ namespace dxvk {
 //     this->GSSetSamplers       (0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, nullptr);
     
     this->PSSetShader(nullptr, nullptr, 0);
-//     this->PSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, nullptr);
+    this->PSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, nullptr);
 //     this->PSSetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, nullptr);
 //     this->PSSetSamplers       (0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, nullptr);
     
@@ -360,7 +360,32 @@ namespace dxvk {
     const void*                             pSrcData,
           UINT                              SrcRowPitch,
           UINT                              SrcDepthPitch) {
-    Logger::err("D3D11DeviceContext::UpdateSubresource: Not implemented");
+    // We need a different code path for buffers
+    D3D11_RESOURCE_DIMENSION resourceType;
+    pDstResource->GetType(&resourceType);
+    
+    if (resourceType == D3D11_RESOURCE_DIMENSION_BUFFER) {
+      Com<IDXGIBufferResourcePrivate> bufferResource;
+      
+      pDstResource->QueryInterface(
+        __uuidof(IDXGIBufferResourcePrivate),
+        reinterpret_cast<void**>(&bufferResource));
+      
+      VkDeviceSize offset = 0;
+      VkDeviceSize size = VK_WHOLE_SIZE;
+      
+      if (pDstBox != nullptr) {
+        offset = pDstBox->left;
+        size   = pDstBox->right - pDstBox->left;
+      }
+      
+      m_context->updateBuffer(
+        bufferResource->GetDXVKBuffer(),
+        offset, size, pSrcData);
+    } else {
+      Logger::err("D3D11DeviceContext::UpdateSubresource: Images not yet supported");
+    }
+    
   }
   
   
@@ -613,16 +638,10 @@ namespace dxvk {
     switch (binding.format) {
       case DXGI_FORMAT_R16_UINT: indexType = VK_INDEX_TYPE_UINT16; break;
       case DXGI_FORMAT_R32_UINT: indexType = VK_INDEX_TYPE_UINT32; break;
-      
-      default:
-        Logger::err(str::format(
-          "D3D11DeviceContext::IASetIndexBuffer: Invalid index format: ",
-          binding.format));
     }
     
     m_context->bindIndexBuffer(
       dxvkBinding, indexType);
-      
   }
   
   
@@ -676,7 +695,11 @@ namespace dxvk {
           UINT                              StartSlot,
           UINT                              NumBuffers,
           ID3D11Buffer* const*              ppConstantBuffers) {
-    Logger::err("D3D11DeviceContext::VSSetConstantBuffers: Not implemented");
+    this->BindConstantBuffers(
+      D3D11ShaderStage::VertexShader,
+      &m_state.vs.constantBuffers,
+      StartSlot, NumBuffers,
+      ppConstantBuffers);
   }
   
   
@@ -942,7 +965,11 @@ namespace dxvk {
           UINT                              StartSlot,
           UINT                              NumBuffers,
           ID3D11Buffer* const*              ppConstantBuffers) {
-    Logger::err("D3D11DeviceContext::PSSetConstantBuffers: Not implemented");
+    this->BindConstantBuffers(
+      D3D11ShaderStage::PixelShader,
+      &m_state.vs.constantBuffers,
+      StartSlot, NumBuffers,
+      ppConstantBuffers);
   }
   
   
@@ -1301,6 +1328,38 @@ namespace dxvk {
   }
   
   
+  void D3D11DeviceContext::BindConstantBuffers(
+          D3D11ShaderStage                  ShaderStage,
+          D3D11ConstantBufferBindings*      pBindings,
+          UINT                              StartSlot,
+          UINT                              NumBuffers,
+          ID3D11Buffer* const*              ppConstantBuffers) {
+    for (uint32_t i = 0; i < NumBuffers; i++) {
+      D3D11Buffer* buffer = nullptr;
+      
+      if (ppConstantBuffers != nullptr)
+        buffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
+      
+      if (pBindings->at(StartSlot + i) != buffer) {
+        pBindings->at(StartSlot + i) = buffer;
+        
+        DxvkBufferBinding dxvkBinding;
+        
+        if (buffer != nullptr) {
+          dxvkBinding = DxvkBufferBinding(
+            buffer->GetDXVKBuffer(),
+            0, VK_WHOLE_SIZE);
+        }
+        
+        // TODO compute actual slot index
+        m_context->bindResourceBuffer(
+          VK_PIPELINE_BIND_POINT_GRAPHICS, 0,
+          dxvkBinding);
+      }
+    }
+  }
+  
+  
   void D3D11DeviceContext::ApplyViewportState() {
     // We cannot set less than one viewport in Vulkan, and
     // rendering with no active viewport is illegal anyway.
diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h
index a69d6148..b86dd7bc 100644
--- a/src/d3d11/d3d11_context.h
+++ b/src/d3d11/d3d11_context.h
@@ -554,6 +554,13 @@ namespace dxvk {
     
     D3D11ContextState   m_state;
     
+    void BindConstantBuffers(
+            D3D11ShaderStage                  ShaderStage,
+            D3D11ConstantBufferBindings*      pBindings,
+            UINT                              StartSlot,
+            UINT                              NumBuffers,
+            ID3D11Buffer* const*              ppConstantBuffers);
+    
     void ApplyViewportState();
     
     void SetupIAStateObjects();
diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h
index 41dcac51..31bc2896 100644
--- a/src/d3d11/d3d11_context_state.h
+++ b/src/d3d11/d3d11_context_state.h
@@ -10,54 +10,51 @@
 
 namespace dxvk {
   
-  struct D3D11ComputePipelineBindings {
-    std::array<Com<D3D11Buffer>,              D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT> constantBuffers;
-//     std::array<Com<D3D11ShaderResourceView>,  D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT>      shaderResourceViews;
-//     std::array<Com<D3D11UnorderedAccessView>, D3D11_1_UAV_SLOT_COUNT>                            uniformAccessViews;
-//     std::array<Com<D3D11SamplerState>,        D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT>             samplers;
-  };
-  
-  
-  struct D3D11GraphicsPipelineBindings {
-    std::array<Com<D3D11Buffer>,              D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT> constantBuffers;
-//     std::array<Com<D3D11ShaderResourceView>,  D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT>      shaderResourceViews;
-//     std::array<Com<D3D11SamplerState>,        D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT>             samplers;
+  enum class D3D11ShaderStage {
+    VertexShader      = 0,
+    HullShader        = 1,
+    DomainShader      = 2,
+    GeometryShader    = 3,
+    PixelShader       = 4,
+    ComputeShader     = 5,
   };
   
+  using D3D11ConstantBufferBindings = std::array<
+    Com<D3D11Buffer>, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT>;
   
   struct D3D11ContextStateVS {
     Com<D3D11VertexShader>        shader;
-    D3D11GraphicsPipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
   struct D3D11ContextStateHS {
     Com<D3D11HullShader>          shader;
-    D3D11GraphicsPipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
   struct D3D11ContextStateDS {
     Com<D3D11DomainShader>        shader;
-    D3D11GraphicsPipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
   struct D3D11ContextStateGS {
     Com<D3D11GeometryShader>      shader;
-    D3D11GraphicsPipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
   struct D3D11ContextStatePS {
     Com<D3D11PixelShader>         shader;
-    D3D11GraphicsPipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
   struct D3D11ContextStateCS {
     Com<D3D11ComputeShader>      shader;
-    D3D11ComputePipelineBindings bindings;
+    D3D11ConstantBufferBindings   constantBuffers;
   };
   
   
diff --git a/src/dxbc/gen/dxbc_gen_common.cpp b/src/dxbc/gen/dxbc_gen_common.cpp
index 3629ba90..e4f26995 100644
--- a/src/dxbc/gen/dxbc_gen_common.cpp
+++ b/src/dxbc/gen/dxbc_gen_common.cpp
@@ -43,6 +43,7 @@ namespace dxvk {
       DxbcValueType(DxbcScalarType::Float32, 4, elementCount));
     uint32_t structType = m_module.defStructType(1, &arrayType);
     
+    m_module.decorateArrayStride(arrayType, 16);
     m_module.memberDecorateOffset(structType, 0, 0);
     m_module.decorateBlock(structType);
     
@@ -50,8 +51,14 @@ namespace dxvk {
       m_module.defPointerType(structType, spv::StorageClassUniform),
       spv::StorageClassUniform);
     
+    m_module.setDebugName(varIndex, str::format("cb", bufferId).c_str());
+    m_module.decorateDescriptorSet(varIndex, 0);
+    m_module.decorateBinding(varIndex, 0);
     m_constantBuffers.at(bufferId).varId = varIndex;
     m_constantBuffers.at(bufferId).size  = elementCount;
+    
+    // TODO compute resource slot index
+    m_resourceSlots.push_back({ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER });
   }
   
   
diff --git a/src/dxbc/gen/dxbc_gen_common.h b/src/dxbc/gen/dxbc_gen_common.h
index 77bb014e..4bf7c08a 100644
--- a/src/dxbc/gen/dxbc_gen_common.h
+++ b/src/dxbc/gen/dxbc_gen_common.h
@@ -156,7 +156,8 @@ namespace dxvk {
     
     std::vector<DxbcPointer> m_rRegs;
     
-    std::array<DxbcConstantBuffer, 16> m_constantBuffers;
+    std::array<DxbcConstantBuffer, 16>  m_constantBuffers;
+    std::vector<DxvkResourceSlot>       m_resourceSlots;
     
     uint32_t defScalarType(
             DxbcScalarType          type);
diff --git a/src/dxbc/gen/dxbc_gen_pixel.cpp b/src/dxbc/gen/dxbc_gen_pixel.cpp
index 6bf9afcd..86bcf355 100644
--- a/src/dxbc/gen/dxbc_gen_pixel.cpp
+++ b/src/dxbc/gen/dxbc_gen_pixel.cpp
@@ -60,6 +60,7 @@ namespace dxvk {
           m_module.decorateLocation(var.valueId, regId);
           m_module.setDebugName(var.valueId,
             str::format("v", regId).c_str());
+          m_entryPointInterfaces.push_back(var.valueId);
           
           switch (im) {
             case DxbcInterpolationMode::Undefined:
@@ -168,7 +169,8 @@ namespace dxvk {
     
     return new DxvkShader(
       VK_SHADER_STAGE_FRAGMENT_BIT,
-      0, nullptr,
+      m_resourceSlots.size(),
+      m_resourceSlots.data(),
       m_module.compile());
   }
   
diff --git a/src/dxbc/gen/dxbc_gen_vertex.cpp b/src/dxbc/gen/dxbc_gen_vertex.cpp
index 6894df71..1c8dfdcb 100644
--- a/src/dxbc/gen/dxbc_gen_vertex.cpp
+++ b/src/dxbc/gen/dxbc_gen_vertex.cpp
@@ -48,6 +48,7 @@ namespace dxvk {
           m_module.decorateLocation(m_vRegs.at(regId).valueId, regId);
           m_module.setDebugName(m_vRegs.at(regId).valueId,
             str::format("v", regId).c_str());
+          m_entryPointInterfaces.push_back(m_vRegs.at(regId).valueId);
         }
         
         if (sv != DxbcSystemValue::None) {
@@ -64,6 +65,7 @@ namespace dxvk {
           m_module.decorateLocation(m_oRegs.at(regId).valueId, regId);
           m_module.setDebugName(m_oRegs.at(regId).valueId,
             str::format("o", regId).c_str());
+          m_entryPointInterfaces.push_back(m_oRegs.at(regId).valueId);
         }
         
         if (sv != DxbcSystemValue::None) {
@@ -134,7 +136,8 @@ namespace dxvk {
     
     return new DxvkShader(
       VK_SHADER_STAGE_VERTEX_BIT,
-      0, nullptr,
+      m_resourceSlots.size(),
+      m_resourceSlots.data(),
       m_module.compile());
   }
   
@@ -160,6 +163,7 @@ namespace dxvk {
           this->regStore(this->ptrBuiltInPosition(), srcValue,
             DxbcComponentMask(true, true, true, true));
         } break;
+        default: ;
       }
     }
   }
diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp
index f8b176ac..7d33e358 100644
--- a/src/dxvk/dxvk_context.cpp
+++ b/src/dxvk/dxvk_context.cpp
@@ -340,26 +340,29 @@ namespace dxvk {
           VkDeviceSize              offset,
           VkDeviceSize              size,
     const void*                     data) {
+    this->renderPassEnd();
     
-    if (size == 0)
-      return;
+    if (size == VK_WHOLE_SIZE)
+      size = buffer->info().size;
     
-    if (size <= 65536) {
-      m_cmd->cmdUpdateBuffer(
-        buffer->handle(),
-        offset, size, data);
-    } else {
-      // TODO implement
-      Logger::err("DxvkContext::updateBuffer: Large updates not yet supported");
+    if (size != 0) {
+      if (size <= 65536) {
+        m_cmd->cmdUpdateBuffer(
+          buffer->handle(),
+          offset, size, data);
+      } else {
+        // TODO implement
+        Logger::err("DxvkContext::updateBuffer: Large updates not yet supported");
+      }
+      
+      m_barriers.accessBuffer(
+        buffer, offset, size,
+        VK_PIPELINE_STAGE_TRANSFER_BIT,
+        VK_ACCESS_TRANSFER_WRITE_BIT,
+        buffer->info().stages,
+        buffer->info().access);
+      m_barriers.recordCommands(m_cmd);
     }
-    
-    m_barriers.accessBuffer(
-      buffer, offset, size,
-      VK_PIPELINE_STAGE_TRANSFER_BIT,
-      VK_ACCESS_TRANSFER_WRITE_BIT,
-      buffer->info().stages,
-      buffer->info().access);
-    m_barriers.recordCommands(m_cmd);
   }
   
   
diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp
index db02a9d9..0a1bf642 100644
--- a/src/spirv/spirv_module.cpp
+++ b/src/spirv/spirv_module.cpp
@@ -238,6 +238,16 @@ namespace dxvk {
   }
   
   
+  void SpirvModule::decorateArrayStride(
+          uint32_t                object,
+          uint32_t                stride) {
+    m_annotations.putIns  (spv::OpDecorate, 4);
+    m_annotations.putWord (object);
+    m_annotations.putWord (spv::DecorationArrayStride);
+    m_annotations.putInt32(stride);
+  }
+  
+  
   void SpirvModule::decorateBinding(
           uint32_t                object,
           uint32_t                binding) {
diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h
index 1a02cd17..f06a76d1 100644
--- a/src/spirv/spirv_module.h
+++ b/src/spirv/spirv_module.h
@@ -88,6 +88,10 @@ namespace dxvk {
             uint32_t                object,
             spv::Decoration         decoration);
     
+    void decorateArrayStride(
+            uint32_t                object,
+            uint32_t                stride);
+    
     void decorateBinding(
             uint32_t                object,
             uint32_t                binding);
diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp
index 11c10941..c60d9992 100644
--- a/tests/d3d11/test_d3d11_triangle.cpp
+++ b/tests/d3d11/test_d3d11_triangle.cpp
@@ -14,32 +14,17 @@ struct Extent2D {
 
 struct Vertex {
   float x, y, z, w;
-  float r, g, b, a;
 };
 
 const std::string g_vertexShaderCode =
-  "struct VsInput {\n"
-  "  float4 position : IN_POSITION;\n"
-  "  float4 color    : IN_COLOR;\n"
-  "};\n"
-  "struct VsOutput {\n"
-  "  float4 position : SV_POSITION;\n"
-  "  float4 color    : PS_COLOR;\n"
-  "};\n"
-  "VsOutput main(VsInput vsIn) {\n"
-  "  VsOutput vsOut;\n"
-  "  vsOut.position = vsIn.position;\n"
-  "  vsOut.color    = vsIn.color;\n"
-  "  return vsOut;\n"
+  "float4 main(float4 vsIn : IN_POSITION) : SV_POSITION {\n"
+  "  return vsIn;\n"
   "}\n";
 
 const std::string g_pixelShaderCode =
-  "struct PsInput {\n"
-  "  float4 position : SV_POSITION;\n"
-  "  float4 color : PS_COLOR;\n"
-  "};\n"
-  "float4 main(PsInput psIn) : SV_TARGET {\n"
-  "  return psIn.color;\n"
+  "cbuffer c_buffer { float4 ccolor[2]; };\n"
+  "float4 main() : SV_TARGET {\n"
+  "  return ccolor[0];\n"
   "}\n";
 
 class TriangleApp {
@@ -97,9 +82,9 @@ public:
       throw DxvkError("Failed to resize window");
     
     std::array<Vertex, 3> vertexData = {{
-      { -0.5f, -0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f },
-      {  0.0f,  0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f },
-      {  0.5f, -0.5f, 0.0f, 1.0f, 0.03f, 0.03f, 0.03f, 1.0f },
+      { -0.5f, -0.5f, 0.0f, 1.0f },
+      {  0.0f,  0.5f, 0.0f, 1.0f },
+      {  0.5f, -0.5f, 0.0f, 1.0f },
     }};
     
     D3D11_BUFFER_DESC vertexDesc;
@@ -115,6 +100,30 @@ public:
     vertexDataInfo.SysMemPitch      = 0;
     vertexDataInfo.SysMemSlicePitch = 0;
     
+    if (FAILED(m_device->CreateBuffer(&vertexDesc, &vertexDataInfo, &m_vertexBuffer)))
+      throw DxvkError("Failed to create vertex buffer");
+    
+    std::array<Vertex, 2> constantData = {{
+      { 0.03f, 0.03f, 0.03f, 1.0f },
+      { 1.00f, 1.00f, 1.00f, 1.0f },
+    }};
+    
+    D3D11_BUFFER_DESC constantDesc;
+    constantDesc.ByteWidth            = sizeof(Vertex) * constantData.size();
+    constantDesc.Usage                = D3D11_USAGE_IMMUTABLE;
+    constantDesc.BindFlags            = D3D11_BIND_CONSTANT_BUFFER;
+    constantDesc.CPUAccessFlags       = 0;
+    constantDesc.MiscFlags            = 0;
+    constantDesc.StructureByteStride  = 0;
+    
+    D3D11_SUBRESOURCE_DATA constantDataInfo;
+    constantDataInfo.pSysMem          = constantData.data();
+    constantDataInfo.SysMemPitch      = 0;
+    constantDataInfo.SysMemSlicePitch = 0;
+    
+    if (FAILED(m_device->CreateBuffer(&constantDesc, &constantDataInfo, &m_constantBuffer)))
+      throw DxvkError("Failed to create constant buffer");
+    
     Com<ID3DBlob> vertexShaderBlob;
     Com<ID3DBlob> pixelShaderBlob;
     
@@ -150,13 +159,8 @@ public:
           nullptr, &m_pixelShader)))
       throw DxvkError("Failed to create pixel shader");
       
-    
-    if (FAILED(m_device->CreateBuffer(&vertexDesc, &vertexDataInfo, &m_vertexBuffer)))
-      throw DxvkError("Failed to create vertex buffer");
-    
-    std::array<D3D11_INPUT_ELEMENT_DESC, 2> vertexFormatDesc = {{
+    std::array<D3D11_INPUT_ELEMENT_DESC, 1> vertexFormatDesc = {{
       { "IN_POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 },
-      { "IN_COLOR", 0,    DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(Vertex, r), D3D11_INPUT_PER_VERTEX_DATA, 0 },
     }};
     
     if (FAILED(m_device->CreateInputLayout(
@@ -193,6 +197,7 @@ public:
     
     m_context->VSSetShader(m_vertexShader.ptr(), nullptr, 0);
     m_context->PSSetShader(m_pixelShader.ptr(), nullptr, 0);
+    m_context->PSSetConstantBuffers(0, 1, &m_constantBuffer);
     
     UINT vsStride = sizeof(Vertex);
     UINT vsOffset = 0;
@@ -247,6 +252,7 @@ private:
     
   Com<ID3D11Texture2D>        m_buffer;
   Com<ID3D11RenderTargetView> m_bufferView;
+  Com<ID3D11Buffer>           m_constantBuffer;
   Com<ID3D11Buffer>           m_vertexBuffer;
   Com<ID3D11InputLayout>      m_vertexFormat;