Warsztat » Forum

[C++] Wczytywanie plików prosto do pamięci - Platform Bin

Feb 16, 2004 | Regedit |
10 wypowiedzi na 1 stronach:
1
Regedit
Feb 16, 2004

Wczytywanie plików prosto do pamięci - Platform Bin

Stosuję sobie dotychczas beztrosko różne pliki tekstowe, jako że mam parser, na bazie którego mogę bardzo szybko i wygodnie tworzyć nowe formaty pliku (języki opisu). Ale to jest - wiadomo - wolne, bo trzeba wczytywać, parsować, wyciągać potrzebne informacje. Spotkałem się ostatnio z ideą wczytywania do pamięci różnorodnych struktur jako JEDNEGO DUŻEGO BINARNEGO BLOKU i korzystania z tego bezpośrednio. Najpierw mówił mi o tym pewien bardzo sympatyczny rzeźnik (mogę ujawnić który? :)), a potem napisał w komentarzach na moim blogu niejaki ed (http://regedit.gamedev.pl/news_1109.html).

Moje pytanie jest: Czy ktoś z was może powiedzieć coś więcej na temat tego rozwiązania, które ed określił jako "PLATFORM BIN"? Jasne, że można tutaj dużo samemu powymyślać, ale fajnie byłoby wiedzieć co zostało już wymyślone. Tymczasem, jak to mówią, Google milczy ;) Macie z tym jakieś doświadczenia? Jak mogłoby wyglądać zapisywanie, a potem odczytywanie i używanie w jednym surowym kawałku pamięci jakiś stringów, wektorów, list, drzew, słowników? Jak przygotowywać taki plik? Napisać jeden wielki wypasiony edytor do gry, a może dużo małych narzędzi? Albo może po prostu konwertować pliki tekstowe we własnym formacie do plików binarnych jakimś prostym programem konsolowym? Czy ten temat, jeśli wiecie o czym mówię, jest mniej więcej tym samym co "SERIALIZACJA"? Czy może ja to źle zrozumiałem i chodzi raczej tylko o VFS (Virtual File System)?
Złośliwiec
Feb 17, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Hmmm... Ja stosuję takie coś w U i nazywam to serializacją (bo nią jest), nie wymyślając żadnych kosmicznych i mylących nazw w stylu "platform bin". A że używam do tego VFS, to już zupełnie inna sprawa :).
Czomolungma
Feb 17, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Samo zapisanie struktury do pliku, a następnie jej odczytanie nie wydaje się być problemem. Gorzej jak któreś z jego pól jest wskaźnikiem lub odnosi się do danych zaalokowanych na stercie - wtedy po odczytaniu jest duże prawdopodobieństwo, że będzie to błędny wskaźnik.
Xion
Feb 17, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Wtedy zapisujemy i ją - na tym generalnie polega serializacja. Nie jest to trudne, ale kłopotliwe w C++, gdzie potrzeba jakoś zapisać w kodzie informacje o strukturze klasy.
Czomolungma
Feb 18, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Xion: IMO coś co by było w stanie zapisać, a następnie poprawnie odczytać takie dane, jak podane w kodzie poniżej, byłoby dość trudne do napisania i wymagałoby sporo danych na wejście (budowa struktury my_struct, ilość miejsca zarezerwowanej na stercie dla pointer3 itp.). Poza tym musiałoby być na tyle dobrze zaimplementowane, aby nie dublować danych i po wczytaniu global_pointer powinien ciągle wskazywać na dane zapisane w obiekcie something.

Kod: cpp]
int number = 5;

struct my_struct
{
int data;
int* pointer1;
int* pointer2;
int* pointer3;

my_struct ()
{
data = 256;
pointer1 = &data;
pointer2 = &number;
pointer3 = new int [10];
for (int x = 0; x < 10; x++)
pointer[x] = x;
}
};

my_struct something;
int* global_pointer = &something.data;
revo
Feb 19, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

To już w pierwszych perełkach było "Sztuczka z szybkim wczytywaniem danych" ;)

Osobiście bym zrobił to tak, że projektując własne pliki ze specyfikacją, dodawałbym typ jako pierwszy bajt. Np. 0 jako pliki tekstowe, 1 jako binarne (lub jakiś specjalny ciąg bajtów określający pliki binarne). Wtedy można zaimplementować wczytywanie danych zależnie od tego jak plik jest skonstruowany. Podczas tworzenia projektu używać wersji tekstowej, bo łatwo w niej coś zmieniać, a przed publikacją przepuścić to przez konwerter do wersji binarnej.

