Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Lock\Unlock поверхностей DirectDraw


Страницы:   1 2 3

NikeOLD ©   (2004-04-22 21:46:00) 

Специально для miek !
Если не веришь мне, вот несколько примеров:
1. Запирать поверхность необходимо, поскольку позиция поверхности в системной памяти может меняться, системный менеджер памяти по каким-то своим соображениям может перемещать блоки памяти. (Краснов М. "DirectX. Графика в проектах Delphi", стр. 76);
2. Видео память не остается на одном и том же месте - она вполне может быть виртуальной. Если же эту память заблокировать, она гарантированно остается в одном и том же адресном пространстве в течение времени блокировки. (Ламот А. "Программирование игр для Windows. Секреты профессионала", стр. 250);
3. While you have a surface locked, you can directly manipulate the contents. The following list describes some tips for avoiding common problems with directly rendering surface memory:
a) Never assume a constant display pitch. Always examine the pitch information returned by the IDirectDrawSurface7::Lock method. This pitch can vary for a number of reasons, including the location of the surface memory, the type of display card, or even the version of the DirectDraw driver. For more information, see Width vs. Pitch.
b) Make certain you blit to unlocked surfaces. DirectDraw blit methods will fail, returning DDERR_SURFACEBUSY or DDERR_LOCKEDSURFACES, if called on a locked surface. Similarly, GDI blit functions fail without returning error values if called on a locked surface that exists in display memory.
(DirectX 7 SDK, "Accessing Surface Memory Directly")
Это, что касается Lock\Unlock.
Теперь относительно доступа к поверхности через графический контекст устройства (знакомо?). Полученный DC тоже нужно освобождать после работы и чем быстрее, тем лучше поскольку они неявно вызывают Lock\Unlock! Читай SDK внимательно.

Короче, если ты не лочишь поверхность перед прямым доступом к ней, то нет никакой гарантии, что на другой машине с другим аппаратным обеспечением твое приложение будет работать нормально.


NikeOLD   (2004-04-28 22:45:00) [21]

Отлично, теперь вижу нормальный лог!
Сразу пара замечаний.
Во-первых, было бы куда правильнее создавать палитру не после установки уровня кооперации, а после изменения разрешения экрана. Во-вторых, при закрытии программы все шаги необходимо выполнять в обратной созданию последовательности, т.е. сначала удаление всех поверхностей, а уж только после этого восстановление режима дисплея, затем нормального уровня кооперации.
В общем при тесте по Alt-Tab все ОК, пока не возникает необходимость выйти из программы обычным путем (по Esc). Программа закрывается, но при этом слышен звук ошибки. Самой ошибки не выдается.

При засыпании - белый экран. В этот моент программа пытается усиленно восстановить первичную поверхность. Вот фрагмент лога, который повторяется до удаления программы через диспетчер задач:
Primary surface lost! Restoring...
*** Restore This surface can not be restored because it was created in a different mode.
Primary surface restored...
*** primarysurface.SetPalette Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.
Palette restored...
*** BltFast Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.
....тоже самое и т.д.

Если честно, то можно забить на восстановлении из спящего режима. Явидел всего пару игр, которые могли корректно восстановиться после усыпления компьютера. А я, поверь, повидал их несколько сотен. Только полоумный юзер усыпит комп во время игры, и поделом ему. Но восстановить по Alt-Tab - святое.
Могу заметить, что корректным был бы подход когда в случае невозможности восстановить поверхность с первого-третьего раза, программа завершала бы свою работу, а не продолжала осуществлять бесконечные попытки восстановления, загрузки палитры (поверхности нет - некуда загружать!) и пр. Miek, исправляй положение срочно. Можно даже сообщить пользователю после уничтожения DirectDraw в обычном окне диалога почему была закрыта программа.


> программа при переключении в фоновый режим потребляет ~100
> % CPU time, игра продолжается, но уже без участия игрока-человека.

Я уже указывал на это. Miek всего лишь прекращает рендеринг, но продолжает получать и обрабатывать сообщения, а так же выполнять физику и логику игры (перемещение спрайтов и т.д.). Miek - исправляйся, делай паузу, Твикс можно не есть - это дело вкуса :))


