I have a C# function that calls a C++ function to fill the array with pixel data from a camera. This is better than allocating memory on the C++ side and marshaling it on C# side each time the function is called.
I thought about running into a scenario where a camera that outputs 720p can receive a command to output 1080p image. When this happens the array size allocated from C# may not be enough to hold the pixel information. That current function call will fail. I do not want to throw an exception and do not want it to fail. It must continue and should not discard that frame.
My current solution is to check if the size of the pixels to write to the array is <
the size of the array allocated from C# before writing to that array from C++ side.
If the size of the pixels to write is bigger than the array, allocate new memory then return it to C#. After that resize the size of the array from C# then use Marshal.Copy
to copy the data returned from C++ to that newly resized array in C#. Finally call a function from C++ side to free the memory allocated there.
Bascially, when this problem happens, I will allocate memory on both sides (C++ and C#).
How can this be improved?
Note that I had to use unsafe
and fixed
keywords to pin the array for maximum performance after days of testing this with other methods. Anything faster than this is also acceptable.
C++:
int* test6FillArrayWithAutoResize(int* data, int count, int* outValue) {
//For testing Purposes. Used to determine how much size to write to the data variable
const int requiredMemory = 20;
//Create new and Resize if memory is not enough
if (requiredMemory > count) {
int* newVar = new int[requiredMemory];
//Do something to the variable then return it
for (int i = 0; i < requiredMemory; i++)
{
newVar[i] = i;
}
//Tell caller memory size
*outValue = requiredMemory;
//Return the new created variable
return newVar;
}
//Memory is enough. Write Directly to it the array that is passed in
for (int i = 0; i < count; i++)
{
data[i] = i;
}
//Tell caller memory size
*outValue = requiredMemory;
//Return null since the memory fits. No need to return pointer
return nullptr;
}
//Free memory allocated in the test6FillArrayWithAutoResize function above
void freeMem(int* data) {
if (data != nullptr)
delete[] data;
}
C#:
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr test6FillArrayWithAutoResize(IntPtr data, int count, ref int outValue);
public unsafe int getTest6FillArrayWithAutoResize(ref int[] outArray, int count, ref int outValue)
{
IntPtr returnedPtr;
//Pin Memory
fixed (int* p = outArray)
{
IntPtr dataParam = (IntPtr)p;
returnedPtr = test6FillArrayWithAutoResize(dataParam, count, ref outValue);
}
//Resize outArray if outValue > count
if (outValue > count)
{
outArray = new int[outValue];
//Copy from result pointer to the C# variable
Marshal.Copy(returnedPtr, outArray, 0, 20);
//Free memory on the native sied
freeMem(returnedPtr);
}
return outValue;
}
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
private static extern void freeMem(IntPtr data);
Test 1:
const int arraySize = 44500;
int[] arrayToFill = new int[arraySize];
void Start()
{
int length = arrayToFill.Length;
int outVal6 = 0;
int returnedSize = 0;
returnedSize = getTest6FillArrayWithAutoResize(ref arrayToFill, length, ref outVal6);
}
Result: Array is not resized because the required size is 20 but array size is 44500.
Test 2:
const int arraySize = 19;
int[] arrayToFill = new int[arraySize];
void Start()
{
int length = arrayToFill.Length;
int outVal6 = 0;
int returnedSize = 0;
returnedSize = getTest6FillArrayWithAutoResize(ref arrayToFill, length, ref outVal6);
}
Result: Array is resized because the required size is 20 but array size is 19.
Note:
The required size is the requiredMemory
variable defined in the C++ code. It is only there to emulate the behavior of the camera and for testing purposes. Also, forget about me using for loop to iterate through the array. This is only for testing purposes too. I plan to use std::copy
for that so pretend that std::copy
is used there.
The thing I want to improve is how memory is allocated twice on both ends when size is not enough. Any other improvement is welcome.