С++ MFC StretchDIBits PixelFormat8bppIndexed
Игра с MFC и кажется, что при рисовании PixelFormat8bppIndexed что-то не так.
С другими форматами все в порядке.
Я думаю, проблема в:
Как это исправить?
Gdiplus::GetHBITMAP позволяет напрямую получать HBITMAP . В большинстве случаев этого достаточно, чтобы разрешить использование функций GDI с помощью GDI+.
Если по какой-то причине вы должны использовать StretchDIBits , тогда сначала используйте GetDIBits для извлечения bits и BITMAPINFO
При распределении памяти для BITMAPINFO убедитесь, что вы добавили дополнительную память для палитры в случае работы с 8-битным растровым изображением:
Вы также можете использовать вспомогательный класс gdiplus_init чтобы убедиться, что запуск/выключение всегда вызываются.
SetDIBitsToDevice vs D3D/DD
сразу оговорюсь о том, что с DirectX знаком на уровне туторов и небольших самописных тестовых приложений. теперь собственно по теме: имеется большой битмап, формат BGRA, типичные размеры 5 000 x 5 000. в риалтайме происходит его обработка\прорисовка на основе получаемых в риалтайме данных. оптимизация алгоритмов под MMX\SSE позволила снизить время обработки до 2-4 ms на проход. узким местом стал именно вывод на экран через SetDIBitsToDevice (аналог StretchDIBits без маштабирования), занимает вывод около 7-8 ms. скорость работы вполне приемлима (
100 fps), но есть несколько но:
1. на мой взгляд, не спортивно когда вывод на экран занимает в два-четыри раза больше времени, чем сами расчёты. хотелось бы этот момент оптимизировать.
2. tearing-артифакт. с этим понятно.
выход один — D3D/DD. тут тоже, по моему мнению, не всё гладко:
1. обработку нельзая перенести на GPU, следовательно текстура будет в обычной памяти, т.е. будет каждый кадр переноситься в память GPU.
2. нельзя создать одну текстуру для всего битмапа, его размеры не позволяют, т.е. каждый кадр получаем дополнительный перенос из битмапа в текстуру меньшего размера.
будет ли в таком случае хоть какой-то прирост производительности? может быть что-то ещё присоветуете?
в д3д10 можно сделать текстуру размером 8192х8192 и думаю вполне можно выполнить любую обработку шейдером.
если по политическим или другим причинам д3д10 не подходит.
то еще можно попробовать
DrawDib
The DrawDib functions provide high performance image-drawing capabilities for device-independent bitmaps (DIBs). DrawDib functions support DIBs of 8-bit, 16-bit, 24-bit, and 32-bit image depths.
DrawDib functions write directly to video memory. They do not rely on functions of the graphics device interface (GDI).
по идее то что не используется GDI может ускорить вывод.
stab
А формат битмэпа соответствует формату экрана? Какой размер выводимого окна? А то что-то медленно, у меня SetDiBits дает 250 fps на 1024*768.
DrawDib API — чуда не произошло, производительность не выросла ни на сотую долю миллисекунды. что касается D3D10, это конечно хорошо, только мало у кого есть D3D10-карточки.
Mikle, в настройках экрана стоит 32 bit, т.е. видимо соответствует. размер 1280×1024.
.. если расчёты отключить то около 150 fps выдаёт. при 1024×768 тоже
stab
>с DirectX знаком на уровне туторов и небольших самописных тестовых приложений.
Рекомендуется сначала изучить тему глубже.
Прироста не будет, будут фантастические тормоза в любой реальной задаче.
ЗлобныйШкольнег, эти 250 fps при 1024×768 следует понимать как предел по пропускной способности AGP?
stab
Потому что у CPU есть еще куча дел, кроме растеризации.
хм.. это уже скорее не по теме. что-то я не очень понимаю откуда берётся это ограничение. загрузка процессора на приоритетах REALTIME_PRIORITY_CLASS + THREAD_PRIORITY_TIME_CRITICAL —
55%, так же как и при обычных приоритетах. выходит, при тупом выводе одного и того же битмапа без его модификаций, около 50 процентов времени процессор простаивает, что есть хорошо, а с другой стороны плохо.
причём, скорость безусловной обработки производимой CPU над битмапом 1024×768 без вывода на экран — 500 fps (2 мс на проход), по 1.5 Гб/c по DDR качает в обе стороны (чтение\запись), данные в кеш CPU полностью точно не влазят. загрузка CPU — 70%. в сумме, при условии, что хоть что-то закешировалось — 2-3 Гб/c.
Mikle
>А формат битмэпа соответствует формату экрана?
stab
>формат BGRA
>.
>в настройках экрана стоит 32 bit,
> т.е. видимо соответствует.
а вот не факт ))
по мойму экранный формат чаще RGBA бывает или ARGB
может там еще байтики местами при выводе меняютцо ?
AndryBlack, NVIDIA в документе озаглавленном как «Achieving Efficient Bandwidth Rates» пишет:
.. NVIDIA graphics cards are built to match the Microsoft GDI
pixel layout, so make sure the pixel format in system memory is BGRA.
.. storing 8-bit textures in a BGRA layout in system memory and use the
GL_BGRA as the external format for textures to avoid swizzling.
c++ — Как заменить StretchDIBits на BitBlt
Здравствуйте! Использую такую функцию:
Но она медленная по сравнению с BitBlt. Вопрос в том, как ее заменить?
-
6 1
- 19 янв 2020 2020-01-19 05:59:32
- helldrg
1 ответ
это делается проще всего где-то так:
Для работы с памятью на прямую, вам нужна таки секция:
За тем вам нужно скопировать данные именно в выданый системой участок памяти и именно с bits работать. эту ссылку bits можно после копирования переписать в buffer->Memory https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd183494%28v=vs.85%29.aspx Освобождать (DeleteObject,DeleteDC) и рисовать (BitBlt) также само.
Рисовать win умеет только dc. Но эта dc должна быть связана с bitmap. Поэтому так.
Проверьте что б CreateBitmap возвращало не ноль. Ф-ция довольно «вредная». Она не все форматы поддерживает. Формат указывается в предпоследнем параметре. Ещё я сталкивался с тем, что строки картинки в некоторых случаях нужно выравнивать по границам двойного слова, иначе картинку «перекашивает» по диагонали набок.
Если надо загружать с памяти или с диска то можно так: Как загрузить картинку из памяти С++ (Win)?
Технология отображения растров
Для вывода DIB-растров используются функции StretchDIBits и SetDIBitsToDevice. Функция StretchDIBits имеет следующие параметры:
— дескриптор контекста устройства;
— х и у координаты, ширина и высота области-приемника изображения (в логических единицах);
— х и у координаты, ширина и высота области-источника изображения^ пикселах);
— адрес массива пикселов изображения;
— адрес заголовка информационного блока в bmp;
— флаг интерпретации цветовой таблицы;
— код растровой операции.
Область-источник указывает, какая часть растра выводится, происходит ли зеркальное отображение по горизонтали и/или по вертикали. Область-приемник задает место на поверхности изображения графического устройства, область-приемник также можно зеркально отразить и масштабировать. Если размеры областей источника и приемника совпадают, то вывод растра происходит без масштабирования. Способ добавления новых или удаления ненужных пикселов хранится в контексте устройства и может быть изменен функцией SetStretchBltMode. Так, возможно вычислять средний цвет по группе пикселов, комбинировать пикселы с помощью побитовых логических операций, отбрасывать лишние пикселы.
Флаг интерпретации цветовой таблицы указывает, что именно содержит эта таблица компоненты RGB или индексы цветов в логической палитре.
Код растровой операции показывает способ копирования из области-источника в область-приемник. Простейшим кодом является SRCCOPY, задающий копирование без дополнительных операций.
Функция SetDIBitsToDevice позволяет выводить растры с сохранением масштаба и ориентации либо полностью, либо по строкам.
Для работы с DDB-растрами, являющимися объектами GDI и хранящимися в памяти GDI, используются другие API-функции.
Создать DDB-растр можно с помощью функций CreateBitmap, CreateBitmapInDirect, CreateCompatibleBitmap. Все эти функции возвращают дескриптор растрового объекта. CreateBitmap имеет следующие параметры;
— ширина и высота растра в пикселах;
— количество плоскостей cPlanes для хранения цвета пиксела;
— количество битов на 1 пиксел cBitsToPxl;
— адрес массива с пикселами.
По параметрам cPlanes и cBitsToPxl драйвер графического устройства осуществляет подбор формата хранения цвета, чтобы количество битов на пиксел не превышало произведения указанных параметров.
Функция CreateBitmapInDirect работает с теми же параметрами, что и CreateBitmap, однако они передаются через структуру типа BITMAP. Функция CreateCompatibleBitmap создает DDB-растр, совместимый с контекстом заданного устройства. Недостатком трех рассмотренных функций является то, что они создают либо монохромный растр с инициализацией пикселов, либо цветной растр без инициализации.
Для работы в программе с инициализированными цветными растрами лучшим выходом является использование ресурсов. Ресурсами являются пиктограммы, рисунки, меню, диалоговые окна, курсоры и шрифты. Они описываются во внешнем текстовом файле, называемом файлом ресурсов и имеющим расширение гс. Различные ресурсы описываются в нем в соответствии со своими форматами. Для того чтобы включить ресурсы в *.ехе файл, их необходимо откомпилировать специальным компилятором ресурсов, который может быть встроен в интегрированную среду разработки программ. Результатом работы компилятора ресурсов является файл с расширением res, который вместе с объектным модулем обрабатывается редактором связей для получения ехе-файла. Преимуществами использования ресурсов являются простота их редактирования и независимость описания от текста исходного модуля, возможность редактирования ресурсов непосредственно в загрузочном файле (например, для перевода пунктов меню на другой язык), возможность извлечения ресурсов из загрузочного файла для последующего использования в других приложениях.
Каждому ресурсу при описании присваивается идентификатор ресурса, который затем используется API-функциями. Например, описание пиктограммы ICON1.ICO имеет вид:
Идентификатор_ресурса ICON [параметры] «ICON1.ICO»
а описание растрового изображения BITMAP1.BMP:
Идентификатор_ресурса BITMAP [параметры] «BITMAP1.BMP» В MASM32 используется числовой идентификатор ресурса.
Несмотря на важность DDB-растров, в Windows отсутствует функция их отображения на устройстве вывода. Их вывод осуществляется
путем копирования с одного устройства на другое как без изменения масштаба (функция BitBlt), так и с изменением (функция StretchBlt). Устройством-приемником служит окно, а в качестве устройства-источника в памяти нужно создать область, которая по своим возможностям должна быть совместима с экраном и в которую нужно записать изображение. Совместимая с окном область памяти также должна иметь свой контекст, называемый контекстом памяти или совместимым контекстом памяти. В контексте памяти хранятся дескрипторы инструментов рисования, которые можно заменять на свои, в контекст памяти можно выводить графику. Отличием контекста памяти от контекста окна является возможность загрузки в контекст памяти дескриптора растрового изображения.
Рассмотрим реализацию вывода на экран DDB-растра, описанного как ресурс. Для вывода растрового изображения необходимо выполнить следующие действия:
1) загрузить растровое изображение в память и запомнить его дескриптор. Для этого используется функция LoadBitmap, первым параметром которой является дескриптор экземпляра приложения, а вторым идентификатор ресурса, описывающего DIB-растр. Функция выделяет память под изображение, загружает его туда, преобразует в DDB-формат и возвращает дескриптор hBmp области памяти с растром. Этот шаг выполняется вне обработки сообщения WMPAINT. Отметим, что если требуется работать с изображением, размер которого будет известен позже, то можно зарезервировать требуемый объем памяти функцией CreateCompatibleBitmap. Загрузку битового образа можно осуществлять с помощью функции Loadlmage, загружающей не только растры, но еще пиктограммы и курсоры. Loadlmage возвращает дескриптор DDB-растра.
2) получить совместимый с окном контекст устройства для области памяти, где будет храниться изображение, с использованием функции CreateCompatibleDC, единственным параметром которой является дескриптор контекста устройства, куда должно быть выведено изображение. Этот дескриптор hDC либо возвращается функцией Begin-Paint в обработке WMPAINT, либо должен быть получен с помощью функции GetDC. Если использовалась функция GetDC, необходимо после работы вернуть контекст системе с помощью функции Re-leaseDC.
3) включить дескриптор области памяти с растровым изображением hBmp в совместимый с окном контекст памяти, используя функцию SelectObject. Значение дескриптора растрового изображения по умолчанию в совместимом контексте нужно сохранить, хотя он описывает
изображение размером всего в 1 пиксел. После этого в совместимую память можно выводить любые объекты, вызывать функции рисования.
4) Для того чтобы отобразить на экране созданное изображение,
необходимо скопировать его в окно с использованием функций BitBIt
или StretchBlt. Рассмотрим вызов и параметры функции BitBIt. Вызов
имеет вид:
— hDC и memDCдескрипторы окна приложения, куда копируется изображение, и совместимого контекста памяти;
— хО и уО координаты начальной точки верхнего левого угла изображения-источника, с которой начинается копирование в изображение-приемник. Если все изображение копируется полностью, то нужно указать нулевые значения хО и уО;
— х и у задают координаты верхнего левого угла копии в окне, считая от начала его клиентской области;
— w и h задают ширину и высоту копируемой прямоугольной части изображения. Максимальное значение этих параметров ширина и высота в пикселах исходного изображения. Характеристики изображения можно получить с помощью функции GetObject, которая для растрового изображения заполняет структуру BITMAP, поля которой bmWidth и bmHeight хранят ширину и высоту изображения.
— FLAG указывает вид операции над битами изображения и битами области копирования, что используется для реализации мультипликации. В простейшем случае FLAG=SRCCOPY, что указывает на копирование источника в приемник с затиранием области копирования. Если нужно реализовать мультипликацию, то в цикле перемещения объекта сначала выводится изображение с FLAG=SRCCOPY, затем после задержки с FLAG=MERGEPAINT, что дает стирание изображения и получение белого фона, после чего изменяют координаты вывода.
Функция StretchBlt позволяет масштабировать изображение и выполнять его зеркальные отражения.
5) вернуть в совместимый контекст памяти старое значение дескриптора битового изображения.
6) Уничтожить контекст совместимой с окном области памяти.
Иллюстрирующий текст продедуры вывода DDB-растра на MASM32:
Paint_Proc proc hWin:DWORD, hDC:DWORD
LOCAL memDC :DWORD
return 0 Paint_Proc endp
Источник: Сучкова, Л.И. Win32 API: основы программирования: учебное пособие/ Л.И. Сучкова; АлтГТУ им. ИИ. Ползунова. -Барнаул, АлтГТУ, 2010. 138 с, ил.
Что такое код stretchdibits
The StretchDIBits function copies the color data for a rectangle of pixels in a DIB, JPEG, or PNG image to the specified destination rectangle. If the destination rectangle is larger than the source rectangle, this function stretches the rows and columns of color data to fit the destination rectangle. If the destination rectangle is smaller than the source rectangle, this function compresses the rows and columns by using the specified raster operation.
Syntax
Parameters
A handle to the destination device context.
The x-coordinate, in logical units, of the upper-left corner of the destination rectangle.
The y-coordinate, in logical units, of the upper-left corner of the destination rectangle.
The width, in logical units, of the destination rectangle.
The height, in logical units, of the destination rectangle.
The x-coordinate, in pixels, of the source rectangle in the image.
The y-coordinate, in pixels, of the source rectangle in the image.
The width, in pixels, of the source rectangle in the image.
The height, in pixels, of the source rectangle in the image.
A pointer to the image bits, which are stored as an array of bytes. For more information, see the Remarks section.
A pointer to a BITMAPINFO structure that contains information about the DIB.
Specifies whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or indexes. The iUsage parameter must be one of the following values.
Value | Meaning |
---|---|
DIB_PAL_COLORS | |
DIB_RGB_COLORS |