> нельзя переключить битность цвета, то бишь, к примеру, вместо
> 1024x768x32 можно поставить 1024х768х8;

Не понял вопроса. Выйти по Alt-Tab, сменить разрешение Рабочего стола Windows и вернуться в программу? Это невозможно однозначно! Поверхность не может быть восстановлена ни при каких обстоятельствах, если она была создана при другом разрешении экрана. Это ограничение DirectDraw, надо смириться!


miek   (2004-04-28 22:25:00) [22]

>После спящего режима

А что в логах?

>при переключении в фоновый режим потребляет ~100 % CPU

Это вполне возможно, я пока не занимался оптимизацией.


VMcL   (2004-04-28 21:02:00) [23]

>>miek ©  (28.04.04 20:34) [26]

1. После спящего режима:
    а) в твоей программе - белый экран (также было слышно по звуку, что где-то вылезла ошибка);
    б) нельзя переключить битность цвета, то бишь, к примеру, вместо 1024x768x32 можно поставить 1024х768х8;
    в) завершить программу можно только менеджером задач.

2. Не по сабджу: программа при переключении в фоновый режим потребляет ~100 % CPU time, игра продолжается, но уже без участия игрока-человека.

P.S. OS: WinXP Rus SP1.


miek   (2004-04-28 20:34:00) [24]

ЮСТАС АЛЕКСУ ТЧК БАБУШКА ПРИЕХАЛА ВСКЛ ЗН

http://www.miek.narod.ru/spacediver.zip


NikeOLD   (2004-04-27 23:58:00) [25]

Очень рад, что мои труды не пропали даром.


> ты основываешся только на интуитивном и экспериментальном опыте

Что ж это тоже неплохо, когда человнк пытается самостоятельно до чего-то докопаться, значит есть надежда. А то частенько здесь на форуме просят едва ли не за них программу написать и принести на блюдечке.

Однако, мне хотелось бы уточнить в какой момент при смене видеорежима происходит потеря поверхности? Может попытаюсь объяснить.


> Вторые полбеды в том, что при ее восстановлении она разом
оказывается в видеопамяти и вылезать оттуда не желает! Естественно, обращение к ней позле разлочивания - дает ошибку, сообщение о которой, видимо, не видно из-за монопольного режима экрана.

Объясняю сразу. При создании поверхности DirectDraw пытается поместить ее в видеопамять сразу же, если не задано в лоб иное. В случае, если поверхность невозможно создать в видеопамяти, она создается в системной памяти. Если в лоб задать видеопамять, а таковой не хватит, вывалится ошибка "Недостаточно видеопамяти".
Похоже, что обе твои поверхности создаются в видеопамяти (спасибо 8 битному режиму за малое количество отъедаемой памяти). После первого залочивания и последующего разлочивания у тебя остается указатель на корректный адрес поверхности в видеопамяти. Однако при переключении по Alt-Tab и последующем восстановлении, адрес поверхности меняется, а ты пытаешься обратиться по старому адресу в непринадлежащий больше тебе участок видеопамяти, что естественно вызывает протест со стороны системного диспетчера памяти. Вот и все объяснение. Наилучший выход это каждый раз делать Lock/Unlock заново, чтобы получить КОРРЕКТНЫЙ АДРЕС ПОВЕРХНОСТИ.

Кстати, замечу, что 8 битный режим, хотя и имеет большое число прелестей, навроде создания спецэффектов при смене индексов палитры, но все же доставляет куда больше хлопот, чем 16, 24 или 32 битный режим.


> Неприятность в том еще, что это не ошибка DirectDraw и его
> процедуры всегда, даже перед самым глюком, возвращают DD_OK,
> а система при выводе сообщения "забывает" переключить режим
> экрана...

