ufo-anka-backproject-task.c 37 KB

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