Alternatywnie, niech parametrem funkcji ładującej będzie nazwa pliku bez rozszerzenia i wersje binarne kończą się na b (tzn rozszerzenie). Wtedy sprawdzamy czy istnieje plik binarny, jak nie to ładujemy w podstawowej formie.
Krzysiek K.
Feb 17, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Cytat:
Najpierw mówił mi o tym pewien bardzo sympatyczny rzeźnik (mogę ujawnić który? :))

Jasne. :) Mój pomysł polegał na tym, żeby wczytywać ekspresowo z pliku dowolnie skomplikowane zależności różnych struktur z pliku o banalnym wręcz formacie.

Ów format wyglądałby tak:
4 bajty - liczba bajtów danych
n bajtów - właściwe dane
4 bajty - liczba wskaźników do naprawy
4n bajtów - lista offsetów na wskaźniki

Algorytm wczytywania polega na wczytaniu danych oraz listy offsetów wskaźników, po czym naprawieniu wskaźników przez dodanie do nich adresu początku bloku danych wykonując operację typu "*(int*)(data+offset) = *(int*)(data+offset) ? *(int*)(data+offset) + (int)data + 1 : NULL;" (uwzględniono możliwość kodowania NULL'a). Na koniec zwracamy jako void* początek bloku danych, a aplikacja korzystająca z tej funkcji rzutuje sobie to na typ wskaźnika do początkowej struktury.

Co prawda algorytm zapisu do czegoś takiego jest niebanalny i wymaga rozumienia znaczenia pól wszystkich zapisywanych struktur oraz przechodzenia po grafie połączeń pomiędzy nimi, ale jak widać algorytm odczytu wymaga jedynie rozkodowania wartości zapisanych wskaźników.

W efekcie w pliku mogą być zapisywane dane typów:
- struktury, klasy niewirtualne i unie, których składowe są typów z niniejszej listy,
- wszystkie typy podstawowe (int, bool, float, __int64 itd),
- wskaźniki na struktury i klasy z punktu pierwszego,
- wskaźniki na tablice struktur, klas i wszystkich innych typów z tej listy (jednak ilość elementów trzeba wywnioskować w inny sposób, na przykład trzymając go w jakiejś zmiennej),
- tablice struktur i innych typów o stałym rozmiarze (np. char[32]),
- wskaźniki na łańcuchy tekstowe (char* - tu nie ma problemów bo wiemy że kończą się zerem),
- (pewnie można by jeszcze coś wymyślić, ale i tak trochę tego jest),

Jeżeli chodzi o klasy wirtualne, to teoretycznie też dało by się je zapisywać, tyle że trzeba by w pliku zapisać także dla nich vtable oraz sam kod metod lub uwzględnić je dodatkowo w trakcie rozkodowywania wskaźników (np. określony kod będzie zamieniany na adres vtable danej klasy). Można się także pokusić o dodanie do pliku dodatkowej listy offsetów do klas wymagających konstrukcji i na tej podstawie wywołać dla nich konstruktory umieszczające o specjalnym formacie (uwzględniające, że wszystkie pola klasy są już wypełnione właściwymi wartościami).


Cytat:
Czy ktoś z was może powiedzieć coś więcej na temat tego rozwiązania, które ed określił jako "PLATFORM BIN"?

Najwidoczniej jest to nazwa wymyślona, ale wyraźnie chodzi tu po prostu o memory dumpa, który jest plikiem binarnym ściśle związanym z daną platformą.

Cytat:
Czy ten temat, jeśli wiecie o czym mówię, jest mniej więcej tym samym co "SERIALIZACJA"?

Mniej więcej, tyle że jest to serializacja nieestetyczna i efektywna w odróżnieniu od klasycznego pojęcia serializacji, które są eleganckie i wolniejsze.
yarpen
Feb 18, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Cytat:

Cytat:
Czy ktoś z was może powiedzieć coś więcej na temat tego rozwiązania, które ed określił jako "PLATFORM BIN"?

Najwidoczniej jest to nazwa wymyślona, ale wyraźnie chodzi tu po prostu o memory dumpa, który jest plikiem binarnym ściśle związanym z daną platformą.

Dokladnie. Beda roznice pomiedzy platformami, nawet w przypadku identycznych struktur. Zreszta roznice sa nawet miedzy kompilatorami, dalo nam to niezle w kosc na samym poczatu developingu Wiedzmina, gdy jeszcze toolset byl napisany w Borlandzie.
Krzysiek K.
Feb 18, 2004

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

Cytat:
Dokladnie. Beda roznice pomiedzy platformami, nawet w przypadku identycznych struktur. Zreszta roznice sa nawet miedzy kompilatorami, dalo nam to niezle w kosc na samym poczatu developingu Wiedzmina, gdy jeszcze toolset byl napisany w Borlandzie.

No ale jak ktoś się uczepił jak rzep Visuala 2005 EE i pisze tylko pod PC x86 z Win32, to rozwiązanie samo w sobie większych wad nie ma. :)
Esidar
Dec 16, 2003

