I’ve been trying to add support for threads with an image processing script, but I’m getting some unexpected results.
First I load some bitmapdata, then I setup a ThreadPool and add a worker function that will process different regions of the bitmapdata.
Then I queue each region.
With the final onComplete, as a test I tried reassembling all the tiles back into a single bitmap in their original positions, but every time I ran the script some tiles were placed in unexpected places, but it was different on each run. However the majority of tiles were correctly placed:
Limiting the number of threads in the ThreadPool to 1 resulted in no misplaced tiles.
I’m new to the idea of threads and terms like ‘race conditions’, I suspect I’ve probably demonstrated one in the code below:
var threadPool = new ThreadPool(0,8);
var i = 0;
var total = 0;
var bd = Assets.getBitmapData("test");
var tilesize = 128;
var grid_w = Math.ceil(bd.width / tilesize);
var grid_h = Math.ceil(bd.height / tilesize);
var tiles:Array<MetaTile> = [];
threadPool.doWork.add((p:{x:Int,y:Int})->{
var x = p.x*tilesize;
var y = p.y*tilesize;
var s = tilesize;
var sr = new Rectangle(x, y, s, s);
var opaque_rect = get_nontransparent_pixels_rect(bd, sr); // returns the sub-region of non-transparent pixels within a region
if (opaque_rect.width > 0 && opaque_rect.height > 0) {
var sbd = new BitmapData(Math.ceil(opaque_rect.width), Math.ceil(opaque_rect.height), true, 0);
sbd.copyPixels(bd, opaque_rect, new Point());
var tile = {bd:sbd, x:x, y:y, ox:Std.int(x-opaque_rect.x), oy:Std.int(y-opaque_rect.y)};
tiles.push(tile);
}
threadPool.sendComplete(null);
});
threadPool.onComplete.add((tile)->{
i++;
trace(i+"/"+total);
if (i == total) {
// now let's try and reconstruct the original image with the tiles...
var temp_bd = new BitmapData(bd.width, bd.height, true, 0);
for (tile in tiles) {
temp_bd.copyPixels(tile.bd, tile.bd.rect, new Point(tile.x-tile.ox,tile.y-tile.oy));
}
save(temp_bd, "image.png");
}
});
for (y in 0...grid_h) {
for (x in 0...grid_w) {
total++;
threadPool.queue({x:x, y:y});
}
}
It appears some regions are being repeatedly copied into the image.
Is this a limitation of OpenFl and the way bitmapdata is handled internally?
Or is it possible but my approach is wrong?