Java – Android Bitmap Multithreading – Not Thread-Safe?

Android Bitmap Multithreading – Not Thread-Safe?… here is a solution to the problem.

Android Bitmap Multithreading – Not Thread-Safe?

I

want to work with bitmaps in my Android app – bitmaps can be large, so I use multithreading to perform faster operations. Here is my code (part of the Runnable subcode):

@Override
public void run() {
    int imageHeight = filter.getBitmap().getHeight();
    int start = threadNumber * imageHeight / threadCount;
    int stop = (threadNumber + 1) * imageHeight / threadCount;
    for (int j = start; j < stop; j++) {
        filter.processLine(j);
    }
}
//...
protected void processLine(int lineNumber)
{
    int width = bitmap.getWidth();
    int pixels[] = new int[width];
    bitmap.getPixels(pixels, 0, width, 0, lineNumber, width, 1);
    for (int i = 0; i < width; i++) {
        pixels[i] = processPixel(pixels[i]);
    }
    bitmap.setPixels(pixels, 0, width, 0, lineNumber, width, 1);
}

When I only use 1 thread in the pool, everything works fine. Unfortunately, when the number of threads I use is equal to the number of cores of the processor (4 in my device), the result is as follows (for grayscale filters):

issue

Sometimes it looks like:

  • bitmap.getPixels(…) does not work because there are black lines in the output
  • bitmap.setPixels(…) does not work because there are unchanged lines in the output

Am I right? Are these functions thread-unsafe? How should I perform multithreaded bitmap filtering to be fast and thread-safe?

Solution

2D image processing in Android is provided by the Skia library, which is also used by Chrome.

It’s hard to find definitive answers. “Skia is not thread-safe, although SkBitmap [Bitmap uses] is thread-safe…” I perused a bunch of inscrutable JNI/C++ code, and this is the best I can offer (which seems to be more than anyone else):

I think you should call bitmap.getPixels() on the entire bitmap. The resulting array is then divided and threaded. When all threads are complete, reassemble the results and call bitmap.setPixels().

It looks like bitmap.getPixels() and bitmap.setPixels() should be nothing more than memcpy(), but there’s a lot more to do under the hood, including reference counting, image caching, color space conversion, premultiplication, and who knows what else. Removing Bitmap methods from concurrent processing should keep you out of trouble.

Related Problems and Solutions