기술 문서

Alcinoe 컴포넌트 라이브러리 및 델파이 11.1 알렉산드리아 호환성

Alcinoe는 Zeus64가 GitHub에서 유지 관리하는 델파이 및 C++Builder용 오픈 소스 컴포넌트 라이브러리입니다. 이 라이브러리는 VCL 및 FireMonkey RTL이 타사(third parties)에 맡겨두는 영역을 다룹니다: GPU 가속 비디오 플레이어, WebRTC 래퍼, 네이티브 iOS 및 Android 편집 컨트롤, 이중 모드 JSON/BSON 파서, 연결 풀링을 지원하는 MongoDB 클라이언트, ImageMagick 래퍼, 기본 렌더링 파이프라인을 완전히 우회하는 일련의 FireMonkey 컨트롤 등이 포함됩니다. 이 라이브러리는 Rio(10.3.3) 및 Sydney(10.4.2)에서 명성을 얻었으며, 이후 각 Embarcadero 릴리스를 추적해 왔습니다. 작성 시점을 기준으로 델파이 11.1 알렉산드리아(Alexandria) 및 델파이 아테네(Athens) 12.3과 완벽하게 호환됩니다

프로젝트에 Alcinoe 추가하기

설치는 한 가지 질문으로 나뉩니다: Alcinoe의 시각적 컨트롤에 대한 디자인 타임 지원이 필요합니까? 그렇지 않다면 BPL을 완전히 건너뛰십시오. 프로젝트의 라이브러리 검색 경로에 {alcinoe_rootdir}\source를 추가하면 완료됩니다. 파서, 데이터베이스 클라이언트, 문자열 유틸리티를 포함한 모든 비시각적 컴포넌트는 아무것도 등록할 필요 없이 소스에서 직접 컴파일됩니다

디자인 타임 지원이 필요한 경우 경로는 약간 더 깁니다. 델파이 IDE에서 Component > Install Packages를 열고 사용 중인 버전과 일치하는 BPL(예: {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl)을 찾아 설치한 다음, 여전히 검색 경로에 {alcinoe_rootdir}\source를 추가합니다. BPL은 컴포넌트를 등록하고, 소스 디렉토리는 컴파일러가 프로젝트를 컴파일할 때 찾는 곳입니다

Alcinoe는 Embarcadero RTL 소스에 대한 선택적 패치를 제공합니다. 이를 원한다면 {alcinoe_rootdir}\embarcadero\로 이동하여 해당 버전에 맞는 하위 디렉토리를 선택하고 update.bat를 실행하세요. 이 스크립트는 PATH에 GIT이 설정되어 있기를 기대하며 기본 Embarcadero 설치 위치를 가정합니다. 원래 RTL 소스를 가져와 패치를 적용합니다. 완료되면 컴파일러가 Embarcadero 설치 트리의 읽기 전용 사본보다 패치된 소스를 먼저 선택하도록 패치된 소스 디렉토리를 프로젝트 검색 경로에 추가합니다. 이 중 어느 것도 시작하는 데 필수적인 것은 아닙니다. 패치가 해결하는 버그에 부딪혔을 때만 의미가 있습니다

Android 및 D8 디슈가링(desugaring) 프록시

몇몇 Alcinoe 컴포넌트(WebRTC, ExoPlayer 지원 비디오)는 Java 8 언어 기능을 사용하는 Java 라이브러리에 의존합니다. 이전 델파이 버전과 함께 제공되는 Android 툴체인은 DEX 변환에 dx.bat를 사용하며, API 레벨 26 미만에서는 이러한 바이트코드를 처리할 수 없습니다. 해결책은 D8을 직접 호출할 때 자동으로 처리되는 디슈가링(desugaring)입니다. Alcinoe는 델파이 빌드 시스템의 호출을 D8로 전달하여 디슈가링을 투명하게 만드는 프록시 스크립트를 {alcinoe_rootdir}\tools\D8Proxy\dx.bat에 제공합니다. Android SDK build-tools 디렉토리(일반적으로 C:\SDKs\android\build-tools\30.0.3\)의 원래 dx.bat를 이 프록시로 바꾸세요. Embarcadero는 근본적인 문제를 RSP-24155에서 추적했으며 이후 버전의 SDK 도구에서 이를 직접 해결했으므로 현재 툴체인에서 여전히 이 임시방편(workaround)이 필요한지 확인하세요

FireMonkey 렌더링 문제와 Alcinoe의 해답

FireMonkey의 기본 그리기(paint) 주기는 스크롤이 많은 UI에서 병목 현상이 됩니다. 모서리가 둥근 단일 TRectangle은 기본 구현이 매 프레임마다 경로를 다시 계산하기 때문에 다시 그리는 데 약 3ms가 걸릴 수 있습니다. 이러한 컨트롤이 20개 보이면 프레임 패스당 60ms가 더해지며, 이는 유효 프레임 속도를 부드러운 스크롤의 임계값 훨씬 아래로 제한합니다

Alcinoe는 각 컨트롤에 대한 GPU 상주 버퍼로 이 문제를 해결합니다. 첫 번째 그리기는 컨트롤을 GPU 메모리에 저장된 TTexture로 렌더링합니다. 후속 다시 그리기는 그리기 알고리즘을 다시 실행하는 대신 해당 텍스처를 블리팅(blit)합니다. 동일한 둥근 사각형에 대해 측정된 결과는 약 3ms에서 약 0.1ms로 떨어집니다. 버퍼링 외에도 Alcinoe는 Form.Quality와 관련된 품질/성능 절충안을 피하면서 기본 도형에 대한 OpenGL 경로 그리기를 네이티브 Android 및 iOS 그리기 API로 대체합니다. 관련 컨트롤은 TALRectangle, TALCircleScrollBoxTabControl을 포함한 개선된 레이아웃 컨테이너 세트입니다

TALJsonDocument: 하나의 타입에 포함된 DOM과 SAX

TALJsonDocument는 Alcinoe의 JSON 및 BSON 파서입니다. 두 가지 탐색 모드를 지원합니다. DOM 모드는 문서 크기에 비례하는 메모리를 희생하면서 모든 노드에 대한 무작위 액세스를 제공하여 메모리 내 객체 트리를 구축합니다. SAX 모드는 트리를 유지하지 않고 파서가 각 토큰을 읽을 때 이벤트를 발생시킵니다. 이는 큰 문서를 필터링하고 소수의 값만 유지해야 할 때 올바른 선택입니다. 델파이의 DOM 파서(DBXJSON, SuperObject 및 기타)는 동일한 내용에 대해 SAX 방식보다 일반적으로 3~5배 느립니다. 각 노드 할당이 파싱 작업 자체 위에 객체 생성 오버헤드를 수반하기 때문입니다

이 타입은 TALXMLDocument와 동일한 노드 탐색 패턴을 따릅니다. 최소한의 DOM 읽기는 다음과 같습니다:

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);