Да она и не обязана его переключать. Чтобы иметь возможность выводить стандартные виндовые окна из-под DirectX, надо использовать функцию FlipToGDISurface();главного объекта DirectDraw, которая позволяет выводить поверхность GDI поверх поверхности DirectDraw. Без ее вызова ни одно стандартное диалоговое окно, или любое другое, ты никогда не увидишь!
Вот, что по этому поводу сказано в SDK DX7:
"This method can be called at the end of a page-flipping application to ensure that the display memory that the GDI is writing to is visible.
The method can also be used to make the GDI surface the primary surface so that normal windows such as dialog boxes can be displayed in full-screen mode. The hardware must have the DDCAPS2_CANRENDERWINDOWED capability. For more information, see Displaying a Window in Full-Screen Mode"

Удачи, если что пиши на мыло. Обсуждение НЕ закрыто!


miek   (2004-04-27 23:10:00) [26]

Завтра к девяти вечера, сейчас слишком времени мало.


VMcL   (2004-04-27 22:20:00) [27]

>>miek ©  (27.04.04 22:05) [22]

Давай исправленную прогу (если есть). Будем тестить.


miek   (2004-04-27 22:05:00) [28]

Итак, в результате долгих экспериментов проблема локализована и скоро будет решена. (Смена интерфейса на IDirectDraw7 ничего, разумеется, не дала). Можно смело считать, что одной недокументированной дырой в MSDN стало больше.

Причина глюков до смешного проста - при смене видеорежима почему-то теряется не только первичная поверхность, но и вторичная (хотя во многих доках уверяют, что такого быть не должно - может, тут все дело в 8-битном режиме? Не знаю). Это, конечно, было бы полбеды. Вторые полбеды в том, что при ее восстановлении она разом оказывается в видеопамяти и вылезать оттуда не желает! Естественно, обращение к ней позле разлочивания - дает ошибку, сообщение о которой, видимо, не видно из-за монопольного режима экрана.

Неприятность в том еще, что это не ошибка DirectDraw и его процедуры всегда, даже перед самым глюком, возвращают DD_OK, а система при выводе сообщения "забывает" переключить режим экрана...

Вот так. Товарищу NikeOld - большое спасибо за помощь, остальным м*кам - большое "фу".


VLoB   (2004-04-26 01:44:00) [29]


> Цитировать талмуды - это, конечно, здорово

это даже больше, чем здорово =))


> А на MSDN иногда и положить можно

нельзя

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

з.ы.: прога твоя после альт-таба валится "Exception Exception in module spacediver.exe at <адрес>. Access violation in module..." и дальше как заказывали
запускал под ХР - конфиг более чем - 780mb ram/128mb video, чего ей не хватает? а не хватает ей здравого рассудка автора, который лучше чем мелкософт знает, как правильно работать с памятью DX.

без обид, удачи =)


NikeOLD   (2004-04-24 10:43:00) [30]

Жаль, что не местный.

Прошу прощения, что не обратил внимания сразу. Блин, попробуй переделать на интерфейсы 7 версии.
Код инициализации:
 DDrawObject: IDirectDraw7;
 PrimarySurface: IDirectDrawSurface7;
 DXResult: HRESULT;

 DXResult := DirectDrawCreateEx(nil, DDrawObject, IID_IDirectDraw7, nil);
 log(DDErrorString(DXResult));
 if Failed(DXResult) then Exit;

Далее по SDK. Потом посмотришь, что получилось. Желаю удачи, но ветка еще не закрыта.


miek   (2004-04-24 09:42:00) [31]

>Не надо. 7 версия самая надежная

Но я-то использую первую!

>ты случаем не из Нижнего Новгорода

Увы, нет.


Mihey   (2004-04-24 00:14:00) [32]

> машина 64 КБОЗУ, Win98, S3 Virge

Однако не думал, что винды такие скромненькие.


NikeOLD   (2004-04-23 22:35:00) [33]

С тем экзешником, который я выдернул с твоего сайта все в порядке. У меня  на 98SE он прошел и твой изуверский тест (впрочем, картинка там создается не в видеопамяти, а в свапе) и еще один: запуск параллельно еще одной DirectDraw программы (моей). Обе программы живут практически одновременно и все корректно восстанавливается.
Один минус: пока прога находится в фоне, у тебя похоже идет обработка логики игры - персонаж куда-то зачем-то двигается. Надо бы паузу поставить, а то улетает черт знает куда.


