Перейти к содержанию

GDI против GDI+


Antonshka

Рекомендуемые сообщения

Привет всем.

На днях я захотел нарисовать скругленный прямоугольник средствами стандартного GDI. Его я всегда использовал и использую. Но, как оказалось, GDI не очень хорош в этом плане. Скругленные края получаются зубчатыми.

Я решил попробовать GDI+, с которым я не знаком вообще, и который мне всегда был интересен. Я открыл сайт MSDN, начал читать все подряд. Читаю и думаю, -"вот же оно, зачем я использовал стандартный GDI, перепишу теперь все на GDI+!".

Но, не долго я радовался. Тестирование, и информация из интернета, показали, - GDI+ медленнее GDI.

GDI+ не использует Hardware acceleration, он использует Software acceleration. Конечно, у GDI+ есть много преимуществ, как-то, Font, который не зависит от разрешения монитора, альфа смешивание, кривые, трансформации.

 

Думается мне теперь, что лучшая схема использования этих двух GDI, это их комбинирование. Там где стандартный GDI не справляется, то есть не имеет способности, нужно использовать GDI+.

Всегда использовать по максимуму стандартный GDI, а GDI+, использовать только в случае острой необходимости.

 

Вот один тест для GDI и GDI+ на градиентную заливку. Замер скорости отрисовки.

Спойлер

12/04/22  11:49:56 - [INFO] GDI gradient elapsed_ms = 10
12/04/22  11:49:56 - [INFO] Gdiplus gradient elapsed_ms = 12
12/04/22  11:49:56 - [INFO] GDI solid brush elapsed_ms = 0
12/04/22  11:49:57 - [INFO] GDI gradient elapsed_ms = 3
12/04/22  11:49:57 - [INFO] Gdiplus gradient elapsed_ms = 6
12/04/22  11:49:57 - [INFO] GDI solid brush elapsed_ms = 0
12/04/22  11:49:57 - [INFO] GDI gradient elapsed_ms = 2
12/04/22  11:49:57 - [INFO] Gdiplus gradient elapsed_ms = 8
12/04/22  11:49:57 - [INFO] GDI solid brush elapsed_ms = 0
12/04/22  11:49:59 - [INFO] GDI gradient elapsed_ms = 1
12/04/22  11:49:59 - [INFO] Gdiplus gradient elapsed_ms = 5
12/04/22  11:49:59 - [INFO] GDI solid brush elapsed_ms = 0
12/04/22  11:50:01 - [INFO] GDI gradient elapsed_ms = 1
12/04/22  11:50:01 - [INFO] Gdiplus gradient elapsed_ms = 5
12/04/22  11:50:01 - [INFO] GDI solid brush elapsed_ms = 0
12/04/22  11:50:01 - [INFO] GDI gradient elapsed_ms = 1
12/04/22  11:50:01 - [INFO] Gdiplus gradient elapsed_ms = 4
12/04/22  11:50:01 - [INFO] GDI solid brush elapsed_ms = 0

 

Это код.

Спойлер
LRESULT onPaintForMainWindow(WGW::OnPaintEvent* eventParam) {
	RECT clientRect{ 0 };
	GetClientRect(eventParam->hWnd, &clientRect);

	//GDI gradient.
	auto begin = std::chrono::steady_clock::now();
	WGW::GdiGraphics::gradientRectangle(eventParam->compDC, //Пример из книги программирование графики для Windows - Фень Юань
		clientRect.left,
		clientRect.top,
		clientRect.right,
		clientRect.bottom,
		RGB(100, 77, 155), RGB(103, 168, 179), 45);
	auto end = std::chrono::steady_clock::now();
	auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
	WGW::GUILogger::write(WGW::LoggerNotifyType::Info, L"GDI gradient elapsed_ms = %d\n", elapsed_ms);

	//Gdiplus gradient.
	Gdiplus::LinearGradientBrush linGrBrush(
		Gdiplus::Point(0, 0),
		Gdiplus::Point(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top),
		Gdiplus::Color(255, 100, 77, 155),
		Gdiplus::Color(255, 103, 168, 100));
	Gdiplus::Graphics graphics(eventParam->compDC);
	begin = std::chrono::steady_clock::now();
	graphics.FillRectangle(&linGrBrush, 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
	end = std::chrono::steady_clock::now();
	elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
	WGW::GUILogger::write(WGW::LoggerNotifyType::Info, L"Gdiplus gradient elapsed_ms = %d\n", elapsed_ms);
	
	//GDI solid brush.
	begin = std::chrono::steady_clock::now();
	HBRUSH brush = CreateSolidBrush(RGB(100, 77, 155));
	begin = std::chrono::steady_clock::now();
	FillRect(eventParam->compDC, &clientRect, brush);
	end = std::chrono::steady_clock::now();
	elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
	WGW::GUILogger::write(WGW::LoggerNotifyType::Info, L"GDI solid brush elapsed_ms = %d\n", elapsed_ms);
	DeleteBrush(brush);


	CopyRect(eventParam->updateRect, &clientRect);
	return FALSE;
}

 

 

В этом коде вначале рисуется градиентная заливка стандартным GDI. Код, который отвечает за эту заливку, взят из книги Фень Юань, и приведен ниже. Затем идет заливка GDI+. И наконец, простая заливка, не градиентная, стандартным GDI. Простую заливку средствами GDI+ я не стал тестировать.

Сильно заметно, как при резком изменении размера окна, правый его край отстает на 1 сантиметр, это при градиентной заливке средствами GDI+. При стандартном GDI, отставание в 5 - 7 раз меньше.

 

Градиентная заливка из книги Фень Юань

Спойлер
	BOOL GdiGraphics::gradientRectangle(HDC hDC, INT x0, INT y0, INT x1, INT y1, COLORREF c0, COLORREF c1, INT angle) {
		TRIVERTEX vert[4] = {
			{ x0, y0,  r16(c0), g16(c0), b16(c0), 0 },
			{ x1, y1,  r16(c1), g16(c1), b16(c1), 0 },
			{ x0, y1,  r16(c0, c1), g16(c0, c1), b16(c0, c1), 0 },
			{ x1, y0,  r16(c0, c1), g16(c0, c1), b16(c0, c1), 0 }
		};
		ULONG index[] = { 0, 1, 2, 0, 1, 3 };
		switch (angle % 180) {
		case 0:
			return GradientFill(hDC, vert, 2, index, 1, GRADIENT_FILL_RECT_H);
		case 45:
			return GradientFill(hDC, vert, 4, index, 2, GRADIENT_FILL_TRIANGLE);
		case 90:
			return GradientFill(hDC, vert, 2, index, 1, GRADIENT_FILL_RECT_V);
		case 135:
			vert[0].x = x1;
			vert[3].x = x0;
			vert[1].x = x0;
			vert[2].x = x1;
			return GradientFill(hDC, vert, 4, index, 2, GRADIENT_FILL_TRIANGLE);
		default:
			return GradientFill(hDC, vert, 2, index, 1, GRADIENT_FILL_RECT_H);
		}
		return FALSE;
	}

 

 

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.