ufo-anka-backproject-task.c 33 KB

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