> Я имел в виду IDirectDraw6 (или IDirectDraw4) - поскольку
> в первом нет метода RestoreAllSurfaces

Не надо. 7 версия самая надежная. Жаль, что DirectDraw больше не поддерживается. Хотя 3D перспективнее, все же DDraw тоже хорош для определенных задач, рад что кто-то им еще не брезгует.


> >Зачем вызывать Halt

Забей, это бывает и то не всегда. В 2000 этого не происходит. Иначе нет смысла в PostQuitMessage(0);


> >Код слабо комментирован
> Я намерен это исправить, как только будет готова демо-версия
> игры.

Лучше сразу, затраты времени с лихвой окупаются удобством.


> >Попробуй изменить лог таким образом, чтобы он анализировал
> результат
> Уже есть. Функция check() как обертка для всех вызовов DirectDraw.
> Просто она ничего не выводит в случае DD_OK.

Что-то не заметил. Хотя, если это присутствует и все DD_OK, то ошибка кроется в другом. Проверь все указатели, динамические массивы и т.п.

И все же совет: надыбь где-нибудь книжку по DirectX. Лучше Ламота, но там, если с С++ никак, то лучше не соваться. Еще Краснов есть (почти классика :) ).
Забыл что-то важное, вспомню - допишу.

Слушай-ка, ты случаем не из Нижнего Новгорода будешь?


miek   (2004-04-23 21:40:00) [34]

>После alt+tab она зависала и после этого Директ умирал

А ты Esc нажимать пробовал? У меня это тоже выглядело как "смерть", но прога нормально ловила Esc и выходила.

>Зачем вызывать Halt

У меня после установки патча на винду некоторые проги, выходящие обычным способом (скринсэйверы, например), оставляют пустое окошко на таскбаре. Halt решает эту проблему.

>Код слабо комментирован

Я намерен это исправить, как только будет готова демо-версия игры.

>Не понимаю необходимости при восстановлении поверхностей делать повторные вызовы SetCooperativeLevel и SetDisplayMode

Это уже от отчаяния. Не помогло, точно.

>Зачем тартить процессорное время на получение r1

Логично, так и сделаю.

>Попробуй изменить лог таким образом, чтобы он анализировал результат

Уже есть. Функция check() как обертка для всех вызовов DirectDraw. Просто она ничего не выводит в случае DD_OK.

>Не вздумай! Если поставишь 6 Direct

Я имел в виду IDirectDraw6 (или IDirectDraw4) - поскольку в первом нет метода RestoreAllSurfaces.

>протестировать твою прогу на 2000.

У меня здесь есть 2000-й.

Кстати: >Riva TNT2 64МВ. Alt-Tab без проблем много раз

Я делал так: (машина 64КБ ОЗУ, Win98, S3 Virge) запускал игру, альттабился, запускал фотошоп, создавал офигенную картинку - 5000 на 2000, ждал, пока он ее сделает, потом выходил из фотошопа и переключался на прогу. Все работало. В фоне постоянно играл Винамп, причем даже без щелчков-пауз-рывков!


NikeOLD   (2004-04-23 21:12:00) [35]

Слушай, хоть убей не пойму, почему после Alt-Tab у тебя происходит потеря поверхности. Гонял свою прогу. Потеря поверхности происходит только после засыпания компа! При Alt-Tab все ОК.
В общем переделывай лог, пока не увидим воочию, что выдает каждая твоя функция, хрен что поймем. Однозначно, проблема не в интерфесах, возможно даже не Lock/Unlock, но больше ничего не могу сказать.
Через часок еще загляну, а то время из дома жалко.


NikeOLD   (2004-04-23 20:56:00) [36]


> Может, дело в том, что я использую IDirectDraw? Шестой поставить,
> что ли?

