Technical Article

Alcinoe biblioteka komponenti i kompatibilnost sa Delphi 11.1 Alexandria

Alcinoe je biblioteka komponenti otvorenog koda za Delphi i C++Builder, koju na GitHub-u održava Zeus64. Ona pokriva oblasti koje VCL i FireMonkey RTL prepuštaju trećim stranama: video plejer sa GPU ubrzanjem, WebRTC omotač (wrapper), izvorne kontrole za uređivanje za iOS i Android, dvorežimski JSON/BSON parser, MongoDB klijent sa grupisanim vezama (connection pooling), ImageMagick omotač i kolekciju FireMonkey kontrola koje u potpunosti zaobilaze standardni proces renderovanja. Biblioteka je izgradila svoju reputaciju na verzijama Rio (10.3.3) i Sydney (10.4.2), i od tada prati svako Embarcadero izdanje. U trenutku pisanja, u potpunosti je kompatibilna sa Delphi 11.1 Alexandria i Delphi Athens 12.3.

Integracija Alcinoe biblioteke u projekat

Instalacija se deli na jedno pitanje: da li vam je potrebna podrška u vreme dizajniranja (design-time) za vizuelne kontrole Alcinoe? Ako nije, potpuno preskočite BPL. Dodajte {alcinoe_rootdir}\source u putanju pretrage biblioteka projekta i završili ste. Svaka nevizuelna komponenta, uključujući parsere, klijente baza podataka i string uslužne programe, kompajlira se iz izvornog koda bez registrovanja bilo čega.

