How to efficiently create wxBitmap from std::vector<std::vector<wxColour>> Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
fishnet37222
Experienced Solver
Experienced Solver
Posts: 53
Joined: Sat May 06, 2017 1:40 pm

How to efficiently create wxBitmap from std::vector<std::vector<wxColour>>

Post by fishnet37222 » Mon Apr 19, 2021 5:21 pm

I'm using the Microsoft Concurrency Runtime to generate color values for pixels in an image while splitting the work into parallel loads since the calculations are independent of each other.

Here is the code that does the calculations and creates the wxBitmap from the calculated color values.

Code: Select all

void FractalCanvas::Calculate(const long width, const long height, long maxIterations, double xMin, double xMax, double yMin, double yMax, std::vector<wxColour> colors)
{
	this->bmpFractal = wxBitmap(width, height);
	this->CalcVirtualSize();
	this->Refresh();

	auto token = cts.get_token();
	this->isCalculating = true;
	concurrency::concurrent_vector<std::vector<wxColour>> bitmapData(height);

	concurrency::parallel_for(0, static_cast<int>(height), [&](const int screenY)
	{
		std::vector<wxColour> row;
		for (auto screenX = 0; screenX < width; screenX++)
		{
			if (concurrency::is_current_task_group_canceling())
			{
				return;
			}

			// TODO: Replace with actual Mandelbrot calculation.
			row.push_back(wxTheColourDatabase->Find("WHITE"));
		}
		bitmapData[screenY] = row;
	});

	{
		wxMemoryDC dc(this->bmpFractal);
		for (size_t y = 0; y < bitmapData.size(); y++)
		{
			auto row = bitmapData[y];
			for (size_t x = 0; x < row.size(); x++)
			{
				dc.SetPen(row[x]);
				dc.DrawPoint(static_cast<int>(x), static_cast<int>(y));
			}
			wxTheApp->Yield();
		}
	}
	this->isCalculating = false;

	this->Refresh();
}
Is there a more efficient way of doing this?

I was initially going to use concurrency::combinable to give each thread its own wxBitmap to work on and then combine them once all the calculations were done, but I couldn't figure out how to determine which rows each thread had worked on.

I'm pretty sure going the concurrency::combinable route would be more efficient, provided I can figure out how to determine with rows each thread has worked on.
Dave F.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 3041
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to efficiently create wxBitmap from std::vector<std::vector<wxColour>>

Post by PB » Mon Apr 19, 2021 5:27 pm

wxBitmap, just as any other GUI object (and unlike wxImage), cannot be used in a secondary thread.

While it may work on some platforms, the docs clearly say do not this. But while this applies to e.g. wxPens or wxBrushes, I am not sure if it really does to wxBitmap.

BTW, I am just curious, how much speedup did you observe why doing the task with multiple threads. I am certainly not knowledgeable about high speed graphics programming but I wonder if wxBitmap is really suitable as the end target. I would imagine there must be a better solution...

User avatar
doublemax
Moderator
Moderator
Posts: 16014
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to efficiently create wxBitmap from std::vector<std::vector<wxColour>>

Post by doublemax » Mon Apr 19, 2021 6:11 pm

Use wxPixelData to write directly into the bitmap, without the vectors:
https://docs.wxwidgets.org/trunk/classw ... _data.html

As you're just writing into memory, it's safe from multiple threads. But you must destroy the wxPixelData instance before you use the bitmap for any other operation, like drawing onto a wxDC.

Make sure to read the "wxMSW note" on the above page.
Use the source, Luke!

Post Reply