Some minimal documentation about using valgrind to debug libgdiplus and about the different implementations to support regions

svn path=/trunk/libgdiplus/; revision=58362
This commit is contained in:
Sebastien Pouliot 2006-03-23 15:31:01 +00:00
Родитель c507663755
Коммит 3f096850cc
2 изменённых файлов: 145 добавлений и 0 удалений

103
docs/regions Normal file
Просмотреть файл

@ -0,0 +1,103 @@
Region implementations in libgdiplus
Last update: 2006-03-23
* Introduction
First you should notice "implementations" in the title. Yes there is more
than one implementation to handle region code.
* Rectangular based regions
The first implementation (i.e. the only one available before 1.1.14) is
based on rectangles. A region is simply a list of rectangles and all
binary operations (union, intersection, complement, exclude and xor) are
done mathematically (i.e. they results in a new list of rectangles).
This approach is simple, efficient and allow to implement some other GDI+
API very easily (e.g. GdipGetRegionData, GdipGetRegionDataSize,
GdipGetRegionScans).
However it is limited to rectangles (i.e. no polygons, beziers ...) and
makes it impossible to implement some other GDI+ API, like
GdipTransformRegion where the rectangles would be transformed into paths.
Software depending on these features simply can't work.
All the code for this implementation resides inside the file
/libgdiplus/src/region.c
* Bitmap based regions
This implementation use 1bbp (1 bit per pixel) bitmaps to represent the
regions. This allows us to implement the binary operators on memory
buffers, not on coordinates (see /libgdiplus/src/region-bitmap.c). At
display time (GdipFillRegion) the bitmap is used as the alpha channel and
we simply draw a rectangle using the selected brush.
This approach is simple, compared to a pure mathematical implementation,
but not as efficient and somewhat less precise (float to int
conversions). This is why the bitmap implementation co-exists with the
rectangular based region code. Simple regions get treated simply ;-)
To minimize the inconveniences the bitmaps are created only on demand
(e.g. when an API requires them) and we try, as much as possible, to
avoid this code path (e.g. using the rectangle code where possible, check
for special cases, like an union with infinity...).
Sadly having bitmaps isn't quite enough. We still have to be able to
apply transforms (i.e. GdipTransformRegion) and be able to [de]serialize
the region (GdipGetRegionData). While both operations _could_ be done
with bitmaps the results wouldn't be very precise (transform) nor small
(serialization). This is why the region keeps a tree of all the paths and
operations required to re-construct itself (see
/libgdiplus/src/region-path-tree.c).
The code for this implementation resides in the files:
/libgdiplus/src/region.c|h
The GDI+ API for regions. The API will switch to the rectangle or
bitmap code based on the regions type. If required a rectangle-
based region will be "promoted" to a bitmap region.
/libgdiplus/src/region-bitmap.c|h
Handle the bitmap allocation, creation (from path), the binary
operations, ...
/libgdiplus/src/region-path-tree.c|h
Handle the tree of path and (binary) operations required to
re-construct the region if required (e.g. transform and
serialization).
There are currently two main limitations to this approach:
1. Memory. It's simply impossible to allocate enough memory for an
"infinite" region. There is a maximum of 2 megabytes allocated for a
region bitmap (see region-bitmap.h). This is enough (1bbp) for
regions to cover a full screen resolution.
2. Clipping. Graphics.Clip can't use the bitmap (at least not without
major changes). This means that clipping _will_work_ for any region
(not just rectangles) until a binary operation is done on it. So far
I've not seen any code trying that...
* Future?
A pure, totally mathematical, implementation would be a nice addition to
libgdiplus. It could, once debugged, replace both the rectangular and
bitmap implementations.
The main advantages of this implementation would be:
- reduced memory requirements (well most of the time);
- (almost) unlimited size;
- more precision (no float to int conversion);
- no limits on clipping;
So if it's the best solution why don't we have it yet ?
Well it's really not an easy problem. Writing an effective intersector is
a complex problem. You must deal with curves (well they could be cheated
into linear paths) and a _lot_ of corner cases (google for them). Most
existing (open source) implementation aren't satisfied with their results
(e.g. libart, livarot). But don't let us discourage you from trying! ;-)

42
docs/valgrind Normal file
Просмотреть файл

@ -0,0 +1,42 @@
Using valgrind to find memory leaks in libgdiplus
Last update: 2006-03-23
* Introduction
Valgrind (http://valgrind.org/) is a nice tool for finding memory leaks
and related problems (e.g. like reusing freed memory).
Libgdiplus is the foundation of Mono's System.Drawing.dll assembly. Any
leak from libgdiplus will make your .NET application leak - no GC help
here!
There are many ways to run valgrind on libgdiplus. The most simple one is
to use (or write) a C program using and use valgrind on it, but the most
interesting one are running System.Drawing samples using Mono.
* Using valgrind with Mono
Historically Mono and Valgrind didn't always played well together. If
this has discouraged you in the past then it's time to try it again!
Recent valgrind versions are able to deal with for self-modifying
programs (which is what the mono JIT does) by using the
--smc-check=all option.
As an extra bonus, Paolo (lupus) has shared his suppression file for
Mono. This removes a lot, but not all, false positives (or unimportant)
logs coming from the Mono runtime. This makes it easier and faster to
find what you're looking for. The suppression file is available in
Mono's SVN as /mono/data/mono.supp
Sample usage:
valgrind --tool=memcheck -v --leak-check=full --log-file=log
--smc-check=all --suppressions=mono.supp mono app.exe
This will run the app.exe application using mono and create a log file
named "log.####" (where #### is the process id). The log file will
indicates what leaked (and from where), what was (badly) reused after
being freed, ...