Can D3D12 resource barriers be used to synchronize between the compute and 3D engine? What is the best way to synchronize resource access between the (async) compute engine and the 3d engine (aka. direct engine) in D3D 12?

I found this paragraph about multi-engine synchronization on MSDN but it's not very detailed.

You can certainly use a fence for synchronization but then you'd have split the command lists for both engines since fences only operate on queues.

According to the documentation, the 3d engine and the compute engine share the same resource state (only the copy engine has it's own resource state). So if you write to a resource using the async compute engine and then read from it using the 3d engine, is there a way to synchronize this via resource barriers?

I doubt that it works if you use the compute engine to submit a resource barrier since the 3d engine probably won't wait automatically if the resource state is wrong. Same issue if you use the 3d engine for the resource transition (it could happen that the resource state is being changed while the compute engine is still writing to the resource).

Do you have to use split barriers? You could use the compute engine with the D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY flag and the 3d engine with the D3D12_RESOURCE_BARRIER_FLAG_END_ONLY flag. Unfortunately, the documentation doesn't say whether split barriers can be used across engines. What happens if the direct engine executes the end barrier before the compute engine has executed the start barrier?
My understanding would be that resource barriers are not at all about synchronization. They are about memory ordering, which is a related but separate concern. Basically, synchronization is about making sure that A happens before B. Memory ordering is about making sure that if A did X, someone how saw A happen will always also see X and no one will ever see X without first also having seen A happen.

In Direct3D terms, resource barriers are about making sure that if shader A writes to texture X, shader B running after shader A actually gets to see the result of shader A having written to texture X. Fences, on the other hand, are about making sure that shader A actually runs before shader B.

Direct3D resource barriers are just you stating in which way you are going to be using a resource. You cannot rely on just a resource barrier to automagically perform the necessary synchronization for you. The section you linked would seem to agree (emphasis mine):


  
  Although resource state is shared across all Compute and 3D queues, it is not permitted to write to the resource simultaneously on different queues. "Simultaneously" here means unsynchronized, noting unsynchronized execution is not possible on some hardware. The following rules apply.  
  
  
  Only one queue can write to a resource at a time.
  Multiple queues can read from the resource as long as they don’t read the bytes being modified by the writer (reading bytes being simultaneously written produces undefined results).  
  A fence must be used to synchronize after writing before another queue can read the written bytes or make any write access.