SAX 모드의 경우 LoadFromJSON을 호출하기 전에 두 번째 인수를 True로 설정하고 OnParseText에 익명 프로시저를 할당하세요. 콜백은 노드 경로, 이름, 값 및 JSON 타입(문자열, 정수, 부동 소수점, 부울 등)을 식별하는 TALJSONNodeSubType을 수신합니다. 이 모드는 노드에 대한 힙 할당을 생성하지 않으므로 메모리 예산을 초과하지 않고도 임의로 큰 문서로 확장할 수 있습니다

TALJsonDocument는 BSON도 기본적으로 읽고 씁니다. LoadFromFile 또는 SaveToFile에 BSON 플래그로 True를 전달하세요. 두 번째 변형인 TALJsonDocumentU는 주변 코드가 전체적으로 유니코드에서 작동하는 상황을 위해 AnsiString(UTF-8) 대신 내부적으로 UnicodeString(UTF-16)을 사용합니다

MongoDB 클라이언트 및 연결 풀링

Alcinoe의 MongoDB 드라이버는 일반적인 쿼리 작업을 다루며 연결 풀링을 기본적으로 처리합니다. 단순 클라이언트인 TAlMongoDBClient는 작업당 단일 연결을 열고 닫습니다. 풀링된 변형인 TAlMongoDBConnectionPoolClient는 라이브 연결 세트를 유지 관리하고 풀에서 호출하는 각 스레드에 하나를 전달하여 호출이 완료되면 반환합니다. 해당 모델은 여러 스레드가 연결 설정 시 서로를 차단하지 않도록 유지하며, 이는 백그라운드 작업자가 동일한 데이터베이스를 동시에 쿼리할 때 중요합니다. 캡드 컬렉션(capped collections)의 테일러블 커서(tailable cursors)의 경우, TAlMongoDBTailMonitoringThread는 새 문서를 감시하고 문서가 도착할 때 콜백을 발생시킵니다. 이는 폴링(polling) 없는 로그 스트리밍 또는 변경 알림을 위한 표준 패턴입니다

알아둘 가치가 있는 다른 컴포넌트

ALVideoPlayer는 비디오를 오버레이 창이 아닌 TTexture로 렌더링하므로 다른 FireMonkey 컨트롤이 Z-순서(Z-order)에서 그 위에 놓일 수 있습니다. Android 백엔드는 Android의 내장 MediaPlayer가 처리하는 것 이상으로 DASH, HLS 및 SmoothStreaming 지원을 추가하는 ExoPlayer를 사용합니다. iOS 백엔드는 동등한 HLS 지원과 함께 AVPlayer를 사용합니다

TALWebRTC는 P2P(peer-to-peer) 오디오 및 비디오를 위한 WebRTC 스택을 래핑합니다. 브라우저나 플러그인이 필요하지 않으며 연결은 기본 라이브러리가 처리하는 표준 ICE/STUN/TURN 협상을 통해 NAT를 통과합니다

TALStringListTStringListAnsiCompareText 기반 정렬을 로캘에 독립적인 서수 비교와 대용량 목록에서 최대 10배 더 빠른 퀵 정렬로 대체합니다. 해시 변형인 TALHashedStringList는 소규모 목록에서 오버헤드가 약간 더 높다는 비용을 감수하고 O(1) 조회를 위한 내부 해시 테이블을 추가합니다. TALStringList는 유니코드 목록이 아니라 8비트 AnsiString 목록이라는 점에 유의하세요. 이는 UTF-8이 작업 인코딩이고 원시 처리량이 로캘 인지 비교보다 더 중요한 서버 측 코드에 잘 맞습니다

64비트 Windows에서 Alcinoe의 많은 문자열 루틴에 속도 이점을 제공했던 FastCode의 유산(대부분 손으로 작성한 x86 어셈블리)은 이월되지 않습니다. Win64 빌드는 문자열 집약적 워크로드에서 눈에 띄게 느리게 실행되는 Pascal 구현으로 되돌아갑니다. demo\ALStringBenchMark 프로젝트를 사용하면 문자열 처리량이 병목 현상인 64비트 빌드를 커밋하기 전에 하드웨어의 격차를 측정할 수 있습니다

전체 소스는 github.com/Zeus64/alcinoe에 있습니다