Kada vam je potrebna podrška u vreme dizajniranja, put je nešto duži. Otvorite Component > Install Packages u Delphi IDE-u, idite do BPL-a koji odgovara vašoj verziji (na primer {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl), instalirajte ga, a zatim i dalje dodajte {alcinoe_rootdir}\source u putanju pretrage. BPL registruje komponente; izvorni direktorijum je ono što kompajler pronalazi kada kompajlira vaš projekat.

Alcinoe isporučuje opcione zakrpe (patches) za Embarcadero RTL izvorne kodove. Ako ih želite, idite do {alcinoe_rootdir}\embarcadero\, izaberite poddirektorijum za svoju verziju i pokrenite update.bat. Skripta očekuje GIT u putanji PATH i pretpostavlja podrazumevanu Embarcadero lokaciju instalacije. Ona preuzima originalni RTL izvorni kod i primenjuje zakrpe. Kada završite, dodajte taj direktorijum sa zakrpama u putanju pretrage projekta kako bi ga kompajler preuzeo pre kopije koja je samo za čitanje u stablu instalacije Embarcadero. Ništa od ovoga nije obavezno za početak; važno je samo ako naiđete na greške koje zakrpe rešavaju.

Android i D8 proxy za uklanjanje sintaksičkog šećera (desugaring)

Nekoliko Alcinoe komponenti (WebRTC, video podržan ExoPlayer-om) zavise od Java biblioteka koje koriste jezičke funkcije Java 8. Android set alata koji se isporučuje sa starijim verzijama Delphi-ja koristi dx.bat za DEX konverziju, koja ne može da obrađuje te bajtkodove na API nivoima ispod 26. Rešenje je desugaring (uklanjanje sintaksičkog šećera), što D8 automatski obavlja kada se direktno pozove. Alcinoe obezbeđuje proxy skriptu na lokaciji {alcinoe_rootdir}\tools\D8Proxy\dx.bat koja prosleđuje pozive iz Delphi sistema za izgradnju (build system) ka D8, čineći desugaring transparentnim. Zamenite originalni dx.bat u vašem Android SDK build-tools direktorijumu (obično C:\SDKs\android\build-tools\30.0.3\) sa ovim proxy-jem. Embarcadero je pratio ovaj problem pod oznakom RSP-24155; novije verzije SDK alata su to direktno rešile, pa proverite da li je vašem trenutnom setu alata i dalje potrebno ovo rešenje.

Problem renderovanja u FireMonkey-u i Alcinoe rešenje

Podrazumevani ciklus iscrtavanja u FireMonkey-u postaje usko grlo u korisničkim interfejsima sa mnogo skrolovanja. Jednom TRectangle-u sa zaobljenim uglovima može biti potrebno oko 3 ms za ponovno iscrtavanje jer standardna implementacija preračunava putanju u svakom frejmu. Sa 20 takvih kontrola na ekranu, to iznosi 60 ms po prolazu frejma, što ograničava efektivnu brzinu osvežavanja (frame rate) znatno ispod praga za glatko skrolovanje.

Alcinoe ovo rešava pomoću GPU bafera po svakoj kontroli. Prvo iscrtavanje renderuje kontrolu u TTexture koji se čuva u GPU memoriji. Naknadna iscrtavanja kopiraju (blituju) tu teksturu umesto ponovnog izvršavanja algoritma iscrtavanja. Izmereni rezultat na istom zaobljenom pravougaoniku opada sa oko 3 ms na oko 0.1 ms. Pored baferovanja, Alcinoe zamenjuje OpenGL crtanje putanja za osnovne oblike sa izvornim Android i iOS API-jima za crtanje, zaobilazeći kompromis između kvaliteta i performansi koji je povezan sa opcijom Form.Quality. Odgovarajuće kontrole su TALRectangle, TALCircle i skup poboljšanih kontejnera rasporeda (layout containers) uključujući ScrollBox i TabControl.

TALJsonDocument: DOM i SAX u jednom tipu

TALJsonDocument je Alcinoe-ov parser za JSON i BSON. Podržava dva režima prolaska. DOM režim gradi stablo objekata u memoriji, pružajući nasumičan pristup bilo kom čvoru po ceni memorije koja je proporcionalna veličini dokumenta. SAX režim pokreće događaje kako parser čita svaki token bez zadržavanja stabla u memoriji, što je pravi izbor kada treba da filtrirate veliki dokument i zadržite samo nekoliko vrednosti. DOM parseri u Delphi-ju (DBXJSON, SuperObject i drugi) su obično tri do pet puta sporiji od SAX pristupa za isti sadržaj, jer svaka alokacija čvora nosi dodatni trošak kreiranja objekta povrh samog rada na parsiranju.

Tip prati isti obrazac navigacije kroz čvorove kao i TALXMLDocument. Minimalno čitanje preko DOM-a izgleda ovako:

MyJsonDoc.LoadFromJSON(AJsonStr, False {dom mode});
MyJsonDoc.ParseOptions := [poAllowComments];

// read scalar values
ShowMessage(MyJsonDoc.ChildNodes[‘name’].ChildNodes[‘first’].Text);
ShowMessage(IntToStr(MyJsonDoc.ChildNodes[‘_id’].Int32));

// iterate an array
for I := 0 to MyJsonDoc.ChildNodes[‘contribs’].ChildNodes.Count - 1 do
  Writeln(MyJsonDoc.ChildNodes[‘contribs’].ChildNodes[I].Text);

Za SAX režim, dodelite anonimnu proceduru događaju OnParseText pre nego što pozovete LoadFromJSON sa drugim argumentom postavljenim na True. Povratni poziv (callback) prima putanju čvora, ime, vrednost i TALJSONNodeSubType koji identifikuje tip JSON-a (string, ceo broj, realan broj, logička vrednost itd.). Taj režim ne pravi alokacije na hipu (heap) za čvorove, tako da se skalira na proizvoljno velike dokumente bez prekoračenja memorijskog budžeta.

TALJsonDocument takođe izvorno čita i upisuje BSON; prosledite True kao BSON zastavicu za LoadFromFile ili SaveToFile. Druga varijanta, TALJsonDocumentU, interno koristi UnicodeString (UTF-16) umesto AnsiString (UTF-8) za kontekste u kojima prateći kod radi isključivo sa Unicode-om.

MongoDB klijent i grupisanje veza (connection pooling)

Alcinoe-ov MongoDB drajver pokriva uobičajene operacije upita i izvorno upravlja grupisanjem veza. Jednostavan klijent, TAlMongoDBClient, otvara i zatvara jednu vezu po operaciji. Varijanta sa grupisanjem veza, TAlMongoDBConnectionPoolClient, održava skup aktivnih veza i predaje jednu svakoj niti koja je poziva iz grupe, vraćajući je po završetku poziva. Taj model sprečava da više niti blokiraju jedna drugu prilikom uspostavljanja veze, što je važno kad god pozadinski procesi istovremeno šalju upite istoj bazi podataka. Za tailable kursore na capped kolekcijama, TAlMongoDBTailMonitoringThread prati nove dokumente i pokreće povratni poziv kada stignu, što je standardni obrazac za strimovanje logova ili obaveštenja o promenama bez periodičnog upita (polling).

Ostale komponente koje vredi znati

ALVideoPlayer renderuje video u TTexture umesto u prekrivajući prozor (overlay window), tako da se druge FireMonkey kontrole mogu nalaziti iznad njega u Z-redosledu. Android pozadinski sistem (backend) koristi ExoPlayer, koji dodaje podršku za DASH, HLS i SmoothStreaming pored onoga što podržava ugrađeni Android-ov MediaPlayer. iOS backend koristi AVPlayer sa ekvivalentnom HLS podrškom.

TALWebRTC omotava WebRTC stek za direktnu audio i video komunikaciju (peer-to-peer). Za to nije potreban pretraživač niti dodatak, a veza prolazi kroz NAT kroz standardno ICE/STUN/TURN pregovaranje koje obavlja prateća biblioteka.

TALStringList zamenjuje sortiranje komponente TStringList zasnovano na funkciji AnsiCompareText sa ordinalnim poređenjem koje je nezavisno od lokaliteta i quicksort-om koji je do 10 puta brži na velikim listama. Heshirana varijanta, TALHashedStringList, dodaje internu heš tabelu za O(1) pretragu po ceni malo većeg opterećenja na malim listama. Imajte na umu da je TALStringList 8-bitna AnsiString lista, a ne Unicode; dobro se uklapa u kod na strani servera gde je UTF-8 radno kodiranje i sirovi protok je važniji od poređenja prilagođenog lokalitetu.

Na 64-bitnom Windows-u, FastCode nasleđe koje je mnogim Alcinoe string rutinama dalo prednost u brzini (uglavnom ručno pisani x86 asemblerski kod) se ne prenosi. Win64 verzije se oslanjaju na Pascal implementacije, koje rade primetno sporije na zadacima sa intenzivnim korišćenjem stringova. Projekat demo\ALStringBenchMark vam omogućava da izmerite razliku na vašem hardveru pre nego što se odlučite za 64-bitnu verziju u kojoj je protok stringova usko grlo.

Kompletan izvorni kod se nalazi na github.com/Zeus64/alcinoe.