Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Програмирование графики
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
Страницы: 1, 2
whale_nik
Народ, надо вывести двумерный массив данных 1000*800 в виде точек на image (прогаю в buildere)
причем надо его сдвигать на одну координату скоростью 0,1сек ( с вводом новых )
Если делать тупо в лоб то страшные тормоза, посоветуйте куда копать, явно есть методы быстрого вывода,
задача для меня вновье.
Те в итоге видим экран 1000*800, по нему ползет изображение, которое обновляется справа на одну линию все время.
_pv
быстрые методы это аппаратно через opengl.
хотя даже и тупое копирование вроде как работает.
на fltk несколько мс чтобы картинку скопировать и еще ~50мс чтобы отрисовать.


Код
unsigned char pic[1000*800*3];

class MyWindow : public Fl_Double_Window{
public:
  MyWindow() : Fl_Double_Window(1000,800) { }
  void draw(){ fl_draw_image(pic,0,0,1000,800,3,0); }
};

MyWindow * w;

void callback(void*) {
  static int t = GetTickCount();
  printf("%d\n",GetTickCount() - t);
  t = GetTickCount();

  for (int y = 0; y < 800; y++){
    pic[3*(0+y*1000)+0] = rand();
    pic[3*(0+y*1000)+1] = rand();
    pic[3*(0+y*1000)+2] = rand();
    for (int x = 999; x >= 1; x--){
      pic[3*(x+y*1000)+0] = pic[3*((x-1)+y*1000)+0];
      pic[3*(x+y*1000)+1] = pic[3*((x-1)+y*1000)+1];
      pic[3*(x+y*1000)+2] = pic[3*((x-1)+y*1000)+2];
    }
  }
  w->redraw();
  Fl::repeat_timeout(0.1, callback);
}

int main(int argc, char ** argv){
  w = new MyWindow();
  for (int y = 0; y < 800; y++){
    for (int x = 0; x < 1000; x++){
      pic[3*(x+y*1000)+0] = rand();
      pic[3*(x+y*1000)+1] = rand();
      pic[3*(x+y*1000)+2] = rand();
    }
  }
  Fl::add_timeout(0.1, callback);
  w->show();
  return Fl::run();
}

whale_nik
Не совсем понял а как это все вывести на форму ?
Я пока просто точки ставил rolleyes.gif
whale_nik
Типа такого надо )
Вся картинка должна ехать влево с обновлением справа
jcxz
Цитата(whale_nik @ Sep 2 2016, 00:00) *
Типа такого надо )
Вся картинка должна ехать влево с обновлением справа

Открываете MSDN на разделе Windows GDI\Bitmap Functions. Изучаете всё, что касается семейства BitBlt-функций.
Создаёте memory device context, рисуете в нём (только с умом - не перерисовывая каждый раз туеву хучу точек, а дорисовывая только новый участок точек), затем из memory device context перекидываете картинку (с необходимым сдвигом) за пару операций BitBlt (или родственных) на screen device context.
И если всё так сделаете, загрузка CPU будет близкая к нулю, даже на слабом CPU.
AHTOXA
Цитата(whale_nik @ Sep 1 2016, 19:49) *
Если делать тупо в лоб то страшные тормоза, посоветуйте куда копать, явно есть методы быстрого вывода,
задача для меня вновье.

Пример на дельфи, на билдер сами адаптируете.

1. Создаёте вспомогательный TBitmap (где-нибудь в конструкторе):
Код
    bt := TBitMap.Create;


2. Рисуете в него свои точки:
Код
    for y := 1 to bt.Height-1 do
    begin
        pt := bt.ScanLine[y];
        for x := 1 to bt.Width-1 do
          pt^[x] := Round(Random*x);
        end;
    end;


3. Можете добавить что угодно, например, текст:
Код
    bt.Canvas.TextOut(10,10, 'И не надо никакого MSDN');


4. Выводите битмап на форму:
Код
     Canvas.Draw(0,0, bt);


Всё!
whale_nik

