ufo-anka-backproject-task.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /*
  2. * Copyright (C) 2011-2014 Karlsruhe Institute of Technology
  3. *
  4. * This file is part of Ufo.
  5. *
  6. * This library is free software: you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation, either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdio.h>
  20. #include <math.h>
  21. #include <string.h>
  22. #include <glib.h>
  23. #include <glib/gprintf.h>
  24. #ifdef __APPLE__
  25. #include <OpenCL/cl.h>
  26. #else
  27. #include <CL/cl.h>
  28. #endif
  29. #include "ufo-anka-backproject-task.h"
  30. /* Copy only neccessary projection region */
  31. /* TODO: make this a parameter? */
  32. #define COPY_PROJECTION_REGION 1
  33. #define EXTRACT_INT(region, index) g_value_get_int (g_value_array_get_nth ((region), (index)))
  34. #define EXTRACT_FLOAT(region, index) g_value_get_float (g_value_array_get_nth ((region), (index)))
  35. #define REGION_SIZE(region) ((EXTRACT_INT ((region), 2)) == 0) ? 0 : \
  36. ((EXTRACT_INT ((region), 1) - EXTRACT_INT ((region), 0) - 1) /\
  37. EXTRACT_INT ((region), 2) + 1)
  38. #define PAD_TO_DIVIDE(dividend, divisor) ((dividend) + (divisor) - (dividend) % (divisor))
  39. /**
  40. * SECTION:ufo-anka-backproject-task
  41. * @Short_description: Backproject projection by projection
  42. * @Title: anka_backproject
  43. *
  44. */
  45. struct _UfoAnkaBackprojectTaskPrivate {
  46. /* private */
  47. gboolean generated;
  48. guint count;
  49. /* sine and cosine table size based on BURST */
  50. gsize table_size;
  51. /* OpenCL */
  52. cl_context context;
  53. cl_kernel vector_kernel;
  54. cl_kernel scalar_kernel;
  55. cl_sampler sampler;
  56. /* Buffered images for invoking backprojection on BURST projections at once.
  57. * We potentially don't need to copy the last image and can use the one from
  58. * framework directly but it seems to have no performance effects. */
  59. cl_mem images[BURST];
  60. /* properties */
  61. GValueArray *x_region;
  62. GValueArray *y_region;
  63. GValueArray *z_region;
  64. GValueArray *center;
  65. GValueArray *projection_offset;
  66. float sines[BURST], cosines[BURST];
  67. guint num_projections;
  68. gfloat overall_angle;
  69. gfloat tomo_angle;
  70. gfloat lamino_angle;
  71. };
  72. static void ufo_task_interface_init (UfoTaskIface *iface);
  73. G_DEFINE_TYPE_WITH_CODE (UfoAnkaBackprojectTask, ufo_anka_backproject_task, UFO_TYPE_TASK_NODE,
  74. G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
  75. ufo_task_interface_init))
  76. #define UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ANKA_BACKPROJECT_TASK, UfoAnkaBackprojectTaskPrivate))
  77. enum {
  78. PROP_0,
  79. PROP_X_REGION,
  80. PROP_Y_REGION,
  81. PROP_Z_REGION,
  82. PROP_PROJECTION_OFFSET,
  83. PROP_CENTER,
  84. PROP_NUM_PROJECTIONS,
  85. PROP_OVERALL_ANGLE,
  86. PROP_TOMO_ANGLE,
  87. PROP_LAMINO_ANGLE,
  88. N_PROPERTIES
  89. };
  90. static GParamSpec *properties[N_PROPERTIES] = { NULL, };
  91. static inline void
  92. swap (gint *first, gint *second) {
  93. gint tmp;
  94. tmp = *first;
  95. *first = *second;
  96. *second = tmp;
  97. }
  98. /**
  99. * Determine the left and right column to read from a projection at a given
  100. * tomographic angle.
  101. */
  102. static void
  103. determine_x_extrema (gfloat extrema[2], GValueArray *x_extrema, GValueArray *y_extrema,
  104. gfloat tomo_angle, gfloat x_center)
  105. {
  106. gfloat sin_tomo, cos_tomo;
  107. gint x_min, x_max, y_min, y_max;
  108. sin_tomo = sin (tomo_angle);
  109. cos_tomo = cos (tomo_angle);
  110. x_min = EXTRACT_INT (x_extrema, 0);
  111. /* The interval is right-opened when OpenCL indices for both x and y are generated, */
  112. /* so the last index doesn't count */
  113. x_max = EXTRACT_INT (x_extrema, 1) - 1;
  114. y_min = EXTRACT_INT (y_extrema, 0);
  115. y_max = EXTRACT_INT (y_extrema, 1) - 1;
  116. if (sin_tomo < 0) {
  117. swap (&y_min, &y_max);
  118. }
  119. if (cos_tomo < 0) {
  120. swap (&x_min, &x_max);
  121. }
  122. extrema[0] = cos_tomo * x_min + sin_tomo * y_min + x_center;
  123. /* +1 because extrema[1] will be accessed by interpolation
  124. * but the region in copying is right-open */
  125. extrema[1] = cos_tomo * x_max + sin_tomo * y_max + x_center + 1;
  126. }
  127. /**
  128. * Determine the top and bottom row to read from a projection at given
  129. * tomographic and laminographic angles.
  130. */
  131. static void
  132. determine_y_extrema (gfloat extrema[2], GValueArray *x_extrema, GValueArray *y_extrema,
  133. GValueArray *z_extrema, gfloat tomo_angle, gfloat lamino_angle,
  134. gfloat y_center)
  135. {
  136. gfloat sin_tomo, cos_tomo, sin_lamino, cos_lamino;
  137. gint x_min, x_max, y_min, y_max;
  138. sin_tomo = sin (tomo_angle);
  139. cos_tomo = cos (tomo_angle);
  140. sin_lamino = sin (lamino_angle);
  141. cos_lamino = cos (lamino_angle);
  142. x_min = EXTRACT_INT (x_extrema, 0);
  143. x_max = EXTRACT_INT (x_extrema, 1) - 1;
  144. y_min = EXTRACT_INT (y_extrema, 0);
  145. y_max = EXTRACT_INT (y_extrema, 1) - 1;
  146. if (sin_tomo < 0) {
  147. swap (&x_min, &x_max);
  148. }
  149. if (cos_tomo > 0) {
  150. swap (&y_min, &y_max);
  151. }
  152. extrema[0] = sin_tomo * x_min - cos_tomo * y_min;
  153. extrema[1] = sin_tomo * x_max - cos_tomo * y_max;
  154. extrema[0] = extrema[0] * cos_lamino + EXTRACT_INT (z_extrema, 0) * sin_lamino + y_center;
  155. extrema[1] = extrema[1] * cos_lamino + EXTRACT_INT (z_extrema, 1) * sin_lamino + y_center + 1;
  156. }
  157. /**
  158. * clip:
  159. * @result: resulting clipped extrema
  160. * @extrema: (min, max)
  161. * @maximum: projection width or height
  162. *
  163. * Clip extrema to an allowed interval [0, projection width/height)
  164. */
  165. static void
  166. clip (gint result[2], gfloat extrema[2], gint maximum)
  167. {
  168. result[0] = (gint) floorf (extrema[0]);
  169. result[1] = (gint) ceilf (extrema[1]);
  170. if (result[0] < 0) {
  171. result[0] = 0;
  172. }
  173. if (result[0] > maximum) {
  174. result[0] = maximum;
  175. }
  176. if (result[1] < 0) {
  177. result[1] = 0;
  178. }
  179. if (result[1] > maximum) {
  180. result[1] = maximum;
  181. }
  182. if (result[0] == result[1]) {
  183. if (result[1] < maximum) {
  184. result[1]++;
  185. } else if (result[0] > 0) {
  186. result[0]--;
  187. } else {
  188. g_warning ("Cannot extend");
  189. }
  190. } else if (result[0] > result[1]) {
  191. g_warning ("Invalid extrema: minimum larger than maximum");
  192. }
  193. }
  194. /**
  195. * Determine the left and right column to read from a projection at a given
  196. * tomographic angle. The result is bound to [0, projection width)
  197. */
  198. static void
  199. determine_x_region (gint result[2], GValueArray *x_extrema, GValueArray *y_extrema, gfloat tomo_angle,
  200. gfloat x_center, gint width)
  201. {
  202. gfloat extrema[2];
  203. determine_x_extrema (extrema, x_extrema, y_extrema, tomo_angle, x_center);
  204. clip (result, extrema, width);
  205. }
  206. /**
  207. * Determine the top and bottom column to read from a projection at given
  208. * tomographic and laminographic angles. The result is bound to
  209. * [0, projection height).
  210. */
  211. static void
  212. determine_y_region (gint result[2], GValueArray *x_extrema, GValueArray *y_extrema, GValueArray *z_extrema,
  213. gfloat tomo_angle, gfloat lamino_angle, gfloat y_center, gint height)
  214. {
  215. gfloat extrema[2];
  216. determine_y_extrema (extrema, x_extrema, y_extrema, z_extrema, tomo_angle,
  217. lamino_angle, y_center);
  218. clip (result, extrema, height);
  219. }
  220. static void
  221. set_region (GValueArray *src, GValueArray **dst)
  222. {
  223. if (EXTRACT_INT (src, 0) > EXTRACT_INT (src, 1)) {
  224. g_log ("Ufo", G_LOG_LEVEL_CRITICAL,
  225. "Error <%s:%i>: Invalid region [\"from\", \"to\", \"step\"]: [%d, %d, %d], "\
  226. "\"from\" has to be less than or equal to \"to\"",
  227. __FILE__, __LINE__,
  228. EXTRACT_INT (src, 0), EXTRACT_INT (src, 1), EXTRACT_INT (src, 2));
  229. }
  230. else {
  231. g_value_array_free (*dst);
  232. *dst = g_value_array_copy (src);
  233. }
  234. }
  235. static void
  236. copy_to_image (UfoBuffer *input,
  237. cl_mem output_image,
  238. cl_command_queue cmd_queue,
  239. size_t origin[3],
  240. size_t region[3],
  241. gint in_width)
  242. {
  243. const UfoBufferLocation location = ufo_buffer_get_location (input);
  244. cl_mem input_data;
  245. gfloat *input_data_host;
  246. size_t src_offset;
  247. switch (location) {
  248. case UFO_BUFFER_LOCATION_HOST:
  249. input_data_host = ufo_buffer_get_host_array (input, NULL);
  250. src_offset = origin[1] * in_width + origin[0];
  251. UFO_RESOURCES_CHECK_CLERR (clEnqueueWriteImage (cmd_queue,
  252. output_image,
  253. CL_TRUE,
  254. origin,
  255. region,
  256. 0,
  257. 0,
  258. input_data_host + src_offset,
  259. 0,
  260. NULL,
  261. NULL));
  262. break;
  263. case UFO_BUFFER_LOCATION_DEVICE:
  264. input_data = ufo_buffer_get_device_array (input, cmd_queue);
  265. src_offset = (origin[1] * in_width + origin[0]) * sizeof (cl_float);
  266. UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyBufferToImage (cmd_queue,
  267. input_data,
  268. output_image,
  269. src_offset,
  270. origin,
  271. region,
  272. 0,
  273. NULL,
  274. NULL));
  275. break;
  276. case UFO_BUFFER_LOCATION_DEVICE_IMAGE:
  277. input_data = ufo_buffer_get_device_image (input, cmd_queue);
  278. UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyImage (cmd_queue,
  279. input_data,
  280. output_image,
  281. origin,
  282. origin,
  283. region,
  284. 0,
  285. NULL,
  286. NULL));
  287. break;
  288. default:
  289. g_warning ("Invalid input buffer location");
  290. break;
  291. }
  292. }
  293. UfoNode *
  294. ufo_anka_backproject_task_new (void)
  295. {
  296. return UFO_NODE (g_object_new (UFO_TYPE_ANKA_BACKPROJECT_TASK, NULL));
  297. }
  298. static void
  299. ufo_anka_backproject_task_setup (UfoTask *task,
  300. UfoResources *resources,
  301. GError **error)
  302. {
  303. UfoAnkaBackprojectTaskPrivate *priv;
  304. cl_int cl_error;
  305. gint i;
  306. gchar vector_kernel_name[30];
  307. if (!g_sprintf (vector_kernel_name, "backproject_burst_%d", BURST)) {
  308. g_warning ("Error making burst kernel name");
  309. }
  310. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  311. priv->context = ufo_resources_get_context (resources);
  312. priv->vector_kernel = ufo_resources_get_kernel (resources, "ankabackprojectburst.cl",
  313. vector_kernel_name, error);
  314. priv->scalar_kernel = ufo_resources_get_kernel (resources, "ankabackprojectburst.cl",
  315. "backproject_burst_1", error);
  316. priv->sampler = clCreateSampler (priv->context,
  317. (cl_bool) FALSE,
  318. CL_ADDRESS_CLAMP,
  319. CL_FILTER_LINEAR,
  320. &cl_error);
  321. UFO_RESOURCES_CHECK_CLERR (clRetainContext (priv->context));
  322. UFO_RESOURCES_CHECK_CLERR (cl_error);
  323. if (priv->vector_kernel) {
  324. UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->vector_kernel));
  325. }
  326. if (priv->scalar_kernel) {
  327. UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->scalar_kernel));
  328. }
  329. for (i = 0; i < BURST; i++) {
  330. priv->images[i] = NULL;
  331. }
  332. switch (BURST) {
  333. case 1: priv->table_size = sizeof (cl_float); break;
  334. case 2: priv->table_size = sizeof (cl_float2); break;
  335. case 4: priv->table_size = sizeof (cl_float4); break;
  336. case 8: priv->table_size = sizeof (cl_float8); break;
  337. case 16: priv->table_size = sizeof (cl_float16); break;
  338. default: g_warning ("Unsupported vector size"); break;
  339. }
  340. }
  341. static void
  342. ufo_anka_backproject_task_get_requisition (UfoTask *task,
  343. UfoBuffer **inputs,
  344. UfoRequisition *requisition)
  345. {
  346. UfoAnkaBackprojectTaskPrivate *priv;
  347. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  348. if (!priv->num_projections) {
  349. g_warning ("Number of projections has not been set");
  350. }
  351. requisition->n_dims = 3;
  352. requisition->dims[0] = REGION_SIZE (priv->x_region);
  353. requisition->dims[1] = REGION_SIZE (priv->y_region);
  354. requisition->dims[2] = REGION_SIZE (priv->z_region);
  355. }
  356. static guint
  357. ufo_anka_backproject_task_get_num_inputs (UfoTask *task)
  358. {
  359. return 1;
  360. }
  361. static guint
  362. ufo_anka_backproject_task_get_num_dimensions (UfoTask *task,
  363. guint input)
  364. {
  365. g_return_val_if_fail (input == 0, 0);
  366. return 3;
  367. }
  368. static gboolean
  369. ufo_anka_backproject_task_equal_real (UfoNode *n1,
  370. UfoNode *n2)
  371. {
  372. g_return_val_if_fail (UFO_IS_ANKA_BACKPROJECT_TASK (n1) && UFO_IS_ANKA_BACKPROJECT_TASK (n2), FALSE);
  373. return UFO_ANKA_BACKPROJECT_TASK (n1)->priv->vector_kernel == UFO_ANKA_BACKPROJECT_TASK (n2)->priv->vector_kernel;
  374. }
  375. static UfoTaskMode
  376. ufo_anka_backproject_task_get_mode (UfoTask *task)
  377. {
  378. return UFO_TASK_MODE_REDUCTOR | UFO_TASK_MODE_GPU;
  379. }
  380. static gboolean
  381. ufo_anka_backproject_task_process (UfoTask *task,
  382. UfoBuffer **inputs,
  383. UfoBuffer *output,
  384. UfoRequisition *requisition)
  385. {
  386. UfoAnkaBackprojectTaskPrivate *priv;
  387. UfoRequisition in_req;
  388. UfoGpuNode *node;
  389. UfoProfiler *profiler;
  390. gfloat tomo_angle, *sines, *cosines;
  391. gint i, index;
  392. gint cumulate;
  393. gsize table_size;
  394. gboolean scalar;
  395. /* regions stripped off the "to" value */
  396. gfloat x_region[2], y_region[2], z_region[2], center[2], sin_lamino, cos_lamino;
  397. gint x_copy_region[2], y_copy_region[2];
  398. cl_kernel kernel;
  399. cl_command_queue cmd_queue;
  400. cl_mem out_mem;
  401. cl_int cl_error;
  402. /* image creation and copying */
  403. cl_image_format image_fmt;
  404. size_t origin[3];
  405. size_t region[3];
  406. /* keep the warp size satisfied but make sure the local grid is localized
  407. * around a point in 3D for efficient caching */
  408. const gint real_size[4] = {requisition->dims[0], requisition->dims[1], requisition->dims[2], 0};
  409. const gsize local_work_size[] = {16, 8, 8};
  410. gsize global_work_size[3];
  411. global_work_size[0] = requisition->dims[0] % local_work_size[0] ?
  412. PAD_TO_DIVIDE (requisition->dims[0], local_work_size[0]) :
  413. requisition->dims[0];
  414. global_work_size[1] = requisition->dims[1] % local_work_size[1] ?
  415. PAD_TO_DIVIDE (requisition->dims[1], local_work_size[1]) :
  416. requisition->dims[1];
  417. global_work_size[2] = requisition->dims[2] % local_work_size[2] ?
  418. PAD_TO_DIVIDE (requisition->dims[2], local_work_size[2]) :
  419. requisition->dims[2];
  420. priv = UFO_ANKA_BACKPROJECT_TASK (task)->priv;
  421. node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
  422. cmd_queue = ufo_gpu_node_get_cmd_queue (node);
  423. out_mem = ufo_buffer_get_device_array (output, cmd_queue);
  424. ufo_buffer_get_requisition (inputs[0], &in_req);
  425. index = priv->count % BURST;
  426. tomo_angle = priv->tomo_angle > -G_MAXFLOAT ? priv->tomo_angle :
  427. priv->overall_angle * priv->count / priv->num_projections;
  428. priv->sines[index] = sin (tomo_angle);
  429. priv->cosines[index] = cos (tomo_angle);
  430. x_region[0] = (gfloat) EXTRACT_INT (priv->x_region, 0);
  431. x_region[1] = (gfloat) EXTRACT_INT (priv->x_region, 2);
  432. y_region[0] = (gfloat) EXTRACT_INT (priv->y_region, 0);
  433. y_region[1] = (gfloat) EXTRACT_INT (priv->y_region, 2);
  434. z_region[0] = (gfloat) EXTRACT_INT (priv->z_region, 0);
  435. z_region[1] = (gfloat) EXTRACT_INT (priv->z_region, 2);
  436. center[0] = EXTRACT_FLOAT (priv->center, 0) - EXTRACT_INT (priv->projection_offset, 0);
  437. center[1] = EXTRACT_FLOAT (priv->center, 1) - EXTRACT_INT (priv->projection_offset, 1);
  438. sin_lamino = sinf (priv->lamino_angle);
  439. cos_lamino = cosf (priv->lamino_angle);
  440. scalar = priv->count >= priv->num_projections / BURST * BURST ? 1 : 0;
  441. /* If COPY_PROJECTION_REGION is True we copy only the part necessary */
  442. /* for a given tomographic and laminographic angle */
  443. if (COPY_PROJECTION_REGION) {
  444. determine_x_region (x_copy_region, priv->x_region, priv->y_region, tomo_angle,
  445. EXTRACT_FLOAT (priv->center, 0), in_req.dims[0]);
  446. determine_y_region (y_copy_region, priv->x_region, priv->y_region, priv->z_region,
  447. tomo_angle, priv->lamino_angle, EXTRACT_FLOAT (priv->center, 1),
  448. in_req.dims[1]);
  449. origin[0] = x_copy_region[0];
  450. origin[1] = y_copy_region[0];
  451. origin[2] = 0;
  452. region[0] = x_copy_region[1] - x_copy_region[0];
  453. region[1] = y_copy_region[1] - y_copy_region[0];
  454. } else {
  455. origin[0] = origin[1] = origin[2] = 0;
  456. region[0] = in_req.dims[0];
  457. region[1] = in_req.dims[1];
  458. }
  459. region[2] = 1;
  460. if (priv->images[index] == NULL) {
  461. /* TODO: dangerous, don't rely on the ufo-buffer */
  462. image_fmt.image_channel_order = CL_R;
  463. image_fmt.image_channel_data_type = CL_FLOAT;
  464. /* TODO: what with the "other" API? */
  465. priv->images[index] = clCreateImage2D (priv->context,
  466. CL_MEM_READ_ONLY,
  467. &image_fmt,
  468. in_req.dims[0],
  469. in_req.dims[1],
  470. 0,
  471. NULL,
  472. &cl_error);
  473. UFO_RESOURCES_CHECK_CLERR (cl_error);
  474. }
  475. copy_to_image (inputs[0], priv->images[index], cmd_queue, origin, region, in_req.dims[0]);
  476. if (scalar) {
  477. kernel = priv->scalar_kernel;
  478. cumulate = priv->count;
  479. table_size = sizeof (cl_float);
  480. sines = &priv->sines[index];
  481. cosines = &priv->cosines[index];
  482. i = 1;
  483. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem), &priv->images[index]));
  484. } else {
  485. kernel = priv->vector_kernel;
  486. cumulate = priv->count + 1 == BURST ? 0 : 1;
  487. table_size = priv->table_size;
  488. sines = priv->sines;
  489. cosines = priv->cosines;
  490. i = BURST;
  491. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, index, sizeof (cl_mem), &priv->images[index]));
  492. }
  493. if (scalar || index == BURST - 1) {
  494. /* Execute the kernel after BURST images have arrived, i.e. we use more
  495. * projections at one invocation, so the number of read/writes to the
  496. * result is reduced by a factor of BURST. If there are not enough
  497. * projecttions left, execute the scalar kernel */
  498. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_mem), &out_mem));
  499. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_sampler), &priv->sampler));
  500. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_int3), real_size));
  501. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), center));
  502. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), x_region));
  503. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), y_region));
  504. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), z_region));
  505. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &sin_lamino));
  506. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &cos_lamino));
  507. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, table_size, sines));
  508. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, table_size, cosines));
  509. UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i, sizeof (cl_int), (cl_int *) &cumulate));
  510. profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (task));
  511. ufo_profiler_call (profiler, cmd_queue, kernel, 3, global_work_size, local_work_size);
  512. }
  513. priv->count++;
  514. return TRUE;
  515. }
  516. static gboolean
  517. ufo_anka_backproject_task_generate (UfoTask *task,
  518. UfoBuffer *output,
  519. UfoRequisition *requisition)
  520. {
  521. UfoAnkaBackprojectTaskPrivate *priv;
  522. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task);
  523. if (priv->generated) {
  524. return FALSE;
  525. }
  526. priv->generated = TRUE;
  527. return TRUE;
  528. }
  529. static void
  530. ufo_anka_backproject_task_finalize (GObject *object)
  531. {
  532. UfoAnkaBackprojectTaskPrivate *priv;
  533. gint i;
  534. priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  535. g_value_array_free (priv->x_region);
  536. g_value_array_free (priv->y_region);
  537. g_value_array_free (priv->z_region);
  538. g_value_array_free (priv->projection_offset);
  539. g_value_array_free (priv->center);
  540. if (priv->vector_kernel) {
  541. UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->vector_kernel));
  542. priv->vector_kernel = NULL;
  543. }
  544. if (priv->scalar_kernel) {
  545. UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->scalar_kernel));
  546. priv->scalar_kernel = NULL;
  547. }
  548. if (priv->context) {
  549. UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context));
  550. priv->context = NULL;
  551. }
  552. if (priv->sampler) {
  553. UFO_RESOURCES_CHECK_CLERR (clReleaseSampler (priv->sampler));
  554. priv->sampler = NULL;
  555. }
  556. for (i = 0; i < BURST; i++) {
  557. if (priv->images[i] != NULL) {
  558. UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->images[i]));
  559. priv->images[i] = NULL;
  560. }
  561. }
  562. G_OBJECT_CLASS (ufo_anka_backproject_task_parent_class)->finalize (object);
  563. }
  564. static void
  565. ufo_task_interface_init (UfoTaskIface *iface)
  566. {
  567. iface->setup = ufo_anka_backproject_task_setup;
  568. iface->get_requisition = ufo_anka_backproject_task_get_requisition;
  569. iface->get_num_inputs = ufo_anka_backproject_task_get_num_inputs;
  570. iface->get_num_dimensions = ufo_anka_backproject_task_get_num_dimensions;
  571. iface->get_mode = ufo_anka_backproject_task_get_mode;
  572. iface->process = ufo_anka_backproject_task_process;
  573. iface->generate = ufo_anka_backproject_task_generate;
  574. }
  575. static void
  576. ufo_anka_backproject_task_set_property (GObject *object,
  577. guint property_id,
  578. const GValue *value,
  579. GParamSpec *pspec)
  580. {
  581. UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  582. GValueArray *array;
  583. switch (property_id) {
  584. case PROP_X_REGION:
  585. array = (GValueArray *) g_value_get_boxed (value);
  586. set_region (array, &priv->x_region);
  587. break;
  588. case PROP_Y_REGION:
  589. array = (GValueArray *) g_value_get_boxed (value);
  590. set_region (array, &priv->y_region);
  591. break;
  592. case PROP_Z_REGION:
  593. array = (GValueArray *) g_value_get_boxed (value);
  594. set_region (array, &priv->z_region);
  595. break;
  596. case PROP_PROJECTION_OFFSET:
  597. array = (GValueArray *) g_value_get_boxed (value);
  598. g_value_array_free (priv->projection_offset);
  599. priv->projection_offset = g_value_array_copy (array);
  600. break;
  601. case PROP_CENTER:
  602. array = (GValueArray *) g_value_get_boxed (value);
  603. g_value_array_free (priv->center);
  604. priv->center = g_value_array_copy (array);
  605. break;
  606. case PROP_NUM_PROJECTIONS:
  607. priv->num_projections = g_value_get_uint (value);
  608. break;
  609. case PROP_OVERALL_ANGLE:
  610. priv->overall_angle = g_value_get_float (value);
  611. break;
  612. case PROP_TOMO_ANGLE:
  613. priv->tomo_angle = g_value_get_float (value);
  614. break;
  615. case PROP_LAMINO_ANGLE:
  616. priv->lamino_angle = g_value_get_float (value);
  617. break;
  618. default:
  619. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  620. break;
  621. }
  622. }
  623. static void
  624. ufo_anka_backproject_task_get_property (GObject *object,
  625. guint property_id,
  626. GValue *value,
  627. GParamSpec *pspec)
  628. {
  629. UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object);
  630. switch (property_id) {
  631. case PROP_X_REGION:
  632. g_value_set_boxed (value, priv->x_region);
  633. break;
  634. case PROP_Y_REGION:
  635. g_value_set_boxed (value, priv->y_region);
  636. break;
  637. case PROP_Z_REGION:
  638. g_value_set_boxed (value, priv->z_region);
  639. break;
  640. case PROP_PROJECTION_OFFSET:
  641. g_value_set_boxed (value, priv->projection_offset);
  642. break;
  643. case PROP_CENTER:
  644. g_value_set_boxed (value, priv->center);
  645. break;
  646. case PROP_NUM_PROJECTIONS:
  647. g_value_set_uint (value, priv->num_projections);
  648. break;
  649. case PROP_OVERALL_ANGLE:
  650. g_value_set_float (value, priv->overall_angle);
  651. break;
  652. case PROP_TOMO_ANGLE:
  653. g_value_set_float (value, priv->tomo_angle);
  654. break;
  655. case PROP_LAMINO_ANGLE:
  656. g_value_set_float (value, priv->lamino_angle);
  657. break;
  658. default:
  659. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  660. break;
  661. }
  662. }
  663. static void
  664. ufo_anka_backproject_task_class_init (UfoAnkaBackprojectTaskClass *klass)
  665. {
  666. GObjectClass *oclass;
  667. UfoNodeClass *node_class;
  668. oclass = G_OBJECT_CLASS (klass);
  669. node_class = UFO_NODE_CLASS (klass);
  670. oclass->finalize = ufo_anka_backproject_task_finalize;
  671. oclass->set_property = ufo_anka_backproject_task_set_property;
  672. oclass->get_property = ufo_anka_backproject_task_get_property;
  673. GParamSpec *region_vals = g_param_spec_int ("region_values",
  674. "Region values",
  675. "Elements in regions",
  676. G_MININT,
  677. G_MAXINT,
  678. (gint) 0,
  679. G_PARAM_READWRITE);
  680. GParamSpec *float_region_vals = g_param_spec_float ("float_region_values",
  681. "Float Region values",
  682. "Elements in float regions",
  683. -G_MAXFLOAT,
  684. G_MAXFLOAT,
  685. 0.0f,
  686. G_PARAM_READWRITE);
  687. properties[PROP_X_REGION] =
  688. g_param_spec_value_array ("x-region",
  689. "X region for reconstruction as (from, to, step)",
  690. "X region for reconstruction as (from, to, step)",
  691. region_vals,
  692. G_PARAM_READWRITE);
  693. properties[PROP_Y_REGION] =
  694. g_param_spec_value_array ("y-region",
  695. "Y region for reconstruction as (from, to, step)",
  696. "Y region for reconstruction as (from, to, step)",
  697. region_vals,
  698. G_PARAM_READWRITE);
  699. properties[PROP_Z_REGION] =
  700. g_param_spec_value_array ("z-region",
  701. "Z region for reconstruction as (from, to, step)",
  702. "Z region for reconstruction as (from, to, step)",
  703. region_vals,
  704. G_PARAM_READWRITE);
  705. properties[PROP_PROJECTION_OFFSET] =
  706. g_param_spec_value_array ("projection-offset",
  707. "Offset to projection data as (x, y)",
  708. "Offset to projection data as (x, y) for the case input data \
  709. is cropped to the necessary range of interest",
  710. region_vals,
  711. G_PARAM_READWRITE);
  712. properties[PROP_CENTER] =
  713. g_param_spec_value_array ("center",
  714. "Center of the volume with respect to projections (x, y)",
  715. "Center of the volume with respect to projections (x, y), (rotation axes)",
  716. float_region_vals,
  717. G_PARAM_READWRITE);
  718. properties[PROP_OVERALL_ANGLE] =
  719. g_param_spec_float ("overall-angle",
  720. "Angle covered by all projections",
  721. "Angle covered by all projections (can be negative for negative steps "
  722. "in case only num-projections is specified",
  723. -G_MAXFLOAT,
  724. G_MAXFLOAT,
  725. G_PI,
  726. G_PARAM_READWRITE);
  727. properties[PROP_NUM_PROJECTIONS] =
  728. g_param_spec_uint ("num-projections",
  729. "Number of projections",
  730. "Number of projections",
  731. 0,
  732. 16384,
  733. 0,
  734. G_PARAM_READWRITE);
  735. properties[PROP_TOMO_ANGLE] =
  736. g_param_spec_float ("tomo-angle",
  737. "Tomographic rotation angle in radians",
  738. "Tomographic rotation angle in radians (used for acquiring projections)",
  739. -G_MAXFLOAT,
  740. G_MAXFLOAT,
  741. 0.0f,
  742. G_PARAM_READWRITE);
  743. properties[PROP_LAMINO_ANGLE] =
  744. g_param_spec_float ("lamino-angle",
  745. "Absolute laminogrpahic angle in radians",
  746. "Absolute laminogrpahic angle in radians determining the sample tilt",
  747. 0.0f,
  748. (float) G_PI / 2,
  749. 0.0f,
  750. G_PARAM_READWRITE);
  751. for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
  752. g_object_class_install_property (oclass, i, properties[i]);
  753. node_class->equal = ufo_anka_backproject_task_equal_real;
  754. g_type_class_add_private (klass, sizeof(UfoAnkaBackprojectTaskPrivate));
  755. }
  756. static void
  757. ufo_anka_backproject_task_init(UfoAnkaBackprojectTask *self)
  758. {
  759. UfoAnkaBackprojectTaskPrivate *priv;
  760. self->priv = priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(self);
  761. guint i;
  762. GValue int_zero = G_VALUE_INIT;
  763. GValue float_zero = G_VALUE_INIT;
  764. g_value_init (&int_zero, G_TYPE_INT);
  765. g_value_init (&float_zero, G_TYPE_FLOAT);
  766. g_value_set_int (&int_zero, 0);
  767. g_value_set_float (&float_zero, 0.0f);
  768. self->priv->x_region = g_value_array_new (3);
  769. self->priv->y_region = g_value_array_new (3);
  770. self->priv->z_region = g_value_array_new (3);
  771. self->priv->projection_offset = g_value_array_new (2);
  772. self->priv->center = g_value_array_new (2);
  773. for (i = 0; i < 3; i++) {
  774. g_value_array_insert (self->priv->x_region, i, &int_zero);
  775. g_value_array_insert (self->priv->y_region, i, &int_zero);
  776. g_value_array_insert (self->priv->z_region, i, &int_zero);
  777. if (i < 2) {
  778. g_value_array_insert (self->priv->projection_offset, i, &int_zero);
  779. g_value_array_insert (self->priv->center, i, &float_zero);
  780. }
  781. }
  782. self->priv->num_projections = 0;
  783. self->priv->overall_angle = G_PI;
  784. self->priv->tomo_angle = -G_MAXFLOAT;
  785. self->priv->lamino_angle = 0.0f;
  786. self->priv->count = 0;
  787. self->priv->generated = FALSE;
  788. }