@@ -13,6 +13,7 @@ PyObject *pocky_bufpair_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
13
13
if ((self = (pocky_bufpair_object * ) type -> tp_alloc (type , 0 )))
14
14
{
15
15
self -> host = NULL ;
16
+ self -> dirty = NULL ;
16
17
self -> context = NULL ;
17
18
self -> device = NULL ;
18
19
self -> host_size = 0 ;
@@ -52,13 +53,22 @@ int pocky_bufpair_init(pocky_bufpair_object *self,
52
53
self -> host = host ;
53
54
Py_XDECREF (tmp );
54
55
56
+ self -> dirty = Py_NewRef (Py_True );
55
57
self -> host_size = PyArray_SIZE ((PyArrayObject * ) self -> host );
56
58
self -> device_size = self -> host_size ;
57
59
58
60
if (self -> device != NULL ) clReleaseMemObject (self -> device );
59
- self -> device = clCreateBuffer (context -> ctx , CL_MEM_READ_WRITE ,
60
- self -> device_size * sizeof (cl_float ), NULL , & err );
61
- if (err != CL_SUCCESS ) return -1 ;
61
+
62
+ if (self -> device_size > 0 )
63
+ {
64
+ self -> device = clCreateBuffer (context -> ctx , CL_MEM_READ_WRITE ,
65
+ self -> device_size * sizeof (cl_float ), NULL , & err );
66
+ if (err != CL_SUCCESS ) return -1 ;
67
+ }
68
+ else
69
+ {
70
+ self -> device = NULL ;
71
+ }
62
72
63
73
return 0 ;
64
74
}
@@ -67,6 +77,7 @@ void pocky_bufpair_dealloc(pocky_bufpair_object *self)
67
77
{
68
78
Py_XDECREF (self -> context );
69
79
Py_XDECREF (self -> host );
80
+ Py_XDECREF (self -> dirty );
70
81
Py_TYPE (self )-> tp_free ((PyObject * ) self );
71
82
}
72
83
@@ -82,6 +93,118 @@ PyObject *pocky_bufpair_array(pocky_bufpair_object *self,
82
93
return Py_NewRef (self -> host );
83
94
}
84
95
96
+ PyObject * pocky_bufpair_copy_to_device (pocky_bufpair_object * self , PyObject * args )
97
+ {
98
+ cl_int err ;
99
+ cl_uint idx ;
100
+ char buf [BUFSIZ ];
101
+ PyObject * device = NULL ;
102
+ cl_device_id dev = NULL ;
103
+
104
+ if (!PyArg_ParseTuple (args , "|O!" , pocky_device_type , & device )) return NULL ;
105
+
106
+ if (device )
107
+ {
108
+ PyObject * cap ;
109
+
110
+ cap = PyStructSequence_GetItem (device , 0 );
111
+ if (!PyCapsule_CheckExact (cap ))
112
+ {
113
+ PyErr_SetString (PyExc_TypeError , pocky_ocl_msg_not_a_capsule );
114
+ return NULL ;
115
+ }
116
+
117
+ dev = PyCapsule_GetPointer (cap , "DeviceID" );
118
+ }
119
+
120
+ for (idx = 0 ; idx < self -> context -> num_queues ; ++ idx )
121
+ {
122
+ cl_device_id qdev = NULL ;
123
+ cl_command_queue queue = self -> context -> queues [idx ];
124
+
125
+ if (device )
126
+ {
127
+ err = clGetCommandQueueInfo (queue ,
128
+ CL_QUEUE_DEVICE , sizeof (cl_device_id ), & qdev , NULL );
129
+ if (err != CL_SUCCESS )
130
+ {
131
+ snprintf (buf , BUFSIZ , pocky_ocl_fmt_internal ,
132
+ pocky_opencl_error_to_string (err ), err );
133
+ PyErr_SetString (pocky_ocl_error , buf );
134
+ return NULL ;
135
+ }
136
+ }
137
+
138
+ if (qdev == dev )
139
+ {
140
+ err = clEnqueueWriteBuffer (queue , self -> device ,
141
+ CL_TRUE , 0 , self -> host_size * sizeof (cl_float ),
142
+ PyArray_DATA ((PyArrayObject * ) self -> host ), 0 , NULL , NULL );
143
+ if (err != CL_SUCCESS )
144
+ {
145
+ snprintf (buf , BUFSIZ , pocky_ocl_fmt_internal ,
146
+ pocky_opencl_error_to_string (err ), err );
147
+ PyErr_SetString (pocky_ocl_error , buf );
148
+ return NULL ;
149
+ }
150
+ }
151
+ }
152
+
153
+ return Py_NewRef (Py_None );
154
+ }
155
+
156
+ PyObject * pocky_bufpair_copy_from_device (pocky_bufpair_object * self , PyObject * args )
157
+ {
158
+ cl_int err ;
159
+ cl_uint idx ;
160
+ char buf [BUFSIZ ];
161
+ PyObject * device , * cap ;
162
+ cl_device_id dev = NULL ;
163
+
164
+ if (!PyArg_ParseTuple (args , "O!" , pocky_device_type , & device )) return NULL ;
165
+
166
+ cap = PyStructSequence_GetItem (device , 0 );
167
+ if (!PyCapsule_CheckExact (cap ))
168
+ {
169
+ PyErr_SetString (PyExc_TypeError , pocky_ocl_msg_not_a_capsule );
170
+ return NULL ;
171
+ }
172
+
173
+ dev = PyCapsule_GetPointer (cap , "DeviceID" );
174
+
175
+ for (idx = 0 ; idx < self -> context -> num_queues ; ++ idx )
176
+ {
177
+ cl_device_id qdev = NULL ;
178
+ cl_command_queue queue = self -> context -> queues [idx ];
179
+
180
+ err = clGetCommandQueueInfo (queue ,
181
+ CL_QUEUE_DEVICE , sizeof (cl_device_id ), & qdev , NULL );
182
+ if (err != CL_SUCCESS )
183
+ {
184
+ snprintf (buf , BUFSIZ , pocky_ocl_fmt_internal ,
185
+ pocky_opencl_error_to_string (err ), err );
186
+ PyErr_SetString (pocky_ocl_error , buf );
187
+ return NULL ;
188
+ }
189
+
190
+ if (qdev == dev )
191
+ {
192
+ err = clEnqueueReadBuffer (queue , self -> device ,
193
+ CL_TRUE , 0 , self -> host_size * sizeof (cl_float ),
194
+ PyArray_DATA ((PyArrayObject * ) self -> host ), 0 , NULL , NULL );
195
+ if (err != CL_SUCCESS )
196
+ {
197
+ snprintf (buf , BUFSIZ , pocky_ocl_fmt_internal ,
198
+ pocky_opencl_error_to_string (err ), err );
199
+ PyErr_SetString (pocky_ocl_error , buf );
200
+ return NULL ;
201
+ }
202
+ }
203
+ }
204
+
205
+ return Py_NewRef (Py_None );
206
+ }
207
+
85
208
PyObject * pocky_bufpair_get_host (pocky_bufpair_object * self , void * closure )
86
209
{
87
210
return Py_NewRef (self -> host );
@@ -122,17 +245,50 @@ int pocky_bufpair_set_host(pocky_bufpair_object *self,
122
245
return 0 ;
123
246
}
124
247
248
+ PyObject * pocky_bufpair_get_dirty (pocky_bufpair_object * self , void * closure )
249
+ {
250
+ return Py_NewRef (self -> dirty );
251
+ }
252
+
253
+ int pocky_bufpair_set_dirty (pocky_bufpair_object * self ,
254
+ PyObject * value , void * closure )
255
+ {
256
+ if (value == NULL )
257
+ {
258
+ PyErr_SetString (PyExc_TypeError , "Cannot delete dirty marker" );
259
+ return -1 ;
260
+ }
261
+
262
+ if (!PyBool_Check (value ))
263
+ {
264
+ PyErr_SetString (PyExc_ValueError , "Dirty marker must be a boolean" );
265
+ return -1 ;
266
+ }
267
+
268
+ Py_SETREF (self -> dirty , Py_NewRef (value ));
269
+ return 0 ;
270
+ }
271
+
125
272
PyGetSetDef pocky_bufpair_getsetters [] = {
126
273
{ "host" , (getter ) pocky_bufpair_get_host , (setter ) pocky_bufpair_set_host ,
127
274
"Exposes the underlying NumPy host array. The size of the array cannot "
128
275
"be increased after the BufferPair is created, but the array can be "
129
276
"replaced by one of the same dtype and equal or smaller size." , NULL },
277
+ { "dirty" , (getter ) pocky_bufpair_get_dirty , (setter ) pocky_bufpair_set_dirty ,
278
+ "Indicates that the host array needs to be copied to the device (True) "
279
+ "or that it is unchanged since the last copy (False). This can be used "
280
+ "by external modules to avoid redundant copies, but it is not updated "
281
+ "dynamically by pocky." },
130
282
{ NULL } /* sentinel */
131
283
};
132
284
133
285
PyMethodDef pocky_bufpair_methods [] = {
134
286
{ "__array__" , (PyCFunction ) pocky_bufpair_array , METH_NOARGS ,
135
287
"Return the host NumPy array" },
288
+ { "copy_to_device" , (PyCFunction ) pocky_bufpair_copy_to_device , METH_VARARGS ,
289
+ "Copy the host data to the specified device" },
290
+ { "copy_from_device" , (PyCFunction ) pocky_bufpair_copy_from_device , METH_VARARGS ,
291
+ "Copy the specified device data to the host" },
136
292
{ NULL , NULL , 0 , NULL } /* sentinel */
137
293
};
138
294
0 commit comments