Сделал как советуете, все равно жесть как медленно и жрет кучу процессорного времени (
Может не так что сделал ?
Builder 6.0
sigmaN
Цитата
Открываете MSDN на разделе Windows GDI\Bitmap Functions. Изучаете всё, что касается семейства BitBlt-функций.
Создаёте memory device context, рисуете в нём (только с умом - не перерисовывая каждый раз туеву хучу точек, а дорисовывая только новый участок точек), затем из memory device context перекидываете картинку (с необходимым сдвигом) за пару операций BitBlt (или родственных) на screen device context.

Плюсую.
Кстати у TCanvas есть Handle, который явялется device context, который, как я понимаю, можно пихать в WinAPI функции. Кроме того у TCanvas имеются методы с аналогичным WinAPI функционалом, но надо бы протестировать их на тормознутость. http://docs.embarcadero.com/products/rad_s...vas_Handle.html

Возможно у TImage тоже будет возможность взять device context....надо погуглить
_pv
у openGL есть glDrawPixels.
инициализация через GLFW

а вот winAPI функции лучше запихать в... <Гусары, МОЛЧАТЬ!>
можно заодно с builder 6.0

Код
#include "GLFW/glfw3.h"
#include <stdio.h>
#include <windows.h>

unsigned char pic[1000*800*3];

int main(void){
    int t0 = GetTickCount();
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit()) return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(1000, 800, "Hello World", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window)){
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);
        for (int i = 0; i < 1000*800*3; i++) pic[i] = rand();
        glDrawPixels(1000,800, GL_RGB, GL_UNSIGNED_BYTE, pic);
        /* Swap front and back buffers */
        glfwSwapBuffers(window);
        /* Poll for and process events */
        glfwPollEvents();
        printf("%d\n", GetTickCount()-t0);
        t0 = GetTickCount();
    }
    glfwTerminate();
    return 0;
}

whale_nik
Мне кажется основные тормоза и загрузка это инициализация битовой матрици все время по новой это 2 640 000 байт
Если бы как то не заносить значения по новой а двигать область памяти этой матрицы, прибавляя справа по одному столбцу, там же все на указателях, нельзя так сделать ? Память как то закольцевать )
jcxz
Цитата(_pv @ Sep 3 2016, 05:34) *
у openGL есть glDrawPixels.
а вот winAPI функции лучше запихать в... <Гусары, МОЛЧАТЬ!>

И Ваш код будет таким-же тормознутым как и предыдущих дельфи-"специалистов". Главная ошибка: перерисовывать попиксельно каждый раз весь экран. Рисовать по пикселам нужно минимум - только обновлённую часть. Старую часть изображения просто копировать ...Blt-функциями.
Сомневаюсь, что у OpenGL будет выигрыш по сравнению с WinAPI-шными BitBlt/PatBlt/....
В своё время много времени потратил на оптимизацию подобной задачи: переделывал изначальный свой WinAPI-вариант (через BitBlt/PatBlt/...) на DirectDraw. Получил абсолютно то же самое время работы. Сделал вывод, что при возможности, WinAPI-шные BitBlt/PatBlt/... вызывают изнутри DirectX, поэтому и не видно разницы во времени работы. Думаю что с OpenGL будет то же самое.
Конечно в том, что ставить точки лучше не по одной, а пачкой - Вы правы. В WinAPI по-моему тоже есть подобная функция.

Цитата(whale_nik @ Sep 3 2016, 06:36) *
Если бы как то не заносить значения по новой а двигать область памяти этой матрицы, прибавляя справа по одному столбцу, там же все на указателях, нельзя так сделать ? Память как то закольцевать )

