Свернуть-развернуть D3D форму.

Работа с 2D и 3D графикой, видео, звуком.

Модератор: Mikle

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Свернуть-развернуть D3D форму.

Сообщение Mikle » 01.12.2003 (Пн) 18:18

D3D форма при оконном D3D переживает свертывание в панель задач без проблем. Правда при этом резко возрастает нагрузка на систему, но это лечится запретом рендера при событии Resize если WindowState=vbMin... ,так же возрастает нагрузка, если перекрыть форму другой формой ПОЛНОСТЬЮ.
Отсюда первый вопрос - как это отследить. LostFocus и Deactivate не помогает.

Хуже, когда D3D полноэкранный. Уже сворачивание формы, скажем при случайном нажатии WinKey и т. п., вызывает сбой. При этом событие Resize почему-то не происходит. Я нашел отсюда один, довольно корявый, выход - в процедуре рендер ставлю "On Local Error Resume Next".
Отсюда второй вопрос - можно ли это побороть более "корректно", ведь так я теряю возможность отследить ДРУГИЕ ошибки.

Далее. Как восстановить форму после сворачивания? Я не нашел другого варианта, кроме как уничтожить и заново создать D3DDevice, а значит и все его RenderState-ы и т. п. Это очень неудобно и явно неправильно. Кроме того приходится эти RenderState-ы при каждом изменении фиксировать в переменных. С этим я пока борюсь удалением из главного цикла DoEvents - без этого сворачивания не происходит, но теряется возможность использовать KeyDown, MouseDown, Timer и вообще ВСЕ СОБЫТИЯ.
Отсюда третий вопрос, пожалуй главный - как поступать тут, не отказываясь от DoEvents?

Я написал минимальный D3D проект и предлагаю на нем испытывать свои методы и предложения, стараясь все делать максимально коротко. Программа закрашивает бэкбуфер в разные цвета и показывает. Вставляем этот код в новую форму - и проект готов.

PS . Думаю, решение этих проблем нужны нам всем.

Код: Выделить всё
Option Explicit

Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim d3dDevice As Direct3DDevice8
Dim Running As Boolean
Dim RenderEnable As Boolean
Const FullScreen = True

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  If KeyCode = vbKeyEscape Then Running = False
End Sub

Private Sub Form_Load()
  Me.Show
  InitD3D
  Running = True
  RenderEnable = True
  Do While Running
    DoEvents
    If RenderEnable Then Render
  Loop
  CloseD3D
  Unload Me
End Sub

Private Sub Render()
  On Local Error Resume Next
  d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, Rnd * &HFFFFFF, 1, 0
  d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub

Private Sub CloseD3D()
  Set d3dDevice = Nothing
  Set d3d = Nothing
  Set dx = Nothing
End Sub

Private Sub InitD3D()
Dim DispMode As D3DDISPLAYMODE
Dim d3dpp As D3DPRESENT_PARAMETERS
  Set d3d = dx.Direct3DCreate
  d3d.GetAdapterDisplayMode D3DADAPTER_DEFAULT, DispMode

  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD
  d3dpp.BackBufferFormat = DispMode.Format
  d3dpp.EnableAutoDepthStencil = True
  d3dpp.AutoDepthStencilFormat = D3DFMT_D16

  If FullScreen Then
    d3dpp.Windowed = False
    d3dpp.BackBufferWidth = DispMode.Width
    d3dpp.BackBufferHeight = DispMode.Height
    d3dpp.BackBufferFormat = D3DFMT_R5G6B5
    Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
  Else
    d3dpp.Windowed = True
    Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
  End If
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Running = False
End Sub

Private Sub Form_Resize()
  If Me.WindowState <> vbMinimized Then
    RenderEnable = True
  Else
    RenderEnable = False
  End If
End Sub

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 02.12.2003 (Вт) 9:55

Могу порекомендовать всем рульный сайт. Там хоть и на C++, но принцип выполнения всяких фишек в общем-то один.

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

Yurich
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 675
Зарегистрирован: 05.03.2003 (Ср) 3:43
Откуда: DONBASS/Gorlovka

Re: Свернуть-развернуть D3D форму.

Сообщение Yurich » 03.12.2003 (Ср) 2:59

