text: /******************************************************************************
   * The MIT License (MIT)
   *
   * Copyright (c) 2019-2022 Baldur Karlsson
   * Copyright (c) 2014 Crytek
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   ******************************************************************************/
  
  #include "d3d11_device.h"
  #include "d3d11_context.h"
  #include "d3d11_debug.h"
  #include "d3d11_resources.h"
  
  void WrappedID3D11Device::MaskResourceMiscFlags(UINT &MiscFlags)
  {
    MiscFlags &=
        ~(D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX |
          D3D11_RESOURCE_MISC_GDI_COMPATIBLE | D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
          D3D11_RESOURCE_MISC_RESTRICTED_CONTENT | D3D11_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE |
          D3D11_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE_DRIVER | D3D11_RESOURCE_MISC_GUARDED |
          D3D11_RESOURCE_MISC_HW_PROTECTED);
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateBuffer(SerialiserType &ser, const D3D11_BUFFER_DESC *pDesc,
                                                   const D3D11_SUBRESOURCE_DATA *pInitialData,
                                                   ID3D11Buffer **ppBuffer)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pDesc).Named("pDesc"_lit).Important();
    // unused, just for the sake of the user
    SERIALISE_ELEMENT_OPT(pInitialData);
    SERIALISE_ELEMENT_LOCAL(pBuffer, GetIDForDeviceChild(*ppBuffer)).TypedAs("ID3D11Buffer *"_lit);
  
    D3D11_SUBRESOURCE_DATA fakeData;
    RDCEraseEl(fakeData);
    // we always want buffers to have data, so we create some to serialise
    if(pInitialData == NULL && ser.IsWriting())
    {
      fakeData.pSysMem = new byte[Descriptor.ByteWidth];
      fakeData.SysMemPitch = fakeData.SysMemSlicePitch = Descriptor.ByteWidth;
      // fill with 0xdddddddd to indicate that the data is uninitialised, if that option is enabled
      memset((void *)fakeData.pSysMem,
             RenderDoc::Inst().GetCaptureOptions().verifyBufferAccess ? 0xdd : 0x0,
             Descriptor.ByteWidth);
      pInitialData = &fakeData;
    }
  
    // work around an nvidia driver bug, if a buffer is created as IMMUTABLE then it
    // can't be CopySubresourceRegion'd with a box offset, the data that's read is
    // wrong.
    if(IsReplayingAndReading() && Descriptor.Usage == D3D11_USAGE_IMMUTABLE)
    {
      Descriptor.Usage = D3D11_USAGE_DEFAULT;
      // paranoid - I don't know what requirements might change, so set some sane default
      if(Descriptor.BindFlags == 0)
        Descriptor.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    }
  
    const void *InitialData = NULL;
    uint64_t InitialDataLength = 0;
  
    if(ser.IsWriting())
    {
      InitialData = pInitialData->pSysMem;
      InitialDataLength = Descriptor.ByteWidth;
    }
  
    SERIALISE_ELEMENT_ARRAY(InitialData, InitialDataLength);
  
    if(ser.IsWriting())
    {
      uint64_t offs = ser.GetWriter()->GetOffset() - InitialDataLength;
  
      RDCASSERT((offs % 64) == 0);
  
      RDCASSERT(GetResourceManager()->GetResourceRecord(pBuffer) == NULL);
  
      D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(pBuffer);
      record->SetDataOffset(offs);
      record->DataInSerialiser = true;
      record->Length = Descriptor.ByteWidth;
    }
  
    SERIALISE_ELEMENT(InitialDataLength);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11Buffer *ret;
  
      HRESULT hr = S_OK;
  
      // unset flags that are unimportant/problematic in replay
      MaskResourceMiscFlags(Descriptor.MiscFlags);
  
      D3D11_SUBRESOURCE_DATA data;
      data.pSysMem = InitialData;
      data.SysMemPitch = Descriptor.ByteWidth;
      data.SysMemSlicePitch = Descriptor.ByteWidth;
      hr = m_pDevice->CreateBuffer(&Descriptor, &data, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Buffer(ret, Descriptor.ByteWidth, this);
  
        GetResourceManager()->AddLiveResource(pBuffer, ret);
      }
  
      AddResource(pBuffer, ResourceType::Buffer, "Buffer");
  
      if(Descriptor.Usage != D3D11_USAGE_IMMUTABLE)
      {
        ID3D11Buffer *stage = NULL;
  
        D3D11_BUFFER_DESC desc;
        desc.ByteWidth = Descriptor.ByteWidth;
        desc.MiscFlags = 0;
        desc.StructureByteStride = 0;
        // We don't need to bind this, but IMMUTABLE requires at least one
        // BindFlags.
        desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        desc.CPUAccessFlags = 0;
        desc.Usage = D3D11_USAGE_IMMUTABLE;
  
        data.SysMemPitch = Descriptor.ByteWidth;
        data.SysMemSlicePitch = Descriptor.ByteWidth;
        hr = m_pDevice->CreateBuffer(&desc, &data, &stage);
  
        if(FAILED(hr) || stage == NULL)
        {
          RDCERR("Failed to create staging buffer for buffer initial contents HRESULT: %s",
                 ToStr(hr).c_str());
        }
        else
        {
          m_ResourceManager->SetInitialContents(pBuffer, D3D11InitialContents(Resource_Buffer, stage));
        }
      }
    }
  
    char *arr = (char *)fakeData.pSysMem;
    SAFE_DELETE_ARRAY(arr);
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateBuffer(const D3D11_BUFFER_DESC *pDesc,
                                            const D3D11_SUBRESOURCE_DATA *pInitialData,
                                            ID3D11Buffer **ppBuffer)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppBuffer == NULL)
      return m_pDevice->CreateBuffer(pDesc, pInitialData, NULL);
  
    bool intelExtensionMagic = false;
    byte intelExtensionData[28] = {0};
  
    // snoop to disable the absurdly implemented intel DX11 extensions.
    if(pDesc->ByteWidth == sizeof(intelExtensionData) && pDesc->Usage == D3D11_USAGE_STAGING &&
       pInitialData && pDesc->BindFlags == 0)
    {
      byte *data = (byte *)pInitialData->pSysMem;
  
      if(!memcmp(data, "INTCEXTN", 8))
      {
        RDCLOG("Intercepting and preventing attempt to initialise intel extensions.");
  
        intelExtensionMagic = true;
  
        // back-up the data from the user
        memcpy(intelExtensionData, data, sizeof(intelExtensionData));
  
        // overwrite the initial data, so the driver doesn't see the request (it just sees an empty
        // buffer). Just in case passing along the real data does something.
        memset(data, 0, sizeof(intelExtensionData));
      }
    }
  
    ID3D11Buffer *real = NULL;
    ID3D11Buffer *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateBuffer(pDesc, pInitialData, &real));
  
    if(intelExtensionMagic)
    {
      byte *data = (byte *)pInitialData->pSysMem;
  
      // restore the user's data unmodified, which is the expected behaviour when the extensions
      // aren't supported.
      memcpy(data, intelExtensionData, sizeof(intelExtensionData));
    }
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Buffer(real, pDesc->ByteWidth, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *chunk = NULL;
  
        {
          USE_SCRATCH_SERIALISER();
          SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateBuffer);
          Serialise_CreateBuffer(GET_SERIALISER, pDesc, pInitialData, &wrapped);
          chunk = scope.Get();
        }
  
        D3D11ResourceRecord *record =
            GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(wrapped));
        RDCASSERT(record);
        record->AddChunk(chunk);
        record->SetDataPtr(chunk->GetData());
      }
      else
      {
        WrappedID3D11Buffer *w = (WrappedID3D11Buffer *)wrapped;
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppBuffer = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  rdcarray<D3D11_SUBRESOURCE_DATA> WrappedID3D11Device::Serialise_CreateTextureData(
      SerialiserType &ser, ID3D11Resource *tex, ResourceId id, const D3D11_SUBRESOURCE_DATA *data,
      UINT w, UINT h, UINT d, DXGI_FORMAT fmt, UINT mips, UINT arr, bool HasData)
  {
    UINT numSubresources = mips;
    UINT numMips = mips;
  
    if(mips == 0)
      numSubresources = numMips = CalcNumMips(w, h, d);
  
    numSubresources *= arr;
  
    rdcarray<D3D11_SUBRESOURCE_DATA> descs;
    if(IsReplayingAndReading() && HasData)
      descs.resize(numSubresources);
  
    // scratch memory. Used to linearise & tightly pack incoming data for serialising, so that we know
    // the data is in a fixed and predictable layout for
    byte *scratch = NULL;
  
    for(UINT i = 0; i < numSubresources; i++)
    {
      int mip = i % numMips;
  
      byte *SubresourceContents = NULL;
      UINT SubresourceContentsLength = GetByteSize(w, h, d, fmt, mip);
  
      RDCASSERT(SubresourceContentsLength > 0);
  
      D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(id);
  
      if(ser.IsWriting())
      {
        // on the first iteration, set up the resource record
        if(i == 0)
        {
          RDCASSERT(record == NULL);
  
          record = GetResourceManager()->AddResourceRecord(id);
          record->Length = 1;
  
          if(HasData)
            record->DataInSerialiser = true;
  
          record->NumSubResources = numSubresources;
          record->SubResources = new D3D11ResourceRecord *[record->NumSubResources];
          for(UINT s = 0; s < numSubresources; s++)
          {
            record->SubResources[s] = new D3D11ResourceRecord(ResourceId());
            record->SubResources[s]->DataInSerialiser = HasData;
          }
        }
  
        RDCASSERT(record);
  
        record->SubResources[i]->Length = SubresourceContentsLength;
      }
  
      // skip the remaining if there's no data to serialise
      if(!HasData)
        continue;
  
      // we linearise the data so that future functions know the format of the data in the record
      if(ser.IsWriting())
      {
        // since we iterate from largest subresource down, we only need to allocate once - the rest of
        // the subresources use progressively less of the allocation at a time
        if(scratch == NULL)
          scratch = new byte[SubresourceContentsLength];
  
        MapIntercept intercept;
        intercept.SetD3D(data[i]);
  
        D3D11_RESOURCE_DIMENSION dim;
        tex->GetType(&dim);
  
        if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D)
          intercept.Init((ID3D11Texture1D *)tex, i, scratch);
        else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D)
          intercept.Init((ID3D11Texture2D *)tex, i, scratch);
        else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
          intercept.Init((ID3D11Texture3D *)tex, i, scratch);
        else
          RDCERR("Unexpected resource type!");
  
        intercept.CopyFromD3D();
  
        SubresourceContents = scratch;
      }
  
      SERIALISE_ELEMENT_ARRAY(SubresourceContents, SubresourceContentsLength);
  
      if(ser.IsWriting())
      {
        RDCASSERT(record);
  
        record->SubResources[i]->SetDataOffset(ser.GetWriter()->GetOffset() - SubresourceContentsLength);
      }
  
      SERIALISE_ELEMENT(SubresourceContentsLength);
  
      if(IsReplayingAndReading())
      {
        // we 'steal' the SubresourceContents buffer so it doesn't get de-serialised and free'd
        descs[i].pSysMem = SubresourceContents;
        SubresourceContents = NULL;
  
        // calculate tightly packed pitches
        descs[i].SysMemPitch = GetRowPitch(w, fmt, mip);
        descs[i].SysMemSlicePitch = GetByteSize(w, h, 1, fmt, mip);
      }
    }
  
    // delete our scratch memory
    SAFE_DELETE_ARRAY(scratch);
  
    return descs;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateTexture1D(SerialiserType &ser,
                                                      const D3D11_TEXTURE1D_DESC *pDesc,
                                                      const D3D11_SUBRESOURCE_DATA *pInitialData,
                                                      ID3D11Texture1D **ppTexture1D)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pDesc).Important();
  
    // unused, just for the sake of the user
    {
      UINT numSubresources =
          Descriptor.MipLevels ? Descriptor.MipLevels : CalcNumMips(Descriptor.Width, 1, 1);
      numSubresources *= Descriptor.ArraySize;
  
      SERIALISE_ELEMENT_ARRAY(pInitialData, pInitialData ? numSubresources : 0);
    }
  
    SERIALISE_ELEMENT_LOCAL(pTexture, GetIDForDeviceChild(*ppTexture1D))
        .TypedAs("ID3D11Texture1D *"_lit);
  
    rdcarray<D3D11_SUBRESOURCE_DATA> descs = Serialise_CreateTextureData(
        ser, ppTexture1D ? *ppTexture1D : NULL, pTexture, pInitialData, Descriptor.Width, 1, 1,
        Descriptor.Format, Descriptor.MipLevels, Descriptor.ArraySize, pInitialData != NULL);
  
    if(IsReplayingAndReading() && ser.IsErrored())
    {
      // need to manually free the serialised buffers we stole in Serialise_CreateTextureData here,
      // before the SERIALISE_CHECK_READ_ERRORS macro below returns out of the function
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11Texture1D *ret;
      HRESULT hr = S_OK;
  
      TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
      // unset flags that are unimportant/problematic in replay
      MaskResourceMiscFlags(Descriptor.MiscFlags);
  
      if(pInitialData != NULL)
        hr = m_pDevice->CreateTexture1D(&Descriptor, &descs[0], &ret);
      else
        hr = m_pDevice->CreateTexture1D(&Descriptor, NULL, &ret);
  
      APIProps.YUVTextures |= IsYUVFormat(Descriptor.Format);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Texture1D(ret, this, dispType);
  
        GetResourceManager()->AddLiveResource(pTexture, ret);
      }
  
      const char *prefix = Descriptor.ArraySize > 1 ? "1D TextureArray" : "1D Texture";
  
      if(Descriptor.BindFlags & D3D11_BIND_RENDER_TARGET)
        prefix = "1D Render Target";
      else if(Descriptor.BindFlags & D3D11_BIND_DEPTH_STENCIL)
        prefix = "1D Depth Target";
  
      AddResource(pTexture, ResourceType::Texture, prefix);
  
      // free the serialised buffers we stole in Serialise_CreateTextureData
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateTexture1D(const D3D11_TEXTURE1D_DESC *pDesc,
                                               const D3D11_SUBRESOURCE_DATA *pInitialData,
                                               ID3D11Texture1D **ppTexture1D)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppTexture1D == NULL)
      return m_pDevice->CreateTexture1D(pDesc, pInitialData, NULL);
  
    ID3D11Texture1D *real = NULL;
    ID3D11Texture1D *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateTexture1D(pDesc, pInitialData, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Texture1D(real, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *chunk = NULL;
  
        {
          USE_SCRATCH_SERIALISER();
          SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateTexture1D);
          Serialise_CreateTexture1D(GET_SERIALISER, pDesc, pInitialData, &wrapped);
  
          chunk = scope.Get();
        }
  
        D3D11ResourceRecord *record =
            GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(wrapped));
        RDCASSERT(record);
  
        record->AddChunk(chunk);
        record->SetDataPtr(chunk->GetData());
      }
      else
      {
        WrappedID3D11Texture1D *w = (WrappedID3D11Texture1D *)wrapped;
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppTexture1D = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateTexture2D(SerialiserType &ser,
                                                      const D3D11_TEXTURE2D_DESC *pDesc,
                                                      const D3D11_SUBRESOURCE_DATA *pInitialData,
                                                      ID3D11Texture2D **ppTexture2D)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pDesc).Important();
  
    // unused, just for the sake of the user
    {
      UINT numSubresources = Descriptor.MipLevels
                                 ? Descriptor.MipLevels
                                 : CalcNumMips(Descriptor.Width, Descriptor.Height, 1);
      numSubresources *= Descriptor.ArraySize;
  
      SERIALISE_ELEMENT_ARRAY(pInitialData, pInitialData ? numSubresources : 0);
    }
  
    SERIALISE_ELEMENT_LOCAL(pTexture, GetIDForDeviceChild(*ppTexture2D))
        .TypedAs("ID3D11Texture2D *"_lit);
  
    rdcarray<D3D11_SUBRESOURCE_DATA> descs =
        Serialise_CreateTextureData(ser, ppTexture2D ? *ppTexture2D : NULL, pTexture, pInitialData,
                                    Descriptor.Width, Descriptor.Height, 1, Descriptor.Format,
                                    Descriptor.MipLevels, Descriptor.ArraySize, pInitialData != NULL);
  
    if(IsReplayingAndReading() && ser.IsErrored())
    {
      // need to manually free the serialised buffers we stole in Serialise_CreateTextureData here,
      // before the SERIALISE_CHECK_READ_ERRORS macro below returns out of the function
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11Texture2D *ret;
      HRESULT hr = S_OK;
  
      TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
      APIProps.YUVTextures |= IsYUVFormat(Descriptor.Format);
  
      // unset flags that are unimportant/problematic in replay
      MaskResourceMiscFlags(Descriptor.MiscFlags);
  
      if(pInitialData != NULL)
        hr = m_pDevice->CreateTexture2D(&Descriptor, &descs[0], &ret);
      else
        hr = m_pDevice->CreateTexture2D(&Descriptor, NULL, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Texture2D1(ret, this, dispType);
  
        GetResourceManager()->AddLiveResource(pTexture, ret);
      }
  
      const char *prefix = Descriptor.ArraySize > 1 ? "2D TextureArray" : "2D Texture";
  
      if(Descriptor.BindFlags & D3D11_BIND_RENDER_TARGET)
        prefix = "2D Render Target";
      else if(Descriptor.BindFlags & D3D11_BIND_DEPTH_STENCIL)
        prefix = "2D Depth Target";
  
      AddResource(pTexture, ResourceType::Texture, prefix);
  
      // free the serialised buffers we stole in Serialise_CreateTextureData
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateTexture2D(const D3D11_TEXTURE2D_DESC *pDesc,
                                               const D3D11_SUBRESOURCE_DATA *pInitialData,
                                               ID3D11Texture2D **ppTexture2D)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppTexture2D == NULL)
      return m_pDevice->CreateTexture2D(pDesc, pInitialData, NULL);
  
    ID3D11Texture2D *real = NULL;
    ID3D11Texture2D *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateTexture2D(pDesc, pInitialData, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Texture2D1(real, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *chunk = NULL;
  
        {
          USE_SCRATCH_SERIALISER();
          SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateTexture2D);
          Serialise_CreateTexture2D(GET_SERIALISER, pDesc, pInitialData, &wrapped);
  
          chunk = scope.Get();
        }
  
        D3D11ResourceRecord *record =
            GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(wrapped));
        RDCASSERT(record);
  
        record->AddChunk(chunk);
        record->SetDataPtr(chunk->GetData());
      }
      else
      {
        WrappedID3D11Texture2D1 *w = (WrappedID3D11Texture2D1 *)wrapped;
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppTexture2D = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateTexture3D(SerialiserType &ser,
                                                      const D3D11_TEXTURE3D_DESC *pDesc,
                                                      const D3D11_SUBRESOURCE_DATA *pInitialData,
                                                      ID3D11Texture3D **ppTexture3D)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pDesc).Important();
  
    // unused, just for the sake of the user
    {
      UINT numSubresources = Descriptor.MipLevels
                                 ? Descriptor.MipLevels
                                 : CalcNumMips(Descriptor.Width, Descriptor.Height, Descriptor.Depth);
  
      SERIALISE_ELEMENT_ARRAY(pInitialData, pInitialData ? numSubresources : 0);
    }
  
    SERIALISE_ELEMENT_LOCAL(pTexture, GetIDForDeviceChild(*ppTexture3D))
        .TypedAs("ID3D11Texture3D *"_lit);
  
    rdcarray<D3D11_SUBRESOURCE_DATA> descs =
        Serialise_CreateTextureData(ser, ppTexture3D ? *ppTexture3D : NULL, pTexture, pInitialData,
                                    Descriptor.Width, Descriptor.Height, Descriptor.Depth,
                                    Descriptor.Format, Descriptor.MipLevels, 1, pInitialData != NULL);
  
    if(IsReplayingAndReading() && ser.IsErrored())
    {
      // need to manually free the serialised buffers we stole in Serialise_CreateTextureData here,
      // before the SERIALISE_CHECK_READ_ERRORS macro below returns out of the function
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11Texture3D *ret;
      HRESULT hr = S_OK;
  
      TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
      APIProps.YUVTextures |= IsYUVFormat(Descriptor.Format);
  
      // unset flags that are unimportant/problematic in replay
      MaskResourceMiscFlags(Descriptor.MiscFlags);
  
      if(pInitialData != NULL)
        hr = m_pDevice->CreateTexture3D(&Descriptor, &descs[0], &ret);
      else
        hr = m_pDevice->CreateTexture3D(&Descriptor, NULL, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Texture3D1(ret, this, dispType);
  
        GetResourceManager()->AddLiveResource(pTexture, ret);
      }
  
      const char *prefix = "3D Texture";
  
      if(Descriptor.BindFlags & D3D11_BIND_RENDER_TARGET)
        prefix = "3D Render Target";
      else if(Descriptor.BindFlags & D3D11_BIND_DEPTH_STENCIL)
        prefix = "3D Depth Target";
  
      AddResource(pTexture, ResourceType::Texture, prefix);
  
      // free the serialised buffers we stole in Serialise_CreateTextureData
      for(size_t i = 0; i < descs.size(); i++)
        FreeAlignedBuffer((byte *)descs[i].pSysMem);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateTexture3D(const D3D11_TEXTURE3D_DESC *pDesc,
                                               const D3D11_SUBRESOURCE_DATA *pInitialData,
                                               ID3D11Texture3D **ppTexture3D)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppTexture3D == NULL)
      return m_pDevice->CreateTexture3D(pDesc, pInitialData, NULL);
  
    ID3D11Texture3D *real = NULL;
    ID3D11Texture3D *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateTexture3D(pDesc, pInitialData, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Texture3D1(real, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *chunk = NULL;
  
        {
          USE_SCRATCH_SERIALISER();
          SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateTexture3D);
          Serialise_CreateTexture3D(GET_SERIALISER, pDesc, pInitialData, &wrapped);
  
          chunk = scope.Get();
        }
  
        D3D11ResourceRecord *record =
            GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(wrapped));
        RDCASSERT(record);
  
        record->AddChunk(chunk);
        record->SetDataPtr(chunk->GetData());
      }
      else
      {
        WrappedID3D11Texture3D1 *w = (WrappedID3D11Texture3D1 *)wrapped;
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppTexture3D = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateShaderResourceView(
      SerialiserType &ser, ID3D11Resource *pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc,
      ID3D11ShaderResourceView **ppSRView)
  {
    SERIALISE_ELEMENT(pResource).Important();
    SERIALISE_ELEMENT_OPT(pDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pView, GetIDForDeviceChild(*ppSRView))
        .TypedAs("ID3D11ShaderResourceView *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pResource)
    {
      ID3D11ShaderResourceView *ret;
  
      D3D11_SHADER_RESOURCE_VIEW_DESC *pSRVDesc = (D3D11_SHADER_RESOURCE_VIEW_DESC *)pDesc;
  
      WrappedID3D11Texture2D1 *tex2d = (WrappedID3D11Texture2D1 *)pResource;
  
      D3D11_SHADER_RESOURCE_VIEW_DESC backbufferTypedDesc;
  
      // need to fixup typeless backbuffer fudging, if a descriptor isn't specified then
      // we need to make one to give the correct type
      if(!pDesc && WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        backbufferTypedDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  
        if(tex2d->m_RealDescriptor->SampleDesc.Quality > 0 ||
           tex2d->m_RealDescriptor->SampleDesc.Count > 1)
          backbufferTypedDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
  
        backbufferTypedDesc.Format = tex2d->m_RealDescriptor->Format;
        backbufferTypedDesc.Texture2D.MipLevels = 1;
        backbufferTypedDesc.Texture2D.MostDetailedMip = 0;
        pSRVDesc = &backbufferTypedDesc;
      }
  
      // if we have a descriptor but it specifies DXGI_FORMAT_UNKNOWN format, that means use
      // the texture's format. But as above, we fudge around the typeless backbuffer so we
      // have to set the correct typed format
      //
      // This behaviour is documented only for render targets, but seems to be used & work for
      // SRVs, so apply it here too.
      if(pSRVDesc && pSRVDesc->Format == DXGI_FORMAT_UNKNOWN &&
         WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        pSRVDesc->Format = tex2d->m_RealDescriptor->Format;
      }
  
      if(pSRVDesc)
        APIProps.YUVTextures |= IsYUVFormat(pSRVDesc->Format);
  
      HRESULT hr = m_pDevice->CreateShaderResourceView(UnwrapResource(pResource), pSRVDesc, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11ShaderResourceView1(ret, pResource, this);
  
        GetResourceManager()->AddLiveResource(pView, ret);
      }
  
      AddResource(pView, ResourceType::View, "Shader Resource View");
      DerivedResource(pResource, pView);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateShaderResourceView(ID3D11Resource *pResource,
                                                        const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc,
                                                        ID3D11ShaderResourceView **ppSRView)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppSRView == NULL)
      return m_pDevice->CreateShaderResourceView(UnwrapResource(pResource), pDesc, NULL);
  
    ID3D11ShaderResourceView *real = NULL;
    ID3D11ShaderResourceView *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateShaderResourceView(UnwrapResource(pResource), pDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11ShaderResourceView1(real, pResource, this);
  
      Chunk *chunk = NULL;
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateShaderResourceView);
        Serialise_CreateShaderResourceView(GET_SERIALISER, pResource, pDesc, &wrapped);
  
        chunk = scope.Get();
  
        {
          D3D11ResourceRecord *parent =
              GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(pResource));
  
          RDCASSERT(parent);
  
          WrappedID3D11ShaderResourceView1 *view = (WrappedID3D11ShaderResourceView1 *)wrapped;
          ResourceId id = view->GetResourceID();
  
          RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
          D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
          record->Length = 0;
  
          record->AddParent(parent);
  
          record->AddChunk(chunk);
        }
      }
  
      *ppSRView = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateUnorderedAccessView(
      SerialiserType &ser, ID3D11Resource *pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc,
      ID3D11UnorderedAccessView **ppUAView)
  {
    SERIALISE_ELEMENT(pResource).Important();
    SERIALISE_ELEMENT_OPT(pDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pView, GetIDForDeviceChild(*ppUAView))
        .TypedAs("ID3D11UnorderedAccessView *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pResource)
    {
      ID3D11UnorderedAccessView *ret;
  
      D3D11_UNORDERED_ACCESS_VIEW_DESC *pUAVDesc = (D3D11_UNORDERED_ACCESS_VIEW_DESC *)pDesc;
  
      WrappedID3D11Texture2D1 *tex2d = (WrappedID3D11Texture2D1 *)pResource;
  
      D3D11_UNORDERED_ACCESS_VIEW_DESC backbufferTypedDesc;
  
      // need to fixup typeless backbuffer fudging, if a descriptor isn't specified then
      // we need to make one to give the correct type
      if(!pDesc && WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        // MSAA UAVs aren't supported so this must be non-MSAA
        backbufferTypedDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
        backbufferTypedDesc.Format = tex2d->m_RealDescriptor->Format;
        backbufferTypedDesc.Texture2D.MipSlice = 0;
        pUAVDesc = &backbufferTypedDesc;
      }
  
      // if we have a descriptor but it specifies DXGI_FORMAT_UNKNOWN format, that means use
      // the texture's format. But as above, we fudge around the typeless backbuffer so we
      // have to set the correct typed format
      //
      // This behaviour is documented only for render targets, but seems to be used & work for
      // UAVs, so apply it here too.
      if(pUAVDesc && pUAVDesc->Format == DXGI_FORMAT_UNKNOWN &&
         WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        pUAVDesc->Format = tex2d->m_RealDescriptor->Format;
      }
  
      HRESULT hr = m_pDevice->CreateUnorderedAccessView(UnwrapResource(pResource), pUAVDesc, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11UnorderedAccessView1(ret, pResource, this);
  
        GetResourceManager()->AddLiveResource(pView, ret);
      }
  
      AddResource(pView, ResourceType::View, "Unordered Access View");
      DerivedResource(pResource, pView);
  
      {
        D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
        ret->GetDesc(&desc);
  
        if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER &&
           (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER)))
        {
          ResourceId counterBuffer = GetDebugManager()->AddCounterUAVBuffer(ret);
          AddResource(counterBuffer, ResourceType::Buffer, "UAV Counter");
          DerivedResource(ret, counterBuffer);
        }
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateUnorderedAccessView(ID3D11Resource *pResource,
                                                         const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc,
                                                         ID3D11UnorderedAccessView **ppUAView)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppUAView == NULL)
      return m_pDevice->CreateUnorderedAccessView(UnwrapResource(pResource), pDesc, NULL);
  
    ID3D11UnorderedAccessView *real = NULL;
    ID3D11UnorderedAccessView *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateUnorderedAccessView(UnwrapResource(pResource), pDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11UnorderedAccessView1(real, pResource, this);
  
      Chunk *chunk = NULL;
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateUnorderedAccessView);
        Serialise_CreateUnorderedAccessView(GET_SERIALISER, pResource, pDesc, &wrapped);
  
        chunk = scope.Get();
  
        {
          D3D11ResourceRecord *parent =
              GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(pResource));
  
          RDCASSERT(parent);
  
          WrappedID3D11UnorderedAccessView1 *view = (WrappedID3D11UnorderedAccessView1 *)wrapped;
          ResourceId id = view->GetResourceID();
  
          RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
          D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
          record->Length = 0;
  
          record->AddParent(parent);
  
          record->AddChunk(chunk);
  
          // if this UAV has a hidden counter, immediately mark it as dirty so we force initial
          // contents to fetch its counter
          if(pDesc && pDesc->ViewDimension == D3D11_UAV_DIMENSION_BUFFER &&
             (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_COUNTER | D3D11_BUFFER_UAV_FLAG_APPEND)) != 0)
          {
            GetResourceManager()->MarkDirtyResource(id);
          }
        }
      }
  
      *ppUAView = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateRenderTargetView(SerialiserType &ser,
                                                             ID3D11Resource *pResource,
                                                             const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,
                                                             ID3D11RenderTargetView **ppRTView)
  {
    SERIALISE_ELEMENT(pResource).Important();
    SERIALISE_ELEMENT_OPT(pDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pView, GetIDForDeviceChild(*ppRTView))
        .TypedAs("ID3D11RenderTargetView *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pResource)
    {
      ID3D11RenderTargetView *ret;
  
      D3D11_RENDER_TARGET_VIEW_DESC *pRTVDesc = (D3D11_RENDER_TARGET_VIEW_DESC *)pDesc;
  
      WrappedID3D11Texture2D1 *tex2d = (WrappedID3D11Texture2D1 *)pResource;
  
      D3D11_RENDER_TARGET_VIEW_DESC backbufferTypedDesc;
  
      // need to fixup typeless backbuffer fudging, if a descriptor isn't specified then
      // we need to make one to give the correct type
      if(!pDesc && WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        backbufferTypedDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
  
        if(tex2d->m_RealDescriptor->SampleDesc.Quality > 0 ||
           tex2d->m_RealDescriptor->SampleDesc.Count > 1)
          backbufferTypedDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
  
        backbufferTypedDesc.Format = tex2d->m_RealDescriptor->Format;
        backbufferTypedDesc.Texture2D.MipSlice = 0;
        pRTVDesc = &backbufferTypedDesc;
      }
  
      // if we have a descriptor but it specifies DXGI_FORMAT_UNKNOWN format, that means use
      // the texture's format. But as above, we fudge around the typeless backbuffer so we
      // have to set the correct typed format
      if(pRTVDesc && pRTVDesc->Format == DXGI_FORMAT_UNKNOWN &&
         WrappedID3D11Texture2D1::IsAlloc(pResource) && tex2d->m_RealDescriptor)
      {
        pRTVDesc->Format = tex2d->m_RealDescriptor->Format;
      }
  
      HRESULT hr = m_pDevice->CreateRenderTargetView(UnwrapResource(pResource), pRTVDesc, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11RenderTargetView1(ret, pResource, this);
  
        GetResourceManager()->AddLiveResource(pView, ret);
      }
  
      AddResource(pView, ResourceType::View, "Render Target View");
      DerivedResource(pResource, pView);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateRenderTargetView(ID3D11Resource *pResource,
                                                      const D3D11_RENDER_TARGET_VIEW_DESC *pDesc,
                                                      ID3D11RenderTargetView **ppRTView)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppRTView == NULL)
      return m_pDevice->CreateRenderTargetView(UnwrapResource(pResource), pDesc, NULL);
  
    ID3D11RenderTargetView *real = NULL;
    ID3D11RenderTargetView *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateRenderTargetView(UnwrapResource(pResource), pDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11RenderTargetView1(real, pResource, this);
  
      Chunk *chunk = NULL;
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateRenderTargetView);
        Serialise_CreateRenderTargetView(GET_SERIALISER, pResource, pDesc, &wrapped);
  
        chunk = scope.Get();
  
        {
          D3D11ResourceRecord *parent =
              GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(pResource));
  
          RDCASSERT(parent);
  
          WrappedID3D11RenderTargetView1 *view = (WrappedID3D11RenderTargetView1 *)wrapped;
          ResourceId id = view->GetResourceID();
  
          RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
          D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
          record->Length = 0;
  
          record->AddParent(parent);
  
          record->AddChunk(chunk);
        }
      }
  
      *ppRTView = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateDepthStencilView(
      SerialiserType &ser, ID3D11Resource *pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc,
      ID3D11DepthStencilView **ppDepthStencilView)
  {
    SERIALISE_ELEMENT(pResource).Important();
    SERIALISE_ELEMENT_OPT(pDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pView, GetIDForDeviceChild(*ppDepthStencilView))
        .TypedAs("ID3D11DepthStencilView *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pResource)
    {
      ID3D11DepthStencilView *ret;
  
      HRESULT hr = m_pDevice->CreateDepthStencilView(UnwrapResource(pResource), pDesc, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11DepthStencilView(ret, pResource, this);
  
        GetResourceManager()->AddLiveResource(pView, ret);
      }
  
      AddResource(pView, ResourceType::View, "Depth Stencil View");
      DerivedResource(pResource, pView);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateDepthStencilView(ID3D11Resource *pResource,
                                                      const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc,
                                                      ID3D11DepthStencilView **ppDepthStencilView)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppDepthStencilView == NULL)
      return m_pDevice->CreateDepthStencilView(UnwrapResource(pResource), pDesc, NULL);
  
    ID3D11DepthStencilView *real = NULL;
    ID3D11DepthStencilView *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateDepthStencilView(UnwrapResource(pResource), pDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11DepthStencilView(real, pResource, this);
  
      Chunk *chunk = NULL;
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateDepthStencilView);
        Serialise_CreateDepthStencilView(GET_SERIALISER, pResource, pDesc, &wrapped);
  
        chunk = scope.Get();
  
        {
          D3D11ResourceRecord *parent =
              GetResourceManager()->GetResourceRecord(GetIDForDeviceChild(pResource));
  
          RDCASSERT(parent);
  
          WrappedID3D11DepthStencilView *view = (WrappedID3D11DepthStencilView *)wrapped;
          ResourceId id = view->GetResourceID();
  
          RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
          D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
          record->Length = 0;
  
          record->AddParent(parent);
  
          record->AddChunk(chunk);
        }
      }
  
      *ppDepthStencilView = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateInputLayout(
      SerialiserType &ser, const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, UINT NumElements,
      const void *pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength_,
      ID3D11InputLayout **ppInputLayout)
  {
    SERIALISE_ELEMENT_ARRAY(pInputElementDescs, NumElements).Important();
    SERIALISE_ELEMENT(NumElements);
    SERIALISE_ELEMENT_ARRAY(pShaderBytecodeWithInputSignature, BytecodeLength_);
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT_LOCAL(pInputLayout, GetIDForDeviceChild(*ppInputLayout))
        .TypedAs("ID3D11InputLayout *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      // for no explicable reason, CreateInputLayout requires a descriptor pointer even if
      // NumElements==0.
      D3D11_INPUT_ELEMENT_DESC dummy = {};
      const D3D11_INPUT_ELEMENT_DESC *inputDescs = pInputElementDescs ? pInputElementDescs : &dummy;
  
      ID3D11InputLayout *ret = NULL;
      HRESULT hr = m_pDevice->CreateInputLayout(
          inputDescs, NumElements, pShaderBytecodeWithInputSignature, (SIZE_T)BytecodeLength, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11InputLayout(ret, this);
  
        GetResourceManager()->AddLiveResource(pInputLayout, ret);
      }
  
      AddResource(pInputLayout, ResourceType::StateObject, "Input Layout");
  
      if(NumElements > 0)
        m_LayoutDescs[ret] = rdcarray<D3D11_INPUT_ELEMENT_DESC>(pInputElementDescs, NumElements);
  
      if(BytecodeLength > 0 && pShaderBytecodeWithInputSignature)
        m_LayoutShaders[ret] = new WrappedShader(this, pInputLayout, GetIDForDeviceChild(ret),
                                                 (const byte *)pShaderBytecodeWithInputSignature,
                                                 (size_t)BytecodeLength);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
                                                 UINT NumElements,
                                                 const void *pShaderBytecodeWithInputSignature,
                                                 SIZE_T BytecodeLength,
                                                 ID3D11InputLayout **ppInputLayout)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppInputLayout == NULL)
      return m_pDevice->CreateInputLayout(pInputElementDescs, NumElements,
                                          pShaderBytecodeWithInputSignature, BytecodeLength, NULL);
  
    ID3D11InputLayout *real = NULL;
    ID3D11InputLayout *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateInputLayout(pInputElementDescs, NumElements,
                                                           pShaderBytecodeWithInputSignature,
                                                           BytecodeLength, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11InputLayout(real, this);
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateInputLayout);
        Serialise_CreateInputLayout(GET_SERIALISER, pInputElementDescs, NumElements,
                                    pShaderBytecodeWithInputSignature, BytecodeLength, &wrapped);
  
        WrappedID3D11InputLayout *lay = (WrappedID3D11InputLayout *)wrapped;
        ResourceId id = lay->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
    }
  
    *ppInputLayout = wrapped;
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateVertexShader(SerialiserType &ser,
                                                         const void *pShaderBytecode,
                                                         SIZE_T BytecodeLength_,
                                                         ID3D11ClassLinkage *pClassLinkage,
                                                         ID3D11VertexShader **ppVertexShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppVertexShader))
        .TypedAs("ID3D11VertexShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11VertexShader *ret;
      HRESULT hr =
          m_pDevice->CreateVertexShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                        UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11VertexShader>(ret, pShader, (const byte *)pShaderBytecode,
                                                          (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Vertex Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11VertexShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateVertexShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                  ID3D11ClassLinkage *pClassLinkage,
                                                  ID3D11VertexShader **ppVertexShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppVertexShader == NULL)
      return m_pDevice->CreateVertexShader(pShaderBytecode, BytecodeLength,
                                           UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11VertexShader *real = NULL;
    ID3D11VertexShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateVertexShader(pShaderBytecode, BytecodeLength,
                                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11VertexShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateVertexShader);
        Serialise_CreateVertexShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                     &wrapped);
  
        WrappedID3D11Shader<ID3D11VertexShader> *sh =
            (WrappedID3D11Shader<ID3D11VertexShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11VertexShader> *w = (WrappedID3D11Shader<ID3D11VertexShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppVertexShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateGeometryShader(SerialiserType &ser,
                                                           const void *pShaderBytecode,
                                                           SIZE_T BytecodeLength_,
                                                           ID3D11ClassLinkage *pClassLinkage,
                                                           ID3D11GeometryShader **ppGeometryShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppGeometryShader))
        .TypedAs("ID3D11GeometryShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11GeometryShader *ret;
      HRESULT hr =
          m_pDevice->CreateGeometryShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                          UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11GeometryShader>(
            ret, pShader, (const byte *)pShaderBytecode, (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Geometry Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11GeometryShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateGeometryShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                    ID3D11ClassLinkage *pClassLinkage,
                                                    ID3D11GeometryShader **ppGeometryShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppGeometryShader == NULL)
      return m_pDevice->CreateGeometryShader(pShaderBytecode, BytecodeLength,
                                             UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11GeometryShader *real = NULL;
    ID3D11GeometryShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateGeometryShader(
                            pShaderBytecode, BytecodeLength,
                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11GeometryShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateGeometryShader);
        Serialise_CreateGeometryShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                       &wrapped);
  
        WrappedID3D11Shader<ID3D11GeometryShader> *sh =
            (WrappedID3D11Shader<ID3D11GeometryShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11GeometryShader> *w =
            (WrappedID3D11Shader<ID3D11GeometryShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppGeometryShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateGeometryShaderWithStreamOutput(
      SerialiserType &ser, const void *pShaderBytecode, SIZE_T BytecodeLength_,
      const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT NumEntries, const UINT *pBufferStrides,
      UINT NumStrides, UINT RasterizedStream, ID3D11ClassLinkage *pClassLinkage,
      ID3D11GeometryShader **ppGeometryShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT_ARRAY(pSODeclaration, NumEntries).Important();
    SERIALISE_ELEMENT(NumEntries);
    SERIALISE_ELEMENT_ARRAY(pBufferStrides, NumStrides);
    SERIALISE_ELEMENT(NumStrides);
    SERIALISE_ELEMENT(RasterizedStream);
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppGeometryShader))
        .TypedAs("ID3D11GeometryShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11GeometryShader *ret;
      HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput(
          pShaderBytecode, (SIZE_T)BytecodeLength, pSODeclaration, NumEntries, pBufferStrides,
          NumStrides, RasterizedStream, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11GeometryShader>(
            ret, pShader, (const byte *)pShaderBytecode, (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Geometry Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11GeometryShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateGeometryShaderWithStreamOutput(
      const void *pShaderBytecode, SIZE_T BytecodeLength,
      const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT NumEntries, const UINT *pBufferStrides,
      UINT NumStrides, UINT RasterizedStream, ID3D11ClassLinkage *pClassLinkage,
      ID3D11GeometryShader **ppGeometryShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppGeometryShader == NULL)
      return m_pDevice->CreateGeometryShaderWithStreamOutput(
          pShaderBytecode, BytecodeLength, pSODeclaration, NumEntries, pBufferStrides, NumStrides,
          RasterizedStream, UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11GeometryShader *real = NULL;
    ID3D11GeometryShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateGeometryShaderWithStreamOutput(
                            pShaderBytecode, BytecodeLength, pSODeclaration, NumEntries,
                            pBufferStrides, NumStrides, RasterizedStream,
                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11GeometryShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateGeometryShaderWithStreamOutput);
        Serialise_CreateGeometryShaderWithStreamOutput(
            GET_SERIALISER, pShaderBytecode, BytecodeLength, pSODeclaration, NumEntries,
            pBufferStrides, NumStrides, RasterizedStream, pClassLinkage, &wrapped);
  
        WrappedID3D11Shader<ID3D11GeometryShader> *sh =
            (WrappedID3D11Shader<ID3D11GeometryShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11GeometryShader> *w =
            (WrappedID3D11Shader<ID3D11GeometryShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppGeometryShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreatePixelShader(SerialiserType &ser,
                                                        const void *pShaderBytecode,
                                                        SIZE_T BytecodeLength_,
                                                        ID3D11ClassLinkage *pClassLinkage,
                                                        ID3D11PixelShader **ppPixelShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppPixelShader))
        .TypedAs("ID3D11PixelShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11PixelShader *ret;
      HRESULT hr = m_pDevice->CreatePixelShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                                UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11PixelShader>(ret, pShader, (const byte *)pShaderBytecode,
                                                         (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Pixel Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11PixelShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreatePixelShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                 ID3D11ClassLinkage *pClassLinkage,
                                                 ID3D11PixelShader **ppPixelShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppPixelShader == NULL)
      return m_pDevice->CreatePixelShader(pShaderBytecode, BytecodeLength,
                                          UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11PixelShader *real = NULL;
    ID3D11PixelShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreatePixelShader(pShaderBytecode, BytecodeLength,
                                           UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11PixelShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreatePixelShader);
        Serialise_CreatePixelShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                    &wrapped);
  
        WrappedID3D11Shader<ID3D11PixelShader> *sh = (WrappedID3D11Shader<ID3D11PixelShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11PixelShader> *w = (WrappedID3D11Shader<ID3D11PixelShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppPixelShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateHullShader(SerialiserType &ser, const void *pShaderBytecode,
                                                       SIZE_T BytecodeLength_,
                                                       ID3D11ClassLinkage *pClassLinkage,
                                                       ID3D11HullShader **ppHullShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppHullShader))
        .TypedAs("ID3D11HullShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11HullShader *ret;
      HRESULT hr = m_pDevice->CreateHullShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                               UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11HullShader>(ret, pShader, (const byte *)pShaderBytecode,
                                                        (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Hull Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11HullShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateHullShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                ID3D11ClassLinkage *pClassLinkage,
                                                ID3D11HullShader **ppHullShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppHullShader == NULL)
      return m_pDevice->CreateHullShader(pShaderBytecode, BytecodeLength,
                                         UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11HullShader *real = NULL;
    ID3D11HullShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateHullShader(pShaderBytecode, BytecodeLength,
                                          UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11HullShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateHullShader);
        Serialise_CreateHullShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                   &wrapped);
  
        WrappedID3D11Shader<ID3D11HullShader> *sh = (WrappedID3D11Shader<ID3D11HullShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11HullShader> *w = (WrappedID3D11Shader<ID3D11HullShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppHullShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateDomainShader(SerialiserType &ser,
                                                         const void *pShaderBytecode,
                                                         SIZE_T BytecodeLength_,
                                                         ID3D11ClassLinkage *pClassLinkage,
                                                         ID3D11DomainShader **ppDomainShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppDomainShader))
        .TypedAs("ID3D11DomainShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11DomainShader *ret;
      HRESULT hr =
          m_pDevice->CreateDomainShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                        UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11DomainShader>(ret, pShader, (const byte *)pShaderBytecode,
                                                          (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Domain Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11DomainShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateDomainShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                  ID3D11ClassLinkage *pClassLinkage,
                                                  ID3D11DomainShader **ppDomainShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppDomainShader == NULL)
      return m_pDevice->CreateDomainShader(pShaderBytecode, BytecodeLength,
                                           UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11DomainShader *real = NULL;
    ID3D11DomainShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(
        ret = m_pDevice->CreateDomainShader(pShaderBytecode, BytecodeLength,
                                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11DomainShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateDomainShader);
        Serialise_CreateDomainShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                     &wrapped);
  
        WrappedID3D11Shader<ID3D11DomainShader> *sh =
            (WrappedID3D11Shader<ID3D11DomainShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11DomainShader> *w = (WrappedID3D11Shader<ID3D11DomainShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppDomainShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateComputeShader(SerialiserType &ser,
                                                          const void *pShaderBytecode,
                                                          SIZE_T BytecodeLength_,
                                                          ID3D11ClassLinkage *pClassLinkage,
                                                          ID3D11ComputeShader **ppComputeShader)
  {
    SERIALISE_ELEMENT_ARRAY(pShaderBytecode, BytecodeLength_).Important();
    SERIALISE_ELEMENT_LOCAL(BytecodeLength, uint64_t(BytecodeLength_));
    SERIALISE_ELEMENT(pClassLinkage);
    SERIALISE_ELEMENT_LOCAL(pShader, GetIDForDeviceChild(*ppComputeShader))
        .TypedAs("ID3D11ComputeShader *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11ComputeShader *ret;
      HRESULT hr =
          m_pDevice->CreateComputeShader(pShaderBytecode, (SIZE_T)BytecodeLength,
                                         UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Shader<ID3D11ComputeShader>(
            ret, pShader, (const byte *)pShaderBytecode, (size_t)BytecodeLength, this);
  
        GetResourceManager()->AddLiveResource(pShader, ret);
      }
  
      AddResource(pShader, ResourceType::Shader, "Compute Shader");
      // if this shader was initialised with a shader ext UAV, pull in that chunk as one of ours
      // and unset it (there will be one for each create that actually used vendor extensions)
      if(m_GlobalEXTUAV != ~0U)
      {
        // set the UAV slot used, for post-processing DXBC
        ((WrappedID3D11Shader<ID3D11ComputeShader> *)ret)->SetShaderExtSlot(m_GlobalEXTUAV);
        GetResourceDesc(pShader).initialisationChunks.push_back(
            (uint32_t)m_StructuredFile->chunks.size() - 2);
        m_GlobalEXTUAV = ~0U;
      }
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateComputeShader(const void *pShaderBytecode, SIZE_T BytecodeLength,
                                                   ID3D11ClassLinkage *pClassLinkage,
                                                   ID3D11ComputeShader **ppComputeShader)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppComputeShader == NULL)
      return m_pDevice->CreateComputeShader(pShaderBytecode, BytecodeLength,
                                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), NULL);
  
    ID3D11ComputeShader *real = NULL;
    ID3D11ComputeShader *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateComputeShader(
                            pShaderBytecode, BytecodeLength,
                            UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage), &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Shader<ID3D11ComputeShader>(
          real, ResourceId(), (const byte *)pShaderBytecode, BytecodeLength, this);
  
      if(IsCaptureMode(m_State))
      {
        Chunk *vendorChunk = NULL;
        if(m_VendorEXT != GPUVendor::Unknown)
        {
          uint32_t slot = GetShaderExtUAV();
  
          if(DXBC::DXBCContainer::UsesExtensionUAV(slot, ~0U, pShaderBytecode, BytecodeLength))
          {
            // don't set initparams until we've seen at least one shader actually created using the
            // extensions.
            m_InitParams.VendorExtensions = m_VendorEXT;
  
            // if this shader uses the UAV slot registered for vendor extensions, serialise that out
            // too
            USE_SCRATCH_SERIALISER();
            SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetShaderExtUAV);
            Serialise_SetShaderExtUAV(GET_SERIALISER, m_VendorEXT, slot, true);
            vendorChunk = scope.Get();
          }
        }
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateComputeShader);
        Serialise_CreateComputeShader(GET_SERIALISER, pShaderBytecode, BytecodeLength, pClassLinkage,
                                      &wrapped);
  
        WrappedID3D11Shader<ID3D11ComputeShader> *sh =
            (WrappedID3D11Shader<ID3D11ComputeShader> *)wrapped;
        ResourceId id = sh->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        if(vendorChunk)
          record->AddChunk(vendorChunk);
        record->AddChunk(scope.Get());
      }
      else
      {
        WrappedID3D11Shader<ID3D11ComputeShader> *w =
            (WrappedID3D11Shader<ID3D11ComputeShader> *)wrapped;
  
        if(m_GlobalEXTUAV != ~0U)
          w->SetShaderExtSlot(m_GlobalEXTUAV);
  
        GetResourceManager()->AddLiveResource(w->GetResourceID(), wrapped);
      }
  
      *ppComputeShader = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  // Class Linkage 'fake' interfaces
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateClassInstance(SerialiserType &ser, LPCSTR pClassTypeName,
                                                          UINT ConstantBufferOffset,
                                                          UINT ConstantVectorOffset,
                                                          UINT TextureOffset, UINT SamplerOffset,
                                                          ID3D11ClassLinkage *pClassLinkage,
                                                          ID3D11ClassInstance **ppInstance)
  {
    SERIALISE_ELEMENT(pClassTypeName).Important();
    SERIALISE_ELEMENT(ConstantBufferOffset);
    SERIALISE_ELEMENT(ConstantVectorOffset);
    SERIALISE_ELEMENT(TextureOffset);
    SERIALISE_ELEMENT(SamplerOffset);
    SERIALISE_ELEMENT(pClassLinkage).Important();
    SERIALISE_ELEMENT_LOCAL(pInstance, GetIDForDeviceChild(*ppInstance))
        .TypedAs("ID3D11ClassInstance *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pClassLinkage)
    {
      ID3D11ClassInstance *real = NULL;
      ID3D11ClassInstance *wrapped = NULL;
      HRESULT hr = UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage)
                       ->CreateClassInstance(pClassTypeName, ConstantBufferOffset,
                                             ConstantVectorOffset, TextureOffset, SamplerOffset, &real);
  
      APIProps.ShaderLinkage = true;
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        FlushPendingDead();
        wrapped = new WrappedID3D11ClassInstance(real, pClassLinkage, this);
  
        GetResourceManager()->AddLiveResource(pInstance, wrapped);
      }
  
      AddResource(pInstance, ResourceType::ShaderBinding, "Class Instance");
      DerivedResource(pClassLinkage, pInstance);
    }
  
    return true;
  }
  
  ID3D11ClassInstance *WrappedID3D11Device::CreateClassInstance(
      LPCSTR pClassTypeName, UINT ConstantBufferOffset, UINT ConstantVectorOffset, UINT TextureOffset,
      UINT SamplerOffset, ID3D11ClassLinkage *pClassLinkage, ID3D11ClassInstance **ppInstance)
  {
    ID3D11ClassInstance *wrapped = NULL;
  
    if(IsCaptureMode(m_State))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11ClassInstance(*ppInstance, pClassLinkage, this);
  
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateClassInstance);
        Serialise_CreateClassInstance(GET_SERIALISER, pClassTypeName, ConstantBufferOffset,
                                      ConstantVectorOffset, TextureOffset, SamplerOffset,
                                      pClassLinkage, &wrapped);
  
        m_DeviceRecord->AddChunk(scope.Get());
      }
  
      return wrapped;
    }
  
    RDCERR("Creating class instances while not in capture mode!");
    return NULL;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_GetClassInstance(SerialiserType &ser, LPCSTR pClassInstanceName,
                                                       UINT InstanceIndex,
                                                       ID3D11ClassLinkage *pClassLinkage,
                                                       ID3D11ClassInstance **ppInstance)
  {
    SERIALISE_ELEMENT(pClassInstanceName).Important();
    SERIALISE_ELEMENT(InstanceIndex);
    SERIALISE_ELEMENT(pClassLinkage).Important();
    SERIALISE_ELEMENT_LOCAL(pInstance, GetIDForDeviceChild(*ppInstance))
        .TypedAs("ID3D11ClassInstance *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading() && pClassLinkage)
    {
      ID3D11ClassInstance *real = NULL;
      ID3D11ClassInstance *wrapped = NULL;
      HRESULT hr = UNWRAP(WrappedID3D11ClassLinkage, pClassLinkage)
                       ->GetClassInstance(pClassInstanceName, InstanceIndex, &real);
  
      APIProps.ShaderLinkage = true;
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        FlushPendingDead();
        wrapped = new WrappedID3D11ClassInstance(real, pClassLinkage, this);
  
        GetResourceManager()->AddLiveResource(pInstance, wrapped);
      }
  
      AddResource(pInstance, ResourceType::ShaderBinding, "Class Instance");
      DerivedResource(pClassLinkage, pInstance);
    }
  
    return true;
  }
  
  ID3D11ClassInstance *WrappedID3D11Device::GetClassInstance(LPCSTR pClassInstanceName,
                                                             UINT InstanceIndex,
                                                             ID3D11ClassLinkage *pClassLinkage,
                                                             ID3D11ClassInstance **ppInstance)
  {
    ID3D11ClassInstance *wrapped = NULL;
  
    if(IsCaptureMode(m_State))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11ClassInstance(*ppInstance, pClassLinkage, this);
  
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::GetClassInstance);
        Serialise_GetClassInstance(GET_SERIALISER, pClassInstanceName, InstanceIndex, pClassLinkage,
                                   &wrapped);
  
        m_DeviceRecord->AddChunk(scope.Get());
      }
  
      return wrapped;
    }
  
    RDCERR("Creating class instances while not in capture mode!");
    return NULL;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateClassLinkage(SerialiserType &ser,
                                                         ID3D11ClassLinkage **ppLinkage)
  {
    SERIALISE_ELEMENT_LOCAL(pLinkage, GetIDForDeviceChild(*ppLinkage))
        .TypedAs("ID3D11ClassLinkage *"_lit)
        .Unimportant();
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11ClassLinkage *ret;
      HRESULT hr = m_pDevice->CreateClassLinkage(&ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11ClassLinkage(ret, this);
  
        GetResourceManager()->AddLiveResource(pLinkage, ret);
      }
  
      AddResource(pLinkage, ResourceType::ShaderBinding, "Class Linkage");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateClassLinkage(ID3D11ClassLinkage **ppLinkage)
  {
    // get 'real' return value for NULL parameter
    if(ppLinkage == NULL)
      return m_pDevice->CreateClassLinkage(NULL);
  
    ID3D11ClassLinkage *real = NULL;
    ID3D11ClassLinkage *wrapped = NULL;
    HRESULT ret = m_pDevice->CreateClassLinkage(&real);
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11ClassLinkage(real, this);
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateClassLinkage);
        Serialise_CreateClassLinkage(GET_SERIALISER, &wrapped);
  
        m_DeviceRecord->AddChunk(scope.Get());
      }
  
      *ppLinkage = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateBlendState(SerialiserType &ser,
                                                       const D3D11_BLEND_DESC *pBlendStateDesc,
                                                       ID3D11BlendState **ppBlendState)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pBlendStateDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pState, GetIDForDeviceChild(*ppBlendState))
        .TypedAs("ID3D11BlendState *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11BlendState *ret;
      HRESULT hr = m_pDevice->CreateBlendState(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        if(GetResourceManager()->HasWrapper(ret))
        {
          ret->Release();
          ret = (ID3D11BlendState *)GetResourceManager()->GetWrapper(ret);
          ret->AddRef();
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
        else
        {
          ret = new WrappedID3D11BlendState1(ret, this);
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
      }
  
      AddResource(pState, ResourceType::StateObject, "Blend State");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateBlendState(const D3D11_BLEND_DESC *pBlendStateDesc,
                                                ID3D11BlendState **ppBlendState)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppBlendState == NULL)
      return m_pDevice->CreateBlendState(pBlendStateDesc, NULL);
  
    ID3D11BlendState *real = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateBlendState(pBlendStateDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      // need to flush pending dead now so we don't find a 'dead' wrapper below
      FlushPendingDead();
  
      // duplicate states can be returned, if Create is called with a previous descriptor
      if(GetResourceManager()->HasWrapper(real))
      {
        real->Release();
        *ppBlendState = (ID3D11BlendState *)GetResourceManager()->GetWrapper(real);
        Resurrect(*ppBlendState);
        (*ppBlendState)->AddRef();
        return ret;
      }
  
      FlushPendingDead();
      ID3D11BlendState *wrapped = new WrappedID3D11BlendState1(real, this);
  
      CachedObjectsGarbageCollect();
  
      {
        RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end());
        // add an internal reference too just so if the application creates and destroys state objects
        // at high frequency we keep it around.
        IntAddRef(wrapped);
        m_CachedStateObjects.insert(wrapped);
      }
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateBlendState);
        Serialise_CreateBlendState(GET_SERIALISER, pBlendStateDesc, &wrapped);
  
        WrappedID3D11BlendState1 *st = (WrappedID3D11BlendState1 *)wrapped;
        ResourceId id = st->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppBlendState = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateDepthStencilState(
      SerialiserType &ser, const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc,
      ID3D11DepthStencilState **ppDepthStencilState)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pDepthStencilDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pState, GetIDForDeviceChild(*ppDepthStencilState))
        .TypedAs("ID3D11DepthStencilState *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11DepthStencilState *ret;
      HRESULT hr = m_pDevice->CreateDepthStencilState(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        if(GetResourceManager()->HasWrapper(ret))
        {
          ret->Release();
          ret = (ID3D11DepthStencilState *)GetResourceManager()->GetWrapper(ret);
          ret->AddRef();
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
        else
        {
          ret = new WrappedID3D11DepthStencilState(ret, this);
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
      }
  
      AddResource(pState, ResourceType::StateObject, "Depth-Stencil State");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateDepthStencilState(const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc,
                                                       ID3D11DepthStencilState **ppDepthStencilState)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppDepthStencilState == NULL)
      return m_pDevice->CreateDepthStencilState(pDepthStencilDesc, NULL);
  
    ID3D11DepthStencilState *real = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateDepthStencilState(pDepthStencilDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      // need to flush pending dead now so we don't find a 'dead' wrapper below
      FlushPendingDead();
  
      // duplicate states can be returned, if Create is called with a previous descriptor
      if(GetResourceManager()->HasWrapper(real))
      {
        real->Release();
        *ppDepthStencilState = (ID3D11DepthStencilState *)GetResourceManager()->GetWrapper(real);
        Resurrect(*ppDepthStencilState);
        (*ppDepthStencilState)->AddRef();
        return ret;
      }
  
      FlushPendingDead();
      ID3D11DepthStencilState *wrapped = new WrappedID3D11DepthStencilState(real, this);
  
      CachedObjectsGarbageCollect();
  
      {
        RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end());
        IntAddRef(wrapped);
        m_CachedStateObjects.insert(wrapped);
      }
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateDepthStencilState);
        Serialise_CreateDepthStencilState(GET_SERIALISER, pDepthStencilDesc, &wrapped);
  
        WrappedID3D11DepthStencilState *st = (WrappedID3D11DepthStencilState *)wrapped;
        ResourceId id = st->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppDepthStencilState = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateRasterizerState(SerialiserType &ser,
                                                            const D3D11_RASTERIZER_DESC *pRasterizerDesc,
                                                            ID3D11RasterizerState **ppRasterizerState)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pRasterizerDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pState, GetIDForDeviceChild(*ppRasterizerState))
        .TypedAs("ID3D11RasterizerState *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11RasterizerState *ret;
      HRESULT hr = m_pDevice->CreateRasterizerState(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        if(GetResourceManager()->HasWrapper(ret))
        {
          ret->Release();
          ret = (ID3D11RasterizerState *)GetResourceManager()->GetWrapper(ret);
          ret->AddRef();
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
        else
        {
          ret = new WrappedID3D11RasterizerState2(ret, this);
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
      }
  
      AddResource(pState, ResourceType::StateObject, "Rasterizer State");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateRasterizerState(const D3D11_RASTERIZER_DESC *pRasterizerDesc,
                                                     ID3D11RasterizerState **ppRasterizerState)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppRasterizerState == NULL)
      return m_pDevice->CreateRasterizerState(pRasterizerDesc, NULL);
  
    ID3D11RasterizerState *real = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateRasterizerState(pRasterizerDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      // need to flush pending dead now so we don't find a 'dead' wrapper below
      FlushPendingDead();
  
      // duplicate states can be returned, if Create is called with a previous descriptor
      if(GetResourceManager()->HasWrapper(real))
      {
        real->Release();
        *ppRasterizerState = (ID3D11RasterizerState *)GetResourceManager()->GetWrapper(real);
        Resurrect(*ppRasterizerState);
        (*ppRasterizerState)->AddRef();
        return ret;
      }
  
      FlushPendingDead();
      ID3D11RasterizerState *wrapped = new WrappedID3D11RasterizerState2(real, this);
  
      CachedObjectsGarbageCollect();
  
      {
        RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end());
        IntAddRef(wrapped);
        m_CachedStateObjects.insert(wrapped);
      }
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateRasterizerState);
        Serialise_CreateRasterizerState(GET_SERIALISER, pRasterizerDesc, &wrapped);
  
        WrappedID3D11RasterizerState2 *st = (WrappedID3D11RasterizerState2 *)wrapped;
        ResourceId id = st->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppRasterizerState = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateSamplerState(SerialiserType &ser,
                                                         const D3D11_SAMPLER_DESC *pSamplerDesc,
                                                         ID3D11SamplerState **ppSamplerState)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pSamplerDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pState, GetIDForDeviceChild(*ppSamplerState))
        .TypedAs("ID3D11SamplerState *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11SamplerState *ret;
      HRESULT hr = m_pDevice->CreateSamplerState(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        if(GetResourceManager()->HasWrapper(ret))
        {
          ret->Release();
          ret = (ID3D11SamplerState *)GetResourceManager()->GetWrapper(ret);
          ret->AddRef();
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
        else
        {
          ret = new WrappedID3D11SamplerState(ret, this);
  
          GetResourceManager()->AddLiveResource(pState, ret);
        }
      }
  
      AddResource(pState, ResourceType::Sampler, "Sampler State");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateSamplerState(const D3D11_SAMPLER_DESC *pSamplerDesc,
                                                  ID3D11SamplerState **ppSamplerState)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppSamplerState == NULL)
      return m_pDevice->CreateSamplerState(pSamplerDesc, NULL);
  
    ID3D11SamplerState *real = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateSamplerState(pSamplerDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      // need to flush pending dead now so we don't find a 'dead' wrapper below
      FlushPendingDead();
  
      // duplicate states can be returned, if Create is called with a previous descriptor
      if(GetResourceManager()->HasWrapper(real))
      {
        real->Release();
        *ppSamplerState = (ID3D11SamplerState *)GetResourceManager()->GetWrapper(real);
        Resurrect(*ppSamplerState);
        (*ppSamplerState)->AddRef();
        return ret;
      }
  
      FlushPendingDead();
      ID3D11SamplerState *wrapped = new WrappedID3D11SamplerState(real, this);
  
      CachedObjectsGarbageCollect();
  
      {
        RDCASSERT(m_CachedStateObjects.find(wrapped) == m_CachedStateObjects.end());
        IntAddRef(wrapped);
        m_CachedStateObjects.insert(wrapped);
      }
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateSamplerState);
        Serialise_CreateSamplerState(GET_SERIALISER, pSamplerDesc, &wrapped);
  
        WrappedID3D11SamplerState *st = (WrappedID3D11SamplerState *)wrapped;
        ResourceId id = st->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppSamplerState = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateQuery(SerialiserType &ser,
                                                  const D3D11_QUERY_DESC *pQueryDesc,
                                                  ID3D11Query **ppQuery)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pQueryDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pQuery, GetIDForDeviceChild(*ppQuery)).TypedAs("ID3D11Query *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11Query *ret;
      HRESULT hr = m_pDevice->CreateQuery(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Query1(ret, this);
  
        GetResourceManager()->AddLiveResource(pQuery, ret);
      }
  
      AddResource(pQuery, ResourceType::Query, "Query");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateQuery(const D3D11_QUERY_DESC *pQueryDesc, ID3D11Query **ppQuery)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppQuery == NULL)
      return m_pDevice->CreateQuery(pQueryDesc, NULL);
  
    ID3D11Query *real = NULL;
    ID3D11Query *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateQuery(pQueryDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Query1(real, this);
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateQuery);
        Serialise_CreateQuery(GET_SERIALISER, pQueryDesc, &wrapped);
  
        WrappedID3D11Query1 *q = (WrappedID3D11Query1 *)wrapped;
        ResourceId id = q->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppQuery = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreatePredicate(SerialiserType &ser,
                                                      const D3D11_QUERY_DESC *pPredicateDesc,
                                                      ID3D11Predicate **ppPredicate)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pPredicateDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pPredicate, GetIDForDeviceChild(*ppPredicate))
        .TypedAs("ID3D11Predicate *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      // We don't use predicates directly, so removing this flag doesn't make any direct difference.
      // It means we can query the result via GetData which we can't if the flag is set.
      Descriptor.MiscFlags &= ~D3D11_QUERY_MISC_PREDICATEHINT;
  
      ID3D11Predicate *ret;
      HRESULT hr = m_pDevice->CreatePredicate(&Descriptor, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Predicate(ret, this);
  
        GetResourceManager()->AddLiveResource(pPredicate, ret);
      }
  
      AddResource(pPredicate, ResourceType::Query, "Predicate");
  
      // prime the predicate with a true result, so that if we end up referencing a predicate that was
      // filled in a previous frame that we don't have the data for, we default to passing.
      m_pImmediateContext->Begin(ret);
      m_DebugManager->RenderForPredicate();
      m_pImmediateContext->End(ret);
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreatePredicate(const D3D11_QUERY_DESC *pPredicateDesc,
                                               ID3D11Predicate **ppPredicate)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppPredicate == NULL)
      return m_pDevice->CreatePredicate(pPredicateDesc, NULL);
  
    ID3D11Predicate *real = NULL;
    ID3D11Predicate *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreatePredicate(pPredicateDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Predicate(real, this);
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreatePredicate);
        Serialise_CreatePredicate(GET_SERIALISER, pPredicateDesc, &wrapped);
  
        WrappedID3D11Predicate *p = (WrappedID3D11Predicate *)wrapped;
        ResourceId id = p->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppPredicate = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateCounter(SerialiserType &ser,
                                                    const D3D11_COUNTER_DESC *pCounterDesc,
                                                    ID3D11Counter **ppCounter)
  {
    SERIALISE_ELEMENT_LOCAL(Descriptor, *pCounterDesc).Important();
    SERIALISE_ELEMENT_LOCAL(pCounter, GetIDForDeviceChild(*ppCounter)).TypedAs("ID3D11Counter *"_lit);
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      // counters may not always be available on the replay, so instead we create a timestamp query as
      // a dummy. We never replay any counter fetch since it doesn't affect rendering, so the
      // difference doesn't matter.
      D3D11_QUERY_DESC dummyQueryDesc;
      dummyQueryDesc.Query = D3D11_QUERY_TIMESTAMP;
      dummyQueryDesc.MiscFlags = 0;
      ID3D11Query *ret;
      HRESULT hr = m_pDevice->CreateQuery(&dummyQueryDesc, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11Query1(ret, this);
  
        GetResourceManager()->AddLiveResource(pCounter, ret);
      }
  
      AddResource(pCounter, ResourceType::Query, "Counter");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateCounter(const D3D11_COUNTER_DESC *pCounterDesc,
                                             ID3D11Counter **ppCounter)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppCounter == NULL)
      return m_pDevice->CreateCounter(pCounterDesc, NULL);
  
    ID3D11Counter *real = NULL;
    ID3D11Counter *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateCounter(pCounterDesc, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      FlushPendingDead();
      wrapped = new WrappedID3D11Counter(real, this);
  
      if(IsCaptureMode(m_State))
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateCounter);
        Serialise_CreateCounter(GET_SERIALISER, pCounterDesc, &wrapped);
  
        WrappedID3D11Counter *c = (WrappedID3D11Counter *)wrapped;
        ResourceId id = c->GetResourceID();
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(id) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(id);
  
        record->Length = 0;
  
        record->AddChunk(scope.Get());
      }
  
      *ppCounter = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_CreateDeferredContext(SerialiserType &ser,
                                                            const UINT ContextFlags,
                                                            ID3D11DeviceContext **ppDeferredContext)
  {
    SERIALISE_ELEMENT(ContextFlags);
    SERIALISE_ELEMENT_LOCAL(pDeferredContext,
                            ((WrappedID3D11DeviceContext *)*ppDeferredContext)->GetResourceID())
        .TypedAs("ID3D11DeviceContext *"_lit)
        .Unimportant();
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
    {
      ID3D11DeviceContext *ret;
      HRESULT hr = m_pDevice->CreateDeferredContext(ContextFlags, &ret);
  
      if(FAILED(hr))
      {
        RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
        return false;
      }
      else
      {
        ret = new WrappedID3D11DeviceContext(this, ret);
  
        AddDeferredContext((WrappedID3D11DeviceContext *)ret);
  
        GetResourceManager()->AddLiveResource(pDeferredContext, ret);
      }
  
      AddResource(pDeferredContext, ResourceType::CommandBuffer, "Deferred Context");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::CreateDeferredContext(UINT ContextFlags,
                                                     ID3D11DeviceContext **ppDeferredContext)
  {
    // validation, returns S_FALSE for valid params, or an error code
    if(ppDeferredContext == NULL)
      return m_pDevice->CreateDeferredContext(ContextFlags, NULL);
  
    ID3D11DeviceContext *real = NULL;
    ID3D11DeviceContext *wrapped = NULL;
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->CreateDeferredContext(ContextFlags, &real));
  
    if(SUCCEEDED(ret))
    {
      SCOPED_LOCK(m_D3DLock);
  
      WrappedID3D11DeviceContext *w = new WrappedID3D11DeviceContext(this, real);
  
      w->GetScratchSerialiser().SetChunkMetadataRecording(
          m_ScratchSerialiser.GetChunkMetadataRecording());
  
      wrapped = w;
  
      if(IsActiveCapturing(m_State))
        w->AttemptCapture();
  
      if(IsCaptureMode(m_State))
      {
        AddDeferredContext(w);
  
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(D3D11Chunk::CreateDeferredContext);
        Serialise_CreateDeferredContext(GET_SERIALISER, ContextFlags, &wrapped);
  
        m_DeviceRecord->AddChunk(scope.Get());
      }
  
      *ppDeferredContext = wrapped;
    }
    else
    {
      CheckHRESULT(ret);
    }
  
    return ret;
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_OpenSharedResource(SerialiserType &ser, HANDLE,
                                                         REFIID ReturnedInterface, void **ppResource)
  {
    ID3D11DeviceChild *res = ser.IsWriting() ? (ID3D11DeviceChild *)*ppResource : NULL;
  
    SERIALISE_ELEMENT_LOCAL(Type, IdentifyTypeByPtr(res)).Important();
    SERIALISE_ELEMENT_LOCAL(pResource, GetIDForDeviceChild(res)).TypedAs("ID3D11DeviceChild *"_lit);
  
    if(Type == Resource_Buffer)
    {
      D3D11_BUFFER_DESC Descriptor;
      RDCEraseEl(Descriptor);
  
      byte *BufferContents = NULL;
  
      if(ser.IsWriting())
      {
        ID3D11Buffer *buf = (ID3D11Buffer *)res;
        buf->GetDesc(&Descriptor);
  
        // need to allocate record storage for this buffer
        BufferContents = new byte[Descriptor.ByteWidth];
      }
  
      SERIALISE_ELEMENT(Descriptor);
      SERIALISE_ELEMENT_ARRAY(BufferContents, Descriptor.ByteWidth);
  
      if(ser.IsWriting())
      {
        SAFE_DELETE_ARRAY(BufferContents);
  
        uint64_t offs = ser.GetWriter()->GetOffset() - Descriptor.ByteWidth;
  
        RDCASSERT((offs % 64) == 0);
  
        RDCASSERT(GetResourceManager()->GetResourceRecord(pResource) == NULL);
  
        D3D11ResourceRecord *record = GetResourceManager()->AddResourceRecord(pResource);
        record->SetDataOffset(offs);
        record->DataInSerialiser = true;
        record->Length = Descriptor.ByteWidth;
      }
  
      SERIALISE_CHECK_READ_ERRORS();
  
      if(IsReplayingAndReading())
      {
        ID3D11Buffer *ret;
  
        HRESULT hr = S_OK;
  
        // unset flags that are unimportant/problematic in replay
        MaskResourceMiscFlags(Descriptor.MiscFlags);
  
        D3D11_SUBRESOURCE_DATA data;
        data.pSysMem = BufferContents;
        data.SysMemPitch = Descriptor.ByteWidth;
        data.SysMemSlicePitch = Descriptor.ByteWidth;
        hr = m_pDevice->CreateBuffer(&Descriptor, &data, &ret);
  
        if(FAILED(hr))
        {
          RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
          return false;
        }
        else
        {
          ret = new WrappedID3D11Buffer(ret, Descriptor.ByteWidth, this);
  
          GetResourceManager()->AddLiveResource(pResource, ret);
        }
  
        AddResource(pResource, ResourceType::Buffer, "Shared Buffer");
  
        if(Descriptor.Usage != D3D11_USAGE_IMMUTABLE)
        {
          ID3D11Buffer *stage = NULL;
  
          UINT byteSize = Descriptor.ByteWidth;
  
          RDCEraseEl(Descriptor);
          Descriptor.ByteWidth = byteSize;
          Descriptor.MiscFlags = 0;
          Descriptor.StructureByteStride = 0;
          // We don't need to bind this, but IMMUTABLE requires at least one
          // BindFlags.
          Descriptor.BindFlags = D3D11_BIND_VERTEX_BUFFER;
          Descriptor.CPUAccessFlags = 0;
          Descriptor.Usage = D3D11_USAGE_IMMUTABLE;
  
          hr = m_pDevice->CreateBuffer(&Descriptor, &data, &stage);
  
          if(FAILED(hr) || stage == NULL)
          {
            RDCERR("Failed to create staging buffer for buffer initial contents HRESULT: %s",
                   ToStr(hr).c_str());
          }
          else
          {
            m_ResourceManager->SetInitialContents(pResource,
                                                  D3D11InitialContents(Resource_Buffer, stage));
          }
        }
      }
    }
    else if(Type == Resource_Texture1D)
    {
      D3D11_TEXTURE1D_DESC Descriptor;
      RDCEraseEl(Descriptor);
  
      ID3D11Texture1D *tex = (ID3D11Texture1D *)res;
  
      if(ser.IsWriting())
        tex->GetDesc(&Descriptor);
  
      SERIALISE_ELEMENT(Descriptor);
  
      Serialise_CreateTextureData(ser, tex, pResource, NULL, Descriptor.Width, 1, 1, Descriptor.Format,
                                  Descriptor.MipLevels, Descriptor.ArraySize, false);
  
      SERIALISE_CHECK_READ_ERRORS();
  
      if(IsReplayingAndReading())
      {
        ID3D11Texture1D *ret;
        HRESULT hr = S_OK;
  
        TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
        // unset flags that are unimportant/problematic in replay
        MaskResourceMiscFlags(Descriptor.MiscFlags);
  
        hr = m_pDevice->CreateTexture1D(&Descriptor, NULL, &ret);
  
        if(FAILED(hr))
        {
          RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
          return false;
        }
        else
        {
          ret = new WrappedID3D11Texture1D(ret, this, dispType);
  
          GetResourceManager()->AddLiveResource(pResource, ret);
        }
  
        AddResource(pResource, ResourceType::Texture, "Shared 1D Texture");
      }
    }
    else if(Type == Resource_Texture2D)
    {
      D3D11_TEXTURE2D_DESC Descriptor;
      RDCEraseEl(Descriptor);
  
      ID3D11Texture2D *tex = (ID3D11Texture2D *)res;
  
      if(ser.IsWriting())
        tex->GetDesc(&Descriptor);
  
      SERIALISE_ELEMENT(Descriptor);
  
      Serialise_CreateTextureData(ser, tex, pResource, NULL, Descriptor.Width, Descriptor.Height, 1,
                                  Descriptor.Format, Descriptor.MipLevels, Descriptor.ArraySize, false);
  
      SERIALISE_CHECK_READ_ERRORS();
  
      if(IsReplayingAndReading())
      {
        ID3D11Texture2D *ret;
        HRESULT hr = S_OK;
  
        TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
        // unset flags that are unimportant/problematic in replay
        MaskResourceMiscFlags(Descriptor.MiscFlags);
  
        hr = m_pDevice->CreateTexture2D(&Descriptor, NULL, &ret);
  
        if(FAILED(hr))
        {
          RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
          return false;
        }
        else
        {
          ret = new WrappedID3D11Texture2D1(ret, this, dispType);
  
          GetResourceManager()->AddLiveResource(pResource, ret);
        }
  
        AddResource(pResource, ResourceType::Texture, "Shared 2D Texture");
      }
    }
    else if(Type == Resource_Texture3D)
    {
      D3D11_TEXTURE3D_DESC Descriptor;
      RDCEraseEl(Descriptor);
  
      ID3D11Texture3D *tex = (ID3D11Texture3D *)res;
  
      if(ser.IsWriting())
        tex->GetDesc(&Descriptor);
  
      SERIALISE_ELEMENT(Descriptor);
  
      Serialise_CreateTextureData(ser, tex, pResource, NULL, Descriptor.Width, Descriptor.Height,
                                  Descriptor.Depth, Descriptor.Format, Descriptor.MipLevels, 1, false);
  
      SERIALISE_CHECK_READ_ERRORS();
  
      if(IsReplayingAndReading())
      {
        ID3D11Texture3D *ret;
        HRESULT hr = S_OK;
  
        TextureDisplayType dispType = DispTypeForTexture(Descriptor);
  
        // unset flags that are unimportant/problematic in replay
        MaskResourceMiscFlags(Descriptor.MiscFlags);
  
        hr = m_pDevice->CreateTexture3D(&Descriptor, NULL, &ret);
  
        if(FAILED(hr))
        {
          RDCERR("Failed on resource serialise-creation, HRESULT: %s", ToStr(hr).c_str());
          return false;
        }
        else
        {
          ret = new WrappedID3D11Texture3D1(ret, this, dispType);
  
          GetResourceManager()->AddLiveResource(pResource, ret);
        }
  
        AddResource(pResource, ResourceType::Texture, "Shared 3D Texture");
      }
    }
    else
    {
      RDCERR("Unknown type of resource being shared");
    }
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::OpenSharedResource(HANDLE hResource, REFIID ReturnedInterface,
                                                  void **ppResource)
  {
    if(ppResource == NULL)
      return E_INVALIDARG;
  
    HRESULT hr;
  
    SERIALISE_TIME_CALL(hr = m_pDevice->OpenSharedResource(hResource, ReturnedInterface, ppResource));
  
    if(FAILED(hr))
    {
      IUnknown *unk = (IUnknown *)*ppResource;
      SAFE_RELEASE(unk);
      return hr;
    }
  
    return OpenSharedResourceInternal(D3D11Chunk::OpenSharedResource, ReturnedInterface, ppResource);
  }
  
  HRESULT WrappedID3D11Device::OpenSharedResourceInternal(D3D11Chunk chunkType,
                                                          REFIID ReturnedInterface, void **ppResource)
  {
    if(IsReplayMode(m_State))
    {
      RDCERR("Don't support opening shared resources during replay.");
      return E_NOTIMPL;
    }
  
    // fences aren't serialised
    if(ReturnedInterface == __uuidof(ID3D11Fence))
    {
      WrappedID3D11Fence *w = new WrappedID3D11Fence((ID3D11Fence *)*ppResource, this);
  
      *ppResource = (ID3D11Fence *)w;
  
      return S_OK;
    }
  
    bool isUnknown = ReturnedInterface == __uuidof(IUnknown);
    bool isDXGIRes =
        ReturnedInterface == __uuidof(IDXGIResource) || ReturnedInterface == __uuidof(IDXGIResource1);
    bool isRes = ReturnedInterface == __uuidof(ID3D11Resource);
    bool isBuf = ReturnedInterface == __uuidof(ID3D11Buffer);
    bool isTex1D = ReturnedInterface == __uuidof(ID3D11Texture1D);
    bool isTex2D = ReturnedInterface == __uuidof(ID3D11Texture2D) ||
                   ReturnedInterface == __uuidof(ID3D11Texture2D1);
    bool isTex3D = ReturnedInterface == __uuidof(ID3D11Texture3D) ||
                   ReturnedInterface == __uuidof(ID3D11Texture3D1);
  
    if(isUnknown || isDXGIRes || isRes || isBuf || isTex1D || isTex2D || isTex3D)
    {
      void *res = *ppResource;
      HRESULT hr = S_OK;
  
      if(isUnknown || isDXGIRes)
      {
        IUnknown *unknownRes = (IUnknown *)res;
  
        if(ReturnedInterface == __uuidof(IDXGIResource))
          unknownRes = (IDXGIResource *)res;
  
        if(ReturnedInterface == __uuidof(IDXGIResource1))
          unknownRes = (IDXGIResource1 *)res;
  
        ID3D11Resource *d3d11Res = NULL;
        hr = unknownRes->QueryInterface(__uuidof(ID3D11Resource), (void **)&d3d11Res);
  
        // release this interface
        SAFE_RELEASE(unknownRes);
  
        // if we can't get a d3d11Res then we can't properly wrap this resource,
        // whatever it is.
        if(FAILED(hr) || d3d11Res == NULL)
        {
          SAFE_RELEASE(d3d11Res);
          return E_NOINTERFACE;
        }
  
        // and use this one, so it'll be casted back below
        res = (void *)d3d11Res;
        isRes = true;
      }
  
      SCOPED_LOCK(m_D3DLock);
  
      ResourceId wrappedID;
  
      if(isRes)
      {
        ID3D11Resource *resource = (ID3D11Resource *)res;
        D3D11_RESOURCE_DIMENSION dim;
        resource->GetType(&dim);
  
        if(dim == D3D11_RESOURCE_DIMENSION_BUFFER)
        {
          res = (ID3D11Buffer *)(ID3D11Resource *)res;
          isBuf = true;
        }
        else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE1D)
        {
          res = (ID3D11Texture1D *)(ID3D11Resource *)res;
          isTex1D = true;
        }
        else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D)
        {
          res = (ID3D11Texture2D *)(ID3D11Resource *)res;
          isTex2D = true;
        }
        else if(dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
        {
          res = (ID3D11Texture3D *)(ID3D11Resource *)res;
          isTex3D = true;
        }
      }
  
      void *ppvWrapped = NULL;
  
      if(isBuf)
      {
        WrappedID3D11Buffer *w = new WrappedID3D11Buffer((ID3D11Buffer *)res, 0, this);
        wrappedID = w->GetResourceID();
  
        ppvWrapped = (ID3D11Buffer *)w;
  
        if(isDXGIRes)
        {
          w->QueryInterface(ReturnedInterface, ppResource);
          w->Release();
        }
        else if(isRes)
        {
          *ppResource = (ID3D11Resource *)w;
        }
        else
        {
          *ppResource = (ID3D11Buffer *)w;
        }
      }
      else if(isTex1D)
      {
        WrappedID3D11Texture1D *w = new WrappedID3D11Texture1D((ID3D11Texture1D *)res, this);
        wrappedID = w->GetResourceID();
  
        ppvWrapped = (ID3D11Texture1D *)w;
  
        if(isDXGIRes)
        {
          w->QueryInterface(ReturnedInterface, ppResource);
          w->Release();
        }
        else if(isRes)
        {
          *ppResource = (ID3D11Resource *)w;
        }
        else
        {
          *ppResource = (ID3D11Texture1D *)w;
        }
      }
      else if(isTex2D)
      {
        ID3D11Texture2D *tex2d = (ID3D11Texture2D *)res;
        if(ReturnedInterface == __uuidof(ID3D11Texture2D1))
          tex2d = (ID3D11Texture2D1 *)res;
  
        WrappedID3D11Texture2D1 *w = new WrappedID3D11Texture2D1(tex2d, this);
        wrappedID = w->GetResourceID();
  
        ppvWrapped = (ID3D11Texture2D *)w;
  
        if(isDXGIRes)
        {
          w->QueryInterface(ReturnedInterface, ppResource);
          w->Release();
        }
        else if(isRes)
        {
          *ppResource = (ID3D11Resource *)w;
        }
        else
        {
          *ppResource = (ID3D11Texture2D *)w;
          if(ReturnedInterface == __uuidof(ID3D11Texture2D1))
            *ppResource = (ID3D11Texture2D1 *)w;
        }
      }
      else if(isTex3D)
      {
        ID3D11Texture3D *tex3d = (ID3D11Texture3D *)res;
        if(ReturnedInterface == __uuidof(ID3D11Texture3D1))
          tex3d = (ID3D11Texture3D1 *)res;
  
        WrappedID3D11Texture3D1 *w = new WrappedID3D11Texture3D1(tex3d, this);
        wrappedID = w->GetResourceID();
  
        ppvWrapped = (ID3D11Texture3D *)w;
  
        if(isDXGIRes)
        {
          w->QueryInterface(ReturnedInterface, ppResource);
          w->Release();
        }
        else if(isRes)
        {
          *ppResource = (ID3D11Resource *)w;
        }
        else
        {
          *ppResource = (ID3D11Texture3D *)w;
          if(ReturnedInterface == __uuidof(ID3D11Texture3D1))
            *ppResource = (ID3D11Texture3D1 *)w;
        }
      }
  
      Chunk *chunk = NULL;
  
      {
        USE_SCRATCH_SERIALISER();
        SCOPED_SERIALISE_CHUNK(chunkType);
        Serialise_OpenSharedResource(GET_SERIALISER, 0, ReturnedInterface, &ppvWrapped);
  
        chunk = scope.Get();
      }
  
      // don't know where this came from or who might modify it at any point.
      GetResourceManager()->MarkDirtyResource(wrappedID);
  
      D3D11ResourceRecord *record = GetResourceManager()->GetResourceRecord(wrappedID);
      RDCASSERT(record);
  
      record->AddChunk(chunk);
      record->SetDataPtr(chunk->GetData());
  
      if(IsActiveCapturing(m_State))
        Prepare_InitialState(GetResourceManager()->GetCurrentResource(wrappedID));
  
      return S_OK;
    }
  
    RDCERR("Unknown OpenSharedResourceInternal GUID: %s", ToStr(ReturnedInterface).c_str());
  
    IUnknown *unk = (IUnknown *)*ppResource;
    SAFE_RELEASE(unk);
  
    return E_NOINTERFACE;
  }
  
  HRESULT WrappedID3D11Device::CheckFormatSupport(DXGI_FORMAT Format, UINT *pFormatSupport)
  {
    return m_pDevice->CheckFormatSupport(Format, pFormatSupport);
  }
  
  HRESULT WrappedID3D11Device::CheckMultisampleQualityLevels(DXGI_FORMAT Format, UINT SampleCount,
                                                             UINT *pNumQualityLevels)
  {
    return m_pDevice->CheckMultisampleQualityLevels(Format, SampleCount, pNumQualityLevels);
  }
  
  void WrappedID3D11Device::CheckCounterInfo(D3D11_COUNTER_INFO *pCounterInfo)
  {
    m_pDevice->CheckCounterInfo(pCounterInfo);
  }
  
  HRESULT WrappedID3D11Device::CheckCounter(const D3D11_COUNTER_DESC *pDesc, D3D11_COUNTER_TYPE *pType,
                                            UINT *pActiveCounters, LPSTR szName, UINT *pNameLength,
                                            LPSTR szUnits, UINT *pUnitsLength, LPSTR szDescription,
                                            UINT *pDescriptionLength)
  {
    return m_pDevice->CheckCounter(pDesc, pType, pActiveCounters, szName, pNameLength, szUnits,
                                   pUnitsLength, szDescription, pDescriptionLength);
  }
  
  HRESULT WrappedID3D11Device::CheckFeatureSupport(D3D11_FEATURE Feature, void *pFeatureSupportData,
                                                   UINT FeatureSupportDataSize)
  {
    if(Feature == D3D11_FEATURE_D3D11_OPTIONS2)
    {
      HRESULT hr = m_pDevice->CheckFeatureSupport(Feature, pFeatureSupportData, FeatureSupportDataSize);
  
      if(SUCCEEDED(hr))
      {
        D3D11_FEATURE_DATA_D3D11_OPTIONS2 *opts =
            (D3D11_FEATURE_DATA_D3D11_OPTIONS2 *)pFeatureSupportData;
        if(FeatureSupportDataSize != sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS2))
          return E_INVALIDARG;
  
        // don't support tiled resources
        opts->TiledResourcesTier = D3D11_TILED_RESOURCES_NOT_SUPPORTED;
  
        return S_OK;
      }
  
      return hr;
    }
  
    return m_pDevice->CheckFeatureSupport(Feature, pFeatureSupportData, FeatureSupportDataSize);
  }
  
  HRESULT WrappedID3D11Device::GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData)
  {
    return m_pDevice->GetPrivateData(guid, pDataSize, pData);
  }
  
  HRESULT WrappedID3D11Device::SetPrivateData(REFGUID guid, UINT DataSize, const void *pData)
  {
    return m_pDevice->SetPrivateData(guid, DataSize, pData);
  }
  
  HRESULT WrappedID3D11Device::SetPrivateDataInterface(REFGUID guid, const IUnknown *pData)
  {
    return m_pDevice->SetPrivateDataInterface(guid, pData);
  }
  
  D3D_FEATURE_LEVEL WrappedID3D11Device::GetFeatureLevel()
  {
    return m_pDevice->GetFeatureLevel();
  }
  
  UINT WrappedID3D11Device::GetCreationFlags()
  {
    return m_pDevice->GetCreationFlags();
  }
  
  HRESULT WrappedID3D11Device::GetDeviceRemovedReason()
  {
    return m_pDevice->GetDeviceRemovedReason();
  }
  
  void WrappedID3D11Device::GetImmediateContext(ID3D11DeviceContext **ppImmediateContext)
  {
    if(ppImmediateContext)
    {
      *ppImmediateContext = (ID3D11DeviceContext *)m_pImmediateContext;
      m_pImmediateContext->AddRef();
    }
  }
  
  template <typename SerialiserType>
  bool WrappedID3D11Device::Serialise_SetExceptionMode(SerialiserType &ser, UINT RaiseFlags)
  {
    SERIALISE_ELEMENT(RaiseFlags).Important();
  
    SERIALISE_CHECK_READ_ERRORS();
  
    if(IsReplayingAndReading())
      m_pDevice->SetExceptionMode(RaiseFlags);
  
    return true;
  }
  
  HRESULT WrappedID3D11Device::SetExceptionMode(UINT RaiseFlags)
  {
    HRESULT ret;
    SERIALISE_TIME_CALL(ret = m_pDevice->SetExceptionMode(RaiseFlags));
  
    if(SUCCEEDED(ret) && IsCaptureMode(m_State))
    {
      SCOPED_LOCK(m_D3DLock);
  
      USE_SCRATCH_SERIALISER();
      SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetExceptionMode);
      Serialise_SetExceptionMode(GET_SERIALISER, RaiseFlags);
  
      m_DeviceRecord->AddChunk(scope.Get());
    }
  
    return ret;
  }
  
  UINT WrappedID3D11Device::GetExceptionMode()
  {
    return m_pDevice->GetExceptionMode();
  }
  
  #undef IMPLEMENT_FUNCTION_SERIALISED
  #define IMPLEMENT_FUNCTION_SERIALISED(ret, func, ...)                                            \
    template bool WrappedID3D11Device::CONCAT(Serialise_, func(ReadSerialiser &ser, __VA_ARGS__)); \
    template bool WrappedID3D11Device::CONCAT(Serialise_, func(WriteSerialiser &ser, __VA_ARGS__));
  
  SERIALISED_ID3D11DEVICE_FUNCTIONS();
  SERIALISED_ID3D11DEVICE_FAKE_FUNCTIONS();
  