Я Вам это советовал ещё несколько сообщений назад. Но видно "чукча - не читатель..."
AHTOXA
Цитата(whale_nik @ Sep 3 2016, 02:26) *
Сделал как советуете, все равно жесть как медленно и жрет кучу процессорного времени (
Может не так что сделал ?

Так у вас таймер молотит раз в миллисекунду! Это 1000FPS, конечно жрёт. Сделайте, 100ms, и будет всё нормально.
k155la3
Курить в сторону направления, заданного jcxz sm.gif

Перемещая окна винды, очевидно, что скроллинг реализовать можно. Так как сама ОС это делает.

ТС можно также попробовать посмотреть в сторону оптимизации алгоритма вывода на отображение
нарисованного тем или иным способом. Я имею ввиду конвейерную подготовку данных и их отображение.
( Пока виртуально отрисовывается массив, уже готовый образ отображается другим потоком).

Кроме того, если ОНО сдвигается, то нет смысла перерисовывать 99.999 информации.
Достаточно вывести правый "столбик", который "новый". Эти 99.999 изображения уже на экране, их выводить не нужно, достаточно
только указать драйверу сместить указатель отображения левого верхнего угла массива в видео-памяти.
Как до него добраться - это уже спортивный вопрос sm.gif


_pv
Цитата(jcxz @ Sep 3 2016, 09:01) *
И Ваш код будет таким-же тормознутым как и предыдущих дельфи-"специалистов".

не будет,
нынче скопировать пару МБайт из памяти в память это долго??? на моём довольно древнем компе, которому лет 10 уже, это занимает 1.5мс.
Код
LARGE_INTEGER t0,t1,f;
QueryPerformanceFrequency(&f);
QueryPerformanceCounter(&t0);
for (int j = 0; j < 800; j++) memcpy(&pic[j*3000],&pic[j*3000+3],3000-3);
QueryPerformanceCounter(&t1);
printf("%G\n", (double)(t1.QuadPart - t0.QuadPart)/  f.QuadPart);


да это криво и правильно было бы сделать два буфера размером с экран и заполнять их по очереди и отрисовывать со сдвигом.
для этого есть glRasterPos3f.
а совсем правильно сложить это сразу в память видеокарты, тогда и сдвиги и отрисовка процессор никак не нагрузят
whale_nik
Я правильно понял, что
если создать две одинаковые матрицы, и потом по очереди копировать одну в другую со сдвигом , прибавляя новые данные ? Так можно скопировать ?
Можно примерчик плиз ?
Я так понимаю это glCopyPixels ?

Цитата(AHTOXA @ Sep 3 2016, 10:09) *
Так у вас таймер молотит раз в миллисекунду! Это 1000FPS, конечно жрёт. Сделайте, 100ms, и будет всё нормально.


Эта штука вообще должна летать со скоростью пули по хорошему, как на локаторе С-400 )
со 100 мс пока зкран весь сдвинется родить можно будет )
Onkel
Цитата(_pv @ Sep 3 2016, 11:48) *
а совсем правильно сложить это сразу в память видеокарты, тогда и сдвиги и отрисовка процессор никак не нагрузят

я еще когда в 90е делал систему сдирания буржуйских чипов для наших конфетных харь, готовил следующий экран в памяти, vga имело буфер размером со всю экранную память, и потом просто переключал память, выводимую на экран.
AHTOXA
Цитата(whale_nik @ Sep 3 2016, 14:38) *
со 100 мс пока зкран весь сдвинется родить можно будет )

Вы же сами в стартовом посте написали про 0.1с. Вот это и есть 100мс.
А 1000FPS вы никакими BitBlt и OpenGl-ями не получите. Урежьте осетраsm.gif
_pv
Цитата(whale_nik @ Sep 3 2016, 16:38) *
Я правильно понял, что
если создать две одинаковые матрицы, и потом по очереди копировать одну в другую со сдвигом , прибавляя новые данные ? Так можно скопировать ?
Можно примерчик плиз ?
Я так понимаю это glCopyPixels ?

с glCopyPixels сдвинуть текущую картинку на один пиксель и через glDrawPixels дорисовать только один недостающий столбец.
никаких дополнительных буферов в этом случае вообще не надо.
whale_nik
Цитата(AHTOXA @ Sep 3 2016, 14:10) *
Вы же сами в стартовом посте написали про 0.1с. Вот это и есть 100мс.
А 1000FPS вы никакими BitBlt и OpenGl-ями не получите. Урежьте осетраsm.gif

Чета я не то сказал )))
Реально хотелось бы достичь макс скорость 5 сек на весь экран, это 5/1100 = 4,5 мс/столбец
ну а тут как получиться
Цитата(_pv @ Sep 3 2016, 14:17) *
с glCopyPixels сдвинуть текущую картинку на один пиксель и через glDrawPixels дорисовать только один недостающий столбец.
никаких дополнительных буферов в этом случае вообще не надо.

Осталось все это нарисовать в коде )
Цитата(Onkel @ Sep 3 2016, 13:47) *
я еще когда в 90е делал систему сдирания буржуйских чипов для наших конфетных харь, готовил следующий экран в памяти, vga имело буфер размером со всю экранную память, и потом просто переключал память, выводимую на экран.

Ну тут кроме это окна еще куча других работает, копировать весь экран не получиться.

Такое предлагаю,
создаем матрицу размер +1 по х,
вводим новые значения в правый столбец,
выводим в канву со сдвигом -1 (чтобы новые данные появились справа)
копируем полученную канву в матрицу с нуля,
и тд.

Типа того, работает но жрет ресурсов столько же как предыдущие варианты (
похоже это типа тоже тупое копирование массива а не сдвиг указателя памяти

TRect tRectFrom(1,0,1101,800);
TRect tRectTo (0,0,1100,800);

Image1->Canvas->CopyMode=cmSrcCopy;
Image1->Canvas->CopyRect(tRectTo,gBitmap->Canvas,tRectFrom);

TRect tRectFrom2(0,0,1100,800);
TRect tRectTo2 (0,0,1100,800);

gBitmap->Canvas->CopyRect(tRectTo2,Image1->Canvas,tRectFrom2);

for ( y = 0; y < h1; y++)
{
ptr = (Byte *)gBitmap->ScanLine[y];

ptr[3300+0] = (Byte)Col;
ptr[3300-1] = (Byte)0;
ptr[3300-2] = (Byte)0;

ptr[3300-3] = (Byte)Col;
ptr[3300-4] = (Byte)0;
ptr[3300-5] = (Byte)0;

ptr[3300-6] = (Byte)Col;
ptr[3300-7] = (Byte)0;
ptr[3300-8] = (Byte)0;

}

ps а не , был не прав, вроде меньше нагрузка ...
k155la3
Цитата(whale_nik @ Sep 3 2016, 14:51) *
. . . .
Ну тут кроме это окна еще куча других работает, копировать весь экран не получиться.
. . . .

Если Вам эта работа нужна в качестве инструмента.
В винде, по крайней мере в XP, можно "монополизировать" экран, те. фактически работать без окон, графика в полноэкранном режиме.
(я давненько игрался с этим режимомом для реализации простого, но длинного графика-лога с удобным скроллингом мышкой и масштабированием)
Окон естесетвенно, нет. Ваш график отображается реалтайм.
При восстановлении стандартного режима, окно "свертывается", с упрощенным отрбражением, скроллинг загрубляется,
например, до 20 позиций раз по полсекунды.


whale_nik
Без окон никак, увы.

Вот вроде бы нагрузка небольшая получилась...
DASM
а почему побайтно работаете и не пословно?
whale_nik
Цитата(DASM @ Sep 3 2016, 16:43) *
а почему побайтно работаете и не пословно?


Не понял вопроса, в смысле цвета ?

AHTOXA
Цитата(whale_nik @ Sep 3 2016, 16:51) *
Чета я не то сказал )))
Реально хотелось бы достичь макс скорость 5 сек на весь экран, это 5/1100 = 4,5 мс/столбец
ну а тут как получиться

4,5 мс - это 222 герца. Тоже многовато.
Вы примите во внимание, что для человеческого глаза не нужна такая частота. Достаточно, скажем, 60 Гц (вернее, достаточно 25, а 60 - это будет ультра-гладкая картинка). Вот и перерисовывайте соответственно 60 раз в секунду. Пусть за одну перерисовку у вас добавляется не один, а несколько столбцов.
amaora
В лоб будет больше 60 к/с, если оптимизировать как должно, немного медленнее memcpy. А можно и взять готовый memmove, останется добавлять один столбец. Выводить можно через libsdl.
whale_nik
Цитата(AHTOXA @ Sep 3 2016, 17:16) *
4,5 мс - это 222 герца. Тоже многовато.
Вы примите во внимание, что для человеческого глаза не нужна такая частота. Достаточно, скажем, 60 Гц (вернее, достаточно 25, а 60 - это будет ультра-гладкая картинка). Вот и перерисовывайте соответственно 60 раз в секунду. Пусть за одну перерисовку у вас добавляется не один, а несколько столбцов.

4,5 это не обновление картинки а добавление одного столбца, а частота окна получиться 5 сек если считать кадром обновление всего окна.

Цитата(amaora @ Sep 3 2016, 17:26) *
В лоб будет больше 60 к/с, если оптимизировать как должно, немного медленнее memcpy. А можно и взять готовый memmove, останется добавлять один столбец. Выводить можно через libsdl.

Вы говорите для меня загадками )

Господа, вот такая штука виснет намертво и ничего не выводит, если без goto в таймере вызывать все отлично, в чем дело ?

int h1 = gBitmap->Height;
int w1 = 3300;

fg:

Col--;

for ( y = 0; y < h1; y++) // âàðèàíò 2 = ìåíÿåì â ìàñèâå òîëüêî îäèí ñòîëáåö
{
data_in[0][y]=random(250);
data_in[1][y]=random(250);
data_in[2][y]=random(250);
}

//-----------------------------------

TRect tRectFrom(1,0,1101,h1);
TRect tRectTo (0,0,1100,h1);

Image1->Canvas->CopyMode=cmSrcCopy;
Image1->Canvas->CopyRect(tRectTo,gBitmap->Canvas,tRectFrom);

TRect tRectFrom2(0,0,1100,h1);
TRect tRectTo2 (0,0,1100,h1);

gBitmap->Canvas->CopyRect(tRectTo2,Image1->Canvas,tRectFrom2);


for ( y = 0; y < h1; y++)
{
ptr = (Byte *)gBitmap->ScanLine[y];


ptr[w1+0] = (Byte)data_in[0][y];
ptr[w1-1] = (Byte)data_in[1][y];
ptr[w1-2] = (Byte)data_in[2][y];

}

//-----------------------------------

Sleep(100);
goto fg;
sigmaN
Ребят, я не понимаю зачем нам тут gl и уж тем более полноэкранная графика с монополизацией экрана....
Компонент лежит на форме и может предоставить свой DC(Device Context). Этот контекст как раз позволит рисовать в заданную область на форме(в окне).
Зачем лезть в gl если есть более стандартные функции из GDI. Сделать это всё на Canvas вместо Image и будет счастье.
Я бы взял за основу вот этот пример, где есть скроллинг битмэпа
https://msdn.microsoft.com/ru-ru/library/wi...0(v=vs.85).aspx
Используется как раз BitBlt()
Device context у нас есть, буфер сделать нет проблем... в целом тоже нет проблем )

Ежели кто-то сможет пояснить за использование GL в данном случае то я бы с интересом почитал.
whale_nik
Цитата(AHTOXA @ Sep 3 2016, 17:16) *


Вот 5 сек на весь экран примерно 5мс/столбец, не вижу тут мега быстрого чего то .
sigmaN
Логичнее было бы в архив прилепить исходник, вместо этого безобразия
whale_nik
Цитата(sigmaN @ Sep 3 2016, 22:31) *
Логичнее было бы в архив прилепить исходник, вместо этого безобразия


Пардон, попробуйте этот
sigmaN
Проц не грузит(не более 1 - 2% показывает диспетчер задач)
Плохо только, что дёргается немного скроллинг. Видимо используется таймер(ну, который Timer, который на форму кидается).
Он как-то кривовато работает с маленькими задержками....
Предлагаю попробовать отдельный Thread + Sleep() с подкрученным перед этим таймером для увеличения точности
https://msdn.microsoft.com/ru-ru/library/wi...8(v=vs.85).aspx
Цитата
To increase the accuracy of the sleep interval, call the timeGetDevCaps function to determine the supported minimum timer resolution and the timeBeginPeriod function to set the timer resolution to its minimum. Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock, system power usage, and the scheduler. If you call timeBeginPeriod, call it one time early in the application and be sure to call the timeEndPeriod function at the very end of the application.


Кстати помнится у меня были проблемы когда я рисовал из другого потока. Так что рисуйте только из основного потока!
Вполне может быть, что существует не многопоточный способ убрать эту дерготню.... Это я просто предположил, что дело в таймере. Просто я когда-то наблюдал такие-же подергивания когда таймером анимировал выезд строки в титрах.

Кстати еще как-то использовал для точного измерения времени QueryPerformanceCounter(), может удастся сюда приспособиьт как-нибудь
https://msdn.microsoft.com/en-us/library/wi...8(v=vs.85).aspx
whale_nik
Да, наверняка дергается из за того что таймер нестабильно выдает тики.
С потоками у меня совсем труба и программирование на С++ не мой основной профиль, на асм еще куда ни шло )
Если кто напишет как запихать эту прогу в быстрый, стабильный опрос можно попробовать разогнать ее , посмотреть до каких пределов )))
sigmaN
а, ну если чисто для пробы то
в цикле while(!Application.terminated() )
{
делаете то что вы делаете сейчас в обработчике онтаймер;
потом Application.processMessages();
}
Ну там в документации гляньте, может Terminated это не функция...
В общем это наверно будет самое быстрое что можно сделать легко и просто

Цикл этот запихните в обработчик кнопки старт например.
DASM
Таймер тут не причем, просто поток, ушедший в Sleep получит управление только тогда, когда не будет активных потоков более высокого приоритета, а это может случится хоть после обеда
sigmaN
Ну Sleep() это я предложил просто. Хотя вы правы, в MSDN этот момент описывается.
Я тут подумал, что в принципе таймер это просто надстройка над API
Цитата
TTimer is used to simplify calling the Windows API timer functions SetTimer and KillTimer, and to simplify processing the WM_TIMER messages.

http://docwiki.embarcadero.com/Libraries/B...ExtCtrls.TTimer

Есть информация, что стандартное разрешение таймера в венде 15.6ms
https://randomascii.wordpress.com/2013/07/0...gawatts-wasted/
Думаю это довольно мало для наших целей...

Так что самое первое что надо попробовать - таки задрать частоту таймера(не забыть потом вернуть как было!)
https://msdn.microsoft.com/en-us/library/wi...6(v=vs.85).aspx

Я тут начал задумываться а как вообще тогда сделать плавную анимацию средствами GDI?

Add:
Провел эксперимент: увеличил частоту таймера. Ничего не изменилось.
Заметил кстати, что изменяя ширину окна изменяется и скорость движения пикселей... Очень странно....
DASM
Таймера в винде для такого иные, см. BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)
jcxz
Цитата(DASM @ Sep 4 2016, 05:43) *
Таймера в винде для такого иные, см. BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)

По этим таймерам не получишь пробуждение потока. Только время померить можно.
Чтобы не дёргалось изображеие, копать надо в сторону синхронизации с кадровой развёрткой видеокарты.
И если хочется чтобы под виндой потоку и процессу меньше мешали другие процессы/потоки, повышайте приоритет и потока и процесса: SetThreadPriority()/SetPriorityClass().
Но опять-же - если поток уже ушёл в Sleep то получить управление он может только с дискретностью таймера виндового шедулера, который 18.2Гц всего.
Ну хотя если получит событие от периферии какой-либо, то может тоже пробудится? Например - от изохронной точки USB с частотой 1кГц может быть сможет пробуждаться.
Но винда - это не реалтайм система, она не для того делалась, так что гарантии нет никакой.
alexunder
Автор, а чего в сторону Direct2D не посмотрите? Двумерная графика с аппаратным ускорением.
Я недавно его к Питону (IronPython) прикрутил.
sigmaN
Провел тут пару экспериментов со слипом...
за основу было взято это
https://www.daniweb.com/programming/softwar...the-windows-gdi

В общем создать в Visual Studio Win32 проект и скопипастить туда
http://pastebin.com/USiiAXxZ

fps специально зажат, чтобы цикл упирался именно в Sleep()
таким образом равномерность движения будет зависеть только от равномерности слипа.
Также интересно раскоментить //timeBeginPeriod(1); в WinMain() и убедиться, что Sleep() тоже начинает работать точнее.
Т.е. виндовый шедулер зависит от частоты таймера(о чем в MSDN тоже где-то читал).

Сам скроллинг сделано втупую на циклах... тут не в этом прикол как говорится.

Кстати у ТСа пиксели какие-то большие в примере! Вот тут у меня реально 1000*800 как в первом посте указано.

Во вложении exe для проверки плавности ) У ТСа проблема с плавностью явно не из-за проблемы точности Sleep()! Ибо там рывки такие, что со стула упасть можно

P.S. кстати если в цикле оставить только BitBlt то получается более 500FPS. так что сама операция отрисовки на экран реально быстрая!
jcxz
Цитата(alexunder @ Sep 4 2016, 15:43) *
Автор, а чего в сторону Direct2D не посмотрите? Двумерная графика с аппаратным ускорением.

Я писал ещё в самом начале: пробовал DirectDraw, разницы в скорости между ним и ...Blt-функциями WinAPI не увидел.
Из чего сделал вывод, что WinAPI изнутри и вызывает DirectDraw когда нужно.
sigmaN
Ну а мне было больше даже интересно Sleep() по тестировать. То что Blt работает реально быстро это факт.
Кстати я до сих пор не нашел ответа как сделать реально плавную анимацию и при этом не грузануть процессор?
Да, высокий приоритет потока + разгон таймера вроде дают желаемый эффект даже со Sleep(), но это не правильно.
Крутить цикл и не засыпать тоже можно - но это еще более неправильно!
Кто знает как по правильному реализовать гладкую анимацию(скроллинг)?
whale_nik
Цитата(sigmaN @ Sep 4 2016, 01:59) *
а, ну если чисто для пробы то
в цикле while(!Application.terminated() )
{
делаете то что вы делаете сейчас в обработчике онтаймер;
потом Application.processMessages();
}
Ну там в документации гляньте, может Terminated это не функция...
В общем это наверно будет самое быстрое что можно сделать легко и просто

Цикл этот запихните в обработчик кнопки старт например.


Так пробовал, ничего не работало, все виснет намертво почему то.


Насчет пикселей в том примере что у вас там сразу по три выводиться для скорости, это был пример для Антохи с 5 сек на экран.
sigmaN
Странно.. при условии, что в цикле есть вызов Application.processMessages(); висеть не должно...
whale_nik
Удалил файл проекта так как вы уже свой написали, я просмотрел )

Цитата(sigmaN @ Sep 4 2016, 23:15) *
Странно.. при условии, что в цикле есть вызов Application.processMessages(); висеть не должно...


Счас спробую .

Заработало, но в цикле самое быстрое 10 сек на экран, проц уже грузиться сильно, если в примере что я давал по три точки это 3,3 сек,
Так чтобы как пуля надо уже что то другое делать.

вот по три точки сразу в бесконечном цикле без таймеров и задержек
sigmaN
Ну проц и должен грузиться сильно. В цикле же нет Sleep(). Т.е. процесс не отпускает процессор и делает непрерывно свою работу.

Сейчас запустил новый exeшник, на глаз реально быстрее и плавнее двигается же!
Если других изменений в коде сделано не было, то этот эксперимент показывает, что причина дёрганий была именно в таймере.
whale_nik
Никаких изменений, просто таймер отключил и все в цикле по кнопке.
jcxz
Цитата(sigmaN @ Sep 5 2016, 00:14) *
Кто знает как по правильному реализовать гладкую анимацию(скроллинг)?

Только при помощи кадровой синхронизации. Если от видеокарты (или её низкоуровневого API) получите сигнал кадровой синхронизации, то сможете сделать.
Я в своё время находил такую опцию среди API DirectDraw, но уже точно не помню - или она не работала на моей карте или она там только в полноэкранном режиме работает.
Ну или должна быть какая-то функция в самом GDI API, которая копирует картинку в видеопамять синхронизируясь с кадровой развёрткой.
sigmaN
Что-то мне подсказывает, что кадровая развертка тут не при чем.... В тех-же играх даже можно её включать и выключать(VSync или вертикальная синхронизация это обычно называется).
Отсутствие синхронизации с кадровой разверткой приводит к тирингу, я уже писал об этом https://en.wikipedia.org/wiki/Screen_tearing это то ладно, это другой вопрос.

Тут же задача состоит в том, чтобы просто гонять определенный кусок кода раз в 20миллисекунд например. И чтобы эти 20мс всегда были 20мс. Что, как мы понимаем, весьма затруднительно при точности таймера в плюс минус 15мс... Вот поэтому и нет плавности анимации.
whale_nik
Похоже если надо плавнее и быстрее уже придется в видеокарту лезть.
sigmaN
Глянул пару исходничков тут.. В том числе Quake 3 даже.
Похоже нормальные пацаны для измерения времени c миллисекундной точностью используют timeGetTime() вместо GetTickCount();
И таки в самом начале они разгоняют таймер использую timeBeginPeriod(1), что в том числе благотворно сказывается и на Sleep();

В общем вот усовершенствованная версия максимально плавной анимации, которую я смог достичь.
http://pastebin.com/gAQqdrJ0

Кстати по скорости тоже я впечатлен. Скроллинг удалось разогнать до 680FPS!

В принципе учитывая, что TCanvas даёт нам свой DC - можно то-же самое реализовать и в C++ Builder и в Delphi.
И даже в случае чего завернуть это в отдельный компонент, чтоб можно было эти графики ложить на форму. Я так когда-то самодельный DBGrid делал с нестандартной раскраской )
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.