Forge
ComputeCopy.h
Go to the documentation of this file.
1 /*******************************************************
2  * Copyright (c) 2015-2019, ArrayFire
3  * All rights reserved.
4  *
5  * This file is distributed under 3-clause BSD license.
6  * The complete license agreement can be obtained at:
7  * http://arrayfire.com/licenses/BSD-3-Clause
8  ********************************************************/
9 
10 #ifndef __COMPUTE_DATA_COPY_H__
11 #define __COMPUTE_DATA_COPY_H__
12 
13 #include <stdlib.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 
20 #if defined(USE_FORGE_CPU_COPY_HELPERS)
21 
22 // No special headers for cpu backend
23 
24 #elif defined(USE_FORGE_CUDA_COPY_HELPERS)
25 
26 #include <stdio.h>
27 
28 #ifndef GL_VERSION
29 // gl.h is required by cuda_gl_interop to be included before it
30 // And gl.h requires windows.h to be included before it
31 #if defined(OS_WIN)
32 #include <windows.h>
33 #endif // OS_WIN
34 #include <GL/gl.h>
35 #endif // GL_VERSION
36 
37 #include <cuda.h>
38 #include <cuda_runtime.h>
39 #include <cuda_gl_interop.h>
40 
41 #elif defined(USE_FORGE_OPENCL_COPY_HELPERS)
42 
43 // No special headers for opencl backend
44 
45 #else
46 
47  #error "Invalid Compute model, exiting."
48 
49 #endif
50 
51 
58 #if defined(USE_FORGE_CPU_COPY_HELPERS)
59 typedef unsigned GfxResourceHandle;
60 #elif defined(USE_FORGE_CUDA_COPY_HELPERS)
61 typedef cudaGraphicsResource* GfxResourceHandle;
62 #elif defined(USE_FORGE_OPENCL_COPY_HELPERS)
63 typedef cl_mem GfxResourceHandle;
64 #endif
65 
66 
73 typedef void* ComputeResourceHandle;
74 
75 typedef enum {
79 
80 typedef struct {
81  GfxResourceHandle mId;
83 } GfxHandle;
84 
85 
87 
88 #if defined(USE_FORGE_CPU_COPY_HELPERS)
89 
90 static
91 void createGLBuffer(GfxHandle** pOut, const unsigned pResourceId, const BufferType pTarget)
92 {
93  GfxHandle* temp = (GfxHandle*)malloc(sizeof(GfxHandle));
94 
95  temp->mId = pResourceId;
96  temp->mTarget = pTarget;
97 
98  *pOut = temp;
99 }
100 
101 static
102 void releaseGLBuffer(GfxHandle* pHandle)
103 {
104  free(pHandle);
105 }
106 
107 static
108 void copyToGLBuffer(GfxHandle* pGLDestination, ComputeResourceHandle pSource, const size_t pSize)
109 {
110  GfxHandle* temp = pGLDestination;
111 
112  if (temp->mTarget==FORGE_IMAGE_BUFFER) {
113  fg_update_pixel_buffer(temp->mId, pSize, pSource);
114  } else if (temp->mTarget==FORGE_VERTEX_BUFFER) {
115  fg_update_vertex_buffer(temp->mId, pSize, pSource);
116  }
117 }
118 #endif
119 
121 
122 #if defined(USE_FORGE_CUDA_COPY_HELPERS)
123 
124 static void handleCUDAError(cudaError_t err, const char *file, int line)
125 {
126  if (err != cudaSuccess) {
127  printf( "%s in %s at line %d\n", cudaGetErrorString(err), file, line);
128  exit(EXIT_FAILURE);
129  }
130 }
131 
132 #define FORGE_CUDA_CHECK(err) (handleCUDAError(err, __FILE__, __LINE__ ))
133 
134 static
135 void createGLBuffer(GfxHandle** pOut, const unsigned pResourceId, const BufferType pTarget)
136 {
137  GfxHandle* temp = (GfxHandle*)malloc(sizeof(GfxHandle));
138 
139  temp->mTarget = pTarget;
140 
141  cudaGraphicsResource *cudaImageResource;
142 
143  FORGE_CUDA_CHECK(cudaGraphicsGLRegisterBuffer(&cudaImageResource,
144  pResourceId,
145  cudaGraphicsMapFlagsWriteDiscard));
146 
147  temp->mId = cudaImageResource;
148 
149  *pOut = temp;
150 }
151 
152 static
153 void releaseGLBuffer(GfxHandle* pHandle)
154 {
155  FORGE_CUDA_CHECK(cudaGraphicsUnregisterResource(pHandle->mId));
156  free(pHandle);
157 }
158 
159 static
160 void copyToGLBuffer(GfxHandle* pGLDestination, ComputeResourceHandle pSource, const size_t pSize)
161 {
162  size_t numBytes;
163  void* pointer = NULL;
164 
165  cudaGraphicsResource *cudaResource = pGLDestination->mId;
166 
167  FORGE_CUDA_CHECK(cudaGraphicsMapResources(1, &cudaResource, 0));
168 
169  FORGE_CUDA_CHECK(cudaGraphicsResourceGetMappedPointer(&pointer, &numBytes, cudaResource));
170 
171  FORGE_CUDA_CHECK(cudaMemcpy(pointer, pSource, numBytes, cudaMemcpyDeviceToDevice));
172 
173  FORGE_CUDA_CHECK(cudaGraphicsUnmapResources(1, &cudaResource, 0));
174 }
175 #endif
176 
178 
179 #if defined(USE_FORGE_OPENCL_COPY_HELPERS)
180 
181 #if defined(__GNUC__)
182 #pragma GCC diagnostic push
183 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
184 #endif
185 
186 #define FORGE_OCL_CHECK(cl_status, message) \
187  if(cl_status != CL_SUCCESS) \
188  { \
189  printf("Error: %s \nError Code: %d\n", message, cl_status);\
190  printf("Location: %s:%i\n", __FILE__, __LINE__);\
191  exit(EXIT_FAILURE); \
192  }
193 
194 static
195 void createGLBuffer(GfxHandle** pOut, const unsigned pResourceId, const BufferType pTarget)
196 {
197  GfxHandle* temp = (GfxHandle*)malloc(sizeof(GfxHandle));
198 
199  temp->mTarget = pTarget;
200 
201  cl_int returnCode = CL_SUCCESS;
202 
203  temp->mId = clCreateFromGLBuffer(getContext(), CL_MEM_WRITE_ONLY, pResourceId, &returnCode);
204 
205  FORGE_OCL_CHECK(returnCode, "Failed in clCreateFromGLBuffer");
206 
207  *pOut = temp;
208 }
209 
210 static
211 void releaseGLBuffer(GfxHandle* pHandle)
212 {
213  FORGE_OCL_CHECK(clReleaseMemObject(pHandle->mId), "Failed in clReleaseMemObject");
214  free(pHandle);
215 }
216 
217 static
218 void copyToGLBuffer(GfxHandle* pGLDestination, ComputeResourceHandle pSource, const size_t pSize)
219 {
220  // The user is expected to implement a function
221  // `cl_command_queue getCommandQueue()`
222  cl_command_queue queue = getCommandQueue();
223 
224  cl_event waitEvent;
225 
226  cl_mem src = (cl_mem)pSource;
227  cl_mem dst = pGLDestination->mId;
228 
229  fg_finish();
230 
231  FORGE_OCL_CHECK(clEnqueueAcquireGLObjects(queue, 1, &dst, 0, NULL, &waitEvent),
232  "Failed in clEnqueueAcquireGLObjects");
233 
234  FORGE_OCL_CHECK(clWaitForEvents(1, &waitEvent),
235  "Failed in clWaitForEvents after clEnqueueAcquireGLObjects");
236 
237  FORGE_OCL_CHECK(clEnqueueCopyBuffer(queue, src, dst, 0, 0, pSize, 0, NULL, &waitEvent),
238  "Failed in clEnqueueCopyBuffer");
239 
240  FORGE_OCL_CHECK(clEnqueueReleaseGLObjects(queue, 1, &dst, 0, NULL, &waitEvent),
241  "Failed in clEnqueueReleaseGLObjects");
242 
243  FORGE_OCL_CHECK(clWaitForEvents(1, &waitEvent),
244  "Failed in clWaitForEvents after clEnqueueReleaseGLObjects");
245 }
246 
247 #if defined(__GNUC__)
248 #pragma GCC diagnostic pop
249 #endif
250 
251 #endif
252 
254 
255 #ifdef __cplusplus
256 }
257 #endif
258 
259 #endif
fg_finish
FGAPI fg_err fg_finish()
Sync all rendering operations till this point.
ComputeResourceHandle
void * ComputeResourceHandle
A backend-agnostic handle to a compute memory resource originating from an OpenGL resource.
Definition: ComputeCopy.h:73
GfxHandle::mTarget
BufferType mTarget
Definition: ComputeCopy.h:82
fg_update_pixel_buffer
FGAPI fg_err fg_update_pixel_buffer(const unsigned pBufferId, const size_t pBufferSize, const void *pBufferData)
Update backend specific pixel buffer from given host side memory.
FORGE_IMAGE_BUFFER
@ FORGE_IMAGE_BUFFER
OpenGL Pixel Buffer Object.
Definition: ComputeCopy.h:76
FORGE_VERTEX_BUFFER
@ FORGE_VERTEX_BUFFER
OpenGL Vertex Buffer Object.
Definition: ComputeCopy.h:77
fg_update_vertex_buffer
FGAPI fg_err fg_update_vertex_buffer(const unsigned pBufferId, const size_t pBufferSize, const void *pBufferData)
Update backend specific vertex buffer from given host side memory.
GfxHandle
Definition: ComputeCopy.h:80
BufferType
BufferType
Definition: ComputeCopy.h:75
GfxHandle::mId
GfxResourceHandle mId
Definition: ComputeCopy.h:81