В какой-то мере, Майк, с тобой солидарен, но появились свои соображения:
Mikle писал(а):... так же возрастает нагрузка, если перекрыть форму другой формой ПОЛНОСТЬЮ...

Это не нагрузка растет, это наша прога жрет весь временной ресурс. В коротком цикле, корнем которого явлется рендер сцены, вряд ли стоит рассчитывать на податливость системы. Я поэкспериментировал с примерами от мелкософта - никакого тормоза не наблюдается ни при сворачивании, ни при перекрытии окна. Удалось эти программы только "чуть притормозить". Видимых причин три: достаточно длинный (размеренный) код, что дает системе возможность поработать с эвентами, четкое распределение действий по временным интервалам, простота сцены. При этом я так и не смог найти никаких участков кода, что отвечали бы за перекрытие окна.
Mikle писал(а):...Хуже, когда D3D полноэкранный. Уже сворачивание формы, скажем при случайном нажатии WinKey и т. п., вызывает сбой.

Не могу подтвердить, у меня старая клава, без "WinKey". Не в этом дело! Попытайся вспомнить хотя бы одну игрушку, которая из полноэкранного режима без проблем могла отвалиться в панель задач, а? Битая "Контра"? И та ведет себя непредсказуемо. А там ведь есть HRESULT, в отличие от VB. Как решить? Наверное полностью исключить все ситемные эвенты клавиатуры и мыши и отдать их директу.
Mikle писал(а):... Я нашел отсюда один, довольно корявый, выход - в процедуре рендер ставлю "On Local Error Resume Next".
Отсюда второй вопрос - можно ли это побороть более "корректно", ведь так я теряю возможность отследить ДРУГИЕ ошибки.

Однозначно можно, но с потерей скорости, разбив RENDER на кусочки.

Mikle писал(а):... С этим я пока борюсь удалением из главного цикла DoEvents - без этого сворачивания не происходит, но теряется возможность использовать KeyDown, MouseDown, Timer и вообще ВСЕ СОБЫТИЯ.
Отсюда третий вопрос, пожалуй главный - как поступать тут, не отказываясь от DoEvents?

Или всё забери для директ, или все отдай системе (причины смотри выше). Fifty-Fifty не будет никогда.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Сообщение Mikle » 04.12.2003 (Чт) 15:40

Yurich

1. Да нет, это не программа, а DirectX жрет временной ресурс. Достаточно из цикла убрать рендер (или заменить на любую VB операцию), и все в порядке.

2. Сразу вспомнил NFS5 и Unreal Tournament. Оба на DirectX, оба без проблем сворачиваются-разворачиваются.
У меня тоже старая клава, но к сертыванию приводит нажатие Ctrl-Esc, Alt-Esc, Alt-Tab и т. п. Если даже не пользоваться клавиатурными событиями, эти сочетания все равно срабатывают. Избавиться от этого, не блокируя клаву, я смог только удалив DoEvents.

3. Разбив RENDER на кусочки, я смогу отследить другие ошибки. Просто мне кажется в корне неверным признать, что есть ошибки, и закрыть на них глаза, используя On Error.

Локализую проблемы:
1. При сворачивании полноэкранного приложения НЕ ПРОИСХОДИТ события Resize, либо другого события формы. Может такое событие может дать DirectX? Если да - как его декларировать?

2. DirectX, видимо, накапливает задачи в некий кеш, и если мы не даем каманду Render, продолжает рисовать из кеша. Как запретить это?

Ссылки GSerg изучаю... но тяжко. Задаю вопросы с надеждой, что кто-то решал уже это на VB.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 05.12.2003 (Пт) 10:31

Ну, с небольшим переводом помогу :)
Определение Dim d3dpp As D3DPRESENT_PARAMETERS переносим на уровень формы. А процедура Render будет выглядеть так:
Код: Выделить всё
Private Sub Render()
  On Local Error Resume Next
 
  Select Case d3dDevice.TestCooperativeLevel
  Case D3DERR_DEVICELOST
    Exit Sub
  Case D3DERR_DEVICENOTRESET
    d3dDevice.Reset d3dpp
  End Select
 
  d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, Rnd * &HFFFFFF, 1, 0
  d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Сообщение Mikle » 05.12.2003 (Пт) 15:46

