Як завантажувати графічні ресурси асинхронно?


9

Давайте подумаємо платформно-агностично: я хочу завантажити деякі графічні ресурси, поки решта гри працює.

В принципі, я можу завантажувати фактичні файли в окремий потік або використовуючи async I / O. Але з графічними об'єктами мені доведеться завантажувати їх у GPU, і це можна (як правило) робити лише в основному потоці.

Я можу змінити цикл гри, щоб виглядати приблизно так:

while true do
    update()
    for each pending resource do
        load resource to gpu
    end
    draw()
end

маючи окремі потокові ресурси завантаження з диска в оперативну пам'ять.

Однак якщо є багато великих ресурсів для завантаження, це може змусити мене пропустити рамковий термін і в кінцевому підсумку отримати скинуті кадри. Тож я можу змінити цикл на це:

while true do
    update()
    if there are pending resources then
        load one resource to gpu
        remove that resource from the pending list
    end
    draw()
end

Ефективно завантажуючи лише один ресурс на кадр. Однак, якщо для завантаження є багато невеликих ресурсів, завантаження їх забирає багато кадрів, і витрачається багато часу.

Оптимально, я хотів би виконати завантаження таким чином:

while true do
    time_start = get_time()
    update()
    while there are pending resources then
        current_time = get_time()
        if (current_time - time_start) + time_to_load(resource) >= 1/60 then
            break
        load one resource to gpu
        remove that resource from the pending list
    end
    draw()
end

Таким чином, я б завантажував ресурс лише тоді, коли зможу це зробити протягом часу, який я маю для цього кадру. На жаль, для цього потрібен спосіб оцінити кількість часу, необхідне для завантаження певного ресурсу, і, наскільки я знаю, зазвичай це не існує.

Що я тут пропускаю? Як багато ігор змушують завантажувати всі свої речі повністю асинхронно і без опущених кадрів або надзвичайно тривалих періодів завантаження?

Відповіді:


7

Почнемо з прийняття ідеального світу. Існує два етапи завантаження ресурсу: спочатку ви виймете його з носія інформації та в пам'ять у правильному форматі, а другий - перенесіть його через шину пам'яті у відеопам'ять. Жоден із цих двох кроків насправді не потребує використання часу на вашій основній нитці - потрібно лише залучитись до видачі команди вводу / виводу. І ваш процесор, і GPU можуть продовжувати виконувати інші дії під час копіювання ресурсу. Єдиний реальний ресурс, який споживається, - пропускна здатність пам'яті.

Якщо ви використовуєте платформу без особливого шару абстракції між вами та обладнанням, API, ймовірно, викриває ці поняття безпосередньо. Але якщо ви перебуваєте на ПК, напевно, між вами та графічним процесором сидить драйвер, і він хоче все робити по-своєму. Залежно від API ви можете створити текстуру, яку підтримує пам'ять, яка є вашою власністю, але, швидше за все, виклик API "створити текстуру" скопіює текстуру в деяку пам'ять, якою володіє драйвер. У цьому випадку створення текстури матиме певний фіксований накладні витрати та деякий час, пропорційний розміру текстури. Після цього драйвер може зробити що завгодно - він може проактивно переносити текстуру в VRAM, або може не турбувати завантаження текстури, поки ви не спробуєте зробити її вперше.

Ви можете чи не можете зробити щось з цього приводу, але ви можете зробити загальну оцінку часу, необхідного для здійснення дзвінка "створити текстуру". Звичайно, всі номери будуть змінюватися залежно від апаратного та програмного забезпечення, тому, мабуть, не варто витрачати купу часу на реверсивну інженерію. Тому просто спробуйте і подивіться! Виберіть метрику: або "кількість текстур на кадр", або "загальний розмір текстур на кадр", виберіть квоту (скажімо, 4 текстури на кадр) і починайте її стрес-тестувати.

У патологічних випадках вам може знадобитися навіть відслідковувати обидві квоти одночасно (наприклад, обмежте 4 текстури на кадр або 2 МБ текстур на кадр, залежно від того, що нижче). Але справжня хитрість більшості потоків текстур - це з’ясування, які текстури потрібно вписати у вашу обмежену пам’ять, а не скільки часу потрібно для їх копіювання.

Крім того, патологічні випадки створення текстури - як і багато крихітних текстур, які потрібні відразу - виявляються патологічними і для інших областей. Варто отримати просту робочу реалізацію, перш ніж потурбуватися про те, скільки саме мікросекунд потребує копіювання текстури. (Плюс до цього, справжнє звернення до продуктивності може не виникати як час процесора під час виклику "створити текстуру", а натомість як час GPU на першому кадрі ви використовуєте текстуру.)


Це досить хороше пояснення. Багато речей, яких я не знав, але мають багато сенсу. Замість того, щоб стрес-тестувати це, я міг би виміряти створення текстури накладних витрат під час виконання, почати обережно і заглушити, щоб сказати, 80% від доступного часу виконання, щоб залишити місце для людей, що вижили.
Піжама Panda

@PandaPajama Я трохи скептично ставлюсь до цього. Я б очікував, що в стаціонарному стані не буде "копіювання текстур" і величезна кількість дисперсії. І як я вже говорив, я підозрюю, що частина хіта - це перший кадр візуалізації, який використовує текстуру, що набагато важче динамічно виміряти, не впливаючи на продуктивність.
Джон Калсбек

Також, ось презентація NVIDIA щодо асинхронних передач текстури. Найголовніше, що він їздить додому, наскільки я читаю, - це те, що занадто рано після завантаження текстура використовується після того, як ви завантажуєте її. developer.download.nvidia.com/GTC/PDF/GTC2012/PresentationPDF/…
Джон Calsbeek

Я не водій-жокей, але це звичайне явище? Немає сенсу реалізовувати драйвери таким чином, тому що, швидше за все, текстури, що спочатку користуються текстурами, будуть мати шипи (як на початку кожного рівня), а не на відстані за часовою шкалою.
Піжама Panda

@PandaPajama Також звичайно для додатків створювати більше текстур, ніж є VRAM, та створювати текстури, а потім ніколи їх не використовувати. Поширений випадок - "створити купу текстур, а потім негайно намалювати сцену, яка їх використовує", і в цьому випадку лінь допомагає водієві, тому що він може зрозуміти, які текстури використовуються насправді, і цей перший кадр все-таки зачепить. . Але я також не розвідник водіїв, візьміть його із зерном солі (і випробуйте!).
Джон Калсбек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.