Не вздумай!
DirectX это технология COM, надеюсь в общих чертах ты с ней знаком. Если поставишь 6 Direct, то интерфейсы 7 версии сосать будут и тебе придется полпрограммы переписать, тем более, что часть методов в интерфейсе 6 версии отсутсвует, например метод RestoreAllSurfaces. У меня стоит 9b, но интерфейсывсе работают и как видишь не жалуюсь. До этого стояли две 8 версии. Если потерпишь до понедельника, то могу протестировать твою прогу на 2000.


NikeOLD   (2004-04-23 20:51:00) [37]

Нет проблема не в этом.
Короче, я приведу некоторые соображения по беглому просмотру исходников.
1. Зачем вызывать Halt в процедуре Quit после отправки PostQuitMessage(0)? Это и так даст винде команду прибить приложение. Хотя PostQuitMessage(0) принято посылать в обработчике сообщения WM_Destroy. Лирика...
2. Код слабо комментирован, точнее вообще никак! Поверь моему опыту, через месяц каникул ты потритишь ни один час на восстановлении в памяти всех подробностей кода. Разобраться из-за этого сложно.
3. Не понимаю необходимости при восстановлении поверхностей делать повторные вызовы SetCooperativeLevel и SetDisplayMode. Direct это делает автоматически, равно как и при закрытии приложения (последнее - дурной тон). А вот при переключении Alt-Tab гонять разрешение туда сюда нет никакой необходимости.

Черт, как сложно без комментариев разобраться что к чему.

4.  if curtime - lastframetime > 1000 div maxfpsallowed then begin
   lastframetime := curtime;
   r1 := makerect(0, 0, ScreenX, ScreenY);
   if setup.WaitForVerticalBlank then
     ddrawobject.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
   //      secondarysurface.Lock( nil, desc, DDLOCK_WAIT, 0);
   //      ppublicdib( screen).fbits:= desc.lpSurface;
   primarysurface.BltFast(0, 0, secondarysurface, @r1, setup.bltwait);
   //      secondarysurface.Unlock( desc.lpSurface);
 end;

Зачем тартить процессорное время на получение r1. Он же один на всю игру, кроме того передай вместо нее NULL, т.е. nil и получишь тот же эффект. Кстати рекомендую для полного экрана организовать chain.

5. Попробуй изменить лог таким образом, чтобы он анализировал результат выполнения каждой функции на корректное значение HRESULT (DD_OK) или лог - в противном случае. Много нового о своей программе узнаешь, честное слово. Код от этого сильно увеличится, но за быстродействие не волнуйся. Просто анализировать результат функции не только правило хорошего тона, но и хороший ответ по всяким багам. Для вывода инфы в лог воспользуйся функцией function DDErrorString(Value: HResult): string;. В параметр Value - результат любой функции или метода DirectDraw.

Кстати, хорошая новость для тебя: у меня 98 и карточка Riva TNT2 64МВ. Alt-Tab без проблем много раз.


NailMan   (2004-04-23 20:45:00) [38]

miek ©  

Насчет W2000 пока не спорю. Про 98 - как именно нестабильна?
После alt+tab она зависала и после этого Директ умирал до перезагрузки компа. Т.е. после принудительного сваливания из задач твоей проги не могла запуститься ни одна DirectX программа.

Win98SE, DX 9b. Сейчас правда комп этот не доступен, так как он не у меня дома.


miek   (2004-04-23 20:12:00) [39]

Короче, свежая новость (плохая) - вставка обратно Lock/UnLock проблему на NT не решает и поведение не изменяет.

Может, дело в том, что я использую IDirectDraw? Шестой поставить, что ли?


NikeOLD   (2004-04-23 19:52:00) [40]


> у меня поверхности не связаны в цепь - вторая OFFSCREENPLAIN.

Это не принципиально. Данный метод восстанавливает ВСЕ имеющиеся поверхности. Тебе останется только восстановить палитру и загрузить заново графику.

> Вот именно лог-то и позволяет видеть, что никакого AV нет.
> Наоборот, что под 98, что под NT - DirectDraw бодро рапортует
> об отсутствии ошибок.

Ересь какая-то. А лог очень подробный? Ладно, попробую сейчас в исходниках покопаться.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо