/// <summary> /// Reads the specified memory object associated with this command queue. /// </summary> /// <param name="memoryObject">The memory object that is to be read.</param> /// <param name="outputLength">The number of array elements that are to be filled.</param> /// <typeparam name="T">The type of the array that is to be returned.</typeparam> /// <returns>Returns the value of the memory object.</param> public unsafe void EnqueueReadBuffer <T>(MemoryObject memoryObject, int outputLength, ref T[] output) { switch (output) { case uint[] uintArray: unsafe { fixed(uint *uintPtr = uintArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(uint) * outputLength)), (IntPtr)((void *)uintPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } case int[] intArray: unsafe { fixed(int *intPtr = intArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(int) * outputLength)), (IntPtr)((void *)intPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } case byte[] byteArray: unsafe { fixed(byte *bytePtr = byteArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(outputLength)), (IntPtr)((void *)bytePtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } case sbyte[] sbyteArray: unsafe { fixed(sbyte *sbytePtr = sbyteArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(outputLength)), (IntPtr)((void *)sbytePtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } case ulong[] ulongArray: unsafe { fixed(ulong *ulongPtr = ulongArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(ulong) * outputLength)), (IntPtr)((void *)ulongPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } case long[] longArray: unsafe { fixed(long *longPtr = longArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(long) * outputLength)), (IntPtr)((void *)longPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } break; } default: throw new NotSupportedException("Non-blittable types are not supported."); } }
/// <summary> /// Reads the specified memory object associated with this command queue asynchronously. /// </summary> /// <param name="memoryObject">The memory object that is to be read.</param> /// <param name="outputSize">The number of array elements that are to be returned.</param> /// <typeparam name="T">The type of the array that is to be returned.</typeparam> /// <returns>Returns the value of the memory object.</param> public Task <T[]> EnqueueReadBufferAsync <T>(MemoryObject memoryObject, int outputSize) where T : struct { // Creates a new task completion source, which is used to signal when the command has completed TaskCompletionSource <T[]> taskCompletionSource = new TaskCompletionSource <T[]>(); // Allocates enough memory for the result value IntPtr resultValuePointer = IntPtr.Zero; int size = Marshal.SizeOf <T>() * outputSize; resultValuePointer = Marshal.AllocHGlobal(size); // Reads the memory object, by enqueuing the read operation to the command queue Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)size), resultValuePointer, 0, null, out IntPtr waitEventPointer); // Checks if the read operation was queued successfuly, if not, an exception is thrown if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } // Subscribes to the completed event of the wait event that was returned, when the command finishes, the task completion source is resolved AwaitableEvent awaitableEvent = new AwaitableEvent(waitEventPointer); awaitableEvent.OnCompleted += (sender, e) => { try { // Checks if the command was executed successfully, if not, then an exception is thrown if (awaitableEvent.CommandExecutionStatus == CommandExecutionStatus.Error) { taskCompletionSource.TrySetException(new OpenClException( $"The command completed with the error code {awaitableEvent.CommandExecutionStatusCode}.")); return; } // Goes through the result and converts the content of the result to an array T[] resultValue = new T[outputSize]; for (int i = 0; i < outputSize; i++) { resultValue[i] = Marshal.PtrToStructure <T>(IntPtr.Add(resultValuePointer, i * Marshal.SizeOf <T>())); } // Sets the result taskCompletionSource.TrySetResult(resultValue); } catch (Exception exception) { taskCompletionSource.TrySetException(exception); } finally { // Finally the allocated memory has to be freed and the allocated resources are disposed of if (resultValuePointer != IntPtr.Zero) { Marshal.FreeHGlobal(resultValuePointer); } awaitableEvent.Dispose(); } }; // Returns the task completion source, which resolves when the command has finished return(taskCompletionSource.Task); }
/// <summary> /// Reads the specified memory object associated with this command queue. /// </summary> /// <param name="memoryObject">The memory object that is to be read.</param> /// <param name="outputLength">The number of array elements that are to be returned.</param> /// <typeparam name="T">The type of the array that is to be returned.</typeparam> /// <returns>Returns the value of the memory object.</param> public T[] EnqueueReadBuffer <T>(MemoryObject memoryObject, int outputLength) where T : struct { T[] resultValue = new T[outputLength]; #if UNSAFE switch (resultValue) { case int[] intArray: unsafe { fixed(int *intPtr = intArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(int) * outputLength)), (IntPtr)((void *)intPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } return(resultValue); } case uint[] uintArray: unsafe { fixed(uint *uintPtr = uintArray) { Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)(sizeof(uint) * outputLength)), (IntPtr)((void *)uintPtr), 0, null, out IntPtr zero); if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } } return(resultValue); } default: // Tries to read the memory object IntPtr resultValuePointer = IntPtr.Zero; try { // Allocates enough memory for the result value int size = Marshal.SizeOf <T>() * outputLength; resultValuePointer = Marshal.AllocHGlobal(size); // Reads the memory object, by enqueuing the read operation to the command queue IntPtr waitEventPointer; Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)size), resultValuePointer, 0, null, out waitEventPointer); // Checks if the read operation was queued successfuly, if not, an exception is thrown if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } // Goes through the result and converts the content of the result to an array for (int i = 0; i < outputLength; i++) { resultValue[i] = Marshal.PtrToStructure <T>(IntPtr.Add(resultValuePointer, i * Marshal.SizeOf <T>())); } // Returns the content of the memory object return(resultValue); } finally { // Finally the allocated memory has to be freed if (resultValuePointer != IntPtr.Zero) { Marshal.FreeHGlobal(resultValuePointer); } } } #else // Tries to read the memory object IntPtr resultValuePointer = IntPtr.Zero; try { // Allocates enough memory for the result value int size = Marshal.SizeOf <T>() * outputLength; resultValuePointer = Marshal.AllocHGlobal(size); // Reads the memory object, by enqueuing the read operation to the command queue IntPtr waitEventPointer; Result result = EnqueuedCommandsNativeApi.EnqueueReadBuffer(this.Handle, memoryObject.Handle, 1, UIntPtr.Zero, new UIntPtr((uint)size), resultValuePointer, 0, null, out waitEventPointer); // Checks if the read operation was queued successfuly, if not, an exception is thrown if (result != Result.Success) { throw new OpenClException("The memory object could not be read.", result); } // Goes through the result and converts the content of the result to an array for (int i = 0; i < outputLength; i++) { resultValue[i] = Marshal.PtrToStructure <T>(IntPtr.Add(resultValuePointer, i * Marshal.SizeOf <T>())); } // Returns the content of the memory object return(resultValue); } finally { // Finally the allocated memory has to be freed if (resultValuePointer != IntPtr.Zero) { Marshal.FreeHGlobal(resultValuePointer); } } #endif }