Skip to content
Permalink
Browse files

more fixups from the vips7 removal

  • Loading branch information...
jcupitt committed Apr 14, 2019
1 parent 6a3b197 commit c351c665a18bc070db8f51d0d5fd9021e98024a2
Showing with 48 additions and 73 deletions.
  1. +0 −1 Makefile.am
  2. +0 −8 autogen.sh
  3. +0 −1 configure.ac
  4. +1 −1 doc/How-it-works.md
  5. +46 −51 doc/How-it-works.xml
  6. +1 −1 doc/Makefile.am
  7. +0 −10 vipsCC.pc.in
@@ -12,7 +12,6 @@ EXTRA_DIST = \
benchmark \
autogen.sh \
vips.pc.in \
vipsCC.pc.in \
vips-cpp.pc.in \
libvips.supp \
depcomp \
@@ -17,9 +17,6 @@ rm -f m4/gtk-doc.m4
rm -f config.* configure depcomp
rm -f install-sh intltool-* libtool ltmain.sh missing mkinstalldirs
rm -f stamp-*
rm -f swig/vipsCC/*.cxx
rm -f swig/vipsCC/VImage.h
rm -f swig/vipsCC/VImage.py python/vipsCC/VError.py python/vipsCC/VMask.py python/vipsCC/Display.py
rm -f benchmark/temp*
find doc -depth \( \
-path doc/libvips-docs.xml.in \
@@ -64,9 +61,4 @@ autoheader
$LIBTOOLIZE --copy --force --automake
automake --add-missing --copy

swig -version > /dev/null
if [ $? -ne 0 ]; then
echo you need swig to build from source control
fi

./configure $*
@@ -1385,7 +1385,6 @@ AC_SUBST(TOP_SRCDIR)

AC_OUTPUT([
vips.pc
vipsCC.pc
vips-cpp.pc
Makefile
libvips/include/vips/version.h
@@ -250,7 +250,7 @@ fancier and adds things like automatic object lifetime management. The
operation in the class hierarchy.

There are bindings for [many other
languages](https://jcupitt.github.io/libvips/) on many platforms. Most of
languages](https://libvips.github.io/libvips/) on many platforms. Most of
these bindings use the introspection system to generate the binding at
run-time.

@@ -13,13 +13,13 @@
<para>
Compared to most image processing libraries, VIPS needs little RAM and runs quickly, especially on machines with more than one CPU. VIPS achieves this improvement by only keeping the pixels currently being processed in RAM and by having an efficient, threaded image IO system. This page explains how these features are implemented.
</para>
<refsect3 id="images">
<section xml:id="images">
<title>Images</title>
<para>
VIPS images have three dimensions: width, height and bands. Bands usually (though not always) represent colour. These three dimensions can be any size up to 2 ** 31 elements. Every band element in an image has to have the same format. A format is an 8-, 16- or 32-bit int, signed or unsigned, 32- or 64-bit float, and 64- or 128-bit complex.
</para>
</refsect3>
<refsect3 id="regions">
</section>
<section xml:id="regions">
<title>Regions</title>
<para>
An image can be very large, much larger than the available memory, so you can’t just access pixels with a pointer *.
@@ -59,8 +59,8 @@ g_object_unref( region );
<para>
(* there is an image access mode where you can just use a pointer, but it’s rarely used)
</para>
</refsect3>
<refsect3 id="partial-images">
</section>
<section xml:id="partial-images">
<title>Partial images</title>
<para>
A partial image is one where, instead of storing a value for each pixel, VIPS stores a function which can make any rectangular area of pixels on demand.
@@ -74,109 +74,104 @@ g_object_unref( region );
<para>
VIPS makes a set of guarantees about parallelism that make this simple to program. Start and stop functions are mutually exclusive and a state is never used by more than one generate. In other words, a start / generate / generate / stop sequence works like a thread.
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Sequence.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
(* in fact VIPS keeps a cache of calculated pixel buffers and will return a pointer to a previously-calculated buffer if it can)
</para>
</refsect3>
<refsect3 id="operations">
</section>
<section xml:id="operations">
<title>Operations</title>
<para>
VIPS operations read input images and write output images, performing some transformation on the pixels. When an operation writes to an image the action it takes depends upon the image type. For example, if the image is a file on disc then VIPS will start a data sink to stream pixels to the file, or if the image is a partial one then it will just attach start / generate / stop functions.
</para>
<para>
Like most threaded image processing systems, all VIPS operations have to be free of side-effects. In other words, operations cannot modify images, they can only create new images. This could result in a lot of copying if an operation is only making a small change to a large image so VIPS has a set of mechanisms to copy image areas by just adjusting pointers. Most of the time no actual copying is necessary and you can perform operations on large images at low cost.
</para>
</refsect3>
<refsect3 id="run-time-code-generation">
</section>
<section xml:id="run-time-code-generation">
<title>Run-time code generation</title>
<para>
VIPS uses <ulink url="http://code.entropywave.com/orc/">Orc</ulink>, a run-time compiler, to generate code for some operations. For example, to compute a convolution on an 8-bit image, VIPS will examine the convolution matrix and the source image and generate a tiny program to calculate the convolution. This program is then <quote>compiled</quote> to the vector instruction set for your CPU, for example SSE3 on most x86 processors.
VIPS uses <link xlink:href="http://code.entropywave.com/orc/">Orc</link>, a run-time compiler, to generate code for some operations. For example, to compute a convolution on an 8-bit image, VIPS will examine the convolution matrix and the source image and generate a tiny program to calculate the convolution. This program is then <quote>compiled</quote> to the vector instruction set for your CPU, for example SSE3 on most x86 processors.
</para>
<para>
Run-time vector code generation typically speeds operations up by a factor of three or four.
</para>
</refsect3>
<refsect3 id="joining-operations-together">
</section>
<section xml:id="joining-operations-together">
<title>Joining operations together</title>
<para>
The region create / prepare / prepare / free calls you use to get pixels from an image are an exact parallel to the start / generate / generate / stop calls that images use to create pixels. In fact, they are the same: a region on a partial image holds the state created by that image for the generate function that will fill the region with pixels.
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Combine.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
VIPS joins image processing operations together by linking the output of one operation (the start / generate / stop sequence) to the input of the next (the region it uses to get pixels for processing). This link is a single function call, and very fast. Additionally, because of the the split between allocation and processing, once a pipeline of operations has been set up, VIPS is able to run without allocating and freeing memory.
</para>
<para>
This graph (generated by <literal>vipsprofile</literal>, the vips profiler) shows memory use over time for a vips pipeline running on a large image. The bottom trace shows total memory, the upper traces show threads calculating useful results (green), threads blocked on synchronisation (red) and memory allocations (white ticks).
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Memtrace.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
Because the intermediate image is just a small region in memory, a pipeline of operations running together needs very little RAM. In fact, intermediates are small enough that they can fit in L2 cache on most machines, so an entire pipeline can run without touching main memory. And finally, because each thread runs a very cheap copy of just the writeable state of the entire pipeline, threads can run with few locks. VIPS needs just four lock operations per output tile, regardless of the pipeline length or complexity.
</para>
</refsect3>
<refsect3 id="data-sources">
</section>
<section xml:id="data-sources">
<title>Data sources</title>
<para>
VIPS has data sources which can supply pixels for processing from a variety of sources. VIPS can stream images from files in VIPS native format, from tiled TIFF files, from binary PPM/PGM/PBM/PFM, from Radiance (HDR) files, from FITS images and from tiled OpenEXR images. VIPS will automatically unpack other formats to temporary disc files for you but this can obviously generate a lot of disc traffic. It also has a special sequential mode for streaming operations on non-random-access formats. Another section in these docs explains <ulink url="How-it-opens-files.html">how libvips opens a file</ulink>. One of the sources uses the <ulink url="http://www.imagemagick.org">ImageMagick</ulink> (or optionally <ulink url="http://www.graphicsmagick.org">GraphicsMagick</ulink>) library, so VIPS can read any image format that these libraries can read.
VIPS has data sources which can supply pixels for processing from a variety of sources. VIPS can stream images from files in VIPS native format, from tiled TIFF files, from binary PPM/PGM/PBM/PFM, from Radiance (HDR) files, from FITS images and from tiled OpenEXR images. VIPS will automatically unpack other formats to temporary disc files for you but this can obviously generate a lot of disc traffic. It also has a special sequential mode for streaming operations on non-random-access formats. Another section in these docs explains <link xlink:href="How-it-opens-files.html">how libvips opens a file</link>. One of the sources uses the <link xlink:href="http://www.imagemagick.org">ImageMagick</link> (or optionally <link xlink:href="http://www.graphicsmagick.org">GraphicsMagick</link>) library, so VIPS can read any image format that these libraries can read.
</para>
<para>
VIPS images are held on disc as a 64-byte header containing basic image information like width, height, bands and format, then the image data as a single large block of pixels, left-to-right and top-to-bottom, then an XML extension block holding all the image metadata, such as ICC profiles and EXIF blocks.
</para>
<para>
When reading from a large VIPS image (or any other format with the same structure on disc, such as binary PPM), VIPS keeps a set of small rolling windows into the file, some small number of scanlines in size. As pixels are demanded by different threads VIPS will move these windows up and down the file. As a result, VIPS can process images much larger than RAM, even on 32-bit machines.
</para>
</refsect3>
<refsect3 id="data-sinks">
</section>
<section xml:id="data-sinks">
<title>Data sinks</title>
<para>
In a demand-driven system, something has to do the demanding. VIPS has a variety of data sinks that you can use to pull image data though a pipeline in various situations. There are sinks that will build a complete image in memory, sinks to draw to a display, sinks to loop over an image (useful for statistical operations, for example) and sinks to stream an image to disc.
</para>
<para>
The disc sink looks something like this:
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Sink.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
The sink keeps two buffers*, each as wide as the image. It starts threads as rapidly as it can up to the concurrency limit, filling each buffer with tiles** of calculated pixels, each thread calculating one tile at once. A separate background thread watches each buffer and, as soon as the last tile in a buffer finishes, writes that complete set of scanlines to disc using whatever image write library is appropriate. VIPS can write with libjpeg, libtiff, libpng and others. It then wipes the buffer and repositions it further down the image, ready for the next set of tiles to stream in.
</para>
<para>
These features in combination mean that, once a pipeline of image processing operations has been built, VIPS can run almost lock-free. This is very important for SMP scaling: you don’t want the synchronization overhead to scale with either the number of threads or the complexity of the pipeline of operations being performed. As a result, VIPS scales almost linearly with increasing numbers of threads:
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Vips-smp.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
Number of CPUs is on the horizontal axis, speedup is on the vertical axis. Taken from the [[Benchmarks]] page.
</para>
@@ -186,8 +181,8 @@ g_object_unref( region );
<para>
(** tiles can be any shape and size, VIPS has a tile hint system that operations use to tell sinks what tile geometry they prefer)
</para>
</refsect3>
<refsect3 id="operation-cache">
</section>
<section xml:id="operation-cache">
<title>Operation cache</title>
<para>
Because VIPS operations are free of side-effects*, you can cache them. Every time you call an operation, VIPS searches the cache for a previous call to the same operation with the same arguments. If it finds a match, you get the previous result again. This can give a huge speedup.
@@ -198,20 +193,20 @@ g_object_unref( region );
<para>
(* Some vips operations DO have side effects, for example, <literal>vips_draw_circle()</literal> will draw a circle on an image. These operations emit an <quote>invalidate</quote> signal on the image they are called on and this signal makes all downstream operations and caches drop their contents.)
</para>
</refsect3>
<refsect3 id="operation-database-and-apis">
</section>
<section xml:id="operation-database-and-apis">
<title>Operation database and APIs</title>
<para>
VIPS has around 300 image processing operations written in this style. Each operation is a GObject class. You can use the standard GObject calls to walk the class hierarchy and discover operations, and libvips adds a small amount of extra introspection metadata to handle things like optional arguments.
</para>
<para>
The <ulink url="using-from-c.html">C API</ulink> is a set of simple wrappers which create class instances for you. The <ulink url="using-from-cpp.html">C++ API</ulink> is a little fancier and adds things like automatic object lifetime management. The <ulink url="using-cli.html">command-line interface</ulink> uses introspection to run any vips operation in the class hierarchy.
The <link xlink:href="using-from-c.html">C API</link> is a set of simple wrappers which create class instances for you. The <link xlink:href="using-from-cpp.html">C++ API</link> is a little fancier and adds things like automatic object lifetime management. The <link xlink:href="using-cli.html">command-line interface</link> uses introspection to run any vips operation in the class hierarchy.
</para>
<para>
The <ulink url="using-from-python.html">Python API</ulink> is built on top of gobject-introspection. It is written in Python, so as long as you can get gobject-introspection working, you should be able to use vips. It supports python2 and python3 and works on Linux, OS X and Windows.
There are bindings for <link xlink:href="https://libvips.github.io/libvips/">many other languages</link> on many platforms. Most of these bindings use the introspection system to generate the binding at run-time.
</para>
</refsect3>
<refsect3 id="snip">
</section>
<section xml:id="snip">
<title>Snip</title>
<para>
The VIPS GUI, nip2, has its own scripting language called Snip. Snip is a lazy, higher-order, purely functional, object oriented language. Almost all of nip2’s menus are implemented in it, and nip2 workspaces are Snip programs.
@@ -276,7 +271,7 @@ Math_arithmetic_item = class
<para>
Now the user can select an object and click <literal>Math / Abs</literal> to find the absolute value of that object.
</para>
</refsect3>
</section>


</refentry>
@@ -138,7 +138,7 @@ HTML_IMAGES = \
# we have some files in markdown ... convert to docbook for gtk-doc
# pandoc makes sect1 headers, we want refsect3 for gtk-doc
.md.xml:
pandoc -s -S --template="$(realpath pandoc-docbook-template.docbook)" --wrap=none -V title="$<" -f markdown -t docbook -o $@ $<
pandoc -s --template="$(realpath pandoc-docbook-template.docbook)" --wrap=none -V title="$<" -f markdown+smart -t docbook-smart -o $@ $<
sed -e s/sect1/refsect3/g < $@ > x && mv x $@

# Our markdown source files

This file was deleted.

0 comments on commit c351c66

Please sign in to comment.
You can’t perform that action at this time.