[ufo-core] 01/08: Imported Upstream version 0.3
Frédéric-Emmanuel Picca
picca at moszumanska.debian.org
Sat Nov 30 20:54:11 UTC 2013
This is an automated email from the git hooks/post-receive script.
picca pushed a commit to branch master
in repository ufo-core.
commit a9dd653b28ac01b53af2920de2d904b0e6b39795
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date: Sat Jul 27 09:00:13 2013 +0200
Imported Upstream version 0.3
---
.gitignore | 1 +
CMakeLists.txt | 119 +++
COPYING | 165 ++++
common/cmake/FindFFTW3.cmake | 133 ++++
common/cmake/FindGObjectIntrospection.cmake | 61 ++
common/cmake/FindNumpy.cmake | 57 ++
common/cmake/FindOCLFFT.cmake | 14 +
common/cmake/FindOpenCL.cmake | 89 +++
common/cmake/FindVala.cmake | 65 ++
docs/CMakeLists.txt | 41 +
docs/Ufo-docs.xml.in | 29 +
docs/Ufo-sections.txt.in | 180 +++++
docs/manual/_static/ufo-logo.png | Bin 0 -> 2512 bytes
docs/manual/_templates/indexcontent.html | 48 ++
docs/manual/_templates/indexsidebar.html | 5 +
docs/manual/_templates/layout.html | 5 +
docs/manual/api/general.rst | 19 +
docs/manual/api/index.rst | 13 +
docs/manual/api/ufo-0.3.rst | 1093 +++++++++++++++++++++++++++
docs/manual/bugs.rst | 18 +
docs/manual/conf.py.in | 202 +++++
docs/manual/contents.rst | 17 +
docs/manual/copyright.rst | 8 +
docs/manual/faq.rst | 153 ++++
docs/manual/glossary.rst | 14 +
docs/manual/install/index.rst | 14 +
docs/manual/install/linux.rst | 175 +++++
docs/manual/install/mac.rst | 69 ++
docs/manual/json.rst | 144 ++++
docs/manual/using/background.rst | 86 +++
docs/manual/using/cluster.rst | 23 +
docs/manual/using/filters.rst | 244 ++++++
docs/manual/using/index.rst | 30 +
docs/manual/using/quickstart.rst | 195 +++++
docs/manual/whatsnew/0.1.rst | 12 +
docs/manual/whatsnew/0.2.rst | 69 ++
docs/manual/whatsnew/0.3.rst | 31 +
docs/manual/whatsnew/index.rst | 15 +
docs/scangobj.sh.in | 1 +
python/CMakeLists.txt | 29 +
python/setup.py.in | 13 +
python/ufotools/__init__.py | 27 +
tests/CMakeLists.txt | 33 +
tests/gtester.xsl | 72 ++
tests/test-config.c | 96 +++
tests/test-graph.c | 283 +++++++
tests/test-profiler.c | 76 ++
tests/test-suite.c | 47 ++
tests/test-suite.h | 8 +
tests/test.json | 24 +
tools/CMakeLists.txt | 13 +
tools/clprof | 126 +++
tools/deploy.sh | 91 +++
tools/leakcheck.sh | 4 +
tools/mkfilter.py | 87 +++
tools/runjson.c | 135 ++++
tools/templates/ufo-cpu-task.c.in | 174 +++++
tools/templates/ufo-cpu-task.h.in | 66 ++
tools/templates/ufo-gpu-task.c.in | 181 +++++
tools/templates/ufo-gpu-task.h.in | 66 ++
tools/ufod.c | 468 ++++++++++++
ufo/CMakeLists.txt | 271 +++++++
ufo/Ufo.types | 0
ufo/config.h.in | 3 +
ufo/ufo-arch-graph.c | 292 +++++++
ufo/ufo-arch-graph.h | 78 ++
ufo/ufo-buffer.c | 566 ++++++++++++++
ufo/ufo-buffer.h | 161 ++++
ufo/ufo-config.c | 281 +++++++
ufo/ufo-config.h | 72 ++
ufo/ufo-configurable.c | 53 ++
ufo/ufo-configurable.h | 50 ++
ufo/ufo-cpu-node.c | 121 +++
ufo/ufo-cpu-node.h | 71 ++
ufo/ufo-cpu-task-iface.c | 85 +++
ufo/ufo-cpu-task-iface.h | 73 ++
ufo/ufo-dummy-task.c | 88 +++
ufo/ufo-dummy-task.h | 70 ++
ufo/ufo-enums.c.template | 44 ++
ufo/ufo-enums.h.template | 25 +
ufo/ufo-gpu-node.c | 110 +++
ufo/ufo-gpu-node.h | 71 ++
ufo/ufo-gpu-task-iface.c | 90 +++
ufo/ufo-gpu-task-iface.h | 80 ++
ufo/ufo-graph.c | 744 ++++++++++++++++++
ufo/ufo-graph.h | 123 +++
ufo/ufo-group.c | 346 +++++++++
ufo/ufo-group.h | 103 +++
ufo/ufo-input-task.c | 204 +++++
ufo/ufo-input-task.h | 74 ++
ufo/ufo-node.c | 147 ++++
ufo/ufo-node.h | 80 ++
ufo/ufo-output-task.c | 244 ++++++
ufo/ufo-output-task.h | 75 ++
ufo/ufo-plugin-manager.c | 369 +++++++++
ufo/ufo-plugin-manager.h | 86 +++
ufo/ufo-profiler.c | 353 +++++++++
ufo/ufo-profiler.h | 110 +++
ufo/ufo-remote-node.c | 374 +++++++++
ufo/ufo-remote-node.h | 133 ++++
ufo/ufo-remote-task.c | 176 +++++
ufo/ufo-remote-task.h | 70 ++
ufo/ufo-resources.c | 691 +++++++++++++++++
ufo/ufo-resources.h | 103 +++
ufo/ufo-scheduler.c | 704 +++++++++++++++++
ufo/ufo-scheduler.h | 80 ++
ufo/ufo-task-graph.c | 846 +++++++++++++++++++++
ufo/ufo-task-graph.h | 104 +++
ufo/ufo-task-iface.c | 92 +++
ufo/ufo-task-iface.h | 103 +++
ufo/ufo-task-node.c | 240 ++++++
ufo/ufo-task-node.h | 96 +++
ufo/ufo.h | 52 ++
ufo/ufo.pc.in | 13 +
114 files changed, 15466 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..a608d96
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,119 @@
+cmake_minimum_required(VERSION 2.6)
+project(ufo C)
+
+set(TARNAME "libufo")
+set(UFO_VERSION_MAJOR "0")
+set(UFO_VERSION_MINOR "3")
+set(UFO_VERSION_PATCH "1")
+set(UFO_GIR_VERSION "${UFO_VERSION_MAJOR}.${UFO_VERSION_MINOR}")
+
+# increase UFO_SO_VERSION on each version that breaks ABI compatibility
+set(UFO_SO_VERSION "3")
+
+set(UFO_DESCRIPTION "UFO high-speed image processing core library")
+set(UFO_DESCRIPTION_SUMMARY "UFO high-speed image processing core library")
+
+set(PACKAGE_VERSION_MAJOR ${UFO_VERSION_MAJOR})
+set(PACKAGE_VERSION_MINOR ${UFO_VERSION_MINOR})
+set(PACKAGE_VERSION_PATCH ${UFO_VERSION_PATCH})
+set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}")
+set(PACKAGE_NAME ${TARNAME})
+set(PACKAGE_TARNAME ${TARNAME})
+set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+set(PACKAGE_BUGREPORT "http://ufo.kit.edu/ufo/newticket")
+
+enable_testing()
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/common/cmake")
+
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ufo")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/ufo")
+
+
+# --- Options -----------------------------------------------------------------
+option(WITH_PROFILING "Enable profiling" OFF)
+if (WITH_PROFILING)
+ add_definitions("-pg")
+ set(CMAKE_C_FLAGS "-pg")
+endif ()
+
+
+# --- Find packages and libraries ---------------------------------------------
+
+# These packages are required in all sub-directories because Glib and GObject is
+# part of the API/ABI.
+
+find_package(OpenCL REQUIRED)
+find_package(PkgConfig REQUIRED)
+
+pkg_check_modules(GLIB2 glib-2.0>=2.22 REQUIRED)
+pkg_check_modules(GOBJECT2 gobject-2.0>=2.22 REQUIRED)
+pkg_check_modules(GMODULE2 gmodule-2.0>=2.22 REQUIRED)
+pkg_check_modules(GTHREAD2 gthread-2.0>=2.22 REQUIRED)
+pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
+pkg_check_modules(ZMQ libzmq>=3.2 REQUIRED)
+
+set(UFOCORE_DEPS
+ ${OPENCL_LIBRARIES}
+ ${GLIB2_LIBRARIES}
+ ${GOBJECT2_LIBRARIES}
+ ${GMODULE2_LIBRARIES}
+ ${GTHREAD2_LIBRARIES}
+ ${JSON_GLIB_LIBRARIES}
+ ${ZMQ_LIBRARIES})
+
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${GLIB2_INCLUDE_DIRS}
+ ${OPENCL_INCLUDE_DIRS}
+ ${JSON_GLIB_INCLUDE_DIRS}
+ ${ZMQ_INCLUDE_DIRS})
+
+link_directories(
+ ${ZMQ_LIBRARY_DIRS}
+ ${JSON_GLIB_LIBRARY_DIRS})
+
+add_definitions("-std=c99 -pedantic -Wall -Wextra -fPIC")
+
+if (CMAKE_COMPILER_IS_GNUCC)
+ add_definitions("-Wmissing-prototypes -Wmissing-declarations -Wshadow
+ -Wpointer-arith -Wcast-align -Wwrite-strings -Wredundant-decls -Wcast-qual
+ -Wnested-externs -Winline -Wno-long-long -Wconversion -Wstrict-prototypes")
+
+ add_definitions("-Wno-unused-parameter -Wno-missing-field-initializers")
+endif()
+
+add_definitions(-DG_LOG_DOMAIN=\"Ufo\")
+
+add_subdirectory(ufo)
+add_subdirectory(docs)
+#add_subdirectory(python)
+add_subdirectory(tests)
+add_subdirectory(tools)
+
+
+# --- Package generation ------------------------------------------------------
+set(CPACK_PACKAGE_DESCRIPTION ${UFO_DESCRIPTION})
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${UFO_DESCRIPTION_SUMMARY})
+set(CPACK_PACKAGE_NAME ${TARNAME})
+
+set(CPACK_PACKAGE_CONTACT "matthias.vogelgesang at kit.edu")
+set(CPACK_PACKAGE_VENDOR "Karlsruhe Institute of Technology/IPE")
+set(CPACK_PACKAGE_VERSION_MAJOR ${PACKAGE_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${PACKAGE_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${PACKAGE_VERSION_PATCH})
+set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
+set(VERSION ${PACKAGE_VERSION})
+
+set(CPACK_GENERATOR "DEB;RPM;")
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_IGNORE_FILES "tags" ".bzr" ".swp" "~1~" ".git" ".xml")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}" CACHE INTERNAL "tarball basename")
+
+# --- Distro specific
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1)")
+
+include(CPack)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..65c5ca8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/common/cmake/FindFFTW3.cmake b/common/cmake/FindFFTW3.cmake
new file mode 100644
index 0000000..252fcd9
--- /dev/null
+++ b/common/cmake/FindFFTW3.cmake
@@ -0,0 +1,133 @@
+#
+# Try to find FFTW3 library
+# (see www.fftw.org)
+# Once run this will define:
+#
+# FFTW3_FOUND
+# FFTW3_INCLUDE_DIR
+# FFTW3_LIBRARIES
+# FFTW3_LINK_DIRECTORIES
+#
+# You may set one of these options before including this file:
+# FFTW3_USE_SSE2
+#
+# TODO: _F_ versions.
+#
+# Jan Woetzel 05/2004
+# www.mip.informatik.uni-kiel.de
+# --------------------------------
+
+ FIND_PATH(FFTW3_INCLUDE_DIR fftw3.h
+ ${FFTW3_DIR}/include
+ ${FFTW3_HOME}/include
+ ${FFTW3_DIR}
+ ${FFTW3_HOME}
+ $ENV{FFTW3_DIR}/include
+ $ENV{FFTW3_HOME}/include
+ $ENV{FFTW3_DIR}
+ $ENV{FFTW3_HOME}
+ /usr/include
+ /usr/local/include
+ $ENV{SOURCE_DIR}/fftw3
+ $ENV{SOURCE_DIR}/fftw3/include
+ $ENV{SOURCE_DIR}/fftw
+ $ENV{SOURCE_DIR}/fftw/include
+ )
+#MESSAGE("DBG FFTW3_INCLUDE_DIR=${FFTW3_INCLUDE_DIR}")
+
+
+SET(FFTW3_POSSIBLE_LIBRARY_PATH
+ ${FFTW3_DIR}/lib
+ ${FFTW3_HOME}/lib
+ ${FFTW3_DIR}
+ ${FFTW3_HOME}
+ $ENV{FFTW3_DIR}/lib
+ $ENV{FFTW3_HOME}/lib
+ $ENV{FFTW3_DIR}
+ $ENV{FFTW3_HOME}
+ /usr/lib
+ /usr/local/lib
+ $ENV{SOURCE_DIR}/fftw3
+ $ENV{SOURCE_DIR}/fftw3/lib
+ $ENV{SOURCE_DIR}/fftw
+ $ENV{SOURCE_DIR}/fftw/lib
+)
+
+
+# the lib prefix is containe din filename onf W32, unfortuantely. JW
+# teh "general" lib:
+FIND_LIBRARY(FFTW3_FFTW_LIBRARY
+ NAMES fftw3 libfftw libfftw3 libfftw3-3
+ PATHS
+ ${FFTW3_POSSIBLE_LIBRARY_PATH}
+ )
+#MESSAGE("DBG FFTW3_FFTW_LIBRARY=${FFTW3_FFTW_LIBRARY}")
+
+FIND_LIBRARY(FFTW3_FFTWF_LIBRARY
+ NAMES fftwf3 fftw3f fftwf libfftwf libfftwf3 libfftw3f libfftw3f-3
+ PATHS
+ ${FFTW3_POSSIBLE_LIBRARY_PATH}
+ )
+#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWF_LIBRARY}")
+
+FIND_LIBRARY(FFTW3_FFTWL_LIBRARY
+ NAMES fftwl3 fftw3l fftwl libfftwl libfftwl3 libfftw3l libfftw3l-3
+ PATHS
+ ${FFTW3_POSSIBLE_LIBRARY_PATH}
+ )
+#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWL_LIBRARY}")
+
+
+FIND_LIBRARY(FFTW3_FFTW_SSE2_LIBRARY
+ NAMES fftw_sse2 fftw3_sse2 libfftw_sse2 libfftw3_sse2
+ PATHS
+ ${FFTW3_POSSIBLE_LIBRARY_PATH}
+ )
+#MESSAGE("DBG FFTW3_FFTW_SSE2_LIBRARY=${FFTW3_FFTW_SSE2_LIBRARY}")
+
+FIND_LIBRARY(FFTW3_FFTWF_SSE_LIBRARY
+ NAMES fftwf_sse fftwf3_sse fftw3f_sse libfftwf_sse libfftwf3_sse libfftw3f_sse
+ PATHS
+ ${FFTW3_POSSIBLE_LIBRARY_PATH}
+ )
+#MESSAGE("DBG FFTW3_FFTWF_SSE_LIBRARY=${FFTW3_FFTWF_SSE_LIBRARY}")
+
+
+# --------------------------------
+# select one of the above
+# default:
+IF (FFTW3_FFTW_LIBRARY)
+ SET(FFTW3_LIBRARIES ${FFTW3_FFTW_LIBRARY})
+ENDIF (FFTW3_FFTW_LIBRARY)
+# specialized:
+IF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY)
+ SET(FFTW3_LIBRARIES ${FFTW3_FFTW_SSE2_LIBRARY})
+ENDIF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY)
+
+# --------------------------------
+
+IF(FFTW3_LIBRARIES)
+ IF (FFTW3_INCLUDE_DIR)
+
+ # OK, found all we need
+ SET(FFTW3_FOUND TRUE)
+ GET_FILENAME_COMPONENT(FFTW3_LINK_DIRECTORIES ${FFTW3_LIBRARIES} PATH)
+
+ ELSE (FFTW3_INCLUDE_DIR)
+ MESSAGE("FFTW3 include dir not found. Set FFTW3_DIR to find it.")
+ ENDIF(FFTW3_INCLUDE_DIR)
+ELSE(FFTW3_LIBRARIES)
+ MESSAGE("FFTW3 lib not found. Set FFTW3_DIR to find it.")
+ENDIF(FFTW3_LIBRARIES)
+
+
+MARK_AS_ADVANCED(
+ FFTW3_INCLUDE_DIR
+ FFTW3_LIBRARIES
+ FFTW3_FFTW_LIBRARY
+ FFTW3_FFTW_SSE2_LIBRARY
+ FFTW3_FFTWF_LIBRARY
+ FFTW3_FFTWF_SSE_LIBRARY
+ FFTW3_FFTWL_LIBRARY
+ FFTW3_LINK_DIRECTORIES
+)
diff --git a/common/cmake/FindGObjectIntrospection.cmake b/common/cmake/FindGObjectIntrospection.cmake
new file mode 100644
index 0000000..2073c3c
--- /dev/null
+++ b/common/cmake/FindGObjectIntrospection.cmake
@@ -0,0 +1,61 @@
+# - try to find gobject-introspection
+#
+# Once done this will define
+#
+# INTROSPECTION_FOUND - system has gobject-introspection
+# INTROSPECTION_SCANNER - the gobject-introspection scanner, g-ir-scanner
+# INTROSPECTION_COMPILER - the gobject-introspection compiler, g-ir-compiler
+# INTROSPECTION_GENERATE - the gobject-introspection generate, g-ir-generate
+# INTROSPECTION_GIRDIR
+# INTROSPECTION_TYPELIBDIR
+# INTROSPECTION_CFLAGS
+# INTROSPECTION_LIBS
+#
+# Copyright (C) 2010, Pino Toscano, <pino at kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+macro(_GIR_GET_PKGCONFIG_VAR _outvar _varname)
+ execute_process(
+ COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${_varname} gobject-introspection-1.0
+ OUTPUT_VARIABLE _result
+ RESULT_VARIABLE _null
+ )
+
+ if (_null)
+ else()
+ string(REGEX REPLACE "[\r\n]" " " _result "${_result}")
+ string(REGEX REPLACE " +$" "" _result "${_result}")
+ separate_arguments(_result)
+ set(${_outvar} ${_result} CACHE INTERNAL "")
+ endif()
+endmacro(_GIR_GET_PKGCONFIG_VAR)
+
+find_package(PkgConfig)
+if(PKG_CONFIG_FOUND)
+ if(PACKAGE_FIND_VERSION_COUNT GREATER 0)
+ set(_gir_version_cmp ">=${PACKAGE_FIND_VERSION}")
+ endif()
+ pkg_check_modules(_pc_gir gobject-introspection-1.0${_gir_version_cmp})
+ if(_pc_gir_FOUND)
+ set(INTROSPECTION_FOUND TRUE)
+ _gir_get_pkgconfig_var(INTROSPECTION_SCANNER "g_ir_scanner")
+ _gir_get_pkgconfig_var(INTROSPECTION_COMPILER "g_ir_compiler")
+ _gir_get_pkgconfig_var(INTROSPECTION_GENERATE "g_ir_generate")
+ _gir_get_pkgconfig_var(INTROSPECTION_GIRDIR "girdir")
+ _gir_get_pkgconfig_var(INTROSPECTION_TYPELIBDIR "typelibdir")
+ set(INTROSPECTION_CFLAGS "${_pc_gir_CFLAGS}")
+ set(INTROSPECTION_LIBS "${_pc_gir_LIBS}")
+ endif()
+endif()
+
+mark_as_advanced(
+ INTROSPECTION_SCANNER
+ INTROSPECTION_COMPILER
+ INTROSPECTION_GENERATE
+ INTROSPECTION_GIRDIR
+ INTROSPECTION_TYPELIBDIR
+ INTROSPECTION_CFLAGS
+ INTROSPECTION_LIBS
+)
diff --git a/common/cmake/FindNumpy.cmake b/common/cmake/FindNumpy.cmake
new file mode 100644
index 0000000..367c738
--- /dev/null
+++ b/common/cmake/FindNumpy.cmake
@@ -0,0 +1,57 @@
+#
+# $Id: $
+#
+# Author(s): Anton Deguet
+# Created on: 2010-01-20
+#
+# (C) Copyright 2010 Johns Hopkins University (JHU), All Rights
+# Reserved.
+#
+# --- begin cisst license - do not edit ---
+#
+# This software is provided "as is" under an open source license, with
+# no warranty. The complete license can be found in license.txt and
+# http://www.cisst.org/cisst/license.txt.
+#
+# --- end cisst license ---
+#
+# File based on FindNUMARRAY distributed with ITK 3.4 (see itk.org)
+#
+# Main modifications:
+# - use Numpy instead of Numarray for all naming
+# - added path for Python 2.5 and 2.6
+# - renamed python script generated (det_npp became determineNumpyPath)
+# - use lower case for CMake commands and keywords
+# - updated python script to use get_include, not get_numpy_include which is now deprecated
+#
+# ---
+#
+# Try to find numpy python package
+# Once done this will define
+#
+# PYTHON_NUMPY_FOUND - system has numpy development package and it should be used
+# PYTHON_NUMPY_INCLUDE_DIR - directory where the arrayobject.h header file can be found
+#
+#
+if(PYTHON_EXECUTABLE)
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/determineNumpyPath.py "try: import numpy; print numpy.get_include()\nexcept: pass\n")
+ exec_program("${PYTHON_EXECUTABLE}"
+ ARGS "\"${CMAKE_CURRENT_BINARY_DIR}/determineNumpyPath.py\""
+ OUTPUT_VARIABLE NUMPY_PATH
+ )
+endif(PYTHON_EXECUTABLE)
+
+find_path(PYTHON_NUMPY_INCLUDE_DIR arrayobject.h
+ "${NUMPY_PATH}/numpy/"
+ "${PYTHON_INCLUDE_PATH}/numpy/"
+ /usr/include/python2.6/numpy/
+ /usr/include/python2.5/numpy/
+ /usr/include/python2.4/numpy/
+ /usr/include/python2.3/numpy/
+ DOC "Directory where the arrayobject.h header file can be found. This file is part of the numpy package"
+ )
+
+if(PYTHON_NUMPY_INCLUDE_DIR)
+ set(PYTHON_NUMPY_FOUND 1 CACHE INTERNAL "Python numpy development package is available")
+endif(PYTHON_NUMPY_INCLUDE_DIR)
+
diff --git a/common/cmake/FindOCLFFT.cmake b/common/cmake/FindOCLFFT.cmake
new file mode 100644
index 0000000..fd9c156
--- /dev/null
+++ b/common/cmake/FindOCLFFT.cmake
@@ -0,0 +1,14 @@
+# Try to find liboclfft and clFFT.h. Once found the following variables will be
+# defined:
+#
+# OCLFFT_FOUND
+# OCLFFT_INCLUDE_DIRS
+# OCLFFT_LIBRARIES
+
+find_path(OCLFFT_INCLUDE_DIRS clFFT.h)
+find_library(OCLFFT_LIBRARIES oclfft)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OCLFFT DEFAULT_MSG OCLFFT_INCLUDE_DIRS OCLFFT_LIBRARIES)
+
+mark_as_advanced(OCLFFT_INCLUDE_DIRS OCLFFT_LIBRARIES)
diff --git a/common/cmake/FindOpenCL.cmake b/common/cmake/FindOpenCL.cmake
new file mode 100644
index 0000000..f1b1301
--- /dev/null
+++ b/common/cmake/FindOpenCL.cmake
@@ -0,0 +1,89 @@
+# - Try to find OpenCL
+# This module tries to find an OpenCL implementation on your system. It supports
+# AMD / ATI, Apple and NVIDIA implementations, but shoudl work, too.
+#
+# Once done this will define
+# OPENCL_FOUND - system has OpenCL
+# OPENCL_INCLUDE_DIRS - the OpenCL include directory
+# OPENCL_LIBRARIES - link these to use OpenCL
+#
+# WIN32 should work, but is untested
+
+FIND_PACKAGE( PackageHandleStandardArgs )
+
+SET (OPENCL_VERSION_STRING "0.1.0")
+SET (OPENCL_VERSION_MAJOR 0)
+SET (OPENCL_VERSION_MINOR 1)
+SET (OPENCL_VERSION_PATCH 0)
+
+IF (APPLE)
+
+ FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX")
+ FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX")
+ FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX")
+
+ELSE (APPLE)
+
+ IF (WIN32)
+
+ FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h)
+ FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp)
+
+ # The AMD SDK currently installs both x86 and x86_64 libraries
+ # This is only a hack to find out architecture
+ IF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" )
+ SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86_64")
+ ELSE (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
+ SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86")
+ ENDIF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" )
+ FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR})
+
+ GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE)
+
+ # On Win32 search relative to the library
+ FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}")
+ FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}")
+
+ ELSE (WIN32)
+
+ # Unix style platforms
+ FIND_LIBRARY(OPENCL_LIBRARIES OpenCL
+ ENV LD_LIBRARY_PATH
+ /usr/lib/nvidia-current
+ /usr/lib64/nvidia
+ /opt/nvidia-current
+ /opt/AMDAPP/lib
+ )
+
+ GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH)
+ GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE)
+
+ # The AMD SDK currently does not place its headers
+ # in /usr/include, therefore also search relative
+ # to the library
+ FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS
+ ${_OPENCL_INC_CAND}
+ /usr/local/cuda/include
+ /opt/cuda/include
+ /opt/AMDAPP/include)
+ FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND})
+
+ ENDIF (WIN32)
+
+ENDIF (APPLE)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS )
+
+IF( _OPENCL_CPP_INCLUDE_DIRS )
+ SET( OPENCL_HAS_CPP_BINDINGS TRUE )
+ LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} )
+ # This is often the same, so clean up
+ LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS )
+ENDIF( _OPENCL_CPP_INCLUDE_DIRS )
+
+MARK_AS_ADVANCED(
+ OPENCL_LIBRARIES
+ OPENCL_INCLUDE_DIRS
+ _OPENCL_CPP_INCLUDE_DIRS
+)
+
diff --git a/common/cmake/FindVala.cmake b/common/cmake/FindVala.cmake
new file mode 100644
index 0000000..2d1ed14
--- /dev/null
+++ b/common/cmake/FindVala.cmake
@@ -0,0 +1,65 @@
+##
+# Copyright 2009 Jakob Westhoff. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and documentation are those
+# of the authors and should not be interpreted as representing official policies,
+# either expressed or implied, of Jakob Westhoff
+##
+
+##
+# Find module for the Vala compiler (valac)
+#
+# This module determines wheter a Vala compiler is installed on the current
+# system and where its executable is.
+#
+# Call the module using "find_package(Vala) from within your CMakeLists.txt.
+#
+# The following variables will be set after an invocation:
+#
+# VALA_FOUND Whether the vala compiler has been found or not
+# VALA_EXECUTABLE Full path to the valac executable if it has been found
+# VALA_VERSION Version number of the available valac
+##
+
+
+# Search for the valac executable in the usual system paths.
+find_program(VALA_EXECUTABLE
+ NAMES valac)
+
+# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call.
+# Furthermore set VALA_FOUND to TRUE if Vala has been found (aka.
+# VALA_EXECUTABLE is set)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Vala DEFAULT_MSG VALA_EXECUTABLE)
+
+mark_as_advanced(VALA_EXECUTABLE)
+
+# Determine the valac version
+if(VALA_FOUND)
+ execute_process(COMMAND ${VALA_EXECUTABLE} "--version"
+ OUTPUT_VARIABLE "VALA_VERSION")
+ string(REPLACE "Vala" "" "VALA_VERSION" ${VALA_VERSION})
+ string(STRIP ${VALA_VERSION} "VALA_VERSION")
+endif(VALA_FOUND)
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644
index 0000000..0e9eecc
--- /dev/null
+++ b/docs/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 2.8)
+
+find_program(SPHINX sphinx-build PATHS /usr/local/bin /usr/bin)
+mark_as_advanced(SPHINX)
+
+# --- End-user manual ---------------------------------------------------------
+if(SPHINX)
+ option(WITH_MANUAL "Build user manual" ON)
+
+ if (WITH_MANUAL)
+ set(input_dir ${CMAKE_CURRENT_SOURCE_DIR}/manual)
+ set(output_dir ${CMAKE_CURRENT_BINARY_DIR}/manual)
+
+ file(GLOB_RECURSE sphinx_source ${input_dir}/*.rst)
+ list(APPEND sphinx_source "${output_dir}/conf.py")
+
+ set(sphinx_static
+ _static/ufo-logo.png
+ _templates/indexcontent.html
+ _templates/indexsidebar.html
+ _templates/layout.html
+ )
+
+ configure_file(${input_dir}/conf.py.in ${output_dir}/conf.py)
+
+ foreach(file ${sphinx_static})
+ configure_file(${input_dir}/${file} ${output_dir}/${file} COPYONLY)
+ endforeach()
+
+ add_custom_command(OUTPUT ${output_dir}/html/index.html
+ COMMAND ${SPHINX} -b html -c ${output_dir} ${input_dir} html
+ DEPENDS ${sphinx_source}
+ WORKING_DIRECTORY ${output_dir}
+ COMMENT "Build Sphinx HTML")
+
+ add_custom_target(manual ALL DEPENDS ${output_dir}/html/index.html)
+
+ add_dependencies(manual ufo)
+ endif()
+endif()
+
diff --git a/docs/Ufo-docs.xml.in b/docs/Ufo-docs.xml.in
new file mode 100644
index 0000000..e4bf038
--- /dev/null
+++ b/docs/Ufo-docs.xml.in
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
+]>
+<book id="index">
+ <bookinfo>
+ <title>UFO Reference Manual</title>
+ <releaseinfo>
+ for UFO ${UFO_API_VERSION}
+ The latest version of this documentation can be found on-line at
+ <ulink role="online-location"
+ url="http://ufo.kit.edu/ufo">http://ufo.kit.edu/ufo/</ulink>.
+ </releaseinfo>
+ </bookinfo>
+
+ <chapter>
+ <title>UFO API Reference</title>
+ ${_xml_doc_input}
+
+ </chapter>
+ <index id="api-index-full">
+ <title>API Index</title>
+ <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+ </index>
+
+ <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+</book>
diff --git a/docs/Ufo-sections.txt.in b/docs/Ufo-sections.txt.in
new file mode 100644
index 0000000..b518754
--- /dev/null
+++ b/docs/Ufo-sections.txt.in
@@ -0,0 +1,180 @@
+<SECTION>
+<FILE>ufo-config</FILE>
+<TITLE>UfoConfig</TITLE>
+UfoConfig
+ufo_config_new
+ufo_config_get_paths
+<SUBSECTION Standard>
+UFO_CONFIG
+UFO_CONFIG_CLASS
+UFO_CONFIG_GET_CLASS
+UFO_IS_CONFIG
+UFO_IS_CONFIG_CLASS
+UFO_TYPE_CONFIG
+ufo_config_get_type
+<SUBSECTION Private>
+UfoConfigPrivate
+</SECTION>
+
+<SECTION>
+<FILE>ufo-configurable</FILE>
+<TITLE>UfoConfigurable</TITLE>
+UfoConfigurable
+<SUBSECTION Standard>
+UFO_CONFIGURABLE
+UFO_CONFIGURABLE_CLASS
+UFO_CONFIGURABLE_GET_IFACE
+UFO_IS_CONFIGURABLE
+UFO_IS_CONFIGURABLE_CLASS
+UFO_TYPE_CONFIGURABLE
+ufo_configurable_get_type
+<SUBSECTION Private>
+UfoConfigurableIface
+</SECTION>
+
+<SECTION>
+<FILE>ufo-plugin-manager</FILE>
+<TITLE>UfoPluginManager</TITLE>
+UfoPluginManagerError
+UfoPluginManager
+ufo_plugin_manager_new
+ufo_plugin_manager_get_task
+ufo_plugin_manager_get_all_task_names
+<SUBSECTION Standard>
+UFO_PLUGIN_MANAGER
+UFO_IS_PLUGIN_MANAGER
+UFO_TYPE_PLUGIN_MANAGER
+ufo_plugin_manager_get_type
+UFO_PLUGIN_MANAGER_CLASS
+UFO_IS_PLUGIN_MANAGER_CLASS
+UFO_PLUGIN_MANAGER_GET_CLASS
+<SUBSECTION Private>
+UFO_PLUGIN_MANAGER_ERROR
+UfoPluginManagerPrivate
+ufo_plugin_manager_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>ufo-resource-manager</FILE>
+<TITLE>UfoResources</TITLE>
+UfoResourcesError
+UfoResources
+ufo_resources_new
+ufo_resources_get_kernel
+ufo_resources_get_kernel_from_source
+ufo_resources_get_context
+<SUBSECTION Standard>
+UFO_RESOURCES
+UFO_IS_RESOURCES
+UFO_TYPE_RESOURCES
+ufo_resources_get_type
+UFO_RESOURCES_CLASS
+UFO_IS_RESOURCES_CLASS
+UFO_RESOURCES_GET_CLASS
+<SUBSECTION Private>
+UFO_RESOURCES_ERROR
+UfoResourcesClass
+UfoResourcesPrivate
+opencl_map_error
+ufo_resources_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>ufo-profiler</FILE>
+<TITLE>UfoProfiler</TITLE>
+UfoProfilerFunc
+UfoProfilerLevel
+UfoProfilerTimer
+UfoProfiler
+UfoProfilerClass
+ufo_profiler_new
+ufo_profiler_call
+ufo_profiler_foreach
+ufo_profiler_start
+ufo_profiler_stop
+ufo_profiler_elapsed
+<SUBSECTION Standard>
+UFO_TYPE_PROFILER
+UFO_IS_PROFILER
+UFO_IS_PROFILER_CLASS
+UFO_PROFILER
+UFO_PROFILER_CLASS
+UFO_PROFILER_GET_CLASS
+ufo_profiler_get_type
+<SUBSECTION Private>
+UfoProfilerPrivate
+</SECTION>
+
+<SECTION>
+<FILE>ufo-graph</FILE>
+<TITLE>UfoGraph</TITLE>
+UfoGraph
+ufo_graph_new
+<SUBSECTION Standard>
+UFO_GRAPH
+UFO_IS_GRAPH
+UFO_TYPE_GRAPH
+ufo_graph_get_type
+UFO_GRAPH_CLASS
+UFO_IS_GRAPH_CLASS
+UFO_GRAPH_GET_CLASS
+<SUBSECTION Private>
+UFO_GRAPH_ERROR
+UfoGraphClass
+UfoGraphPrivate
+ufo_graph_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>ufo-buffer</FILE>
+<TITLE>UfoBuffer</TITLE>
+UfoBufferError
+UfoBuffer
+UFO_BUFFER_MAX_NDIMS
+ufo_buffer_new
+ufo_buffer_copy
+ufo_buffer_get_size
+ufo_buffer_get_2d_dimensions
+ufo_buffer_resize
+ufo_buffer_get_host_array
+ufo_buffer_get_device_array
+<SUBSECTION>UfoBufferParamSpec</SUBSECTION>
+UfoBufferParamSpec
+ufo_buffer_param_spec
+<SUBSECTION Standard>
+UFO_BUFFER
+UFO_IS_BUFFER
+UFO_TYPE_BUFFER
+ufo_buffer_get_type
+UFO_BUFFER_CLASS
+UFO_IS_BUFFER_CLASS
+UFO_BUFFER_GET_CLASS
+UFO_BUFFER_PARAM_SPEC
+UFO_IS_PARAM_SPEC_BUFFER
+UFO_TYPE_PARAM_BUFFER
+ufo_buffer_param_get_type
+<SUBSECTION Private>
+UFO_BUFFER_ERROR
+UfoBufferPrivate
+UfoBufferClass
+ufo_buffer_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>ufo-scheduler</FILE>
+<TITLE>UfoScheduler</TITLE>
+UfoScheduler
+ufo_scheduler_new
+ufo_scheduler_run
+<SUBSECTION Standard>
+UFO_SCHEDULER
+UFO_SCHEDULER_CLASS
+UFO_SCHEDULER_GET_CLASS
+UFO_IS_SCHEDULER
+UFO_IS_SCHEDULER_CLASS
+UFO_TYPE_SCHEDULER
+ufo_scheduler_get_type
+<SUBSECTION Private>
+UfoSchedulerClass
+UfoSchedulerPrivate
+</SECTION>
diff --git a/docs/manual/_static/ufo-logo.png b/docs/manual/_static/ufo-logo.png
new file mode 100644
index 0000000..351b64f
Binary files /dev/null and b/docs/manual/_static/ufo-logo.png differ
diff --git a/docs/manual/_templates/indexcontent.html b/docs/manual/_templates/indexcontent.html
new file mode 100644
index 0000000..33883d4
--- /dev/null
+++ b/docs/manual/_templates/indexcontent.html
@@ -0,0 +1,48 @@
+{% extends "defindex.html" %}
+{% block tables %}
+ <p><strong>Parts of the documentation:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("whatsnew/" + version) }}">What's new in UFO {{ version }}?</a><br/>
+ <span class="linkdescr">or <a href="{{ pathto("whatsnew/index") }}">all "What's new" documents</a></span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installation</a><br/>
+ <span class="linkdescr">install from either packages or source</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("using/index") }}">Using UFO</a><br/>
+ <span class="linkdescr">how to use UFO on different platforms</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("json") }}">JSON Configuration</a><br/>
+ <span class="linkdescr">configure UFO graphs textual</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("api/index") }}">UFO API</a><br/>
+ <span class="linkdescr">reference for C/C++ programmers</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
+ <span class="linkdescr">frequently asked questions</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Indices and tables:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/>
+ <span class="linkdescr">all functions, classes, terms</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("glossary") }}">Glossary</a><br/>
+ <span class="linkdescr">the most important terms explained</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
+ <span class="linkdescr">search this documentation</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Complete Table of Contents</a><br/>
+ <span class="linkdescr">lists all sections and subsections</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Meta information:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("todo") }}">TODO</a></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("bugs") }}">Reporting bugs</a></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("copyright") }}">Copyright</a></p>
+ </td></tr>
+ </table>
+
+{% endblock %}
+
diff --git a/docs/manual/_templates/indexsidebar.html b/docs/manual/_templates/indexsidebar.html
new file mode 100644
index 0000000..f6b3914
--- /dev/null
+++ b/docs/manual/_templates/indexsidebar.html
@@ -0,0 +1,5 @@
+ <h3>Other resources</h3>
+ <ul>
+ <li><a href="http://ufo.kit.edu">Project Homepage</a></li>
+ <li><a href="http://ufo.kit.edu/ufo">Development Homepage</a></li>
+ </ul>
diff --git a/docs/manual/_templates/layout.html b/docs/manual/_templates/layout.html
new file mode 100644
index 0000000..0429147
--- /dev/null
+++ b/docs/manual/_templates/layout.html
@@ -0,0 +1,5 @@
+{% extends "!layout.html" %}
+{% block rootrellink %}
+ <li><a href="{{ pathto('index') }}">Index</a> | </li>
+ <li><a href="{{ pathto('contents') }}">Contents</a> »</li>
+{% endblock %}
diff --git a/docs/manual/api/general.rst b/docs/manual/api/general.rst
new file mode 100644
index 0000000..3928260
--- /dev/null
+++ b/docs/manual/api/general.rst
@@ -0,0 +1,19 @@
+================
+General Overview
+================
+
+.. default-domain:: c
+
+UFOs main purpose is to build streaming setups for fast image processing. Each
+setup consists of a :type:`UfoGraph` that contains several :type:`UfoFilter`
+nodes. Each Filter is characterized by its kernel task and the number of its
+input and output :type:`UfoChannel` elements. A Filter is added to the Graph by
+creating a new plugin instance with :func:`ufo_graph_get_filter()`. A connection
+between two Filters can be established either implicitly
+(:func:`ufo_filter_connect_to()`) or explicitly
+(:func:`ufo_filter_connect_by_name()`) which is mandatory for filters with more
+than one in- or output.
+
+Because, each Filter is derived from the `GObject` base class, the properties
+are set with :func:`g_object_set()`.
+
diff --git a/docs/manual/api/index.rst b/docs/manual/api/index.rst
new file mode 100644
index 0000000..c09bb03
--- /dev/null
+++ b/docs/manual/api/index.rst
@@ -0,0 +1,13 @@
+.. _ufo-api:
+
+=====================================
+UFO Application Programming Interface
+=====================================
+
+This information will help you understand how things work together and why some
+of the design decisions were made the way they are now.
+
+.. toctree::
+
+ general.rst
+ ufo-0.3.rst
diff --git a/docs/manual/api/ufo-0.3.rst b/docs/manual/api/ufo-0.3.rst
new file mode 100644
index 0000000..e86002c
--- /dev/null
+++ b/docs/manual/api/ufo-0.3.rst
@@ -0,0 +1,1093 @@
+=====================
+UFO 0.3 API reference
+=====================
+
+UfoArchGraph
+============
+
+.. c:type:: UfoArchGraph
+
+ Graph structure that describes the relation between hardware
+ nodes. The contents of the :c:type:`UfoArchGraph` structure are
+ private and should only be accessed via the provided API.
+
+
+.. c:function:: UfoGraph* ufo_arch_graph_new(UfoResources* resources, GList* remote_addresses)
+
+
+ :param resources: An initialized :c:type:`UfoResources` object
+ :param remote_addresses: A :c:type:`GList` containing address strings.
+
+ :returns: A new :c:type:`UfoArchGraph`.
+
+
+.. c:function:: guint ufo_arch_graph_get_num_cpus(UfoArchGraph* self)
+
+
+ :returns: Number of CPU nodes in ``graph``.
+
+
+.. c:function:: guint ufo_arch_graph_get_num_gpus(UfoArchGraph* self)
+
+
+ :returns: Number of GPU nodes in ``graph``.
+
+
+.. c:function:: guint ufo_arch_graph_get_num_remotes(UfoArchGraph* self)
+
+
+ :returns: Number of remote nodes in ``graph``.
+
+
+.. c:function:: GList* ufo_arch_graph_get_gpu_nodes(UfoArchGraph* self)
+
+ #UfoGpuNode elements in ``graph``.
+
+ :returns: A list of
+
+
+.. c:function:: GList* ufo_arch_graph_get_remote_nodes(UfoArchGraph* self)
+
+ #UfoRemoteNode elements in ``graph``.
+
+ :returns: A list of
+
+
+UfoBuffer
+=========
+
+.. c:type:: UfoBuffer
+
+ Represents n-dimensional data. The contents of the
+ :c:type:`UfoBuffer` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoBuffer* ufo_buffer_new(UfoRequisition* requisition, gpointer context)
+
+ Create a new :c:type:`UfoBuffer`.
+
+ :param requisition: size requisition
+ :param context: cl_context to use for creating the device array
+
+ :returns: A new :c:type:`UfoBuffer` with the given dimensions.
+
+
+.. c:function:: void ufo_buffer_resize(UfoBuffer* self, UfoRequisition* requisition)
+
+ Resize an existing buffer. If the new requisition has the same
+ size as before, resizing is a no-op.
+
+ :param requisition: A :c:type:`UfoRequisition` structure
+
+
+.. c:function:: gint ufo_buffer_cmp_dimensions(UfoBuffer* self, UfoRequisition* requisition)
+
+ Compare the size of ``buffer`` with a given ``requisition``.
+
+ :param requisition: #UfoRequisition
+
+ :returns: value < 0, 0 or > 0 if requisition is smaller, equal or larger.
+
+
+.. c:function:: void ufo_buffer_get_requisition(UfoBuffer* self, UfoRequisition* requisition)
+
+ Return the size of ``buffer``.
+
+ :param requisition: A location to store the requisition of ``buffer``
+
+
+.. c:function:: gsize ufo_buffer_get_size(UfoBuffer* self)
+
+ Get the number of bytes of raw data that is managed by the
+ ``buffer``.
+
+ :returns: The size of ``buffer``'s data.
+
+
+.. c:function:: void ufo_buffer_copy(UfoBuffer* self, UfoBuffer* dst)
+
+ Copy contents of ``src`` to ``dst``. The final memory location is
+ determined by the destination buffer.
+
+ :param dst: Destination :c:type:`UfoBuffer`
+
+
+.. c:function:: UfoBuffer* ufo_buffer_dup(UfoBuffer* self)
+
+ Create a new buffer with the same requisition as ``buffer``. Note,
+ that this is not a copy of ``buffer``!
+
+ :returns: A :c:type:`UfoBuffer` with the same size as ``buffer``.
+
+
+.. c:function:: gfloat* ufo_buffer_get_host_array(UfoBuffer* self, gpointer cmd_queue)
+
+ Returns a flat C-array containing the raw float data.
+
+ :param cmd_queue: A cl_command_queue object or ``NULL``.
+
+ :returns: Float array.
+
+
+.. c:function:: gpointer ufo_buffer_get_device_array(UfoBuffer* self, gpointer cmd_queue)
+
+ Return the current cl_mem object of ``buffer``. If the data is not
+ yet in device memory, it is transfered via ``cmd_queue`` to the
+ object. If ``cmd_queue`` is ``NULL``
+
+ :param cmd_queue: A cl_command_queue object or ``NULL``.
+
+ :returns: A cl_mem object associated with ``buffer``.
+
+
+.. c:function:: void ufo_buffer_discard_location(UfoBuffer* self, UfoMemLocation location)
+
+ Discard ``location`` and use "other" location without copying to
+ it first.
+
+ :param location: Location to discard
+
+
+.. c:function:: void ufo_buffer_convert(UfoBuffer* self, UfoBufferDepth depth)
+
+ Convert host data according to its ``depth`` to the internal
+ 32-bit floating point representation.
+
+ :param depth: Source bit depth of host data
+
+
+UfoBufferParam
+==============
+
+.. c:type:: UfoBufferParam
+
+
+
+UfoConfig
+=========
+
+.. c:type:: UfoConfig
+
+ A :c:type:`UfoConfig` provides access to run-time specific
+ settings.
+
+
+.. c:function:: UfoConfig* ufo_config_new()
+
+ Create a config object.
+
+ :returns: A new config object.
+
+
+.. c:function:: void ufo_config_add_paths(UfoConfig* self, GList* paths)
+
+ Add ``paths`` to the list of search paths for plugins and OpenCL
+ kernel files.
+
+ :param paths: List of strings
+
+
+.. c:function:: GList* ufo_config_get_paths(UfoConfig* self)
+
+ Get an array of path strings. file system paths. Use
+ :c:func:`g_list_free()` to free it.
+
+ :returns: A list of strings containing
+
+
+UfoCpuNode
+==========
+
+.. c:type:: UfoCpuNode
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoCpuNode` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_cpu_node_new(gpointer mask)
+
+
+ :param mask: None
+
+ :returns: None
+
+
+.. c:function:: gpointer ufo_cpu_node_get_affinity(UfoCpuNode* self)
+
+ Get affinity mask of ``node``.
+
+ :returns: A pointer to the cpu_set_t mask associated with
+
+
+UfoDummyTask
+============
+
+.. c:type:: UfoDummyTask
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoDummyTask` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_dummy_task_new()
+
+
+ :returns: None
+
+
+UfoGpuNode
+==========
+
+.. c:type:: UfoGpuNode
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoGpuNode` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_gpu_node_new(gpointer cmd_queue)
+
+
+ :param cmd_queue: None
+
+ :returns: None
+
+
+.. c:function:: gpointer ufo_gpu_node_get_cmd_queue(UfoGpuNode* self)
+
+ Get command queue associated with ``node``.
+
+ :returns: A cl_command_queue object for ``node``.
+
+
+UfoGraph
+========
+
+.. c:type:: UfoGraph
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoGraph` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoGraph* ufo_graph_new()
+
+ Create a new :c:type:`UfoGraph` object.
+
+ :returns: A :c:type:`UfoGraph`.
+
+
+.. c:function:: void ufo_graph_register_node_type(UfoGraph* self, GType type)
+
+ Registers ``type`` to be a valid node type of this graph. If a
+ type has not be an added to ``graph``, any attempt to add such a
+ node will fail.
+
+ :param type: A :c:type:`GType`
+
+
+.. c:function:: GList* ufo_graph_get_registered_node_types(UfoGraph* self)
+
+ Get all types of nodes that can be added to ``graph``. identifiers
+ that can be added to ``graph``.
+
+ :returns: A list of :c:type:`GType`
+
+
+.. c:function:: void ufo_graph_connect_nodes(UfoGraph* self, UfoNode* source, UfoNode* target, gpointer label)
+
+ Connect ``source`` with ``target`` in ``graph`` and annotate the
+ edge with
+
+ :param source: A source node
+ :param target: A target node
+ :param label: An arbitrary label
+
+
+.. c:function:: gboolean ufo_graph_is_connected(UfoGraph* self, UfoNode* from, UfoNode* to)
+
+ Check whether ``from`` is connected to ``to``.
+
+ :param from: A source node
+ :param to: A target node
+
+ :returns: %TRUE if ``from`` is connected to ``to``, otherwise %FALSE.
+
+
+.. c:function:: void ufo_graph_remove_edge(UfoGraph* self, UfoNode* source, UfoNode* target)
+
+ Remove edge between ``source`` and ``target``.
+
+ :param source: A source node
+ :param target: A target node
+
+
+.. c:function:: gpointer ufo_graph_get_edge_label(UfoGraph* self, UfoNode* source, UfoNode* target)
+
+ Retrieve edge label between ``source`` and ``target``.
+
+ :param source: Source node
+ :param target: Target node
+
+ :returns: Edge label pointer.
+
+
+.. c:function:: guint ufo_graph_get_num_nodes(UfoGraph* self)
+
+ Get number of nodes in ``graph``. The number is always divisible
+ by two, because nodes are only part of a graph if member of an
+ edge.
+
+ :returns: Number of nodes.
+
+
+.. c:function:: GList* ufo_graph_get_nodes(UfoGraph* self)
+
+ added to ``graph``.
+
+ :returns: A list of all nodes
+
+
+.. c:function:: GList* ufo_graph_get_nodes_filtered(UfoGraph* self, UfoFilterPredicate func, gpointer user_data)
+
+ Get nodes filtered by the predicate ``func``. that are marked as
+ true by the predicate function ``func``.
+
+ :param func: Predicate function to filter out nodes
+ :param user_data: Data to be passed to ``func`` on invocation
+
+ :returns: A list of all nodes
+
+
+.. c:function:: guint ufo_graph_get_num_edges(UfoGraph* self)
+
+ Get number of edges present in ``graph``.
+
+ :returns: Number of edges.
+
+
+.. c:function:: GList* ufo_graph_get_edges(UfoGraph* self)
+
+ Get all edges contained in ``graph``. error. Release the list with
+ :c:func:`g_list_free()`.
+
+ :returns: a list of :c:type:`UfoEdge` elements or ``NULL`` on
+
+
+.. c:function:: GList* ufo_graph_get_roots(UfoGraph* self)
+
+ Get all roots of ``graph``. that do not have a predessor node.
+
+ :returns: A list of all nodes
+
+
+.. c:function:: GList* ufo_graph_get_leaves(UfoGraph* self)
+
+ Get all leaves of ``graph``. that do not have a predessor node.
+
+ :returns: A list of all nodes
+
+
+.. c:function:: GList* ufo_graph_get_predecessors(UfoGraph* self, UfoNode* node)
+
+ Get the all nodes connected to ``node``. nodes of ``node``. Free
+ the list with :c:func:`g_list_free()` but not its elements.
+
+ :param node: A :c:type:`UfoNode` whose predecessors are returned.
+
+ :returns: A list with preceeding
+
+
+.. c:function:: GList* ufo_graph_get_successors(UfoGraph* self, UfoNode* node)
+
+ Get the successors of ``node``. nodes of ``node``. Free the list
+ with :c:func:`g_list_free()` but not its elements.
+
+ :param node: A :c:type:`UfoNode` whose successors are returned.
+
+ :returns: A list with succeeding
+
+
+.. c:function:: GList* ufo_graph_get_paths(UfoGraph* self, UfoFilterPredicate pred)
+
+ Compute a list of lists that contain complete paths with nodes
+ that match a predicate function. that match ``pred``.
+
+ :param pred: A predicate function
+
+ :returns: A list of lists with paths
+
+
+.. c:function:: void ufo_graph_split(UfoGraph* self, GList* path)
+
+ Duplicate nodes between head and tail of path and insert at the
+ exact the position of where path started and ended.
+
+ :param path: A path of nodes, preferably created with :c:func:`ufo_graph_get_paths()`.
+
+
+.. c:function:: void ufo_graph_dump_dot(UfoGraph* self, gchar* filename)
+
+ Stores a GraphViz dot representation of ``graph`` in ``filename``.
+
+ :param filename: A string containing a filename
+
+
+UfoGroup
+========
+
+.. c:type:: UfoGroup
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoGroup` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoGroup* ufo_group_new(GList* targets, gpointer context, UfoSendPattern pattern)
+
+ Create a new :c:type:`UfoGroup`.
+
+ :param targets: A list of :c:type:`UfoNode` targets
+ :param context: A cl_context on which the targets should operate on.
+ :param pattern: Pattern to distribute data among the ``targets``
+
+ :returns: A new :c:type:`UfoGroup`.
+
+
+.. c:function:: void ufo_group_set_num_expected(UfoGroup* self, UfoTask* target, gint n_expected)
+
+
+ :param target: None
+ :param n_expected: None
+
+
+.. c:function:: UfoBuffer* ufo_group_pop_output_buffer(UfoGroup* self, UfoRequisition* requisition)
+
+ that must be released with
+ :c:func:`ufo_group_push_output_buffer()`.
+
+ :param requisition: Size of the buffer.
+
+ :returns: A newly allocated buffer or a re-used buffer
+
+
+.. c:function:: void ufo_group_push_output_buffer(UfoGroup* self, UfoBuffer* buffer)
+
+
+ :param buffer: None
+
+
+.. c:function:: UfoBuffer* ufo_group_pop_input_buffer(UfoGroup* self, UfoTask* target)
+
+ ufo_group_push_input_buffer().
+
+ :param target: The :c:type:`UfoTask` that is a target in ``group``
+
+ :returns: A buffer that must be released with
+
+
+.. c:function:: void ufo_group_push_input_buffer(UfoGroup* self, UfoTask* target, UfoBuffer* input)
+
+
+ :param target: None
+ :param input: None
+
+
+.. c:function:: void ufo_group_finish(UfoGroup* self)
+
+
+
+UfoInputTask
+============
+
+.. c:type:: UfoInputTask
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoInputTask` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_input_task_new()
+
+
+ :returns: None
+
+
+.. c:function:: void ufo_input_task_stop(UfoInputTask* self)
+
+
+
+.. c:function:: void ufo_input_task_release_input_buffer(UfoInputTask* self, UfoBuffer* buffer)
+
+
+ :param buffer: None
+
+
+.. c:function:: UfoBuffer* ufo_input_task_get_input_buffer(UfoInputTask* self)
+
+ Get the input buffer to which we write the data received from the
+ master remote node.
+
+ :returns: A :c:type:`UfoBuffer` for writing input data.
+
+
+UfoNodes
+========
+
+.. c:type:: UfoNode
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoNode` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_node_new(gpointer label)
+
+
+ :param label: None
+
+ :returns: None
+
+
+.. c:function:: gpointer ufo_node_get_label(UfoNode* self)
+
+ Get arbitrary label data of ``node``.
+
+ :returns: The label of ``node``.
+
+
+.. c:function:: UfoNode* ufo_node_copy(UfoNode* self)
+
+ Get a copy of ``node``. How "deep" the copy is, depends on the
+ inherited implementation of ``node``.
+
+ :returns: Copy of ``node``.
+
+
+.. c:function:: gboolean ufo_node_equal(UfoNode* self, UfoNode* n2)
+
+
+ :param n2: None
+
+ :returns: None
+
+
+UfoOutputTask
+=============
+
+.. c:type:: UfoOutputTask
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoOutputTask` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_output_task_new(guint n_dims)
+
+
+ :param n_dims: None
+
+ :returns: None
+
+
+.. c:function:: void ufo_output_task_get_output_requisition(UfoOutputTask* self, UfoRequisition* requisition)
+
+
+ :param requisition: None
+
+
+.. c:function:: UfoBuffer* ufo_output_task_get_output_buffer(UfoOutputTask* self)
+
+ Get the output buffer from which we read the data to be sent to
+ the master remote node.
+
+ :returns: A :c:type:`UfoBuffer` for reading output data.
+
+
+.. c:function:: void ufo_output_task_release_output_buffer(UfoOutputTask* self, UfoBuffer* buffer)
+
+
+ :param buffer: None
+
+
+UfoPluginManager
+================
+
+.. c:type:: UfoPluginManager
+
+ Creates :c:type:`UfoFilter` instances by loading corresponding
+ shared objects. The contents of the :c:type:`UfoPluginManager`
+ structure are private and should only be accessed via the provided
+ API.
+
+
+.. c:function:: UfoPluginManager* ufo_plugin_manager_new(UfoConfig* config)
+
+ Create a plugin manager object to instantiate filter objects. When
+ a config object is passed to the constructor, its search-path
+ property is added to the internal search paths.
+
+ :param config: A :c:type:`UfoConfig` object or ``NULL``.
+
+ :returns: A new plugin manager object.
+
+
+.. c:function:: UfoNode* ufo_plugin_manager_get_task(UfoPluginManager* self, gchar* name)
+
+ Load a :c:type:`UfoFilter` module and return an instance. The
+ shared object name must be * constructed as "libfilter at name.so".
+
+ :param name: Name of the plugin.
+
+ :returns: #UfoFilter or ``NULL`` if module cannot be found
+
+
+.. c:function:: GList* ufo_plugin_manager_get_all_task_names(UfoPluginManager* self)
+
+ Return a list with potential filter names that match shared
+ objects in all search paths.
+
+ :returns: List of strings with filter names
+
+
+UfoProfiler
+===========
+
+.. c:type:: UfoProfiler
+
+ The :c:type:`UfoProfiler` collects and records OpenCL events and
+ stores them in a convenient format on disk or prints summaries on
+ screen.
+
+
+.. c:function:: UfoProfiler* ufo_profiler_new(UfoProfilerLevel level)
+
+ Create a profiler object.
+
+ :param level: Amount of information that should be tracked by the profiler.
+
+ :returns: A new profiler object.
+
+
+.. c:function:: void ufo_profiler_call(UfoProfiler* self, gpointer command_queue, gpointer kernel, guint work_dim, gsize* global_work_size, gsize* local_work_size)
+
+ Execute the ``kernel`` using the command queue and execution
+ parameters. The event associated with the
+ :c:func:`clEnqueueNDRangeKernel()` call is recorded and may be
+ used for profiling purposes later on.
+
+ :param command_queue: A %cl_command_queue
+ :param kernel: A %cl_kernel
+ :param work_dim: Number of working dimensions.
+ :param global_work_size: Sizes of global dimensions. The array must have at least
+ :param local_work_size: Sizes of local work group dimensions. The array must have at least ``work_dim`` entries.
+
+
+.. c:function:: void ufo_profiler_foreach(UfoProfiler* self, UfoProfilerFunc func, gpointer user_data)
+
+ Iterates through the recorded events and calls ``func`` for each
+ entry.
+
+ :param func: The function to be called for an entry
+ :param user_data: User parameters
+
+
+.. c:function:: void ufo_profiler_start(UfoProfiler* self, UfoProfilerTimer timer)
+
+ Start ``timer``. The timer is not reset but accumulates the time
+ elapsed between :c:func:`ufo_profiler_start()` and
+ :c:func:`ufo_profiler_stop()` calls.
+
+ :param timer: Which timer to start
+
+
+.. c:function:: void ufo_profiler_stop(UfoProfiler* self, UfoProfilerTimer timer)
+
+ Stop ``timer``. The timer is not reset but accumulates the time
+ elapsed between :c:func:`ufo_profiler_start()` and
+ :c:func:`ufo_profiler_stop()` calls.
+
+ :param timer: Which timer to stop
+
+
+.. c:function:: gdouble ufo_profiler_elapsed(UfoProfiler* self, UfoProfilerTimer timer)
+
+ Get the elapsed time in seconds for ``timer``.
+
+ :param timer: Which timer to start
+
+ :returns: Elapsed time in seconds.
+
+
+UfoRemoteNode
+=============
+
+.. c:type:: UfoRemoteNode
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoRemoteNode` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_remote_node_new(gpointer zmq_context, gchar* address)
+
+
+ :param zmq_context: None
+ :param address: None
+
+ :returns: None
+
+
+.. c:function:: guint ufo_remote_node_get_num_gpus(UfoRemoteNode* self)
+
+
+ :returns: None
+
+
+.. c:function:: void ufo_remote_node_request_setup(UfoRemoteNode* self)
+
+
+
+.. c:function:: void ufo_remote_node_send_json(UfoRemoteNode* self, gchar* json, gsize size)
+
+
+ :param json: None
+ :param size: None
+
+
+.. c:function:: void ufo_remote_node_get_structure(UfoRemoteNode* self, guint* n_inputs, UfoInputParam** in_params, UfoTaskMode* mode)
+
+
+ :param n_inputs: None
+ :param in_params: None
+ :param mode: None
+
+
+.. c:function:: void ufo_remote_node_send_inputs(UfoRemoteNode* self, UfoBuffer** inputs)
+
+
+ :param inputs: None
+
+
+.. c:function:: void ufo_remote_node_get_result(UfoRemoteNode* self, UfoBuffer* result)
+
+
+ :param result: None
+
+
+.. c:function:: void ufo_remote_node_get_requisition(UfoRemoteNode* self, UfoRequisition* requisition)
+
+
+ :param requisition: None
+
+
+.. c:function:: void ufo_remote_node_cleanup(UfoRemoteNode* self)
+
+
+
+UfoRemoteTask
+=============
+
+.. c:type:: UfoRemoteTask
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoRemoteTask` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoNode* ufo_remote_task_new()
+
+
+ :returns: None
+
+
+UfoResources
+============
+
+.. c:type:: UfoResources
+
+ Manages OpenCL resources. The contents of the
+ :c:type:`UfoResources` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoResources* ufo_resources_new(UfoConfig* config)
+
+ Create a new :c:type:`UfoResources` instance.
+
+ :param config: A :c:type:`UfoConfiguration` object or ``NULL``
+
+ :returns: A new :c:type:`UfoResources`
+
+
+.. c:function:: gpointer ufo_resources_get_kernel(UfoResources* self, gchar* filename, gchar* kernel)
+
+ Loads a and builds a kernel from a file. The file is searched in
+ the current working directory and all paths added through
+ ufo_resources_add_paths ().
+
+ :param filename: Name of the .cl kernel file
+ :param kernel: Name of a kernel
+
+ :returns: a cl_kernel object that is load from ``filename`` or ``NULL`` on error
+
+
+.. c:function:: gpointer ufo_resources_get_kernel_from_source(UfoResources* self, gchar* source, gchar* kernel)
+
+ Loads and builds a kernel from a string.
+
+ :param source: OpenCL source string
+ :param kernel: Name of a kernel
+
+ :returns: a cl_kernel object that is load from ``filename``
+
+
+.. c:function:: gpointer ufo_resources_get_context(UfoResources* self)
+
+ Returns the OpenCL context object that is used by the resource
+ resources. This context can be used to initialize othe third-party
+ libraries.
+
+ :returns: A cl_context object.
+
+
+.. c:function:: GList* ufo_resources_get_cmd_queues(UfoResources* self)
+
+ Get all command queues managed by ``resources``. cl_command_queue
+ objects. Free with :c:func:`g_list_free()` but not its elements.
+
+ :returns: List with
+
+
+UfoScheduler
+============
+
+.. c:type:: UfoScheduler
+
+ The base class scheduler is responsible of assigning command
+ queues to filters (thus managing GPU device resources) and decide
+ if to run a GPU or a CPU. The actual schedule planning can be
+ overriden.
+
+
+.. c:function:: UfoScheduler* ufo_scheduler_new(UfoConfig* config, GList* remotes)
+
+ Creates a new :c:type:`UfoScheduler`.
+
+ :param config: A :c:type:`UfoConfig` or ``NULL``
+ :param remotes: A :c:type:`GList` with strings describing remote machines or ``NULL``
+
+ :returns: A new :c:type:`UfoScheduler`
+
+
+.. c:function:: void ufo_scheduler_run(UfoScheduler* self, UfoTaskGraph* task_graph)
+
+
+ :param task_graph: None
+
+
+.. c:function:: gpointer ufo_scheduler_get_context(UfoScheduler* self)
+
+ Get the associated OpenCL context of ``scheduler``.
+
+ :returns: An cl_context structure or ``NULL`` on error.
+
+
+.. c:function:: void ufo_scheduler_set_task_split(UfoScheduler* self, gboolean split)
+
+ Sets whether the task graph should be split before execution to
+ increase multi GPU performance.
+
+ :param split: %TRUE if task graph should be split
+
+
+UfoTaskGraph
+============
+
+.. c:type:: UfoTaskGraph
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoTaskGraph` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: UfoGraph* ufo_task_graph_new()
+
+ Create a new task graph without any nodes.
+
+ :returns: A :c:type:`UfoGraph` that can be upcast to a :c:type:`UfoTaskGraph`.
+
+
+.. c:function:: void ufo_task_graph_read_from_file(UfoTaskGraph* self, UfoPluginManager* manager, gchar* filename)
+
+ Read a JSON configuration file to fill the structure of ``graph``.
+
+ :param manager: A :c:type:`UfoPluginManager` used to load the filters
+ :param filename: Path and filename to the JSON file
+
+
+.. c:function:: void ufo_task_graph_read_from_data(UfoTaskGraph* self, UfoPluginManager* manager, gchar* json)
+
+ Read a JSON configuration file to fill the structure of ``graph``.
+
+ :param manager: A :c:type:`UfoPluginManager` used to load the filters
+ :param json: ``NULL``-terminated string with JSON data
+
+
+.. c:function:: void ufo_task_graph_save_to_json(UfoTaskGraph* self, gchar* filename)
+
+ Save a JSON configuration file with the filter structure of
+ ``graph``.
+
+ :param filename: Path and filename to the JSON file
+
+
+.. c:function:: void ufo_task_graph_map(UfoTaskGraph* self, UfoArchGraph* arch_graph)
+
+ Map task nodes of ``task_graph`` to the processing nodes of
+ ``arch_graph``. Not doing this could break execution of
+ ``task_graph``.
+
+ :param arch_graph: A :c:type:`UfoArchGraph` to which ``task_graph``'s nodes are mapped onto
+
+
+.. c:function:: void ufo_task_graph_split(UfoTaskGraph* self, UfoArchGraph* arch_graph)
+
+ Splits ``task_graph`` in a way that most of the resources in
+ ``arch_graph`` can be occupied. In the simple pipeline case, the
+ longest possible GPU paths are duplicated as much as there are
+ GPUs in ``arch_graph``.
+
+ :param arch_graph: A :c:type:`UfoArchGraph`
+
+
+.. c:function:: void ufo_task_graph_connect_nodes(UfoTaskGraph* self, UfoTaskNode* n1, UfoTaskNode* n2)
+
+ Connect ``n1`` with ``n2`` using ``n2``'s default input port. To
+ specify any other port, use
+ :c:func:`ufo_task_graph_connect_nodes_full()`.
+
+ :param n1: A source node
+ :param n2: A destination node
+
+
+.. c:function:: void ufo_task_graph_connect_nodes_full(UfoTaskGraph* self, UfoTaskNode* n1, UfoTaskNode* n2, guint input)
+
+ Connect ``n1`` with ``n2`` using ``n2``'s ``input`` port.
+
+ :param n1: A source node
+ :param n2: A destination node
+ :param input: Input port of ``n2``
+
+
+.. c:function:: void ufo_task_graph_fuse(UfoTaskGraph* self)
+
+ Fuses task nodes to increase data locality.
+
+
+UfoTaskNode
+===========
+
+.. c:type:: UfoTaskNode
+
+ Main object for organizing filters. The contents of the
+ :c:type:`UfoTaskNode` structure are private and should only be
+ accessed via the provided API.
+
+
+.. c:function:: void ufo_task_node_set_plugin_name(UfoTaskNode* self, gchar* name)
+
+
+ :param name: None
+
+
+.. c:function:: gchar* ufo_task_node_get_plugin_name(UfoTaskNode* self)
+
+
+ :returns: None
+
+
+.. c:function:: gchar* ufo_task_node_get_unique_name(UfoTaskNode* self)
+
+
+ :returns: None
+
+
+.. c:function:: void ufo_task_node_set_send_pattern(UfoTaskNode* self, UfoSendPattern pattern)
+
+
+ :param pattern: None
+
+
+.. c:function:: UfoSendPattern ufo_task_node_get_send_pattern(UfoTaskNode* self)
+
+
+ :returns: None
+
+
+.. c:function:: void ufo_task_node_set_num_expected(UfoTaskNode* self, guint pos, gint n_expected)
+
+
+ :param pos: None
+ :param n_expected: None
+
+
+.. c:function:: gint ufo_task_node_get_num_expected(UfoTaskNode* self, guint pos)
+
+
+ :param pos: None
+
+ :returns: None
+
+
+.. c:function:: void ufo_task_node_set_out_group(UfoTaskNode* self, UfoGroup* group)
+
+
+ :param group: None
+
+
+.. c:function:: UfoGroup* ufo_task_node_get_out_group(UfoTaskNode* self)
+
+ Get the current out of ``node``. The out group is used to fetch
+ the ouput buffer for ``node`` using
+ :c:func:`ufo_group_pop_output_buffer()`.
+
+ :returns: The out group of ``node``.
+
+
+.. c:function:: void ufo_task_node_add_in_group(UfoTaskNode* self, guint pos, UfoGroup* group)
+
+
+ :param pos: None
+ :param group: None
+
+
+.. c:function:: UfoGroup* ufo_task_node_get_current_in_group(UfoTaskNode* self, guint pos)
+
+ Several nodes can be connected to input ``pos`` of ``node``.
+ However, at a time currently selected input group at ``pos``.
+
+ :param pos: Input position of ``node``
+
+ :returns: The current in group of ``node`` for ``pos``.
+
+
+.. c:function:: void ufo_task_node_switch_in_group(UfoTaskNode* self, guint pos)
+
+
+ :param pos: None
+
+
+.. c:function:: void ufo_task_node_set_proc_node(UfoTaskNode* self, UfoNode* proc_node)
+
+
+ :param proc_node: None
+
+
+.. c:function:: UfoNode* ufo_task_node_get_proc_node(UfoTaskNode* self)
+
+ Get the associated processing node of ``node``.
+
+ :returns: A :c:type:`UfoNode`.
diff --git a/docs/manual/bugs.rst b/docs/manual/bugs.rst
new file mode 100644
index 0000000..a0a5d82
--- /dev/null
+++ b/docs/manual/bugs.rst
@@ -0,0 +1,18 @@
+.. _reporting-bugs:
+
+==============
+Reporting Bugs
+==============
+
+Using the Trac bug tracker
+============================
+
+Bug reports regarding the UFO framework itself should be submitted via the `Trac
+bug tracker`__ by choosing the ``ufo-core`` component. Anything related to
+specific filter behaviour are classified under the ``ufo-filters`` component.
+
+The Trac system also provides lists of all tickets concerning `core`_ and `filters`_.
+
+.. __: http://ufo.kit.edu/ufo/newticket
+.. _core: http://ufo.kit.edu/ufo/report/10
+.. _filters: http://ufo.kit.edu/ufo/report/11
diff --git a/docs/manual/conf.py.in b/docs/manual/conf.py.in
new file mode 100644
index 0000000..6f40fca
--- /dev/null
+++ b/docs/manual/conf.py.in
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+#
+# UFO documentation build configuration file, created by
+# sphinx-quickstart on Mon Apr 18 12:10:11 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os, time
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath' ]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+#master_doc = 'index'
+
+# General information about the project.
+project = u'UFO'
+copyright = u'%s, UFO Development Team a Collaboration of KIT, SCI and TPU' % time.strftime('%Y')
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = "${UFO_VERSION_MAJOR}.${UFO_VERSION_MINOR}"
+# The full version, including alpha/beta/rc tags.
+release = "${PACKAGE_VERSION}"
+
+primary_domain = 'c'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'default'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+ 'stickysidebar': 'true'
+}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = "_static/ufo-logo.png"
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+ 'index' : 'indexsidebar.html'
+}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = {
+ 'index' : 'indexcontent.html'
+}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'UFOdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'UFO.tex', u'UFO Documentation',
+ u'Matthias Vogelgesang', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/docs/manual/contents.rst b/docs/manual/contents.rst
new file mode 100644
index 0000000..25e0e23
--- /dev/null
+++ b/docs/manual/contents.rst
@@ -0,0 +1,17 @@
+==========================
+UFO Documentation contents
+==========================
+
+.. toctree::
+
+ whatsnew/index.rst
+ install/index.rst
+ using/index.rst
+ api/index.rst
+ json.rst
+ faq.rst
+ glossary.rst
+
+ bugs.rst
+ copyright.rst
+
diff --git a/docs/manual/copyright.rst b/docs/manual/copyright.rst
new file mode 100644
index 0000000..5cdb6d3
--- /dev/null
+++ b/docs/manual/copyright.rst
@@ -0,0 +1,8 @@
+=========
+Copyright
+=========
+
+UFO and this documentation is:
+
+Copyright 2011 Karlsruhe Institute of Technology (Institute for Data Processing
+and Electronics) and Tomsk Polytechnic University
diff --git a/docs/manual/faq.rst b/docs/manual/faq.rst
new file mode 100644
index 0000000..6e738d5
--- /dev/null
+++ b/docs/manual/faq.rst
@@ -0,0 +1,153 @@
+.. _faq:
+
+==========================
+Frequently Asked Questions
+==========================
+
+Installation
+============
+
+.. _faq-linker-cant-find-libufo:
+
+Why can't the linker find libufo.so?
+----------------------------------------
+
+In the rare circumstances that you installed UFO from source for the first time
+by calling ``make install``, the dynamic linker does not know that the library
+exists. If this is the case issue ::
+
+ $ sudo ldconfig
+
+on Debian systems or ::
+
+ $ su
+ $ ldconfig
+
+on openSUSE systems.
+
+If this is not working, the library is neither installed into ``/usr/lib`` nor
+``/usr/local/lib`` on 32-bit systems or ``/usr/lib64`` and ``/usr/local/lib64``
+on 64-bit systems. Make sure not to mess with the ``CMAKE_INSTALL_PREFIX``
+during source :ref:`configuration <inst-installing-into-non-standard-directories>`.
+
+
+Usage
+=====
+
+.. _faq-filter-not-found:
+
+Why do I get a "libfilter<foo>.so not found" message?
+-------------------------------------------------------
+
+Because the UFO core system is unable to locate the filters. By default it looks
+into ``${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/ufo``, where the installation
+prefix is usually something like ``/usr`` or ``/usr/local``. If you don't want
+to install the filters system-wide, you can tell the system to try other paths
+as well::
+
+ >>> from gi.repository import Ufo
+ >>> graph = Ufo.Graph(paths='/home/user/path/to/filters:/another/path')
+
+
+Can I split a linear data stream?
+---------------------------------
+
+The output data stream of a node can be split by setting the
+``UFO_SEND_SEQUENTIAL`` mode and adjusting the number of expecting data items on
+each connected node::
+
+ from gi.repository import Ufo
+
+ out_node.set_send_pattern(Ufo.SendPattern.SEQUENTIAL)
+ in1_node.set_num_expected(0, 5) # expect five items on the first input
+ in2_node.set_num_expected(0, -1) # expect all items
+
+ g = Ufo.TaskGraph()
+ g.connect_nodes(out_node, in1_node)
+ g.connect_nodes(out_node, in2_node)
+
+The connection order matters here! If it would be reversed, ``in2_node`` would
+receive all items whereas ``in1_node`` wouldn't receive anything.
+
+
+How can I control the debug output from libufo?
+-----------------------------------------------
+
+Generally, UFO emits debug messages under the log domain ``Ufo``. To handle
+these messages you must set a log handler_ that decides what to do with the
+messages. To ignore all messages in Python, you would have to write something
+like this::
+
+ from gi.repository import Ufo, GLib
+
+ def ignore_message(domain, level, message, user):
+ pass
+
+ if __name__ == '__main__':
+ GLib.log_set_handler("Ufo", GLib.LogLevelFlags.LEVEL_MASK,
+ ignore_message, None)
+
+.. _handler: http://developer.gnome.org/glib/unstable/glib-Message-Logging.html#g-log-set-handler
+
+
+.. _faq-numpy-output:
+
+How can I use Numpy output?
+---------------------------
+
+Install the Python extension module from ``vogelgesang/ufonp`` with ``setup.py``
+like this::
+
+ $ cd <path-to-ufonp>
+ $ python setup.py build
+ $ sudo python setup.py install
+
+You can then use the BufferInput filter to process Numpy arrays data::
+
+ from gi.repository import Ufo
+ import ufotools
+ import numpy as np
+
+ arrays = [ i*np.eye(100, dtype=np.float32) for i in range(1, 10) ]
+ buffers = [ ufotools.fromarray(a) for a in arrays ]
+
+ g = Ufo.Graph()
+ numpy_input = g.get_filter('bufferinput')
+ numpy_input.set_properties(buffers=buffers)
+
+
+How can I instantiate and pass parameters when creating a filter?
+-----------------------------------------------------------------
+
+Yes, the same module that is used to access Numpy buffers has a convenience
+wrapper around the :c:type:`UfoGraph` class that provides a ``new_filter`` method::
+
+ import ufotools.patch
+
+ g = ufotools.patch.Graph()
+ rd = g.new_filter('reader', path='/home/src', count=5)
+ wr = g.new_filter('writer', path='/home/dst', prefix='foo-')
+
+
+.. _faq-synchronize-properties:
+
+How can I synchronize two properties?
+-------------------------------------
+
+Although this is a general GObject question, synchronizing two properties is
+particularly important if the receiving filter depends on a changed property.
+For example, the back-projection should start only if a center-of-rotation is
+known. In Python you can use the ``bind_property`` function from the
+``ufotools`` module like this::
+
+ from gi.repository import Ufo
+ import ufotools.bind_property
+
+ g = Ufo.Graph()
+ cor = g.get_filter('centerofrotation')
+ bp = g.get_filter('backproject')
+
+ # Now connect the properties
+ ufotools.bind_property(cor, 'center', bp, 'axis-pos')
+
+In C, the similar ``g_object_bind_property`` function is provided out-of-the-box.
diff --git a/docs/manual/glossary.rst b/docs/manual/glossary.rst
new file mode 100644
index 0000000..efe77b7
--- /dev/null
+++ b/docs/manual/glossary.rst
@@ -0,0 +1,14 @@
+.. _glossary:
+
+========
+Glossary
+========
+
+.. keep alphetical sort order!
+
+.. glossary::
+
+ UFO
+ Ultra fast X-ray imaging of scientific processes with on-line assessment
+ and data-driven process control. Now figure out where the individual
+ abbreviation letters come from.
diff --git a/docs/manual/install/index.rst b/docs/manual/install/index.rst
new file mode 100644
index 0000000..bc4781b
--- /dev/null
+++ b/docs/manual/install/index.rst
@@ -0,0 +1,14 @@
+.. _installation:
+
+============
+Installation
+============
+
+In this section, information about how to install the UFO library and the
+accompanying filter suite is described.
+
+.. toctree::
+ :maxdepth: 2
+
+ linux.rst
+ mac.rst
diff --git a/docs/manual/install/linux.rst b/docs/manual/install/linux.rst
new file mode 100644
index 0000000..b3fa48a
--- /dev/null
+++ b/docs/manual/install/linux.rst
@@ -0,0 +1,175 @@
+.. _installation-linux:
+
+#####################
+Installation on Linux
+#####################
+
+====================
+Building from source
+====================
+
+UFO has only a few hard source dependencies, namely
+
+ - `GLib 2.0 <http://developer.gnome.org/glib/stable/>`_,
+ - `JSON-GLib 1.0 <http://live.gnome.org/JsonGlib>`_
+ - `ZeroMQ 3.2 <http://zeromq.org>`_ and
+ - a valid OpenCL installation.
+
+Furthermore, it is necessary to build the framework with a recent version of
+`CMake <http://cmake.org>`_. `Sphinx <http://sphinx.pocoo.org>`_ is used to
+create this documentation and `Bazaar <bazaar.canonical.com>`_ for revision
+control.
+
+In case you use openSUSE, just issue ::
+
+ $ zypper install gcc gcc-c++ glib2-devel json-glib-devel
+ $ zypper install gobject-introspection-devel python-gobject2
+ $ zypper install gtk-doc python-Sphinx
+ $ zypper install libtiff-devel
+
+to install dependencies from the package repositories. Depending on which system
+you are using you have to install ZeroMQ 3.2 from source ::
+
+ $ wget http://download.zeromq.org/zeromq-3.2.2.tar.gz
+ $ tar xfz zeromq-3.2.2.tar.gz
+ $ cd zeromq-3.2.2
+ $ ./configure && make && make distcheck
+ $ make install
+
+OpenCL development files must be installed in order to build UFO. However, we
+cannot give general advices as installation procedures vary between different
+vendors. However, our CMake build facility is in most cases intelligent enough
+to find header files and libraries for NVIDIA CUDA and AMD APP SDKs.
+
+
+Retrieving the source code
+==========================
+
+In an empty directory, issue the following commands to retrieve the current
+unstable version of the source::
+
+ $ git clone http://ufo.kit.edu/git/ufo-core
+ $ git clone http://ufo.kit.edu/git/ufo-filters
+ $ git clone http://ufo.kit.edu/git/oclfft
+
+ OR
+
+ $ git clone git at ufo.kit.edu:ufo-core
+ $ git clone git at ufo.kit.edu:ufo-filters
+ $ git clone git at ufo.kit.edu:oclfft
+
+The latter is used for developers who have write-access to the corresponding
+repositories. All stable versions are tagged. To see a list of all releases
+issue::
+
+ $ git tag -l
+
+
+Quick deployment
+================
+
+UFO comes with a deploy script located in ``$UFO_ROOT/tools``. If executed
+without any arguments it will try to build and install ZeroMQ, UFO (core and
+filters) and oclfft for ``/usr/local``. You can set the installation prefix as
+an argument to install it into your home directory.
+
+
+System-wide installation
+========================
+
+If you have root access on the build machine, you can install the libraries and
+tools system-wide so that every user can access them.
+
+Building ufo-core
+-----------------
+
+Change into another empty `build` directory and issue the following commands to
+configure ::
+
+ $ cmake <path-to-ufo>
+
+CMake will notify you, if some of the dependencies are not met. In case you want
+to install the library system-wide on a 64-bit machine you should generate the
+Makefiles with ::
+
+ $ cmake <path-to-ufo> -DLIB_SUFFIX=64
+
+For earlier versions of PyGObject, it is necessary that the introspection files
+are located under ``/usr`` not ``/usr/local``. You can force the prefix by
+calling ::
+
+ $ cmake <path-to-ufo> -DCMAKE_INSTALL_PREFIX=/usr
+
+Last but not least build the framework, introspection files, API reference and
+the documentation using ::
+
+ $ make
+
+You should now run some basic tests with ::
+
+ $ make test
+
+If everything went well, you can install the library with ::
+
+ $ make install
+
+You can also build ``RPM`` and ``DEB`` packages with ::
+
+ $ make package
+
+and source tarballs with ::
+
+ $ make package_source
+
+.. seealso:: :ref:`faq-linker-cant-find-libufo`
+
+
+Building ufo-filters
+--------------------
+
+Once ufo-core is installed you can build the filter suite in a pretty similar
+way ::
+
+ $ mkdir -p build/ufo-filters
+ $ cd build/ufo-filters
+ $ cmake <path-to-ufo-filters> -DLIB_SUFFIX=64 -DCMAKE_INSTALL_PREFIX=/usr
+ $ make
+ $ make install
+
+
+.. _inst-installing-into-non-standard-directories:
+
+Installing into non-standard directories
+========================================
+
+It is possible to install the library in a non-standard directory, for example
+in the home directory of a user. In case we want to install in ``~/tmp/usr``, we
+have to configure ufo-core like this ::
+
+ $ mkdir -p build/ufo-core
+ $ cd build/ufo-core
+ $ cmake <path-to-ufo> -DCMAKE_INSTALL_PREFIX=/home/user/tmp/usr
+ $ make && make install
+
+Now, we have to adjust the ``pkg-config`` path, so that the library can be
+found when configuring the filters ::
+
+ $ export PKG_CONFIG_PATH=/home/user/tmp/usr/lib/pkgconfig
+ $ mkdir -p build/ufo-filters
+ $ cd build/ufo-filters
+ $ cmake <path-to-ufo-core> -DCMAKE_INSTALL_PREFIX=/home/user/tmp/usr
+ $ make && make install
+
+After installation you have to set the typelib and linker path so that
+everything is found at run-time ::
+
+ $ export GI_TYPELIB_PATH=/home/user/tmp/usr/lib/girepository-1.0
+ $ export LD_LIBRARY_PATH=/home/user/tmp/usr/lib:$LD_LIBRARY_PATH
+
+.. note::
+
+ It is strongly discouraged to abuse the library path for permanent
+ usage. Read some good arguments `here`__ and `here`__.
+
+__ http://web.archive.org/web/20060719201954/http://www.visi.com/~barr/ldpath.html
+__ http://linuxmafia.com/faq/Admin/ld-lib-path.html
diff --git a/docs/manual/install/mac.rst b/docs/manual/install/mac.rst
new file mode 100644
index 0000000..3398838
--- /dev/null
+++ b/docs/manual/install/mac.rst
@@ -0,0 +1,69 @@
+.. _installation-mac:
+
+Installation on MacOS X (Lion 10.7)
+===================================
+
+Preface: This information is kindly provided by Andrey Shkarin and Roman
+Shkarin.
+
+.. highlight:: bash
+
+1. Install the MacPorts from http://macports.org
+
+ .. note::
+
+ If you previously installed MacPorts, and it can not be started after
+ latest installation. `Error: port dlopen (...`
+ You must download the tar.gz file and install it using a terminal::
+
+ ./configure
+ make
+ sudo make install
+
+2. Install the necessary packages through macports::
+
+ sudo port install glib2
+ sudo port install gtk2
+ sudo port install json-glib
+
+3. Install CMake from http://cmake.org
+
+4. Make ufo-core
+
+ 1. Got to the directory ufo-core and run::
+
+ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+ cmake .
+
+ 2. Run::
+
+ make
+ sudo make install
+
+ 3. Installation is complete, perhaps the last lines are as follows::
+
+ -- Installing: /usr/local/lib/pkgconfig/ufo.pc
+ CMake Error at src/bindings/cmake_install.cmake:33 (FILE):
+ file INSTALL cannot find
+ "/Users/Andrey/Desktop/ufo-distr/ufo-core/src/bindings/../src/Ufo-0.1.gir".
+ Call Stack (most recent call first):
+ src/cmake_install.cmake:60 (INCLUDE)
+ cmake_install.cmake:32 (INCLUDE)
+ make: *** [install] Error 1
+
+5. Make filters
+
+ 1. Go to ufo-filters directory. Now, since libufo was installed in lib64, we must update the paths to look
+ for shared libraries::
+
+ export DYLD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64
+ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+
+ 2. Run::
+
+ cmake .
+ make
+ sudo make install
+
+6. Build the test project and verify that everything works.
+
diff --git a/docs/manual/json.rst b/docs/manual/json.rst
new file mode 100644
index 0000000..c2c7c1e
--- /dev/null
+++ b/docs/manual/json.rst
@@ -0,0 +1,144 @@
+.. _json-configuration:
+
+.. highlight:: javascript
+
+=========================
+JSON Configuration Format
+=========================
+
+JSON_ is a self-contained, human-readable data-interchange format. It is pure
+Unicode text and language independent. The main structures objects containing
+key/value pairs (hash-tables, dictionaries, associative arrays ...) and ordered
+lists (arrays, vectors, sequences ...) of objects or values. For a complete
+description you may refer to the complete reference at `json.org
+<http://json.org>`_.
+
+The configuration of a filter setup is stored in a JSON-encoded text file with a
+``.json`` suffix. The root object must at least contain a ``nodes`` and an
+``edges`` array ::
+
+ { "nodes": [], "edges": [] }
+
+The root object may also define several ``prop-set`` s for further reference.
+
+
+Nodes array
+===========
+
+The nodes array contains filter objects that are executed on run-time.
+Information how they are connected is provided in the `Edges array`_.
+
+Filter object
+-------------
+
+A filter consists at least of a ``plugin`` key string pointing to the filter
+that is going to be used and a ``name`` string field for unique identification.
+Of course, plugins have to be available as a shared object in UFO's path.
+
+.. highlight:: python
+
+To configure the filter, the ``properties`` field can be used. This is an object
+that maps string keys specifying the actual filter property to the value.
+Therefore, the Python code to set a property ::
+
+ reader = graph.get_filter('reader')
+ reader.set_properties(path='/home/user/data/*.tif', count=5)
+
+.. highlight:: javascript
+
+translates to ::
+
+ { "path": "/home/user/data/*.tif", "count": 5 }
+
+Instead of defining recurring properties for each filter, you can also use
+pre-defined `Property sets`_.
+
+Example nodes array
+-------------------
+
+An example node array looks like this::
+
+ "nodes" : [
+ {
+ "plugin": "reader",
+ "name": "reader",
+ "properties" : { "path": "/home/user/data/*.tif", "count": 5 }
+ },
+ {
+ "plugin": "writer",
+ "name": "writer"
+ }
+ ]
+
+
+Edges array
+===========
+
+The edges array specifies how the nodes in a `Nodes array`_ are connected. Each
+entry is an object that contains two objects ``from`` and ``to``. In both
+objects you have to specify at least the node name with the ``name`` key.
+Furthermore, if there are several inputs or outputs on a node, you have to tell
+which input and output to use with the ``input`` on the ``to`` node and the
+``output`` key on the ``from`` node. If you omit these, they are assumed to be
+0.
+
+To connect the nodes defined in the `Example nodes array`_ all you have to do is ::
+
+ "edges" : [
+ {
+ "from": {"name": "reader"},
+ "to": {"name": "writer", "input": 2}
+ }
+ ]
+
+Note, that the names specify the name of the node, not the plugin.
+
+Property sets
+=============
+
+To avoid to list the same properties for different filters over and over again,
+properties can be pre-defined with a singular top-level ``prop-sets`` object.
+Each key is a name that can be referenced in filter nodes using the
+``prop-refs`` array. The values are ordinary ``property`` mappings::
+
+ {
+ "prop-sets" : {
+ "foo-prop": {
+ "path": "/home/user/path/to/projections/*.tif",
+ "count": 300
+ }
+ },
+ "nodes" : [
+ {
+ "plugin": "reader",
+ "name": "reader",
+ "prop-refs": ["foo-prop"]
+ }
+ ]
+ }
+
+
+Loading and Saving the Graph
+============================
+
+.. highlight:: python
+
+The ``UfoGraph`` class exports the ``ufo_graph_read_from_json`` and
+``ufo_graph_read_save_to_json`` methods which are responsible for loading and
+saving the graph. In Python this would simply be::
+
+ from gi.repository import Ufo
+
+ g1 = Ufo.Graph()
+
+ # set up the filters using graph.get_filter() and filter.connect_to()
+
+ g1.run()
+ g1.save_to_json('graph.json')
+
+ g2 = Ufo.Graph()
+ g2.load_from_json('graph.json')
+ g2.run()
+
+
+.. _JSON: http://json.org
diff --git a/docs/manual/using/background.rst b/docs/manual/using/background.rst
new file mode 100644
index 0000000..7a26716
--- /dev/null
+++ b/docs/manual/using/background.rst
@@ -0,0 +1,86 @@
+.. _using-objects:
+
+====================
+Technical Background
+====================
+
+Relationship between graph and scheduler
+========================================
+
+A ``Ufo.Graph`` represents a network of interconnected filter nodes. New nodes
+can be added and existing node relationships be queried. Also, the graph can be
+serialized as a JSON structure with ``ufo_graph_save_to_json`` and read back
+again with ``ufo_graph_read_from_json``.
+
+The ``Ufo.Scheduler`` on the other hand is an implementation of a strategy *how*
+to execute the filters contained in a graph. Therefore, the scheduler is passed
+a graph object on execution.
+
+Configuration
+=============
+
+There are two different notions of configuration in the Ufo framework: per-node
+configuration and execution configuration. The former is realized with GObject
+properties. In Python, these properties can be set as a named parameter with
+``set_properties`` or assigned to the property as part of the ``props``::
+
+ writer = pm.get_filter('reader')
+
+ writer.props.prefix = 'foo'
+ writer.set_properties(prefix='foo')
+
+The execution configuration is independent of the parameters of the actual
+computation and used to determine environment specific foos. For example, if the
+filters are not installed system wide, there need to be a way to tell the
+framework were these are located. This information is stored in an
+``Ufo.Configuration`` object. Each part of the framework that implements the
+``Ufo.Configurable`` interface accepts such an object at construction time and
+uses necessary information stored within::
+
+ # Lets assume that filters and .cl files are stored in the parent directory.
+ # So we create a new configuration object and set its `paths' property.
+ config = Ufo.Configuration(paths=['..'])
+
+ # The PluginManager is configurable ...
+ pm = Ufo.PluginManager(configuration=config)
+
+ # ... so is the scheduler
+ scheduler = Ufo.Scheduler(configuration=config)
+
+
+Profiling
+=========
+
+Profiling is disabled by default but can be enabled with the ``profile-level``
+property of a configuration object. This property receives values from the
+``UfoProfilerLevel`` flags enum ::
+
+ # track only OpenCL events
+ config = Ufo.Configuration(profile_level=Ufo.ProfilerLevel.OPENCL)
+
+ scheduler = Ufo.Scheduler(configuration=config)
+
+If you do not specify an output file name (``profile_output`` property), the
+profiling information is output to ``stdout``.
+
+The profiling information can be analysed with the ``clprof`` tool, as part of
+the standard distribution::
+
+ $ clprof stats
+ Kernel Submit Delay Exec Delay Kernel Exec Total Exec Queue Dist
+ -------------------------------------------------------------------------------------
+ filter 0.0033 1.0551 0.0491 0.4915 1.0
+ fft_spread 0.0079 1.0265 0.0398 0.3982 1.0
+ backproject_tex 0.0022 0.5808 4.9480 49.4805 1.0
+ fft_pack 0.0034 0.1187 0.0311 0.3113 1.0
+
+The output is the averaged time in milli seconds for submission delay, execution
+delay and kernel execution:
+
+* *Submission delay*: time between calling the kernel and actually submission
+ into the command queue
+* *Execution delay*: time between enqueueing and execution of the kernel
+* *Execution*: time for executing the kernel
+
+Moreover, the total execution time in milli seconds and the kernel distribution
+among the command queues is shown.
diff --git a/docs/manual/using/cluster.rst b/docs/manual/using/cluster.rst
new file mode 100644
index 0000000..66ac63a
--- /dev/null
+++ b/docs/manual/using/cluster.rst
@@ -0,0 +1,23 @@
+.. _using-cluster:
+
+==========================
+Running tasks in a cluster
+==========================
+
+The UFO framework comes with built-in cluster capabilities based on ZeroMQ 3.2.
+Contrary to bulk cluster approaches (e.g. solving large linear systems), UFO
+tries to distribute `streamed` data on a set of multiple machines. On each
+remote slave, ``ufod`` must be started. By default, the server binds to port
+5555 on any available network adapter. To change this, use the ``-l/--listen``
+option::
+
+ $ ufod --listen tcp://ib0:5555
+
+will let ``ufod`` use the first Infiniband-over-IP connection.
+
+On the master host, you pass the remote slave addresses to the scheduler object.
+In Python this would look like this::
+
+ sched = Ufo.Scheduler(remotes=['tcp://foo.bar.org:5555'])
+
+Address are notated according to `ZeroMQ <http://api.zeromq.org/3-2:zmq-tcp>`_.
diff --git a/docs/manual/using/filters.rst b/docs/manual/using/filters.rst
new file mode 100644
index 0000000..57f26b7
--- /dev/null
+++ b/docs/manual/using/filters.rst
@@ -0,0 +1,244 @@
+.. _filters:
+
+=====
+Tasks
+=====
+
+.. default-domain:: c
+
+UFO filters are simple shared objects that expose their ``GType`` and implement
+the :type:`UfoFilter` class.
+
+
+Writing a task in C
+===================
+
+.. highlight:: bash
+
+Writing a new UFO filter is simple and by calling ::
+
+ ./mkfilter.py --name AwesomeFoo --type TYPE
+
+in the ``tools/`` directory, you can avoid writing that tedious GObject boiler
+plate code on your own. The name is a camel-cased version of your new filter.
+Type must be one of
+
+* ``cpu``: For a CPU-based task
+* ``gpu``: For a CPU-based task
+
+You are now left with two files ``ufo-awesome-foo-task.c`` and
+``ufo-awesome-foo-task.h``. If you intend to distribute that filter with the
+main UFO filter distribution, copy these files to ``ufo-filters/src``. If you
+are not depending on any third-party library you can just add the following line
+to the ``CMakeLists.txt`` file::
+
+ set(ufofilter_SRCS
+ ...
+ ufo-awesome-foo-task.c
+ ...)
+
+You can compile this as usual by typing ::
+
+ make
+
+in the CMake build directory of ``ufo-filters``.
+
+
+Initializing filters
+--------------------
+
+.. highlight:: c
+
+Regardless of filter type, the ``ufo_awesome_foo_task_init()`` method is the
+*constructor* of the filter object and the best place to setup all data that
+does not depend on any input data.
+
+The ``ufo__awesome_foo_task_class_init()`` method on the other hand ist the
+*class constructor* that is used to *override* virtual methods by setting
+function pointers in each classes' vtable.
+
+You *must* override the following methods: ``ufo_awesome_task_get_structure``,
+``ufo_awesome_task_setup``, ``ufo_awesome_task_get_requisition`` and
+``ufo_awesome_task_process``.
+
+``get_structure`` is called by the run-time in order to determine how many
+inputs your task expects, which dimensions are allowed on each input and what
+processing mode your task runs ::
+
+ static void
+ ufo_awesome_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+ {
+ *mode = UFO_TASK_MODE_SINGLE;
+ *n_inputs = 1;
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = 2;
+ }
+
+This task expects one two-dimensional input. Be aware, that the callee must
+allocate memory for the ``in_params`` data structure.
+
+``setup`` can be used to initialize data that depends on run-time resources like
+OpenCL contexts etc. This method is called only *once* ::
+
+ static void
+ ufo_awesome_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+ {
+ cl_context context;
+
+ context = ufo_resources_get_context (resources);
+
+ /*
+ Do something with the context like allocating buffers or create
+ kernels.
+ */
+ }
+
+On the other hand, ``get_requisition`` is called on each iteration right before
+``process``. It is used to determine which size an output buffer must have
+depending on the inputs. For this you must fill in the ``requisition`` structure
+correctly. If our output buffer needs to be as big as our input buffer we would
+specify ::
+
+ static void
+ ufo_awesome_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+ {
+ ufo_buffer_get_requisition (inputs[0], requisition);
+ }
+
+Finally, you have to override the ``process`` method. Note, that the function
+signatures differ for GPU and CPU tasks ::
+
+ static gboolean
+ ufo_awesome_task_process (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+ {
+ /* Now we can request cl_mem or float arrays from in and outputs. */
+ cl_command_queue cmd_queue;
+ cl_mem host_in;
+ cl_mem host_out;
+
+ cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+ host_in = ufo_buffer_get_device_array (inputs[0], cmd_queue);
+ host_out = ufo_buffer_get_device_array (output, cmd_queue);
+
+ /* Call a kernel or do other meaningful work. */
+ }
+
+Tasks can and will be copied to speed up the computation on multi-GPU systems.
+Any parameters that are accessible from the outside via a property are
+automatically copied by the run-time system. To copy private data that is only
+visible at the file scope, you have to override the ``UFO_NODE_CLASS`` method
+``copy`` and copy the data yourself. This method is *always* called before
+``setup`` so you can be assured to re-create your private data on the copied
+task.
+
+.. note::
+
+ It is strongly encouraged that you export all your parameters as properties
+ and re-build any internal data structures off of these parameters.
+
+
+Additional source files
+-----------------------
+
+For modularity reasons, you might want to split your filter sources into
+different compilation units. In order to compile and link them against the
+correct library, add the following statements to the ``src/CMakeLists.txt``
+file ::
+
+ set(awesome_foo_misc_SRCS foo.c bar.c baz.c)
+
+in case your filter is still called ``AwesomeFoo``. Notice, that the variable
+name matches the plugin name with underscores between the lower-cased letters.
+
+
+Writing point-based OpenCL filters
+----------------------------------
+
+.. highlight:: c
+
+For point-based image operations it is much faster to use the cl-plugin that
+writing a full-fledged C filter. We create a new file ``simple.cl``, that
+contains a simple kernel that inverts our normalized input (you can silently
+ignore the ``scratch`` parameter for now)::
+
+ __kernel void invert(__global float *data, __local float *scratch)
+ {
+ /* where are we? */
+ int index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ float inverted_value = 1.0f - data[index];
+ data[index] = inverted_value;
+ }
+
+.. highlight:: python
+
+We wire this small kernel into this short Python script::
+
+ from gi.repository import Ufo
+
+ pm = Ufo.PluginManager()
+ reader = pm.get_filter('reader')
+ writer = pm.get_filter('writer')
+
+ # this filter applies the kernel
+ cl = pm.get_filter('opencl')
+ cl.set_properties(file='simple.cl', kernel='invert')
+
+ g = Ufo.Graph()
+ g.connect_filters(reader, cl)
+ g.connect_filters(cl, writer)
+
+ s = Ufo.Scheduler()
+ s.run(g)
+
+For more information on how to write OpenCL kernels, consult the official
+`OpenCL reference pages`__.
+
+__ http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/
+
+
+The GObject property system
+===========================
+
+.. _filters-block:
+
+Wait until a property satisfies a condition
+-------------------------------------------
+
+.. highlight:: c
+
+For some filters it could be important to not only wait until input buffers
+arrive but also properties change their values. For example, the back-projection
+should only start as soon as it is assigned a correct center-of-rotation. To
+implement this, we have to define a condition function that checks if a
+``GValue`` representing the current property satisfies a certain condition ::
+
+ static gboolean is_larger_than_zero(GValue *value, gpointer user_data)
+ {
+ return g_value_get_float(value) > 0.0f;
+ }
+
+As the filter installed the properties it also knows which type it is and which
+``g_value_get_*()`` function to call. Now, we wait until this conditions holds
+using :c:func:`ufo_filter_wait_until` ::
+
+ /* Somewhere in ufo_filter_process() */
+ ufo_filter_wait_until(self, properties[PROP_CENTER_OF_ROTATION],
+ &is_larger_than_zero, NULL);
+
+.. warning::
+
+ :c:func:`ufo_filter_wait_until` might block indefinitely when the
+ condition function never returns ``TRUE``.
+
+.. seealso:: :ref:`faq-synchronize-properties`
diff --git a/docs/manual/using/index.rst b/docs/manual/using/index.rst
new file mode 100644
index 0000000..79ce8c3
--- /dev/null
+++ b/docs/manual/using/index.rst
@@ -0,0 +1,30 @@
+.. _using-ufo:
+
+=========
+Using UFO
+=========
+
+UFO is a framework for high-speed image processing at Synchrotron_ beamlines. It
+facilitates every available hardware device to process tomographic data as fast
+as possible with on-line reconstruction as the ultimate goal.
+
+.. _Synchrotron: http://en.wikipedia.org/wiki/Synchrotron
+
+It is written in C using the GLib_ and GObject_ libraries to provide an
+object-oriented :ref:`API <ufo-api>`.
+
+.. _GLib: http://developer.gnome.org/glib/
+.. _GObject: http://developer.gnome.org/gobject/stable/index.html
+
+After :ref:`installing <installation>` the framework you're ready to build your
+own image processing pipeline or implement a new filter.
+
+
+.. toctree::
+ :maxdepth: 2
+
+ quickstart.rst
+ background.rst
+ cluster.rst
+ filters.rst
+
diff --git a/docs/manual/using/quickstart.rst b/docs/manual/using/quickstart.rst
new file mode 100644
index 0000000..e807c13
--- /dev/null
+++ b/docs/manual/using/quickstart.rst
@@ -0,0 +1,195 @@
+.. _using-hello-world:
+
+=================
+Quick start guide
+=================
+
+There are essentially two ways to specify and execute a graph of tasks. One
+involves writing a :ref:`JSON file <json-configuration>` that is executed by the
+``runjson`` utility, the other way uses the provided language bindings to setup
+the task graph specifically.
+
+
+Using a JSON description
+========================
+
+The custom JSON format, described :ref:`here <json-configuration>`, has the
+advantage to be language-agnostic and portable across different versions of the
+UFO framework. Let's start with a simple example, that computes the
+one-dimensional Fourier-transform on a set of input files::
+
+ {
+ "nodes" : [
+ {
+ "plugin": "reader",
+ "name": "reader",
+ "properties" : { "path": "*.tif" }
+ },
+ {
+ "plugin": "fft",
+ "name": "fft"
+ }
+ {
+ "plugin": "writer",
+ "name": "writer",
+ "properties" : { "prefix": "fft-" }
+ }
+ ],
+ "edges" : [
+ {
+ "from": { "name": "reader" },
+ "to": { "name": "fft" }
+ },
+ {
+ "from": { "name": "fft" },
+ "to": { "name": "writer" }
+ }
+ ]
+ }
+
+Save this to a file named ``fft.json`` and execute it by calling the ``runjson``
+tool::
+
+ $ runjson fft.json
+
+``runjson`` takes two optional parameters. ``-p`` or ``--path`` expects a path
+name to a location where UFO plugins are stored. This can be useful if the
+standard nodes were installed in a user-defined location or third-party nodes
+should be looked up too.
+
+The ``-a`` or ``--address`` parameter expects a ZeroMQ-conform address where a
+``ufod`` server is running. Part of the work is then distributed to that
+machine. For more information, read up on :ref:`clustering <using-cluster>`.
+
+
+C interface
+===========
+
+.. highlight:: c
+
+A simple UFO program written in C that loads the JSON description can look like
+this::
+
+ /* ufo/ufo.h is the only header allowed to be included */
+ #include <ufo/ufo.h>
+
+ int main (void)
+ {
+ UfoTaskGraph *graph;
+ UfoScheduler *scheduler;
+ UfoPluginManager *manager;
+
+ g_type_init (); /* you _must_ call this! */
+
+ graph = ufo_graph_new ();
+ manager = ufo_plugin_manager_new ();
+
+ ufo_task_graph_read_from_json (graph, manager, "hello-world.json", NULL);
+
+ scheduler = ufo_scheduler_new (NULL, NULL);
+ ufo_scheduler_run (scheduler, graph, NULL);
+
+ /* Destroy all objects */
+ g_object_unref (graph);
+ g_object_unref (scheduler);
+ g_object_unref (manager);
+ return 0;
+ }
+
+.. highlight:: bash
+
+You can compile this with::
+
+ $ gcc `pkg-config --cflags --libs ufo` foo.c -o foo
+
+As you can see we simply construct a new ``UfoGraph`` object from a JSON encoded
+:ref:`configuration file <json-configuration>` and execute the computation
+pipeline with a ``UfoScheduler`` object.
+
+.. highlight:: c
+
+Rather than loading the structure from a file, you can also construct it by
+hand::
+
+ int main(void)
+ {
+ UfoGraph *graph;
+ UfoPluginManager *manager;
+ UfoScheduler *scheduler;
+ UfoNode *reader;
+ UfoNode *writer;
+
+ g_type_init (); /* you _must_ call this! */
+
+ graph = ufo_graph_new ();
+ manager = ufo_plugin_manager_new (NULL);
+ scheduler = ufo_scheduler_new (NULL, NULL);
+ reader = ufo_plugin_manager_get_task (manager, "reader", NULL);
+ writer = ufo_plugin_manager_get_task (manager, "writer", NULL);
+
+ g_object_set (G_OBJECT (reader),
+ "path", "/home/user/data/*.tif",
+ "count", 5,
+ NULL);
+
+ ufo_graph_connect_nodes (graph, reader, writer, NULL);
+ ufo_scheduler_run (scheduler, graph, NULL);
+ return 0;
+ }
+
+
+Python Interface
+================
+
+There are no plans to support any languages with manually written language
+bindings. However, UFO is a GObject-based library from which ``gir`` (GObject
+Introspection) files can be generated at build time. Any language that supports
+GObject Introspection and the ``gir``/``typelib`` format is thus able to
+integrate UFO. No manual intervention is need if the GObject Introspection tools
+are found.
+
+Because several languages support GObject Introspection, you have to consult the
+appropriate reference manuals to find out how the GObjects are mapped to their
+language equivalents. Some of the options are
+
+- Python: PyGObject_
+- Javascript: Gjs_ and Seed_
+- Vala has direct support using the ``--pkg`` option
+
+.. _PyGObject: http://live.gnome.org/PyGObject
+.. _Gjs: http://live.gnome.org/Gjs
+.. _Seed: http://live.gnome.org/Seed
+
+A `GNOME wiki page`__ lists all available runtime bindings.
+
+__ http://live.gnome.org/GObjectIntrospection/Users
+
+.. highlight:: python
+
+The simple example from the beginning -- with Python-GObject installed -- would
+look like this::
+
+ from gi.repository import Ufo
+
+ manager = Ufo.PluginManager()
+ graph = Ufo.TaskGraph()
+ scheduler = Ufo.Scheduler()
+
+ graph.read_from_json(manager, "some-graph.json")
+ scheduler.run(graph)
+
+Similarly, constructing the graph by hand maps one-to-one to the Python object
+and keyword system::
+
+ from gi.repository import Ufo
+
+ graph = Ufo.Graph()
+ manager = Ufo.PluginManager()
+ scheduler = Ufo.Scheduler()
+
+ reader = manager.get_task('reader')
+ writer = manager.get_task('writer')
+ reader.set_properties(path='/home/user/data/*.tif', count=5)
+
+ graph.connect_nodes(reader, writer)
+ scheduler.run(graph)
diff --git a/docs/manual/whatsnew/0.1.rst b/docs/manual/whatsnew/0.1.rst
new file mode 100644
index 0000000..7499916
--- /dev/null
+++ b/docs/manual/whatsnew/0.1.rst
@@ -0,0 +1,12 @@
+==========================
+What's New in ufo-core 0.1
+==========================
+
+:Author: Matthias Vogelgesang
+
+Changes from version 0.1.0 to 0.1.1
+===================================
+
+Fixed bugs
+----------
+ - Ticket #55: tests/test-channel blocks indefinitely
diff --git a/docs/manual/whatsnew/0.2.rst b/docs/manual/whatsnew/0.2.rst
new file mode 100644
index 0000000..e6dc9a3
--- /dev/null
+++ b/docs/manual/whatsnew/0.2.rst
@@ -0,0 +1,69 @@
+==========================
+What's New in ufo-core 0.2
+==========================
+
+Major breakage
+==============
+
+- Filters are now prefixed again with ``libfilter`` to allow introspected
+ documentation. Thus, any filter built for 0.1 cannot be used because they are
+ simply not found.
+
+- :c:func:`ufo_plugin_manager_get_filter` received a new third parameter
+ ``error`` that reports errors when opening and loading a UfoFilter from a
+ shared object.
+
+- :c:func:`ufo_resource_manager_add_program` is removed.
+
+- The kernel file name must be passed to :c:func:`ufo_resource_manager_get_kernel`.
+
+- The ``CHECK_ERROR`` macro defined in ``ufo-resource-manager.h`` was renamed to
+ ``CHECK_OPENCL_ERROR`` to better reflect its real purpose.
+
+- The old JSON specification has been changed to reflect the possibilities of
+ the current API. Thus, JSON files that worked under Ufo 0.1 cannot be read
+ with Ufo 0.2.
+
+- Removed the otherwise unused :c:func:`ufo_buffer_get_transfer_time` and
+ replaced this with the more flexible :c:func:`ufo_buffer_get_transfer_timer`.
+
+- Rename :c:func:`ufo_filter_initialize` to
+ :c:func:`ufo_filter_set_plugin_name` that reflects its true meaning.
+
+Scheduling
+----------
+
+A more scheduable way to run filters has been implemented with the virtual
+:c:func:`process_cpu` and :c:func:`process_gpu` methods. Contrary to the old
+way, they act on *one* working set at a time that is passed as an array of
+pointers to :c:type:`UfoBuffer`. Sometimes, a filter needs to setup data
+depending on the input size. For this reason, the virtual method
+:c:func:`initialize` takes a second parameter that is again a list of pointers
+to buffer objects.
+
+Moreover, the :c:type:`UfoScheduler` class has been added that is combining
+the work previously accomplished by :c:func:`ufo_filter_process` and
+:c:func:`ufo_graph_run`. The scheduler orchestrates the filters and
+assigns resources in a meaningful way.
+
+If written in the new kernel style, producer filters must return a boolean flag
+denoting if data was produced or not.
+
+
+General improvements
+====================
+
+- The manual was restructured considerably.
+
+- Saving graphs as JSON files has been added via
+ :c:func:`ufo_graph_save_to_json()`.
+
+- Filters can now wait until their properties satisfy a condition using
+ :c:func:`ufo_filter_wait_until`, see also :ref:`filters-block`.
+
+- A new method :c:func:`ufo_resource_manager_get_kernel_from_source` so that
+ filters can load kernels directly from source.
+
+- Streamlined error handling: Filters should not issue ``g_warnings`` or
+ ``g_errors`` on their own anymore but create an error with ``g_error_new`` and
+ return that.
diff --git a/docs/manual/whatsnew/0.3.rst b/docs/manual/whatsnew/0.3.rst
new file mode 100644
index 0000000..51f3201
--- /dev/null
+++ b/docs/manual/whatsnew/0.3.rst
@@ -0,0 +1,31 @@
+==========================
+What's New in ufo-core 0.3
+==========================
+
+Major breakage
+==============
+
+- A graph is now a simple data structure and not a specific graph of task nodes.
+ This is implemented by a TaskGraph.
+
+- Filters are now called TaskNodes and connected with
+ ``ufo_task_graph_connect_nodes`` and ``ufo_task_graph_connect_nodes_full``
+ respectively.
+
+
+Graph expansion
+===============
+
+With 0.2, Using multiple GPUs was possible by manually splitting paths in the
+graph and assigning GPUs. Now, task graphs are automatically expanded depending
+on the number of available GPUs and remote processing slaves that are started
+with the newly added ``ufod`` server software.
+
+
+Minor improvements
+==================
+
+- A ``deploy.sh`` script has been added for easier deployment of the software
+ stack. This is especially useful to install everything in the home directory
+ of the user, who only needs to setup ``LD_LIBRARY_PATH`` and
+ ``GI_TYPELIB_PATH`` correctly to run the software.
diff --git a/docs/manual/whatsnew/index.rst b/docs/manual/whatsnew/index.rst
new file mode 100644
index 0000000..f02388c
--- /dev/null
+++ b/docs/manual/whatsnew/index.rst
@@ -0,0 +1,15 @@
+.. _whatsnew-index:
+
+======================
+What's New in ufo-core
+======================
+
+The "What's New in ufo-core" series documents the most important changes between
+major versions of the UFO core package.
+
+.. toctree::
+ :maxdepth: 2
+
+ 0.3.rst
+ 0.2.rst
+ 0.1.rst
diff --git a/docs/scangobj.sh.in b/docs/scangobj.sh.in
new file mode 100644
index 0000000..e58f901
--- /dev/null
+++ b/docs/scangobj.sh.in
@@ -0,0 +1 @@
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${CMAKE_CURRENT_BINARY_DIR}" CFLAGS="${GTK_DOC_CFLAGS}" LDFLAGS="${GTK_DOC_LDFLAGS} -L${CMAKE_CURRENT_BINARY_DIR} -lufo" gtkdoc-scangobj --module=Ufo > /dev/null
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644
index 0000000..f93a571
--- /dev/null
+++ b/python/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 2.6)
+
+# --- Find packages and libraries ---------------------------------------------
+find_program(PYTHON "python")
+
+if (PYTHON)
+ option(WITH_PYTHON_TOOLS "Build Python tools module" ON)
+
+ if (WITH_PYTHON_TOOLS)
+ set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
+ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
+ set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/ufotools/__init__.py")
+ set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
+
+ configure_file(${SETUP_PY_IN} ${SETUP_PY})
+
+ add_custom_command(
+ OUTPUT ${OUTPUT}
+ COMMAND ${PYTHON} setup.py build
+ COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT}
+ DEPENDS ${DEPS}
+ COMMENT "Build ufotools"
+ )
+
+ add_custom_target(ufotools ALL DEPENDS ${OUTPUT})
+
+ install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install)")
+ endif()
+endif()
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644
index 0000000..21bd87d
--- /dev/null
+++ b/python/setup.py.in
@@ -0,0 +1,13 @@
+from distutils.core import setup, Extension
+
+if __name__ == '__main__':
+ setup(name='ufotools',
+ version='${PACKAGE_VERSION}',
+ author='Matthias Vogelgesang',
+ author_email='matthias.vogelgesang at kit.edu',
+ url='http://ufo.kit.edu',
+ license='GPL v3',
+ description='ufo extension module',
+ long_description='ufo extension module',
+ package_dir={ '': '${CMAKE_CURRENT_SOURCE_DIR}' },
+ packages=['ufotools'])
diff --git a/python/ufotools/__init__.py b/python/ufotools/__init__.py
new file mode 100644
index 0000000..30ecdf7
--- /dev/null
+++ b/python/ufotools/__init__.py
@@ -0,0 +1,27 @@
+class CallableFilter(object):
+ def __init__(self, gobject, graph):
+ self.gobject = gobject
+ self.graph = graph
+ self.name = gobject.get_plugin_name()
+
+ def __call__(self, *args, **kwargs):
+ n_inputs = self.gobject.get_num_inputs()
+
+ if n_inputs != len(args):
+ raise TypeError("`%s' receives only %i argument(s) but was called with %i parameters" % (self.name, n_inputs, len(args)))
+
+ for i, target in enumerate(args):
+ self.graph.connect_filters_full(target.gobject, 0, self.gobject, i, Ufo.TransferMode.DISTRIBUTE)
+
+ return self
+
+
+class NodeFactory(object):
+ def __init__(self, plugin_manager, graph):
+ self.pm = plugin_manager
+ self.graph = graph
+
+ def get(self, name, **kwargs):
+ gobject = self.pm.get_filter(name)
+ gobject.set_properties(kwargs)
+ return CallableFilter(gobject, graph)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..84736dd
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8)
+
+# configure unit tests
+set(TEST_SRCS
+ test-suite.c
+ #test-buffer.c
+ #test-channel.c
+ test-config.c
+ #test-filter.c
+ #test-filter-direct.c
+ test-graph.c
+ test-profiler.c
+ )
+
+set(SUITE_BIN "test-suite")
+
+option(WITH_TESTS "Build test suite" ON)
+
+if (WITH_TESTS)
+ include_directories(
+ {CMAKE_CURRENT_SOURCE_DIR})
+
+ add_executable(${SUITE_BIN} ${TEST_SRCS})
+
+ target_link_libraries(${SUITE_BIN}
+ ufo
+ ${UFOCORE_DEPS})
+
+ add_test(${SUITE_BIN} ${SUITE_BIN})
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl"
+ "${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl" @ONLY IMMEDIATE)
+endif()
diff --git a/tests/gtester.xsl b/tests/gtester.xsl
new file mode 100644
index 0000000..8aee6a8
--- /dev/null
+++ b/tests/gtester.xsl
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <!-- I can't believe I have to do this -->
+ <!-- Based on this code:
+ http://geekswithblogs.net/Erik/archive/2008/04/01/120915.aspx
+ -->
+ <xsl:template name="strreplace">
+ <xsl:param name="string"/>
+ <xsl:param name="token"/>
+ <xsl:param name="newtoken"/>
+ <xsl:choose>
+ <xsl:when test="contains($string, $token)">
+ <xsl:value-of select="substring-before($string, $token)"/>
+ <xsl:value-of select="$newtoken"/>
+ <xsl:call-template name="strreplace">
+ <xsl:with-param name="string" select="substring-after($string, $token)"/>
+ <xsl:with-param name="token" select="$token"/>
+ <xsl:with-param name="newtoken" select="$newtoken"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="/">
+ <xsl:for-each select="gtester">
+ <testsuite>
+ <!-- currently we do not support different test binaries and only take the path
+ of the first as the testsuite name -->
+ <xsl:attribute name="name">
+ <xsl:value-of select="testbinary[1]/@path"/>
+ </xsl:attribute>
+ <xsl:attribute name="tests">
+ <xsl:value-of select="count(testbinary/testcase[not(@skipped='1')])"/>
+ </xsl:attribute>
+ <xsl:attribute name="time">
+ <xsl:value-of select="sum(testbinary/duration)"/>
+ </xsl:attribute>
+ <xsl:attribute name="failures">
+ <xsl:value-of select="count(testbinary/testcase/status[@result='failed'])"/>
+ </xsl:attribute>
+ <xsl:for-each select="testbinary/testcase[not(@skipped='1')]">
+ <testcase>
+ <xsl:variable name="classname">
+ <xsl:call-template name="strreplace">
+ <xsl:with-param name="string" select="substring-after(@path, '/')"/>
+ <xsl:with-param name="token" select="'/'"/>
+ <xsl:with-param name="newtoken" select="'.'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:attribute name="classname">
+ <xsl:value-of select="$classname"/>
+ </xsl:attribute>
+ <xsl:attribute name="name">g_test</xsl:attribute>
+ <xsl:attribute name="time">
+ <xsl:value-of select="duration"/>
+ </xsl:attribute>
+ <xsl:if test="status[@result = 'failed']">
+ <failure>
+ <xsl:value-of select="error"/>
+ </failure>
+ </xsl:if>
+ </testcase>
+ </xsl:for-each>
+ </testsuite>
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/tests/test-config.c b/tests/test-config.c
new file mode 100644
index 0000000..1f479e8
--- /dev/null
+++ b/tests/test-config.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo.h>
+#include "test-suite.h"
+
+static void
+test_path (void)
+{
+ UfoConfig *config;
+ GObject *object;
+ GValueArray *array;
+ GValue value = {0};
+ const gchar *p1 = "/usr/foo/bar";
+ const gchar *p2 = "/home/user/foo";
+ GList *paths;
+
+ /* Initialize value array with the two static strings */
+ array = g_value_array_new (2);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, p1);
+ g_value_array_append (array, &value);
+
+ g_value_reset (&value);
+ g_value_set_string (&value, p2);
+ g_value_array_append (array, &value);
+
+ /* Create a new object object and see what happens */
+ object = g_object_new (UFO_TYPE_CONFIG, "paths", array, NULL);
+
+ g_value_array_free (array);
+
+ g_object_get (object,
+ "paths", &array,
+ NULL);
+
+ g_assert (array->n_values == 2);
+
+ /* Check that paths match the ones we added */
+ g_assert (g_strcmp0 (p1, g_value_get_string (g_value_array_get_nth (array, 0))) == 0);
+ g_assert (g_strcmp0 (p2, g_value_get_string (g_value_array_get_nth (array, 1))) == 0);
+
+ g_value_array_free (array);
+
+ /* Now check the C API */
+ config = UFO_CONFIG (object);
+ paths = ufo_config_get_paths (config);
+
+ g_assert (paths != NULL);
+ g_assert (g_list_length (paths) >= 2);
+ g_assert (g_strcmp0 (p1, g_list_nth_data (paths, 0)) == 0);
+ g_assert (g_strcmp0 (p2, g_list_nth_data (paths, 1)) == 0);
+
+ g_list_free (paths);
+ g_object_unref (object);
+}
+
+static void
+test_path_not_set (void)
+{
+ UfoConfig *config;
+ GList *paths;
+
+ config = ufo_config_new ();
+ paths = ufo_config_get_paths (config);
+ g_assert (paths != NULL);
+ g_list_free (paths);
+ g_object_unref (config);
+}
+
+void
+test_add_config (void)
+{
+ g_test_add_func("/config/path",
+ test_path);
+
+ /* Check trac ticket #127 */
+ g_test_add_func("/config/path-not-set",
+ test_path_not_set);
+}
diff --git a/tests/test-graph.c b/tests/test-graph.c
new file mode 100644
index 0000000..e9759ec
--- /dev/null
+++ b/tests/test-graph.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo.h>
+#include "test-suite.h"
+
+typedef struct {
+ UfoGraph *graph;
+ UfoGraph *sequence;
+ UfoNode *root;
+ UfoNode *target1;
+ UfoNode *target2;
+} Fixture;
+
+static gpointer FOO_LABEL = GINT_TO_POINTER (0xDEADF00D);
+static gpointer BAR_LABEL = GINT_TO_POINTER (0xF00BA);
+static gpointer BAZ_LABEL = GINT_TO_POINTER (0xBA22BA22);
+
+static void
+fixture_setup (Fixture *fixture, gconstpointer data)
+{
+ fixture->graph = ufo_graph_new ();
+ g_assert (UFO_IS_GRAPH (fixture->graph));
+
+ fixture->sequence = ufo_graph_new ();
+
+ ufo_graph_register_node_type (fixture->graph, UFO_TYPE_NODE);
+ ufo_graph_register_node_type (fixture->sequence, UFO_TYPE_NODE);
+
+ fixture->root = ufo_node_new (FOO_LABEL);
+ fixture->target1 = ufo_node_new (BAR_LABEL);
+ fixture->target2 = ufo_node_new (BAZ_LABEL);
+
+ ufo_graph_connect_nodes (fixture->graph,
+ fixture->root,
+ fixture->target1,
+ FOO_LABEL);
+
+ ufo_graph_connect_nodes (fixture->graph,
+ fixture->root,
+ fixture->target2,
+ BAR_LABEL);
+
+ ufo_graph_connect_nodes (fixture->sequence,
+ fixture->root,
+ fixture->target1,
+ BAR_LABEL);
+
+ ufo_graph_connect_nodes (fixture->sequence,
+ fixture->target1,
+ fixture->target2,
+ FOO_LABEL);
+}
+
+static void
+fixture_teardown (Fixture *fixture, gconstpointer data)
+{
+ g_object_unref (fixture->graph);
+ g_object_unref (fixture->sequence);
+}
+
+static void
+test_connected (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_is_connected (fixture->sequence,
+ fixture->root,
+ fixture->target1));
+ g_assert (ufo_graph_is_connected (fixture->sequence,
+ fixture->target1,
+ fixture->target2));
+ g_assert (!ufo_graph_is_connected (fixture->sequence,
+ fixture->root,
+ fixture->target2));
+ g_assert (!ufo_graph_is_connected (fixture->sequence,
+ fixture->target1,
+ fixture->root));
+ g_assert (!ufo_graph_is_connected (fixture->sequence,
+ fixture->target2,
+ fixture->root));
+ g_assert (!ufo_graph_is_connected (fixture->sequence,
+ fixture->target2,
+ fixture->target1));
+}
+
+static void
+test_get_roots (Fixture *fixture, gconstpointer data)
+{
+ GList *roots;
+
+ roots = ufo_graph_get_roots (fixture->graph);
+ g_assert (g_list_length (roots) == 1);
+ g_assert (g_list_nth_data (roots, 0) == fixture->root);
+ g_list_free (roots);
+}
+
+static void
+test_get_num_nodes (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_get_num_nodes (fixture->graph) == 3);
+ g_assert (ufo_graph_get_num_nodes (fixture->sequence) == 3);
+}
+
+static void
+test_get_num_edges (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_get_num_edges (fixture->graph) == 2);
+ g_assert (ufo_graph_get_num_edges (fixture->sequence) == 2);
+}
+
+static void
+test_get_edges (Fixture *fixture, gconstpointer data)
+{
+ GList *edges;
+ UfoEdge *edge;
+
+ edges = ufo_graph_get_edges (fixture->graph);
+ g_assert (g_list_length (edges) == 2);
+
+ edge = g_list_nth_data (edges, 0);
+ g_assert (edge->source == fixture->root);
+ g_assert (edge->target == fixture->target1 ||
+ edge->target == fixture->target2);
+
+ edge = g_list_nth_data (edges, 1);
+ g_assert (edge->source == fixture->root);
+ g_assert (edge->target == fixture->target1 ||
+ edge->target == fixture->target2);
+
+ g_list_free (edges);
+}
+
+static void
+test_get_successors (Fixture *fixture, gconstpointer data)
+{
+ GList *successors;
+
+ successors = ufo_graph_get_successors (fixture->sequence, fixture->target1);
+ g_assert (g_list_length (successors) == 1);
+ g_assert (g_list_nth_data (successors, 0) == fixture->target2);
+ g_list_free (successors);
+}
+
+static void
+test_get_predecessors (Fixture *fixture, gconstpointer data)
+{
+ GList *predecessors;
+
+ predecessors = ufo_graph_get_predecessors (fixture->sequence, fixture->target2);
+ g_assert (g_list_length (predecessors) == 1);
+ g_assert (g_list_nth_data (predecessors, 0) == fixture->target1);
+ g_list_free (predecessors);
+}
+
+static void
+test_remove_edge (Fixture *fixture, gconstpointer data)
+{
+ GList *successors;
+
+ ufo_graph_remove_edge (fixture->sequence, fixture->target1, fixture->target2);
+ successors = ufo_graph_get_successors (fixture->sequence, fixture->target1);
+ g_assert (successors == NULL);
+ g_assert (g_list_length (successors) == 0);
+ g_list_free (successors);
+ g_assert (ufo_graph_get_num_edges (fixture->sequence) == 1);
+}
+
+static void
+test_get_labels (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_get_edge_label (fixture->graph, fixture->root, fixture->target1) == FOO_LABEL);
+ g_assert (ufo_graph_get_edge_label (fixture->graph, fixture->root, fixture->target2) == BAR_LABEL);
+}
+
+static void
+test_expansion (Fixture *fixture, gconstpointer data)
+{
+ GList *successors;
+ UfoNode *node;
+ GList *path = NULL;
+
+ path = g_list_append (path, fixture->root);
+ path = g_list_append (path, fixture->target1);
+ path = g_list_append (path, fixture->target2);
+
+ ufo_graph_expand (fixture->sequence, path);
+ g_list_free (path);
+
+ successors = ufo_graph_get_successors (fixture->sequence, fixture->root);
+ g_assert (g_list_length (successors) == 2);
+
+ node = UFO_NODE (g_list_nth_data (successors, 0));
+ g_list_free (successors);
+
+ successors = ufo_graph_get_successors (fixture->sequence, node);
+ g_assert (g_list_length (successors) == 1);
+ node = UFO_NODE (g_list_nth_data (successors, 0));
+ g_list_free (successors);
+
+ g_assert (ufo_node_equal (node, fixture->target2));
+}
+
+static gboolean
+always_true (UfoNode *node, gpointer user_data)
+{
+ return TRUE;
+}
+
+static void
+test_get_nodes_filtered (Fixture *fixture, gconstpointer data)
+{
+ GList *nodes;
+
+ nodes = ufo_graph_get_nodes_filtered (fixture->sequence, always_true, NULL);
+ g_assert (g_list_length (nodes) == 3);
+ g_assert (g_list_find (nodes, fixture->root) != NULL);
+ g_assert (g_list_find (nodes, fixture->target1) != NULL);
+ g_assert (g_list_find (nodes, fixture->target2) != NULL);
+ g_list_free (nodes);
+}
+
+void
+test_add_graph (void)
+{
+ g_test_add ("/graph/connected",
+ Fixture, NULL,
+ fixture_setup, test_connected, fixture_teardown);
+
+ g_test_add ("/graph/nodes/number",
+ Fixture, NULL,
+ fixture_setup, test_get_num_nodes, fixture_teardown);
+
+ g_test_add ("/graph/nodes/roots",
+ Fixture, NULL,
+ fixture_setup, test_get_roots, fixture_teardown);
+
+ g_test_add ("/graph/nodes/successors",
+ Fixture, NULL,
+ fixture_setup, test_get_successors, fixture_teardown);
+
+ g_test_add ("/graph/nodes/predecessors",
+ Fixture, NULL,
+ fixture_setup, test_get_predecessors, fixture_teardown);
+
+ g_test_add ("/graph/nodes/filtered",
+ Fixture, NULL,
+ fixture_setup, test_get_nodes_filtered, fixture_teardown);
+
+ g_test_add ("/graph/edges/number",
+ Fixture, NULL,
+ fixture_setup, test_get_num_edges, fixture_teardown);
+
+ g_test_add ("/graph/edges/all",
+ Fixture, NULL,
+ fixture_setup, test_get_edges, fixture_teardown);
+
+ g_test_add ("/graph/edges/remove",
+ Fixture, NULL,
+ fixture_setup, test_remove_edge, fixture_teardown);
+
+ g_test_add ("/graph/labels",
+ Fixture, NULL,
+ fixture_setup, test_get_labels, fixture_teardown);
+
+ g_test_add ("/graph/expansion",
+ Fixture, NULL,
+ fixture_setup, test_expansion, fixture_teardown);
+}
diff --git a/tests/test-profiler.c b/tests/test-profiler.c
new file mode 100644
index 0000000..ce9b4ae
--- /dev/null
+++ b/tests/test-profiler.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <string.h>
+#include <ufo.h>
+#include "test-suite.h"
+
+typedef struct {
+ UfoProfiler *profiler;
+} Fixture;
+
+
+static void
+fixture_setup (Fixture *fixture, gconstpointer data)
+{
+ fixture->profiler = ufo_profiler_new (UFO_PROFILER_LEVEL_OPENCL |
+ UFO_PROFILER_LEVEL_IO);
+ g_assert (UFO_IS_PROFILER (fixture->profiler));
+}
+
+static void
+fixture_teardown (Fixture *fixture, gconstpointer data)
+{
+ g_object_unref (fixture->profiler);
+}
+
+static void
+test_timer_elapsed (Fixture *fixture, gconstpointer data)
+{
+ gulong one_millisecond = G_USEC_PER_SEC / 1000;
+
+ ufo_profiler_start (fixture->profiler,
+ UFO_PROFILER_TIMER_IO);
+
+ g_usleep (one_millisecond);
+
+ ufo_profiler_stop (fixture->profiler,
+ UFO_PROFILER_TIMER_IO);
+
+ g_assert (ufo_profiler_elapsed (fixture->profiler,
+ UFO_PROFILER_TIMER_CPU) <= 0.0);
+
+ g_assert (ufo_profiler_elapsed (fixture->profiler,
+ UFO_PROFILER_TIMER_IO) >= 0.001);
+}
+
+
+void
+test_add_profiler (void)
+{
+ g_test_add ("/timer/elapsed",
+ Fixture,
+ NULL,
+ fixture_setup,
+ test_timer_elapsed,
+ fixture_teardown);
+}
diff --git a/tests/test-suite.c b/tests/test-suite.c
new file mode 100644
index 0000000..d16b214
--- /dev/null
+++ b/tests/test-suite.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib-object.h>
+#include "test-suite.h"
+
+static void
+ignore_log (const gchar *domain,
+ GLogLevelFlags flags,
+ const gchar *message,
+ gpointer data)
+{
+}
+
+int main(int argc, char *argv[])
+{
+ g_type_init();
+ g_test_init(&argc, &argv, NULL);
+ g_test_bug_base("http://ufo.kit.edu/ufo/ticket");
+
+ g_log_set_handler ("Ufo", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, ignore_log, NULL);
+ g_log_set_handler ("ocl", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, ignore_log, NULL);
+
+ test_add_config ();
+ test_add_graph ();
+ test_add_profiler ();
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-suite.h b/tests/test-suite.h
new file mode 100644
index 0000000..02bf8ff
--- /dev/null
+++ b/tests/test-suite.h
@@ -0,0 +1,8 @@
+#ifndef TEST_SUITE_H
+#define TEST_SUITE_H
+
+void test_add_config (void);
+void test_add_graph (void);
+void test_add_profiler (void);
+
+#endif
diff --git a/tests/test.json b/tests/test.json
new file mode 100644
index 0000000..daf9c2a
--- /dev/null
+++ b/tests/test.json
@@ -0,0 +1,24 @@
+{
+ "type" : "sequence",
+ "elements" : [
+ {
+ "type" : "filter",
+ "plugin" : "uca"
+ },
+ {
+ "type" : "filter",
+ "plugin" : "scale",
+ "properties" : {
+ "scale" : 0.5
+ }
+ },
+ {
+ "type" : "filter",
+ "plugin" : "raw",
+ "properties" : {
+ "prefix" : "foo"
+ }
+ }
+ ]
+}
+
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..48af150
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8)
+
+add_executable(runjson runjson.c)
+add_executable(ufod ufod.c)
+
+target_link_libraries(runjson ufo ${UFOCORE_DEPS})
+target_link_libraries(ufod ufo ${UFOCORE_DEPS})
+
+install(TARGETS ufod runjson
+ RUNTIME DESTINATION bin)
+
+install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/clprof
+ DESTINATION bin)
diff --git a/tools/clprof b/tools/clprof
new file mode 100755
index 0000000..7426bc9
--- /dev/null
+++ b/tools/clprof
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+import sys
+import csv
+import logging
+import optparse
+import numpy as np
+
+class UncommentedFile:
+ def __init__(self, f, commentchar='#'):
+ self.f = f
+ self.commentchar = commentchar
+
+ def next(self):
+ line = self.f.next()
+ while line.startswith(self.commentchar):
+ line = self.f.next()
+ return line
+
+ def __iter__(self):
+ return self
+
+
+def _show(plt, kernel_name, data, color):
+ data = data.reshape((-1, 5))
+ data[:,1:] = data[:,1:] * 1e-6
+ row = data[0,:]
+ p = plt.plot([row[3], row[4]], [row[0], row[0]], '%s-' % color, label=kernel_name)
+
+ for row in data[1:,:]:
+ plt.plot([row[3], row[4]], [row[0], row[0]], '%s-' % color)
+
+ return p
+
+
+def _print_stats(kernel, data, queues):
+ data = data.reshape((-1, 5))
+ n_rows = float(data.shape[0])
+
+ data[:,1:] *= 1e-6
+
+ # Get performance numbers in milli seconds
+ submit_delay = data[:,2] - data[:,1]
+ execution_delay = data[:,3] - data[:,2]
+ execution = data[:,4] - data[:,3]
+
+ # Get queue distribution
+ dist = [(data[data[:,0] == q]).shape[0] / n_rows for q in queues]
+ sdist = ':'.join([('%.1f' % q) for q in dist])
+
+ print '%-20s % 12.4f % 12.4f % 12.4f % 12.4f %12s' % (kernel,
+ np.mean(submit_delay),
+ np.mean(execution_delay),
+ np.mean(execution),
+ np.sum(execution),
+ sdist)
+
+def parse_rows(reader):
+ kernels = {}
+ queues = {}
+
+ for row in reader:
+ name = row[0]
+ queue = row[1]
+
+ try:
+ queue_number = queues[queue]
+ except KeyError:
+ queue_number = len(queues)
+ queues[queue] = queue_number
+
+ a = np.array([queue_number] + [float(x) for x in row[2:]])
+
+ try:
+ kernels[name] = np.hstack((kernels[name], a))
+ except KeyError:
+ kernels[name] = a
+
+ return (kernels, queues)
+
+def process_file(reader, options):
+ kernels, queues = parse_rows(reader)
+
+ header = '%-20s %12s %12s %12s %12s %12s' % ('Kernel', 'Submit Delay',
+ 'Exec Delay', 'Kernel Exec', 'Total Exec', 'Queue Dist')
+ print header
+ print '-'*len(header)
+
+ for key in kernels:
+ _print_stats(key, kernels[key], queues.values())
+
+ if hasattr(options, 'enable_plot') and options.enable_plot:
+ colors = ['b', 'r', 'g', 'm']
+
+ for c, key in enumerate(kernels):
+ p = _show(plt, key, kernels[key], colors[c])
+ plt.legend([p], [key], loc=1)
+
+ plt.show()
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage="Usage: %prog [options] FILE")
+
+ try:
+ import matplotlib.pyplot as plt
+
+ parser.add_option('-p', '--plot',
+ action='store_true',
+ dest='enable_plot',
+ help='Plot the traces',
+ default=False)
+ except ImportError:
+ pass
+
+ options, args = parser.parse_args()
+
+ if not args:
+ parser.print_help()
+ sys.exit(0)
+
+ try:
+ with open(args[0]) as f:
+ reader = csv.reader(UncommentedFile(f), delimiter=' ')
+ process_file(reader, options)
+ except IOError:
+ print "Error: Could not read `%s'" % args[0]
diff --git a/tools/deploy.sh b/tools/deploy.sh
new file mode 100755
index 0000000..0527ab4
--- /dev/null
+++ b/tools/deploy.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+#
+# Usage: deploy.sh PREFIX LIBSUFFIX
+
+ZEROMQ_BASE=zeromq-3.2.2
+ZEROMQ_TARBALL=$ZEROMQ_BASE.tar.gz
+ZEROMQ_URL=http://download.zeromq.org/$ZEROMQ_TARBALL
+UFO_URL=http://ufo.kit.edu/git
+
+ROOT=$(pwd)
+PREFIX=$1
+LIBSUFFIX=$2
+
+export LD_LIBRARY_PATH=$PREFIX/lib$LIBSUFFIX
+export PKG_CONFIG_PATH=$LD_LIBRARY_PATH/pkgconfig
+export GI_TYPELIB_PATH=$LD_LIBRARY_PATH/girepository-1.0
+
+function update() {
+ cd $ROOT/$1
+ git pull
+ make || exit 1
+}
+
+function build_package() {
+ pkg-config --cflags --libs libzmq
+ printf "\n** Fetching $1\n"
+ cd $ROOT
+
+ if [ -d "$ROOT/$1" ]; then
+ cd $ROOT/$1
+ git pull
+ else
+ git clone $UFO_URL/$1
+ cd $ROOT/$1
+ fi
+
+ printf "\n** Building $1\n"
+ cd $ROOT/$1
+ cmake . -DCMAKE_INSTALL_PREFIX=$PREFIX -DLIB_SUFFIX=$LIBSUFFIX || exit 1
+ make || exit 1
+ make install
+}
+
+function install_package() {
+ cd $ROOT/$1
+ make install
+}
+
+function build() {
+ if [ ! -f $ROOT/$ZEROMQ_TARBALL ]; then
+ printf "\n** Fetching ZeroMQ\n"
+ wget $ZEROMQ_URL || die "ERROR: Could not fetch ZeroMQ"
+ fi
+
+ printf "\n** Building ZeroMQ\n"
+ tar xfz $ZEROMQ_TARBALL
+ cd $ROOT/$ZEROMQ_BASE
+ ./configure --prefix=$PREFIX --libdir=$LD_LIBRARY_PATH
+ make -j 4
+ make install
+
+ build_package "ufo-core"
+ build_package "oclfft"
+ build_package "ufo-filters"
+
+ # Link the typelib because the girepository framework is not searching
+ # /usr/local on openSUSE systems.
+ if [[ $EUID -eq 0 ]]; then
+ TYPELIB_PATH=$(ls $GI_TYPELIB_PATH/Ufo-*.typelib)
+ TYPELIB=$(basename $TYPELIB_PATH)
+ ln -s $TYPELIB_PATH /usr/lib$LIBSUFFIX/girepository-1.0/$TYPELIB
+ ldconfig
+ fi
+}
+
+if [ "$PREFIX" == "" ]; then
+ PREFIX=$ROOT/usr
+ printf "** Prefix not set, installing into $PREFIX\n"
+fi
+
+if [ "$PREFIX" == "update" ]; then
+ update "ufo-core"
+ update "ufo-filters"
+elif [ "$PREFIX" == "install" ]; then
+ install_package "$ZEROMQ_BASE"
+ install_package "ufo-core"
+ install_package "oclfft"
+ install_package "ufo-filters"
+else
+ build
+fi
diff --git a/tools/leakcheck.sh b/tools/leakcheck.sh
new file mode 100755
index 0000000..bdaed95
--- /dev/null
+++ b/tools/leakcheck.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+OPTS="--tool=memcheck --leak-check=full --show-reachable=yes --leak-resolution=high --num-callers=20"
+
+G_SLICE=always-malloc G_DEBUG=gc-friendly,resident-modules valgrind $OPTS --log-file=vgdump $1
diff --git a/tools/mkfilter.py b/tools/mkfilter.py
new file mode 100755
index 0000000..5258f39
--- /dev/null
+++ b/tools/mkfilter.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+
+"""
+This file generates GObject file templates that a filter author can use, to
+implement their own nodes.
+"""
+
+import sys
+import re
+import string
+import textwrap
+import argparse
+import jinja2
+
+def type_list():
+ return ', '.join(['`' + f + '\'' for f in FILTER_TYPES])
+
+class FilternameAction(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ if not re.match(r"^[A-Z][a-z]([A-Z][a-z0-9]*)*", values):
+ raise argparse.ArgumentTypeError('Name must be a camel-cased C identifier')
+ setattr(namespace, self.dest, values)
+
+
+class TypeAction(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ lower = values.lower()
+ if lower not in ['gpu', 'cpu']:
+ raise argparse.ArgumentTypeError("Type must be either `cpu' or `gpu'")
+ setattr(namespace, self.dest, values)
+
+
+def generate_file(args, env, suffix='h'):
+ camelcased = args.name
+ hyphenated = args.name[0].lower() + args.name[1:]
+
+ for letter in string.ascii_uppercase:
+ hyphenated = hyphenated.replace(letter, "-" + letter.lower())
+
+ underscored = hyphenated.replace('-', '_')
+ uppercased = underscored.upper()
+
+ template = env.get_template('ufo-%s-task.%s.in' % (args.type, suffix))
+ res = template.render(camelcased=camelcased,
+ uppercased=uppercased,
+ hyphenated=hyphenated,
+ underscored=underscored,
+ args=args)
+
+ filename = "ufo-%s-task.%s" % (hyphenated, suffix)
+
+ with open(filename, 'w') as f:
+ f.writelines(res)
+ f.close()
+ print "Wrote %s" % filename
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Generate UfoNode skeletons')
+ parser.add_argument('-n', '--name', required=True, type=str,
+ action=FilternameAction,
+ help='Name of the new filter in CamelCase')
+ parser.add_argument('-t', '--type', type=str, default='cpu',
+ action=TypeAction,
+ help="Either `cpu' or `gpu' (cpu is default)")
+ parser.add_argument('-d', '--disable-comments',
+ action='store_false',
+ help='Do not insert comments into source files')
+
+ try:
+ args = parser.parse_args()
+ except argparse.ArgumentTypeError as err:
+ print err
+ sys.exit(1)
+
+ env = jinja2.Environment(loader=jinja2.PackageLoader('mkfilter', 'templates'))
+
+ generate_file(args, env, 'h')
+ generate_file(args, env, 'c')
+
+ message = "If you are about to write a UFO internal filter, you should copy \
+the generated files into core/filters and adapt the CMakeLists.txt file. You \
+should only add the filter sources to ${ufo_SRCS} if all build dependencies are \
+met for your particular plugin. Good luck!"
+
+ print ""
+ print textwrap.fill(message)
diff --git a/tools/runjson.c b/tools/runjson.c
new file mode 100644
index 0000000..e108437
--- /dev/null
+++ b/tools/runjson.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of runjson.
+ *
+ * runjson is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * runjson is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with runjson. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <ufo/ufo.h>
+
+static void
+handle_error (const gchar *prefix, GError *error, UfoGraph *graph)
+{
+ if (error) {
+ g_warning ("%s: %s", prefix, error->message);
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+}
+
+static GList *
+string_array_to_list (gchar **array)
+{
+ GList *result = NULL;
+
+ if (array == NULL)
+ return NULL;
+
+ for (guint i = 0; array[i] != NULL; i++)
+ result = g_list_append (result, array[i]);
+
+ return result;
+}
+
+static void
+execute_json (const gchar *filename,
+ gchar **paths,
+ gchar **addresses)
+{
+ UfoConfig *config;
+ UfoTaskGraph *task_graph;
+ UfoScheduler *scheduler;
+ UfoPluginManager *manager;
+ GList *path_list = NULL;
+ GList *address_list = NULL;
+ GError *error = NULL;
+
+ config = ufo_config_new ();
+
+ path_list = string_array_to_list (paths);
+ ufo_config_add_paths (config, path_list);
+ g_list_free (path_list);
+
+ manager = ufo_plugin_manager_new (config);
+
+ task_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+ ufo_task_graph_read_from_file (task_graph, manager, filename, &error);
+ handle_error ("Reading JSON", error, UFO_GRAPH (task_graph));
+
+ address_list = string_array_to_list (addresses);
+ scheduler = ufo_scheduler_new (config, address_list);
+ g_list_free (address_list);
+
+ ufo_scheduler_run (scheduler, task_graph, &error);
+ handle_error ("Executing", error, UFO_GRAPH (task_graph));
+
+ g_object_unref (task_graph);
+ g_object_unref (scheduler);
+ g_object_unref (manager);
+ g_object_unref (config);
+}
+
+int main(int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ gchar **paths = NULL;
+ gchar **addresses = NULL;
+ gboolean show_version = FALSE;
+
+ GOptionEntry entries[] = {
+ { "path", 'p', 0, G_OPTION_ARG_STRING_ARRAY, &paths,
+ "Path to node plugins or OpenCL kernels", NULL },
+ { "address", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &addresses,
+ "Address of remote server running `ufod'", NULL },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version,
+ "Show version information", NULL },
+ { NULL }
+ };
+
+ g_type_init();
+
+ context = g_option_context_new ("FILE");
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_print ("Option parsing failed: %s\n", error->message);
+ return 1;
+ }
+
+ if (show_version) {
+ g_print ("runjson %s\n", UFO_VERSION);
+ exit (EXIT_SUCCESS);
+ }
+
+ if (argc < 2) {
+ gchar *help;
+
+ help = g_option_context_get_help (context, TRUE, NULL);
+ g_print ("%s", help);
+ g_free (help);
+ return 1;
+ }
+
+ execute_json (argv[argc-1], paths, addresses);
+
+ g_strfreev (paths);
+ g_strfreev (addresses);
+ g_option_context_free (context);
+
+ return 0;
+}
diff --git a/tools/templates/ufo-cpu-task.c.in b/tools/templates/ufo-cpu-task.c.in
new file mode 100644
index 0000000..1007dd5
--- /dev/null
+++ b/tools/templates/ufo-cpu-task.c.in
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ufo-{{hyphenated}}-task.h"
+
+/**
+ * SECTION:ufo-{{hyphenated}}-task
+ * @Short_description: Write TIFF files
+ * @Title: {{underscored}}
+ *
+ */
+
+struct _Ufo{{camelcased}}TaskPrivate {
+ gboolean foo;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_cpu_task_interface_init (UfoCpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (Ufo{{camelcased}}Task, ufo_{{underscored}}_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init)
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CPU_TASK,
+ ufo_cpu_task_interface_init))
+
+#define UFO_{{uppercased}}_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_TEST,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_{{underscored}}_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_{{uppercased}}_TASK, NULL));
+}
+
+static void
+ufo_{{underscored}}_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_{{underscored}}_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ requisition->n_dims = 0;
+}
+
+static void
+ufo_{{underscored}}_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ *mode = UFO_TASK_MODE_SINGLE;
+ *n_inputs = 1;
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = 2;
+}
+
+static gboolean
+ufo_{{underscored}}_task_process (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ return TRUE;
+}
+
+static void
+ufo_{{underscored}}_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Ufo{{camelcased}}TaskPrivate *priv = UFO_{{uppercased}}_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_TEST:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_{{underscored}}_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Ufo{{camelcased}}TaskPrivate *priv = UFO_{{uppercased}}_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_TEST:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_{{underscored}}_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_{{underscored}}_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_{{underscored}}_task_setup;
+ iface->get_structure = ufo_{{underscored}}_task_get_structure;
+ iface->get_requisition = ufo_{{underscored}}_task_get_requisition;
+}
+
+static void
+ufo_cpu_task_interface_init (UfoCpuTaskIface *iface)
+{
+ iface->process = ufo_{{underscored}}_task_process;
+}
+
+static void
+ufo_{{underscored}}_task_class_init (Ufo{{camelcased}}TaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_{{underscored}}_task_set_property;
+ gobject_class->get_property = ufo_{{underscored}}_task_get_property;
+ gobject_class->finalize = ufo_{{underscored}}_task_finalize;
+
+ properties[PROP_TEST] =
+ g_param_spec_string ("test",
+ "Test property nick",
+ "Test property description blurb",
+ "",
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(Ufo{{camelcased}}TaskPrivate));
+}
+
+static void
+ufo_{{underscored}}_task_init(Ufo{{camelcased}}Task *self)
+{
+ self->priv = UFO_{{uppercased}}_TASK_GET_PRIVATE(self);
+}
diff --git a/tools/templates/ufo-cpu-task.h.in b/tools/templates/ufo-cpu-task.h.in
new file mode 100644
index 0000000..5102ca2
--- /dev/null
+++ b/tools/templates/ufo-cpu-task.h.in
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_{{uppercased}}_TASK_H
+#define __UFO_{{uppercased}}_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_{{uppercased}}_TASK (ufo_{{underscored}}_task_get_type())
+#define UFO_{{uppercased}}_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}Task))
+#define UFO_IS_{{uppercased}}_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_{{uppercased}}_TASK))
+#define UFO_{{uppercased}}_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskClass))
+#define UFO_IS_{{uppercased}}_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_{{uppercased}}_TASK))
+#define UFO_{{uppercased}}_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskClass))
+
+typedef struct _Ufo{{camelcased}}Task Ufo{{camelcased}}Task;
+typedef struct _Ufo{{camelcased}}TaskClass Ufo{{camelcased}}TaskClass;
+typedef struct _Ufo{{camelcased}}TaskPrivate Ufo{{camelcased}}TaskPrivate;
+
+/**
+ * Ufo{{camelcased}}Task:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #Ufo{{camelcased}}Task structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _Ufo{{camelcased}}Task {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ Ufo{{camelcased}}TaskPrivate *priv;
+};
+
+/**
+ * Ufo{{camelcased}}TaskClass:
+ *
+ * #Ufo{{camelcased}}Task class
+ */
+struct _Ufo{{camelcased}}TaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_{{underscored}}_task_new (void);
+GType ufo_{{underscored}}_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/templates/ufo-gpu-task.c.in b/tools/templates/ufo-gpu-task.c.in
new file mode 100644
index 0000000..c5593df
--- /dev/null
+++ b/tools/templates/ufo-gpu-task.c.in
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include "ufo-{{hyphenated}}-task.h"
+
+/**
+ * SECTION:ufo-{{hyphenated}}-task
+ * @Short_description: Write TIFF files
+ * @Title: {{underscored}}
+ *
+ */
+
+struct _Ufo{{camelcased}}TaskPrivate {
+ gboolean foo;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_gpu_task_interface_init (UfoGpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (Ufo{{camelcased}}Task, ufo_{{underscored}}_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init)
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_GPU_TASK,
+ ufo_gpu_task_interface_init))
+
+#define UFO_{{uppercased}}_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskPrivate))
+
+enum {
+ PROP_0,
+ PROP_TEST,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_{{underscored}}_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_{{uppercased}}_TASK, NULL));
+}
+
+static void
+ufo_{{underscored}}_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_{{underscored}}_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ requisition->n_dims = 0;
+}
+
+static void
+ufo_{{underscored}}_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ *mode = UFO_TASK_MODE_SINGLE;
+ *n_inputs = 1;
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = 2;
+}
+
+static gboolean
+ufo_{{underscored}}_task_process (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ return TRUE;
+}
+
+static void
+ufo_{{underscored}}_task_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Ufo{{camelcased}}TaskPrivate *priv = UFO_{{uppercased}}_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_TEST:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_{{underscored}}_task_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ Ufo{{camelcased}}TaskPrivate *priv = UFO_{{uppercased}}_TASK_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_TEST:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_{{underscored}}_task_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_{{underscored}}_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_{{underscored}}_task_setup;
+ iface->get_structure = ufo_{{underscored}}_task_get_structure;
+ iface->get_requisition = ufo_{{underscored}}_task_get_requisition;
+}
+
+static void
+ufo_gpu_task_interface_init (UfoGpuTaskIface *iface)
+{
+ iface->process = ufo_{{underscored}}_task_process;
+}
+
+static void
+ufo_{{underscored}}_task_class_init (Ufo{{camelcased}}TaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_{{underscored}}_task_set_property;
+ gobject_class->get_property = ufo_{{underscored}}_task_get_property;
+ gobject_class->finalize = ufo_{{underscored}}_task_finalize;
+
+ properties[PROP_TEST] =
+ g_param_spec_string ("test",
+ "Test property nick",
+ "Test property description blurb",
+ "",
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_type_class_add_private (gobject_class, sizeof(Ufo{{camelcased}}TaskPrivate));
+}
+
+static void
+ufo_{{underscored}}_task_init(Ufo{{camelcased}}Task *self)
+{
+ self->priv = UFO_{{uppercased}}_TASK_GET_PRIVATE(self);
+}
diff --git a/tools/templates/ufo-gpu-task.h.in b/tools/templates/ufo-gpu-task.h.in
new file mode 100644
index 0000000..5102ca2
--- /dev/null
+++ b/tools/templates/ufo-gpu-task.h.in
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_{{uppercased}}_TASK_H
+#define __UFO_{{uppercased}}_TASK_H
+
+#include <ufo/ufo.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_{{uppercased}}_TASK (ufo_{{underscored}}_task_get_type())
+#define UFO_{{uppercased}}_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}Task))
+#define UFO_IS_{{uppercased}}_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_{{uppercased}}_TASK))
+#define UFO_{{uppercased}}_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskClass))
+#define UFO_IS_{{uppercased}}_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_{{uppercased}}_TASK))
+#define UFO_{{uppercased}}_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_{{uppercased}}_TASK, Ufo{{camelcased}}TaskClass))
+
+typedef struct _Ufo{{camelcased}}Task Ufo{{camelcased}}Task;
+typedef struct _Ufo{{camelcased}}TaskClass Ufo{{camelcased}}TaskClass;
+typedef struct _Ufo{{camelcased}}TaskPrivate Ufo{{camelcased}}TaskPrivate;
+
+/**
+ * Ufo{{camelcased}}Task:
+ *
+ * [ADD DESCRIPTION HERE]. The contents of the #Ufo{{camelcased}}Task structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _Ufo{{camelcased}}Task {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ Ufo{{camelcased}}TaskPrivate *priv;
+};
+
+/**
+ * Ufo{{camelcased}}TaskClass:
+ *
+ * #Ufo{{camelcased}}Task class
+ */
+struct _Ufo{{camelcased}}TaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_{{underscored}}_task_new (void);
+GType ufo_{{underscored}}_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/ufod.c b/tools/ufod.c
new file mode 100644
index 0000000..6caabae
--- /dev/null
+++ b/tools/ufod.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of ufod.
+ *
+ * ufod is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ufod is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with ufod. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <zmq.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ufo/ufo.h>
+
+typedef struct {
+ UfoConfig *config;
+ UfoPluginManager *manager;
+ UfoTaskGraph *task_graph;
+ UfoScheduler *scheduler;
+ gpointer socket;
+ UfoNode *input_task;
+ UfoNode *output_task;
+ UfoBuffer *input;
+} ServerPrivate;
+
+typedef struct {
+ gchar **paths;
+ gchar *addr;
+} Options;
+
+#define CHECK_ZMQ(r) if (r == -1) g_warning ("%s:%i: zmq_error: %s\n", __FILE__, __LINE__, zmq_strerror (errno));
+
+static gpointer run_scheduler (ServerPrivate *priv);
+
+static void
+ufo_msg_send (UfoMessage *msg, gpointer socket, gint flags)
+{
+ zmq_msg_t reply;
+
+ zmq_msg_init_size (&reply, sizeof (UfoMessage));
+ memcpy (zmq_msg_data (&reply), msg, sizeof (UfoMessage));
+ zmq_msg_send (&reply, socket, flags);
+ zmq_msg_close (&reply);
+}
+
+static void
+send_ack (gpointer socket)
+{
+ UfoMessage msg;
+ msg.type = UFO_MESSAGE_ACK;
+ ufo_msg_send (&msg, socket, 0);
+}
+
+static void
+handle_get_num_devices (ServerPrivate *priv)
+{
+ UfoMessage msg;
+ cl_context context;
+
+ context = ufo_scheduler_get_context (priv->scheduler);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetContextInfo (context,
+ CL_CONTEXT_NUM_DEVICES,
+ sizeof (cl_uint),
+ &msg.d.n_devices,
+ NULL));
+
+ ufo_msg_send (&msg, priv->socket, 0);
+}
+
+static UfoNode *
+remove_dummy_if_present (UfoGraph *graph,
+ UfoNode *first)
+{
+ UfoNode *real = first;
+
+ if (UFO_IS_DUMMY_TASK (first)) {
+ UfoNode *dummy;
+ GList *successors;
+
+ dummy = first;
+ successors = ufo_graph_get_successors (graph, dummy);
+ g_assert (g_list_length (successors) == 1);
+ real = UFO_NODE (successors->data);
+ g_list_free (successors);
+ ufo_graph_remove_edge (graph, dummy, real);
+ }
+
+ return real;
+}
+
+static void
+handle_json (ServerPrivate *priv)
+{
+ zmq_msg_t json_msg;
+ gsize size;
+ gchar *json;
+ GList *roots;
+ GList *leaves;
+ UfoNode *first;
+ UfoNode *last;
+ GError *error = NULL;
+
+ zmq_msg_init (&json_msg);
+ size = (gsize) zmq_msg_recv (&json_msg, priv->socket, 0);
+
+ json = g_malloc0 (size + 1);
+ memcpy (json, zmq_msg_data (&json_msg), size);
+ zmq_msg_close (&json_msg);
+
+ /* Setup local task graph */
+ priv->task_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+ ufo_task_graph_read_from_data (priv->task_graph, priv->manager, json, &error);
+
+ if (error != NULL) {
+ g_printerr ("%s\n", error->message);
+ /* Send error to master */
+ return;
+ }
+
+ roots = ufo_graph_get_roots (UFO_GRAPH (priv->task_graph));
+ g_assert (g_list_length (roots) == 1);
+
+ leaves = ufo_graph_get_leaves (UFO_GRAPH (priv->task_graph));
+ g_assert (g_list_length (leaves) == 1);
+
+ first = UFO_NODE (g_list_nth_data (roots, 0));
+ last = UFO_NODE (g_list_nth_data (leaves, 0));
+
+ first = remove_dummy_if_present (UFO_GRAPH (priv->task_graph), first);
+
+ priv->input_task = ufo_input_task_new ();
+ priv->output_task = ufo_output_task_new (2);
+
+ ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
+ priv->input_task, first,
+ GINT_TO_POINTER (0));
+
+ ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
+ last, priv->output_task,
+ GINT_TO_POINTER (0));
+
+ g_thread_create ((GThreadFunc) run_scheduler, priv, FALSE, NULL);
+ g_free (json);
+ send_ack (priv->socket);
+}
+
+static void
+handle_setup (ServerPrivate *priv)
+{
+ g_message ("Setup requested");
+ send_ack (priv->socket);
+}
+
+static void
+handle_get_structure (ServerPrivate *priv)
+{
+ UfoMessage header;
+ UfoInputParam in_param;
+ zmq_msg_t data_msg;
+
+ g_message ("Structure requested");
+ header.type = UFO_MESSAGE_STRUCTURE;
+
+ /* TODO: do not hardcode these */
+ header.d.n_inputs = 1;
+ in_param.n_dims = 2;
+
+ zmq_msg_init_size (&data_msg, sizeof (UfoInputParam));
+ memcpy (zmq_msg_data (&data_msg), &in_param, sizeof (UfoInputParam));
+
+ ufo_msg_send (&header, priv->socket, ZMQ_SNDMORE);
+ zmq_msg_send (&data_msg, priv->socket, 0);
+ zmq_msg_close (&data_msg);
+}
+
+static void
+handle_send_inputs (ServerPrivate *priv)
+{
+ UfoRequisition *requisition;
+ zmq_msg_t requisition_msg;
+ zmq_msg_t data_msg;
+ gpointer context;
+
+ context = ufo_scheduler_get_context (priv->scheduler);
+
+ /* Receive buffer size */
+ zmq_msg_init (&requisition_msg);
+ zmq_msg_recv (&requisition_msg, priv->socket, 0);
+ g_assert (zmq_msg_size (&requisition_msg) >= sizeof (UfoRequisition));
+ requisition = zmq_msg_data (&requisition_msg);
+
+ if (priv->input == NULL) {
+ priv->input = ufo_buffer_new (requisition, context);
+ }
+ else {
+ if (ufo_buffer_cmp_dimensions (priv->input, requisition))
+ ufo_buffer_resize (priv->input, requisition);
+ }
+
+ zmq_msg_close (&requisition_msg);
+
+ /* Receive actual buffer */
+ zmq_msg_init (&data_msg);
+ zmq_msg_recv (&data_msg, priv->socket, 0);
+
+ memcpy (ufo_buffer_get_host_array (priv->input, NULL),
+ zmq_msg_data (&data_msg),
+ ufo_buffer_get_size (priv->input));
+
+ ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task), priv->input);
+ zmq_msg_close (&data_msg);
+
+ send_ack (priv->socket);
+}
+
+static void
+handle_get_requisition (ServerPrivate *priv)
+{
+ UfoRequisition requisition;
+ zmq_msg_t reply_msg;
+
+ /* We need to get the requisition from the last node */
+ g_message ("Requisition requested");
+ ufo_output_task_get_output_requisition (UFO_OUTPUT_TASK (priv->output_task),
+ &requisition);
+
+ zmq_msg_init_size (&reply_msg, sizeof (UfoRequisition));
+ memcpy (zmq_msg_data (&reply_msg), &requisition, sizeof (UfoRequisition));
+ zmq_msg_send (&reply_msg, priv->socket, 0);
+ zmq_msg_close (&reply_msg);
+}
+
+static
+void handle_get_result (ServerPrivate *priv)
+{
+ UfoBuffer *buffer;
+ zmq_msg_t reply_msg;
+ gsize size;
+
+ buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (priv->output_task));
+ size = ufo_buffer_get_size (buffer);
+
+ zmq_msg_init_size (&reply_msg, size);
+ memcpy (zmq_msg_data (&reply_msg), ufo_buffer_get_host_array (buffer, NULL), size);
+ zmq_msg_send (&reply_msg, priv->socket, 0);
+ zmq_msg_close (&reply_msg);
+ ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (priv->output_task), buffer);
+}
+
+static void
+unref_and_free (GObject **object)
+{
+ if (*object) {
+ g_object_unref (*object);
+ *object = NULL;
+ }
+}
+
+static
+void handle_cleanup (ServerPrivate *priv)
+{
+ /*
+ * We send the ACK early on, because we don't want to let the host wait for
+ * actually cleaning up (and waiting some time to unref the input task).
+ */
+ send_ack (priv->socket);
+
+ if (priv->input_task) {
+ ufo_input_task_stop (UFO_INPUT_TASK (priv->input_task));
+
+ ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task),
+ priv->input);
+
+ g_usleep (1.5 * G_USEC_PER_SEC);
+ unref_and_free ((GObject **) &priv->input_task);
+ unref_and_free ((GObject **) &priv->input);
+ }
+
+ unref_and_free ((GObject **) &priv->output_task);
+ unref_and_free ((GObject **) &priv->task_graph);
+}
+
+static gpointer
+run_scheduler (ServerPrivate *priv)
+{
+ g_message ("Start scheduler");
+ ufo_scheduler_run (priv->scheduler, priv->task_graph, NULL);
+
+ g_message ("Done");
+ g_object_unref (priv->scheduler);
+
+ priv->scheduler = ufo_scheduler_new (priv->config, NULL);
+ return NULL;
+}
+
+static Options *
+opts_parse (gint *argc, gchar ***argv)
+{
+ GOptionContext *context;
+ Options *opts;
+ gboolean show_version = FALSE;
+ GError *error = NULL;
+
+ opts = g_new0 (Options, 1);
+
+ GOptionEntry entries[] = {
+ { "listen", 'l', 0, G_OPTION_ARG_STRING, &opts->addr,
+ "Address to listen on (see http://api.zeromq.org/3-2:zmq-tcp)", NULL },
+ { "path", 'p', 0, G_OPTION_ARG_STRING_ARRAY, &opts->paths,
+ "Path to node plugins or OpenCL kernels", NULL },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &show_version,
+ "Show version information", NULL },
+ { NULL }
+ };
+
+ context = g_option_context_new ("FILE");
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ if (!g_option_context_parse (context, argc, argv, &error)) {
+ g_print ("Option parsing failed: %s\n", error->message);
+ g_free (opts);
+ return NULL;
+ }
+
+ if (show_version) {
+ g_print ("ufod %s\n", UFO_VERSION);
+ exit (EXIT_SUCCESS);
+ }
+
+ if (opts->addr == NULL)
+ opts->addr = g_strdup ("tcp://*:5555");
+
+ g_option_context_free (context);
+
+ return opts;
+}
+
+static UfoConfig *
+opts_new_config (Options *opts)
+{
+ UfoConfig *config;
+ GList *paths = NULL;
+
+ config = ufo_config_new ();
+
+ if (opts->paths != NULL) {
+ for (guint i = 0; opts->paths[i] != NULL; i++)
+ paths = g_list_append (paths, opts->paths[i]);
+
+ ufo_config_add_paths (config, paths);
+ g_list_free (paths);
+ }
+
+ return config;
+}
+
+static void
+opts_free (Options *opts)
+{
+ g_strfreev (opts->paths);
+ g_free (opts->addr);
+ g_free (opts);
+}
+
+int
+main (int argc, char * argv[])
+{
+ gpointer context;
+ Options *opts;
+ ServerPrivate priv;
+
+ g_type_init ();
+ g_thread_init (NULL);
+
+ if ((opts = opts_parse (&argc, &argv)) == NULL)
+ return 1;
+
+ memset (&priv, 0, sizeof (ServerPrivate));
+
+ priv.config = opts_new_config (opts);
+ priv.manager = ufo_plugin_manager_new (priv.config);
+ priv.scheduler = ufo_scheduler_new (priv.config, NULL);
+
+ /* start zmq service */
+ context = zmq_ctx_new ();
+ priv.socket = zmq_socket (context, ZMQ_REP);
+ zmq_bind (priv.socket, opts->addr);
+
+ g_print ("ufod %s - waiting for requests ...\n", UFO_VERSION);
+
+ while (1) {
+ zmq_msg_t request;
+
+ zmq_msg_init (&request);
+ zmq_msg_recv (&request, priv.socket, 0);
+
+ if (zmq_msg_size (&request) < sizeof (UfoMessage)) {
+ g_warning ("Message is smaller than expected\n");
+ send_ack (priv.socket);
+ }
+ else {
+ UfoMessage *msg;
+
+ msg = (UfoMessage *) zmq_msg_data (&request);
+
+ switch (msg->type) {
+ case UFO_MESSAGE_GET_NUM_DEVICES:
+ handle_get_num_devices (&priv);
+ break;
+ case UFO_MESSAGE_TASK_JSON:
+ handle_json (&priv);
+ break;
+ case UFO_MESSAGE_SETUP:
+ handle_setup (&priv);
+ break;
+ case UFO_MESSAGE_GET_STRUCTURE:
+ handle_get_structure (&priv);
+ break;
+ case UFO_MESSAGE_SEND_INPUTS:
+ handle_send_inputs (&priv);
+ break;
+ case UFO_MESSAGE_GET_REQUISITION:
+ handle_get_requisition (&priv);
+ break;
+ case UFO_MESSAGE_GET_RESULT:
+ handle_get_result (&priv);
+ break;
+ case UFO_MESSAGE_CLEANUP:
+ handle_cleanup (&priv);
+ break;
+ default:
+ g_print ("unhandled case\n");
+ }
+ }
+
+ zmq_msg_close (&request);
+ }
+
+ g_object_unref (priv.task_graph);
+ g_object_unref (priv.config);
+ g_object_unref (priv.manager);
+ g_object_unref (priv.scheduler);
+
+ zmq_close (priv.socket);
+ zmq_ctx_destroy (context);
+
+ opts_free (opts);
+
+ return 0;
+}
diff --git a/ufo/CMakeLists.txt b/ufo/CMakeLists.txt
new file mode 100644
index 0000000..6dc6dee
--- /dev/null
+++ b/ufo/CMakeLists.txt
@@ -0,0 +1,271 @@
+cmake_minimum_required(VERSION 2.6)
+
+# --- Set sources -------------------------------------------------------------
+set(ufocore_SRCS
+ ufo-arch-graph.c
+ ufo-buffer.c
+ ufo-configurable.c
+ ufo-config.c
+ ufo-cpu-node.c
+ ufo-cpu-task-iface.c
+ ufo-dummy-task.c
+ ufo-gpu-node.c
+ ufo-gpu-task-iface.c
+ ufo-graph.c
+ ufo-group.c
+ ufo-input-task.c
+ ufo-node.c
+ ufo-output-task.c
+ ufo-plugin-manager.c
+ ufo-profiler.c
+ ufo-remote-node.c
+ ufo-remote-task.c
+ ufo-resources.c
+ ufo-scheduler.c
+ ufo-task-iface.c
+ ufo-task-graph.c
+ ufo-task-node.c
+ )
+
+set(ufocore_HDRS
+ ufo-arch-graph.h
+ ufo-buffer.h
+ ufo-configurable.h
+ ufo-config.h
+ ufo-cpu-node.h
+ ufo-cpu-task-iface.h
+ ufo-dummy-task.h
+ ufo-gpu-node.h
+ ufo-gpu-task-iface.h
+ ufo-graph.h
+ ufo-group.h
+ ufo-input-task.h
+ ufo-node.h
+ ufo-output-task.h
+ ufo-plugin-manager.h
+ ufo-profiler.h
+ ufo-remote-node.h
+ ufo-remote-task.h
+ ufo-resources.h
+ ufo-scheduler.h
+ ufo-task-iface.h
+ ufo-task-graph.h
+ ufo-task-node.h
+ )
+
+
+# --- Find packages and libraries ---------------------------------------------
+find_program(INTROSPECTION_SCANNER "g-ir-scanner")
+find_program(INTROSPECTION_COMPILER "g-ir-compiler")
+find_program(GLIB2_MKENUMS glib-mkenums REQUIRED)
+
+# --- Add enum generation targets ---------------------------------------------
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ COMMAND ${GLIB2_MKENUMS}
+ ARGS
+ --template ufo-enums.h.template
+ ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${ufocore_HDRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.h.template
+)
+
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
+ COMMAND ${GLIB2_MKENUMS}
+ ARGS
+ --template ufo-enums.c.template
+ ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${ufocore_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.c.template
+)
+
+# --- Target ------------------------------------------------------------------
+get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+
+set(LIBDIR "lib${LIB_SUFFIX}")
+set(INCLUDEDIR "include/ufo")
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+add_definitions(-DUFO_COMPILATION)
+
+if(CMAKE_BUILD_TYPE MATCHES "Release")
+ add_definitions(-DG_DISABLE_ASSERT)
+endif()
+
+add_library(ufo SHARED
+ ${ufocore_SRCS}
+ ${ufocore_NODOC_SRCS}
+ ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c)
+
+set_target_properties(ufo PROPERTIES
+ VERSION ${PACKAGE_VERSION}
+ SOVERSION ${UFO_SO_VERSION})
+
+target_link_libraries(ufo ${UFOCORE_DEPS})
+
+install(TARGETS ufo
+ ARCHIVE DESTINATION ${LIBDIR}
+ LIBRARY DESTINATION ${LIBDIR})
+
+install(FILES ${ufocore_HDRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo.h
+ ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ DESTINATION ${INCLUDEDIR})
+
+
+# --- pkg-config --------------------------------------------------------------
+set(UFO_PKG_PREFIX "${CMAKE_INSTALL_PREFIX}")
+set(UFO_PKG_EXEC_PREFIX "${UFO_PKG_PREFIX}/bin")
+set(UFO_PKG_INCLUDEDIR "${UFO_PKG_PREFIX}/include")
+set(UFO_PKG_GIRDIR "${UFO_PKG_PREFIX}/share/gir-1.0")
+set(UFO_PKG_LIBDIR "${UFO_PKG_PREFIX}/${LIBDIR}")
+set(UFO_PKG_TYPELIBDIR "${UFO_PKG_PREFIX}/${LIBDIR}/girepository-1.0")
+
+# FIXME: inside the ufo.pc.in we should set the lib names that we found out, not
+# hard coded values
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ufo.pc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ufo.pc" @ONLY IMMEDIATE)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ufo.pc
+ DESTINATION ${LIBDIR}/pkgconfig)
+
+
+# --- Introspection files -----------------------------------------------------
+if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER)
+ option(WITH_GIR "Build introspection files" ON)
+
+ if (WITH_GIR)
+ set(GIR_PREFIX "Ufo-${UFO_GIR_VERSION}")
+ set(GIR_XML "${GIR_PREFIX}.gir")
+ set(GIR_TYPELIB "${GIR_PREFIX}.typelib")
+ set(_gir_input)
+
+ foreach(_src ${ufocore_SRCS} ${ufocore_HDRS})
+ list(APPEND _gir_input "${CMAKE_CURRENT_SOURCE_DIR}/${_src}")
+ endforeach()
+
+ add_custom_command(OUTPUT ${GIR_XML}
+ COMMAND ${INTROSPECTION_SCANNER}
+ --namespace=Ufo
+ --nsversion=${UFO_GIR_VERSION}
+ --library=ufo
+ --no-libtool
+ --include=GObject-2.0
+ --include=GModule-2.0
+ --include=GLib-2.0
+ -I${OPENCL_INCLUDE_DIRS}
+ -I${CMAKE_CURRENT_SOURCE_DIR}/..
+ -DUFO_COMPILATION
+ --output ${GIR_XML}
+ --warn-all
+ ${_gir_input} > /dev/null
+ DEPENDS ${ufocore_SRCS}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ add_custom_command(OUTPUT ${GIR_TYPELIB}
+ COMMAND ${INTROSPECTION_COMPILER}
+ -o ${GIR_TYPELIB}
+ ${GIR_XML}
+ DEPENDS ${GIR_XML}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ add_custom_target(gir ALL DEPENDS ${GIR_XML} ${GIR_TYPELIB})
+ add_dependencies(gir ufo)
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_XML}
+ DESTINATION share/gir-1.0)
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB}
+ DESTINATION ${LIBDIR}/girepository-1.0)
+ endif()
+endif()
+
+
+# --- Generate config.h -------------------------------------------------------
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+
+# --- Build API reference -----------------------------------------------------
+pkg_check_modules(GTK_DOC gtk-doc)
+if(GTK_DOC_FOUND)
+ option(WITH_GTK_DOC "Build API reference" ON)
+ if (WITH_GTK_DOC)
+ set(docs_dir "${CMAKE_CURRENT_BINARY_DIR}/../docs")
+ set(docs_out "${docs_dir}/reference")
+ set(_xml_doc_input)
+
+ # Create xml entries for Ufo-docs.xml.in
+ foreach(_src ${ufocore_SRCS})
+ string(REPLACE ".c" ".xml" _xml_doc ${_src})
+ list(APPEND _xml_doc_input "<xi:include href=\"xml/${_xml_doc}\"/>")
+ endforeach()
+
+ string(REPLACE ";" "\n" _xml_doc_input ${_xml_doc_input})
+
+ get_directory_property(_current_include_dirs INCLUDE_DIRECTORIES)
+ set(GTK_DOC_CFLAGS)
+ foreach(_incl ${_current_include_dirs})
+ set(GTK_DOC_CFLAGS "-I${_incl} ${GTK_DOC_CFLAGS}")
+ endforeach()
+
+ set(GTK_DOC_LDFLAGS)
+ foreach(_lib ${UFOCORE_DEPS})
+ if (NOT ${_lib} MATCHES "^[/]")
+ set(GTK_DOC_LDFLAGS "-l${_lib} ${GTK_DOC_LDFLAGS}")
+ endif()
+ endforeach()
+
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../docs/Ufo-docs.xml.in" "${docs_out}/Ufo-docs.xml")
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../docs/scangobj.sh.in" "${docs_out}/scangobj.sh")
+
+ set(reference_files
+ "${docs_out}/index.html"
+ "${docs_out}/UfoScheduler.html"
+ "${docs_out}/style.css"
+ "${docs_out}/Ufo.devhelp2"
+ "${docs_out}/home.png"
+ "${docs_out}/left.png"
+ "${docs_out}/right.png"
+ "${docs_out}/up.png")
+
+ find_program(GTK_DOC_SCAN gtkdoc-scan REQUIRED)
+ find_program(GTK_DOC_SCANGOBJ gtkdoc-scangobj REQUIRED)
+ find_program(GTK_DOC_MKDB gtkdoc-mkdb REQUIRED)
+ find_program(GTK_DOC_MKHTML gtkdoc-mkhtml REQUIRED)
+
+ add_custom_command(OUTPUT ${docs_out}/Ufo-decl.txt
+ COMMAND ${GTK_DOC_SCAN}
+ --module=Ufo
+ --source-dir=${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${ufocore_SRCS}
+ WORKING_DIRECTORY ${docs_out})
+
+ add_custom_command(OUTPUT ${docs_out}/Ufo.args
+ COMMAND sh scangobj.sh
+ DEPENDS ${ufocore_SRCS} ${docs_out}/Ufo-decl.txt
+ WORKING_DIRECTORY ${docs_out})
+
+ add_custom_command(OUTPUT ${docs_out}/sgml.stamp
+ COMMAND ${GTK_DOC_MKDB}
+ --module=Ufo
+ --source-dir=${CMAKE_CURRENT_SOURCE_DIR}
+ --sgml-mode
+ --output-format=xml
+ DEPENDS ${docs_out}/Ufo.args ${docs_out}/Ufo-sections.txt ${ufocore_SRCS}
+ WORKING_DIRECTORY ${docs_out})
+
+ add_custom_command(OUTPUT ${docs_dir}/html.stamp
+ COMMAND ${GTK_DOC_MKHTML}
+ Ufo
+ ${docs_out}/Ufo-docs.xml
+ DEPENDS ${docs_out}/sgml.stamp
+ WORKING_DIRECTORY ${docs_out})
+
+ add_custom_target(reference ALL DEPENDS ${docs_dir}/html.stamp)
+
+ install(FILES ${reference_files} DESTINATION share/gtk-doc/html/Ufo)
+ endif()
+endif(GTK_DOC_FOUND)
diff --git a/ufo/Ufo.types b/ufo/Ufo.types
new file mode 100644
index 0000000..e69de29
diff --git a/ufo/config.h.in b/ufo/config.h.in
new file mode 100644
index 0000000..a3cada3
--- /dev/null
+++ b/ufo/config.h.in
@@ -0,0 +1,3 @@
+#cmakedefine WITH_PROFILING 1
+#define UFO_PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/${LIBDIR}/ufo"
+#define UFO_VERSION "${PACKAGE_VERSION}"
diff --git a/ufo/ufo-arch-graph.c b/ufo/ufo-arch-graph.c
new file mode 100644
index 0000000..9e44f1f
--- /dev/null
+++ b/ufo/ufo-arch-graph.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE
+#include <sys/sysinfo.h>
+#include <sched.h>
+#include <zmq.h>
+#include <ufo/ufo-arch-graph.h>
+#include <ufo/ufo-cpu-node.h>
+#include <ufo/ufo-gpu-node.h>
+#include <ufo/ufo-remote-node.h>
+
+/**
+ * SECTION:ufo-arch-graph
+ * @Short_description: Describe and hold #UfoGpuNode, #UfoCpuNode and
+ * #UfoRemoteNode
+ * @Title: UfoArchGraph
+ */
+
+G_DEFINE_TYPE (UfoArchGraph, ufo_arch_graph, UFO_TYPE_GRAPH)
+
+#define UFO_ARCH_GRAPH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ARCH_GRAPH, UfoArchGraphPrivate))
+
+struct _UfoArchGraphPrivate {
+ UfoResources *resources;
+ gpointer zmq_context;
+ gpointer ocl_context;
+ UfoNode **cpu_nodes;
+ UfoNode **gpu_nodes;
+ UfoNode **remote_nodes;
+ guint n_cpus;
+ guint n_gpus;
+ guint n_remotes;
+};
+
+/**
+ * ufo_arch_graph_new:
+ * @resources: An initialized #UfoResources object
+ * @remote_addresses: (element-type utf8): (allow-none): A #GList containing
+ * address strings.
+ *
+ * Returns: A new #UfoArchGraph.
+ */
+UfoGraph *
+ufo_arch_graph_new (UfoResources *resources,
+ GList *remote_addresses)
+{
+ UfoArchGraph *graph;
+ UfoArchGraphPrivate *priv;
+ GList *cmd_queues;
+ cpu_set_t mask;
+
+ graph = UFO_ARCH_GRAPH (g_object_new (UFO_TYPE_ARCH_GRAPH, NULL));
+ priv = graph->priv;
+
+ g_object_ref (resources);
+ priv->resources = resources;
+ priv->ocl_context = ufo_resources_get_context (resources);
+
+ /* Create CPU nodes */
+ priv->n_cpus = (guint) get_nprocs ();
+ priv->cpu_nodes = g_new0 (UfoNode *, priv->n_cpus);
+
+ for (guint i = 0; i < priv->n_cpus; i++) {
+ CPU_ZERO (&mask);
+ CPU_SET (i, &mask);
+ priv->cpu_nodes[i] = ufo_cpu_node_new (&mask);
+ }
+
+ /* Create GPU nodes, each one is associated with its own command queue. */
+ cmd_queues = ufo_resources_get_cmd_queues (resources);
+ priv->n_gpus = g_list_length (cmd_queues);
+ priv->gpu_nodes = g_new0 (UfoNode *, priv->n_gpus);
+
+ for (guint i = 0; i < priv->n_gpus; i++) {
+ priv->gpu_nodes[i] = ufo_gpu_node_new (g_list_nth_data (cmd_queues, i));
+ }
+
+ /* Create remote nodes */
+ priv->n_remotes = g_list_length (remote_addresses);
+
+ if (priv->n_remotes > 0) {
+ priv->zmq_context = zmq_ctx_new ();
+ priv->remote_nodes = g_new0 (UfoNode *, priv->n_remotes);
+
+ for (guint i = 0; i < priv->n_remotes; i++) {
+ priv->remote_nodes[i] = ufo_remote_node_new (priv->zmq_context,
+ (gchar *) g_list_nth_data (remote_addresses, i));
+ }
+ }
+
+ /*
+ * Connect all CPUs to all GPUs. In the future this is the place for a
+ * NUMA-specific mapping.
+ */
+ for (guint i = 0; i < priv->n_cpus; i++) {
+ for (guint j = 0; j < priv->n_gpus; j++) {
+ ufo_graph_connect_nodes (UFO_GRAPH (graph),
+ priv->cpu_nodes[i],
+ priv->gpu_nodes[j],
+ NULL);
+ }
+
+ for (guint j = 0; j < priv->n_remotes; j++) {
+ ufo_graph_connect_nodes (UFO_GRAPH (graph),
+ priv->cpu_nodes[i],
+ priv->remote_nodes[j],
+ NULL);
+ }
+ }
+
+ g_list_free (cmd_queues);
+ return UFO_GRAPH (graph);
+}
+
+/**
+ * ufo_arch_graph_get_num_cpus:
+ * @graph: A #UfoArchGraph object
+ *
+ * Returns: Number of CPU nodes in @graph.
+ */
+guint
+ufo_arch_graph_get_num_cpus (UfoArchGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_ARCH_GRAPH (graph), 0);
+ return graph->priv->n_cpus;
+}
+
+/**
+ * ufo_arch_graph_get_num_gpus:
+ * @graph: A #UfoArchGraph object
+ *
+ * Returns: Number of GPU nodes in @graph.
+ */
+guint
+ufo_arch_graph_get_num_gpus (UfoArchGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_ARCH_GRAPH (graph), 0);
+ return graph->priv->n_gpus;
+}
+
+/**
+ * ufo_arch_graph_get_num_remotes:
+ * @graph: A #UfoArchGraph object
+ *
+ * Returns: Number of remote nodes in @graph.
+ */
+guint
+ufo_arch_graph_get_num_remotes (UfoArchGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_ARCH_GRAPH (graph), 0);
+ return graph->priv->n_remotes;
+}
+
+static gboolean
+is_gpu_node (UfoNode *node, gpointer user_data)
+{
+ return UFO_IS_GPU_NODE (node);
+}
+
+/**
+ * ufo_arch_graph_get_gpu_nodes:
+ * @graph: A #UfoArchGraph
+ *
+ * Returns: (element-type UfoGpuNode) (transfer container): A list of
+ * #UfoGpuNode elements in @graph.
+ */
+GList *
+ufo_arch_graph_get_gpu_nodes (UfoArchGraph *graph)
+{
+ return ufo_graph_get_nodes_filtered (UFO_GRAPH (graph),
+ is_gpu_node,
+ NULL);
+}
+
+static gboolean
+is_remote_node (UfoNode *node, gpointer user_data)
+{
+ return UFO_IS_REMOTE_NODE (node);
+}
+
+/**
+ * ufo_arch_graph_get_remote_nodes:
+ * @graph: A #UfoArchGraph
+ *
+ * Returns: (element-type UfoGpuNode) (transfer container): A list of
+ * #UfoRemoteNode elements in @graph.
+ */
+GList *
+ufo_arch_graph_get_remote_nodes (UfoArchGraph *graph)
+{
+ return ufo_graph_get_nodes_filtered (UFO_GRAPH (graph),
+ is_remote_node,
+ NULL);
+}
+
+static void
+unref_node_array (UfoNode **array,
+ guint n_nodes)
+{
+ for (guint i = 0; i < n_nodes; i++) {
+ if (array[i] != NULL) {
+ g_object_unref (array[i]);
+ array[i] = NULL;
+ }
+ }
+}
+
+static void
+ufo_arch_graph_dispose (GObject *object)
+{
+ UfoArchGraphPrivate *priv;
+
+ priv = UFO_ARCH_GRAPH_GET_PRIVATE (object);
+
+ unref_node_array (priv->cpu_nodes, priv->n_cpus);
+ unref_node_array (priv->gpu_nodes, priv->n_gpus);
+ unref_node_array (priv->remote_nodes, priv->n_remotes);
+
+ if (priv->resources != NULL) {
+ g_object_unref (priv->resources);
+ priv->resources = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_arch_graph_parent_class)->dispose (object);
+}
+
+static void
+ufo_arch_graph_finalize (GObject *object)
+{
+ UfoArchGraphPrivate *priv;
+
+ priv = UFO_ARCH_GRAPH_GET_PRIVATE (object);
+
+ if (priv->zmq_context != NULL) {
+ g_debug ("Destroy zmq_context=%p", priv->zmq_context);
+ zmq_ctx_destroy (priv->zmq_context);
+ priv->zmq_context = NULL;
+ }
+
+ g_free (priv->cpu_nodes);
+ g_free (priv->gpu_nodes);
+ g_free (priv->remote_nodes);
+
+ priv->cpu_nodes = NULL;
+ priv->gpu_nodes = NULL;
+ priv->remote_nodes = NULL;
+
+ G_OBJECT_CLASS (ufo_arch_graph_parent_class)->finalize (object);
+}
+
+static void
+ufo_arch_graph_class_init (UfoArchGraphClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->dispose = ufo_arch_graph_dispose;
+ oclass->finalize = ufo_arch_graph_finalize;
+
+ g_type_class_add_private(klass, sizeof(UfoArchGraphPrivate));
+}
+
+static void
+ufo_arch_graph_init (UfoArchGraph *self)
+{
+ UfoArchGraphPrivate *priv;
+ self->priv = priv = UFO_ARCH_GRAPH_GET_PRIVATE (self);
+
+ priv->cpu_nodes = NULL;
+ priv->gpu_nodes = NULL;
+ priv->remote_nodes = NULL;
+
+ ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_CPU_NODE);
+ ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_GPU_NODE);
+ ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_REMOTE_NODE);
+}
diff --git a/ufo/ufo-arch-graph.h b/ufo/ufo-arch-graph.h
new file mode 100644
index 0000000..9c81e19
--- /dev/null
+++ b/ufo/ufo-arch-graph.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_ARCH_GRAPH_H
+#define __UFO_ARCH_GRAPH_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-graph.h>
+#include <ufo/ufo-resources.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_ARCH_GRAPH (ufo_arch_graph_get_type())
+#define UFO_ARCH_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_ARCH_GRAPH, UfoArchGraph))
+#define UFO_IS_ARCH_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_ARCH_GRAPH))
+#define UFO_ARCH_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_ARCH_GRAPH, UfoArchGraphClass))
+#define UFO_IS_ARCH_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_ARCH_GRAPH))
+#define UFO_ARCH_GRAPH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_ARCH_GRAPH, UfoArchGraphClass))
+
+typedef struct _UfoArchGraph UfoArchGraph;
+typedef struct _UfoArchGraphClass UfoArchGraphClass;
+typedef struct _UfoArchGraphPrivate UfoArchGraphPrivate;
+
+/**
+ * UfoArchGraph:
+ *
+ * Graph structure that describes the relation between hardware nodes. The
+ * contents of the #UfoArchGraph structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UfoArchGraph {
+ /*< private >*/
+ UfoGraph parent_instance;
+
+ UfoArchGraphPrivate *priv;
+};
+
+/**
+ * UfoArchGraphClass:
+ *
+ * #UfoArchGraph class
+ */
+struct _UfoArchGraphClass {
+ /*< private >*/
+ UfoGraphClass parent_class;
+};
+
+UfoGraph *ufo_arch_graph_new (UfoResources *resources,
+ GList *remote_addresses);
+guint ufo_arch_graph_get_num_cpus (UfoArchGraph *graph);
+guint ufo_arch_graph_get_num_gpus (UfoArchGraph *graph);
+guint ufo_arch_graph_get_num_remotes (UfoArchGraph *graph);
+GList *ufo_arch_graph_get_gpu_nodes (UfoArchGraph *graph);
+GList *ufo_arch_graph_get_remote_nodes (UfoArchGraph *graph);
+GType ufo_arch_graph_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-buffer.c b/ufo/ufo-buffer.c
new file mode 100644
index 0000000..cf97967
--- /dev/null
+++ b/ufo/ufo-buffer.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-resources.h>
+
+/**
+ * SECTION:ufo-buffer
+ * @Short_description: Represents n-dimensional data
+ * @Title: UfoBuffer
+ */
+
+G_DEFINE_TYPE(UfoBuffer, ufo_buffer, G_TYPE_OBJECT)
+
+#define UFO_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_BUFFER, UfoBufferPrivate))
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_STRUCTURE,
+ N_PROPERTIES
+};
+
+typedef struct {
+ guint num_dims;
+ gfloat *data;
+ gsize dim_size[UFO_BUFFER_MAX_NDIMS];
+} nd_array;
+
+struct _UfoBufferPrivate {
+ nd_array host_array;
+ cl_mem device_array;
+ cl_context context;
+ cl_command_queue last_queue;
+ gsize size; /**< size of buffer in bytes */
+ UfoMemLocation location;
+ GTimer *timer;
+};
+
+static void
+alloc_mem (UfoBufferPrivate *priv,
+ UfoRequisition *requisition)
+{
+ cl_int err;
+
+ if (priv->host_array.data != NULL)
+ g_free (priv->host_array.data);
+
+ if (priv->device_array != NULL)
+ clReleaseMemObject (priv->device_array);
+
+ priv->size = sizeof(gfloat);
+ priv->host_array.num_dims = requisition->n_dims;
+
+ for (guint i = 0; i < requisition->n_dims; i++) {
+ priv->host_array.dim_size[i] = requisition->dims[i];
+ priv->size *= requisition->dims[i];
+ }
+
+ priv->host_array.data = g_malloc0 (priv->size);
+ priv->device_array = clCreateBuffer (priv->context,
+ CL_MEM_READ_WRITE, /* XXX: we _should_ evaluate USE_HOST_PTR */
+ priv->size,
+ NULL,
+ &err);
+ UFO_RESOURCES_CHECK_CLERR (err);
+ priv->location = UFO_LOCATION_HOST;
+}
+
+/**
+ * ufo_buffer_new:
+ * @requisition: (in): size requisition
+ * @context: (in): cl_context to use for creating the device array
+ *
+ * Create a new #UfoBuffer.
+ *
+ * Return value: A new #UfoBuffer with the given dimensions.
+ */
+UfoBuffer *
+ufo_buffer_new (UfoRequisition *requisition,
+ gpointer context)
+{
+ UfoBuffer *buffer;
+
+ g_return_val_if_fail ((requisition->n_dims <= UFO_BUFFER_MAX_NDIMS), NULL);
+ buffer = UFO_BUFFER (g_object_new (UFO_TYPE_BUFFER, NULL));
+ buffer->priv->context = context;
+
+ alloc_mem (buffer->priv, requisition);
+ return buffer;
+}
+
+/**
+ * ufo_buffer_get_size:
+ * @buffer: A #UfoBuffer
+ *
+ * Get the number of bytes of raw data that is managed by the @buffer.
+ *
+ * Returns: The size of @buffer's data.
+ */
+gsize
+ufo_buffer_get_size (UfoBuffer *buffer)
+{
+ g_return_val_if_fail (UFO_IS_BUFFER (buffer), 0);
+ return buffer->priv->size;
+}
+
+static void
+copy_host_to_host (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv)
+{
+ g_memmove (dst_priv->host_array.data,
+ src_priv->host_array.data,
+ src_priv->size);
+}
+
+static void
+copy_device_to_device (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv)
+{
+ cl_event event;
+ cl_int errcode;
+ cl_command_queue cmd_queue;
+
+ cmd_queue = src_priv->last_queue != NULL ? src_priv->last_queue : dst_priv->last_queue;
+ g_assert (cmd_queue != NULL);
+
+ errcode = clEnqueueCopyBuffer (cmd_queue,
+ src_priv->device_array,
+ dst_priv->device_array,
+ 0, 0, /* offsets */
+ src_priv->size,
+ 0, NULL, &event);
+
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event));
+}
+
+static void
+ufo_buffer_to_host (UfoBuffer *buffer, gpointer cmd_queue)
+{
+ UfoBufferPrivate *priv;
+ cl_int cl_err;
+ cl_command_queue queue;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ priv = buffer->priv;
+
+ queue = cmd_queue == NULL ? priv->last_queue : cmd_queue;
+ priv->last_queue = cmd_queue;
+
+ if (priv->location == UFO_LOCATION_HOST)
+ return;
+
+ cl_err = clEnqueueReadBuffer (queue,
+ priv->device_array,
+ CL_TRUE,
+ 0, priv->size,
+ priv->host_array.data,
+ 0, NULL, NULL);
+
+ priv->location = UFO_LOCATION_HOST;
+ UFO_RESOURCES_CHECK_CLERR (cl_err);
+}
+
+static void
+ufo_buffer_to_device (UfoBuffer *buffer, gpointer cmd_queue)
+{
+ UfoBufferPrivate *priv;
+ cl_int cl_err;
+ cl_command_queue queue;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ priv = buffer->priv;
+
+ queue = cmd_queue == NULL ? priv->last_queue : cmd_queue;
+ priv->last_queue = cmd_queue;
+ g_assert (cmd_queue);
+
+ if (priv->location == UFO_LOCATION_DEVICE)
+ return;
+
+ cl_err = clEnqueueWriteBuffer ((cl_command_queue) queue,
+ priv->device_array,
+ CL_TRUE,
+ 0, priv->size,
+ priv->host_array.data,
+ 0, NULL, NULL);
+
+ priv->location = UFO_LOCATION_DEVICE;
+ UFO_RESOURCES_CHECK_CLERR (cl_err);
+}
+
+/**
+ * ufo_buffer_copy:
+ * @src: Source #UfoBuffer
+ * @dst: Destination #UfoBuffer
+ *
+ * Copy contents of @src to @dst. The final memory location is determined by the
+ * destination buffer.
+ */
+void
+ufo_buffer_copy (UfoBuffer *src, UfoBuffer *dst)
+{
+ UfoBufferPrivate *spriv;
+ UfoBufferPrivate *dpriv;
+
+ g_return_if_fail (UFO_IS_BUFFER (src) && UFO_IS_BUFFER (dst));
+ g_return_if_fail (src->priv->size == dst->priv->size);
+
+ spriv = src->priv;
+ dpriv = dst->priv;
+
+ if (spriv->location == dpriv->location) {
+ switch (spriv->location) {
+ case UFO_LOCATION_HOST:
+ copy_host_to_host (spriv, dpriv);
+ break;
+ case UFO_LOCATION_DEVICE:
+ copy_device_to_device (spriv, dpriv);
+ break;
+ default:
+ g_warning ("oops, we should not copy invalid data");
+ }
+ }
+ else {
+ cl_command_queue cmd_queue;
+
+ cmd_queue = spriv->last_queue != NULL ? spriv->last_queue : dpriv->last_queue;
+
+ if (cmd_queue == NULL || dpriv->location == UFO_LOCATION_HOST) {
+ ufo_buffer_to_host (src, cmd_queue);
+ copy_host_to_host (spriv, dpriv);
+ }
+ else {
+ ufo_buffer_to_device (src, cmd_queue);
+ copy_device_to_device (spriv, dpriv);
+ }
+ }
+}
+
+/**
+ * ufo_buffer_dup:
+ * @buffer: A #UfoBuffer
+ *
+ * Create a new buffer with the same requisition as @buffer. Note, that this is
+ * not a copy of @buffer!
+ *
+ * Returns: (transfer full): A #UfoBuffer with the same size as @buffer.
+ */
+UfoBuffer *
+ufo_buffer_dup (UfoBuffer *buffer)
+{
+ UfoBuffer *copy;
+ UfoRequisition requisition;
+
+ ufo_buffer_get_requisition (buffer, &requisition);
+ copy = ufo_buffer_new (&requisition, buffer->priv->context);
+ return copy;
+}
+
+/**
+ * ufo_buffer_resize:
+ * @buffer: A #UfoBuffer
+ * @requisition: A #UfoRequisition structure
+ *
+ * Resize an existing buffer. If the new requisition has the same size as
+ * before, resizing is a no-op.
+ *
+ * Since: 0.2
+ */
+void
+ufo_buffer_resize (UfoBuffer *buffer,
+ UfoRequisition *requisition)
+{
+ UfoBufferPrivate *priv;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+
+ priv = UFO_BUFFER_GET_PRIVATE (buffer);
+
+ if (priv->host_array.data != NULL) {
+ g_free (priv->host_array.data);
+ priv->host_array.data = NULL;
+ }
+
+ if (priv->device_array != NULL) {
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_array));
+ priv->device_array = NULL;
+ }
+
+ alloc_mem (priv, requisition);
+}
+
+/**
+ * ufo_buffer_cmp_dimensions:
+ * @buffer: A #UfoBuffer
+ * @requisition: #UfoRequisition
+ *
+ * Compare the size of @buffer with a given @requisition.
+ *
+ * Returns: value < 0, 0 or > 0 if requisition is smaller, equal or larger.
+ */
+gint
+ufo_buffer_cmp_dimensions (UfoBuffer *buffer,
+ UfoRequisition *requisition)
+{
+ gint result;
+ g_return_val_if_fail (UFO_IS_BUFFER(buffer), FALSE);
+
+ result = 0;
+
+ for (guint i = 0; i < buffer->priv->host_array.num_dims; i++) {
+ gint req_dim = (gint) requisition->dims[i];
+ gint host_dim = (gint) buffer->priv->host_array.dim_size[i];
+ result += req_dim - host_dim;
+ }
+
+ return result;
+}
+
+/**
+ * ufo_buffer_get_requisition:
+ * @buffer: A #UfoBuffer
+ * @requisition: (out): A location to store the requisition of @buffer
+ *
+ * Return the size of @buffer.
+ */
+void
+ufo_buffer_get_requisition (UfoBuffer *buffer,
+ UfoRequisition *requisition)
+{
+ UfoBufferPrivate *priv;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer) && (requisition != NULL));
+ priv = buffer->priv;
+ requisition->n_dims = priv->host_array.num_dims;
+
+ for (guint i = 0; i < priv->host_array.num_dims; i++)
+ requisition->dims[i] = priv->host_array.dim_size[i];
+}
+
+/**
+ * ufo_buffer_get_host_array:
+ * @buffer: A #UfoBuffer.
+ * @cmd_queue: (allow-none): A cl_command_queue object or %NULL.
+ *
+ * Returns a flat C-array containing the raw float data.
+ *
+ * Returns: Float array.
+ */
+gfloat *
+ufo_buffer_get_host_array (UfoBuffer *buffer, gpointer cmd_queue)
+{
+ g_return_val_if_fail (UFO_IS_BUFFER (buffer), NULL);
+ ufo_buffer_to_host (buffer, cmd_queue);
+ return buffer->priv->host_array.data;
+}
+
+/**
+ * ufo_buffer_get_device_array:
+ * @buffer: A #UfoBuffer.
+ * @cmd_queue: (allow-none): A cl_command_queue object or %NULL.
+ *
+ * Return the current cl_mem object of @buffer. If the data is not yet in device
+ * memory, it is transfered via @cmd_queue to the object. If @cmd_queue is %NULL
+ * @cmd_queue, the last used command queue is used.
+ *
+ * Returns: (transfer none): A cl_mem object associated with @buffer.
+ */
+gpointer
+ufo_buffer_get_device_array (UfoBuffer *buffer, gpointer cmd_queue)
+{
+ g_return_val_if_fail (UFO_IS_BUFFER (buffer), NULL);
+ ufo_buffer_to_device (buffer, cmd_queue);
+ return buffer->priv->device_array;
+}
+
+/**
+ * ufo_buffer_discard_location:
+ * @buffer: A #UfoBuffer
+ * @location: Location to discard
+ *
+ * Discard @location and use "other" location without copying to it first.
+ */
+void
+ufo_buffer_discard_location (UfoBuffer *buffer,
+ UfoMemLocation location)
+{
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ buffer->priv->location = location == UFO_LOCATION_HOST ? UFO_LOCATION_DEVICE : UFO_LOCATION_HOST;
+}
+
+/**
+ * ufo_buffer_convert:
+ * @buffer: A #UfoBuffer
+ * @depth: Source bit depth of host data
+ *
+ * Convert host data according to its @depth to the internal 32-bit floating
+ * point representation.
+ */
+void
+ufo_buffer_convert (UfoBuffer *buffer,
+ UfoBufferDepth depth)
+{
+ UfoBufferPrivate *priv;
+ gint n_pixels;
+ gfloat *dst;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ priv = buffer->priv;
+ n_pixels = (gint) (priv->size / 4);
+ dst = priv->host_array.data;
+
+ /* To save a memory allocation and several copies, we process data from back
+ * to front. This is possible if src bit depth is at most half as wide as
+ * the 32-bit target buffer. The processor cache should not be a
+ * problem. */
+ if (depth == UFO_BUFFER_DEPTH_8U) {
+ guint8 *src = (guint8 *) priv->host_array.data;
+
+ for (gint i = (n_pixels - 1); i >= 0; i--)
+ dst[i] = ((gfloat) src[i]);
+ }
+ else if (depth == UFO_BUFFER_DEPTH_16U) {
+ guint16 *src = (guint16 *) priv->host_array.data;
+
+ for (gint i = (n_pixels - 1); i >= 0; i--)
+ dst[i] = ((gfloat) src[i]);
+ }
+}
+
+/**
+ * ufo_buffer_param_spec:
+ * @name: canonical name of the property specified
+ * @nick: nick name for the property specified
+ * @blurb: description of the property specified
+ * @default_value: default value for the property specified
+ * @flags: flags for the property specified
+ *
+ * Creates a new #UfoBufferParamSpec instance specifying a #UFO_TYPE_BUFFER
+ * property.
+ *
+ * Returns: (transfer none): a newly created parameter specification
+ *
+ * @see g_param_spec_internal() for details on property names.
+ */
+GParamSpec *
+ufo_buffer_param_spec(const gchar *name, const gchar *nick, const gchar *blurb, UfoBuffer *default_value, GParamFlags flags)
+{
+ UfoBufferParamSpec *bspec;
+
+ bspec = g_param_spec_internal(UFO_TYPE_PARAM_BUFFER,
+ name, nick, blurb, flags);
+
+ return G_PARAM_SPEC(bspec);
+}
+
+static void
+ufo_buffer_finalize (GObject *gobject)
+{
+ UfoBuffer *buffer = UFO_BUFFER (gobject);
+ UfoBufferPrivate *priv = UFO_BUFFER_GET_PRIVATE (buffer);
+
+ g_free (priv->host_array.data);
+ priv->host_array.data = NULL;
+
+ if (priv->device_array != NULL) {
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_array));
+ priv->device_array = NULL;
+ }
+
+ if (priv->timer != NULL) {
+ g_timer_destroy (priv->timer);
+ priv->timer = NULL;
+ }
+
+ G_OBJECT_CLASS(ufo_buffer_parent_class)->finalize(gobject);
+}
+
+static void
+ufo_buffer_class_init (UfoBufferClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->finalize = ufo_buffer_finalize;
+
+ g_type_class_add_private(klass, sizeof(UfoBufferPrivate));
+}
+
+static void
+ufo_buffer_init (UfoBuffer *buffer)
+{
+ UfoBufferPrivate *priv;
+ buffer->priv = priv = UFO_BUFFER_GET_PRIVATE(buffer);
+ priv->last_queue = NULL;
+ priv->device_array = NULL;
+ priv->host_array.data = NULL;
+ priv->host_array.num_dims = 0;
+ priv->timer = g_timer_new ();
+ g_timer_stop (priv->timer);
+}
+
+static void
+ufo_buffer_param_init (GParamSpec *pspec)
+{
+ UfoBufferParamSpec *bspec = UFO_BUFFER_PARAM_SPEC(pspec);
+
+ bspec->default_value = NULL;
+}
+
+static void
+ufo_buffer_param_set_default (GParamSpec *pspec, GValue *value)
+{
+ UfoBufferParamSpec *bspec = UFO_BUFFER_PARAM_SPEC(pspec);
+
+ bspec->default_value = NULL;
+ g_value_unset(value);
+}
+
+GType
+ufo_buffer_param_get_type()
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ GParamSpecTypeInfo pspec_info = {
+ sizeof(UfoBufferParamSpec), /* instance_size */
+ 16, /* n_preallocs */
+ ufo_buffer_param_init, /* instance_init */
+ 0, /* value_type */
+ NULL, /* finalize */
+ ufo_buffer_param_set_default, /* value_set_default */
+ NULL, /* value_validate */
+ NULL, /* values_cmp */
+ };
+ pspec_info.value_type = UFO_TYPE_BUFFER;
+ type = g_param_type_register_static(g_intern_static_string("UfoBufferParam"), &pspec_info);
+ g_assert(type == UFO_TYPE_PARAM_BUFFER);
+ }
+
+ return type;
+}
diff --git a/ufo/ufo-buffer.h b/ufo/ufo-buffer.h
new file mode 100644
index 0000000..de6c0f6
--- /dev/null
+++ b/ufo/ufo-buffer.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_BUFFER_H
+#define __UFO_BUFFER_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_BUFFER (ufo_buffer_get_type())
+#define UFO_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_BUFFER, UfoBuffer))
+#define UFO_IS_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_BUFFER))
+#define UFO_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_BUFFER, UfoBufferClass))
+#define UFO_IS_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_BUFFER))
+#define UFO_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_BUFFER, UfoBufferClass))
+
+#define UFO_TYPE_PARAM_BUFFER (ufo_buffer_param_get_type())
+#define UFO_IS_PARAM_SPEC_BUFFER(pspec) (G_TYPE_CHECK_INSTANCE_TYPE((pspec), UFO_TYPE_PARAM_BUFFER))
+#define UFO_BUFFER_PARAM_SPEC(pspec) (G_TYPE_CHECK_INSTANCE_CAST((pspec), UFO_TYPE_PARAM_BUFFER, UfoBufferParamSpec))
+
+/**
+ * UfoMemLocation:
+ * @UFO_LOCATION_INVALID: Memory is neither valid on host nor on device.
+ * @UFO_LOCATION_HOST: Memory is valid on host memory.
+ * @UFO_LOCATION_DEVICE: Memory is valid on device memory.
+ *
+ * Memory locations of a #UfoBuffer.
+ */
+typedef enum {
+ UFO_LOCATION_INVALID,
+ UFO_LOCATION_HOST,
+ UFO_LOCATION_DEVICE
+} UfoMemLocation;
+
+typedef struct _UfoBuffer UfoBuffer;
+typedef struct _UfoBufferClass UfoBufferClass;
+typedef struct _UfoBufferPrivate UfoBufferPrivate;
+typedef struct _UfoBufferParamSpec UfoBufferParamSpec;
+typedef struct _UfoRequisition UfoRequisition;
+
+/**
+ * UfoBuffer:
+ *
+ * Represents n-dimensional data. The contents of the #UfoBuffer structure are
+ * private and should only be accessed via the provided API.
+ */
+struct _UfoBuffer {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoBufferPrivate *priv;
+};
+
+/**
+ * UFO_BUFFER_MAX_NDIMS:
+ *
+ * Maximum number of allowed dimensions. This is a pre-processor macro instead
+ * of const variable because of <ulink
+ * url="http://c-faq.com/ansi/constasconst.html">C constraints</ulink>.
+ */
+#define UFO_BUFFER_MAX_NDIMS 8
+
+/**
+ * UfoBufferClass:
+ *
+ * #UfoBuffer class
+ */
+struct _UfoBufferClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+/**
+ * UfoRequisition:
+ * @n_dims: Number of dimensions
+ * @dims: Size of dimension
+ *
+ * Used to specify buffer size requirements.
+ */
+struct _UfoRequisition {
+ guint n_dims;
+ gsize dims[UFO_BUFFER_MAX_NDIMS];
+};
+
+/**
+ * UfoBufferParamSpec:
+ *
+ * UfoBufferParamSpec class
+ */
+struct _UfoBufferParamSpec {
+ /*< private >*/
+ GParamSpec parent_instance;
+
+ UfoBuffer *default_value;
+};
+
+/**
+ * UfoBufferDepth:
+ * @UFO_BUFFER_DEPTH_8U: 8 bit unsigned
+ * @UFO_BUFFER_DEPTH_16U: 16 bit unsigned
+ *
+ * Source depth of data as used in ufo_buffer_convert().
+ */
+typedef enum {
+ UFO_BUFFER_DEPTH_8U,
+ UFO_BUFFER_DEPTH_16U
+} UfoBufferDepth;
+
+UfoBuffer* ufo_buffer_new (UfoRequisition *requisition,
+ gpointer context);
+void ufo_buffer_resize (UfoBuffer *buffer,
+ UfoRequisition *requisition);
+gint ufo_buffer_cmp_dimensions (UfoBuffer *buffer,
+ UfoRequisition *requisition);
+void ufo_buffer_get_requisition (UfoBuffer *buffer,
+ UfoRequisition *requisition);
+gsize ufo_buffer_get_size (UfoBuffer *buffer);
+void ufo_buffer_copy (UfoBuffer *src,
+ UfoBuffer *dst);
+UfoBuffer *ufo_buffer_dup (UfoBuffer *buffer);
+gfloat* ufo_buffer_get_host_array (UfoBuffer *buffer,
+ gpointer cmd_queue);
+gpointer ufo_buffer_get_device_array (UfoBuffer *buffer,
+ gpointer cmd_queue);
+void ufo_buffer_discard_location (UfoBuffer *buffer,
+ UfoMemLocation location);
+void ufo_buffer_convert (UfoBuffer *buffer,
+ UfoBufferDepth depth);
+GType ufo_buffer_get_type (void);
+
+GParamSpec* ufo_buffer_param_spec (const gchar* name,
+ const gchar* nick,
+ const gchar* blurb,
+ UfoBuffer* default_value,
+ GParamFlags flags);
+GType ufo_buffer_param_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-config.c b/ufo/ufo-config.c
new file mode 100644
index 0000000..afebe19
--- /dev/null
+++ b/ufo/ufo-config.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-profiler.h>
+#include <ufo/ufo-enums.h>
+
+/**
+ * SECTION:ufo-config
+ * @Short_description: Access run-time specific settings
+ * @Title: UfoConfig
+ *
+ * A #UfoConfig object is used to keep settings that affect the run-time
+ * rather than the parameters of the filter graph. Each object that implements
+ * the #UfoConfigurable interface can receive a #UfoConfig object and use
+ * the information stored in it.
+ */
+
+G_DEFINE_TYPE(UfoConfig, ufo_config, G_TYPE_OBJECT)
+
+#define UFO_CONFIG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_CONFIG, UfoConfigPrivate))
+
+static void add_path (const gchar *path, UfoConfigPrivate *priv);
+
+enum {
+ PROP_0,
+ PROP_PATHS,
+ PROP_PROFILE_LEVEL,
+ PROP_PROFILE_OUTPUT_PREFIX,
+ N_PROPERTIES
+};
+
+struct _UfoConfigPrivate {
+ GValueArray *path_array;
+ UfoProfilerLevel profile_level;
+ gchar *profile_output_prefix;
+};
+
+static GParamSpec *config_properties[N_PROPERTIES] = { NULL, };
+
+/**
+ * ufo_config_new:
+ *
+ * Create a config object.
+ *
+ * Return value: A new config object.
+ */
+UfoConfig *
+ufo_config_new (void)
+{
+ return UFO_CONFIG (g_object_new (UFO_TYPE_CONFIG, NULL));
+}
+
+/**
+ * ufo_config_get_paths:
+ * @config: A #UfoConfig object
+ *
+ * Get an array of path strings.
+ *
+ * Returns: (transfer full) (element-type utf8): A list of strings containing
+ * file system paths. Use g_list_free() to free it.
+ */
+GList *
+ufo_config_get_paths (UfoConfig *config)
+{
+ GValueArray *path_array;
+ GList *paths;
+ guint n_paths;
+
+ g_return_val_if_fail (UFO_IS_CONFIG (config), NULL);
+
+ path_array = config->priv->path_array;
+ n_paths = path_array->n_values;
+ paths = NULL;
+
+ for (guint i = 0; i < n_paths; i++) {
+ paths = g_list_append (paths,
+ g_strdup (g_value_get_string (g_value_array_get_nth (path_array, i))));
+ }
+
+ return paths;
+}
+
+/**
+ * ufo_config_add_paths:
+ * @config: A #UfoConfig object
+ * @paths: (element-type utf8): List of strings
+ *
+ * Add @paths to the list of search paths for plugins and OpenCL kernel files.
+ */
+void
+ufo_config_add_paths (UfoConfig *config,
+ GList *paths)
+{
+ g_return_if_fail (UFO_IS_CONFIG (config));
+ g_list_foreach (paths, (GFunc) add_path, config->priv);
+}
+
+static void
+add_path (const gchar *path,
+ UfoConfigPrivate *priv)
+{
+ GValue path_value = {0};
+
+ g_value_init (&path_value, G_TYPE_STRING);
+ g_value_set_string (&path_value, path);
+ g_value_array_prepend (priv->path_array, &path_value);
+ g_value_unset (&path_value);
+}
+
+static void
+ufo_config_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoConfigPrivate *priv = UFO_CONFIG_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_PATHS:
+ {
+ GValueArray *array;
+
+ if (priv->path_array != NULL)
+ g_value_array_free (priv->path_array);
+
+ array = g_value_get_boxed (value);
+
+ if (array != NULL)
+ priv->path_array = g_value_array_copy (array);
+ }
+ break;
+
+ case PROP_PROFILE_LEVEL:
+ priv->profile_level = g_value_get_flags (value);
+ break;
+
+ case PROP_PROFILE_OUTPUT_PREFIX:
+ g_free (priv->profile_output_prefix);
+ priv->profile_output_prefix = g_strdup (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_config_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoConfigPrivate *priv = UFO_CONFIG_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_PATHS:
+ g_value_set_boxed (value, priv->path_array);
+ break;
+
+ case PROP_PROFILE_LEVEL:
+ g_value_set_flags (value, priv->profile_level);
+ break;
+
+ case PROP_PROFILE_OUTPUT_PREFIX:
+ g_value_set_string (value, priv->profile_output_prefix);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_config_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_config_parent_class)->finalize (object);
+ g_debug ("UfoConfig: disposed");
+}
+
+static void
+ufo_config_finalize (GObject *object)
+{
+ UfoConfigPrivate *priv = UFO_CONFIG_GET_PRIVATE (object);
+
+ g_value_array_free (priv->path_array);
+
+ G_OBJECT_CLASS (ufo_config_parent_class)->finalize (object);
+ g_debug ("UfoConfig: finalized");
+}
+
+static void
+ufo_config_class_init (UfoConfigClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->set_property = ufo_config_set_property;
+ gobject_class->get_property = ufo_config_get_property;
+ gobject_class->dispose = ufo_config_dispose;
+ gobject_class->finalize = ufo_config_finalize;
+
+ /**
+ * UfoConfig:paths:
+ *
+ * An array of strings with paths pointing to possible filter and kernel
+ * file locations.
+ */
+ config_properties[PROP_PATHS] =
+ g_param_spec_value_array ("paths",
+ "Array with paths",
+ "Array with paths",
+ g_param_spec_string ("path",
+ "A path",
+ "A path pointing to a filter or kernel",
+ ".",
+ G_PARAM_READWRITE),
+ G_PARAM_READWRITE);
+
+ /**
+ * UfoConfig:profile-level:
+ *
+ * Controls the amount of profiling.
+ *
+ * See: #UfoProfilerLevel for different levels of profiling.
+ */
+ config_properties[PROP_PROFILE_LEVEL] =
+ g_param_spec_flags ("profile-level",
+ "Profiling level",
+ "Profiling level",
+ UFO_TYPE_PROFILER_LEVEL,
+ UFO_PROFILER_LEVEL_NONE,
+ G_PARAM_READWRITE);
+
+ config_properties[PROP_PROFILE_OUTPUT_PREFIX] =
+ g_param_spec_string ("profile-output-prefix",
+ "Filename prefix for profiling output",
+ "Filename prefix for profiling output. If NULL, information is output to stdout.",
+ NULL,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_property (gobject_class, PROP_PATHS, config_properties[PROP_PATHS]);
+ g_object_class_install_property (gobject_class, PROP_PROFILE_LEVEL, config_properties[PROP_PROFILE_LEVEL]);
+ g_object_class_install_property (gobject_class, PROP_PROFILE_OUTPUT_PREFIX, config_properties[PROP_PROFILE_OUTPUT_PREFIX]);
+
+ g_type_class_add_private(klass, sizeof (UfoConfigPrivate));
+}
+
+static void
+ufo_config_init (UfoConfig *config)
+{
+ UfoConfigPrivate *priv;
+
+ config->priv = priv = UFO_CONFIG_GET_PRIVATE (config);
+ priv->path_array = g_value_array_new (0);
+ priv->profile_level = UFO_PROFILER_LEVEL_NONE;
+ priv->profile_output_prefix = NULL;
+
+ add_path ("/usr/local/lib64/ufo", priv);
+ add_path ("/usr/local/lib/ufo", priv);
+ add_path ("/usr/lib64/ufo", priv);
+ add_path ("/usr/lib/ufo", priv);
+ add_path (UFO_PLUGIN_DIR, priv);
+}
diff --git a/ufo/ufo-config.h b/ufo/ufo-config.h
new file mode 100644
index 0000000..447350e
--- /dev/null
+++ b/ufo/ufo-config.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_CONFIG_H
+#define __UFO_CONFIG_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CONFIG (ufo_config_get_type())
+#define UFO_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CONFIG, UfoConfig))
+#define UFO_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CONFIG))
+#define UFO_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CONFIG, UfoConfigClass))
+#define UFO_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CONFIG))
+#define UFO_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_CONFIG, UfoConfigClass))
+
+typedef struct _UfoConfig UfoConfig;
+typedef struct _UfoConfigClass UfoConfigClass;
+typedef struct _UfoConfigPrivate UfoConfigPrivate;
+
+/**
+ * UfoConfig:
+ *
+ * A #UfoConfig provides access to run-time specific settings.
+ */
+struct _UfoConfig {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoConfigPrivate *priv;
+};
+
+/**
+ * UfoConfigClass:
+ *
+ * #UfoConfig class
+ */
+struct _UfoConfigClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoConfig * ufo_config_new (void);
+void ufo_config_add_paths (UfoConfig *config,
+ GList *paths);
+GList * ufo_config_get_paths (UfoConfig *config);
+GType ufo_config_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-configurable.c b/ufo/ufo-configurable.c
new file mode 100644
index 0000000..7e6a260
--- /dev/null
+++ b/ufo/ufo-configurable.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-configurable.h>
+#include <ufo/ufo-config.h>
+
+/**
+ * SECTION:ufo-configurable
+ * @Short_description: An interface for configurable objects
+ * @Title: UfoConfigurable
+ *
+ * An object that implements the #UfoConfigurable interface provides the common
+ * #UfoConfigurable:config property.
+ */
+
+typedef UfoConfigurableIface UfoConfigurableInterface;
+G_DEFINE_INTERFACE (UfoConfigurable, ufo_configurable, G_TYPE_OBJECT)
+
+static void
+ufo_configurable_default_init (UfoConfigurableInterface *iface)
+{
+ GParamSpec *config_spec;
+
+ /**
+ * UfoConfigurable:configuration:
+ *
+ * The #UfoConfiguration object that can be passed to all objects that
+ * implement the #UfoConfigurable interface.
+ */
+ config_spec = g_param_spec_object ("config",
+ "A UfoConfig object",
+ "A UfoConfig object",
+ UFO_TYPE_CONFIG,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+
+ g_object_interface_install_property (iface, config_spec);
+}
diff --git a/ufo/ufo-configurable.h b/ufo/ufo-configurable.h
new file mode 100644
index 0000000..99e6adc
--- /dev/null
+++ b/ufo/ufo-configurable.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_CONFIGURABLE_H
+#define __UFO_CONFIGURABLE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CONFIGURABLE (ufo_configurable_get_type())
+#define UFO_CONFIGURABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CONFIGURABLE, UfoConfigurable))
+#define UFO_CONFIGURABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CONFIGURABLE, UfoConfigurableIface))
+#define UFO_IS_CONFIGURABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CONFIGURABLE))
+#define UFO_IS_CONFIGURABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CONFIGURABLE))
+#define UFO_CONFIGURABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), UFO_TYPE_CONFIGURABLE, UfoConfigurableIface))
+
+typedef struct _UfoConfigurable UfoConfigurable;
+typedef struct _UfoConfigurableIface UfoConfigurableIface;
+
+struct _UfoConfigurableIface {
+ /*< private >*/
+ GTypeInterface parent_iface;
+};
+
+GType ufo_configurable_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-cpu-node.c b/ufo/ufo-cpu-node.c
new file mode 100644
index 0000000..424d32f
--- /dev/null
+++ b/ufo/ufo-cpu-node.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <ufo/ufo-cpu-node.h>
+
+G_DEFINE_TYPE (UfoCpuNode, ufo_cpu_node, UFO_TYPE_NODE)
+
+#define UFO_CPU_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_CPU_NODE, UfoCpuNodePrivate))
+
+
+struct _UfoCpuNodePrivate {
+ cpu_set_t *mask;
+};
+
+UfoNode *
+ufo_cpu_node_new (gpointer mask)
+{
+ UfoCpuNode *node;
+
+ g_return_val_if_fail (mask != NULL, NULL);
+ node = UFO_CPU_NODE (g_object_new (UFO_TYPE_CPU_NODE, NULL));
+ node->priv->mask = g_memdup (mask, sizeof(cpu_set_t));
+ return UFO_NODE (node);
+}
+
+/**
+ * ufo_cpu_node_get_affinity:
+ * @node: A #UfoCpuNode
+ *
+ * Get affinity mask of @node.
+ *
+ * Returns: (transfer none): A pointer to the cpu_set_t mask associated with
+ * @node.
+ */
+gpointer
+ufo_cpu_node_get_affinity (UfoCpuNode *node)
+{
+ g_return_val_if_fail (UFO_IS_CPU_NODE (node), NULL);
+ return node->priv->mask;
+}
+
+static void
+ufo_cpu_node_finalize (GObject *object)
+{
+ UfoCpuNodePrivate *priv;
+
+ priv = UFO_CPU_NODE_GET_PRIVATE (object);
+
+ if (priv->mask) {
+ g_free (priv->mask);
+ priv->mask = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_cpu_node_parent_class)->finalize (object);
+}
+
+static UfoNode *
+ufo_cpu_node_copy_real (UfoNode *node,
+ GError **error)
+{
+ return UFO_NODE (ufo_cpu_node_new (UFO_CPU_NODE (node)->priv->mask));
+}
+
+static gboolean
+ufo_cpu_node_equal_real (UfoNode *n1,
+ UfoNode *n2)
+{
+ UfoCpuNodePrivate *priv1;
+ UfoCpuNodePrivate *priv2;
+ const gsize MAX_CPUS = MIN (16, CPU_SETSIZE);
+
+ g_return_val_if_fail (UFO_IS_CPU_NODE (n1) && UFO_IS_CPU_NODE (n2), FALSE);
+ priv1 = UFO_CPU_NODE_GET_PRIVATE (n1);
+ priv2 = UFO_CPU_NODE_GET_PRIVATE (n2);
+
+ for (gsize i = 0; i < MAX_CPUS; i++) {
+ if (CPU_ISSET (i, priv1->mask) != CPU_ISSET (i, priv2->mask))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ufo_cpu_node_class_init (UfoCpuNodeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ UfoNodeClass *node_class = UFO_NODE_CLASS (klass);
+
+ object_class->finalize = ufo_cpu_node_finalize;
+ node_class->copy = ufo_cpu_node_copy_real;
+ node_class->equal = ufo_cpu_node_equal_real;
+
+ g_type_class_add_private(klass, sizeof(UfoCpuNodePrivate));
+}
+
+static void
+ufo_cpu_node_init (UfoCpuNode *self)
+{
+ UfoCpuNodePrivate *priv;
+ self->priv = priv = UFO_CPU_NODE_GET_PRIVATE (self);
+ priv->mask = NULL;
+}
diff --git a/ufo/ufo-cpu-node.h b/ufo/ufo-cpu-node.h
new file mode 100644
index 0000000..6ac4f7a
--- /dev/null
+++ b/ufo/ufo-cpu-node.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_CPU_NODE_H
+#define __UFO_CPU_NODE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CPU_NODE (ufo_cpu_node_get_type())
+#define UFO_CPU_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CPU_NODE, UfoCpuNode))
+#define UFO_IS_CPU_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CPU_NODE))
+#define UFO_CPU_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CPU_NODE, UfoCpuNodeClass))
+#define UFO_IS_CPU_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CPU_NODE))
+#define UFO_CPU_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_CPU_NODE, UfoCpuNodeClass))
+
+typedef struct _UfoCpuNode UfoCpuNode;
+typedef struct _UfoCpuNodeClass UfoCpuNodeClass;
+typedef struct _UfoCpuNodePrivate UfoCpuNodePrivate;
+
+/**
+ * UfoCpuNode:
+ *
+ * Main object for organizing filters. The contents of the #UfoCpuNode structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoCpuNode {
+ /*< private >*/
+ UfoNode parent_instance;
+
+ UfoCpuNodePrivate *priv;
+};
+
+/**
+ * UfoCpuNodeClass:
+ *
+ * #UfoCpuNode class
+ */
+struct _UfoCpuNodeClass {
+ /*< private >*/
+ UfoNodeClass parent_class;
+};
+
+UfoNode *ufo_cpu_node_new (gpointer mask);
+gpointer ufo_cpu_node_get_affinity (UfoCpuNode *node);
+GType ufo_cpu_node_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-cpu-task-iface.c b/ufo/ufo-cpu-task-iface.c
new file mode 100644
index 0000000..fe85176
--- /dev/null
+++ b/ufo/ufo-cpu-task-iface.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-cpu-task-iface.h>
+
+typedef UfoCpuTaskIface UfoCpuTaskInterface;
+
+G_DEFINE_INTERFACE (UfoCpuTask, ufo_cpu_task, UFO_TYPE_TASK)
+
+
+gboolean
+ufo_cpu_task_process (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ return UFO_CPU_TASK_GET_IFACE (task)->process (task, inputs, output, requisition);
+}
+
+void
+ufo_cpu_task_reduce (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UFO_CPU_TASK_GET_IFACE (task)->reduce (task, output, requisition);
+}
+
+gboolean
+ufo_cpu_task_generate (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ return UFO_CPU_TASK_GET_IFACE (task)->generate (task, output, requisition);
+}
+
+static gboolean
+ufo_cpu_task_process_real (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ g_warning ("`process' of UfoCpuTaskInterface not implemented");
+ return FALSE;
+}
+
+static void
+ufo_cpu_task_reduce_real (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ g_warning ("`reduce' of UfoCpuTaskInterface not implemented");
+}
+
+static gboolean
+ufo_cpu_task_generate_real (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ g_warning ("`generate' of UfoCpuTaskInterface not implemented");
+ return FALSE;
+}
+
+static void
+ufo_cpu_task_default_init (UfoCpuTaskInterface *iface)
+{
+ iface->process = ufo_cpu_task_process_real;
+ iface->reduce = ufo_cpu_task_reduce_real;
+ iface->generate = ufo_cpu_task_generate_real;
+}
diff --git a/ufo/ufo-cpu-task-iface.h b/ufo/ufo-cpu-task-iface.h
new file mode 100644
index 0000000..5cc2e64
--- /dev/null
+++ b/ufo/ufo-cpu-task-iface.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UFO_CPU_TASK_IFACE_H
+#define UFO_CPU_TASK_IFACE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-iface.h>
+#include <ufo/ufo-buffer.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_CPU_TASK (ufo_cpu_task_get_type())
+#define UFO_CPU_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_CPU_TASK, UfoCpuTask))
+#define UFO_CPU_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_CPU_TASK, UfoCpuTaskIface))
+#define UFO_IS_CPU_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_CPU_TASK))
+#define UFO_IS_CPU_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_CPU_TASK))
+#define UFO_CPU_TASK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), UFO_TYPE_CPU_TASK, UfoCpuTaskIface))
+
+typedef struct _UfoCpuTask UfoCpuTask;
+typedef struct _UfoCpuTaskIface UfoCpuTaskIface;
+
+struct _UfoCpuTaskIface {
+ /*< private >*/
+ UfoTaskIface parent_iface;
+
+ gboolean (*process) (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+ void (*reduce) (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+ gboolean (*generate)(UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+};
+
+gboolean ufo_cpu_task_process (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+void ufo_cpu_task_reduce (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+gboolean ufo_cpu_task_generate(UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+
+GType ufo_cpu_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-dummy-task.c b/ufo/ufo-dummy-task.c
new file mode 100644
index 0000000..3fe3d4f
--- /dev/null
+++ b/ufo/ufo-dummy-task.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gmodule.h>
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <ufo/ufo-dummy-task.h>
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoDummyTask, ufo_dummy_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init))
+
+#define UFO_DUMMY_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_DUMMY_TASK, UfoDummyTaskPrivate))
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+UfoNode *
+ufo_dummy_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_DUMMY_TASK, NULL));
+}
+
+static void
+ufo_dummy_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_dummy_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+}
+
+static void
+ufo_dummy_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+}
+
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_dummy_task_setup;
+ iface->get_structure = ufo_dummy_task_get_structure;
+ iface->get_requisition = ufo_dummy_task_get_requisition;
+}
+
+static void
+ufo_dummy_task_class_init (UfoDummyTaskClass *klass)
+{
+}
+
+static void
+ufo_dummy_task_init (UfoDummyTask *task)
+{
+ ufo_task_node_set_plugin_name (UFO_TASK_NODE (task), "[dummy]");
+}
diff --git a/ufo/ufo-dummy-task.h b/ufo/ufo-dummy-task.h
new file mode 100644
index 0000000..d89e595
--- /dev/null
+++ b/ufo/ufo-dummy-task.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_DUMMY_TASK_H
+#define __UFO_DUMMY_TASK_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_DUMMY_TASK (ufo_dummy_task_get_type())
+#define UFO_DUMMY_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_DUMMY_TASK, UfoDummyTask))
+#define UFO_IS_DUMMY_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_DUMMY_TASK))
+#define UFO_DUMMY_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_DUMMY_TASK, UfoDummyTaskClass))
+#define UFO_IS_DUMMY_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_DUMMY_TASK))
+#define UFO_DUMMY_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_DUMMY_TASK, UfoDummyTaskClass))
+
+typedef struct _UfoDummyTask UfoDummyTask;
+typedef struct _UfoDummyTaskClass UfoDummyTaskClass;
+typedef struct _UfoDummyTaskPrivate UfoDummyTaskPrivate;
+
+/**
+ * UfoDummyTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoDummyTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoDummyTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoDummyTaskPrivate *priv;
+};
+
+/**
+ * UfoDummyTaskClass:
+ *
+ * #UfoDummyTask class
+ */
+struct _UfoDummyTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode * ufo_dummy_task_new (void);
+GType ufo_dummy_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-enums.c.template b/ufo/ufo-enums.c.template
new file mode 100644
index 0000000..dbed629
--- /dev/null
+++ b/ufo/ufo-enums.c.template
@@ -0,0 +1,44 @@
+/*** BEGIN file-header ***/
+#include <config.h>
+
+#include "ufo-enums.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@filename@"
+/*** END file-production ***/
+
+
+/*** BEGIN value-header ***/
+GType
+ at enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile)) {
+ static const G at Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ GType g_define_type_id =
+ g_ at type@_register_static (g_intern_static_string ("@EnumName@"), values);
+
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+
+/*** END file-tail ***/
diff --git a/ufo/ufo-enums.h.template b/ufo/ufo-enums.h.template
new file mode 100644
index 0000000..6484bc7
--- /dev/null
+++ b/ufo/ufo-enums.h.template
@@ -0,0 +1,25 @@
+/*** BEGIN file-header ***/
+
+#ifndef UFO_ENUMS_H
+#define UFO_ENUMS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name at _get_type (void) G_GNUC_CONST;
+#define UFO_TYPE_ at ENUMSHORT@ (@enum_name at _get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* !UFO_ENUMS_H */
+/*** END file-tail ***/
diff --git a/ufo/ufo-gpu-node.c b/ufo/ufo-gpu-node.c
new file mode 100644
index 0000000..92af7e2
--- /dev/null
+++ b/ufo/ufo-gpu-node.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <CL/cl.h>
+#include <ufo/ufo-gpu-node.h>
+
+G_DEFINE_TYPE (UfoGpuNode, ufo_gpu_node, UFO_TYPE_NODE)
+
+#define UFO_GPU_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_GPU_NODE, UfoGpuNodePrivate))
+
+
+struct _UfoGpuNodePrivate {
+ gpointer cmd_queue;
+};
+
+UfoNode *
+ufo_gpu_node_new (gpointer cmd_queue)
+{
+ UfoGpuNode *node;
+
+ g_return_val_if_fail (cmd_queue != NULL, NULL);
+ node = UFO_GPU_NODE (g_object_new (UFO_TYPE_GPU_NODE, NULL));
+ node->priv->cmd_queue = cmd_queue;
+ clRetainCommandQueue (cmd_queue);
+
+ return UFO_NODE (node);
+}
+
+/**
+ * ufo_gpu_node_get_cmd_queue:
+ * @node: A #UfoGpuNode
+ *
+ * Get command queue associated with @node.
+ *
+ * Returns: (transfer none): A cl_command_queue object for @node.
+ */
+gpointer
+ufo_gpu_node_get_cmd_queue (UfoGpuNode *node)
+{
+ g_return_val_if_fail (UFO_IS_GPU_NODE (node), NULL);
+ return node->priv->cmd_queue;
+}
+
+static UfoNode *
+ufo_gpu_node_copy_real (UfoNode *node,
+ GError **error)
+{
+ return UFO_NODE (ufo_gpu_node_new (UFO_GPU_NODE (node)->priv->cmd_queue));
+}
+
+static gboolean
+ufo_gpu_node_equal_real (UfoNode *n1,
+ UfoNode *n2)
+{
+ g_return_val_if_fail (UFO_IS_GPU_NODE (n1) && UFO_IS_GPU_NODE (n2), FALSE);
+ return UFO_GPU_NODE (n1)->priv->cmd_queue == UFO_GPU_NODE (n2)->priv->cmd_queue;
+}
+
+static void
+ufo_gpu_node_dispose (GObject *object)
+{
+ UfoGpuNodePrivate *priv;
+
+ priv = UFO_GPU_NODE_GET_PRIVATE (object);
+
+ if (priv->cmd_queue != NULL) {
+ g_debug ("Release cmd_queue=%p", priv->cmd_queue);
+ clReleaseCommandQueue (priv->cmd_queue);
+ priv->cmd_queue = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_gpu_node_parent_class)->dispose (object);
+}
+
+static void
+ufo_gpu_node_class_init (UfoGpuNodeClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ UfoNodeClass *node_class = UFO_NODE_CLASS (klass);
+
+ oclass->dispose = ufo_gpu_node_dispose;
+ node_class->copy = ufo_gpu_node_copy_real;
+ node_class->equal = ufo_gpu_node_equal_real;
+
+ g_type_class_add_private (klass, sizeof (UfoGpuNodePrivate));
+}
+
+static void
+ufo_gpu_node_init (UfoGpuNode *self)
+{
+ UfoGpuNodePrivate *priv;
+ self->priv = priv = UFO_GPU_NODE_GET_PRIVATE (self);
+ priv->cmd_queue = NULL;
+}
diff --git a/ufo/ufo-gpu-node.h b/ufo/ufo-gpu-node.h
new file mode 100644
index 0000000..9c121a0
--- /dev/null
+++ b/ufo/ufo-gpu-node.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_GPU_NODE_H
+#define __UFO_GPU_NODE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_GPU_NODE (ufo_gpu_node_get_type())
+#define UFO_GPU_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_GPU_NODE, UfoGpuNode))
+#define UFO_IS_GPU_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_GPU_NODE))
+#define UFO_GPU_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_GPU_NODE, UfoGpuNodeClass))
+#define UFO_IS_GPU_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_GPU_NODE))
+#define UFO_GPU_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_GPU_NODE, UfoGpuNodeClass))
+
+typedef struct _UfoGpuNode UfoGpuNode;
+typedef struct _UfoGpuNodeClass UfoGpuNodeClass;
+typedef struct _UfoGpuNodePrivate UfoGpuNodePrivate;
+
+/**
+ * UfoGpuNode:
+ *
+ * Main object for organizing filters. The contents of the #UfoGpuNode structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoGpuNode {
+ /*< private >*/
+ UfoNode parent_instance;
+
+ UfoGpuNodePrivate *priv;
+};
+
+/**
+ * UfoGpuNodeClass:
+ *
+ * #UfoGpuNode class
+ */
+struct _UfoGpuNodeClass {
+ /*< private >*/
+ UfoNodeClass parent_class;
+};
+
+UfoNode *ufo_gpu_node_new (gpointer cmd_queue);
+gpointer ufo_gpu_node_get_cmd_queue (UfoGpuNode *node);
+GType ufo_gpu_node_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-gpu-task-iface.c b/ufo/ufo-gpu-task-iface.c
new file mode 100644
index 0000000..bc33ff4
--- /dev/null
+++ b/ufo/ufo-gpu-task-iface.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-gpu-task-iface.h>
+
+typedef UfoGpuTaskIface UfoGpuTaskInterface;
+
+G_DEFINE_INTERFACE (UfoGpuTask, ufo_gpu_task, UFO_TYPE_TASK)
+
+gboolean
+ufo_gpu_task_process (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ return UFO_GPU_TASK_GET_IFACE (task)->process (task, inputs, output, requisition, node);
+}
+
+void
+ufo_gpu_task_reduce (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ UFO_GPU_TASK_GET_IFACE (task)->reduce (task, output, requisition, node);
+}
+
+gboolean
+ufo_gpu_task_generate (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ return UFO_GPU_TASK_GET_IFACE (task)->generate (task, output, requisition, node);
+}
+
+static gboolean
+ufo_gpu_task_process_real (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ g_warning ("`process' of UfoGpuTaskInterface not implemented");
+ return FALSE;
+}
+
+static void
+ufo_gpu_task_reduce_real (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ g_warning ("`reduce' of UfoGpuTaskInterface not implemented");
+}
+
+static gboolean
+ufo_gpu_task_generate_real (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node)
+{
+ g_warning ("`generate' of UfoGpuTaskInterface not implemented");
+ return FALSE;
+}
+
+static void
+ufo_gpu_task_default_init (UfoGpuTaskInterface *iface)
+{
+ iface->process = ufo_gpu_task_process_real;
+ iface->reduce = ufo_gpu_task_reduce_real;
+ iface->generate = ufo_gpu_task_generate_real;
+}
diff --git a/ufo/ufo-gpu-task-iface.h b/ufo/ufo-gpu-task-iface.h
new file mode 100644
index 0000000..1a78f74
--- /dev/null
+++ b/ufo/ufo-gpu-task-iface.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UFO_GPU_TASK_IFACE_H
+#define UFO_GPU_TASK_IFACE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-gpu-node.h>
+#include <ufo/ufo-task-iface.h>
+#include <ufo/ufo-buffer.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_GPU_TASK (ufo_gpu_task_get_type())
+#define UFO_GPU_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_GPU_TASK, UfoGpuTask))
+#define UFO_GPU_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_GPU_TASK, UfoGpuTaskIface))
+#define UFO_IS_GPU_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_GPU_TASK))
+#define UFO_IS_GPU_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_GPU_TASK))
+#define UFO_GPU_TASK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), UFO_TYPE_GPU_TASK, UfoGpuTaskIface))
+
+typedef struct _UfoGpuTask UfoGpuTask;
+typedef struct _UfoGpuTaskIface UfoGpuTaskIface;
+
+struct _UfoGpuTaskIface {
+ /*< private >*/
+ UfoTaskIface parent_iface;
+
+ gboolean (*process) (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+ void (*reduce) (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+ gboolean (*generate)(UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+};
+
+gboolean ufo_gpu_task_process (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+void ufo_gpu_task_reduce (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+gboolean ufo_gpu_task_generate(UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition,
+ UfoGpuNode *node);
+
+GType ufo_gpu_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-graph.c b/ufo/ufo-graph.c
new file mode 100644
index 0000000..57c2e5b
--- /dev/null
+++ b/ufo/ufo-graph.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <ufo/ufo-node.h>
+#include <ufo/ufo-graph.h>
+
+/**
+ * SECTION:ufo-graph
+ * @Short_description: Generic graph structure
+ * @Title: UfoGraph
+ */
+
+G_DEFINE_TYPE (UfoGraph, ufo_graph, G_TYPE_OBJECT)
+
+#define UFO_GRAPH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_GRAPH, UfoGraphPrivate))
+
+struct _UfoGraphPrivate {
+ GList *node_types;
+ GList *nodes;
+ GList *edges;
+};
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+static gint cmp_edge (gconstpointer a, gconstpointer b);
+static gint cmp_edge_source (gconstpointer a, gconstpointer b);
+static gint cmp_edge_target (gconstpointer a, gconstpointer b);
+static UfoEdge *find_edge (GList *edges, UfoNode *source, UfoNode *target);
+static GList *g_list_find_all_data (GList *list, gconstpointer data, GCompareFunc func);
+
+/**
+ * ufo_graph_new:
+ *
+ * Create a new #UfoGraph object.
+ *
+ * Returns: (transfer full): A #UfoGraph.
+ */
+UfoGraph *
+ufo_graph_new (void)
+{
+ return UFO_GRAPH (g_object_new (UFO_TYPE_GRAPH, NULL));
+}
+
+/**
+ * ufo_graph_register_node_type:
+ * @graph: A #UfoGraph
+ * @type: A #GType
+ *
+ * Registers @type to be a valid node type of this graph. If a type has not be
+ * an added to @graph, any attempt to add such a node will fail.
+ */
+void
+ufo_graph_register_node_type (UfoGraph *graph,
+ GType type)
+{
+ UfoGraphPrivate *priv;
+
+ g_return_if_fail (UFO_IS_GRAPH (graph));
+
+ /* Make sure type is at least a node type */
+ g_return_if_fail (g_type_is_a (type, UFO_TYPE_NODE));
+
+ priv = graph->priv;
+ priv->node_types = g_list_append (priv->node_types, GINT_TO_POINTER (type));
+}
+
+/**
+ * ufo_graph_get_registered_node_types:
+ * @graph: A #UfoGraph
+ *
+ * Get all types of nodes that can be added to @graph.
+ *
+ * Returns: (element-type GType) (transfer container): A list of #GType
+ * identifiers that can be added to @graph.
+ */
+GList *
+ufo_graph_get_registered_node_types (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ return g_list_copy (graph->priv->node_types);
+}
+
+/**
+ * ufo_graph_is_connected:
+ * @graph: A #UfoGraph
+ * @from: A source node
+ * @to: A target node
+ *
+ * Check whether @from is connected to @to.
+ *
+ * Returns: %TRUE if @from is connected to @to, otherwise %FALSE.
+ */
+gboolean
+ufo_graph_is_connected (UfoGraph *graph,
+ UfoNode *from,
+ UfoNode *to)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge *edge;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), FALSE);
+ priv = graph->priv;
+ edge = find_edge (priv->edges, from, to);
+ return edge != NULL;
+}
+
+static gboolean
+is_valid_node_type (UfoGraphPrivate *priv,
+ UfoNode *node)
+{
+ for (GList *it = g_list_first (priv->node_types); it != NULL; it = g_list_next (it)) {
+ GType type = (GType) GPOINTER_TO_INT (it->data);
+
+ if (G_TYPE_CHECK_INSTANCE_TYPE (node, type))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+add_node_if_not_found (UfoGraphPrivate *priv,
+ UfoNode *node)
+{
+ if (!g_list_find (priv->nodes, node)) {
+ priv->nodes = g_list_append (priv->nodes, node);
+ g_object_ref (node);
+ }
+}
+
+/**
+ * ufo_graph_connect_nodes:
+ * @graph: A #UfoGraph
+ * @source: A source node
+ * @target: A target node
+ * @label: An arbitrary label
+ *
+ * Connect @source with @target in @graph and annotate the edge with
+ * @label.
+ */
+void
+ufo_graph_connect_nodes (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target,
+ gpointer label)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge *edge;
+
+ g_return_if_fail (UFO_IS_GRAPH (graph));
+ priv = graph->priv;
+
+ g_return_if_fail (is_valid_node_type (priv, source) && is_valid_node_type (priv, target));
+
+ edge = g_new0 (UfoEdge, 1);
+ edge->source = source;
+ edge->target = target;
+ edge->label = label;
+
+ priv->edges = g_list_append (priv->edges, edge);
+
+ add_node_if_not_found (priv, source);
+ add_node_if_not_found (priv, target);
+}
+
+/**
+ * ufo_graph_get_num_nodes:
+ * @graph: A #UfoGraph
+ *
+ * Get number of nodes in @graph. The number is always divisible by two, because
+ * nodes are only part of a graph if member of an edge.
+ * Returns: Number of nodes.
+ */
+guint
+ufo_graph_get_num_nodes (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), 0);
+ return g_list_length (graph->priv->nodes);
+}
+
+/**
+ * ufo_graph_get_num_edges:
+ * @graph: A #UfoGraph
+ *
+ * Get number of edges present in @graph.
+ *
+ * Returns: Number of edges.
+ */
+guint
+ufo_graph_get_num_edges (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), 0);
+ return g_list_length (graph->priv->edges);
+}
+
+/**
+ * ufo_graph_get_edges:
+ * @graph: A #UfoGraph
+ *
+ * Get all edges contained in @graph.
+ *
+ * Returns: (element-type UfoEdge): a list of #UfoEdge elements or %NULL on
+ * error. Release the list with g_list_free().
+ */
+GList *
+ufo_graph_get_edges (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ return g_list_copy (graph->priv->edges);
+}
+
+/**
+ * ufo_graph_get_nodes:
+ * @graph: A #UfoGraph
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list of all nodes
+ * added to @graph.
+ */
+GList *
+ufo_graph_get_nodes (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ return g_list_copy (graph->priv->nodes);
+}
+
+/**
+ * ufo_graph_get_nodes_filtered:
+ * @graph: A #UfoGraph
+ * @func: (scope call): Predicate function to filter out nodes
+ * @user_data: Data to be passed to @func on invocation
+ *
+ * Get nodes filtered by the predicate @func.
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list of all nodes
+ * that are marked as true by the predicate function @func.
+ */
+GList *
+ufo_graph_get_nodes_filtered (UfoGraph *graph,
+ UfoFilterPredicate func,
+ gpointer user_data)
+{
+ UfoGraphPrivate *priv;
+ GList *result = NULL;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ priv = graph->priv;
+
+ for (GList *it = g_list_first (priv->nodes); it != NULL; it = g_list_next (it)) {
+ UfoNode *node = UFO_NODE (it->data);
+
+ if (func (node, user_data))
+ result = g_list_append (result, node);
+ }
+
+ return result;
+}
+
+/**
+ * ufo_graph_remove_edge:
+ * @graph: A #UfoGraph
+ * @source: A source node
+ * @target: A target node
+ *
+ * Remove edge between @source and @target.
+ */
+void
+ufo_graph_remove_edge (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge *edge;
+
+ g_return_if_fail (UFO_IS_GRAPH (graph));
+ priv = graph->priv;
+ edge = find_edge (priv->edges, source, target);
+
+ if (edge != NULL) {
+ priv->nodes = g_list_remove (priv->nodes, source);
+ g_object_unref (source);
+
+ priv->nodes = g_list_remove (priv->nodes, target);
+ g_object_unref (target);
+
+ priv->edges = g_list_remove (priv->edges, edge);
+ }
+}
+
+/**
+ * ufo_graph_get_edge_label:
+ * @graph: A #UfoGraph
+ * @source: Source node
+ * @target: Target node
+ *
+ * Retrieve edge label between @source and @target.
+ *
+ * Returns: (transfer none): Edge label pointer.
+ */
+gpointer
+ufo_graph_get_edge_label (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge *edge;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ priv = graph->priv;
+ edge = find_edge (priv->edges, source, target);
+
+ if (edge != NULL)
+ return edge->label;
+
+ g_warning ("target not found");
+ return NULL;
+}
+
+static gboolean
+has_no_predecessor (UfoNode *node,
+ UfoGraph *graph)
+{
+ for (GList *it = g_list_first (graph->priv->nodes); it != NULL; it = g_list_next (it)) {
+ UfoNode *source = (UfoNode *) it->data;
+
+ if (ufo_graph_is_connected (graph, source, node))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * ufo_graph_get_roots:
+ * @graph: A #UfoGraph
+ *
+ * Get all roots of @graph.
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list of all nodes
+ * that do not have a predessor node.
+ */
+GList *
+ufo_graph_get_roots (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ return ufo_graph_get_nodes_filtered (graph, (UfoFilterPredicate ) has_no_predecessor, graph);
+}
+
+static gboolean
+has_no_successor (UfoNode *node,
+ UfoGraph *graph)
+{
+ for (GList *it = g_list_first (graph->priv->nodes); it != NULL; it = g_list_next (it)) {
+ UfoNode *target = (UfoNode *) it->data;
+
+ if (ufo_graph_is_connected (graph, node, target))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * ufo_graph_get_leaves:
+ * @graph: A #UfoGraph
+ *
+ * Get all leaves of @graph.
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list of all nodes
+ * that do not have a predessor node.
+ */
+GList *
+ufo_graph_get_leaves (UfoGraph *graph)
+{
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ return ufo_graph_get_nodes_filtered (graph, (UfoFilterPredicate) has_no_successor, graph);
+}
+
+/**
+ * ufo_graph_get_predecessors:
+ * @graph: A #UfoGraph
+ * @node: A #UfoNode whose predecessors are returned.
+ *
+ * Get the all nodes connected to @node.
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list with preceeding
+ * nodes of @node. Free the list with g_list_free() but not its elements.
+ */
+GList *
+ufo_graph_get_predecessors (UfoGraph *graph,
+ UfoNode *node)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge match;
+ GList *edges;
+ GList *result;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ priv = graph->priv;
+
+ match.target = node;
+ edges = g_list_find_all_data (priv->edges, &match, cmp_edge_target);
+ result = NULL;
+
+ for (GList *it = g_list_first (edges); it != NULL; it = g_list_next (it)) {
+ UfoEdge *edge = (UfoEdge *) it->data;
+ result = g_list_prepend (result, edge->source);
+ }
+
+ g_list_free (edges);
+ return result;
+}
+
+/**
+ * ufo_graph_get_successors:
+ * @graph: A #UfoGraph
+ * @node: A #UfoNode whose successors are returned.
+ *
+ * Get the successors of @node.
+ *
+ * Returns: (element-type UfoNode) (transfer container): A list with succeeding
+ * nodes of @node. Free the list with g_list_free() but not its elements.
+ */
+GList *
+ufo_graph_get_successors (UfoGraph *graph,
+ UfoNode *node)
+{
+ UfoGraphPrivate *priv;
+ UfoEdge match;
+ GList *edges;
+ GList *result;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
+ priv = graph->priv;
+
+ match.source = node;
+ edges = g_list_find_all_data (priv->edges, &match, cmp_edge_source);
+ result = NULL;
+
+ for (GList *it = g_list_first (edges); it != NULL; it = g_list_next (it)) {
+ UfoEdge *edge = (UfoEdge *) it->data;
+ result = g_list_append (result, edge->target);
+ }
+
+ g_list_free (edges);
+ return result;
+}
+
+/**
+ * ufo_graph_expand:
+ * @graph: A #UfoGraph
+ * @path: (element-type UfoNode): A path of nodes, preferably created with
+ * ufo_graph_get_paths().
+ *
+ * Duplicate nodes between head and tail of path and insert at the exact the
+ * position of where path started and ended.
+ */
+void
+ufo_graph_expand (UfoGraph *graph,
+ GList *path)
+{
+ GList *head;
+ GList *tail;
+ UfoNode *orig;
+ UfoNode *current;
+ GError *error = NULL;
+
+ g_return_if_fail (UFO_IS_GRAPH (graph));
+
+ head = g_list_first (path);
+ tail = g_list_last (path);
+ g_assert (head != tail);
+
+ orig = UFO_NODE (head->data);
+
+ /* The first link goes from the original head */
+ current = orig;
+
+ for (GList *it = g_list_next (head); it != tail; it = g_list_next (it)) {
+ UfoNode *next;
+ UfoNode *copy;
+ gpointer label;
+
+ next = UFO_NODE (it->data);
+ copy = ufo_node_copy (next, &error);
+ label = ufo_graph_get_edge_label (graph, orig, next);
+ ufo_graph_connect_nodes (graph, current, copy, label);
+ current = copy;
+ orig = next;
+ }
+
+ if (tail->data != NULL) {
+ ufo_graph_connect_nodes (graph, current, UFO_NODE (tail->data),
+ ufo_graph_get_edge_label (graph, orig, UFO_NODE (tail->data)));
+ }
+}
+
+static void
+pickup_paths (UfoGraph *graph,
+ UfoFilterPredicate pred,
+ UfoNode *current,
+ UfoNode *last,
+ GList *current_path,
+ GList **paths)
+{
+ GList *successors;
+
+ if (pred (current, NULL)) {
+ if (!pred (last, NULL))
+ current_path = g_list_append (current_path, last);
+
+ current_path = g_list_append (current_path, current);
+ }
+ else {
+ if (current_path != NULL) {
+ current_path = g_list_append (current_path, current);
+ *paths = g_list_append (*paths, current_path);
+ }
+
+ current_path = NULL;
+ }
+
+ successors = ufo_graph_get_successors (graph, current);
+
+ for (GList *it = g_list_first (successors); it != NULL; it = g_list_next (it))
+ pickup_paths (graph, pred, it->data, current, g_list_copy (current_path), paths);
+
+ g_list_free (successors);
+}
+
+/**
+ * ufo_graph_get_paths:
+ * @graph: A #UfoGraph
+ * @pred: (scope call): A predicate function
+ *
+ * Compute a list of lists that contain complete paths with nodes that match a
+ * predicate function.
+ *
+ * Returns: (element-type GLib.GList) (transfer full): A list of lists with paths
+ * that match @pred.
+ */
+GList *
+ufo_graph_get_paths (UfoGraph *graph,
+ UfoFilterPredicate pred)
+{
+ GList *roots;
+ GList *paths = NULL;
+
+ roots = ufo_graph_get_roots (graph);
+
+ for (GList *it = g_list_first (roots); it != NULL; it = g_list_next (it)) {
+ UfoNode *node = UFO_NODE (it->data);
+ pickup_paths (graph, pred, node, node, NULL, &paths);
+ }
+
+ g_list_free (roots);
+ return paths;
+}
+
+/**
+ * ufo_graph_dump_dot:
+ * @graph: A #UfoGraph
+ * @filename: A string containing a filename
+ *
+ * Stores a GraphViz dot representation of @graph in @filename.
+ */
+void
+ufo_graph_dump_dot (UfoGraph *graph,
+ const gchar *filename)
+{
+ FILE *fp;
+ GList *nodes;
+
+ fp = fopen (filename, "w");
+ fprintf (fp, "digraph foo {\n");
+
+ nodes = ufo_graph_get_nodes (graph);
+
+ for (GList *it = g_list_first (nodes); it != NULL; it = g_list_next (it)) {
+ UfoNode *source;
+ GList *successors;
+
+ source = UFO_NODE (it->data);
+ successors = ufo_graph_get_successors (graph, source);
+
+ for (GList *jt = g_list_first (successors); jt != NULL; jt = g_list_next (jt)) {
+ UfoNode *target;
+
+ target = UFO_NODE (jt->data);
+
+ fprintf (fp, " %s_%p -> %s_%p;\n",
+ g_type_name (G_TYPE_FROM_INSTANCE (source)), (gpointer) source,
+ g_type_name (G_TYPE_FROM_INSTANCE (target)), (gpointer) target);
+ }
+
+ g_list_free (successors);
+ }
+
+ g_list_free (nodes);
+ fprintf (fp, "}\n");
+ fclose (fp);
+}
+
+static gint
+cmp_edge (gconstpointer a, gconstpointer b)
+{
+ const UfoEdge *edge_a = a;
+ const UfoEdge *edge_b = b;
+
+ if ((edge_a->source == edge_b->source) &&
+ (edge_a->target == edge_b->target)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static gint
+cmp_edge_source (gconstpointer a, gconstpointer b)
+{
+ const UfoEdge *edge_a = a;
+ const UfoEdge *edge_b = b;
+
+ if (edge_a->source == edge_b->source)
+ return 0;
+
+ return -1;
+}
+
+static gint
+cmp_edge_target (gconstpointer a, gconstpointer b)
+{
+ const UfoEdge *edge_a = a;
+ const UfoEdge *edge_b = b;
+
+ if (edge_a->target == edge_b->target)
+ return 0;
+
+ return -1;
+}
+
+static GList *
+g_list_find_all_data (GList *list,
+ gconstpointer data,
+ GCompareFunc func)
+{
+ GList *result = NULL;
+
+ for (GList *it = g_list_first (list); it != NULL; it = g_list_next (it)) {
+ if (func (data, it->data) == 0)
+ result = g_list_prepend (result, it->data);
+ }
+
+ return result;
+}
+
+static UfoEdge *
+find_edge (GList *edges,
+ UfoNode *source,
+ UfoNode *target)
+{
+ UfoEdge search_edge;
+ UfoEdge *edge;
+ GList *result;
+
+ search_edge.source = source;
+ search_edge.target = target;
+ result = g_list_find_custom (edges, &search_edge, cmp_edge);
+ edge = result != NULL ? g_list_nth_data (result, 0) : NULL;
+ return edge;
+}
+
+static void
+ufo_graph_dispose (GObject *object)
+{
+ UfoGraphPrivate *priv;
+
+ priv = UFO_GRAPH_GET_PRIVATE (object);
+
+ if (priv->edges != NULL) {
+ g_list_foreach (priv->edges, (GFunc) g_free, NULL);
+ g_list_free (priv->edges);
+ priv->edges = NULL;
+ }
+
+ if (priv->nodes != NULL) {
+ g_list_foreach (priv->nodes, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->nodes);
+ priv->nodes = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_graph_parent_class)->dispose (object);
+}
+
+static void
+ufo_graph_finalize (GObject *object)
+{
+ UfoGraphPrivate *priv;
+
+ priv = UFO_GRAPH_GET_PRIVATE (object);
+ g_list_free (priv->node_types);
+ priv->node_types = NULL;
+
+ G_OBJECT_CLASS (ufo_graph_parent_class)->finalize (object);
+}
+
+static void
+ufo_graph_class_init (UfoGraphClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->dispose = ufo_graph_dispose;
+ oclass->finalize = ufo_graph_finalize;
+
+ g_type_class_add_private(klass, sizeof(UfoGraphPrivate));
+}
+
+static void
+ufo_graph_init (UfoGraph *self)
+{
+ UfoGraphPrivate *priv;
+ self->priv = priv = UFO_GRAPH_GET_PRIVATE (self);
+ priv->node_types = NULL;
+ priv->nodes = NULL;
+}
diff --git a/ufo/ufo-graph.h b/ufo/ufo-graph.h
new file mode 100644
index 0000000..325a6f2
--- /dev/null
+++ b/ufo/ufo-graph.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_GRAPH_H
+#define __UFO_GRAPH_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_GRAPH (ufo_graph_get_type())
+#define UFO_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_GRAPH, UfoGraph))
+#define UFO_IS_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_GRAPH))
+#define UFO_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_GRAPH, UfoGraphClass))
+#define UFO_IS_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_GRAPH))
+#define UFO_GRAPH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_GRAPH, UfoGraphClass))
+
+typedef struct _UfoGraph UfoGraph;
+typedef struct _UfoGraphClass UfoGraphClass;
+typedef struct _UfoGraphPrivate UfoGraphPrivate;
+typedef struct _UfoEdge UfoEdge;
+
+typedef gboolean (*UfoFilterPredicate) (UfoNode *node, gpointer user_data);
+
+/**
+ * UfoEdge:
+ * @source: source node
+ * @target: target node
+ * @label: label
+ *
+ * An edge in a #UfoGraph.
+ */
+struct _UfoEdge {
+ UfoNode *source;
+ UfoNode *target;
+ gpointer label;
+};
+
+/**
+ * UfoGraph:
+ *
+ * Main object for organizing filters. The contents of the #UfoGraph structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoGraph {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoGraphPrivate *priv;
+};
+
+/**
+ * UfoGraphClass:
+ *
+ * #UfoGraph class
+ */
+struct _UfoGraphClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoGraph *ufo_graph_new (void);
+void ufo_graph_register_node_type (UfoGraph *graph,
+ GType type);
+GList *ufo_graph_get_registered_node_types
+ (UfoGraph *graph);
+void ufo_graph_connect_nodes (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target,
+ gpointer label);
+gboolean ufo_graph_is_connected (UfoGraph *graph,
+ UfoNode *from,
+ UfoNode *to);
+void ufo_graph_remove_edge (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target);
+gpointer ufo_graph_get_edge_label (UfoGraph *graph,
+ UfoNode *source,
+ UfoNode *target);
+guint ufo_graph_get_num_nodes (UfoGraph *graph);
+GList *ufo_graph_get_nodes (UfoGraph *graph);
+GList *ufo_graph_get_nodes_filtered (UfoGraph *graph,
+ UfoFilterPredicate func,
+ gpointer user_data);
+guint ufo_graph_get_num_edges (UfoGraph *graph);
+GList *ufo_graph_get_edges (UfoGraph *graph);
+GList *ufo_graph_get_roots (UfoGraph *graph);
+GList *ufo_graph_get_leaves (UfoGraph *graph);
+GList *ufo_graph_get_predecessors (UfoGraph *graph,
+ UfoNode *node);
+GList *ufo_graph_get_successors (UfoGraph *graph,
+ UfoNode *node);
+GList *ufo_graph_get_paths (UfoGraph *graph,
+ UfoFilterPredicate pred);
+void ufo_graph_expand (UfoGraph *graph,
+ GList *path);
+void ufo_graph_dump_dot (UfoGraph *graph,
+ const gchar *filename);
+GType ufo_graph_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-group.c b/ufo/ufo-group.c
new file mode 100644
index 0000000..0e5a694
--- /dev/null
+++ b/ufo/ufo-group.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <CL/cl.h>
+#include <ufo/ufo-group.h>
+#include <ufo/ufo-task-node.h>
+
+G_DEFINE_TYPE (UfoGroup, ufo_group, G_TYPE_OBJECT)
+
+#define UFO_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_GROUP, UfoGroupPrivate))
+
+typedef struct {
+ GAsyncQueue *queues[2];
+ guint capacity;
+} UfoQueue;
+
+struct _UfoGroupPrivate {
+ GList *targets;
+ guint n_targets;
+ UfoQueue **queues;
+ gint *n_expected;
+ gint n_received;
+ gboolean *ready;
+ UfoSendPattern pattern;
+ guint current;
+ cl_context context;
+ GList *buffers;
+};
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+typedef enum {
+ UFO_QUEUE_PRODUCER = 0,
+ UFO_QUEUE_CONSUMER = 1
+} UfoQueueAccess;
+
+static UfoQueue *ufo_queue_new (void);
+static gpointer ufo_queue_pop (UfoQueue *queue, UfoQueueAccess access);
+static void ufo_queue_push (UfoQueue *queue, UfoQueueAccess access, gpointer data);
+static void ufo_queue_insert (UfoQueue *queue, UfoQueueAccess access, gpointer data);
+static guint ufo_queue_get_capacity (UfoQueue *queue);
+
+/**
+ * ufo_group_new:
+ * @targets: (element-type UfoNode): A list of #UfoNode targets
+ * @context: A cl_context on which the targets should operate on.
+ * @pattern: Pattern to distribute data among the @targets
+ *
+ * Create a new #UfoGroup.
+ *
+ * Returns: A new #UfoGroup.
+ */
+UfoGroup *
+ufo_group_new (GList *targets,
+ gpointer context,
+ UfoSendPattern pattern)
+{
+ UfoGroup *group;
+ UfoGroupPrivate *priv;
+
+ group = UFO_GROUP (g_object_new (UFO_TYPE_GROUP, NULL));
+ priv = group->priv;
+
+ priv->targets = g_list_copy (targets);
+ priv->n_targets = g_list_length (targets);
+ priv->queues = g_new0 (UfoQueue *, priv->n_targets);
+ priv->n_expected = g_new0 (gint, priv->n_targets);
+ priv->pattern = pattern;
+ priv->current = 0;
+ priv->context = context;
+ priv->n_received = 0;
+
+ for (guint i = 0; i < priv->n_targets; i++)
+ priv->queues[i] = ufo_queue_new ();
+
+ return group;
+}
+
+static UfoBuffer *
+pop_or_alloc_buffer (UfoGroupPrivate *priv,
+ guint pos,
+ UfoRequisition *requisition)
+{
+ UfoBuffer *buffer;
+
+ if (ufo_queue_get_capacity (priv->queues[pos]) < priv->n_targets) {
+ buffer = ufo_buffer_new (requisition, priv->context);
+ priv->buffers = g_list_append (priv->buffers, buffer);
+ ufo_queue_insert (priv->queues[pos], UFO_QUEUE_PRODUCER, buffer);
+ }
+
+ buffer = ufo_queue_pop (priv->queues[pos], UFO_QUEUE_PRODUCER);
+
+ if (ufo_buffer_cmp_dimensions (buffer, requisition))
+ ufo_buffer_resize (buffer, requisition);
+
+ return buffer;
+}
+
+/**
+ * ufo_group_pop_output_buffer:
+ * @group: A #UfoGroup
+ * @requisition: Size of the buffer.
+ *
+ * Return value: (transfer full): A newly allocated buffer or a re-used buffer
+ * that must be released with ufo_group_push_output_buffer().
+ */
+UfoBuffer *
+ufo_group_pop_output_buffer (UfoGroup *group,
+ UfoRequisition *requisition)
+{
+ UfoGroupPrivate *priv;
+ guint pos;
+
+ priv = group->priv;
+ pos = priv->pattern == UFO_SEND_SCATTER || UFO_SEND_SEQUENTIAL ? priv->current : 0;
+
+ return pop_or_alloc_buffer (priv, pos, requisition);
+}
+
+void
+ufo_group_push_output_buffer (UfoGroup *group,
+ UfoBuffer *buffer)
+{
+ UfoGroupPrivate *priv;
+
+ priv = group->priv;
+ priv->n_received++;
+
+ /* Copy or not depending on the send pattern */
+ if (priv->pattern == UFO_SEND_SCATTER) {
+ ufo_queue_push (priv->queues[priv->current],
+ UFO_QUEUE_PRODUCER,
+ buffer);
+
+ priv->current = (priv->current + 1) % priv->n_targets;
+ }
+ else if (priv->pattern == UFO_SEND_BROADCAST) {
+ UfoRequisition requisition;
+
+ ufo_buffer_get_requisition (buffer, &requisition);
+
+ for (guint pos = 1; pos < priv->n_targets; pos++) {
+ UfoBuffer *copy;
+
+ copy = pop_or_alloc_buffer (priv, pos, &requisition);
+ ufo_buffer_copy (buffer, copy);
+ ufo_queue_push (priv->queues[pos], UFO_QUEUE_PRODUCER, copy);
+ }
+
+ ufo_queue_push (priv->queues[0], UFO_QUEUE_PRODUCER, buffer);
+ }
+ else if (priv->pattern == UFO_SEND_SEQUENTIAL) {
+ ufo_queue_push (priv->queues[priv->current],
+ UFO_QUEUE_PRODUCER,
+ buffer);
+
+ if (priv->n_expected[priv->current] == priv->n_received) {
+ ufo_queue_push (priv->queues[priv->current],
+ UFO_QUEUE_PRODUCER,
+ UFO_END_OF_STREAM);
+ /* FIXME: setting priv->current to 0 again wouldn't be right */
+ priv->current = (priv->current + 1) % priv->n_targets;
+ priv->n_received = 0;
+ }
+ }
+}
+
+void
+ufo_group_set_num_expected (UfoGroup *group,
+ UfoTask *target,
+ gint n_expected)
+{
+ UfoGroupPrivate *priv;
+ gint pos;
+
+ g_return_if_fail (UFO_IS_GROUP (group));
+ priv = group->priv;
+ pos = g_list_index (priv->targets, target);
+ priv->n_expected[pos] = n_expected;
+}
+
+/**
+ * ufo_group_pop_input_buffer:
+ * @group: A #UfoGroup
+ * @target: The #UfoTask that is a target in @group
+ *
+ * Return value: (transfer full): A buffer that must be released with
+ * ufo_group_push_input_buffer().
+ */
+UfoBuffer *
+ufo_group_pop_input_buffer (UfoGroup *group,
+ UfoTask *target)
+{
+ UfoGroupPrivate *priv;
+ UfoBuffer *input;
+ gint pos;
+
+ priv = group->priv;
+ pos = g_list_index (priv->targets, target);
+ input = pos >= 0 ? ufo_queue_pop (priv->queues[pos], UFO_QUEUE_CONSUMER) : NULL;
+
+ return input;
+}
+
+void
+ufo_group_push_input_buffer (UfoGroup *group,
+ UfoTask *target,
+ UfoBuffer *input)
+{
+ UfoGroupPrivate *priv;
+ gint pos;
+
+ priv = group->priv;
+ pos = g_list_index (priv->targets, target);
+
+ if (pos >= 0)
+ ufo_queue_push (priv->queues[pos], UFO_QUEUE_CONSUMER, input);
+}
+
+void
+ufo_group_finish (UfoGroup *group)
+{
+ UfoGroupPrivate *priv;
+
+ priv = group->priv;
+
+ for (guint i = 0; i < priv->n_targets; i++) {
+ ufo_queue_push (priv->queues[i],
+ UFO_QUEUE_PRODUCER,
+ UFO_END_OF_STREAM);
+ }
+}
+
+static UfoQueue *
+ufo_queue_new (void)
+{
+ UfoQueue *queue = g_new0 (UfoQueue, 1);
+ queue->queues[0] = g_async_queue_new ();
+ queue->queues[1] = g_async_queue_new ();
+ queue->capacity = 0;
+ return queue;
+}
+
+static void
+ufo_queue_free (UfoQueue *queue)
+{
+ g_async_queue_unref (queue->queues[0]);
+ g_async_queue_unref (queue->queues[1]);
+ g_free (queue);
+}
+
+static gpointer
+ufo_queue_pop (UfoQueue *queue, UfoQueueAccess access)
+{
+ return g_async_queue_pop (queue->queues[access]);
+}
+
+static void
+ufo_queue_push (UfoQueue *queue, UfoQueueAccess access, gpointer data)
+{
+ g_async_queue_push (queue->queues[1-access], data);
+}
+
+static void
+ufo_queue_insert (UfoQueue *queue, UfoQueueAccess access, gpointer data)
+{
+ g_async_queue_push (queue->queues[access], data);
+ queue->capacity++;
+}
+
+static guint
+ufo_queue_get_capacity (UfoQueue *queue)
+{
+ return queue->capacity;
+}
+
+static void
+ufo_group_dispose(GObject *object)
+{
+ UfoGroupPrivate *priv;
+
+ priv = UFO_GROUP_GET_PRIVATE (object);
+ g_list_foreach (priv->buffers, (GFunc) g_object_unref, NULL);
+ G_OBJECT_CLASS (ufo_group_parent_class)->dispose (object);
+}
+
+static void
+ufo_group_finalize (GObject *object)
+{
+ UfoGroupPrivate *priv;
+
+ priv = UFO_GROUP_GET_PRIVATE (object);
+
+ g_list_free (priv->targets);
+ priv->targets = NULL;
+
+ g_list_free (priv->buffers);
+ priv->buffers = NULL;
+
+ for (guint i = 0; i < priv->n_targets; i++)
+ ufo_queue_free (priv->queues[i]);
+
+ g_free (priv->queues);
+ priv->queues = NULL;
+
+ G_OBJECT_CLASS (ufo_group_parent_class)->finalize (object);
+}
+
+static void
+ufo_group_class_init (UfoGroupClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->dispose = ufo_group_dispose;
+ gobject_class->finalize = ufo_group_finalize;
+
+ g_type_class_add_private(klass, sizeof(UfoGroupPrivate));
+}
+
+static void
+ufo_group_init (UfoGroup *self)
+{
+ UfoGroupPrivate *priv;
+ self->priv = priv = UFO_GROUP_GET_PRIVATE (self);
+ priv->buffers = NULL;
+}
diff --git a/ufo/ufo-group.h b/ufo/ufo-group.h
new file mode 100644
index 0000000..e4e7e32
--- /dev/null
+++ b/ufo/ufo-group.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_GROUP_H
+#define __UFO_GROUP_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-iface.h>
+#include <ufo/ufo-buffer.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_GROUP (ufo_group_get_type())
+#define UFO_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_GROUP, UfoGroup))
+#define UFO_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_GROUP))
+#define UFO_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_GROUP, UfoGroupClass))
+#define UFO_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_GROUP))
+#define UFO_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_GROUP, UfoGroupClass))
+
+typedef struct _UfoGroup UfoGroup;
+typedef struct _UfoGroupClass UfoGroupClass;
+typedef struct _UfoGroupPrivate UfoGroupPrivate;
+
+#define UFO_END_OF_STREAM (GINT_TO_POINTER(1))
+
+/**
+ * UfoSendPattern:
+ * @UFO_SEND_BROADCAST: Broadcast data to all connected nodes
+ * @UFO_SEND_SCATTER: Scatter data among connected nodes.
+ * @UFO_SEND_SEQUENTIAL: Break up a linear input stream and transfer sub streams
+ * one by one to connected nodes.
+ *
+ * The send pattern describes how results are passed to connected nodes.
+ */
+typedef enum {
+ UFO_SEND_BROADCAST,
+ UFO_SEND_SCATTER,
+ UFO_SEND_SEQUENTIAL
+} UfoSendPattern;
+
+/**
+ * UfoGroup:
+ *
+ * Main object for organizing filters. The contents of the #UfoGroup structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoGroup {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoGroupPrivate *priv;
+};
+
+/**
+ * UfoGroupClass:
+ *
+ * #UfoGroup class
+ */
+struct _UfoGroupClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoGroup * ufo_group_new (GList *targets,
+ gpointer context,
+ UfoSendPattern pattern);
+void ufo_group_set_num_expected (UfoGroup *group,
+ UfoTask *target,
+ gint n_expected);
+UfoBuffer * ufo_group_pop_output_buffer (UfoGroup *group,
+ UfoRequisition *requisition);
+void ufo_group_push_output_buffer (UfoGroup *group,
+ UfoBuffer *buffer);
+UfoBuffer * ufo_group_pop_input_buffer (UfoGroup *group,
+ UfoTask *target);
+void ufo_group_push_input_buffer (UfoGroup *group,
+ UfoTask *target,
+ UfoBuffer *input);
+void ufo_group_finish (UfoGroup *group);
+GType ufo_group_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-input-task.c b/ufo/ufo-input-task.c
new file mode 100644
index 0000000..68f0cad
--- /dev/null
+++ b/ufo/ufo-input-task.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <gmodule.h>
+#include <ufo/ufo-input-task.h>
+#include <ufo/ufo-cpu-task-iface.h>
+#include <ufo/ufo-gpu-task-iface.h>
+#include <ufo/ufo-gpu-node.h>
+
+/**
+ * SECTION:ufo-input-task
+ * @Short_description: An input task
+ * @Title: UfoInputTask
+ */
+
+struct _UfoInputTaskPrivate {
+ GAsyncQueue *in_queue;
+ GAsyncQueue *out_queue;
+ UfoTaskMode mode;
+ gboolean active;
+ guint n_inputs;
+ UfoInputParam *in_params;
+ UfoBuffer *input;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_cpu_task_interface_init (UfoCpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoInputTask, ufo_input_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init)
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CPU_TASK,
+ ufo_cpu_task_interface_init))
+
+#define UFO_INPUT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_INPUT_TASK, UfoInputTaskPrivate))
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+UfoNode *
+ufo_input_task_new (void)
+{
+ UfoInputTask *task;
+ UfoInputTaskPrivate *priv;
+
+ task = UFO_INPUT_TASK (g_object_new (UFO_TYPE_INPUT_TASK, NULL));
+ priv = task->priv;
+
+ /* TODO: free in_params and queues */
+ priv->in_queue = g_async_queue_new ();
+ priv->out_queue = g_async_queue_new ();
+ priv->active = TRUE;
+
+ return UFO_NODE (task);
+}
+
+void
+ufo_input_task_stop (UfoInputTask *task)
+{
+ g_return_if_fail (UFO_IS_INPUT_TASK (task));
+ task->priv->active = FALSE;
+}
+
+void
+ufo_input_task_release_input_buffer (UfoInputTask *task,
+ UfoBuffer *buffer)
+{
+ g_return_if_fail (UFO_IS_INPUT_TASK (task));
+ g_async_queue_push (task->priv->in_queue, buffer);
+}
+
+/**
+ * ufo_input_task_get_input_buffer:
+ * @task: A #UfoInputTask
+ *
+ * Get the input buffer to which we write the data received from the master
+ * remote node.
+ *
+ * Return value: (transfer full): A #UfoBuffer for writing input data.
+ */
+UfoBuffer *
+ufo_input_task_get_input_buffer (UfoInputTask *task)
+{
+ g_return_val_if_fail (UFO_IS_INPUT_TASK (task), NULL);
+ return g_async_queue_pop (task->priv->out_queue);
+}
+
+static void
+ufo_input_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_input_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ *n_inputs = 0;
+ *mode = UFO_TASK_MODE_SINGLE;
+}
+
+static void
+ufo_input_task_get_requisition (UfoTask *task,
+ UfoBuffer **none,
+ UfoRequisition *requisition)
+{
+ UfoInputTaskPrivate *priv;
+
+ priv = UFO_INPUT_TASK_GET_PRIVATE (task);
+
+ /* Pop input here but release later in ufo_input_task_process */
+ priv->input = g_async_queue_pop (priv->in_queue);
+ ufo_buffer_get_requisition (priv->input, requisition);
+}
+
+static gboolean
+ufo_input_task_process (UfoCpuTask *task,
+ UfoBuffer **none,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoInputTaskPrivate *priv;
+
+ g_return_val_if_fail (UFO_IS_INPUT_TASK (task), FALSE);
+ priv = UFO_INPUT_TASK_GET_PRIVATE (task);
+
+ if (!priv->active)
+ return FALSE;
+
+ ufo_buffer_discard_location (output, UFO_LOCATION_DEVICE);
+ ufo_buffer_copy (priv->input, output);
+
+ /* input was popped in ufo_input_task_get_requisition */
+ g_async_queue_push (priv->out_queue, priv->input);
+
+ return priv->active;
+}
+
+static void
+ufo_input_task_finalize (GObject *object)
+{
+ UfoInputTaskPrivate *priv;
+
+ priv = UFO_INPUT_TASK_GET_PRIVATE (object);
+ g_async_queue_unref (priv->in_queue);
+ g_async_queue_unref (priv->out_queue);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_input_task_setup;
+ iface->get_structure = ufo_input_task_get_structure;
+ iface->get_requisition = ufo_input_task_get_requisition;
+}
+
+static void
+ufo_cpu_task_interface_init (UfoCpuTaskIface *iface)
+{
+ iface->process = ufo_input_task_process;
+}
+
+static void
+ufo_input_task_class_init (UfoInputTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = ufo_input_task_finalize;
+
+ g_type_class_add_private (gobject_class, sizeof(UfoInputTaskPrivate));
+}
+
+static void
+ufo_input_task_init (UfoInputTask *task)
+{
+ task->priv = UFO_INPUT_TASK_GET_PRIVATE (task);
+ ufo_task_node_set_plugin_name (UFO_TASK_NODE (task), "input-task");
+}
diff --git a/ufo/ufo-input-task.h b/ufo/ufo-input-task.h
new file mode 100644
index 0000000..276d752
--- /dev/null
+++ b/ufo/ufo-input-task.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_INPUT_TASK_H
+#define __UFO_INPUT_TASK_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_INPUT_TASK (ufo_input_task_get_type())
+#define UFO_INPUT_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_INPUT_TASK, UfoInputTask))
+#define UFO_IS_INPUT_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_INPUT_TASK))
+#define UFO_INPUT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_INPUT_TASK, UfoInputTaskClass))
+#define UFO_IS_INPUT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_INPUT_TASK))
+#define UFO_INPUT_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_INPUT_TASK, UfoInputTaskClass))
+
+typedef struct _UfoInputTask UfoInputTask;
+typedef struct _UfoInputTaskClass UfoInputTaskClass;
+typedef struct _UfoInputTaskPrivate UfoInputTaskPrivate;
+
+/**
+ * UfoInputTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoInputTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoInputTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoInputTaskPrivate *priv;
+};
+
+/**
+ * UfoInputTaskClass:
+ *
+ * #UfoInputTask class
+ */
+struct _UfoInputTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode * ufo_input_task_new (void);
+void ufo_input_task_stop (UfoInputTask *task);
+void ufo_input_task_release_input_buffer (UfoInputTask *task,
+ UfoBuffer *buffer);
+UfoBuffer * ufo_input_task_get_input_buffer (UfoInputTask *task);
+GType ufo_input_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-node.c b/ufo/ufo-node.c
new file mode 100644
index 0000000..a60e690
--- /dev/null
+++ b/ufo/ufo-node.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-node.h>
+
+/**
+ * SECTION:ufo-node
+ * @Short_description: Generic node that can be connected in a #UfoGraph
+ * @Title: UfoNode
+ */
+
+G_DEFINE_TYPE (UfoNode, ufo_node, G_TYPE_OBJECT)
+
+#define UFO_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_NODE, UfoNodePrivate))
+
+struct _UfoNodePrivate {
+ UfoNode *copied_from;
+ gpointer label;
+};
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+UfoNode *
+ufo_node_new (gpointer label)
+{
+ UfoNode *node;
+
+ node = UFO_NODE (g_object_new (UFO_TYPE_NODE, NULL));
+ node->priv->label = label;
+ return node;
+}
+
+/**
+ * ufo_node_get_label:
+ * @node: A #UfoNode
+ *
+ * Get arbitrary label data of @node.
+ *
+ * Returns: (transfer none): The label of @node.
+ */
+gpointer
+ufo_node_get_label (UfoNode *node)
+{
+ g_return_val_if_fail (UFO_IS_NODE (node), NULL);
+ return node->priv->label;
+}
+
+static UfoNode *
+ufo_node_copy_real (UfoNode *node,
+ GError **error)
+{
+ GObject *copy;
+ GParamSpec **props;
+ guint n_props;
+
+ copy = g_object_new (G_OBJECT_TYPE (node), NULL);
+ props = g_object_class_list_properties (G_OBJECT_GET_CLASS (node), &n_props);
+
+ for (guint i = 0; i < n_props; i++) {
+ GValue value = {0};
+
+ g_value_init (&value, props[i]->value_type);
+ g_object_get_property (G_OBJECT (node), props[i]->name, &value);
+ g_object_set_property (G_OBJECT (copy), props[i]->name, &value);
+ }
+
+ g_free (props);
+ return UFO_NODE (copy);
+}
+
+static gboolean
+ufo_node_equal_real (UfoNode *n1,
+ UfoNode *n2)
+{
+ g_return_val_if_fail (UFO_IS_NODE (n1) && UFO_IS_NODE (n2), FALSE);
+
+ /* FIXME: When done we should just check if the types match */
+ return n1 == n2 ||
+ n1->priv->copied_from == n2 ||
+ n2->priv->copied_from == n1;
+}
+
+/**
+ * ufo_node_copy:
+ * @node: A #UfoNode
+ * @error: Location for an error
+ *
+ * Get a copy of @node. How "deep" the copy is, depends on the inherited
+ * implementation of @node.
+ *
+ * Returns: (transfer full): Copy of @node.
+ */
+UfoNode *
+ufo_node_copy (UfoNode *node,
+ GError **error)
+{
+ UfoNode *offspring;
+
+ offspring = UFO_NODE_GET_CLASS (node)->copy (node, error);
+ offspring->priv->copied_from = node;
+ return offspring;
+}
+
+gboolean
+ufo_node_equal (UfoNode *n1,
+ UfoNode *n2)
+{
+ return UFO_NODE_GET_CLASS (n1)->equal (n1, n2);
+}
+
+static void
+ufo_node_class_init (UfoNodeClass *klass)
+{
+ klass->copy = ufo_node_copy_real;
+ klass->equal = ufo_node_equal_real;
+
+ g_type_class_add_private(klass, sizeof(UfoNodePrivate));
+}
+
+static void
+ufo_node_init (UfoNode *self)
+{
+ UfoNodePrivate *priv;
+ self->priv = priv = UFO_NODE_GET_PRIVATE (self);
+
+ priv->copied_from = NULL;
+ priv->label = NULL;
+}
diff --git a/ufo/ufo-node.h b/ufo/ufo-node.h
new file mode 100644
index 0000000..9d5eb18
--- /dev/null
+++ b/ufo/ufo-node.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_NODE_H
+#define __UFO_NODE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_NODE (ufo_node_get_type())
+#define UFO_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_NODE, UfoNode))
+#define UFO_IS_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_NODE))
+#define UFO_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_NODE, UfoNodeClass))
+#define UFO_IS_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_NODE))
+#define UFO_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_NODE, UfoNodeClass))
+
+typedef struct _UfoNode UfoNode;
+typedef struct _UfoNodeClass UfoNodeClass;
+typedef struct _UfoNodePrivate UfoNodePrivate;
+
+/**
+ * UfoNode:
+ *
+ * Main object for organizing filters. The contents of the #UfoNode structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoNode {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoNodePrivate *priv;
+};
+
+/**
+ * UfoNodeClass:
+ *
+ * #UfoNode class
+ */
+struct _UfoNodeClass {
+ /*< private >*/
+ GObjectClass parent_class;
+
+ UfoNode * (*copy) (UfoNode *node,
+ GError **error);
+ gboolean (*equal) (UfoNode *n1,
+ UfoNode *n2);
+};
+
+UfoNode *ufo_node_new (gpointer label);
+gpointer ufo_node_get_label (UfoNode *node);
+UfoNode *ufo_node_copy (UfoNode *node,
+ GError **error);
+gboolean ufo_node_equal (UfoNode *n1,
+ UfoNode *n2);
+GType ufo_node_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-output-task.c b/ufo/ufo-output-task.c
new file mode 100644
index 0000000..a14f6c4
--- /dev/null
+++ b/ufo/ufo-output-task.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gmodule.h>
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <ufo/ufo-output-task.h>
+#include <ufo-cpu-task-iface.h>
+
+/**
+ * SECTION:ufo-output-task
+ * @Short_description: Output task
+ * @Title: UfoOutputTask
+ */
+
+struct _UfoOutputTaskPrivate {
+ GAsyncQueue *out_queue;
+ GAsyncQueue *in_queue;
+ guint n_dims;
+ guint n_copies;
+ GList *copies;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_cpu_task_interface_init (UfoCpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoOutputTask, ufo_output_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init)
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CPU_TASK,
+ ufo_cpu_task_interface_init))
+
+#define UFO_OUTPUT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_OUTPUT_TASK, UfoOutputTaskPrivate))
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+UfoNode *
+ufo_output_task_new (guint n_dims)
+{
+ UfoOutputTask *task = UFO_OUTPUT_TASK (g_object_new (UFO_TYPE_OUTPUT_TASK, NULL));
+
+ task->priv->n_dims = n_dims;
+ return UFO_NODE (task);
+}
+
+void
+ufo_output_task_get_output_requisition (UfoOutputTask *task,
+ UfoRequisition *requisition)
+{
+ UfoBuffer *buffer;
+ UfoOutputTaskPrivate *priv;
+
+ g_return_if_fail (UFO_IS_OUTPUT_TASK (task));
+ priv = task->priv;
+ buffer = g_async_queue_pop (priv->out_queue);
+ ufo_buffer_get_requisition (buffer, requisition);
+ g_async_queue_push (priv->out_queue, buffer);
+}
+
+/**
+ * ufo_output_task_get_output_buffer:
+ * @task: A #UfoInputTask
+ *
+ * Get the output buffer from which we read the data to be sent to the master
+ * remote node.
+ *
+ * Return value: (transfer full): A #UfoBuffer for reading output data.
+ */
+UfoBuffer *
+ufo_output_task_get_output_buffer (UfoOutputTask *task)
+{
+ g_return_val_if_fail (UFO_IS_OUTPUT_TASK (task), NULL);
+ return g_async_queue_pop (task->priv->out_queue);
+}
+
+void
+ufo_output_task_release_output_buffer (UfoOutputTask *task,
+ UfoBuffer *buffer)
+{
+ g_return_if_fail (UFO_IS_OUTPUT_TASK (task));
+ g_async_queue_push (task->priv->in_queue, buffer);
+}
+
+static void
+ufo_output_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+}
+
+static void
+ufo_output_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ (*requisition).n_dims = 0;
+}
+
+static void
+ufo_output_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ UfoOutputTaskPrivate *priv = UFO_OUTPUT_TASK_GET_PRIVATE (task);
+
+ *mode = UFO_TASK_MODE_SINGLE;
+ *n_inputs = 1;
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = priv->n_dims;
+}
+
+static gboolean
+ufo_output_task_process (UfoCpuTask *task,
+ UfoBuffer **outputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoOutputTaskPrivate *priv;
+ UfoRequisition req;
+ UfoBuffer *copy;
+
+ g_return_val_if_fail (UFO_IS_OUTPUT_TASK (task), FALSE);
+ ufo_buffer_get_requisition (outputs[0], &req);
+
+ priv = UFO_OUTPUT_TASK_GET_PRIVATE (task);
+
+ if (priv->n_copies == 0) {
+ copy = ufo_buffer_dup (outputs[0]);
+ g_async_queue_push (priv->in_queue, copy);
+ priv->copies = g_list_append (priv->copies, copy);
+ priv->n_copies++;
+ }
+
+ copy = g_async_queue_pop (priv->in_queue);
+ ufo_buffer_copy (outputs[0], copy);
+ g_async_queue_push (priv->out_queue, copy);
+ return TRUE;
+}
+
+static void
+ufo_output_task_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_output_task_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_output_task_dispose (GObject *object)
+{
+ UfoOutputTaskPrivate *priv;
+
+ priv = UFO_OUTPUT_TASK_GET_PRIVATE (object);
+ g_list_foreach (priv->copies, (GFunc) g_object_unref, NULL);
+
+ G_OBJECT_CLASS (ufo_output_task_parent_class)->dispose (object);
+}
+
+static void
+ufo_output_task_finalize (GObject *object)
+{
+ UfoOutputTaskPrivate *priv;
+
+ priv = UFO_OUTPUT_TASK_GET_PRIVATE (object);
+ g_list_free (priv->copies);
+ priv->copies = NULL;
+
+ G_OBJECT_CLASS (ufo_output_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_output_task_setup;
+ iface->get_structure = ufo_output_task_get_structure;
+ iface->get_requisition = ufo_output_task_get_requisition;
+}
+
+static void
+ufo_cpu_task_interface_init (UfoCpuTaskIface *iface)
+{
+ iface->process = ufo_output_task_process;
+}
+
+static void
+ufo_output_task_class_init (UfoOutputTaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_output_task_set_property;
+ gobject_class->get_property = ufo_output_task_get_property;
+ gobject_class->dispose = ufo_output_task_dispose;
+ gobject_class->finalize = ufo_output_task_finalize;
+
+ g_type_class_add_private (gobject_class, sizeof(UfoOutputTaskPrivate));
+}
+
+static void
+ufo_output_task_init (UfoOutputTask *task)
+{
+ task->priv = UFO_OUTPUT_TASK_GET_PRIVATE (task);
+ task->priv->out_queue = g_async_queue_new ();
+ task->priv->in_queue = g_async_queue_new ();
+ task->priv->n_copies = 0;
+ task->priv->copies = NULL;
+
+ ufo_task_node_set_plugin_name (UFO_TASK_NODE (task), "output-task");
+}
diff --git a/ufo/ufo-output-task.h b/ufo/ufo-output-task.h
new file mode 100644
index 0000000..e1d07ff
--- /dev/null
+++ b/ufo/ufo-output-task.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_OUTPUT_TASK_H
+#define __UFO_OUTPUT_TASK_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_OUTPUT_TASK (ufo_output_task_get_type())
+#define UFO_OUTPUT_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_OUTPUT_TASK, UfoOutputTask))
+#define UFO_IS_OUTPUT_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_OUTPUT_TASK))
+#define UFO_OUTPUT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_OUTPUT_TASK, UfoOutputTaskClass))
+#define UFO_IS_OUTPUT_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_OUTPUT_TASK))
+#define UFO_OUTPUT_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_OUTPUT_TASK, UfoOutputTaskClass))
+
+typedef struct _UfoOutputTask UfoOutputTask;
+typedef struct _UfoOutputTaskClass UfoOutputTaskClass;
+typedef struct _UfoOutputTaskPrivate UfoOutputTaskPrivate;
+
+/**
+ * UfoOutputTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoOutputTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoOutputTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoOutputTaskPrivate *priv;
+};
+
+/**
+ * UfoOutputTaskClass:
+ *
+ * #UfoOutputTask class
+ */
+struct _UfoOutputTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode * ufo_output_task_new (guint n_dims);
+void ufo_output_task_get_output_requisition (UfoOutputTask *task,
+ UfoRequisition *requisition);
+UfoBuffer * ufo_output_task_get_output_buffer (UfoOutputTask *task);
+void ufo_output_task_release_output_buffer (UfoOutputTask *task,
+ UfoBuffer *buffer);
+GType ufo_output_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-plugin-manager.c b/ufo/ufo-plugin-manager.c
new file mode 100644
index 0000000..d45ea6c
--- /dev/null
+++ b/ufo/ufo-plugin-manager.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <gmodule.h>
+#include <glob.h>
+#include <ufo/ufo-plugin-manager.h>
+#include <ufo/ufo-configurable.h>
+#include <ufo/ufo-task-node.h>
+#include <ufo/ufo-dummy-task.h>
+
+/**
+ * SECTION:ufo-plugin-manager
+ * @Short_description: Load an #UfoFilter from a shared object
+ * @Title: UfoPluginManager
+ *
+ * The plugin manager opens shared object modules searched for in locations
+ * specified with ufo_plugin_manager_add_paths(). An #UfoFilter can be
+ * instantiated with ufo_plugin_manager_get_filter() with a one-to-one mapping
+ * between filter name xyz and module name libfilterxyz.so. Any errors are
+ * reported as one of #UfoPluginManagerError codes.
+ */
+
+G_DEFINE_TYPE_WITH_CODE (UfoPluginManager, ufo_plugin_manager, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL))
+
+#define UFO_PLUGIN_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_PLUGIN_MANAGER, UfoPluginManagerPrivate))
+
+typedef UfoNode* (* NewFunc) (void);
+
+struct _UfoPluginManagerPrivate {
+ GList *search_paths;
+ GSList *modules;
+ GHashTable *new_funcs; /**< maps from gchar* to NewFunc* */
+};
+
+enum {
+ PROP_0,
+ PROP_CONFIG,
+ N_PROPERTIES
+};
+
+/**
+ * UfoPluginManagerError:
+ * @UFO_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND: The module could not be found
+ * @UFO_PLUGIN_MANAGER_ERROR_MODULE_OPEN: Module could not be opened
+ * @UFO_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND: Necessary entry symbol was not
+ * found
+ *
+ * Possible errors that ufo_plugin_manager_get_filter() can return.
+ */
+GQuark
+ufo_plugin_manager_error_quark (void)
+{
+ return g_quark_from_static_string ("ufo-plugin-manager-error-quark");
+}
+
+static gchar *
+plugin_manager_get_path (UfoPluginManagerPrivate *priv, const gchar *name)
+{
+ /* Check first if filename is already a path */
+ if (g_path_is_absolute (name)) {
+ if (g_file_test (name, G_FILE_TEST_EXISTS))
+ return g_strdup (name);
+ else
+ return NULL;
+ }
+
+ /* If it is not a path, search in all known paths */
+ for (GList *p = g_list_first (priv->search_paths); p != NULL; p = g_list_next (p)) {
+ gchar *path = g_build_filename ((gchar *) p->data, name, NULL);
+
+ if (g_file_test (path, G_FILE_TEST_EXISTS))
+ return path;
+
+ g_free (path);
+ }
+
+ return NULL;
+}
+
+static void
+copy_config_paths (UfoPluginManagerPrivate *priv, UfoConfig *config)
+{
+ priv->search_paths = g_list_concat (ufo_config_get_paths (config), priv->search_paths);
+}
+
+/**
+ * ufo_plugin_manager_new:
+ * @config: (allow-none): A #UfoConfig object or %NULL.
+ *
+ * Create a plugin manager object to instantiate filter objects. When a config
+ * object is passed to the constructor, its search-path property is added to the
+ * internal search paths.
+ *
+ * Return value: A new plugin manager object.
+ */
+UfoPluginManager *
+ufo_plugin_manager_new (UfoConfig *config)
+{
+ UfoPluginManager *manager;
+
+ manager = UFO_PLUGIN_MANAGER (g_object_new (UFO_TYPE_PLUGIN_MANAGER,
+ "config", config,
+ NULL));
+
+ return manager;
+}
+
+static gchar *
+transform_string (const gchar *pattern,
+ const gchar *s,
+ const gchar *separator)
+{
+ gchar **sv;
+ gchar *transformed;
+ gchar *result;
+
+ sv = g_strsplit_set (s, "-_ ", -1);
+ transformed = g_strjoinv (separator, sv);
+ result = g_strdup_printf (pattern, transformed);
+
+ g_strfreev (sv);
+ g_free (transformed);
+ return result;
+}
+
+/**
+ * ufo_plugin_manager_get_task:
+ * @manager: A #UfoPluginManager
+ * @name: Name of the plugin.
+ * @error: return location for a GError or %NULL
+ *
+ * Load a #UfoFilter module and return an instance. The shared object name must
+ * be * constructed as "libfilter at name.so".
+ *
+ * Since: 0.2, the error parameter is available
+ *
+ * Returns: (transfer none): (allow-none): #UfoFilter or %NULL if module cannot be found
+ */
+UfoNode *
+ufo_plugin_manager_get_task (UfoPluginManager *manager, const gchar *name, GError **error)
+{
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) && (name != NULL), NULL);
+ UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
+ UfoNode *node;
+ NewFunc *func;
+ GModule *module;
+ gchar *func_name = NULL;
+ gchar *module_name = NULL;
+
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) && name != NULL, NULL);
+
+ if (!g_strcmp0 (name, "[dummy]"))
+ return ufo_dummy_task_new ();
+
+ func = g_hash_table_lookup (priv->new_funcs, name);
+
+ if (func == NULL) {
+ module_name = transform_string ("libufofilter%s.so", name, NULL);
+ func_name = transform_string ("ufo_%s_task_new", name, "_");
+
+ gchar *path = plugin_manager_get_path (priv, module_name);
+
+ if (path == NULL) {
+ g_set_error (error, UFO_PLUGIN_MANAGER_ERROR, UFO_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND,
+ "Module %s not found", module_name);
+ goto handle_error;
+ }
+
+ module = g_module_open (path, G_MODULE_BIND_LAZY);
+ g_free (path);
+
+ if (!module) {
+ g_set_error (error, UFO_PLUGIN_MANAGER_ERROR, UFO_PLUGIN_MANAGER_ERROR_MODULE_OPEN,
+ "Module %s could not be opened: %s", module_name, g_module_error ());
+ goto handle_error;
+ }
+
+ func = g_malloc0 (sizeof (NewFunc));
+
+ if (!g_module_symbol (module, func_name, (gpointer *) func)) {
+ g_set_error (error, UFO_PLUGIN_MANAGER_ERROR, UFO_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND,
+ "%s is not exported by module %s: %s", func_name, module_name, g_module_error ());
+ g_free (func);
+
+ if (!g_module_close (module))
+ g_warning ("%s", g_module_error ());
+
+ goto handle_error;
+ }
+
+ priv->modules = g_slist_append (priv->modules, module);
+ g_hash_table_insert (priv->new_funcs, g_strdup (name), func);
+
+ g_free (func_name);
+ g_free (module_name);
+ }
+
+ node = (*func) ();
+ ufo_task_node_set_plugin_name (UFO_TASK_NODE (node), name);
+ g_message ("UfoPluginManager: Created %s-%p", name, (gpointer) node);
+
+ return node;
+
+handle_error:
+ g_free (module_name);
+ g_free (func_name);
+ return NULL;
+}
+
+/**
+ * ufo_plugin_manager_get_all_task_names:
+ * @manager: A #UfoPluginManager
+ *
+ * Return a list with potential filter names that match shared objects in all
+ * search paths.
+ *
+ * Return value: (element-type utf8) (transfer full): List of strings with filter names
+ */
+GList *
+ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager)
+{
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager), NULL);
+ UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
+ GList *result = NULL;
+
+ GRegex *regex = g_regex_new ("libufofilter([A-Za-z]+).so", 0, 0, NULL);
+ GMatchInfo *match_info = NULL;
+
+ for (GList *path = g_list_first (priv->search_paths); path != NULL; path = g_list_next (path)) {
+ glob_t glob_vector;
+ gchar *pattern;
+
+ pattern = g_build_filename ((gchar *) path->data, "libufofilter*.so", NULL);
+ glob (pattern, GLOB_MARK | GLOB_TILDE, NULL, &glob_vector);
+ g_free (pattern);
+ gsize i = 0;
+
+ while (i < glob_vector.gl_pathc) {
+ g_regex_match (regex, glob_vector.gl_pathv[i], 0, &match_info);
+
+ if (g_match_info_matches (match_info)) {
+ gchar *word = g_match_info_fetch (match_info, 1);
+ result = g_list_append (result, word);
+ }
+
+ i++;
+ }
+ }
+
+ g_match_info_free (match_info);
+ g_regex_unref (regex);
+ return result;
+}
+
+static void
+ufo_plugin_manager_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_plugin_manager_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONFIG:
+ {
+ GObject *value_object;
+
+ value_object = g_value_get_object (value);
+
+ if (value_object != NULL) {
+ UfoConfig *config;
+
+ config = UFO_CONFIG (value_object);
+ copy_config_paths (UFO_PLUGIN_MANAGER_GET_PRIVATE (object), config);
+ }
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_plugin_manager_constructed (GObject *object)
+{
+ UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (object);
+
+ if (priv->search_paths == NULL) {
+ UfoConfig *config = ufo_config_new ();
+ copy_config_paths (priv, config);
+ g_object_unref (config);
+ }
+}
+
+static void
+ufo_plugin_manager_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_plugin_manager_parent_class)->dispose (object);
+ g_debug ("UfoPluginManager: disposed");
+}
+
+static void
+ufo_plugin_manager_finalize (GObject *gobject)
+{
+ UfoPluginManager *manager = UFO_PLUGIN_MANAGER (gobject);
+ UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
+
+ g_slist_foreach (priv->modules, (GFunc) g_module_close, NULL);
+ g_slist_free (priv->modules);
+
+ g_list_foreach (priv->search_paths, (GFunc) g_free, NULL);
+ g_list_free (priv->search_paths);
+
+ g_hash_table_destroy (priv->new_funcs);
+ G_OBJECT_CLASS (ufo_plugin_manager_parent_class)->finalize (gobject);
+ g_debug ("UfoPluginManager: finalized");
+}
+
+static void
+ufo_plugin_manager_class_init (UfoPluginManagerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->get_property = ufo_plugin_manager_get_property;
+ gobject_class->set_property = ufo_plugin_manager_set_property;
+ gobject_class->constructed = ufo_plugin_manager_constructed;
+ gobject_class->dispose = ufo_plugin_manager_dispose;
+ gobject_class->finalize = ufo_plugin_manager_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_CONFIG, "config");
+
+ g_type_class_add_private (klass, sizeof (UfoPluginManagerPrivate));
+}
+
+static void
+ufo_plugin_manager_init (UfoPluginManager *manager)
+{
+ UfoPluginManagerPrivate *priv;
+
+ manager->priv = priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
+ priv->modules = NULL;
+ priv->search_paths = NULL;
+ priv->new_funcs = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+}
diff --git a/ufo/ufo-plugin-manager.h b/ufo/ufo-plugin-manager.h
new file mode 100644
index 0000000..76c6570
--- /dev/null
+++ b/ufo/ufo-plugin-manager.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_PLUGIN_MANAGER_H
+#define __UFO_PLUGIN_MANAGER_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-configurable.h>
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_PLUGIN_MANAGER (ufo_plugin_manager_get_type())
+#define UFO_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_PLUGIN_MANAGER, UfoPluginManager))
+#define UFO_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_PLUGIN_MANAGER))
+#define UFO_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_PLUGIN_MANAGER, UfoPluginManagerClass))
+#define UFO_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_PLUGIN_MANAGER))
+#define UFO_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_PLUGIN_MANAGER, UfoPluginManagerClass))
+
+#define UFO_PLUGIN_MANAGER_ERROR ufo_plugin_manager_error_quark()
+GQuark ufo_plugin_manager_error_quark(void);
+
+typedef enum {
+ UFO_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND,
+ UFO_PLUGIN_MANAGER_ERROR_MODULE_OPEN,
+ UFO_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND
+} UfoPluginManagerError;
+
+typedef struct _UfoPluginManager UfoPluginManager;
+typedef struct _UfoPluginManagerClass UfoPluginManagerClass;
+typedef struct _UfoPluginManagerPrivate UfoPluginManagerPrivate;
+
+/**
+ * UfoPluginManager:
+ *
+ * Creates #UfoFilter instances by loading corresponding shared objects. The
+ * contents of the #UfoPluginManager structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UfoPluginManager {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoPluginManagerPrivate *priv;
+};
+
+/**
+ * UfoPluginManagerClass:
+ *
+ * #UfoPluginManager class
+ */
+struct _UfoPluginManagerClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoPluginManager * ufo_plugin_manager_new (UfoConfig *config);
+UfoNode * ufo_plugin_manager_get_task (UfoPluginManager *manager,
+ const gchar *name,
+ GError **error);
+GList * ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager);
+GType ufo_plugin_manager_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-profiler.c b/ufo/ufo-profiler.c
new file mode 100644
index 0000000..3a9e73e
--- /dev/null
+++ b/ufo/ufo-profiler.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <gmodule.h>
+#include <glob.h>
+
+#include <ufo/ufo-profiler.h>
+#include <ufo/ufo-resources.h>
+
+/**
+ * SECTION:ufo-profiler
+ * @Short_description: Profile different measures
+ * @Title: UfoProfiler
+ *
+ * The #UfoProfiler provides a drop-in replacement for a manual
+ * clEnqueueNDRangeKernel() call and tracks any associated events. The amount of
+ * profiling can be controlled with an #UfoProfilerLevel when constructing the
+ * profiler.
+ *
+ * Each #UfoFilter is assigned a profiler with ufo_profiler_set_profiler() by
+ * the managing #UfoBaseScheduler. Filter implementations should call
+ * ufo_filter_get_profiler() to receive their profiler and make profiled kernel
+ * calls with ufo_profiler_call().
+ *
+ * Moreover, a profiler object is used to measure wall clock time for I/O,
+ * synchronization and general CPU computation.
+ */
+
+G_DEFINE_TYPE(UfoProfiler, ufo_profiler, G_TYPE_OBJECT)
+
+#define UFO_PROFILER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_PROFILER, UfoProfilerPrivate))
+
+struct EventRow {
+ cl_event event;
+ cl_kernel kernel;
+};
+
+struct _UfoProfilerPrivate {
+ UfoProfilerLevel level;
+
+ GArray *event_array;
+ GTimer **timers;
+};
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+/**
+ * timer_level:
+ *
+ * Maps UfoProfilerTimer to a UfoProfilerLevel
+ */
+static UfoProfilerLevel timer_level[] = {
+ UFO_PROFILER_LEVEL_IO, /* TIMER_IO */
+ UFO_PROFILER_LEVEL_CPU, /* TIMER_CPU */
+ UFO_PROFILER_LEVEL_SYNC, /* TIMER_FETCH */
+ UFO_PROFILER_LEVEL_SYNC /* TIMER_RELEASE */
+};
+
+/**
+ * UfoProfilerLevel:
+ * @UFO_PROFILER_LEVEL_NONE: Do not track any profiling information
+ * @UFO_PROFILER_LEVEL_IO: Track I/O events
+ * @UFO_PROFILER_LEVEL_OPENCL: Track OpenCL events
+ * @UFO_PROFILER_LEVEL_CPU: Track general CPU time
+ * @UFO_PROFILER_LEVEL_SYNC: Track synchronization wait time
+ *
+ * Profiling levels that the profiler supports. To set the global profiling
+ * level use the #UfoConfiguration:profile-level: property on a
+ * #UfoConfiguration object set to the #UfoScheduler.
+ */
+
+/**
+ * UfoProfilerTimer:
+ * @UFO_PROFILER_TIMER_IO: Select I/O timer
+ * @UFO_PROFILER_TIMER_CPU: Select CPU timer
+ * @UFO_PROFILER_TIMER_FETCH: Select timer that measures the synchronization
+ * time to fetch data from the queues.
+ * @UFO_PROFILER_TIMER_RELEASE: Select timer that measures the synchronization
+ * time to push data to the queues.
+ * @UFO_PROFILER_TIMER_CPU: Select CPU timer
+ * @UFO_PROFILER_TIMER_LAST: Auxiliary value, do not use.
+ *
+ * Use these values to select a specific timer when calling
+ * ufo_profiler_start(), ufo_profiler_stop() and ufo_profiler_elapsed().
+ */
+
+/**
+ * ufo_profiler_new:
+ * @level: Amount of information that should be tracked by the profiler.
+ *
+ * Create a profiler object.
+ *
+ * Return value: A new profiler object.
+ */
+UfoProfiler *
+ufo_profiler_new (UfoProfilerLevel level)
+{
+ UfoProfiler *profiler;
+
+ profiler = UFO_PROFILER (g_object_new (UFO_TYPE_PROFILER, NULL));
+ profiler->priv->level = level;
+ return profiler;
+}
+
+/**
+ * ufo_profiler_call:
+ * @profiler: A #UfoProfiler object.
+ * @command_queue: A %cl_command_queue
+ * @kernel: A %cl_kernel
+ * @work_dim: Number of working dimensions.
+ * @global_work_size: Sizes of global dimensions. The array must have at least
+ * @work_dim entries.
+ * @local_work_size: Sizes of local work group dimensions. The array must have
+ * at least @work_dim entries.
+ *
+ * Execute the @kernel using the command queue and execution parameters. The
+ * event associated with the clEnqueueNDRangeKernel() call is recorded and may
+ * be used for profiling purposes later on.
+ */
+void
+ufo_profiler_call (UfoProfiler *profiler,
+ gpointer command_queue,
+ gpointer kernel,
+ guint work_dim,
+ const gsize *global_work_size,
+ const gsize *local_work_size)
+{
+ UfoProfilerPrivate *priv;
+ cl_event event;
+ cl_event *event_loc;
+ cl_int cl_err;
+ struct EventRow row;
+
+ priv = profiler->priv;
+ event_loc = priv->level & UFO_PROFILER_LEVEL_OPENCL ? &event : NULL;
+
+ cl_err = clEnqueueNDRangeKernel (command_queue,
+ kernel,
+ work_dim,
+ NULL,
+ global_work_size,
+ local_work_size,
+ 0, NULL, event_loc);
+ UFO_RESOURCES_CHECK_CLERR (cl_err);
+
+ if (priv->level & UFO_PROFILER_LEVEL_OPENCL) {
+ row.event = event;
+ row.kernel = kernel;
+ g_array_append_val (priv->event_array, row);
+ }
+}
+
+/**
+ * ufo_profiler_start:
+ * @profiler: A #UfoProfiler object.
+ * @timer: Which timer to start
+ *
+ * Start @timer. The timer is not reset but accumulates the time elapsed between
+ * ufo_profiler_start() and ufo_profiler_stop() calls.
+ */
+void
+ufo_profiler_start (UfoProfiler *profiler,
+ UfoProfilerTimer timer)
+{
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
+
+ if (profiler->priv->level & timer_level[timer])
+ g_timer_continue (profiler->priv->timers[timer]);
+}
+
+/**
+ * ufo_profiler_stop:
+ * @profiler: A #UfoProfiler object.
+ * @timer: Which timer to stop
+ *
+ * Stop @timer. The timer is not reset but accumulates the time elapsed between
+ * ufo_profiler_start() and ufo_profiler_stop() calls.
+ */
+void
+ufo_profiler_stop (UfoProfiler *profiler,
+ UfoProfilerTimer timer)
+{
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
+
+ if (profiler->priv->level & timer_level[timer])
+ g_timer_stop (profiler->priv->timers[timer]);
+}
+
+/**
+ * ufo_profiler_elapsed:
+ * @profiler: A #UfoProfiler object.
+ * @timer: Which timer to start
+ *
+ * Get the elapsed time in seconds for @timer.
+ *
+ * Returns: Elapsed time in seconds.
+ */
+gdouble
+ufo_profiler_elapsed (UfoProfiler *profiler,
+ UfoProfilerTimer timer)
+{
+ g_return_val_if_fail (UFO_IS_PROFILER (profiler), 0.0);
+ return g_timer_elapsed (profiler->priv->timers[timer], NULL);
+}
+
+static gchar *
+get_kernel_name (cl_kernel kernel)
+{
+ gsize size;
+ gchar *s;
+
+ clGetKernelInfo (kernel, CL_KERNEL_FUNCTION_NAME, 0, NULL, &size);
+ s = g_malloc0(size + 1);
+ clGetKernelInfo (kernel, CL_KERNEL_FUNCTION_NAME, size, s, NULL);
+ return s;
+}
+
+static void
+get_time_stamps (cl_event event, gulong *queued, gulong *submitted, gulong *start, gulong *end)
+{
+ clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, sizeof (cl_ulong), queued, NULL);
+ clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_SUBMIT, sizeof (cl_ulong), submitted, NULL);
+ clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_START, sizeof (cl_ulong), start, NULL);
+ clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END, sizeof (cl_ulong), end, NULL);
+}
+
+/**
+ * ufo_profiler_foreach:
+ * @profiler: A #UfoProfiler object.
+ * @func: (scope call): The function to be called for an entry
+ * @user_data: User parameters
+ *
+ * Iterates through the recorded events and calls @func for each entry.
+ */
+void
+ufo_profiler_foreach (UfoProfiler *profiler,
+ UfoProfilerFunc func,
+ gpointer user_data)
+{
+ UfoProfilerPrivate *priv;
+ struct EventRow *row;
+
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
+
+ priv = profiler->priv;
+
+ if (priv->level == UFO_PROFILER_LEVEL_NONE)
+ return;
+
+ for (guint i = 0; i < priv->event_array->len; i++) {
+ cl_command_queue queue;
+ gulong queued, submitted, start, end;
+ gchar *kernel_name;
+ gchar *row_string;
+
+ row = &g_array_index (priv->event_array, struct EventRow, i);
+
+ kernel_name = get_kernel_name (row->kernel);
+ clGetEventInfo (row->event, CL_EVENT_COMMAND_QUEUE, sizeof (cl_command_queue), &queue, NULL);
+ get_time_stamps (row->event, &queued, &submitted, &start, &end);
+
+ row_string = g_strdup_printf ("%s %p %lu %lu %lu %lu",
+ kernel_name,
+ (gpointer) queue,
+ queued, submitted, start, end);
+ func (row_string, user_data);
+
+ g_free (row_string);
+ g_free (kernel_name);
+ }
+}
+
+static void
+ufo_profiler_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_profiler_parent_class)->dispose (object);
+ g_message ("UfoProfiler: disposed");
+}
+
+static void
+ufo_profiler_finalize (GObject *object)
+{
+ UfoProfilerPrivate *priv;
+
+ G_OBJECT_CLASS (ufo_profiler_parent_class)->finalize (object);
+ priv = UFO_PROFILER_GET_PRIVATE (object);
+
+ g_array_free (priv->event_array, TRUE);
+
+ for (guint i = 0; i < UFO_PROFILER_TIMER_LAST; i++)
+ g_timer_destroy (priv->timers[i]);
+
+ g_free (priv->timers);
+
+ g_message ("UfoProfiler: finalized");
+}
+
+static void
+ufo_profiler_class_init (UfoProfilerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->dispose = ufo_profiler_dispose;
+ gobject_class->finalize = ufo_profiler_finalize;
+
+ g_type_class_add_private (klass, sizeof (UfoProfilerPrivate));
+}
+
+static void
+ufo_profiler_init (UfoProfiler *manager)
+{
+ UfoProfilerPrivate *priv;
+
+ manager->priv = priv = UFO_PROFILER_GET_PRIVATE (manager);
+ priv->event_array = g_array_sized_new (FALSE, TRUE, sizeof(struct EventRow), 2048);
+
+ /* Setup timers for all events */
+ priv->timers = g_new0 (GTimer *, UFO_PROFILER_TIMER_LAST);
+
+ for (guint i = 0; i < UFO_PROFILER_TIMER_LAST; i++) {
+ GTimer *timer;
+
+ timer = g_timer_new ();
+ g_timer_stop (timer);
+ g_timer_reset (timer);
+ priv->timers[i] = timer;
+ }
+
+ priv->level = UFO_PROFILER_LEVEL_NONE;
+}
diff --git a/ufo/ufo-profiler.h b/ufo/ufo-profiler.h
new file mode 100644
index 0000000..050e251
--- /dev/null
+++ b/ufo/ufo-profiler.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_PROFILER_H
+#define __UFO_PROFILER_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_PROFILER (ufo_profiler_get_type())
+#define UFO_PROFILER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_PROFILER, UfoProfiler))
+#define UFO_IS_PROFILER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_PROFILER))
+#define UFO_PROFILER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_PROFILER, UfoProfilerClass))
+#define UFO_IS_PROFILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_PROFILER))
+#define UFO_PROFILER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_PROFILER, UfoProfilerClass))
+
+typedef struct _UfoProfiler UfoProfiler;
+typedef struct _UfoProfilerClass UfoProfilerClass;
+typedef struct _UfoProfilerPrivate UfoProfilerPrivate;
+
+/**
+ * UfoProfiler:
+ *
+ * The #UfoProfiler collects and records OpenCL events and stores them in a
+ * convenient format on disk or prints summaries on screen.
+ */
+struct _UfoProfiler {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoProfilerPrivate *priv;
+};
+
+/**
+ * UfoProfilerFunc:
+ * @row: A string with profiling information for a certain event.
+ * @user_data: User data passed to ufo_profiler_foreach().
+ *
+ * Specifies the type of functions passed to ufo_profiler_foreach().
+ */
+typedef void (*UfoProfilerFunc) (const gchar *row, gpointer user_data);
+
+/**
+ * UfoProfilerClass:
+ *
+ * #UfoProfiler class
+ */
+struct _UfoProfilerClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+typedef enum {
+ UFO_PROFILER_TIMER_IO = 0,
+ UFO_PROFILER_TIMER_CPU,
+ UFO_PROFILER_TIMER_FETCH,
+ UFO_PROFILER_TIMER_RELEASE,
+ UFO_PROFILER_TIMER_LAST,
+} UfoProfilerTimer;
+
+typedef enum {
+ UFO_PROFILER_LEVEL_NONE = 0,
+ UFO_PROFILER_LEVEL_CPU = 1 << 0,
+ UFO_PROFILER_LEVEL_OPENCL = 1 << 1,
+ UFO_PROFILER_LEVEL_IO = 1 << 2,
+ UFO_PROFILER_LEVEL_SYNC = 1 << 3
+} UfoProfilerLevel;
+
+UfoProfiler *ufo_profiler_new (UfoProfilerLevel level);
+void ufo_profiler_call (UfoProfiler *profiler,
+ gpointer command_queue,
+ gpointer kernel,
+ guint work_dim,
+ const gsize *global_work_size,
+ const gsize *local_work_size);
+void ufo_profiler_foreach (UfoProfiler *profiler,
+ UfoProfilerFunc func,
+ gpointer user_data);
+void ufo_profiler_start (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+void ufo_profiler_stop (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+gdouble ufo_profiler_elapsed (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+GType ufo_profiler_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-remote-node.c b/ufo/ufo-remote-node.c
new file mode 100644
index 0000000..21d367a
--- /dev/null
+++ b/ufo/ufo-remote-node.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <zmq.h>
+#include <string.h>
+#include <ufo/ufo-remote-node.h>
+
+G_DEFINE_TYPE (UfoRemoteNode, ufo_remote_node, UFO_TYPE_NODE)
+
+#define UFO_REMOTE_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REMOTE_NODE, UfoRemoteNodePrivate))
+
+static void ufo_msg_send (UfoMessage *msg, gpointer socket, gint flags);
+static void receive_ack (gpointer socket);
+
+struct _UfoRemoteNodePrivate {
+ gpointer context;
+ gpointer socket;
+ guint n_inputs;
+ GMutex *mutex;
+};
+
+UfoNode *
+ufo_remote_node_new (gpointer zmq_context,
+ const gchar *address)
+{
+ UfoRemoteNode *node;
+ UfoRemoteNodePrivate *priv;
+
+ g_return_val_if_fail (zmq_context != NULL && address != NULL, NULL);
+ node = UFO_REMOTE_NODE (g_object_new (UFO_TYPE_REMOTE_NODE, NULL));
+ priv = node->priv;
+ priv->context = zmq_context;
+ priv->socket = zmq_socket (zmq_context, ZMQ_REQ);
+
+ if (zmq_connect (priv->socket, address) == 0) {
+ g_message ("Connected remote node to `%s' via socket=%p",
+ address,
+ priv->socket);
+ return UFO_NODE (node);
+ }
+ else {
+ g_warning ("Could not connect to `%s': %s",
+ address,
+ zmq_strerror (errno));
+ g_object_unref (node);
+ return NULL;
+ }
+}
+
+guint
+ufo_remote_node_get_num_gpus (UfoRemoteNode *node)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+ UfoMessage result;
+ zmq_msg_t reply;
+
+ g_return_val_if_fail (UFO_IS_REMOTE_NODE (node), 0);
+ priv = node->priv;
+
+ g_mutex_lock (priv->mutex);
+
+ request.type = UFO_MESSAGE_GET_NUM_DEVICES;
+ ufo_msg_send (&request, priv->socket, 0);
+
+ zmq_msg_init (&reply);
+ zmq_msg_recv (&reply, priv->socket, 0);
+ memcpy (&result, zmq_msg_data (&reply), sizeof (UfoMessage));
+ zmq_msg_close (&reply);
+
+ g_mutex_unlock (priv->mutex);
+
+ return result.d.n_devices;
+}
+
+void
+ufo_remote_node_request_setup (UfoRemoteNode *node)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request.type = UFO_MESSAGE_SETUP;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, 0);
+ receive_ack (priv->socket);
+
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_remote_node_send_json (UfoRemoteNode *node,
+ const gchar *json,
+ gsize size)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+ zmq_msg_t json_msg;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request.type = UFO_MESSAGE_TASK_JSON;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, ZMQ_SNDMORE);
+
+ zmq_msg_init_size (&json_msg, size);
+ memcpy (zmq_msg_data (&json_msg), json, size);
+ zmq_msg_send (&json_msg, priv->socket, 0);
+ zmq_msg_close (&json_msg);
+
+ receive_ack (priv->socket);
+
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_remote_node_get_structure (UfoRemoteNode *node,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+ UfoMessage *header;
+ zmq_msg_t header_msg;
+ zmq_msg_t payload_msg;
+ UfoInputParam *in_param;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ *mode = UFO_TASK_MODE_SINGLE;
+ request.type = UFO_MESSAGE_GET_STRUCTURE;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, 0);
+
+ /* Receive header */
+ zmq_msg_init (&header_msg);
+ zmq_msg_recv (&header_msg, priv->socket, 0);
+ header = (UfoMessage *) zmq_msg_data (&header_msg);
+
+ /* Receive payload */
+ zmq_msg_init (&payload_msg);
+ zmq_msg_recv (&payload_msg, priv->socket, 0);
+ in_param = (UfoInputParam *) zmq_msg_data (&payload_msg);
+
+ priv->n_inputs = header->d.n_inputs;
+ *n_inputs = header->d.n_inputs;
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = in_param->n_dims;
+
+ zmq_msg_close (&header_msg);
+ zmq_msg_close (&payload_msg);
+
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_remote_node_send_inputs (UfoRemoteNode *node,
+ UfoBuffer **inputs)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request.type = UFO_MESSAGE_SEND_INPUTS;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, ZMQ_SNDMORE);
+
+ /*
+ * For each of the input data items send two frames: the first one contains
+ * the size as an UfoRequisition struct and the second one the raw byte
+ * data.
+ */
+ for (guint i = 0; i < priv->n_inputs; i++) {
+ UfoRequisition requisition;
+ zmq_msg_t requisition_msg;
+ zmq_msg_t data_msg;
+ gsize size;
+ gint flags;
+
+ ufo_buffer_get_requisition (inputs[i], &requisition);
+ size = ufo_buffer_get_size (inputs[i]);
+
+ zmq_msg_init_size (&requisition_msg, sizeof (UfoRequisition));
+ zmq_msg_init_size (&data_msg, size);
+
+ memcpy (zmq_msg_data (&requisition_msg), &requisition, sizeof (UfoRequisition));
+ memcpy (zmq_msg_data (&data_msg), ufo_buffer_get_host_array (inputs[i], NULL), size);
+
+ flags = i == priv->n_inputs - 1 ? 0 : ZMQ_SNDMORE;
+ zmq_msg_send (&requisition_msg, priv->socket, ZMQ_SNDMORE);
+ zmq_msg_send (&data_msg, priv->socket, flags);
+
+ zmq_msg_close (&requisition_msg);
+ zmq_msg_close (&data_msg);
+ }
+
+ receive_ack (priv->socket);
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_remote_node_get_result (UfoRemoteNode *node,
+ UfoBuffer *buffer)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+ zmq_msg_t reply_msg;
+ gpointer host_array;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request.type = UFO_MESSAGE_GET_RESULT;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, 0);
+
+ /* Get the remote data and put it into our buffer */
+ zmq_msg_init (&reply_msg);
+ zmq_msg_recv (&reply_msg, priv->socket, 0);
+
+ ufo_buffer_discard_location (buffer, UFO_LOCATION_DEVICE);
+ host_array = ufo_buffer_get_host_array (buffer, NULL);
+ g_assert (ufo_buffer_get_size (buffer) == zmq_msg_size (&reply_msg));
+ memcpy (host_array, zmq_msg_data (&reply_msg), ufo_buffer_get_size (buffer));
+
+ zmq_msg_close (&reply_msg);
+
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_remote_node_get_requisition (UfoRemoteNode *node,
+ UfoRequisition *requisition)
+{
+ UfoRemoteNodePrivate *priv;
+ UfoMessage request;
+ zmq_msg_t reply_msg;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request.type = UFO_MESSAGE_GET_REQUISITION;
+
+ g_mutex_lock (priv->mutex);
+
+ ufo_msg_send (&request, priv->socket, 0);
+
+ zmq_msg_init (&reply_msg);
+ zmq_msg_recv (&reply_msg, priv->socket, 0);
+ g_assert (zmq_msg_size (&reply_msg) >= sizeof (UfoRequisition));
+ memcpy (requisition, zmq_msg_data (&reply_msg), sizeof (UfoRequisition));
+ zmq_msg_close (&reply_msg);
+
+ g_mutex_unlock (priv->mutex);
+}
+
+static void
+cleanup_remote (gpointer socket)
+{
+ UfoMessage request;
+
+ request.type = UFO_MESSAGE_CLEANUP;
+
+ ufo_msg_send (&request, socket, 0);
+ receive_ack (socket);
+}
+
+static void
+ufo_msg_send (UfoMessage *msg,
+ gpointer socket,
+ gint flags)
+{
+ zmq_msg_t request;
+
+ zmq_msg_init_size (&request, sizeof (UfoMessage));
+ memcpy (zmq_msg_data (&request), msg, sizeof (UfoMessage));
+ zmq_msg_send (&request, socket, flags);
+ zmq_msg_close (&request);
+}
+
+static void
+receive_ack (gpointer socket)
+{
+ zmq_msg_t reply_msg;
+
+ zmq_msg_init (&reply_msg);
+ zmq_msg_recv (&reply_msg, socket, 0);
+ zmq_msg_close (&reply_msg);
+}
+
+static void
+ufo_remote_node_dispose (GObject *object)
+{
+ UfoRemoteNodePrivate *priv;
+
+ priv = UFO_REMOTE_NODE_GET_PRIVATE (object);
+
+ if (priv->socket != NULL) {
+ cleanup_remote (priv->socket);
+
+ g_debug ("Close socket=%p", priv->socket);
+ zmq_close (priv->socket);
+ priv->socket = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_remote_node_parent_class)->dispose (object);
+}
+
+static void
+ufo_remote_node_finalize (GObject *object)
+{
+ UfoRemoteNodePrivate *priv;
+
+ priv = UFO_REMOTE_NODE_GET_PRIVATE (object);
+ g_mutex_free (priv->mutex);
+
+ G_OBJECT_CLASS (ufo_remote_node_parent_class)->finalize (object);
+}
+
+static void
+ufo_remote_node_class_init (UfoRemoteNodeClass *klass)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_remote_node_dispose;
+ oclass->finalize = ufo_remote_node_finalize;
+
+ g_type_class_add_private (klass, sizeof(UfoRemoteNodePrivate));
+}
+
+static void
+ufo_remote_node_init (UfoRemoteNode *self)
+{
+ UfoRemoteNodePrivate *priv;
+ self->priv = priv = UFO_REMOTE_NODE_GET_PRIVATE (self);
+ priv->context = NULL;
+ priv->socket = NULL;
+ priv->n_inputs = 0;
+ priv->mutex = g_mutex_new ();
+}
diff --git a/ufo/ufo-remote-node.h b/ufo/ufo-remote-node.h
new file mode 100644
index 0000000..ad2bf63
--- /dev/null
+++ b/ufo/ufo-remote-node.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_REMOTE_NODE_H
+#define __UFO_REMOTE_NODE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-node.h>
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-task-iface.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_REMOTE_NODE (ufo_remote_node_get_type())
+#define UFO_REMOTE_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_REMOTE_NODE, UfoRemoteNode))
+#define UFO_IS_REMOTE_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_REMOTE_NODE))
+#define UFO_REMOTE_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_REMOTE_NODE, UfoRemoteNodeClass))
+#define UFO_IS_REMOTE_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_REMOTE_NODE))
+#define UFO_REMOTE_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_REMOTE_NODE, UfoRemoteNodeClass))
+
+typedef struct _UfoRemoteNode UfoRemoteNode;
+typedef struct _UfoRemoteNodeClass UfoRemoteNodeClass;
+typedef struct _UfoRemoteNodePrivate UfoRemoteNodePrivate;
+typedef struct _UfoMessage UfoMessage;
+
+/**
+ * UfoRemoteNode:
+ *
+ * Main object for organizing filters. The contents of the #UfoRemoteNode structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoRemoteNode {
+ /*< private >*/
+ UfoNode parent_instance;
+
+ UfoRemoteNodePrivate *priv;
+};
+
+/**
+ * UfoRemoteNodeClass:
+ *
+ * #UfoRemoteNode class
+ */
+struct _UfoRemoteNodeClass {
+ /*< private >*/
+ UfoNodeClass parent_class;
+};
+
+/**
+ * UfoMessageType: (skip)
+ * @UFO_MESSAGE_TASK_JSON: insert
+ * @UFO_MESSAGE_GET_NUM_DEVICES: insert
+ * @UFO_MESSAGE_SETUP: insert
+ * @UFO_MESSAGE_GET_STRUCTURE: insert
+ * @UFO_MESSAGE_STRUCTURE: insert
+ * @UFO_MESSAGE_GET_REQUISITION: insert
+ * @UFO_MESSAGE_REQUISITION: insert
+ * @UFO_MESSAGE_SEND_INPUTS: insert
+ * @UFO_MESSAGE_GET_RESULT: insert
+ * @UFO_MESSAGE_RESULT: insert
+ * @UFO_MESSAGE_CLEANUP: insert
+ * @UFO_MESSAGE_ACK: insert
+ */
+typedef enum {
+ UFO_MESSAGE_TASK_JSON = 0,
+ UFO_MESSAGE_GET_NUM_DEVICES,
+ UFO_MESSAGE_SETUP,
+ UFO_MESSAGE_GET_STRUCTURE,
+ UFO_MESSAGE_STRUCTURE,
+ UFO_MESSAGE_GET_REQUISITION,
+ UFO_MESSAGE_REQUISITION,
+ UFO_MESSAGE_SEND_INPUTS,
+ UFO_MESSAGE_GET_RESULT,
+ UFO_MESSAGE_RESULT,
+ UFO_MESSAGE_CLEANUP,
+ UFO_MESSAGE_ACK
+} UfoMessageType;
+
+/**
+ * UfoMessage: (skip)
+ * @type: Type of the wire message
+ */
+struct _UfoMessage {
+ UfoMessageType type;
+
+ union {
+ guint16 n_inputs;
+ guint16 n_devices;
+ } d;
+};
+
+UfoNode *ufo_remote_node_new (gpointer zmq_context,
+ const gchar *address);
+guint ufo_remote_node_get_num_gpus (UfoRemoteNode *node);
+void ufo_remote_node_request_setup (UfoRemoteNode *node);
+void ufo_remote_node_send_json (UfoRemoteNode *node,
+ const gchar *json,
+ gsize size);
+void ufo_remote_node_get_structure (UfoRemoteNode *node,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode);
+void ufo_remote_node_send_inputs (UfoRemoteNode *node,
+ UfoBuffer **inputs);
+void ufo_remote_node_get_result (UfoRemoteNode *node,
+ UfoBuffer *result);
+void ufo_remote_node_get_requisition (UfoRemoteNode *node,
+ UfoRequisition *requisition);
+void ufo_remote_node_cleanup (UfoRemoteNode *node);
+GType ufo_remote_node_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-remote-task.c b/ufo/ufo-remote-task.c
new file mode 100644
index 0000000..5aa54b9
--- /dev/null
+++ b/ufo/ufo-remote-task.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gmodule.h>
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <ufo/ufo-remote-task.h>
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-cpu-task-iface.h>
+
+/**
+ * SECTION:ufo-remote-task
+ * @Short_description: Encapsulate remote tasks
+ * @Title: UfoRemoteTask
+ */
+
+struct _UfoRemoteTaskPrivate {
+ UfoRemoteNode *remote;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_cpu_task_interface_init (UfoCpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoRemoteTask, ufo_remote_task, UFO_TYPE_TASK_NODE,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+ ufo_task_interface_init)
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CPU_TASK,
+ ufo_cpu_task_interface_init))
+
+#define UFO_REMOTE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REMOTE_TASK, UfoRemoteTaskPrivate))
+
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+UfoNode *
+ufo_remote_task_new (void)
+{
+ return UFO_NODE (g_object_new (UFO_TYPE_REMOTE_TASK, NULL));
+}
+
+static void
+ufo_remote_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ UfoRemoteTaskPrivate *priv;
+
+ priv = UFO_REMOTE_TASK_GET_PRIVATE (UFO_REMOTE_TASK (task));
+ priv->remote = UFO_REMOTE_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
+ g_assert (priv->remote != NULL);
+ ufo_remote_node_get_num_gpus (priv->remote);
+ ufo_remote_node_request_setup (priv->remote);
+}
+
+static void
+ufo_remote_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ UfoRemoteTaskPrivate *priv;
+
+ priv = UFO_REMOTE_TASK_GET_PRIVATE (UFO_REMOTE_TASK (task));
+
+ /*
+ * We send our input to the remote node which will execute immediately.
+ * After remote execution, we will know the requisition of the _last_ remote
+ * task node and can get it back.
+ */
+ ufo_remote_node_send_inputs (priv->remote, inputs);
+ ufo_remote_node_get_requisition (priv->remote, requisition);
+}
+
+static void
+ufo_remote_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ UfoRemoteTaskPrivate *priv;
+
+ priv = UFO_REMOTE_TASK_GET_PRIVATE (UFO_REMOTE_TASK (task));
+ ufo_remote_node_get_structure (priv->remote, n_inputs, in_params, mode);
+}
+
+static gboolean
+ufo_remote_task_process (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
+{
+ UfoRemoteTaskPrivate *priv;
+ priv = UFO_REMOTE_TASK_GET_PRIVATE (UFO_REMOTE_TASK (task));
+
+ ufo_remote_node_get_result (priv->remote, output);
+ return TRUE;
+}
+
+static void
+ufo_remote_task_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_remote_task_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_remote_task_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_remote_task_parent_class)->dispose (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+ iface->setup = ufo_remote_task_setup;
+ iface->get_structure = ufo_remote_task_get_structure;
+ iface->get_requisition = ufo_remote_task_get_requisition;
+}
+
+static void
+ufo_cpu_task_interface_init (UfoCpuTaskIface *iface)
+{
+ iface->process = ufo_remote_task_process;
+}
+
+static void
+ufo_remote_task_class_init (UfoRemoteTaskClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ oclass->set_property = ufo_remote_task_set_property;
+ oclass->get_property = ufo_remote_task_get_property;
+ oclass->dispose = ufo_remote_task_dispose;
+
+ g_type_class_add_private (oclass, sizeof(UfoRemoteTaskPrivate));
+}
+
+static void
+ufo_remote_task_init(UfoRemoteTask *self)
+{
+ self->priv = UFO_REMOTE_TASK_GET_PRIVATE(self);
+}
diff --git a/ufo/ufo-remote-task.h b/ufo/ufo-remote-task.h
new file mode 100644
index 0000000..3fed504
--- /dev/null
+++ b/ufo/ufo-remote-task.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_REMOTE_TASK_H
+#define __UFO_REMOTE_TASK_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_REMOTE_TASK (ufo_remote_task_get_type())
+#define UFO_REMOTE_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_REMOTE_TASK, UfoRemoteTask))
+#define UFO_IS_REMOTE_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_REMOTE_TASK))
+#define UFO_REMOTE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_REMOTE_TASK, UfoRemoteTaskClass))
+#define UFO_IS_REMOTE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_REMOTE_TASK))
+#define UFO_REMOTE_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_REMOTE_TASK, UfoRemoteTaskClass))
+
+typedef struct _UfoRemoteTask UfoRemoteTask;
+typedef struct _UfoRemoteTaskClass UfoRemoteTaskClass;
+typedef struct _UfoRemoteTaskPrivate UfoRemoteTaskPrivate;
+
+/**
+ * UfoRemoteTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoRemoteTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoRemoteTask {
+ /*< private >*/
+ UfoTaskNode parent_instance;
+
+ UfoRemoteTaskPrivate *priv;
+};
+
+/**
+ * UfoRemoteTaskClass:
+ *
+ * #UfoRemoteTask class
+ */
+struct _UfoRemoteTaskClass {
+ /*< private >*/
+ UfoTaskNodeClass parent_class;
+};
+
+UfoNode *ufo_remote_task_new (void);
+GType ufo_remote_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-resources.c b/ufo/ufo-resources.c
new file mode 100644
index 0000000..d8295e7
--- /dev/null
+++ b/ufo/ufo-resources.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <stdio.h>
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <ufo/ufo-resources.h>
+#include <ufo/ufo-configurable.h>
+
+/**
+ * SECTION:ufo-resources
+ * @Short_description: Manage OpenCL resources
+ * @Title: UfoResources
+ *
+ * The #UfoResources creates the OpenCL environment and loads OpenCL
+ * kernels from text files.
+ */
+
+G_DEFINE_TYPE_WITH_CODE (UfoResources, ufo_resources, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL))
+
+#define UFO_RESOURCES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_RESOURCES, UfoResourcesPrivate))
+
+/**
+ * UfoResourcesError:
+ * @UFO_RESOURCES_ERROR_LOAD_PROGRAM: Could not load the OpenCL file
+ * @UFO_RESOURCES_ERROR_CREATE_PROGRAM: Could not create a program from
+ * the sources
+ * @UFO_RESOURCES_ERROR_BUILD_PROGRAM: Could not build program from
+ * sources
+ * @UFO_RESOURCES_ERROR_CREATE_KERNEL: Could not create kernel
+ *
+ * OpenCL related errors.
+ */
+GQuark
+ufo_resources_error_quark (void)
+{
+ return g_quark_from_static_string ("ufo-resource-resources-error-quark");
+}
+
+struct _UfoResourcesPrivate {
+ UfoConfig *config;
+
+ cl_uint num_platforms;
+ cl_platform_id *opencl_platforms;
+ cl_context opencl_context;
+ cl_uint *num_devices; /**< Number of OpenCL devices per platform id */
+ cl_device_id **opencl_devices; /**< Array of OpenCL devices per platform id */
+ cl_command_queue *command_queues; /**< Array of command queues per device */
+
+ GList *kernel_paths; /**< Colon-separated string with paths to kernel files */
+ GHashTable *opencl_programs; /**< Map from filename to cl_program */
+ GList *opencl_kernels;
+ GString *opencl_build_options;
+ GString *include_paths; /**< List of include paths "-I/foo/bar" built from added paths */
+};
+
+enum {
+ PROP_0,
+ PROP_CONFIG,
+ N_PROPERTIES
+};
+
+const gchar *opencl_error_msgs[] = {
+ "CL_SUCCESS",
+ "CL_DEVICE_NOT_FOUND",
+ "CL_DEVICE_NOT_AVAILABLE",
+ "CL_COMPILER_NOT_AVAILABLE",
+ "CL_MEM_OBJECT_ALLOCATION_FAILURE",
+ "CL_OUT_OF_RESOURCES",
+ "CL_OUT_OF_HOST_MEMORY",
+ "CL_PROFILING_INFO_NOT_AVAILABLE",
+ "CL_MEM_COPY_OVERLAP",
+ "CL_IMAGE_FORMAT_MISMATCH",
+ "CL_IMAGE_FORMAT_NOT_SUPPORTED",
+ "CL_BUILD_PROGRAM_FAILURE",
+ "CL_MAP_FAILURE",
+ "CL_MISALIGNED_SUB_BUFFER_OFFSET",
+ "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST",
+
+ /* next IDs start at 30! */
+ "CL_INVALID_VALUE",
+ "CL_INVALID_DEVICE_TYPE",
+ "CL_INVALID_PLATFORM",
+ "CL_INVALID_DEVICE",
+ "CL_INVALID_CONTEXT",
+ "CL_INVALID_QUEUE_PROPERTIES",
+ "CL_INVALID_COMMAND_QUEUE",
+ "CL_INVALID_HOST_PTR",
+ "CL_INVALID_MEM_OBJECT",
+ "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
+ "CL_INVALID_IMAGE_SIZE",
+ "CL_INVALID_SAMPLER",
+ "CL_INVALID_BINARY",
+ "CL_INVALID_BUILD_OPTIONS",
+ "CL_INVALID_PROGRAM",
+ "CL_INVALID_PROGRAM_EXECUTABLE",
+ "CL_INVALID_KERNEL_NAME",
+ "CL_INVALID_KERNEL_DEFINITION",
+ "CL_INVALID_KERNEL",
+ "CL_INVALID_ARG_INDEX",
+ "CL_INVALID_ARG_VALUE",
+ "CL_INVALID_ARG_SIZE",
+ "CL_INVALID_KERNEL_ARGS",
+ "CL_INVALID_WORK_DIMENSION",
+ "CL_INVALID_WORK_GROUP_SIZE",
+ "CL_INVALID_WORK_ITEM_SIZE",
+ "CL_INVALID_GLOBAL_OFFSET",
+ "CL_INVALID_EVENT_WAIT_LIST",
+ "CL_INVALID_EVENT",
+ "CL_INVALID_OPERATION",
+ "CL_INVALID_GL_OBJECT",
+ "CL_INVALID_BUFFER_SIZE",
+ "CL_INVALID_MIP_LEVEL",
+ "CL_INVALID_GLOBAL_WORK_SIZE"
+};
+
+/**
+ * ufo_resources_clerr:
+ * @error: An OpenCL error code
+ *
+ * Get a human-readable string representation of @error.
+ *
+ * Returns: (transfer none): A static string of @error.
+ */
+const gchar *
+ufo_resources_clerr (int error)
+{
+ static const gchar *invalid = "Invalid error code";
+ const gint array_size = sizeof opencl_error_msgs/sizeof(gchar*);
+ gint index;
+
+ index = error >= -14 ? -error : -error-15;
+
+ if (index >= 0 && index < array_size)
+ return opencl_error_msgs[index];
+
+ return invalid;
+}
+
+static gchar *
+resources_load_opencl_program (const gchar *filename)
+{
+ FILE *fp = fopen (filename, "r");
+
+ if (fp == NULL)
+ return NULL;
+
+ fseek (fp, 0, SEEK_END);
+ const gsize length = (gsize) ftell (fp);
+ rewind (fp);
+ gchar *buffer = (gchar *) g_malloc0(length + 1);
+
+ if (buffer == NULL) {
+ fclose (fp);
+ return NULL;
+ }
+
+ size_t buffer_length = fread (buffer, 1, length, fp);
+ fclose (fp);
+
+ if (buffer_length != length) {
+ g_free (buffer);
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static void
+resources_release_kernel (cl_kernel kernel)
+{
+ UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (kernel));
+}
+
+static void
+resources_release_program (cl_program program)
+{
+ UFO_RESOURCES_CHECK_CLERR (clReleaseProgram (program));
+}
+
+static gchar *
+resources_find_path (UfoResourcesPrivate *priv, const gchar *filename)
+{
+ /* Check first if filename is already a path */
+ if (g_path_is_absolute (filename)) {
+ if (g_file_test (filename, G_FILE_TEST_EXISTS))
+ return g_strdup (filename);
+ else
+ return NULL;
+ }
+
+ /* If it is not a path, search in all paths that were added */
+ GList *elem = g_list_first (priv->kernel_paths);
+
+ while (elem != NULL) {
+ gchar *path = g_strdup_printf ("%s%c%s", (gchar *) elem->data, G_DIR_SEPARATOR, filename);
+
+ if (g_file_test (path, G_FILE_TEST_EXISTS))
+ return path;
+
+ g_free (path);
+ elem = g_list_next (elem);
+ }
+
+ return NULL;
+}
+
+/**
+ * ufo_resources_new:
+ * @config: A #UfoConfiguration object or %NULL
+ *
+ * Create a new #UfoResources instance.
+ *
+ * Returns: (transfer none): A new #UfoResources
+ */
+UfoResources *
+ufo_resources_new (UfoConfig *config)
+{
+ return UFO_RESOURCES (g_object_new (UFO_TYPE_RESOURCES,
+ "config", config,
+ NULL));
+}
+
+static void
+append_include_path (gchar *path,
+ GString *directive)
+{
+ g_string_append_printf (directive, " -I%s", path);
+}
+
+static cl_program
+add_program_from_source (UfoResourcesPrivate *priv,
+ const gchar *source,
+ const gchar *options,
+ GError **error)
+{
+ cl_program program;
+ gchar *build_options = NULL;
+ cl_int errcode = CL_SUCCESS;
+
+ program = clCreateProgramWithSource (priv->opencl_context,
+ 1, &source, NULL, &errcode);
+
+ if (errcode != CL_SUCCESS) {
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_CREATE_PROGRAM,
+ "Failed to create OpenCL program: %s", ufo_resources_clerr (errcode));
+ return NULL;
+ }
+
+ if (options != NULL)
+ build_options = g_strdup_printf ("%s %s %s", priv->opencl_build_options->str, priv->include_paths->str, options);
+ else
+ build_options = g_strdup_printf ("%s %s", priv->opencl_build_options->str, priv->include_paths->str);
+
+ errcode = clBuildProgram (program,
+ priv->num_devices[0],
+ priv->opencl_devices[0],
+ build_options,
+ NULL, NULL);
+
+ g_free (build_options);
+
+ if (errcode != CL_SUCCESS) {
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_BUILD_PROGRAM,
+ "Failed to build OpenCL program: %s", ufo_resources_clerr (errcode));
+
+ const gsize LOG_SIZE = 4096;
+ gchar *log = (gchar *) g_malloc0(LOG_SIZE * sizeof (char));
+ UFO_RESOURCES_CHECK_CLERR (clGetProgramBuildInfo (program,
+ priv->opencl_devices[0][0],
+ CL_PROGRAM_BUILD_LOG,
+ LOG_SIZE, (void *) log, NULL));
+ g_print ("\n=== Build log for s===%s\n\n", log);
+ g_free (log);
+ return NULL;
+ }
+
+ return program;
+}
+
+static cl_program
+resources_add_program (UfoResources *resources, const gchar *filename, const gchar *options, GError **error)
+{
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources) || (filename != NULL), FALSE);
+ UfoResourcesPrivate *priv = resources->priv;
+
+ /* Programs might be added multiple times if this is not locked */
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+ g_static_mutex_lock (&mutex);
+
+ /* Don't process the kernel file again, if already load */
+ cl_program program = g_hash_table_lookup (priv->opencl_programs, filename);
+
+ if (program != NULL) {
+ g_static_mutex_unlock (&mutex);
+ return program;
+ }
+
+ gchar *path = resources_find_path (priv, filename);
+
+ if (path == NULL) {
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_LOAD_PROGRAM,
+ "Could not find `%s'. Maybe you forgot to pass a configuration?", filename);
+ g_static_mutex_unlock (&mutex);
+ return NULL;
+ }
+
+ gchar *buffer = resources_load_opencl_program (path);
+ g_free (path);
+
+ if (buffer == NULL) {
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_LOAD_PROGRAM,
+ "Could not open `%s'", filename);
+ g_static_mutex_unlock (&mutex);
+ return NULL;
+ }
+
+ program = add_program_from_source (priv, buffer, options, error);
+ g_message ("Added program %p from `%s`", (gpointer) program, filename);
+
+ if (program != NULL)
+ g_hash_table_insert (priv->opencl_programs, g_strdup (filename), program);
+
+ g_static_mutex_unlock (&mutex);
+ g_free (buffer);
+ return program;
+}
+
+static cl_kernel
+resources_get_kernel (UfoResourcesPrivate *priv,
+ cl_program program,
+ const gchar *kernel_name,
+ GError **error)
+{
+ cl_int errcode = CL_SUCCESS;
+ cl_kernel kernel = clCreateKernel (program, kernel_name, &errcode);
+
+ if (kernel == NULL || errcode != CL_SUCCESS) {
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_CREATE_KERNEL,
+ "Failed to create kernel `%s`: %s", kernel_name, ufo_resources_clerr (errcode));
+ return NULL;
+ }
+
+ priv->opencl_kernels = g_list_append (priv->opencl_kernels, kernel);
+ return kernel;
+}
+
+/**
+ * ufo_resources_get_kernel:
+ * @resources: A #UfoResources object
+ * @filename: Name of the .cl kernel file
+ * @kernel: Name of a kernel
+ * @error: Return location for a GError from #UfoResourcesError, or NULL
+ *
+ * Loads a and builds a kernel from a file. The file is searched in the current
+ * working directory and all paths added through
+ * ufo_resources_add_paths ().
+ *
+ * Returns: (transfer none): a cl_kernel object that is load from @filename or %NULL on error
+ */
+gpointer
+ufo_resources_get_kernel (UfoResources *resources,
+ const gchar *filename,
+ const gchar *kernel,
+ GError **error)
+{
+ UfoResourcesPrivate *priv;
+ cl_program program;
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources) &&
+ (filename != NULL) &&
+ (kernel != NULL), NULL);
+
+ priv = resources->priv;
+ program = resources_add_program (resources, filename, "", &tmp_error);
+
+ if (program == NULL) {
+ g_propagate_error (error, tmp_error);
+ return NULL;
+ }
+
+ return resources_get_kernel (priv, program, kernel, error);
+}
+
+/**
+ * ufo_resources_get_kernel_from_source:
+ * @resources: A #UfoResources
+ * @source: OpenCL source string
+ * @kernel: Name of a kernel
+ * @error: Return location for a GError from #UfoResourcesError, or NULL
+ *
+ * Loads and builds a kernel from a string.
+ *
+ * Returns: (transfer none): a cl_kernel object that is load from @filename
+ */
+gpointer
+ufo_resources_get_kernel_from_source (UfoResources *resources,
+ const gchar *source,
+ const gchar *kernel,
+ GError **error)
+{
+ UfoResourcesPrivate *priv;
+ cl_program program;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources) &&
+ (source != NULL) &&
+ (kernel != NULL), NULL);
+
+ priv = UFO_RESOURCES_GET_PRIVATE (resources);
+ program = add_program_from_source (priv, source, NULL, error);
+
+ /*
+ * We add the program under a fake file name. This looks very brittle to me
+ * (kernel name could be the same as a source filename) but it should work
+ * in most cases.
+ */
+ if (program != NULL)
+ g_hash_table_insert (priv->opencl_programs, g_strdup (kernel), program);
+ else
+ return NULL;
+
+ return resources_get_kernel (priv, program, kernel, error);
+}
+
+/**
+ * ufo_resources_get_context: (skip)
+ * @resources: A #UfoResources
+ *
+ * Returns the OpenCL context object that is used by the resource resources. This
+ * context can be used to initialize othe third-party libraries.
+ *
+ * Return value: A cl_context object.
+ */
+gpointer
+ufo_resources_get_context (UfoResources *resources)
+{
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources), NULL);
+ return resources->priv->opencl_context;
+}
+
+/**
+ * ufo_resources_get_cmd_queues:
+ * @resources: A #UfoResources
+ *
+ * Get all command queues managed by @resources.
+ *
+ * Return value: (element-type gpointer) (transfer container): List with
+ * cl_command_queue objects. Free with g_list_free() but not its elements.
+ */
+GList *
+ufo_resources_get_cmd_queues (UfoResources *resources)
+{
+ UfoResourcesPrivate *priv;
+ GList *result = NULL;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources), NULL);
+ priv = resources->priv;
+
+ for (guint i = 0; i < priv->num_devices[0]; i++)
+ result = g_list_append (result, priv->command_queues[i]);
+
+ return result;
+}
+
+static void
+ufo_resources_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoResourcesPrivate *priv = UFO_RESOURCES_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_CONFIG:
+ {
+ GObject *value_object = g_value_get_object (value);
+
+ if (priv->config)
+ g_object_unref (priv->config);
+
+ if (value_object != NULL) {
+ UfoConfig *config;
+ GList *paths;
+
+ config = UFO_CONFIG (value_object);
+ paths = ufo_config_get_paths (config);
+ priv->kernel_paths = g_list_concat (priv->kernel_paths, paths);
+ g_list_foreach (paths, (GFunc) append_include_path, priv->include_paths);
+ g_object_ref (config);
+ priv->config = config;
+ }
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_resources_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoResourcesPrivate *priv = UFO_RESOURCES_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_CONFIG:
+ g_value_set_object (value, priv->config);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_resources_dispose (GObject *object)
+{
+ UfoResourcesPrivate *priv = UFO_RESOURCES_GET_PRIVATE (object);
+
+ if (priv->config) {
+ g_object_unref (priv->config);
+ priv->config = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_resources_parent_class)->finalize (object);
+}
+
+static void
+ufo_resources_finalize (GObject *object)
+{
+ UfoResourcesPrivate *priv = UFO_RESOURCES_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->opencl_programs);
+ g_list_foreach (priv->kernel_paths, (GFunc) g_free, NULL);
+ g_list_free (priv->kernel_paths);
+ g_list_foreach (priv->opencl_kernels, (GFunc) resources_release_kernel, NULL);
+ g_list_free (priv->opencl_kernels);
+
+ for (guint i = 0; i < priv->num_devices[0]; i++)
+ UFO_RESOURCES_CHECK_CLERR (clReleaseCommandQueue (priv->command_queues[i]));
+
+ UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->opencl_context));
+
+ g_string_free (priv->opencl_build_options, TRUE);
+ g_string_free (priv->include_paths, TRUE);
+
+ for (guint i = 0; i < priv->num_platforms; i ++)
+ g_free (priv->opencl_devices[i]);
+
+ g_free (priv->num_devices);
+ g_free (priv->opencl_devices);
+ g_free (priv->opencl_platforms);
+ g_free (priv->command_queues);
+
+ priv->num_devices = NULL;
+ priv->opencl_kernels = NULL;
+ priv->opencl_devices = NULL;
+ priv->opencl_platforms = NULL;
+
+ G_OBJECT_CLASS (ufo_resources_parent_class)->finalize (object);
+ g_debug ("UfoResources: finalized");
+}
+
+static void
+ufo_resources_class_init (UfoResourcesClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = ufo_resources_set_property;
+ gobject_class->get_property = ufo_resources_get_property;
+ gobject_class->dispose = ufo_resources_dispose;
+ gobject_class->finalize = ufo_resources_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_CONFIG, "config");
+
+ g_type_class_add_private (klass, sizeof (UfoResourcesPrivate));
+}
+
+static void
+ufo_resources_init (UfoResources *self)
+{
+ UfoResourcesPrivate *priv;
+ self->priv = priv = UFO_RESOURCES_GET_PRIVATE (self);
+
+ priv->config = NULL;
+ priv->opencl_programs = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) resources_release_program);
+ priv->opencl_kernels = NULL;
+ priv->opencl_platforms = NULL;
+ priv->opencl_build_options = g_string_new ("-cl-mad-enable ");
+ priv->include_paths = g_string_new ("-I. ");
+
+ priv->kernel_paths = g_list_append (NULL, g_strdup ("."));
+ priv->kernel_paths = g_list_append (priv->kernel_paths, g_strdup (UFO_PLUGIN_DIR));
+
+ /* initialize OpenCL subsystem */
+ int errcode = CL_SUCCESS;
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (0, NULL, &priv->num_platforms));
+ priv->opencl_platforms = g_malloc0(priv->num_platforms * sizeof (cl_platform_id));
+
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (priv->num_platforms, priv->opencl_platforms, NULL));
+ priv->num_devices = g_malloc0(priv->num_platforms * sizeof (cl_uint));
+ priv->opencl_devices = g_malloc0(priv->num_platforms * sizeof (cl_device_id *));
+
+ /* Get devices for each available platform */
+ gchar *info_buffer = g_malloc0 (256);
+
+ for (guint i = 0; i < priv->num_platforms; i++) {
+ cl_uint num_devices;
+ cl_platform_id platform = priv->opencl_platforms[i];
+
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformInfo (platform, CL_PLATFORM_VENDOR, 256, info_buffer, NULL));
+
+ if (g_str_has_prefix (info_buffer, "NVIDIA"))
+ g_string_append (priv->opencl_build_options, "-cl-nv-verbose -DVENDOR=NVIDIA");
+ else if (g_str_has_prefix (info_buffer, "Advanced Micro Devices"))
+ g_string_append (priv->opencl_build_options, "-DVENDOR=AMD");
+
+ UFO_RESOURCES_CHECK_CLERR (clGetDeviceIDs (platform,
+ CL_DEVICE_TYPE_ALL,
+ 0, NULL,
+ &num_devices));
+ priv->opencl_devices[i] = g_malloc0 (num_devices * sizeof (cl_device_id));
+
+ UFO_RESOURCES_CHECK_CLERR (clGetDeviceIDs (platform,
+ CL_DEVICE_TYPE_ALL,
+ num_devices, priv->opencl_devices[i],
+ NULL));
+ priv->num_devices[i] = num_devices;
+ }
+
+ g_free (info_buffer);
+ cl_command_queue_properties queue_properties = CL_QUEUE_PROFILING_ENABLE;
+
+ /* XXX: create context for each platform?! */
+ if (priv->num_platforms > 0) {
+ priv->opencl_context = clCreateContext (NULL,
+ priv->num_devices[0],
+ priv->opencl_devices[0],
+ NULL, NULL, &errcode);
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ priv->command_queues = g_malloc0 (priv->num_devices[0] * sizeof (cl_command_queue));
+
+ for (guint i = 0; i < priv->num_devices[0]; i++) {
+ priv->command_queues[i] = clCreateCommandQueue (priv->opencl_context,
+ priv->opencl_devices[0][i],
+ queue_properties, &errcode);
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ }
+ }
+}
diff --git a/ufo/ufo-resources.h b/ufo/ufo-resources.h
new file mode 100644
index 0000000..af465c8
--- /dev/null
+++ b/ufo/ufo-resources.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_RESOURCES_H
+#define __UFO_RESOURCES_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-buffer.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_RESOURCES (ufo_resources_get_type())
+#define UFO_RESOURCES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_RESOURCES, UfoResources))
+#define UFO_IS_RESOURCES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_RESOURCES))
+#define UFO_RESOURCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_RESOURCES, UfoResourcesClass))
+#define UFO_IS_RESOURCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_RESOURCES))
+#define UFO_RESOURCES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_RESOURCES, UfoResourcesClass))
+
+#define UFO_RESOURCES_ERROR ufo_resources_error_quark()
+
+typedef struct _UfoResources UfoResources;
+typedef struct _UfoResourcesClass UfoResourcesClass;
+typedef struct _UfoResourcesPrivate UfoResourcesPrivate;
+
+
+typedef enum {
+ UFO_RESOURCES_ERROR_LOAD_PROGRAM,
+ UFO_RESOURCES_ERROR_CREATE_PROGRAM,
+ UFO_RESOURCES_ERROR_BUILD_PROGRAM,
+ UFO_RESOURCES_ERROR_CREATE_KERNEL
+} UfoResourcesError;
+
+/**
+ * UFO_RESOURCES_CHECK_CLERR:
+ * @error: OpenCL error code
+ *
+ * Check the return value of OpenCL functions and issue a warning with file and
+ * line number if an error occured.
+ */
+#define UFO_RESOURCES_CHECK_CLERR(error) { \
+ if ((error) != CL_SUCCESS) g_log("ocl", G_LOG_LEVEL_CRITICAL, "Error <%s:%i>: %s", __FILE__, __LINE__, ufo_resources_clerr((error))); }
+
+/**
+ * UfoResources:
+ *
+ * Manages OpenCL resources. The contents of the #UfoResources structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoResources {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoResourcesPrivate *priv;
+};
+
+/**
+ * UfoResourcesClass:
+ *
+ * #UfoResources class
+ */
+struct _UfoResourcesClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoResources * ufo_resources_new (UfoConfig *config);
+gpointer ufo_resources_get_kernel (UfoResources *resources,
+ const gchar *filename,
+ const gchar *kernel,
+ GError **error);
+gpointer ufo_resources_get_kernel_from_source (UfoResources *resources,
+ const gchar *source,
+ const gchar *kernel,
+ GError **error);
+gpointer ufo_resources_get_context (UfoResources *resources);
+GList * ufo_resources_get_cmd_queues (UfoResources *resources);
+const gchar * ufo_resources_clerr (int error);
+GType ufo_resources_get_type (void);
+GQuark ufo_resources_error_quark (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-scheduler.c b/ufo/ufo-scheduler.c
new file mode 100644
index 0000000..4b39906
--- /dev/null
+++ b/ufo/ufo-scheduler.c
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-configurable.h>
+#include <ufo/ufo-cpu-task-iface.h>
+#include <ufo/ufo-gpu-task-iface.h>
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-remote-task.h>
+#include <ufo/ufo-resources.h>
+#include <ufo/ufo-scheduler.h>
+#include <ufo/ufo-task-node.h>
+#include <ufo/ufo-task-iface.h>
+
+/**
+ * SECTION:ufo-scheduler
+ * @Short_description: Schedule the execution of a graph of nodes
+ * @Title: UfoScheduler
+ *
+ * A scheduler object uses a graphs information to schedule the contained nodes
+ * on CPU and GPU hardware.
+ */
+
+G_DEFINE_TYPE_WITH_CODE (UfoScheduler, ufo_scheduler, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL))
+
+#define UFO_SCHEDULER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_SCHEDULER, UfoSchedulerPrivate))
+
+typedef struct {
+ UfoTask *task;
+ UfoTaskMode mode;
+ guint n_inputs;
+ UfoInputParam *in_params;
+ gboolean *finished;
+} TaskLocalData;
+
+struct _UfoSchedulerPrivate {
+ UfoConfig *config;
+ UfoResources *resources;
+ GList *remotes;
+ gboolean expand;
+};
+
+enum {
+ PROP_0,
+ PROP_EXPAND,
+ PROP_REMOTES,
+ N_PROPERTIES,
+
+ /* Here come the overriden properties that we don't install ourselves. */
+ PROP_CONFIG,
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+/**
+ * ufo_scheduler_new:
+ * @config: A #UfoConfig or %NULL
+ * @remotes: (element-type utf8): A #GList with strings describing remote machines or %NULL
+ *
+ * Creates a new #UfoScheduler.
+ *
+ * Return value: A new #UfoScheduler
+ */
+UfoScheduler *
+ufo_scheduler_new (UfoConfig *config,
+ GList *remotes)
+{
+ UfoScheduler *sched;
+ UfoSchedulerPrivate *priv;
+
+ sched = UFO_SCHEDULER (g_object_new (UFO_TYPE_SCHEDULER,
+ "config", config,
+ NULL));
+ priv = sched->priv;
+
+ for (GList *it = g_list_first (remotes); it != NULL; it = g_list_next (it))
+ priv->remotes = g_list_append (priv->remotes, g_strdup (it->data));
+
+ return sched;
+}
+
+/**
+ * ufo_scheduler_get_context:
+ * @scheduler: A #UfoScheduler
+ *
+ * Get the associated OpenCL context of @scheduler.
+ *
+ * Return value: (transfer full): An cl_context structure or %NULL on error.
+ */
+gpointer
+ufo_scheduler_get_context (UfoScheduler *scheduler)
+{
+ g_return_val_if_fail (UFO_IS_SCHEDULER (scheduler), NULL);
+ return ufo_resources_get_context (scheduler->priv->resources);
+}
+
+/**
+ * ufo_scheduler_set_task_expansion:
+ * @scheduler: A #UfoScheduler
+ * @split: %TRUE if task graph should be split
+ *
+ * Sets whether the task graph should be expanded before execution to increase
+ * multi GPU performance.
+ */
+void
+ufo_scheduler_set_task_expansion (UfoScheduler *scheduler,
+ gboolean expand)
+{
+ g_return_if_fail (UFO_IS_SCHEDULER (scheduler));
+ g_object_set (G_OBJECT (scheduler), "expand", expand, NULL);
+}
+
+static gboolean
+get_inputs (TaskLocalData *tld,
+ UfoBuffer **inputs)
+{
+ UfoTaskNode *node = UFO_TASK_NODE (tld->task);
+ guint n_finished = 0;
+
+ for (guint i = 0; i < tld->n_inputs; i++) {
+ UfoGroup *group;
+
+ if (!tld->finished[i]) {
+ UfoBuffer *input;
+
+ group = ufo_task_node_get_current_in_group (node, i);
+ input = ufo_group_pop_input_buffer (group, tld->task);
+
+ if (input == UFO_END_OF_STREAM) {
+ tld->finished[i] = TRUE;
+ n_finished++;
+ }
+ else
+ inputs[i] = input;
+ }
+ else
+ n_finished++;
+ }
+
+ return (tld->n_inputs == 0) || (n_finished < tld->n_inputs);
+}
+
+static void
+release_inputs (TaskLocalData *tld,
+ UfoBuffer **inputs)
+{
+ UfoTaskNode *node = UFO_TASK_NODE (tld->task);
+
+ for (guint i = 0; i < tld->n_inputs; i++) {
+ UfoGroup *group;
+
+ group = ufo_task_node_get_current_in_group (node, i);
+ ufo_group_push_input_buffer (group, tld->task, inputs[i]);
+ ufo_task_node_switch_in_group (node, i);
+ }
+}
+
+static void
+exchange_data (UfoBuffer *input,
+ TaskLocalData *tld)
+{
+ UfoRemoteNode *remote;
+ UfoGroup *group;
+ UfoBuffer *output;
+ UfoRequisition requisition;
+
+ remote = UFO_REMOTE_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (tld->task)));
+ ufo_remote_node_send_inputs (remote, &input);
+ release_inputs (tld, &input);
+
+ ufo_remote_node_get_requisition (remote, &requisition);
+ group = ufo_task_node_get_out_group (UFO_TASK_NODE (tld->task));
+ output = ufo_group_pop_output_buffer (group, &requisition);
+ ufo_remote_node_get_result (remote, output);
+ ufo_group_push_output_buffer (group, output);
+}
+
+static void
+run_remote_task (TaskLocalData *tld)
+{
+ UfoRemoteNode *remote;
+ UfoBuffer *input;
+ guint n_remote_gpus;
+ GThreadPool *pool;
+ GError *error = NULL;
+
+ g_assert (tld->n_inputs == 1);
+ remote = UFO_REMOTE_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (tld->task)));
+ n_remote_gpus = ufo_remote_node_get_num_gpus (remote);
+ pool = g_thread_pool_new ((GFunc) exchange_data, tld, (gint) n_remote_gpus, TRUE, &error);
+ g_assert_no_error (error);
+
+ /*
+ * We launch a new thread for each incoming input data set because then we
+ * can send as many items as we have remote GPUs available without waiting
+ * for processing to stop.
+ */
+ while (1) {
+ if (get_inputs (tld, &input))
+ g_thread_pool_push (pool, input, &error);
+ else
+ break;
+ }
+
+ g_thread_pool_free (pool, FALSE, TRUE);
+ ufo_group_finish (ufo_task_node_get_out_group (UFO_TASK_NODE (tld->task)));
+}
+
+static gpointer
+run_task (TaskLocalData *tld)
+{
+ UfoBuffer *inputs[tld->n_inputs];
+ UfoBuffer *output;
+ UfoTaskNode *node;
+ UfoRequisition requisition;
+ gboolean active;
+
+ node = UFO_TASK_NODE (tld->task);
+ active = TRUE;
+ output = NULL;
+
+ if (UFO_IS_REMOTE_TASK (tld->task)) {
+ run_remote_task (tld);
+ return NULL;
+ }
+
+ while (active) {
+ UfoGroup *group;
+
+ group = ufo_task_node_get_out_group (node);
+
+ /* Get input buffers */
+ active = get_inputs (tld, inputs);
+
+ if (!active) {
+ ufo_group_finish (group);
+ break;
+ }
+
+ /* Get output buffers */
+ ufo_task_get_requisition (tld->task, inputs, &requisition);
+
+ if (requisition.n_dims > 0) {
+ output = ufo_group_pop_output_buffer (group, &requisition);
+ g_assert (output != NULL);
+ }
+
+ /* Process */
+ if (UFO_IS_GPU_TASK (tld->task)) {
+ UfoGpuNode *gpu_node;
+
+ if (output != NULL)
+ ufo_buffer_discard_location (output, UFO_LOCATION_HOST);
+
+ gpu_node = UFO_GPU_NODE (ufo_task_node_get_proc_node (node));
+
+ switch (tld->mode) {
+ case UFO_TASK_MODE_SINGLE:
+ active = ufo_gpu_task_process (UFO_GPU_TASK (tld->task),
+ inputs, output,
+ &requisition, gpu_node);
+ break;
+
+ case UFO_TASK_MODE_GENERATE:
+ case UFO_TASK_MODE_REDUCE:
+ do {
+ ufo_gpu_task_process (UFO_GPU_TASK (tld->task),
+ inputs, output,
+ &requisition, gpu_node);
+ release_inputs (tld, inputs);
+ active = get_inputs (tld, inputs);
+ } while (active);
+ break;
+ }
+
+ if (tld->mode == UFO_TASK_MODE_REDUCE)
+ ufo_gpu_task_reduce (UFO_GPU_TASK (tld->task),
+ output,
+ &requisition,
+ gpu_node);
+ }
+ else if (UFO_IS_CPU_TASK (tld->task)) {
+ if (output != NULL)
+ ufo_buffer_discard_location (output, UFO_LOCATION_DEVICE);
+
+ switch (tld->mode) {
+ case UFO_TASK_MODE_SINGLE:
+ active = ufo_cpu_task_process (UFO_CPU_TASK (tld->task), inputs, output, &requisition);
+ break;
+
+ case UFO_TASK_MODE_GENERATE:
+ case UFO_TASK_MODE_REDUCE:
+ do {
+ ufo_cpu_task_process (UFO_CPU_TASK (tld->task),
+ inputs,
+ output,
+ &requisition);
+ release_inputs (tld, inputs);
+ active = get_inputs (tld, inputs);
+ } while (active);
+ break;
+ }
+
+ if (tld->mode == UFO_TASK_MODE_REDUCE)
+ ufo_cpu_task_reduce (UFO_CPU_TASK (tld->task), output, &requisition);
+ }
+
+ /* Release buffers for further consumption */
+ release_inputs (tld, inputs);
+
+ if (requisition.n_dims > 0) {
+ switch (tld->mode) {
+ case UFO_TASK_MODE_SINGLE:
+ if (active)
+ ufo_group_push_output_buffer (group, output);
+ else
+ ufo_group_finish (group);
+ break;
+
+ case UFO_TASK_MODE_REDUCE:
+ ufo_group_push_output_buffer (group, output);
+ ufo_group_finish (group);
+ break;
+
+ case UFO_TASK_MODE_GENERATE:
+ {
+ do {
+ if (UFO_IS_GPU_TASK (tld->task)) {
+ UfoGpuNode *gpu_node;
+
+ ufo_buffer_discard_location (output, UFO_LOCATION_HOST);
+ gpu_node = UFO_GPU_NODE (ufo_task_node_get_proc_node (node));
+ active = ufo_gpu_task_generate (UFO_GPU_TASK (tld->task),
+ output,
+ &requisition, gpu_node);
+ }
+ else {
+ active = ufo_cpu_task_generate (UFO_CPU_TASK (tld->task),
+ output,
+ &requisition);
+ }
+
+ if (active) {
+ ufo_group_push_output_buffer (group, output);
+ output = ufo_group_pop_output_buffer (group, &requisition);
+ }
+ } while (active);
+
+ ufo_group_finish (group);
+ }
+ break;
+ }
+ }
+ }
+
+ g_message ("`%s' finished", G_OBJECT_TYPE_NAME (tld->task));
+
+ return NULL;
+}
+
+static void
+cleanup_task_local_data (TaskLocalData **tlds,
+ guint n)
+{
+ for (guint i = 0; i < n; i++) {
+ TaskLocalData *tld = tlds[i];
+ g_free (tld->in_params);
+ g_free (tld->finished);
+ g_free (tld);
+ }
+
+ g_free (tlds);
+}
+
+static TaskLocalData **
+setup_tasks (UfoSchedulerPrivate *priv,
+ UfoTaskGraph *task_graph,
+ GError **error)
+{
+ TaskLocalData **tlds;
+ GList *nodes;
+ guint n_nodes;
+
+ nodes = ufo_graph_get_nodes (UFO_GRAPH (task_graph));
+ n_nodes = g_list_length (nodes);
+
+ tlds = g_new0 (TaskLocalData *, n_nodes);
+
+ for (guint i = 0; i < n_nodes; i++) {
+ UfoNode *node;
+ TaskLocalData *tld;
+
+ node = g_list_nth_data (nodes, i);
+ tld = g_new0 (TaskLocalData, 1);
+ tld->task = UFO_TASK (node);
+ tlds[i] = tld;
+
+ ufo_task_setup (UFO_TASK (node), priv->resources, error);
+ ufo_task_get_structure (UFO_TASK (node), &tld->n_inputs, &tld->in_params, &tld->mode);
+
+ tld->finished = g_new0 (gboolean, tld->n_inputs);
+
+ if (error && *error != NULL)
+ return NULL;
+ }
+
+ g_list_free (nodes);
+ return tlds;
+}
+
+static GList *
+setup_groups (UfoSchedulerPrivate *priv,
+ UfoTaskGraph *task_graph)
+{
+ GList *groups;
+ GList *nodes;
+ cl_context context;
+
+ groups = NULL;
+ nodes = ufo_graph_get_nodes (UFO_GRAPH (task_graph));
+ context = ufo_resources_get_context (priv->resources);
+
+ for (GList *it = g_list_first (nodes); it != NULL; it = g_list_next (it)) {
+ GList *successors;
+ UfoNode *node;
+ UfoGroup *group;
+ UfoSendPattern pattern;
+
+ node = UFO_NODE (it->data);
+ successors = ufo_graph_get_successors (UFO_GRAPH (task_graph), node);
+ pattern = ufo_task_node_get_send_pattern (UFO_TASK_NODE (node));
+
+ group = ufo_group_new (successors, context, pattern);
+ groups = g_list_append (groups, group);
+ ufo_task_node_set_out_group (UFO_TASK_NODE (node), group);
+
+ for (GList *jt = g_list_first (successors); jt != NULL; jt = g_list_next (jt)) {
+ UfoNode *target;
+ gpointer label;
+ guint input;
+
+ target = UFO_NODE (jt->data);
+ label = ufo_graph_get_edge_label (UFO_GRAPH (task_graph), node, target);
+ input = (guint) GPOINTER_TO_INT (label);
+ ufo_task_node_add_in_group (UFO_TASK_NODE (target), input, group);
+ ufo_group_set_num_expected (group, UFO_TASK (target),
+ ufo_task_node_get_num_expected (UFO_TASK_NODE (target),
+ input));
+ }
+
+ g_list_free (successors);
+ }
+
+ g_list_free (nodes);
+ return groups;
+}
+
+void
+ufo_scheduler_run (UfoScheduler *scheduler,
+ UfoTaskGraph *task_graph,
+ GError **error)
+{
+ UfoSchedulerPrivate *priv;
+ UfoArchGraph *arch_graph;
+ GList *groups;
+ guint n_nodes;
+ GThread **threads;
+ TaskLocalData **tlds;
+ GTimer *timer;
+
+ g_return_if_fail (UFO_IS_SCHEDULER (scheduler));
+ priv = scheduler->priv;
+
+ arch_graph = UFO_ARCH_GRAPH (ufo_arch_graph_new (priv->resources,
+ priv->remotes));
+
+ if (priv->expand)
+ ufo_task_graph_expand (task_graph, arch_graph);
+
+ ufo_task_graph_map (task_graph, arch_graph);
+
+ /* Prepare task structures */
+ tlds = setup_tasks (priv, task_graph, error);
+
+ if (tlds == NULL)
+ return;
+
+ groups = setup_groups (priv, task_graph);
+ n_nodes = ufo_graph_get_num_nodes (UFO_GRAPH (task_graph));
+ threads = g_new0 (GThread *, n_nodes);
+ timer = g_timer_new ();
+
+ /* Spawn threads */
+ for (guint i = 0; i < n_nodes; i++) {
+ threads[i] = g_thread_create ((GThreadFunc) run_task, tlds[i], TRUE, error);
+
+ if (error && (*error != NULL))
+ return;
+ }
+
+ /* Wait for threads to finish */
+ for (guint i = 0; i < n_nodes; i++)
+ g_thread_join (threads[i]);
+
+ g_print ("Processing finished after %3.5fs\n", g_timer_elapsed (timer, NULL));
+ g_timer_destroy (timer);
+
+ /* Cleanup */
+ cleanup_task_local_data (tlds, n_nodes);
+ g_list_foreach (groups, (GFunc) g_object_unref, NULL);
+ g_list_free (groups);
+ g_free (threads);
+
+ g_object_unref (arch_graph);
+}
+
+static void
+copy_remote_list (UfoSchedulerPrivate *priv,
+ GValueArray *array)
+{
+ if (priv->remotes != NULL) {
+ g_list_foreach (priv->remotes, (GFunc) g_free, NULL);
+ g_list_free (priv->remotes);
+ priv->remotes = NULL;
+ }
+
+ for (guint i = 0; i < array->n_values; i++) {
+ priv->remotes = g_list_append (priv->remotes,
+ g_strdup (g_value_get_string (g_value_array_get_nth (array, i))));
+ }
+}
+
+static void
+ufo_scheduler_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ UfoSchedulerPrivate *priv = UFO_SCHEDULER_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_CONFIG:
+ {
+ GObject *vobject = g_value_get_object (value);
+
+ if (vobject != NULL) {
+ if (priv->config != NULL)
+ g_object_unref (priv->config);
+
+ priv->config = UFO_CONFIG (vobject);
+ g_object_ref (priv->config);
+ }
+ }
+ break;
+
+ case PROP_REMOTES:
+ copy_remote_list (priv, g_value_get_boxed (value));
+ break;
+
+ case PROP_EXPAND:
+ priv->expand = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_scheduler_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ UfoSchedulerPrivate *priv = UFO_SCHEDULER_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_EXPAND:
+ g_value_set_boolean (value, priv->expand);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+ufo_scheduler_constructed (GObject *object)
+{
+ UfoSchedulerPrivate *priv;
+
+ priv = UFO_SCHEDULER_GET_PRIVATE (object);
+ priv->resources = ufo_resources_new (priv->config);
+}
+
+static void
+ufo_scheduler_dispose (GObject *object)
+{
+ UfoSchedulerPrivate *priv;
+
+ priv = UFO_SCHEDULER_GET_PRIVATE (object);
+
+ if (priv->config != NULL) {
+ g_object_unref (priv->config);
+ priv->config = NULL;
+ }
+
+ if (priv->resources != NULL) {
+ g_object_unref (priv->resources);
+ priv->resources = NULL;
+ }
+
+ G_OBJECT_CLASS (ufo_scheduler_parent_class)->dispose (object);
+}
+
+static void
+ufo_scheduler_finalize (GObject *object)
+{
+ UfoSchedulerPrivate *priv;
+
+ priv = UFO_SCHEDULER_GET_PRIVATE (object);
+
+ g_list_foreach (priv->remotes, (GFunc) g_free, NULL);
+ g_list_free (priv->remotes);
+ priv->remotes = NULL;
+
+ G_OBJECT_CLASS (ufo_scheduler_parent_class)->finalize (object);
+}
+
+static void
+ufo_scheduler_class_init (UfoSchedulerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->constructed = ufo_scheduler_constructed;
+ gobject_class->set_property = ufo_scheduler_set_property;
+ gobject_class->get_property = ufo_scheduler_get_property;
+ gobject_class->dispose = ufo_scheduler_dispose;
+ gobject_class->finalize = ufo_scheduler_finalize;
+
+ properties[PROP_EXPAND] =
+ g_param_spec_boolean ("expand",
+ "Expand the task graph for better multi GPU performance",
+ "Expand the task graph for better multi GPU performance",
+ TRUE,
+ G_PARAM_READWRITE);
+
+ properties[PROP_REMOTES] =
+ g_param_spec_value_array ("remotes",
+ "List containing remote addresses",
+ "List containing remote addresses of machines running ufod",
+ g_param_spec_string ("remote",
+ "A remote address in the form tcp://addr:port",
+ "A remote address in the form tcp://addr:port (see http://api.zeromq.org/3-2:zmq-tcp)",
+ ".",
+ G_PARAM_READWRITE),
+ G_PARAM_READWRITE);
+
+ for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+ g_object_class_install_property (gobject_class, i, properties[i]);
+
+ g_object_class_override_property (gobject_class, PROP_CONFIG, "config");
+
+ g_type_class_add_private (klass, sizeof (UfoSchedulerPrivate));
+}
+
+static void
+ufo_scheduler_init (UfoScheduler *scheduler)
+{
+ UfoSchedulerPrivate *priv;
+
+ scheduler->priv = priv = UFO_SCHEDULER_GET_PRIVATE (scheduler);
+ priv->expand = TRUE;
+ priv->config = NULL;
+ priv->resources = NULL;
+ priv->remotes = NULL;
+}
diff --git a/ufo/ufo-scheduler.h b/ufo/ufo-scheduler.h
new file mode 100644
index 0000000..f3ae564
--- /dev/null
+++ b/ufo/ufo-scheduler.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_SCHEDULER_H
+#define __UFO_SCHEDULER_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-task-graph.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_SCHEDULER (ufo_scheduler_get_type())
+#define UFO_SCHEDULER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_SCHEDULER, UfoScheduler))
+#define UFO_IS_SCHEDULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_SCHEDULER))
+#define UFO_SCHEDULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_SCHEDULER, UfoSchedulerClass))
+#define UFO_IS_SCHEDULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_SCHEDULER))
+#define UFO_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_SCHEDULER, UfoSchedulerClass))
+
+typedef struct _UfoScheduler UfoScheduler;
+typedef struct _UfoSchedulerClass UfoSchedulerClass;
+typedef struct _UfoSchedulerPrivate UfoSchedulerPrivate;
+
+/**
+ * UfoScheduler:
+ *
+ * The base class scheduler is responsible of assigning command queues to
+ * filters (thus managing GPU device resources) and decide if to run a GPU or a
+ * CPU. The actual schedule planning can be overriden.
+ */
+struct _UfoScheduler {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoSchedulerPrivate *priv;
+};
+
+/**
+ * UfoSchedulerClass:
+ *
+ * #UfoScheduler class
+ */
+struct _UfoSchedulerClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoScheduler* ufo_scheduler_new (UfoConfig *config,
+ GList *remotes);
+void ufo_scheduler_run (UfoScheduler *scheduler,
+ UfoTaskGraph *task_graph,
+ GError** error);
+gpointer ufo_scheduler_get_context (UfoScheduler *scheduler);
+void ufo_scheduler_set_task_expansion
+ (UfoScheduler *scheduler,
+ gboolean split);
+GType ufo_scheduler_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-task-graph.c b/ufo/ufo-task-graph.c
new file mode 100644
index 0000000..3fc0c79
--- /dev/null
+++ b/ufo/ufo-task-graph.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <json-glib/json-glib.h>
+#include <ufo/ufo-task-graph.h>
+#include <ufo/ufo-task-node.h>
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-cpu-task-iface.h>
+#include <ufo/ufo-gpu-task-iface.h>
+#include <ufo/ufo-input-task.h>
+#include <ufo/ufo-dummy-task.h>
+#include <ufo/ufo-remote-task.h>
+
+/**
+ * SECTION:ufo-task-graph
+ * @Short_description: Hold and manage #UfoTaskNode elements.
+ * @Title: UfoTaskGraph
+ */
+
+G_DEFINE_TYPE (UfoTaskGraph, ufo_task_graph, UFO_TYPE_GRAPH)
+
+#define UFO_TASK_GRAPH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_TASK_GRAPH, UfoTaskGraphPrivate))
+
+struct _UfoTaskGraphPrivate {
+ UfoPluginManager *manager;
+ GHashTable *prop_sets;
+ GHashTable *json_nodes;
+ GList *remote_tasks;
+};
+
+typedef enum {
+ JSON_FILE,
+ JSON_DATA
+} JsonLocation;
+
+static void add_nodes_from_json (UfoTaskGraph *, JsonNode *, GError **);
+static void handle_json_prop_set (JsonObject *, const gchar *, JsonNode *, gpointer user);
+static void handle_json_single_prop (JsonObject *, const gchar *, JsonNode *, gpointer user);
+static void handle_json_task_edge (JsonArray *, guint, JsonNode *, gpointer);
+static gboolean handle_json_task_node (JsonNode *, UfoTaskGraphPrivate *priv, GError **error);
+static void add_task_node_to_json_array (UfoNode *, JsonArray *);
+static JsonObject *json_object_from_ufo_node (UfoNode *node);
+static JsonNode *get_json_representation (UfoTaskGraph *, GError **);
+
+/**
+ * UfoTaskGraphError:
+ * @UFO_TASK_GRAPH_ERROR_JSON_KEY: Key is not found in JSON
+ *
+ * Task graph errors
+ */
+GQuark
+ufo_task_graph_error_quark (void)
+{
+ return g_quark_from_static_string ("ufo-task-graph-error-quark");
+}
+
+/**
+ * ufo_task_graph_new:
+ *
+ * Create a new task graph without any nodes.
+ *
+ * Returns: A #UfoGraph that can be upcast to a #UfoTaskGraph.
+ */
+UfoGraph *
+ufo_task_graph_new (void)
+{
+ UfoTaskGraph *graph;
+ graph = UFO_TASK_GRAPH (g_object_new (UFO_TYPE_TASK_GRAPH, NULL));
+ return UFO_GRAPH (graph);
+}
+
+static void
+read_json (UfoTaskGraph *graph,
+ UfoPluginManager *manager,
+ JsonLocation location,
+ const gchar *data,
+ GError **error)
+{
+ JsonParser *json_parser;
+ GError *tmp_error = NULL;
+
+ json_parser = json_parser_new ();
+
+ switch (location) {
+ case JSON_FILE:
+ json_parser_load_from_file (json_parser,
+ data,
+ &tmp_error);
+ break;
+
+ case JSON_DATA:
+ json_parser_load_from_data (json_parser,
+ data,
+ (gssize) strlen (data),
+ &tmp_error);
+ break;
+ }
+
+ if (tmp_error != NULL) {
+ g_propagate_prefixed_error (error, tmp_error, "Parsing JSON: ");
+ g_object_unref (json_parser);
+ return;
+ }
+
+ graph->priv->manager = manager;
+ g_object_ref (manager);
+
+ add_nodes_from_json (graph, json_parser_get_root (json_parser), error);
+ g_object_unref (json_parser);
+}
+
+/**
+ * ufo_task_graph_read_from_file:
+ * @graph: A #UfoTaskGraph.
+ * @manager: A #UfoPluginManager used to load the filters
+ * @filename: Path and filename to the JSON file
+ * @error: Indicates error in case of failed file loading or parsing
+ *
+ * Read a JSON configuration file to fill the structure of @graph.
+ */
+void
+ufo_task_graph_read_from_file (UfoTaskGraph *graph,
+ UfoPluginManager *manager,
+ const gchar *filename,
+ GError **error)
+{
+ g_return_if_fail (UFO_IS_TASK_GRAPH (graph) &&
+ UFO_IS_PLUGIN_MANAGER (manager) &&
+ (filename != NULL));
+
+ read_json (graph, manager, JSON_FILE, filename, error);
+}
+
+/**
+ * ufo_task_graph_read_from_data:
+ * @graph: A #UfoTaskGraph.
+ * @manager: A #UfoPluginManager used to load the filters
+ * @json: %NULL-terminated string with JSON data
+ * @error: Indicates error in case of failed file loading or parsing
+ *
+ * Read a JSON configuration file to fill the structure of @graph.
+ */
+void
+ufo_task_graph_read_from_data (UfoTaskGraph *graph,
+ UfoPluginManager *manager,
+ const gchar *json,
+ GError **error)
+{
+ g_return_if_fail (UFO_IS_TASK_GRAPH (graph) &&
+ UFO_IS_PLUGIN_MANAGER (manager) &&
+ (json != NULL));
+
+ read_json (graph, manager, JSON_DATA, json, error);
+}
+
+static JsonNode *
+get_json_representation (UfoTaskGraph *graph,
+ GError **error)
+{
+ GList *task_nodes;
+ JsonNode *root_node = json_node_new (JSON_NODE_OBJECT);
+ JsonObject *root_object = json_object_new ();
+ JsonArray *nodes = json_array_new ();
+ JsonArray *edges = json_array_new ();
+
+ task_nodes = ufo_graph_get_nodes (UFO_GRAPH (graph));
+ g_list_foreach (task_nodes, (GFunc) add_task_node_to_json_array, nodes);
+
+ for (GList *it = g_list_first (task_nodes); it != NULL; it = g_list_next (it)) {
+ UfoNode *from;
+ GList *successors;
+
+ from = UFO_NODE (it->data);
+ successors = ufo_graph_get_successors (UFO_GRAPH (graph), from);
+
+ for (GList *jt = g_list_first (successors); jt != NULL; jt = g_list_next (jt)) {
+ UfoNode *to;
+ gint port;
+ JsonObject *to_object;
+ JsonObject *from_object;
+ JsonObject *edge_object;
+
+ to = UFO_NODE (jt->data);
+ port = GPOINTER_TO_INT (ufo_graph_get_edge_label (UFO_GRAPH (graph), from, to));
+ to_object = json_object_from_ufo_node (to);
+ from_object = json_object_from_ufo_node (from);
+ edge_object = json_object_new ();
+
+ json_object_set_int_member (to_object, "input", port);
+ json_object_set_object_member (edge_object, "to", to_object);
+ json_object_set_object_member (edge_object, "from", from_object);
+ json_array_add_object_element (edges, edge_object);
+ }
+
+ g_list_free (successors);
+ }
+
+ json_object_set_array_member (root_object, "nodes", nodes);
+ json_object_set_array_member (root_object, "edges", edges);
+ json_node_set_object (root_node, root_object);
+ g_list_free (task_nodes);
+
+ return root_node;
+}
+
+/**
+ * ufo_task_graph_save_to_json:
+ * @graph: A #UfoTaskGraph.
+ * @filename: Path and filename to the JSON file
+ * @error: Indicates error in case of failed file saving
+ *
+ * Save a JSON configuration file with the filter structure of @graph.
+ */
+void
+ufo_task_graph_save_to_json (UfoTaskGraph *graph,
+ const gchar *filename,
+ GError **error)
+{
+ JsonNode *root_node;
+ JsonGenerator *generator;
+
+ root_node = get_json_representation (graph, error);
+
+ if (error != NULL && *error != NULL)
+ return;
+
+ generator = json_generator_new ();
+ json_generator_set_root (generator, root_node);
+ json_generator_to_file (generator, filename, error);
+
+ json_node_free (root_node);
+ g_object_unref (generator);
+}
+
+static gboolean
+is_gpu_task (UfoNode *node, gpointer user_data)
+{
+ return UFO_IS_GPU_TASK (node);
+}
+
+static UfoTaskNode *
+build_remote_graph (UfoTaskGraph *remote_graph,
+ GList *first,
+ GList *last)
+{
+ UfoTaskNode *node;
+ UfoTaskNode *predecessor = NULL;
+
+ for (GList *it = g_list_next (first); it != last; it = g_list_next (it)) {
+ node = UFO_TASK_NODE (it->data);
+
+ if (predecessor != NULL)
+ ufo_task_graph_connect_nodes (remote_graph, predecessor, node);
+
+ predecessor = node;
+ }
+
+ return node;
+}
+
+static void
+create_remote_tasks (UfoTaskGraph *task_graph,
+ UfoTaskGraph *remote_graph,
+ UfoTaskNode *first,
+ UfoTaskNode *last,
+ UfoRemoteNode *remote)
+{
+ UfoTaskGraphPrivate *priv;
+ UfoTaskNode *task;
+ JsonNode *root;
+ JsonGenerator *generator;
+ gchar *json;
+ gsize size;
+
+ root = get_json_representation (remote_graph, NULL);
+ generator = json_generator_new ();
+ json_generator_set_root (generator, root);
+ json = json_generator_to_data (generator, &size);
+
+ priv = task_graph->priv;
+ ufo_remote_node_send_json (remote, json, size);
+
+ task = UFO_TASK_NODE (ufo_remote_task_new ());
+ priv->remote_tasks = g_list_append (priv->remote_tasks, task);
+ ufo_task_node_set_proc_node (task, UFO_NODE (remote));
+
+ ufo_task_graph_connect_nodes (task_graph, first, task);
+ ufo_task_graph_connect_nodes (task_graph, task, last);
+
+ g_free (json);
+ json_node_free (root);
+ g_object_unref (generator);
+}
+
+static void
+expand_remotes (UfoTaskGraph *task_graph,
+ GList *remotes,
+ GList *path)
+{
+ UfoTaskGraph *remote_graph;
+ UfoTaskNode *node;
+ GList *first;
+ GList *last;
+
+ first = g_list_first (path);
+ last = g_list_last (path);
+ remote_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+ node = build_remote_graph (remote_graph, first, last);
+
+ if (ufo_graph_get_num_nodes (UFO_GRAPH (remote_graph)) == 0) {
+ ufo_task_graph_connect_nodes (remote_graph,
+ UFO_TASK_NODE (ufo_dummy_task_new ()),
+ node);
+ }
+
+ for (GList *jt = g_list_first (remotes); jt != NULL; jt = g_list_next (jt)) {
+ create_remote_tasks (task_graph, remote_graph,
+ first->data, last->data, jt->data);
+ }
+
+ g_object_unref (remote_graph);
+}
+
+static gboolean
+path_unvisited (GList *path,
+ GList **visited)
+{
+ GList *head;
+ GList *tail;
+
+ head = g_list_first (path);
+ tail = g_list_last (path);
+
+ for (GList *it = g_list_first (head); it != tail; it = g_list_next (it)) {
+ UfoNode *node = (UfoNode *) it->data;
+
+ if (g_list_find (*visited, node))
+ return FALSE;
+
+ *visited = g_list_append (*visited, node);
+ }
+
+ return TRUE;
+}
+
+static GList *
+remove_common_ancestry_paths (GList *paths)
+{
+ GList *result;
+ GList *visited;
+
+ result = NULL;
+ visited = NULL;
+
+ for (GList *it = g_list_first (paths); it != NULL; it = g_list_next (it)) {
+ GList *path = (GList *) it->data;
+
+ if (path_unvisited (it->data, &visited))
+ result = g_list_append (result, path);
+ }
+
+ g_list_free (visited);
+ g_list_free (paths);
+ return result;
+}
+
+static GList *
+find_longest_path (GList *paths)
+{
+ GList *longest = NULL;
+ guint max_length = 0;
+
+ for (GList *it = g_list_first (paths); it != NULL; it = g_list_next (it)) {
+ guint length;
+ GList *path;
+
+ path = (GList *) it->data;
+ length = g_list_length (path);
+
+ if (length > max_length) {
+ max_length = length;
+ longest = path;
+ }
+ }
+
+ return longest;
+}
+
+/**
+ * ufo_task_graph_expand:
+ * @task_graph: A #UfoTaskGraph
+ * @arch_graph: A #UfoArchGraph
+ *
+ * Expands @task_graph in a way that most of the resources in @arch_graph can be
+ * occupied. In the simple pipeline case, the longest possible GPU paths are
+ * duplicated as much as there are GPUs in @arch_graph.
+ */
+void
+ufo_task_graph_expand (UfoTaskGraph *task_graph,
+ UfoArchGraph *arch_graph)
+{
+ GList *paths;
+ GList *path;
+
+ g_return_if_fail (UFO_IS_TASK_GRAPH (task_graph));
+
+ paths = ufo_graph_get_paths (UFO_GRAPH (task_graph), is_gpu_task);
+ g_debug ("Number of identified paths: %i", g_list_length (paths));
+ paths = remove_common_ancestry_paths (paths);
+ g_debug ("Number of cleaned paths: %i", g_list_length (paths));
+ path = find_longest_path (paths);
+
+ if (path != NULL) {
+ GList *remotes;
+ guint n_gpus;
+ guint n_remotes;
+
+ remotes = ufo_arch_graph_get_remote_nodes (arch_graph);
+ n_remotes = g_list_length (remotes);
+
+ if (n_remotes > 0) {
+ g_debug ("Expand for %i remote nodes", n_remotes);
+ expand_remotes (task_graph, remotes, path);
+ }
+
+ n_gpus = ufo_arch_graph_get_num_gpus (arch_graph);
+ g_debug ("Expand for %i GPU nodes", n_gpus);
+
+ for (guint i = 1; i < n_gpus; i++)
+ ufo_graph_expand (UFO_GRAPH (task_graph), path);
+
+ g_list_free (remotes);
+ }
+
+ g_list_foreach (paths, (GFunc) g_list_free, NULL);
+ g_list_free (paths);
+}
+
+/**
+ * ufo_task_graph_fuse:
+ * @task_graph: A #UfoTaskGraph
+ *
+ * Fuses task nodes to increase data locality.
+ *
+ * Note: This is not implemented and a no-op right now.
+ */
+void
+ufo_task_graph_fuse (UfoTaskGraph *task_graph)
+{
+}
+
+static void
+map_proc_node (UfoGraph *graph,
+ UfoNode *node,
+ guint proc_index,
+ GList *gpu_nodes)
+{
+ UfoNode *proc_node;
+ GList *successors;
+ guint n_gpus;
+
+ proc_node = UFO_NODE (g_list_nth_data (gpu_nodes, proc_index));
+
+ if ((UFO_IS_GPU_TASK (node) || UFO_IS_INPUT_TASK (node)) &&
+ (!ufo_task_node_get_proc_node (UFO_TASK_NODE (node)))) {
+
+ g_debug ("Mapping GPU %i to %s-%p",
+ proc_index, G_OBJECT_TYPE_NAME (node),
+ (gpointer) node);
+
+ ufo_task_node_set_proc_node (UFO_TASK_NODE (node), proc_node);
+ }
+
+ n_gpus = g_list_length (gpu_nodes);
+ successors = ufo_graph_get_successors (graph, node);
+
+ for (GList *it = g_list_first (successors); it != NULL; it = g_list_next (it)) {
+ map_proc_node (graph, UFO_NODE (it->data), proc_index, gpu_nodes);
+ proc_index = (proc_index + 1) % n_gpus;
+ }
+
+ g_list_free (successors);
+}
+
+
+/**
+ * ufo_task_graph_map:
+ * @task_graph: A #UfoTaskGraph
+ * @arch_graph: A #UfoArchGraph to which @task_graph's nodes are mapped onto
+ *
+ * Map task nodes of @task_graph to the processing nodes of @arch_graph. Not
+ * doing this could break execution of @task_graph.
+ */
+void
+ufo_task_graph_map (UfoTaskGraph *task_graph,
+ UfoArchGraph *arch_graph)
+{
+ GList *gpu_nodes;
+ GList *roots;
+
+ gpu_nodes = ufo_arch_graph_get_gpu_nodes (arch_graph);
+ roots = ufo_graph_get_roots (UFO_GRAPH (task_graph));
+
+ for (GList *it = g_list_first (roots); it != NULL; it = g_list_next (it))
+ map_proc_node (UFO_GRAPH (task_graph), UFO_NODE (it->data), 0, gpu_nodes);
+
+ g_list_free (roots);
+ g_list_free (gpu_nodes);
+}
+
+/**
+ * ufo_task_graph_connect_nodes:
+ * @graph: A #UfoTaskGraph
+ * @n1: A source node
+ * @n2: A destination node
+ *
+ * Connect @n1 with @n2 using @n2's default input port. To specify any other
+ * port, use ufo_task_graph_connect_nodes_full().
+ */
+void
+ufo_task_graph_connect_nodes (UfoTaskGraph *graph,
+ UfoTaskNode *n1,
+ UfoTaskNode *n2)
+{
+ ufo_task_graph_connect_nodes_full (graph, n1, n2, 0);
+}
+
+/**
+ * ufo_task_graph_connect_nodes_full:
+ * @graph: A #UfoTaskGraph
+ * @n1: A source node
+ * @n2: A destination node
+ * @input: Input port of @n2
+ *
+ * Connect @n1 with @n2 using @n2's @input port.
+ */
+void
+ufo_task_graph_connect_nodes_full (UfoTaskGraph *graph,
+ UfoTaskNode *n1,
+ UfoTaskNode *n2,
+ guint input)
+{
+ ufo_graph_connect_nodes (UFO_GRAPH (graph), UFO_NODE (n1), UFO_NODE (n2), GINT_TO_POINTER (input));
+}
+
+static void
+add_nodes_from_json (UfoTaskGraph *graph,
+ JsonNode *root,
+ GError **error)
+{
+ JsonObject *root_object = json_node_get_object (root);
+
+ if (json_object_has_member (root_object, "prop-sets")) {
+ JsonObject *sets = json_object_get_object_member (root_object, "prop-sets");
+ json_object_foreach_member (sets, handle_json_prop_set, graph->priv);
+ }
+
+ if (json_object_has_member (root_object, "nodes")) {
+ JsonArray *nodes = json_object_get_array_member (root_object, "nodes");
+ GList *elements = json_array_get_elements (nodes);
+
+ for (GList *it = g_list_first (elements); it != NULL; it = g_list_next (it)) {
+ if (!handle_json_task_node (it->data, graph->priv, error)) {
+ g_list_free (elements);
+ return;
+ }
+ }
+
+ g_list_free (elements);
+
+ /*
+ * We only check edges if we have nodes, anything else doesn't make much
+ * sense.
+ */
+ if (json_object_has_member (root_object, "edges")) {
+ JsonArray *edges = json_object_get_array_member (root_object, "edges");
+ json_array_foreach_element (edges, handle_json_task_edge, graph);
+ }
+ }
+}
+
+static gboolean
+handle_json_task_node (JsonNode *element,
+ UfoTaskGraphPrivate *priv,
+ GError **error)
+{
+ UfoNode *plugin;
+ JsonObject *object;
+ GError *tmp_error = NULL;
+ const gchar *name;
+ const gchar *plugin_name;
+
+ object = json_node_get_object (element);
+
+ if (!json_object_has_member (object, "plugin") ||
+ !json_object_has_member (object, "name")) {
+ g_set_error (error, UFO_TASK_GRAPH_ERROR, UFO_TASK_GRAPH_ERROR_JSON_KEY,
+ "Node does not have `plugin' or `name' key");
+ return FALSE;
+ }
+
+ plugin_name = json_object_get_string_member (object, "plugin");
+ plugin = ufo_plugin_manager_get_task (priv->manager, plugin_name, &tmp_error);
+
+ if (tmp_error != NULL) {
+ g_propagate_error (error, tmp_error);
+ return FALSE;
+ }
+
+ name = json_object_get_string_member (object, "name");
+
+ if (g_hash_table_lookup (priv->json_nodes, name) != NULL)
+ g_error ("Duplicate name `%s' found", name);
+
+ g_hash_table_insert (priv->json_nodes, g_strdup (name), plugin);
+
+ if (json_object_has_member (object, "properties")) {
+ JsonObject *prop_object = json_object_get_object_member (object, "properties");
+ json_object_foreach_member (prop_object, handle_json_single_prop, plugin);
+ }
+
+ if (json_object_has_member (object, "prop-refs")) {
+ JsonArray *prop_refs;
+
+ prop_refs = json_object_get_array_member (object, "prop-refs");
+
+ for (guint i = 0; i < json_array_get_length (prop_refs); i++) {
+ const gchar *ref_name = json_array_get_string_element (prop_refs, i);
+ JsonObject *prop_set = g_hash_table_lookup (priv->prop_sets, ref_name);
+
+ if (prop_set == NULL) {
+ g_warning ("No property set `%s' found in `prop-sets'", ref_name);
+ }
+ else {
+ json_object_foreach_member (prop_set,
+ handle_json_single_prop,
+ plugin);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+handle_json_task_edge (JsonArray *array,
+ guint index,
+ JsonNode *element,
+ gpointer user)
+{
+ UfoTaskGraph *graph = user;
+ UfoTaskGraphPrivate *priv = graph->priv;
+ JsonObject *edge;
+ UfoTaskNode *from_node, *to_node;
+ JsonObject *from_object, *to_object;
+ guint to_port;
+ const gchar *from_name;
+ const gchar *to_name;
+ GError *error = NULL;
+
+ edge = json_node_get_object (element);
+
+ if (!json_object_has_member (edge, "from") ||
+ !json_object_has_member (edge, "to")) {
+ g_error ("Edge does not have `from' or `to' key");
+ return;
+ }
+
+ /* Get from details */
+ from_object = json_object_get_object_member (edge, "from");
+
+ if (!json_object_has_member (from_object, "name")) {
+ g_error ("From node does not have `name' key");
+ return;
+ }
+
+ from_name = json_object_get_string_member (from_object, "name");
+
+ /* Get to details */
+ to_object = json_object_get_object_member (edge, "to");
+
+ if (!json_object_has_member (to_object, "name")) {
+ g_error ("To node does not have `name' key");
+ return;
+ }
+
+ to_name = json_object_get_string_member (to_object, "name");
+ to_port = 0;
+
+ if (json_object_has_member (to_object, "input"))
+ to_port = (guint) json_object_get_int_member (to_object, "input");
+
+ /* Get actual filters and connect them */
+ from_node = g_hash_table_lookup (priv->json_nodes, from_name);
+ to_node = g_hash_table_lookup (priv->json_nodes, to_name);
+
+ ufo_task_graph_connect_nodes_full (graph, from_node, to_node, to_port);
+
+ if (error != NULL)
+ g_warning ("%s", error->message);
+}
+
+static void
+handle_json_prop_set (JsonObject *object,
+ const gchar *name,
+ JsonNode *node,
+ gpointer user)
+{
+ UfoTaskGraphPrivate *priv;
+ JsonObject *properties;
+
+ priv = (UfoTaskGraphPrivate *) user;
+ properties = json_object_get_object_member (object, name);
+ json_object_ref (properties);
+ g_hash_table_insert (priv->prop_sets, g_strdup (name), properties);
+}
+
+static void
+handle_json_single_prop (JsonObject *object,
+ const gchar *name,
+ JsonNode *node,
+ gpointer user)
+{
+ GValue val = {0,};
+ json_node_get_value (node, &val);
+ g_object_set_property (G_OBJECT(user), name, &val);
+}
+
+static void
+add_task_node_to_json_array (UfoNode *node, JsonArray *array)
+{
+ JsonObject *node_object;
+ JsonNode *prop_node;
+
+ node_object = json_object_new ();
+
+ json_object_set_string_member (node_object,
+ "plugin",
+ ufo_task_node_get_plugin_name (UFO_TASK_NODE (node)));
+
+ json_object_set_string_member (node_object,
+ "name",
+ ufo_task_node_get_unique_name (UFO_TASK_NODE (node)));
+
+ prop_node = json_gobject_serialize (G_OBJECT (node));
+ json_object_set_member (node_object, "properties", prop_node);
+ json_array_add_object_element (array, node_object);
+}
+
+static JsonObject *
+json_object_from_ufo_node (UfoNode *node)
+{
+ JsonObject *object;
+
+ object = json_object_new ();
+ json_object_set_string_member (object,
+ "name",
+ ufo_task_node_get_unique_name (UFO_TASK_NODE (node)));
+ return object;
+}
+
+
+static void
+ufo_task_graph_dispose (GObject *object)
+{
+ UfoTaskGraphPrivate *priv;
+ GList *nodes;
+
+ priv = UFO_TASK_GRAPH_GET_PRIVATE (object);
+
+ if (priv->manager != NULL) {
+ g_object_unref (priv->manager);
+ priv->manager = NULL;
+ }
+
+ g_list_foreach (priv->remote_tasks, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->remote_tasks);
+ priv->remote_tasks = NULL;
+
+ nodes = g_hash_table_get_values (priv->json_nodes);
+ g_list_foreach (nodes, (GFunc) g_object_unref, NULL);
+ g_list_free (nodes);
+
+ G_OBJECT_CLASS (ufo_task_graph_parent_class)->dispose (object);
+}
+
+static void
+ufo_task_graph_finalize (GObject *object)
+{
+ UfoTaskGraphPrivate *priv;
+
+ priv = UFO_TASK_GRAPH_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->json_nodes);
+ g_hash_table_destroy (priv->prop_sets);
+
+ G_OBJECT_CLASS (ufo_task_graph_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_graph_class_init (UfoTaskGraphClass *klass)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_task_graph_dispose;
+ oclass->finalize = ufo_task_graph_finalize;
+
+ g_type_class_add_private(klass, sizeof(UfoTaskGraphPrivate));
+}
+
+static void
+ufo_task_graph_init (UfoTaskGraph *self)
+{
+ UfoTaskGraphPrivate *priv;
+ self->priv = priv = UFO_TASK_GRAPH_GET_PRIVATE (self);
+
+ priv->manager = NULL;
+ priv->remote_tasks = NULL;
+ priv->json_nodes = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ priv->prop_sets = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) json_object_unref);
+
+ /* Maybe we should define a specific task node type from which all tasks
+ * must inherit */
+ ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_NODE);
+}
diff --git a/ufo/ufo-task-graph.h b/ufo/ufo-task-graph.h
new file mode 100644
index 0000000..10b9c1a
--- /dev/null
+++ b/ufo/ufo-task-graph.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_TASK_GRAPH_H
+#define __UFO_TASK_GRAPH_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-graph.h>
+#include <ufo/ufo-arch-graph.h>
+#include <ufo/ufo-task-node.h>
+#include <ufo/ufo-plugin-manager.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_TASK_GRAPH (ufo_task_graph_get_type())
+#define UFO_TASK_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_TASK_GRAPH, UfoTaskGraph))
+#define UFO_IS_TASK_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_TASK_GRAPH))
+#define UFO_TASK_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_TASK_GRAPH, UfoTaskGraphClass))
+#define UFO_IS_TASK_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_TASK_GRAPH))
+#define UFO_TASK_GRAPH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_TASK_GRAPH, UfoTaskGraphClass))
+
+#define UFO_TASK_GRAPH_ERROR ufo_task_graph_error_quark()
+
+typedef struct _UfoTaskGraph UfoTaskGraph;
+typedef struct _UfoTaskGraphClass UfoTaskGraphClass;
+typedef struct _UfoTaskGraphPrivate UfoTaskGraphPrivate;
+
+
+typedef enum {
+ UFO_TASK_GRAPH_ERROR_JSON_KEY
+} UfoTaskGraphError;
+
+/**
+ * UfoTaskGraph:
+ *
+ * Main object for organizing filters. The contents of the #UfoTaskGraph structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoTaskGraph {
+ /*< private >*/
+ UfoGraph parent_instance;
+
+ UfoTaskGraphPrivate *priv;
+};
+
+/**
+ * UfoTaskGraphClass:
+ *
+ * #UfoTaskGraph class
+ */
+struct _UfoTaskGraphClass {
+ /*< private >*/
+ UfoGraphClass parent_class;
+};
+
+UfoGraph *ufo_task_graph_new (void);
+void ufo_task_graph_read_from_file (UfoTaskGraph *graph,
+ UfoPluginManager *manager,
+ const gchar *filename,
+ GError **error);
+void ufo_task_graph_read_from_data (UfoTaskGraph *graph,
+ UfoPluginManager *manager,
+ const gchar *json,
+ GError **error);
+void ufo_task_graph_save_to_json (UfoTaskGraph *graph,
+ const gchar *filename,
+ GError **error);
+void ufo_task_graph_map (UfoTaskGraph *task_graph,
+ UfoArchGraph *arch_graph);
+void ufo_task_graph_expand (UfoTaskGraph *task_graph,
+ UfoArchGraph *arch_graph);
+void ufo_task_graph_connect_nodes (UfoTaskGraph *graph,
+ UfoTaskNode *n1,
+ UfoTaskNode *n2);
+void ufo_task_graph_connect_nodes_full (UfoTaskGraph *graph,
+ UfoTaskNode *n1,
+ UfoTaskNode *n2,
+ guint input);
+void ufo_task_graph_fuse (UfoTaskGraph *task_graph);
+GType ufo_task_graph_get_type (void);
+GQuark ufo_task_graph_error_quark (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-task-iface.c b/ufo/ufo-task-iface.c
new file mode 100644
index 0000000..356064f
--- /dev/null
+++ b/ufo/ufo-task-iface.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-task-iface.h>
+
+typedef UfoTaskIface UfoTaskInterface;
+
+G_DEFINE_INTERFACE (UfoTask, ufo_task, G_TYPE_OBJECT)
+
+/**
+ * UfoTaskError:
+ * @UFO_TASK_ERROR_SETUP: Error during setup of a task.
+ */
+GQuark
+ufo_task_error_quark ()
+{
+ return g_quark_from_static_string ("ufo-task-error-quark");
+}
+
+void
+ufo_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ UFO_TASK_GET_IFACE (task)->setup (task, resources, error);
+}
+
+void
+ufo_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ UFO_TASK_GET_IFACE (task)->get_requisition (task, inputs, requisition);
+}
+
+void
+ufo_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ UFO_TASK_GET_IFACE (task)->get_structure (task, n_inputs, in_params, mode);
+}
+
+static void
+ufo_task_setup_real (UfoTask *task,
+ UfoResources *resources,
+ GError **error)
+{
+ g_warning ("`setup' not implemented");
+}
+
+static void
+ufo_task_get_requisition_real (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition)
+{
+ g_warning ("`get_allocation' not implemented");
+}
+
+static void
+ufo_task_get_structure_real (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode)
+{
+ g_warning ("`get_structure' not implemented");
+}
+
+static void
+ufo_task_default_init (UfoTaskInterface *iface)
+{
+ iface->setup = ufo_task_setup_real;
+ iface->get_requisition = ufo_task_get_requisition_real;
+ iface->get_structure = ufo_task_get_structure_real;
+}
diff --git a/ufo/ufo-task-iface.h b/ufo/ufo-task-iface.h
new file mode 100644
index 0000000..1199627
--- /dev/null
+++ b/ufo/ufo-task-iface.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UFO_TASK_IFACE_H
+#define UFO_TASK_IFACE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-resources.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_TASK (ufo_task_get_type())
+#define UFO_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_TASK, UfoTask))
+#define UFO_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_TASK, UfoTaskIface))
+#define UFO_IS_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_TASK))
+#define UFO_IS_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_TASK))
+#define UFO_TASK_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), UFO_TYPE_TASK, UfoTaskIface))
+
+#define UFO_TASK_ERROR ufo_task_error_quark()
+
+typedef struct _UfoTask UfoTask;
+typedef struct _UfoTaskIface UfoTaskIface;
+typedef struct _UfoInputParam UfoInputParam;
+
+typedef enum {
+ UFO_TASK_ERROR_SETUP
+} UfoTaskError;
+
+/**
+ * UfoTaskMode:
+ * @UFO_TASK_MODE_SINGLE: one-by-one processing
+ * @UFO_TASK_MODE_REDUCE: receive fininite stream and generate a reduced stream
+ * @UFO_TASK_MODE_GENERATE: do not receive any data but produce a stream.
+ *
+ * Task modes describe how a task operates considering the input data.
+ */
+typedef enum {
+ UFO_TASK_MODE_SINGLE,
+ UFO_TASK_MODE_REDUCE,
+ UFO_TASK_MODE_GENERATE
+} UfoTaskMode;
+
+/**
+ * UfoInputParam:
+ * @n_dims: Number of dimensions
+ */
+struct _UfoInputParam {
+ guint n_dims;
+};
+
+struct _UfoTaskIface {
+ /*< private >*/
+ GTypeInterface parent_iface;
+
+ void (*setup) (UfoTask *task,
+ UfoResources *resources,
+ GError **error);
+ void (*get_structure) (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode);
+ void (*get_requisition) (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition);
+};
+
+void ufo_task_setup (UfoTask *task,
+ UfoResources *resources,
+ GError **error);
+void ufo_task_get_requisition (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoRequisition *requisition);
+void ufo_task_get_structure (UfoTask *task,
+ guint *n_inputs,
+ UfoInputParam **in_params,
+ UfoTaskMode *mode);
+
+GQuark ufo_task_error_quark (void);
+GType ufo_task_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-task-node.c b/ufo/ufo-task-node.c
new file mode 100644
index 0000000..6f60db6
--- /dev/null
+++ b/ufo/ufo-task-node.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <ufo/ufo-task-node.h>
+
+G_DEFINE_TYPE (UfoTaskNode, ufo_task_node, UFO_TYPE_NODE)
+
+#define UFO_TASK_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_TASK_NODE, UfoTaskNodePrivate))
+
+
+struct _UfoTaskNodePrivate {
+ gchar *plugin;
+ gchar *unique;
+ UfoSendPattern pattern;
+ UfoNode *proc_node;
+ UfoGroup *out_group;
+ GList *in_groups[16];
+ GList *current[16];
+ gint n_expected[16];
+};
+
+void
+ufo_task_node_set_plugin_name (UfoTaskNode *task_node,
+ const gchar *name)
+{
+ UfoTaskNodePrivate *priv;
+
+ g_return_if_fail (UFO_IS_TASK_NODE (task_node));
+ priv = task_node->priv;
+
+ g_free (priv->plugin);
+ priv->plugin = g_strdup (name);
+
+ g_free (priv->unique);
+ priv->unique = g_strdup_printf ("%s-%p", name, (gpointer) task_node);
+}
+
+const gchar *
+ufo_task_node_get_plugin_name (UfoTaskNode *task_node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (task_node), NULL);
+ return task_node->priv->plugin;
+}
+
+const gchar *
+ufo_task_node_get_unique_name (UfoTaskNode *task_node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (task_node), NULL);
+ return task_node->priv->unique;
+}
+
+void
+ufo_task_node_set_send_pattern (UfoTaskNode *node,
+ UfoSendPattern pattern)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ node->priv->pattern = pattern;
+}
+
+UfoSendPattern
+ufo_task_node_get_send_pattern (UfoTaskNode *node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), 0);
+ return node->priv->pattern;
+}
+
+void
+ufo_task_node_set_num_expected (UfoTaskNode *node,
+ guint pos,
+ gint n_expected)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ g_return_if_fail (pos < 16);
+ node->priv->n_expected[pos] = n_expected;
+}
+
+gint
+ufo_task_node_get_num_expected (UfoTaskNode *node,
+ guint pos)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), 0);
+ g_return_val_if_fail (pos < 16, 0);
+ return node->priv->n_expected[pos];
+}
+
+void
+ufo_task_node_set_out_group (UfoTaskNode *node,
+ UfoGroup *group)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ node->priv->out_group = group;
+}
+
+/**
+ * ufo_task_node_get_out_group:
+ * @node: A #UfoTaskNode
+ *
+ * Get the current out of @node. The out group is used to fetch the ouput buffer
+ * for @node using ufo_group_pop_output_buffer().
+ *
+ * Return value: (transfer full): The out group of @node.
+ */
+UfoGroup *
+ufo_task_node_get_out_group (UfoTaskNode *node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), NULL);
+ return node->priv->out_group;
+}
+
+void
+ufo_task_node_add_in_group (UfoTaskNode *node,
+ guint pos,
+ UfoGroup *group)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ /* TODO: check out-of-bounds condition */
+ node->priv->in_groups[pos] = g_list_prepend (node->priv->in_groups[pos], group);
+ node->priv->current[pos] = node->priv->in_groups[pos];
+}
+
+/**
+ * ufo_task_node_get_current_in_group:
+ * @node: A #UfoTaskNode
+ * @pos: Input position of @node
+ *
+ * Several nodes can be connected to input @pos of @node. However, at a time
+ * @node will fetch only one buffer from all its inputs. This method returns the
+ * currently selected input group at @pos.
+ *
+ * Return value: (transfer full): The current in group of @node for @pos.
+ */
+UfoGroup *
+ufo_task_node_get_current_in_group (UfoTaskNode *node,
+ guint pos)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), NULL);
+ return UFO_GROUP (node->priv->current[pos]->data);
+}
+
+void
+ufo_task_node_switch_in_group (UfoTaskNode *node,
+ guint pos)
+{
+ UfoTaskNodePrivate *priv;
+
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ priv = node->priv;
+ priv->current[pos] = g_list_next (priv->current[pos]);
+
+ if (priv->current[pos] == NULL)
+ priv->current[pos] = g_list_first (priv->in_groups[pos]);
+}
+
+void
+ufo_task_node_set_proc_node (UfoTaskNode *task_node,
+ UfoNode *proc_node)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (task_node) && UFO_IS_NODE (proc_node));
+ task_node->priv->proc_node = proc_node;
+}
+
+/**
+ * ufo_task_node_get_proc_node:
+ * @node: A #UfoTaskNode
+ *
+ * Get the associated processing node of @node.
+ *
+ * Return value: (transfer full): A #UfoNode.
+ */
+UfoNode *
+ufo_task_node_get_proc_node (UfoTaskNode *node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), NULL);
+ return node->priv->proc_node;
+}
+
+static void
+ufo_task_node_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (ufo_task_node_parent_class)->dispose (object);
+}
+
+static void
+ufo_task_node_finalize (GObject *object)
+{
+ UfoTaskNodePrivate *priv;
+
+ priv = UFO_TASK_NODE_GET_PRIVATE (object);
+ g_free (priv->plugin);
+ g_free (priv->unique);
+
+ G_OBJECT_CLASS (ufo_task_node_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_node_class_init (UfoTaskNodeClass *klass)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_task_node_dispose;
+ oclass->finalize = ufo_task_node_finalize;
+
+ g_type_class_add_private (klass, sizeof(UfoTaskNodePrivate));
+}
+
+static void
+ufo_task_node_init (UfoTaskNode *self)
+{
+ self->priv = UFO_TASK_NODE_GET_PRIVATE (self);
+ self->priv->plugin = NULL;
+ self->priv->unique = NULL;
+ self->priv->pattern = UFO_SEND_SCATTER;
+ self->priv->proc_node = NULL;
+ self->priv->out_group = NULL;
+
+ for (guint i = 0; i < 16; i++) {
+ self->priv->in_groups[i] = NULL;
+ self->priv->current[i] = NULL;
+ self->priv->n_expected[i] = -1;
+ }
+}
diff --git a/ufo/ufo-task-node.h b/ufo/ufo-task-node.h
new file mode 100644
index 0000000..2e6df01
--- /dev/null
+++ b/ufo/ufo-task-node.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_TASK_NODE_H
+#define __UFO_TASK_NODE_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-node.h>
+#include <ufo/ufo-group.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_TASK_NODE (ufo_task_node_get_type())
+#define UFO_TASK_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_TASK_NODE, UfoTaskNode))
+#define UFO_IS_TASK_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_TASK_NODE))
+#define UFO_TASK_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_TASK_NODE, UfoTaskNodeClass))
+#define UFO_IS_TASK_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_TASK_NODE))
+#define UFO_TASK_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_TASK_NODE, UfoTaskNodeClass))
+
+typedef struct _UfoTaskNode UfoTaskNode;
+typedef struct _UfoTaskNodeClass UfoTaskNodeClass;
+typedef struct _UfoTaskNodePrivate UfoTaskNodePrivate;
+
+
+/**
+ * UfoTaskNode:
+ *
+ * Main object for organizing filters. The contents of the #UfoTaskNode structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoTaskNode {
+ /*< private >*/
+ UfoNode parent_instance;
+
+ UfoTaskNodePrivate *priv;
+};
+
+/**
+ * UfoTaskNodeClass:
+ *
+ * #UfoTaskNode class
+ */
+struct _UfoTaskNodeClass {
+ /*< private >*/
+ UfoNodeClass parent_class;
+};
+
+void ufo_task_node_set_plugin_name (UfoTaskNode *node,
+ const gchar *name);
+const gchar *ufo_task_node_get_plugin_name (UfoTaskNode *node);
+const gchar *ufo_task_node_get_unique_name (UfoTaskNode *node);
+void ufo_task_node_set_send_pattern (UfoTaskNode *node,
+ UfoSendPattern pattern);
+UfoSendPattern ufo_task_node_get_send_pattern (UfoTaskNode *node);
+void ufo_task_node_set_num_expected (UfoTaskNode *node,
+ guint pos,
+ gint n_expected);
+gint ufo_task_node_get_num_expected (UfoTaskNode *node,
+ guint pos);
+void ufo_task_node_set_out_group (UfoTaskNode *node,
+ UfoGroup *group);
+UfoGroup *ufo_task_node_get_out_group (UfoTaskNode *node);
+void ufo_task_node_add_in_group (UfoTaskNode *node,
+ guint pos,
+ UfoGroup *group);
+UfoGroup *ufo_task_node_get_current_in_group (UfoTaskNode *node,
+ guint pos);
+void ufo_task_node_switch_in_group (UfoTaskNode *node,
+ guint pos);
+void ufo_task_node_set_proc_node (UfoTaskNode *task_node,
+ UfoNode *proc_node);
+UfoNode *ufo_task_node_get_proc_node (UfoTaskNode *node);
+GType ufo_task_node_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo.h b/ufo/ufo.h
new file mode 100644
index 0000000..b9b3d8e
--- /dev/null
+++ b/ufo/ufo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_H
+#define __UFO_H
+
+#define __UFO_H_INSIDE__
+
+#include <ufo/ufo-arch-graph.h>
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-configurable.h>
+#include <ufo/ufo-cpu-node.h>
+#include <ufo/ufo-cpu-task-iface.h>
+#include <ufo/ufo-dummy-task.h>
+#include <ufo/ufo-enums.h>
+#include <ufo/ufo-gpu-node.h>
+#include <ufo/ufo-gpu-task-iface.h>
+#include <ufo/ufo-graph.h>
+#include <ufo/ufo-group.h>
+#include <ufo/ufo-input-task.h>
+#include <ufo/ufo-node.h>
+#include <ufo/ufo-output-task.h>
+#include <ufo/ufo-plugin-manager.h>
+#include <ufo/ufo-profiler.h>
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-remote-task.h>
+#include <ufo/ufo-resources.h>
+#include <ufo/ufo-scheduler.h>
+#include <ufo/ufo-task-graph.h>
+#include <ufo/ufo-task-iface.h>
+#include <ufo/ufo-task-node.h>
+
+#undef __UFO_H_INSIDE__
+
+#endif
diff --git a/ufo/ufo.pc.in b/ufo/ufo.pc.in
new file mode 100644
index 0000000..732f672
--- /dev/null
+++ b/ufo/ufo.pc.in
@@ -0,0 +1,13 @@
+prefix=@UFO_PKG_PREFIX@
+exec_prefix=@UFO_PKG_EXEC_PREFIX@
+libdir=@UFO_PKG_LIBDIR@
+includedir=@UFO_PKG_INCLUDEDIR@
+girdir=@UFO_PKG_GIRDIR@
+typelibdir=@UFO_PKG_TYPELIBDIR@
+
+Name: @TARNAME@
+Description: @UFO_DESCRIPTION_SUMMARY@
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lufo
+Cflags: -I${includedir}
+Requires: glib-2.0 gobject-2.0
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ufo-core.git
More information about the debian-science-commits
mailing list