示例#1
0
VkResult WrappedVulkan::vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount,
                                          const VkBindSparseInfo *pBindInfo, VkFence fence)
{
  if(m_State >= WRITING_CAPFRAME)
  {
    CACHE_THREAD_SERIALISER();

    for(uint32_t i = 0; i < bindInfoCount; i++)
    {
      SCOPED_SERIALISE_CONTEXT(BIND_SPARSE);
      Serialise_vkQueueBindSparse(localSerialiser, queue, 1, pBindInfo + i, fence);

      m_FrameCaptureRecord->AddChunk(scope.Get());
      GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);
      GetResourceManager()->MarkResourceFrameReferenced(GetResID(fence), eFrameRef_Read);
      // images/buffers aren't marked referenced. If the only ref is a memory bind, we just skip it

      for(uint32_t w = 0; w < pBindInfo[i].waitSemaphoreCount; w++)
        GetResourceManager()->MarkResourceFrameReferenced(GetResID(pBindInfo[i].pWaitSemaphores[w]),
                                                          eFrameRef_Read);
      for(uint32_t s = 0; s < pBindInfo[i].signalSemaphoreCount; s++)
        GetResourceManager()->MarkResourceFrameReferenced(
            GetResID(pBindInfo[i].pSignalSemaphores[s]), eFrameRef_Read);
    }
  }

  // update our internal page tables
  if(m_State >= WRITING)
  {
    for(uint32_t i = 0; i < bindInfoCount; i++)
    {
      for(uint32_t buf = 0; buf < pBindInfo[i].bufferBindCount; buf++)
      {
        const VkSparseBufferMemoryBindInfo &bind = pBindInfo[i].pBufferBinds[buf];
        GetRecord(bind.buffer)->sparseInfo->Update(bind.bindCount, bind.pBinds);
      }

      for(uint32_t op = 0; op < pBindInfo[i].imageOpaqueBindCount; op++)
      {
        const VkSparseImageOpaqueMemoryBindInfo &bind = pBindInfo[i].pImageOpaqueBinds[op];
        GetRecord(bind.image)->sparseInfo->Update(bind.bindCount, bind.pBinds);
      }

      for(uint32_t op = 0; op < pBindInfo[i].imageBindCount; op++)
      {
        const VkSparseImageMemoryBindInfo &bind = pBindInfo[i].pImageBinds[op];
        GetRecord(bind.image)->sparseInfo->Update(bind.bindCount, bind.pBinds);
      }
    }
  }

  // need to allocate space for each bind batch
  size_t tempmemSize = sizeof(VkBindSparseInfo) * bindInfoCount;

  for(uint32_t i = 0; i < bindInfoCount; i++)
  {
    // within each batch, need to allocate space for each resource bind
    tempmemSize += pBindInfo[i].bufferBindCount * sizeof(VkSparseBufferMemoryBindInfo);
    tempmemSize += pBindInfo[i].imageOpaqueBindCount * sizeof(VkSparseImageOpaqueMemoryBindInfo);
    tempmemSize += pBindInfo[i].imageBindCount * sizeof(VkSparseImageMemoryBindInfo);
    tempmemSize += pBindInfo[i].waitSemaphoreCount * sizeof(VkSemaphore);
    tempmemSize += pBindInfo[i].signalSemaphoreCount * sizeof(VkSparseImageMemoryBindInfo);

    // within each resource bind, need to save space for each individual bind operation
    for(uint32_t b = 0; b < pBindInfo[i].bufferBindCount; b++)
      tempmemSize += pBindInfo[i].pBufferBinds[b].bindCount * sizeof(VkSparseMemoryBind);
    for(uint32_t b = 0; b < pBindInfo[i].imageOpaqueBindCount; b++)
      tempmemSize += pBindInfo[i].pImageOpaqueBinds[b].bindCount * sizeof(VkSparseMemoryBind);
    for(uint32_t b = 0; b < pBindInfo[i].imageBindCount; b++)
      tempmemSize += pBindInfo[i].pImageBinds[b].bindCount * sizeof(VkSparseImageMemoryBind);
  }

  byte *memory = GetTempMemory(tempmemSize);

  VkBindSparseInfo *unwrapped = (VkBindSparseInfo *)memory;
  byte *next = (byte *)(unwrapped + bindInfoCount);

  // now go over each batch..
  for(uint32_t i = 0; i < bindInfoCount; i++)
  {
    // copy the original so we get all the params we don't need to change
    RDCASSERT(pBindInfo[i].sType == VK_STRUCTURE_TYPE_BIND_SPARSE_INFO && pBindInfo[i].pNext == NULL);
    unwrapped[i] = pBindInfo[i];

    // unwrap the signal semaphores into a new array
    VkSemaphore *signal = (VkSemaphore *)next;
    next += sizeof(VkSemaphore) * unwrapped[i].signalSemaphoreCount;
    unwrapped[i].pSignalSemaphores = signal;
    for(uint32_t j = 0; j < unwrapped[i].signalSemaphoreCount; j++)
      signal[j] = Unwrap(pBindInfo[i].pSignalSemaphores[j]);

    // and the wait semaphores
    VkSemaphore *wait = (VkSemaphore *)next;
    next += sizeof(VkSemaphore) * unwrapped[i].waitSemaphoreCount;
    unwrapped[i].pWaitSemaphores = wait;
    for(uint32_t j = 0; j < unwrapped[i].waitSemaphoreCount; j++)
      wait[j] = Unwrap(pBindInfo[i].pWaitSemaphores[j]);

    // now copy & unwrap the sparse buffer binds
    VkSparseBufferMemoryBindInfo *buf = (VkSparseBufferMemoryBindInfo *)next;
    next += sizeof(VkSparseBufferMemoryBindInfo) * unwrapped[i].bufferBindCount;
    unwrapped[i].pBufferBinds = buf;
    for(uint32_t j = 0; j < unwrapped[i].bufferBindCount; j++)
    {
      buf[j] = pBindInfo[i].pBufferBinds[j];
      buf[j].buffer = Unwrap(buf[j].buffer);

      // for each buffer bind, copy & unwrap the individual memory binds too
      VkSparseMemoryBind *binds = (VkSparseMemoryBind *)next;
      next += sizeof(VkSparseMemoryBind) * buf[j].bindCount;
      buf[j].pBinds = binds;
      for(uint32_t k = 0; k < buf[j].bindCount; k++)
      {
        binds[k] = pBindInfo[i].pBufferBinds[j].pBinds[k];
        binds[k].memory = Unwrap(buf[j].pBinds[k].memory);
      }
    }

    // same as above
    VkSparseImageOpaqueMemoryBindInfo *opaque = (VkSparseImageOpaqueMemoryBindInfo *)next;
    next += sizeof(VkSparseImageOpaqueMemoryBindInfo) * unwrapped[i].imageOpaqueBindCount;
    unwrapped[i].pImageOpaqueBinds = opaque;
    for(uint32_t j = 0; j < unwrapped[i].imageOpaqueBindCount; j++)
    {
      opaque[j] = pBindInfo[i].pImageOpaqueBinds[j];
      opaque[j].image = Unwrap(opaque[j].image);

      VkSparseMemoryBind *binds = (VkSparseMemoryBind *)next;
      next += sizeof(VkSparseMemoryBind) * opaque[j].bindCount;
      opaque[j].pBinds = binds;
      for(uint32_t k = 0; k < opaque[j].bindCount; k++)
      {
        binds[k] = pBindInfo[i].pImageOpaqueBinds[j].pBinds[k];
        binds[k].memory = Unwrap(opaque[j].pBinds[k].memory);
      }
    }

    // same as above
    VkSparseImageMemoryBindInfo *im = (VkSparseImageMemoryBindInfo *)next;
    next += sizeof(VkSparseImageMemoryBindInfo) * unwrapped[i].imageBindCount;
    unwrapped[i].pImageBinds = im;
    for(uint32_t j = 0; j < unwrapped[i].imageBindCount; j++)
    {
      im[j] = pBindInfo[i].pImageBinds[j];
      im[j].image = Unwrap(im[j].image);

      VkSparseImageMemoryBind *binds = (VkSparseImageMemoryBind *)next;
      next += sizeof(VkSparseImageMemoryBind) * im[j].bindCount;
      im[j].pBinds = binds;
      for(uint32_t k = 0; k < im[j].bindCount; k++)
      {
        binds[k] = pBindInfo[i].pImageBinds[j].pBinds[k];
        binds[k].memory = Unwrap(im[j].pBinds[k].memory);
      }
    }
  }

  return ObjDisp(queue)->QueueBindSparse(Unwrap(queue), bindInfoCount, unwrapped, Unwrap(fence));
}
示例#2
0
void WrappedVulkan::vkCmdWaitEvents(
			VkCommandBuffer                                 cmdBuffer,
			uint32_t                                    eventCount,
			const VkEvent*                              pEvents,
			VkPipelineStageFlags                        srcStageMask,
			VkPipelineStageFlags                        dstStageMask,
			uint32_t                                    memoryBarrierCount,
			const VkMemoryBarrier*                      pMemoryBarriers,
			uint32_t                                    bufferMemoryBarrierCount,
			const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
			uint32_t                                    imageMemoryBarrierCount,
			const VkImageMemoryBarrier*                 pImageMemoryBarriers)
{
	{
		byte *memory = GetTempMemory( sizeof(VkEvent)*eventCount +
			sizeof(VkBufferMemoryBarrier)*bufferMemoryBarrierCount + 
			sizeof(VkImageMemoryBarrier)*imageMemoryBarrierCount);

		VkEvent *ev = (VkEvent *)memory;
		VkImageMemoryBarrier *im = (VkImageMemoryBarrier *)(ev + eventCount);
		VkBufferMemoryBarrier *buf = (VkBufferMemoryBarrier *)(im + imageMemoryBarrierCount);

		for(uint32_t i=0; i < eventCount; i++)
			ev[i] = Unwrap(pEvents[i]);

		for(uint32_t i=0; i < bufferMemoryBarrierCount; i++)
		{
			buf[i] = pBufferMemoryBarriers[i];
			buf[i].buffer = Unwrap(buf[i].buffer);
		}

		for(uint32_t i=0; i < imageMemoryBarrierCount; i++)
		{
			im[i] = pImageMemoryBarriers[i];
			im[i].image = Unwrap(im[i].image);
		}
		
		ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), eventCount, ev, srcStageMask, dstStageMask,
			memoryBarrierCount, pMemoryBarriers,
			bufferMemoryBarrierCount, buf,
			imageMemoryBarrierCount, im);
	}

	if(m_State >= WRITING)
	{
		VkResourceRecord *record = GetRecord(cmdBuffer);

		CACHE_THREAD_SERIALISER();

		SCOPED_SERIALISE_CONTEXT(CMD_WAIT_EVENTS);
		Serialise_vkCmdWaitEvents(localSerialiser, cmdBuffer, eventCount, pEvents, srcStageMask, dstStageMask,
			memoryBarrierCount, pMemoryBarriers,
			bufferMemoryBarrierCount, pBufferMemoryBarriers,
			imageMemoryBarrierCount, pImageMemoryBarriers);
		
		if(imageMemoryBarrierCount > 0)
		{
			SCOPED_LOCK(m_ImageLayoutsLock);
			GetResourceManager()->RecordBarriers(GetRecord(cmdBuffer)->cmdInfo->imgbarriers, m_ImageLayouts, imageMemoryBarrierCount, pImageMemoryBarriers);
		}

		record->AddChunk(scope.Get());
		for(uint32_t i=0; i < eventCount; i++)
			record->MarkResourceFrameReferenced(GetResID(pEvents[i]), eFrameRef_Read);
	}
}
示例#3
0
VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
                                      const VkSubmitInfo *pSubmits, VkFence fence)
{
  SCOPED_DBG_SINK();

  size_t tempmemSize = sizeof(VkSubmitInfo) * submitCount;

  // need to count how many semaphore and command buffer arrays to allocate for
  for(uint32_t i = 0; i < submitCount; i++)
  {
    tempmemSize += pSubmits[i].commandBufferCount * sizeof(VkCommandBuffer);
    tempmemSize += pSubmits[i].signalSemaphoreCount * sizeof(VkSemaphore);
    tempmemSize += pSubmits[i].waitSemaphoreCount * sizeof(VkSemaphore);
  }

  byte *memory = GetTempMemory(tempmemSize);

  VkSubmitInfo *unwrappedSubmits = (VkSubmitInfo *)memory;
  VkSemaphore *unwrappedWaitSems = (VkSemaphore *)(unwrappedSubmits + submitCount);

  for(uint32_t i = 0; i < submitCount; i++)
  {
    RDCASSERT(pSubmits[i].sType == VK_STRUCTURE_TYPE_SUBMIT_INFO && pSubmits[i].pNext == NULL);
    unwrappedSubmits[i] = pSubmits[i];

    unwrappedSubmits[i].pWaitSemaphores =
        unwrappedSubmits[i].waitSemaphoreCount ? unwrappedWaitSems : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].waitSemaphoreCount; o++)
      unwrappedWaitSems[o] = Unwrap(pSubmits[i].pWaitSemaphores[o]);
    unwrappedWaitSems += unwrappedSubmits[i].waitSemaphoreCount;

    VkCommandBuffer *unwrappedCommandBuffers = (VkCommandBuffer *)unwrappedWaitSems;

    unwrappedSubmits[i].pCommandBuffers =
        unwrappedSubmits[i].commandBufferCount ? unwrappedCommandBuffers : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].commandBufferCount; o++)
      unwrappedCommandBuffers[o] = Unwrap(pSubmits[i].pCommandBuffers[o]);
    unwrappedCommandBuffers += unwrappedSubmits[i].commandBufferCount;

    VkSemaphore *unwrappedSignalSems = (VkSemaphore *)unwrappedCommandBuffers;

    unwrappedSubmits[i].pSignalSemaphores =
        unwrappedSubmits[i].signalSemaphoreCount ? unwrappedSignalSems : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].signalSemaphoreCount; o++)
      unwrappedSignalSems[o] = Unwrap(pSubmits[i].pSignalSemaphores[o]);
  }

  VkResult ret =
      ObjDisp(queue)->QueueSubmit(Unwrap(queue), submitCount, unwrappedSubmits, Unwrap(fence));

  bool capframe = false;
  set<ResourceId> refdIDs;

  for(uint32_t s = 0; s < submitCount; s++)
  {
    for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++)
    {
      ResourceId cmd = GetResID(pSubmits[s].pCommandBuffers[i]);

      VkResourceRecord *record = GetRecord(pSubmits[s].pCommandBuffers[i]);

      {
        SCOPED_LOCK(m_ImageLayoutsLock);
        GetResourceManager()->ApplyBarriers(record->bakedCommands->cmdInfo->imgbarriers,
                                            m_ImageLayouts);
      }

      // need to lock the whole section of code, not just the check on
      // m_State, as we also need to make sure we don't check the state,
      // start marking dirty resources then while we're doing so the
      // state becomes capframe.
      // the next sections where we mark resources referenced and add
      // the submit chunk to the frame record don't have to be protected.
      // Only the decision of whether we're inframe or not, and marking
      // dirty.
      {
        SCOPED_LOCK(m_CapTransitionLock);
        if(m_State == WRITING_CAPFRAME)
        {
          for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
              it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
            GetResourceManager()->MarkPendingDirty(*it);

          capframe = true;
        }
        else
        {
          for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
              it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
            GetResourceManager()->MarkDirtyResource(*it);
        }
      }

      if(capframe)
      {
        // for each bound descriptor set, mark it referenced as well as all resources currently
        // bound to it
        for(auto it = record->bakedCommands->cmdInfo->boundDescSets.begin();
            it != record->bakedCommands->cmdInfo->boundDescSets.end(); ++it)
        {
          GetResourceManager()->MarkResourceFrameReferenced(GetResID(*it), eFrameRef_Read);

          VkResourceRecord *setrecord = GetRecord(*it);

          for(auto refit = setrecord->descInfo->bindFrameRefs.begin();
              refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
          {
            refdIDs.insert(refit->first);
            GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second);

            if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
            {
              VkResourceRecord *sparserecord = GetResourceManager()->GetResourceRecord(refit->first);

              GetResourceManager()->MarkSparseMapReferenced(sparserecord->sparseInfo);
            }
          }
        }

        for(auto it = record->bakedCommands->cmdInfo->sparse.begin();
            it != record->bakedCommands->cmdInfo->sparse.end(); ++it)
          GetResourceManager()->MarkSparseMapReferenced(*it);

        // pull in frame refs from this baked command buffer
        record->bakedCommands->AddResourceReferences(GetResourceManager());
        record->bakedCommands->AddReferencedIDs(refdIDs);

        // ref the parent command buffer by itself, this will pull in the cmd buffer pool
        GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), eFrameRef_Read);

        for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
        {
          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences(
              GetResourceManager());
          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs);
          GetResourceManager()->MarkResourceFrameReferenced(
              record->bakedCommands->cmdInfo->subcmds[sub]->GetResourceID(), eFrameRef_Read);

          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddRef();
        }

        GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);

        if(fence != VK_NULL_HANDLE)
          GetResourceManager()->MarkResourceFrameReferenced(GetResID(fence), eFrameRef_Read);

        {
          SCOPED_LOCK(m_CmdBufferRecordsLock);
          m_CmdBufferRecords.push_back(record->bakedCommands);
          for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
            m_CmdBufferRecords.push_back(record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands);
        }

        record->bakedCommands->AddRef();
      }

      record->cmdInfo->dirtied.clear();
    }
  }

  if(capframe)
  {
    vector<VkResourceRecord *> maps;
    {
      SCOPED_LOCK(m_CoherentMapsLock);
      maps = m_CoherentMaps;
    }

    for(auto it = maps.begin(); it != maps.end(); ++it)
    {
      VkResourceRecord *record = *it;
      MemMapState &state = *record->memMapState;

      // potential persistent map
      if(state.mapCoherent && state.mappedPtr && !state.mapFlushed)
      {
        // only need to flush memory that could affect this submitted batch of work
        if(refdIDs.find(record->GetResourceID()) == refdIDs.end())
        {
          RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
                   record->GetResourceID());
          continue;
        }

        size_t diffStart = 0, diffEnd = 0;
        bool found = true;

// enabled as this is necessary for programs with very large coherent mappings
// (> 1GB) as otherwise more than a couple of vkQueueSubmit calls leads to vast
// memory allocation. There might still be bugs lurking in here though
#if 1
        // this causes vkFlushMappedMemoryRanges call to allocate and copy to refData
        // from serialised buffer. We want to copy *precisely* the serialised data,
        // otherwise there is a gap in time between serialising out a snapshot of
        // the buffer and whenever we then copy into the ref data, e.g. below.
        // during this time, data could be written to the buffer and it won't have
        // been caught in the serialised snapshot, and if it doesn't change then
        // it *also* won't be caught in any future FindDiffRange() calls.
        //
        // Likewise once refData is allocated, the call below will also update it
        // with the data serialised out for the same reason.
        //
        // Note: it's still possible that data is being written to by the
        // application while it's being serialised out in the snapshot below. That
        // is OK, since the application is responsible for ensuring it's not writing
        // data that would be needed by the GPU in this submit. As long as the
        // refdata we use for future use is identical to what was serialised, we
        // shouldn't miss anything
        state.needRefData = true;

        // if we have a previous set of data, compare.
        // otherwise just serialise it all
        if(state.refData)
          found = FindDiffRange((byte *)state.mappedPtr, state.refData, (size_t)state.mapSize,
                                diffStart, diffEnd);
        else
#endif
          diffEnd = (size_t)state.mapSize;

        if(found)
        {
          // MULTIDEVICE should find the device for this queue.
          // MULTIDEVICE only want to flush maps associated with this queue
          VkDevice dev = GetDev();

          {
            RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", record->GetResourceID(),
                   (uint64_t)diffStart, (uint64_t)diffEnd);
            VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL,
                                         (VkDeviceMemory)(uint64_t)record->Resource,
                                         state.mapOffset + diffStart, diffEnd - diffStart};
            vkFlushMappedMemoryRanges(dev, 1, &range);
            state.mapFlushed = false;
          }

          GetResourceManager()->MarkPendingDirty(record->GetResourceID());
        }
        else
        {
          RDCDEBUG("Persistent map flush not needed for %llu", record->GetResourceID());
        }
      }
    }

    {
      CACHE_THREAD_SERIALISER();

      for(uint32_t s = 0; s < submitCount; s++)
      {
        SCOPED_SERIALISE_CONTEXT(QUEUE_SUBMIT);
        Serialise_vkQueueSubmit(localSerialiser, queue, 1, &pSubmits[s], fence);

        m_FrameCaptureRecord->AddChunk(scope.Get());

        for(uint32_t sem = 0; sem < pSubmits[s].waitSemaphoreCount; sem++)
          GetResourceManager()->MarkResourceFrameReferenced(
              GetResID(pSubmits[s].pWaitSemaphores[sem]), eFrameRef_Read);

        for(uint32_t sem = 0; sem < pSubmits[s].signalSemaphoreCount; sem++)
          GetResourceManager()->MarkResourceFrameReferenced(
              GetResID(pSubmits[s].pSignalSemaphores[sem]), eFrameRef_Read);
      }
    }
  }

  return ret;
}
void WrappedVulkan::vkUpdateDescriptorSets(
    VkDevice                                    device,
    uint32_t                                    writeCount,
    const VkWriteDescriptorSet*                 pDescriptorWrites,
    uint32_t                                    copyCount,
    const VkCopyDescriptorSet*                  pDescriptorCopies)
{
    {
        // need to count up number of descriptor infos, to be able to alloc enough space
        uint32_t numInfos = 0;
        for(uint32_t i=0; i < writeCount; i++) numInfos += pDescriptorWrites[i].descriptorCount;

        byte *memory = GetTempMemory(sizeof(VkDescriptorBufferInfo)*numInfos +
                                     sizeof(VkWriteDescriptorSet)*writeCount + sizeof(VkCopyDescriptorSet)*copyCount);

        RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkDescriptorImageInfo), "Descriptor structs sizes are unexpected, ensure largest size is used");

        VkWriteDescriptorSet *unwrappedWrites = (VkWriteDescriptorSet *)memory;
        VkCopyDescriptorSet *unwrappedCopies = (VkCopyDescriptorSet *)(unwrappedWrites + writeCount);
        VkDescriptorBufferInfo *nextDescriptors = (VkDescriptorBufferInfo *)(unwrappedCopies + copyCount);

        for(uint32_t i=0; i < writeCount; i++)
        {
            unwrappedWrites[i] = pDescriptorWrites[i];
            unwrappedWrites[i].dstSet = Unwrap(unwrappedWrites[i].dstSet);

            VkDescriptorBufferInfo *bufInfos = nextDescriptors;
            VkDescriptorImageInfo *imInfos = (VkDescriptorImageInfo *)bufInfos;
            VkBufferView *bufViews = (VkBufferView *)bufInfos;
            nextDescriptors += pDescriptorWrites[i].descriptorCount;

            // unwrap and assign the appropriate array
            if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
            {
                unwrappedWrites[i].pTexelBufferView = (VkBufferView *)bufInfos;
                for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++)
                    bufViews[j] = Unwrap(pDescriptorWrites[i].pTexelBufferView[j]);
            }
            else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
                    pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
            {
                unwrappedWrites[i].pImageInfo = (VkDescriptorImageInfo *)bufInfos;
                for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++)
                {
                    imInfos[j].imageView = Unwrap(pDescriptorWrites[i].pImageInfo[j].imageView);
                    imInfos[j].sampler = Unwrap(pDescriptorWrites[i].pImageInfo[j].sampler);
                    imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout;
                }
            }
            else
            {
                unwrappedWrites[i].pBufferInfo = bufInfos;
                for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++)
                {
                    bufInfos[j].buffer = Unwrap(pDescriptorWrites[i].pBufferInfo[j].buffer);
                    bufInfos[j].offset = pDescriptorWrites[i].pBufferInfo[j].offset;
                    bufInfos[j].range = pDescriptorWrites[i].pBufferInfo[j].range;
                }
            }
        }

        for(uint32_t i=0; i < copyCount; i++)
        {
            unwrappedCopies[i] = pDescriptorCopies[i];
            unwrappedCopies[i].dstSet = Unwrap(unwrappedCopies[i].dstSet);
            unwrappedCopies[i].srcSet = Unwrap(unwrappedCopies[i].srcSet);
        }

        ObjDisp(device)->UpdateDescriptorSets(Unwrap(device), writeCount, unwrappedWrites, copyCount, unwrappedCopies);
    }

    bool capframe = false;
    {
        SCOPED_LOCK(m_CapTransitionLock);
        capframe = (m_State == WRITING_CAPFRAME);
    }

    if(capframe)
    {
        // don't have to mark referenced any of the resources pointed to by the descriptor set - that's handled
        // on queue submission by marking ref'd all the current bindings of the sets referenced by the cmd buffer

        for(uint32_t i=0; i < writeCount; i++)
        {
            {
                CACHE_THREAD_SERIALISER();

                SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET);
                Serialise_vkUpdateDescriptorSets(localSerialiser, device, 1, &pDescriptorWrites[i], 0, NULL);

                m_FrameCaptureRecord->AddChunk(scope.Get());
            }

            // as long as descriptor sets are forced to have initial states, we don't have to mark them ref'd for
            // write here. The reason being that as long as we only mark them as ref'd when they're actually bound,
            // we can safely skip the ref here and it means any descriptor set updates of descriptor sets that are
            // never used in the frame can be ignored.
            //GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorWrites[i].destSet), eFrameRef_Write);
        }

        for(uint32_t i=0; i < copyCount; i++)
        {
            {
                CACHE_THREAD_SERIALISER();

                SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET);
                Serialise_vkUpdateDescriptorSets(localSerialiser, device, 0, NULL, 1, &pDescriptorCopies[i]);

                m_FrameCaptureRecord->AddChunk(scope.Get());
            }

            // Like writes we don't have to mark the written descriptor set as used because unless it's bound somewhere
            // we don't need it anyway. However we DO have to mark the source set as used because it doesn't have to
            // be bound to still be needed (think about if the dest set is bound somewhere after this copy - what refs
            // the source set?).
            // At the same time as ref'ing the source set, we must ref all of its resources (via the bindFrameRefs).
            // We just ref all rather than looking at only the copied sets to keep things simple.
            // This does mean a slightly conservative ref'ing if the dest set doesn't end up getting bound, but we only
            // do this during frame capture so it's not too bad.
            //GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].destSet), eFrameRef_Write);

            {
                GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].srcSet), eFrameRef_Read);

                VkResourceRecord *setrecord = GetRecord(pDescriptorCopies[i].srcSet);

                for(auto refit = setrecord->descInfo->bindFrameRefs.begin(); refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
                {
                    GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second);

                    if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
                    {
                        VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first);

                        GetResourceManager()->MarkSparseMapReferenced(record->sparseInfo);
                    }
                }
            }
        }
    }

    // need to track descriptor set contents whether capframing or idle
    if(m_State >= WRITING)
    {
        for(uint32_t i=0; i < writeCount; i++)
        {
            VkResourceRecord *record = GetRecord(pDescriptorWrites[i].dstSet);
            RDCASSERT(record->descInfo && record->descInfo->layout);
            const DescSetLayout &layout = *record->descInfo->layout;

            RDCASSERT(pDescriptorWrites[i].dstBinding < record->descInfo->descBindings.size());

            DescriptorSetSlot *binding = record->descInfo->descBindings[pDescriptorWrites[i].dstBinding];

            FrameRefType ref = eFrameRef_Write;

            switch(layout.bindings[pDescriptorWrites[i].dstBinding].descriptorType)
            {
            case VK_DESCRIPTOR_TYPE_SAMPLER:
            case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
            case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
            case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
            case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
                ref = eFrameRef_Read;
                break;
            case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
            case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
                ref = eFrameRef_Write;
                break;
            default:
                RDCERR("Unexpected descriptor type");
            }

            // We need to handle the cases where these bindings are stale:
            // ie. image handle 0xf00baa is allocated
            // bound into a descriptor set
            // image is released
            // descriptor set is bound but this image is never used by shader etc.
            //
            // worst case, a new image or something has been added with this handle -
            // in this case we end up ref'ing an image that isn't actually used.
            // Worst worst case, we ref an image as write when actually it's not, but
            // this is likewise not a serious problem, and rather difficult to solve
            // (would need to version handles somehow, but don't have enough bits
            // to do that reliably).
            //
            // This is handled by RemoveBindFrameRef silently dropping id == ResourceId()

            for(uint32_t d=0; d < pDescriptorWrites[i].descriptorCount; d++)
            {
                DescriptorSetSlot &bind = binding[pDescriptorWrites[i].dstArrayElement + d];

                if(bind.texelBufferView != VK_NULL_HANDLE)
                {
                    record->RemoveBindFrameRef(GetResID(bind.texelBufferView));
                    if(GetRecord(bind.texelBufferView)->baseResource != ResourceId())
                        record->RemoveBindFrameRef(GetRecord(bind.texelBufferView)->baseResource);
                }
                if(bind.imageInfo.imageView != VK_NULL_HANDLE)
                {
                    record->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView));
                    record->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource);
                    if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId())
                        record->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem);
                }
                if(bind.imageInfo.sampler != VK_NULL_HANDLE)
                {
                    record->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler));
                }
                if(bind.bufferInfo.buffer != VK_NULL_HANDLE)
                {
                    record->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer));
                    if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId())
                        record->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource);
                }

                // NULL everything out now so that we don't accidentally reference an object
                // that was removed already
                bind.texelBufferView = VK_NULL_HANDLE;
                bind.bufferInfo.buffer = VK_NULL_HANDLE;
                bind.imageInfo.imageView = VK_NULL_HANDLE;
                bind.imageInfo.sampler = VK_NULL_HANDLE;

                if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
                        pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
                {
                    bind.texelBufferView = pDescriptorWrites[i].pTexelBufferView[d];
                }
                else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
                        pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
                        pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
                        pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
                        pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
                {
                    bind.imageInfo = pDescriptorWrites[i].pImageInfo[d];

                    // ignore descriptors not part of the write, by NULL'ing out those members
                    // as they might not even point to a valid object
                    if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
                        bind.imageInfo.imageView = VK_NULL_HANDLE;
                    else if(pDescriptorWrites[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
                        bind.imageInfo.sampler = VK_NULL_HANDLE;
                }
                else
                {
                    bind.bufferInfo = pDescriptorWrites[i].pBufferInfo[d];
                }

                if(bind.texelBufferView != VK_NULL_HANDLE)
                {
                    record->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, GetRecord(bind.texelBufferView)->sparseInfo != NULL);
                    if(GetRecord(bind.texelBufferView)->baseResource != ResourceId())
                        record->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref);
                }
                if(bind.imageInfo.imageView != VK_NULL_HANDLE)
                {
                    record->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL);
                    record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref);
                    if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId())
                        record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, eFrameRef_Read);
                }
                if(bind.imageInfo.sampler != VK_NULL_HANDLE)
                {
                    record->AddBindFrameRef(GetResID(bind.imageInfo.sampler), eFrameRef_Read);
                }
                if(bind.bufferInfo.buffer != VK_NULL_HANDLE)
                {
                    record->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL);
                    if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId())
                        record->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref);
                }
            }
        }

        // this is almost identical to the above loop, except that instead of sourcing the descriptors
        // from the writedescriptor struct, we source it from our stored bindings on the source
        // descrpitor set

        for(uint32_t i=0; i < copyCount; i++)
        {
            VkResourceRecord *dstrecord = GetRecord(pDescriptorCopies[i].dstSet);
            RDCASSERT(dstrecord->descInfo && dstrecord->descInfo->layout);
            const DescSetLayout &layout = *dstrecord->descInfo->layout;

            VkResourceRecord *srcrecord = GetRecord(pDescriptorCopies[i].srcSet);

            RDCASSERT(pDescriptorCopies[i].dstBinding < dstrecord->descInfo->descBindings.size());
            RDCASSERT(pDescriptorCopies[i].srcBinding < srcrecord->descInfo->descBindings.size());

            DescriptorSetSlot *dstbinding = dstrecord->descInfo->descBindings[pDescriptorCopies[i].dstBinding];
            DescriptorSetSlot *srcbinding = srcrecord->descInfo->descBindings[pDescriptorCopies[i].srcBinding];

            FrameRefType ref = eFrameRef_Write;

            switch(layout.bindings[pDescriptorCopies[i].dstBinding].descriptorType)
            {
            case VK_DESCRIPTOR_TYPE_SAMPLER:
            case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
            case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
            case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
            case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
                ref = eFrameRef_Read;
                break;
            case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
            case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
                ref = eFrameRef_Write;
                break;
            default:
                RDCERR("Unexpected descriptor type");
            }

            for(uint32_t d=0; d < pDescriptorCopies[i].descriptorCount; d++)
            {
                DescriptorSetSlot &bind = dstbinding[pDescriptorCopies[i].dstArrayElement + d];

                if(bind.texelBufferView != VK_NULL_HANDLE)
                {
                    dstrecord->RemoveBindFrameRef(GetResID(bind.texelBufferView));
                    if(GetRecord(bind.texelBufferView)->baseResource != ResourceId())
                        dstrecord->RemoveBindFrameRef(GetRecord(bind.texelBufferView)->baseResource);
                }
                if(bind.imageInfo.imageView != VK_NULL_HANDLE)
                {
                    dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView));
                    dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource);
                    if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId())
                        dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem);
                }
                if(bind.imageInfo.sampler != VK_NULL_HANDLE)
                {
                    dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler));
                }
                if(bind.bufferInfo.buffer != VK_NULL_HANDLE)
                {
                    dstrecord->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer));
                    if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId())
                        dstrecord->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource);
                }

                bind = srcbinding[pDescriptorCopies[i].srcArrayElement + d];

                if(bind.texelBufferView != VK_NULL_HANDLE)
                {
                    dstrecord->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, GetRecord(bind.texelBufferView)->sparseInfo != NULL);
                    if(GetRecord(bind.texelBufferView)->baseResource != ResourceId())
                        dstrecord->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref);
                }
                if(bind.imageInfo.imageView != VK_NULL_HANDLE)
                {
                    dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL);
                    dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref);
                    if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId())
                        dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, eFrameRef_Read);
                }
                if(bind.imageInfo.sampler != VK_NULL_HANDLE)
                {
                    dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.sampler), ref);
                }
                if(bind.bufferInfo.buffer != VK_NULL_HANDLE)
                {
                    dstrecord->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL);
                    if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId())
                        dstrecord->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref);
                }
            }
        }

    }
}
VkResult WrappedVulkan::vkAllocateDescriptorSets(
    VkDevice                                    device,
    const VkDescriptorSetAllocateInfo*          pAllocateInfo,
    VkDescriptorSet*                            pDescriptorSets)
{
    size_t tempmemSize = sizeof(VkDescriptorSetAllocateInfo) + sizeof(VkDescriptorSetLayout)*pAllocateInfo->descriptorSetCount;

    byte *memory = GetTempMemory(tempmemSize);

    VkDescriptorSetAllocateInfo *unwrapped = (VkDescriptorSetAllocateInfo *)memory;
    VkDescriptorSetLayout *layouts = (VkDescriptorSetLayout *)(unwrapped + 1);

    *unwrapped = *pAllocateInfo;
    unwrapped->pSetLayouts = layouts;
    unwrapped->descriptorPool = Unwrap(unwrapped->descriptorPool);
    for(uint32_t i=0; i < pAllocateInfo->descriptorSetCount; i++)
        layouts[i] = Unwrap(pAllocateInfo->pSetLayouts[i]);

    VkResult ret = ObjDisp(device)->AllocateDescriptorSets(Unwrap(device), unwrapped, pDescriptorSets);

    if(ret != VK_SUCCESS) return ret;

    for(uint32_t i=0; i < pAllocateInfo->descriptorSetCount; i++)
    {
        ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), pDescriptorSets[i]);

        if(m_State >= WRITING)
        {
            Chunk *chunk = NULL;

            {
                CACHE_THREAD_SERIALISER();

                VkDescriptorSetAllocateInfo info = *pAllocateInfo;
                info.descriptorSetCount = 1;
                info.pSetLayouts += i;

                SCOPED_SERIALISE_CONTEXT(ALLOC_DESC_SET);
                Serialise_vkAllocateDescriptorSets(localSerialiser, device, &info, &pDescriptorSets[i]);

                chunk = scope.Get();
            }

            VkResourceRecord *record = GetResourceManager()->AddResourceRecord(pDescriptorSets[i]);
            record->AddChunk(chunk);

            ResourceId layoutID = GetResID(pAllocateInfo->pSetLayouts[i]);
            VkResourceRecord *layoutRecord = GetRecord(pAllocateInfo->pSetLayouts[i]);

            VkResourceRecord *poolrecord = GetRecord(pAllocateInfo->descriptorPool);

            {
                poolrecord->LockChunks();
                poolrecord->pooledChildren.push_back(record);
                poolrecord->UnlockChunks();
            }

            record->pool = poolrecord;

            record->AddParent(poolrecord);
            record->AddParent(GetResourceManager()->GetResourceRecord(layoutID));

            // just always treat descriptor sets as dirty
            {
                SCOPED_LOCK(m_CapTransitionLock);
                if(m_State != WRITING_CAPFRAME)
                    GetResourceManager()->MarkDirtyResource(id);
                else
                    GetResourceManager()->MarkPendingDirty(id);
            }

            record->descInfo = new DescriptorSetData();
            record->descInfo->layout = layoutRecord->descInfo->layout;
            record->descInfo->layout->CreateBindingsArray(record->descInfo->descBindings);
        }
        else
        {
            GetResourceManager()->AddLiveResource(id, pDescriptorSets[i]);
        }
    }

    return ret;
}
VkResult WrappedVulkan::vkCreateDescriptorSetLayout(
    VkDevice                                    device,
    const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkDescriptorSetLayout*                      pSetLayout)
{
    size_t tempmemSize = sizeof(VkDescriptorSetLayoutBinding)*pCreateInfo->bindingCount;

    // need to count how many VkSampler arrays to allocate for
    for(uint32_t i=0; i < pCreateInfo->bindingCount; i++)
        if(pCreateInfo->pBindings[i].pImmutableSamplers)
            tempmemSize += pCreateInfo->pBindings[i].descriptorCount*sizeof(VkSampler);

    byte *memory = GetTempMemory(tempmemSize);

    VkDescriptorSetLayoutBinding *unwrapped = (VkDescriptorSetLayoutBinding *)memory;
    VkSampler *nextSampler = (VkSampler *)(unwrapped + pCreateInfo->bindingCount);

    for(uint32_t i=0; i < pCreateInfo->bindingCount; i++)
    {
        unwrapped[i] = pCreateInfo->pBindings[i];

        if(unwrapped[i].pImmutableSamplers)
        {
            VkSampler *unwrappedSamplers = nextSampler;
            nextSampler += unwrapped[i].descriptorCount;
            for(uint32_t j=0; j < unwrapped[i].descriptorCount; j++)
                unwrappedSamplers[j] = Unwrap(unwrapped[i].pImmutableSamplers[j]);
            unwrapped[i].pImmutableSamplers = unwrappedSamplers;
        }
    }

    VkDescriptorSetLayoutCreateInfo unwrappedInfo = *pCreateInfo;
    unwrappedInfo.pBindings = unwrapped;
    VkResult ret = ObjDisp(device)->CreateDescriptorSetLayout(Unwrap(device), &unwrappedInfo, pAllocator, pSetLayout);

    if(ret == VK_SUCCESS)
    {
        ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), *pSetLayout);

        if(m_State >= WRITING)
        {
            Chunk *chunk = NULL;

            {
                CACHE_THREAD_SERIALISER();

                SCOPED_SERIALISE_CONTEXT(CREATE_DESCRIPTOR_SET_LAYOUT);
                Serialise_vkCreateDescriptorSetLayout(localSerialiser, device, pCreateInfo, NULL, pSetLayout);

                chunk = scope.Get();
            }

            VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pSetLayout);
            record->AddChunk(chunk);

            record->descInfo = new DescriptorSetData();
            record->descInfo->layout = new DescSetLayout();
            record->descInfo->layout->Init(GetResourceManager(), m_CreationInfo, pCreateInfo);
        }
        else
        {
            GetResourceManager()->AddLiveResource(id, *pSetLayout);

            m_CreationInfo.m_DescSetLayout[id].Init(GetResourceManager(), m_CreationInfo, &unwrappedInfo);
        }
    }

    return ret;
}
示例#7
0
VkResult WrappedVulkan::vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache,
                                                  uint32_t count,
                                                  const VkGraphicsPipelineCreateInfo *pCreateInfos,
                                                  const VkAllocationCallbacks *pAllocator,
                                                  VkPipeline *pPipelines)
{
  // conservatively request memory for 5 stages on each pipeline
  // (worst case - can't have compute stage). Avoids needing to count
  byte *unwrapped = GetTempMemory(sizeof(VkGraphicsPipelineCreateInfo) * count +
                                  sizeof(VkPipelineShaderStageCreateInfo) * count * 5);

  // keep pipelines first in the memory, then the stages
  VkGraphicsPipelineCreateInfo *unwrappedInfos = (VkGraphicsPipelineCreateInfo *)unwrapped;
  VkPipelineShaderStageCreateInfo *nextUnwrappedStages =
      (VkPipelineShaderStageCreateInfo *)(unwrappedInfos + count);

  for(uint32_t i = 0; i < count; i++)
  {
    VkPipelineShaderStageCreateInfo *unwrappedStages = nextUnwrappedStages;
    nextUnwrappedStages += pCreateInfos[i].stageCount;
    for(uint32_t j = 0; j < pCreateInfos[i].stageCount; j++)
    {
      unwrappedStages[j] = pCreateInfos[i].pStages[j];
      unwrappedStages[j].module = Unwrap(unwrappedStages[j].module);
    }

    unwrappedInfos[i] = pCreateInfos[i];
    unwrappedInfos[i].pStages = unwrappedStages;
    unwrappedInfos[i].layout = Unwrap(unwrappedInfos[i].layout);
    unwrappedInfos[i].renderPass = Unwrap(unwrappedInfos[i].renderPass);
    unwrappedInfos[i].basePipelineHandle = Unwrap(unwrappedInfos[i].basePipelineHandle);
  }

  VkResult ret = ObjDisp(device)->CreateGraphicsPipelines(
      Unwrap(device), Unwrap(pipelineCache), count, unwrappedInfos, pAllocator, pPipelines);

  if(ret == VK_SUCCESS)
  {
    for(uint32_t i = 0; i < count; i++)
    {
      ResourceId id = GetResourceManager()->WrapResource(Unwrap(device), pPipelines[i]);

      if(m_State >= WRITING)
      {
        Chunk *chunk = NULL;

        {
          CACHE_THREAD_SERIALISER();

          VkGraphicsPipelineCreateInfo modifiedCreateInfo;
          const VkGraphicsPipelineCreateInfo *createInfo = &pCreateInfos[i];

          // since we serialise one by one, we need to fixup basePipelineIndex
          if(createInfo->basePipelineIndex != -1 && createInfo->basePipelineIndex < (int)i)
          {
            modifiedCreateInfo = *createInfo;
            modifiedCreateInfo.basePipelineHandle = pPipelines[modifiedCreateInfo.basePipelineIndex];
            modifiedCreateInfo.basePipelineIndex = -1;
            createInfo = &modifiedCreateInfo;
          }

          SCOPED_SERIALISE_CONTEXT(CREATE_GRAPHICS_PIPE);
          Serialise_vkCreateGraphicsPipelines(localSerialiser, device, pipelineCache, 1, createInfo,
                                              NULL, &pPipelines[i]);

          chunk = scope.Get();
        }

        VkResourceRecord *record = GetResourceManager()->AddResourceRecord(pPipelines[i]);
        record->AddChunk(chunk);

        if(pipelineCache != VK_NULL_HANDLE)
        {
          VkResourceRecord *cacherecord = GetRecord(pipelineCache);
          record->AddParent(cacherecord);
        }

        VkResourceRecord *rprecord = GetRecord(pCreateInfos[i].renderPass);
        record->AddParent(rprecord);

        VkResourceRecord *layoutrecord = GetRecord(pCreateInfos[i].layout);
        record->AddParent(layoutrecord);

        for(uint32_t s = 0; s < pCreateInfos[i].stageCount; s++)
        {
          VkResourceRecord *modulerecord = GetRecord(pCreateInfos[i].pStages[s].module);
          record->AddParent(modulerecord);
        }
      }
      else
      {
        GetResourceManager()->AddLiveResource(id, pPipelines[i]);

        m_CreationInfo.m_Pipeline[id].Init(GetResourceManager(), m_CreationInfo, &unwrappedInfos[i]);
      }
    }
  }

  return ret;
}