Large AVStream DMA transfers; DMA in upper drivers

I’ve been struggling to fully understand several aspects of AVStream and how to effectively utilize DMA given my device’s capabilities and constraints. I have several questions in this regard.

1.) Is is possible to use packet-based DMA without using scatter/gather? Since the buffers provided by AVStream are physically contiguous, I would think it should be possible to transfer a whole frame in a single DMA operation as long as the hardware supports such large transfers (mine does). However, I can’t figure out how to obtain a bus logical address for the buffers (and using the physical address directly seems to be a no-no).

Of course I could get bus logical addresses for scatter/gather mappings by specifying KSPIN_FLAGS_GENERATE_MAPPINGS. However, despite specifying a large value (larger than the frame size) for MaxMappingsByteCount in IKsDeviceFunctions::RegisterAdapterObjectEx() and for MaximumLength in DEVICE_DESCRIPTION, I still get a list of numerous small mappings, whereas I would like a single mapping large enough to transfer the whole frame in one operation (my hardware does not support scatter/gather).

2.) Could someone point out some documentation that describes how allocators are selected? The “AVStream Allocators” points out that the vendor-supplied allocator (I assume that the AVStream default allocator still counts as the “vendor-supplied” allocator if custom allocator dispatch routines are not used?) is not guaranteed to be used.

Does this mean that if I have alignment constraints (my DMA hardware requires a strict alignment) specified in my AllocatorFraming, it could be violated due to the use of some other downstream allocator? Is there any way to safeguard against this short of using a common buffer with known alignment and CPU copying the data into the AVStream buffer?

3.) Though IoGetDmaAdapter() works when my driver sits directly on top of pci.sys, the call fails and returns NULL if I introduce an intermediate bus driver between the two. How, if at all, can I obtain a DMA adapter in the AVStream driver if the driver is higher up in the stack?

xxxxx@cspeed.com wrote:

1.) Is is possible to use packet-based DMA without using scatter/gather? Since the buffers provided by AVStream are physically contiguous, I would think it should be possible to transfer a whole frame in a single DMA operation as long as the hardware supports such large transfers (mine does). However, I can’t figure out how to obtain a bus logical address for the buffers (and using the physical address directly seems to be a no-no).

The buffers provided by AVStream are certainly not physically
contiguous. Where did you get that impression? They are typically
allocated in user mode, by DirectShow. If you happen to have a minimal
graph, where your capture device can render directly into an overlay
surface or a texture surface on your graphics card, that would be
physically contiguous, but that’s not the normal case.

The officially blessed mechanism for getting a bus address is to use a
DMA adapter, from IoGetDmaAdapter.

…whereas I would like a single mapping large enough to transfer the whole frame in one operation (my hardware does not support scatter/gather).

If your hardware does not support scatter/gather, then you must allocate
a common buffer and copy the data for each frame. There is no alternative.

2.) Could someone point out some documentation that describes how allocators are selected? The “AVStream Allocators” points out that the vendor-supplied allocator (I assume that the AVStream default allocator still counts as the “vendor-supplied” allocator if custom allocator dispatch routines are not used?) is not guaranteed to be used.

An AVStream driver is almost always used as part of a DirectShow graph.
In that case, the DirectShow graph manager is responsible for
negotiating the allocator. It generally prefers to use the default
DirectShow allocator, unless it can determine (through a heuristic that
is not clear to me) that the default one is not acceptable.

Does this mean that if I have alignment constraints (my DMA hardware requires a strict alignment) specified in my AllocatorFraming, it could be violated due to the use of some other downstream allocator?

Absolutely, although in my experience, the negotiated allocator usually
honors your alignment requirements. It doesn’t know anything about your
physically contiguous requirement, however.

Is there any way to safeguard against this short of using a common buffer with known alignment and CPU copying the data into the AVStream buffer?

Nope. A common buffer is the only choice.

3.) Though IoGetDmaAdapter() works when my driver sits directly on top of pci.sys, the call fails and returns NULL if I introduce an intermediate bus driver between the two. How, if at all, can I obtain a DMA adapter in the AVStream driver if the driver is higher up in the stack?

Your bus driver will need to be involved, through some kind of API. It
can make its PDO available to the upper layers, or it can create the DMA
adapter and send it up, or it can manage all of the DMA itself as a
service to the upper layers.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

On the AVStream Allocators documentation page, it states that “The AVStream class driver uses an Allocator to allocate data buffers in units called frames. A frame is a chunk of physically contiguous memory, the size of which is vendor-specified through the AllocatorFraming member of KSPIN_DESCRIPTOR_EX.” The documentation makes it sound as though the data buffers are physically contiguous, but I must have misinterpreted.

Based on what you’ve stated, it seems like the common buffer approach is probably the safest bet. I’m a little disappointed to resort to CPU copying, but if that’s the cost of a guarantee, it my be in our best interest. That being the case, and with regard to my comments about the driver stack, it would probably make sense in our design for the bus driver to take care of the DMA.

Nonetheless, I’m still curious about using IoGetDmaAdapter() directly from the AVStream driver. Are you suggesting to use the PDO of the bus driver as the PhysicalDeviceObject argument to IoGetDmaAdapter()? I had trouble (crash in nt during the execution of IoGetDmaAdapter(), but I don’t have the dump anymore) when I tried this approach, but I’ll have another look at it tomorrow.

As always, thanks for the response!

xxxxx@cspeed.com wrote:

On the AVStream Allocators documentation page, it states that “The AVStream class driver uses an Allocator to allocate data buffers in units called frames. A frame is a chunk of physically contiguous memory, the size of which is vendor-specified through the AllocatorFraming member of KSPIN_DESCRIPTOR_EX.” The documentation makes it sound as though the data buffers are physically contiguous, but I must have misinterpreted.

Interesting. I’m going to submit a documentation bug report about that,
because as far as I know that has never been the case. The correct
statement is farther down the page: “The default allocator allocates
pool memory based on the allocator requirements”… Pool memory is
virtually contiguous, but not physically contiguous.

Based on what you’ve stated, it seems like the common buffer approach is probably the safest bet. I’m a little disappointed to resort to CPU copying, but if that’s the cost of a guarantee, it my be in our best interest.

Today’s CPUs copy memory really, really quickly. Copying a full,
uncompressed HD stream at 200MB/sec is less than 5% of a modern CPU.

Nonetheless, I’m still curious about using IoGetDmaAdapter() directly from the AVStream driver. Are you suggesting to use the PDO of the bus driver as the PhysicalDeviceObject argument to IoGetDmaAdapter()? I had trouble (crash in nt during the execution of IoGetDmaAdapter(), but I don’t have the dump anymore) when I tried this approach, but I’ll have another look at it tomorrow.

Theoretically, that should work. IoGetDmaAdapter needs to see a PDO
that was created by the PCI bus driver. So, assuming your bus driver is
a direct child of the PCI bus, it’s PDO should qualify. If there’s some
other magic going on, then you need a different spell.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.