Odp: Wczytywanie plików prosto do pamięci - Platform Bin

IMO nie powinno się używać Platform Bin'ów jako sposobu na serializację. W czasie developingu często zmieniają się struktury i głupio byłoby gdyby nagle wszystkie pliki przestały się wczytywać :) Miałem ten problem w CI gdzie główny programista odpowiedzialny za silnik napisał serializację do plików binarnych i potem zupełnie nie przyjmował do wiadomości fakt, że jeśli na 2tyg przed końcem projektu, przestały się wczytywać wszystkie zasoby gry to nie jest to dobry znak :)
Ja do serializacji używam XML lub formatu zbliżonego do IFF (z dodatkowymi właściwościami takimi jak np. nazwy chunków mogą mieć dowolną długość, a stringi są zapisywane w tablicy stringów na końcu pliku a w środku pliku są używane tylko indeksy do nich).

Co do samych Platform Bin'ów to powinien być już format końcowy do uruchamiania zoptymalizowanej gry. Jest to dość często stosowane na konsolach na PC mało kto się w to bawi, co nawiązuje do rozmowy w innym wątku o tym czy opłaca się inwestować w optymalizację :). A czasami gdy się nie zoptymalizuje wczytywania to wychodzą różne nie ciekawe rzeczy (patrz, jedna z polskich produkcji ;) ). W konsolach jest mało pamięci 32MB do 512MB i często się stosuje streamowanie świata. To wymusza używanie optymalizowanych Platform Bin'ów. Przykładowo w jednej z gier na X360, świat jest podzielony bloki po 55MB danych i gra wczytuje ich 3 na raz. Biorąc pod uwagę to że napęd DVD ma prędkość 18MB/s, to daje w najgorszym przypadku czas wczytywania bloku 3sec. Czas ten jest trochę zmniejszony dzięki temu że te bloki są dekompresowane podczas wczytywania. Dodatkowo używany jest "trick" i na początku wczytywane są meshe, potem lightmapy a na końcu tekstury. Dzięki temu meshe są aktywne najszybciej (są podłączane pod fizykę co zapobiega spadnięciu gracza w nicość :) ).

Tutaj jest prezentacja z GDC2006 na ten temat https://www.cmpevents.com/sessions/GD/S2304i1.ppt . Jest tutaj stwierdzony dość ciekawy fakt. O ile konsole zwiększyły ilość pamięci 8x-16x, to prędkość wczytywania z DVD zwiększyła się tylko o 2x-4x.
Tutaj też jest inny ciekawy artykuł http://entland.homelinux.com/blog/2007/02/21/fast-file-loading-ii-load-in-place/

W obydwu linkach jest poruszony problem relokacji wskaźników. Jest tam użyta konstrukcja z którą nie spotykam się czesto na PC :) "new (pointer) Class()" czyli wywołanie konstruktora dla obiektu już zaalokowanego.

Edit: tworzeniu i używaniu platform bin'a, z pewnością sprzyja porządnie zrobiona serializacja którą potem można łatwo przełożyć na format "load in place". Ja, zarówno w XML jak i w IFF używam mechanizmów do serializacji wskaźników. Podczas zapisu serializer zapamiętuje listę serializowanych wskaźników i nadaje im kolejne numery. Te numery są zapisywane w pliku. Potem podczas wczytywania, jest znana ogólna ilość wskaźników i każdy z wczytywanych numerów służy albo do stworzenia nowego obiektu albo do zwrócenia wskaźnika, na już istniejący obiekt (wcześniej od-serializowany :) ). Oczywiście trzeba też, oprócz numeru wskaźnika, zapisać typ tego wskaźnika (żeby podczas wczytywania, serializer wiedział jaki obiekt ma utworzyć).
Strony:
1