Source code for nabu.reconstruction.fbp_opencl
import pyopencl as cl
from ..utils import get_opencl_srcfile
from ..opencl.processing import OpenCLProcessing
from ..opencl.kernel import OpenCLKernel
from ..opencl.utils import allocate_texture, check_textures_availability, copy_to_texture
from .filtering_opencl import OpenCLSinoFilter
from .sinogram_opencl import OpenCLSinoMult
from .fbp_base import BackprojectorBase
[docs]
class OpenCLBackprojector(BackprojectorBase):
default_extra_options = {**BackprojectorBase.default_extra_options, "use_textures": True}
backend = "opencl"
kernel_filename = "backproj.cl"
backend_processing_class = OpenCLProcessing
SinoFilterClass = OpenCLSinoFilter
SinoMultClass = OpenCLSinoMult
[docs]
def reset_rot_center(self, rot_center):
"""
Define a new center of rotation for the current backprojector.
"""
bp = self.backprojector
bp.axis_pos = rot_center
bp.kern_proj_args[2] = rot_center
def _get_kernel_options(self):
super()._get_kernel_options()
self._kernel_options.update(
{
"file_name": get_opencl_srcfile(self.kernel_filename),
}
)
def _prepare_kernel_args(self):
super()._prepare_kernel_args()
block = self.kern_proj_kwargs.pop("block")
local_size = block
grid = self.kern_proj_kwargs.pop("grid")
global_size = (grid[0] * block[0], grid[1] * block[1])
# global_size = (updiv(self.n_x, 2), updiv(self.n_y, 2))
self.kern_proj_args.insert(0, self._processing.queue) # OpenCLProcessing.__call__ expects first arg to be queue
self.kern_proj_kwargs.update(
{
"global_size": global_size,
"local_size": local_size,
}
)
def _prepare_textures(self):
self._use_textures = self.extra_options.get("use_textures", True) and check_textures_availability(
self._processing.ctx
)
if self._use_textures:
d_sino_ref = self.d_sino_tex = allocate_texture(self._processing.ctx, self.sino_shape)
self._kernel_options["sourcemodule_options"].append("-DUSE_TEXTURES")
else:
d_sino_ref = self._d_sino.data
self.kern_proj_args.insert(2, d_sino_ref)
def _compile_kernels(self):
self._prepare_kernel_args()
self._prepare_textures() # has to be done before compilation for OpenCL (to pass -DUSE_TEXTURES)
self.kern_proj_args.append(cl.LocalMemory(self._kernel_options["shared_size"]))
self.gpu_projector = OpenCLKernel(
self._kernel_options["kernel_name"],
self._processing.ctx,
filename=self._kernel_options["file_name"],
options=self._kernel_options["sourcemodule_options"],
)
if self.halftomo and self.rot_center < self.dwidth:
self.sino_mult = OpenCLSinoMult(self.sino_shape, self.rot_center, ctx=self._processing.ctx)
def _transfer_to_texture(self, sino, do_checks=True):
if self._use_textures:
return copy_to_texture(self._processing.queue, self.d_sino_tex, sino)
else:
if id(self._d_sino) == id(sino):
return
return cl.enqueue_copy(self._processing.queue, self._d_sino.data, sino)
def _set_kernel_slice_arg(self, d_slice):
self.kern_proj_args[1] = d_slice