Подтвердить что ты не робот

Управление памятью С++ для потоковой передачи текстур в видеоиграх

это "жесткий" вопрос. Я не нашел ничего интересного в Интернете.

Я разрабатываю модуль управления памятью для своей компании. Мы разрабатываем игры для консолей следующего поколения (Xbox 360, PS3 и ПК... мы рассматриваем ПК консоль!).

В будущих играх нам понадобится обработать потоки текстур для больших игровых миров, которые не могут быть загружены в основную консольную память (не говоря уже о ПК на данный момент).

Мы собираемся передать в начале hi-res мипмапы текстур (что составляет около 70% от объема мировых данных). Может быть, в будущем нам придется потопить также геометрию, меньшие мип-карты, аудио и т.д.

Я разрабатываю диспетчер памяти для этой проблемы, ориентированный на X360 (потому что на PS3 мы можем использовать память хоста и связанный с ним автодефракционный GMM-распределитель).

Проблема, с которой я сталкиваюсь, заключается в следующем: мы решили зарезервировать определенную область памяти для потоковой передачи текстур (например, 64 мегабайта), и мы хотим обрабатывать все распределения и освобождения от необходимости в этой области. Мы выделили область в начале приложения, и область физически гарантирована быть смежной (не только практически, потому что нам нужно хранить текстуры там).

Я реализовал автоматический дефрагментационный распределитель, используя дескрипторы вместо указателей. Время не проблема, проблема в фрагментации памяти. В игре мы постоянно загружаем и выгружаем потоковые цели, поэтому мы хотели бы использовать максимальный объем нашего буфера (64 мегабайта).

С помощью этого распределителя мы можем использовать все выделенное пространство, но подпрограмма дефрагментации работает в неаккуратное время (иногда 60 миллисекунд, больше, чем кадры!), в то время как алгоритм не так уж плох... есть слишком чересчур непредсказуемые тетср!

Я ищу решение для решения этой проблемы. Я бы хотел найти хотя бы хорошую бумагу или посмертное слово или кого-то, у кого была та же проблема.

Теперь я выбираю между двумя стратегиями: 1) переместите подпрограмму дефрагментации на выделенный поток (хорошо для X360 с потоками 6 hw, плохо для PS3 с потоком hw... и не говорите мне использовать SPU!) Со всеми проблемами многопоточности областей блокировки, доступ к региону, который перемещается,... 2) найти "инкрементное" решение проблемы дефрагментации: мы можем предоставить каждому кадру временный бюджет (например, до 1 миллисекунды) для дефрагментации, а диспетчер памяти будет делать то, что он может сделать в бюджете каждого кадра.

Может ли кто-нибудь рассказать мне о своем опыте?

4b9b3361

Ответ 1

Недавно я много изучил управление памятью, и это самая информативная и полезная статья, которую я нашел в сети.

http://www.ibm.com/developerworks/linux/library/l-memory/

Основываясь на этой статье, лучший и быстрый результат, который вы получите, состоит в том, чтобы разделить 64 МБ на куски равного размера. Размер кусков будет зависеть от размера вашего объекта. И выделять или освобождать полный кусок за раз. Это

  • Быстрее, чем инкрементная сборка мусора.
  • Simpler.
  • И решает эту проблему "слишком много фрагментации" на какую-то сумму.

Прочтите, вы найдете отличную информацию о каждом возможном решении, которое есть, и достоинствах и недостатках для каждого.

Ответ 2

Почему бы не использовать несколько областей памяти для потоковых текстур и пула по размеру текстуры?

Insomniac имеет документ об их реализации потоковой передачи текстур на PS3. Я полагаю, это может быть полезно: ссылка.

Для общих стратегий распределения, чтобы минимизировать фрагментацию, может помочь Doug Lea.

Но из моего чтения вашего вопроса, похоже, вы переусердствовали, и я настоятельно рекомендую использовать объединенный подход. (Кроме того, запуск дефрагментационного прохода в памяти с записью не звучит особенно безопасно или забавно.)

Ответ 3

Поскольку вы используете ручки, у вас есть много свободы для перемещения памяти. Я думаю, что использование отдельного потока, вероятно, не самый лучший (самый безопасный или быстрый) способ - думаю, вам лучше использовать тип инкрементного распределителя копирования, где на каждом malloc() или free() вы компактны ( копировать вперед или назад в памяти) некоторое количество выделенных блоков с количеством байтов, которое вы копируете, истощая "бюджет", который периодически reset, до его начального значения (например, при каждом обновлении экрана). (Конечно, копируются только целые блоки.)

Идея состоит в том, что копирование заданного количества байтов занимает довольно предсказуемое количество времени, поэтому вы можете оценить, сколько байтов копирования вы можете безопасно выполнять на обновление экрана, и ограничиться этим. Если в бюджете достаточно времени, вызов malloc() или free() будет полностью дефрагментировать память, в противном случае он будет дефрагментировать его как можно больше в заданных временных ограничениях.

Есть некоторые вопросы, которые я оставляю здесь нерешенными - например. точно как сжать память. Стандартный неинкрементный копировальный распределитель может просто начать выделять с фронта, а затем копировать все в спину (освобождая память спереди), когда память заканчивается, но у вас нет этой свободы здесь. Возможно, вам понадобится эвристика, чтобы решить, нужно ли перемещать блоки вперед или назад. Важно избегать колебаний (один и тот же блок перемещается вперед, а затем назад при последовательных вызовах на malloc() или free()).

Ответ 4

Мы почти точно описали систему, за исключением того, что мы выделяем в слоты фиксированного размера - 256x256, 512x512, 1024x1024 и 2048x2048 текстуры в двух форматах каждый (DXT1 и DXT5) - чтобы избежать управления памятью.

Ответ 5

Я бы рекомендовал постепенный подход. Каждый кадр находит непрерывный блок памяти inuse, который имеет свободное пространство с обеих сторон и перемещает его в зависимости от того, какое из направлений позволит ему поместиться. или вы можете просто переместить все блоки в одном направлении, найти зазор и использовать блок, который лучше всего подходит для него и переместить его. На 360 вам, вероятно, следует использовать поток для перемещения, в то время как на PS3 лучше всего использовать графический процессор для перемещения данных вокруг вас.