mirror of
git://nv-tegra.nvidia.com/tegra/nv-sci-src/nvsci_samples.git
synced 2025-12-22 09:21:21 +03:00
2eba699906039d6615aae4967f6ea79bfe44a40a - event_sample_app/block_pool.c f3abb0a884f0647204ad32ff51255c4712e52120 - event_sample_app/Makefile 9ee49033e077ac5c8bf458a04c91dd3dbed9633d - event_sample_app/event_loop.h b33adce6eb1bbc7af23f6c37b6a635479e18a66a - event_sample_app/block_returnsync.c a56041c06b6bc1d3812b72b399d7d78dd7895485 - event_sample_app/block_limiter.c ca34c957759f7a010f0cbbbf9bedc03a2c98092b - event_sample_app/block_c2c.c 8d6d0ec3aa8e374a1d2a5fedc9dd24ff7bbdb731 - event_sample_app/block_multicast.c a76149a2531899e35843d939f60ad8979d8cf65f - event_sample_app/block_consumer_uc1.c 9da8763e4af4b4b7278507a3ebfe2c68a7a24585 - event_sample_app/util.h 2bf7e1383d6e8913c9b0a6a8bdd48fe63d8098d0 - event_sample_app/block_producer_uc1.c a54abf82eaa2d888e379ab4596ba68ce264e80b5 - event_sample_app/block_info.h 080a6efe263be076c7046e70e31098c2bbed0f6d - event_sample_app/block_presentsync.c 7dd10e5ea71f0c4a09bbe1f9f148f67a13ee098c - event_sample_app/util.c bc1a6f9017b28e5707c166a658a35e6b3986fdf4 - event_sample_app/usecase1.h 317f43efc59638bf1eae8303f0c79eafb059241a - event_sample_app/block_ipc.c 40361c8f0b68f7d5207db2466ce08c19c0bf1c90 - event_sample_app/event_loop_service.c efad113d0107e5d8f90146f3102a7c0ed22f1a35 - event_sample_app/event_loop_threads.c 2908615cebcf36330b9850c57e8745bf324867b2 - event_sample_app/block_queue.c 36ed68eca1a7800cf0d94e763c9fc352ee8cda1e - event_sample_app/block_common.c 675f75d61bd0226625a8eaaf0e503c9e976c8d61 - event_sample_app/main.c c3b26619dd07d221e953fc5dc29a50dcb95a8b97 - rawstream/Makefile 1fbb82e2281bb2e168c87fd20903bbed898ca160 - rawstream/rawstream_cuda.c 1d96498fe3c922f143f7e50e0a32b099714060ad - rawstream/rawstream_consumer.c d077dafc9176686f6d081026225325c2a303a60e - rawstream/rawstream_producer.c 54ae655edddda7dcabe22fbf0b27c3f617978851 - rawstream/rawstream.h d5ffeef3c7ad2af6f6f31385db7917b5ef9a7438 - rawstream/rawstream_ipc_linux.c 81e3d6f8ff5252797a7e9e170b74df6255f54f1b - rawstream/rawstream_main.c Change-Id: I0f4e671693eb0addfe8d0e6532cc8f240cb6c778
753 lines
28 KiB
C
753 lines
28 KiB
C
//! \file
|
|
//! \brief NvStreams rawstream producer file.
|
|
//!
|
|
//! \copyright
|
|
//! SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
//! SPDX-License-Identifier: LicenseRef-NvidiaProprietary
|
|
//!
|
|
//! NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
|
|
//! property and proprietary rights in and to this material, related
|
|
//! documentation and any modifications thereto. Any use, reproduction,
|
|
//! disclosure or distribution of this material and related documentation
|
|
//! without an express license agreement from NVIDIA CORPORATION or
|
|
//! its affiliates is strictly prohibited.
|
|
|
|
#include "rawstream.h"
|
|
|
|
extern int late_attach;
|
|
|
|
void* producerFunc(void* arg)
|
|
{
|
|
CudaClientInfo cudaInfo;
|
|
NvSciError sciErr;
|
|
int cudaErr;
|
|
void* recvWaitListDesc = NULL;
|
|
void* recvObjAndListDesc = NULL;
|
|
void* consumerReadAttrsDesc = NULL;
|
|
|
|
*(int*)arg = 1;
|
|
fprintf(stderr, "Producer starting\n");
|
|
|
|
// Do common cuda initialization
|
|
if (!setupCuda(&cudaInfo)) {
|
|
goto done;
|
|
}
|
|
|
|
// Create an empty sync attribute list for signaling permissions.
|
|
sciErr = NvSciSyncAttrListCreate(syncModule, &producerSignalAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to create producer signal attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Query CUDA for attributes needed to signal syncs
|
|
cudaErr = cudaDeviceGetNvSciSyncAttributes(producerSignalAttrs,
|
|
cudaInfo.deviceId,
|
|
cudaNvSciSyncAttrSignal);
|
|
if (cudaSuccess != cudaErr) {
|
|
fprintf(stderr,
|
|
"Could not query signal attributes from CUDA (%d)\n",
|
|
cudaErr);
|
|
goto done;
|
|
}
|
|
|
|
fprintf(stderr, "Producer signal attributes established\n");
|
|
|
|
// Create an empty sync attribute list for waiting permissions.
|
|
sciErr = NvSciSyncAttrListCreate(syncModule, &producerWaitAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to create producer wait attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Query CUDA for attributes needed to wait for syncs
|
|
cudaErr = cudaDeviceGetNvSciSyncAttributes(producerWaitAttrs,
|
|
cudaInfo.deviceId,
|
|
cudaNvSciSyncAttrWait);
|
|
if (cudaSuccess != cudaErr) {
|
|
fprintf(stderr,
|
|
"Could not query wait attributes from CUDA (%d)\n",
|
|
cudaErr);
|
|
goto done;
|
|
}
|
|
|
|
fprintf(stderr, "Producer wait attributes established\n");
|
|
|
|
// Export producer's wait attributes to a form suitable for IPC
|
|
size_t sendWaitAttrListSize = 0U;
|
|
void* sendWaitListDesc = NULL;
|
|
sciErr = NvSciSyncAttrListIpcExportUnreconciled(&producerWaitAttrs,
|
|
1,
|
|
ipcWrapper.endpoint,
|
|
&sendWaitListDesc,
|
|
&sendWaitAttrListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to export producer wait attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the size of the producer's wait attributes to the consumer,
|
|
// so it knows how much data to expect
|
|
sciErr = ipcSend(&ipcWrapper,
|
|
&sendWaitAttrListSize,
|
|
sizeof(sendWaitAttrListSize));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to send producer wait attrs size (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the exported form of the producer's wait attributes
|
|
sciErr = ipcSend(&ipcWrapper,
|
|
sendWaitListDesc,
|
|
sendWaitAttrListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to send producer wait attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Wait to receive the size of the consumer's wait attributes
|
|
size_t recvWaitAttrListSize = 0U;
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
&recvWaitAttrListSize,
|
|
sizeof(recvWaitAttrListSize));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to recv consumer wait attr size (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Allocate a buffer big enough to receive the consumer's wait attributes
|
|
recvWaitListDesc = malloc(recvWaitAttrListSize);
|
|
if (NULL == recvWaitListDesc) {
|
|
sciErr = NvSciError_InsufficientMemory;
|
|
fprintf(stderr,
|
|
"Sync attr allocation failed (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Wait to receive consumer's wait attributes
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
recvWaitListDesc,
|
|
recvWaitAttrListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to recv consumer wait attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Convert the received consumer wait attributes to an attribute list
|
|
sciErr = NvSciSyncAttrListIpcImportUnreconciled(syncModule,
|
|
ipcWrapper.endpoint,
|
|
recvWaitListDesc,
|
|
recvWaitAttrListSize,
|
|
&consumerWaitAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to import consumer wait attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Get combined attributes for producer to consumer signaling
|
|
NvSciSyncAttrList syncAllAttrs[2], syncConflictAttrs;
|
|
syncAllAttrs[0] = producerSignalAttrs;
|
|
syncAllAttrs[1] = consumerWaitAttrs;
|
|
sciErr = NvSciSyncAttrListReconcile(syncAllAttrs,
|
|
2,
|
|
&prodToConsAttrs,
|
|
&syncConflictAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't merge producer->consumer attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Allocate producer to consumer sync object
|
|
sciErr = NvSciSyncObjAlloc(prodToConsAttrs, &producerSignalObj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't allocate producer->consumer sync (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Export sync attributes and object to a form suitable for IPC
|
|
void* sendObjAndListDesc = NULL;
|
|
size_t sendObjAndListSize = 0U;
|
|
sciErr = NvSciSyncIpcExportAttrListAndObj(producerSignalObj,
|
|
NvSciSyncAccessPerm_WaitOnly,
|
|
ipcWrapper.endpoint,
|
|
&sendObjAndListDesc,
|
|
&sendObjAndListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't export producer->consumer sync description (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the size of the sync description to the consumer,
|
|
// so it knows how much data to expect
|
|
sciErr = ipcSend(&ipcWrapper, &sendObjAndListSize, sizeof(size_t));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't send producer->consumer sync description size(%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the sync description to the consumer
|
|
sciErr = ipcSend(&ipcWrapper, sendObjAndListDesc, sendObjAndListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't send producer->consumer sync description (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Wait to receive the size of the consumer->producer sync desription
|
|
size_t recvObjAndListSize = 0U;
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
&recvObjAndListSize,
|
|
sizeof(size_t));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't recv consumer->produce sync description size (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Allocate a buffer big enough to receive the description
|
|
recvObjAndListDesc = malloc(recvObjAndListSize);
|
|
if (NULL == recvObjAndListDesc) {
|
|
sciErr = NvSciError_InsufficientMemory;
|
|
fprintf(stderr,
|
|
"Sync description allocation failed (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Wait to receive consumer->producer sync description
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
recvObjAndListDesc,
|
|
recvObjAndListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't receive consumer->producer sync description (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Convert the received consumer->producer sync description to a
|
|
// sync attribute list and object
|
|
sciErr = NvSciSyncIpcImportAttrListAndObj(syncModule,
|
|
ipcWrapper.endpoint,
|
|
recvObjAndListDesc,
|
|
recvObjAndListSize,
|
|
&producerWaitAttrs,
|
|
1,
|
|
NvSciSyncAccessPerm_WaitOnly,
|
|
ipcWrapper.endpoint,
|
|
&producerWaitObj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't import consumer->producer sync (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Set up CUDA sync objects, importing NvSciSync objects
|
|
if (!setupCudaSync(&cudaInfo, producerSignalObj, producerWaitObj)) {
|
|
goto done;
|
|
}
|
|
|
|
fprintf(stderr, "Producer exchanged sync objects with consumer\n");
|
|
|
|
// Create an empty buffer attribute list for producer buffers
|
|
sciErr = NvSciBufAttrListCreate(bufModule, &producerWriteAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to create producer buffer attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Fill producer buffer attribute list with values
|
|
NvSciBufAttrKeyValuePair bufKeyValue[7];
|
|
NvSciRmGpuId gpuId;
|
|
memcpy(&gpuId.bytes, &cudaInfo.uuid.bytes, sizeof(cudaInfo.uuid.bytes));
|
|
bufKeyValue[0].key = NvSciBufGeneralAttrKey_GpuId;
|
|
bufKeyValue[0].value = &gpuId;
|
|
bufKeyValue[0].len = sizeof(gpuId);
|
|
NvSciBufType bufType = NvSciBufType_RawBuffer;
|
|
bufKeyValue[1].key = NvSciBufGeneralAttrKey_Types;
|
|
bufKeyValue[1].value = &bufType;
|
|
bufKeyValue[1].len = sizeof(bufType);
|
|
NvSciBufAttrValAccessPerm bufPerm = NvSciBufAccessPerm_ReadWrite;
|
|
bufKeyValue[2].key = NvSciBufGeneralAttrKey_RequiredPerm;
|
|
bufKeyValue[2].value = &bufPerm;
|
|
bufKeyValue[2].len = sizeof(bufPerm);
|
|
bool bufAccessFlag = true;
|
|
bufKeyValue[3].key = NvSciBufGeneralAttrKey_NeedCpuAccess;
|
|
bufKeyValue[3].value = &bufAccessFlag;
|
|
bufKeyValue[3].len = sizeof(bufAccessFlag);
|
|
uint64_t rawsize = (128 * 1024);
|
|
bufKeyValue[4].key = NvSciBufRawBufferAttrKey_Size;
|
|
bufKeyValue[4].value = &rawsize;
|
|
bufKeyValue[4].len = sizeof(rawsize);
|
|
uint64_t align = (4 * 1024);
|
|
bufKeyValue[5].key = NvSciBufRawBufferAttrKey_Align;
|
|
bufKeyValue[5].value = &align;
|
|
bufKeyValue[5].len = sizeof(align);
|
|
if (late_attach) {
|
|
// Add late peer location attribute
|
|
NvSciBufPeerLocationInfo peerLocation;
|
|
peerLocation.socID = NV_SCI_BUF_PEER_INFO_SELF_SOCID;
|
|
peerLocation.vmID = NV_SCI_BUF_PEER_INFO_SELF_VMID;
|
|
peerLocation.reserved = 0;
|
|
bufKeyValue[6].key = NvSciBufGeneralAttrKey_PeerLocationInfo;
|
|
bufKeyValue[6].value = &peerLocation;
|
|
bufKeyValue[6].len = sizeof(peerLocation);
|
|
sciErr = NvSciBufAttrListSetAttrs(producerWriteAttrs, bufKeyValue, 7);
|
|
} else {
|
|
sciErr = NvSciBufAttrListSetAttrs(producerWriteAttrs, bufKeyValue, 6);
|
|
}
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Unable to fill producer buffer attrs (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
fprintf(stderr, "Producer buffer attributes established\n");
|
|
|
|
|
|
void* sendBufListDesc = NULL;
|
|
|
|
if (late_attach) {
|
|
// We don't have peer attributes. Just reconciled our own attributes
|
|
NvSciBufAttrList bufAllAttrs[2], bufConflictAttrs;
|
|
bufAllAttrs[0] = producerWriteAttrs;
|
|
// bufAllAttrs[1] = consumerReadAttrs;
|
|
sciErr = NvSciBufAttrListReconcile(bufAllAttrs, 1,
|
|
&combinedBufAttrs, &bufConflictAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't merge buffer attrs (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Allocate all buffers
|
|
for (uint32_t i=0U; i<totalBuffers; ++i) {
|
|
|
|
Buffer* buf = &buffers[i];
|
|
// Allocate the buffer
|
|
sciErr = NvSciBufObjAlloc(combinedBufAttrs, &buf->obj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't allocate buffer %d (%x)\n", i, sciErr);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait to receive the size of the consumer's buffer attributes
|
|
size_t consumerReadAttrsSize = 0U;
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
&consumerReadAttrsSize,
|
|
sizeof(consumerReadAttrsSize));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to recv consumer buffer attr size (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Allocate a buffer big enough to receive the consumer's buffer attributes
|
|
consumerReadAttrsDesc = malloc(consumerReadAttrsSize);
|
|
if (NULL == recvWaitListDesc) {
|
|
sciErr = NvSciError_InsufficientMemory;
|
|
fprintf(stderr, "Buffer attr allocation failed(%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Wait to receive the consumer's buffer attributes
|
|
sciErr = ipcRecvFill(&ipcWrapper,
|
|
consumerReadAttrsDesc,
|
|
consumerReadAttrsSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Unable to recv consumer buffer attrs (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Convert the received consumer buffer attributes to an attribute list
|
|
sciErr = NvSciBufAttrListIpcImportUnreconciled(bufModule,
|
|
ipcWrapper.endpoint,
|
|
consumerReadAttrsDesc,
|
|
consumerReadAttrsSize,
|
|
&consumerReadAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to import consumer buffer attrs (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Get combined attributes for buffers
|
|
NvSciBufAttrList bufAllAttrs[2], bufConflictAttrs;
|
|
bufAllAttrs[0] = producerWriteAttrs;
|
|
bufAllAttrs[1] = consumerReadAttrs;
|
|
sciErr = NvSciBufAttrListReconcile(bufAllAttrs, 2,
|
|
&combinedBufAttrs, &bufConflictAttrs);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't merge buffer attrs (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Export combined buffer attributes to a form suitable for IPC
|
|
sendBufListDesc = NULL;
|
|
size_t sendBufListSize = 0U;
|
|
sciErr = NvSciBufAttrListIpcExportReconciled(combinedBufAttrs,
|
|
ipcWrapper.endpoint,
|
|
&sendBufListDesc,
|
|
&sendBufListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't export reconciled buffer attrs to consumer (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the size of the combined buffer attributes to the consumer,
|
|
// so it knows how much data to expect
|
|
sciErr = ipcSend(&ipcWrapper,
|
|
&sendBufListSize,
|
|
sizeof(sendBufListSize));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to send combined buffer attrs size (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the exported form of the combined buffer attributes
|
|
sciErr = ipcSend(&ipcWrapper,
|
|
sendBufListDesc,
|
|
sendBufListSize);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Unable to send combined buffer attrs (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
|
|
// Extract attributes needed by CUDA
|
|
if (!setupCudaBufAttr(&cudaInfo, combinedBufAttrs)) {
|
|
goto done;
|
|
}
|
|
|
|
// Export all buffers
|
|
for (uint32_t i=0U; i<totalBuffers; ++i) {
|
|
|
|
Buffer* buf = &buffers[i];
|
|
|
|
if (0 == late_attach) {
|
|
// Allocate the buffer
|
|
sciErr = NvSciBufObjAlloc(combinedBufAttrs, &buf->obj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't allocate buffer %d (%x)\n", i, sciErr);
|
|
goto done;
|
|
}
|
|
} else {
|
|
NvSciBufAttrList bufAllAttrs[1];
|
|
///NV
|
|
//Use imported consumer attribute list.
|
|
// bufAllAttrs[0] = producerWriteAttrs;
|
|
bufAllAttrs[0] = consumerReadAttrs;
|
|
// Invoke NvSciBufObjAttachPeer() before exporting the SciBufObj
|
|
sciErr = NvSciBufObjAttachPeer(buf->obj, bufAllAttrs, 1);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "NvSciBufObjAttachPeer call failed error: %x\n", sciErr);
|
|
goto done;
|
|
} else {
|
|
fprintf(stderr, "NvSciBufObjAttachPeer call succeeded\n");
|
|
}
|
|
}
|
|
|
|
// Export buffer object to a form suitable for IPC
|
|
// Note: Unlike attribute lists, the exported form of objects has
|
|
// a fixed size.
|
|
NvSciBufObjIpcExportDescriptor objDesc;
|
|
sciErr = NvSciBufObjIpcExport(buf->obj,
|
|
NvSciBufAccessPerm_ReadWrite,
|
|
ipcWrapper.endpoint,
|
|
&objDesc);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Unable to export buffer %d object to consumer (%x)\n",
|
|
i, sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send the buffer description to the consumer
|
|
sciErr = ipcSend(&ipcWrapper,
|
|
&objDesc,
|
|
sizeof(NvSciBufObjIpcExportDescriptor));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Unable to send buffer %d (%x)\n", i, sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Import the buffer into CUDA
|
|
if (!setupCudaBuffer(&cudaInfo, buf)) {
|
|
goto done;
|
|
}
|
|
|
|
{
|
|
NvSciBufAttrList reconciledList;
|
|
sciErr = NvSciBufObjGetAttrList(buf->obj, &reconciledList);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Can't get the reconciled list from NvSciBufObj %d (%x)\n", i, sciErr);
|
|
goto done;
|
|
}
|
|
|
|
sciErr = NvSciBufAttrListValidateReconciledAgainstAttrs(
|
|
reconciledList, bufKeyValue, 6);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Validation of combinedBufAttrs failed (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
sciErr = NvSciBufObjValidate(buf->obj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Validation of buffer %d failed (%x)\n", i, sciErr);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Producer buffers established and transmitted\n");
|
|
|
|
// Validate handles before starting the runtime phase
|
|
{
|
|
NvSciSyncAttrList producerWaitList;
|
|
|
|
sciErr = NvSciSyncAttrListValidateReconciledAgainstAttrs(
|
|
prodToConsAttrs,
|
|
NULL,
|
|
0,
|
|
NvSciSyncAccessPerm_SignalOnly);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(
|
|
stderr,
|
|
"Validation of prodToCons list failed: %x\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
sciErr = NvSciSyncObjGetAttrList(producerWaitObj,
|
|
&producerWaitList);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Can't get the reconciled list from producer wait object (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
sciErr = NvSciSyncAttrListValidateReconciledAgainstAttrs(
|
|
producerWaitList,
|
|
NULL,
|
|
0,
|
|
NvSciSyncAccessPerm_WaitOnly);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(
|
|
stderr,
|
|
"Validation of imported reconciled producer wait list failed: %x\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
sciErr = NvSciSyncObjValidate(producerWaitObj);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(
|
|
stderr,
|
|
"Validation of imported producer wait object failed: %x\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// Send all frames
|
|
uint32_t currFrame = 0;
|
|
uint32_t currBuffer = 0;
|
|
Packet packet;
|
|
while (currFrame < totalFrames) {
|
|
fprintf(stderr, "Producer starting frame %d in buffer %d\n",
|
|
currFrame, currBuffer);
|
|
Buffer* buf = &buffers[currBuffer];
|
|
|
|
// Wait for buffer to be available
|
|
// Note: On first frame for each buffer, the producer already owns
|
|
// it, so this is skipped. On subsequent frames it must wait
|
|
// for the buffer's return.
|
|
while (buf->owner != 0U) {
|
|
|
|
// Wait for next returned buffer
|
|
sciErr = ipcRecvFill(&ipcWrapper, &packet, sizeof(packet));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Failure to recv buffer from consumer (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Import transmitted fence description to a fence
|
|
sciErr = NvSciSyncIpcImportFence(producerWaitObj,
|
|
&packet.fenceDesc,
|
|
&buffers[packet.bufferId].fence);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Failure to import fence from consumer (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Extract checksum from packet
|
|
buffers[packet.bufferId].crc = packet.crc;
|
|
|
|
// Mark producer as owner of this buffer
|
|
buffers[packet.bufferId].owner = 0U;
|
|
}
|
|
|
|
// Wait for fence returned by consumer before rendering
|
|
if (!waitCudaFence(&cudaInfo, buf)) {
|
|
goto done;
|
|
}
|
|
|
|
// CUDA rendering to buffer
|
|
(void)memset(cudaInfo.bufCopy, (currFrame & 0xFF), cudaInfo.bufSize);
|
|
|
|
cudaErr = cudaMemcpy2DAsync(buf->ptr,
|
|
cudaInfo.bufSize,
|
|
cudaInfo.bufCopy,
|
|
cudaInfo.bufSize,
|
|
cudaInfo.bufSize,
|
|
1,
|
|
cudaMemcpyHostToDevice,
|
|
cudaInfo.stream);
|
|
if (cudaSuccess != cudaErr) {
|
|
fprintf(stderr, "Unable to initiate CUDA copy (%d)\n", cudaErr);
|
|
goto done;
|
|
}
|
|
|
|
// Generate new fence for the sync object
|
|
if (!signalCudaFence(&cudaInfo, buf)) {
|
|
goto done;
|
|
}
|
|
|
|
// Wait for operation to finish and compute checksum
|
|
// IMPORTANT NOTE:
|
|
// A normal stream application would not perform these steps.
|
|
// A checksum is not required for streaming, and waiting for
|
|
// operations to finish (which we only need because the
|
|
// checksum is calculated by the CPU) introduces bubbles
|
|
// in the hardware pipeline. A real application can rely on
|
|
// the generated NvSciSync fences for synchronization.
|
|
// These steps are only taken in this sample application
|
|
// because the consumer has no output visible to the user,
|
|
// so the checksum allows us to verify that the application
|
|
// is behaving properly.
|
|
cudaDeviceSynchronize();
|
|
buf->crc = GenerateCRC(cudaInfo.bufCopy,
|
|
1,
|
|
cudaInfo.bufSize,
|
|
cudaInfo.bufSize);
|
|
|
|
fprintf(stderr, "Producer wrote frame %d in buffer %d\n",
|
|
currFrame, currBuffer);
|
|
|
|
// Mark buffer as owned by consumer now
|
|
buf->owner = 1U;
|
|
|
|
// Export buffer index, checksum, and fence for transmission over IPC
|
|
packet.bufferId = currBuffer;
|
|
packet.crc = buf->crc;
|
|
sciErr = NvSciSyncIpcExportFence(&buf->fence,
|
|
ipcWrapper.endpoint,
|
|
&packet.fenceDesc);
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr, "Unable to export producer fence (%x)\n", sciErr);
|
|
goto done;
|
|
}
|
|
|
|
// Send buffer index and fence to consumer
|
|
sciErr = ipcSend(&ipcWrapper, &packet, sizeof(packet));
|
|
if (NvSciError_Success != sciErr) {
|
|
fprintf(stderr,
|
|
"Failure to send buffer to consumer (%x)\n",
|
|
sciErr);
|
|
goto done;
|
|
}
|
|
|
|
fprintf(stderr, "Producer finished frame %d in buffer %d\n",
|
|
currFrame, currBuffer);
|
|
|
|
// Advance buffer and frame
|
|
currBuffer = (currBuffer + 1U) % totalBuffers;
|
|
currFrame++;
|
|
}
|
|
|
|
|
|
// Success
|
|
*(int*)arg = 0;
|
|
done:
|
|
// Free CUDA resources
|
|
deinitCudaBuffer(buffers, totalBuffers);
|
|
deinitCuda(&cudaInfo);
|
|
|
|
// Free NvSci objects
|
|
if (NULL != producerSignalAttrs)
|
|
NvSciSyncAttrListFree(producerSignalAttrs);
|
|
if (NULL != consumerWaitAttrs)
|
|
NvSciSyncAttrListFree(consumerWaitAttrs);
|
|
if (NULL != sendWaitListDesc)
|
|
NvSciSyncAttrListFreeDesc(sendWaitListDesc);
|
|
if (NULL != producerWaitAttrs)
|
|
NvSciSyncAttrListFree(producerWaitAttrs);
|
|
if (NULL != prodToConsAttrs)
|
|
NvSciSyncAttrListFree(prodToConsAttrs);
|
|
if (NULL != syncConflictAttrs)
|
|
NvSciSyncAttrListFree(syncConflictAttrs);
|
|
if (NULL != producerSignalObj)
|
|
NvSciSyncObjFree(producerSignalObj);
|
|
if (NULL != sendObjAndListDesc)
|
|
NvSciSyncAttrListAndObjFreeDesc(sendObjAndListDesc);
|
|
if (NULL != producerWaitObj)
|
|
NvSciSyncObjFree(producerWaitObj);
|
|
if (NULL != producerWriteAttrs)
|
|
NvSciBufAttrListFree(producerWriteAttrs);
|
|
if (NULL != consumerReadAttrs)
|
|
NvSciBufAttrListFree(consumerReadAttrs);
|
|
if (NULL != combinedBufAttrs)
|
|
NvSciBufAttrListFree(combinedBufAttrs);
|
|
if (NULL != sendBufListDesc)
|
|
NvSciBufAttrListFreeDesc(sendBufListDesc);
|
|
|
|
// Free malloc'd resources
|
|
if (NULL != recvWaitListDesc)
|
|
free(recvWaitListDesc);
|
|
if (NULL != recvObjAndListDesc)
|
|
free(recvObjAndListDesc);
|
|
if (NULL != consumerReadAttrsDesc)
|
|
free(consumerReadAttrsDesc);
|
|
|
|
fprintf(stderr, "Producer exiting\n");
|
|
return NULL;
|
|
}
|