Ура!!! Наконец-то. Я даже On Error из рендера убрал - ошибок НЕТ!
GSerg
Спасибо! :P

Vovik
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 643
Зарегистрирован: 02.08.2003 (Сб) 15:14
Откуда: Belarus, Minsk

Сообщение Vovik » 13.12.2003 (Сб) 23:39

Mikle писал(а):Ура!!! Наконец-то. Я даже On Error из рендера убрал - ошибок НЕТ!
GSerg
Спасибо! :P

Пришли мне пожалуйста исходничок. Я мучаюсь-мучаюсь - ничерта не выходит! :cry: Или на форум скинь...плиз...

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Сообщение Mikle » 15.12.2003 (Пн) 9:59

Код: Выделить всё
Option Explicit

Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim d3dDevice As Direct3DDevice8
Dim Running As Boolean
Dim RenderEnable As Boolean
Dim d3dpp As D3DPRESENT_PARAMETERS
Const FullScreen = True

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  If KeyCode = vbKeyEscape Then Running = False
End Sub

Private Sub Form_Load()
  Me.Show
  InitD3D
  Running = True
  RenderEnable = True
  Do While Running
    DoEvents
    If RenderEnable Then Render
  Loop
  CloseD3D
  Unload Me
End Sub

Private Sub Render()
'  On Local Error Resume Next
 
  Select Case d3dDevice.TestCooperativeLevel
  Case D3DERR_DEVICELOST
    Exit Sub
  Case D3DERR_DEVICENOTRESET
    d3dDevice.Reset d3dpp
  End Select
 
  d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, Rnd * &HFFFFFF, 1, 0
  d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
Private Sub CloseD3D()
  Set d3dDevice = Nothing
  Set d3d = Nothing
  Set dx = Nothing
End Sub

Private Sub InitD3D()
Dim DispMode As D3DDISPLAYMODE
  Set d3d = dx.Direct3DCreate
  d3d.GetAdapterDisplayMode D3DADAPTER_DEFAULT, DispMode

  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD
  d3dpp.BackBufferFormat = DispMode.Format
  d3dpp.EnableAutoDepthStencil = True
  d3dpp.AutoDepthStencilFormat = D3DFMT_D16

  If FullScreen Then
    d3dpp.Windowed = False
    d3dpp.BackBufferWidth = DispMode.Width
    d3dpp.BackBufferHeight = DispMode.Height
    d3dpp.BackBufferFormat = D3DFMT_R5G6B5
    Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
  Else
    d3dpp.Windowed = True
    Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
  End If
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Running = False
End Sub

Private Sub Form_Resize()
  If Me.WindowState <> vbMinimized Then
    RenderEnable = True
  Else
    RenderEnable = False
  End If
End Sub

Vovik
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 643
Зарегистрирован: 02.08.2003 (Сб) 15:14
Откуда: Belarus, Minsk

Сообщение Vovik » 15.12.2003 (Пн) 14:44

Mikle писал(а):
Спасибо большое! :D

Vovik
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 643
Зарегистрирован: 02.08.2003 (Сб) 15:14
Откуда: Belarus, Minsk

Сообщение Vovik » 15.12.2003 (Пн) 15:18

Это опять я со своими проблемами... :cry: Всё бы ничего, но не пахает оно полность. Да, уже при сворачивании ошибки не возникает, но при восстанавливании, если в цикле рендеринга включаю прорисовку Mesh, то он просто рендерит чёрный экран, а если включаю в цикл писать FPS, то вообще выкидывает из проги. Помогите... :cry:

Vovik
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 643
Зарегистрирован: 02.08.2003 (Сб) 15:14
Откуда: Belarus, Minsk

Сообщение Vovik » 17.02.2004 (Вт) 16:53

Vovik писал(а):Это опять я со своими проблемами... :cry: Всё бы ничего, но не пахает оно полность. Да, уже при сворачивании ошибки не возникает, но при восстанавливании, если в цикле рендеринга включаю прорисовку Mesh, то он просто рендерит чёрный экран, а если включаю в цикл писать FPS, то вообще выкидывает из проги. Помогите... :cry:

Все исправил! При восстановке надо просто опять отключать свет, фильтры настраивать и матрици вида...я в сдк посмотрел, они там так делают... :lol:


Вернуться в Мультимедиа

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 31

    TopList