Определить, видна ли клиентская часть окна?

Тема в разделе "WASM.WIN32", создана пользователем S_T_A_S_, 10 янв 2005.

  1. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    В окне постоянно рисуется изображение (ресурсоёмкий процесс). WM_PAINT в этом не участвует.

    Если окно полностью закрыто другим окном, то перерисовку хорошо бы не делать, что бы разгрузить CPU.



    Пока приходит на ум такое решение: проверять цвет пикселей по углам клиентской области и сравнивать с предыдущим состоянием - если изменился, то окно закрыто другим. Это мне не нравится :/



    Например, MS Media Player и другие программы продолжают рендеринг в подобных случаях...

    неужели сабж не из разряда "иконок в трэе" ?
     
  2. spidea

    spidea New Member

    Публикаций:
    0
    Регистрация:
    22 дек 2004
    Сообщения:
    10
    Мой велосипед(алгоритм):



    Рендеринг:

    идет рендеринг

    проверить на потерю фокуса

    если фокуса потерян вызов функции "ФОКУС"

    инче прыгнуть на метку "Рендеринг"



    ФОКУС proc

    получить хэндл текущего окна

    взять его RECT

    сравнить с RECT_YOU_PROGRAMM, сделать выводы

    итак повторять до тех пор пока фокус не вернется в YOU_PROGRAMM

    endp
     
  3. vinnie_pooh

    vinnie_pooh New Member

    Публикаций:
    0
    Регистрация:
    30 июн 2004
    Сообщения:
    98
    Хук на WM_MOVE? (Сравнивать RECT перемещаемого окна со своим.)
     
  4. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    Решение проблемы в общем случае было бы более полезным. А то ведь возможен вариант, когда окно закрыто полностью, но _двумя_ разными окнами, каждым по половинке.
     
  5. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




    Если WM_PAINT не обрабатывается, но приходит, (а оно обязано приходить), можно использовать его как индикатор необходимости перерисовать окно.


    Код (Text):
    1. .elseif uMsg==WM_TIMER    ;будильник
    2.     ;провоцируем wm_paint
    3.     invoke InvalidateRect,hWin,NULL,FALSE
    4.  
    5. .elseif uMsg==WM_PAINT
    6.     mov hDC,FUNC(BeginPaint,hWin,ADDR Ps)
    7.     mov eax,Ps.rcPaint.right
    8.     add eax,Ps.rcPaint.bottom
    9.     sub eax,Ps.rcPaint.left
    10.     sub eax,Ps.rcPaint.top
    11.     jz @NoVisible
    12.  
    13.  
    14. @NoVisible:
    15.     ;тут окажемся только если окно закрыто полностью
    16.  
    17.     invoke EndPaint......
     
  6. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    S_T_A_S_

    Может GetUpdateRgn?
     
  7. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Black_mirror

    Может быть GetUpdateRect?
     
  8. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Всем спасибо за ответы!





    Black_mirror

    q_q



    В чистом виде GetUpdateRect в моём случае не подходит: возвращает 0 (there is no update region) когда окно ничем не закрыто или полностью закрыто. 1 (the update region is not empty) только в случае частичного перекрытия. К окну присоеденина такая штука как IDirectDrawClipper, видимо он что-то "обрезает"...





    vinnie_pooh



    Хук на WM_MOVE (тогда наверное лучше на WM_WINDOWPOSCHANGING) IMHO слишком громоздко + ресурсоёмко. К томуже хочется без мордобоя :).





    spidea



    Идею понял, если принять во внимание замечание CyberManiac, то можно доработать: EnumWindows + вычисление общего закрытого пространства, что IMHO может быть достаточно долго, если много левых окошек :-(

    (мне нужно рисовать каждый кадр + синхронизация по IDirectDraw7::GetScanLine)







    cresta



    Модернизировал твой вариант. таймер не подходит, слишком низкий приоритет у него, поэтому InvalidateRect делает другой трэд каждый кадр. Нюанс - для межтрэдового взаимодействия делать не флаг, а счётчик кадров, когда размер клиента равен нулю. иначе возникают дёрганья всякие (пропуск кадров) из-за EnterCriticalSection или остановка рендеринга по Воле Божъей.


    Код (Text):
    1.  
    2.         case WM_PAINT:
    3.             PAINTSTRUCT ps;
    4.             BeginPaint(handle, &ps);
    5.             if( ps.rcPaint.left + ps.rcPaint.top - ps.rcPaint.right - ps.rcPaint.bottom )
    6.                 no_repaint = 0;
    7.             else
    8.                 no_repaint++;
    9.             EndPaint(handle, &ps);
    10.  
    11. // В трэде где рисую
    12.  
    13.         do  Sleep(0);
    14.         while( no_repaint > 5 );
    15.       //
    16.            DRAW();
    17.            InvalidateRect(handle, 0, 0);
    18.  


    Интересно, что если я меняю BeginPaint + EndPaint на GetUpdateRect + ValidateRect, то это не работает, несмотря на






    Остаётся померять затраты времени на разные способы, щас у меня опять начались проблемы с ходом луча - странно, только вчера их решил :-((
     
  9. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Измерил время выполнения различных вариантов.

    AXP2000+(@1666)/512Mb/Radeon8500/WXPSP2/DX9c

    Все цифры, конечно, очень примерные. В тактах CPU (для сравнения - на один кадр при 75 Герцах приходится 22 222 222 тактов)





    WM_PAINT:



    InvalidateRect - 37 000

    BeginPaint + EndPaint - 30 000



    Итого 67 000





    Определение RECT других окон:



    GetWindowRect - 1 500 очень немного, но если нужно учитывать вариант перекрытия несколькими окнами:

    EnumWindows - 400 000 (для десяти окон)



    Остальные функции измерять смысла не вижу :)





    Чтение 4х пикселей по углам:



    a) Прямой доступ к экранной памяти:



    IDirectDrawSurface7::Lock + IDirectDrawSurface7::Unlock - 100 000



    Чтением можно пренебречь :)





    b) GDI:



    GetDC + ReleaseDC - 35 000



    GetPixel - 8 000



    Итого 67 000





    Выходит, что GetPixel и WM_PAINT являются наиболее быстрыми методами. Однако вариант со чтением 4х точек по углам не является решением в общем виде - можно расположить 2 окна так, что метод будет считать, что наше окно закрыто полностью, что является багом :-(





    Второй вывод, гораздо более важный (хотя к теме отношения не имеет):

    Digital Vidio Interface (DVI) SUXX !!!!!!!!!!!!

    Частота обновления матрицы при подключении LCD (по крайней мере моего) по DVI не равна частоте развёртки, выдаваемой видеоадаптером!

    Очень близка к ней, но не равна. Из-за интерференции этих 2х частот наблюдается jerking анимации, с которым я безуспешно пытался бороться 2 дня >:-(
     
  10. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    S_T_A_S_

    Проверил, GetUpdateRgn не работает - в регион попадают все области для которых были вызваны функции типа InvalidateRect, без отсечения по видимой области.



    Если в программе используется DirectDraw, то может стоит попробовать IDirectDrawClipper::IsClipListChanged+GetClipList? Тоже самое что и хук на WM_MOVE, только всё делает винда.
     
  11. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Black_mirror



    Ну что тут сказать, чайник я :))))))

    Вместо того, что бы посмотреть доки, начал смотреть чужие проги :dntknw:



    IDirectDrawClipper::GetClipList не только работает (~50 000 тактов), но и позоляет обходиться и без IDirectDrawClipper::IsClipListChanged


    Код (Text):
    1.  
    2.     unsigned long   size;
    3.     clipper->GetClipList(0, 0, &size);
    4.     if( size < sizeof(RGNDATA) )
    5.         // значит окно перекрыто другими.
    6.         // реально возвращает 32 т.е. sizeof(RGNDATAHEADER)
    7.  




    >




    Это я уже понял, микрософт явно гонит говоря
    (последняя строит RECT на основе регионов GetUpdateRgn)



    Вот фрагмент лога (BeginPaint идёт непосредственно после GetUpdateRect)

    видно, когда окно ушло на задний план:
    Код (Text):
    1. [ 0012772543 mcs ]  GetUpdateRect:  left=0, top=0, right=640, bottom=480
    2. [ 0012777694 mcs ]  BeginPaint:     left=0, top=0, right=640, bottom=480
    3. [ 0012805669 mcs ]  GetUpdateRect:  left=0, top=0, right=640, bottom=480
    4. [ 0012811200 mcs ]  BeginPaint:     left=0, top=0, right=640, bottom=480
    5. [ 0012836313 mcs ]  GetUpdateRect:  left=0, top=0, right=640, bottom=480
    6. [ 0012840728 mcs ]  BeginPaint:     left=0, top=0, right=0, bottom=0
    7. [ 0012852249 mcs ]  GetUpdateRect:  left=0, top=0, right=640, bottom=480
    8. [ 0012856562 mcs ]  BeginPaint:     left=0, top=0, right=0, bottom=0
    9. [ 0012869604 mcs ]  GetUpdateRect:  left=0, top=0, right=640, bottom=480
    10. [ 0012874004 mcs ]  BeginPaint:     left=0, top=0, right=0, bottom=0




    GetUpdateRect делает GreGetRgnBox и потом IntersectRect.

    BeginPaint логика немного иная - если GreGetClipBox возвращает NULLREGION, то IntersectRect не делается, возвращается нулевой RECT. (хотя сами ф-ции GreXXX отсутствуют, но по названиям кое о чём судить можно)
     
  12. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    S_T_A_S_

    Если IsClipListChanged говорит, что видимая область не изменилась, то можно использовать результат последнего вызова GetClipList. Это должно сэкономить некоторое количество тактов.
     
  13. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    GetUpdateRect у меня тоже всегда одно значение выдает.




    А может, мелкософт имел ввиду, что используется такой же lpRect, а не допустим POINT :)))
     
  14. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Black_mirror >




    Это уже не существенно :) Хотя экономия есть IsClipListChanged "стоит" всего 2500 тактов.

    Всё равно приходится вызывать как минимум Sleep(1) каждый кадр - иначе виндос умирает. Вот если бы можно было заморозить остальные процессы, что бы не мешели :))))))
     
  15. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    S_T_A_S_

    Всё равно приходится вызывать как минимум Sleep(1) каждый кадр - иначе виндос умирает.



    Осталось только выяснить, чему равна единица под Windows 98 (а она не равна единице :) ) и не возникнет ли из-за этого проблем с неравномерностью отображения кадров. Я бы еще проверил, можно ли вместо Sleep использовать 10-милликесундное ожидание ненаступающего события, вдруг от этого будет больше пользы.



    S_T_A_S_

    Вот если бы можно было заморозить остальные процессы, что бы не мешели :))))))



    А чего мелочиться? Kill'em all!
     
  16. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Та поставь THREAD_PRIORITY_TIME_CRITICAL и почти все кванты твои :) Я при таком зацикле в w2k вообще сделать ничего не могу, приходится жать reset (сорри если оффтоп)
     
  17. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    CyberManiac >




    Дык она нигде единице не равна. Смысл этого - отдать время другим процессам, т.к. иначе система сама его заберёт, причём в самый неподходящий момент и всё сразу - вот тогда точно будет неравномерность :-(

    А так - в худьшем случае _изредка_ (конечно, если проц не слабый) буду получать пропуск одного отображаемого кадра - а это мало кто заметит, если при переисовке учитывать.



    >




    Нееееееа :) Например, при развётрке 100Гц - 10 милликесунд - это длительность полного кадра :)





    bogrus >




    У меня и так такой приоритет - и на других потоках тоже :)

    В том-то и дело, что
    все.
     
  18. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    S_T_A_S_
    >Если окно полностью закрыто другим окном, [...]


    RectVisible (GetWindowDC, GetWindowRect) дает ответ ПОЧТИ всегда.

    Кстати: сможете указать, когда - НЕ дает ? :)

    // Offtop//
    А почему S_T_A_S_ - "Забанен" ??
     
  19. slow

    slow New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2004
    Сообщения:
    615
    в поиск
     
  20. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    // Offtop //

    slow
    >в поиск

    Поискал.
    Оказывается, S_T_A_S_ - это gear nuke на RSDN !
    Ну, знаете, банить ТАКИХ авторов - это... как бы по-мягче... странно.

    // Конец оффтопу //