스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Metal-cpp를 통해 C++로 Metal 프로그래밍
이제 C++ 게임과 앱에서 Metal의 강력한 기능을 활용할 수 있습니다. Metal-cpp를 통해 C++ 코드를 Metal과 연동하는 방법을 보여드리고, 각각을 통해 개체 라이프사이클을 관리하는 방법을 살펴보며, 이러한 언어가 앱에서 협력할 수 있도록 돕는 유틸리티를 시연합니다. 또한 Objective-C와 C++를 함께 원활하게 통합하는 앱 아키텍처 디자인의 모범 사례를 보여드립니다.
리소스
관련 비디오
WWDC22
-
다운로드
♪ 부드러운 힙합 음악 ♪ ♪ 안녕하세요, Keyi Yu입니다 Metal Ecosystem 팀의 엔지니어죠 오늘 여러분에게 Metal-cpp를 소개하게 되어 기쁩니다 우리는 누구나 C++을 사용해 Apple 플랫폼용 Metal 응용 프로그램을 만들 수 있게 Metal-cpp를 만들었습니다 Metal-cpp는 오버헤드가 낮은 라이브러리로 C++ 응용 프로그램을 Metal과 연결합니다 우선 Metal-cpp가 무엇이며 작동 방식은 어떤지 살펴본 다음 Objective-C 객체의 수명 주기에 대해 자세히 다루겠습니다 C++와 Objective-C는 수명 주기를 약간 다르게 다루죠 그 차이를 다루는 방법을 보여 드리겠습니다 Xcode와 Metal-cpp에는 뛰어난 유틸리티가 있어서 여러분이 앱에서 객체의 수명 주기를 관리하도록 도와줍니다 이제 Objective-C 클래스와 C++ 코드를 통합하는 방법을 보여 드리겠습니다 이제 Metal-cpp의 모습과 작동 방식을 한번 보세요 Metal은 Apple 플랫폼에서 가속화된 그래픽과 컴퓨팅을 위한 기반이 되며 앱과 게임이 GPU의 놀라운 성능을 활용할 수 있도록 지원합니다 원래 Objective-C에서 제공하는 강력한 기능과 규칙을 사용하여 설계됐습니다 하지만 코드 베이스가 C++라면 코드와 Metal의 Objective-C 코드를 연결할 수 있는 무언가가 필요할 수 있습니다 Metal-cpp를 소개합니다! 여러분의 C++ 응용 프로그램과 Objective-C 사이의 허브 역할을 합니다 응용 프로그램에 Metal-cpp가 있다면 여러분은 C++로 Metal 클래스와 함수를 사용할 수 있으며 Metal-cpp는 런타임에 Objective-C 함수를 호출하도록 지원합니다 Metal-cpp는 가벼운 Metal C++ 래퍼입니다 가볍다고 말한 이유는 인라인 함수 호출이 있는 헤더 전용 라이브러리로 구현됐기 때문입니다 C++ 호출을 Objective-C API에 일대일로 매핑하여 Metal API의 커버리지를 100% 제공합니다 이를 위해 Metal-cpp는 Foundation 및 Core Animation 프레임워크의 일부를 래핑합니다 Apache 2 라이선스에서 오픈 소스이므로 라이브러리를 수정하고 응용 프로그램에 쉽게 포함할 수 있습니다 Metal-cpp는 C를 사용하여 Objective-C 런타임에 직접 호출합니다 Objective-C 컴파일러가 Objective-C 메서드를 실행할 때 사용하는 메커니즘과 정확하게 동일합니다 따라서 이 래퍼는 오버헤드를 거의 일으키지 않습니다 Metal-cpp는 C++와 Objective-C 호출의 일대일 매핑을 구현하므로 동일한 Cocoa 메모리 관리 규칙을 따릅니다 이 내용은 나중에 더 자세히 다루겠습니다 이 일대일 매핑을 통해 모든 개발자 도구가 원활하게 작동하며 GPU 프레임 캡처와 Xcode 디버거도 포함됩니다 이들은 Metal-cpp로 삼각형을 그리는 데 필요한 일련의 호출입니다 여러분이 C++에 익숙하다면 Metal을 배우기 딱 좋습니다 언어 구문에 대해 걱정할 필요가 없으니까요 이미 Objective-C로 Metal을 사용 중이라면 함수 호출 측면에서 Metal의 Objective-C 인터페이스와 Metal-cpp 사이에는 차이가 거의 없습니다 이제 Metal-cpp 사용이 얼마나 쉬운지 보여 드리죠 우선 명령 버퍼를 만듭니다 GPU가 실행할 명령으로 채우겠습니다 C++의 원시 포인터를 Objective-C의 ID에 대한 매핑으로 사용할 수 있습니다 명령 버퍼로 렌더 명령 인코더를 만들고 렌더 명령을 작성할 수 있습니다 C++ 함수 renderCommandEncoder와 Objective-C 메서드 renderCommandEncoder WithDescriptor는 동일합니다 유일한 차이점은 언어의 이름 규칙입니다 이어서 정점과 프래그먼트 셰이더 기타 다양한 렌더링 상태를 포함하는 렌더 파이프라인 상태 객체를 설정합니다 그다음 드로우 콜을 인코딩해 단일 삼각형을 렌더링합니다 그러면 렌더링 명령 인코딩을 마쳤음을 나타냅니다 이제 드로어블을 통해 삼각형이 화면에 표시됩니다 마침내 명령 버퍼를 커밋합니다 이는 GPU에 내 명령 실행을 시작할 수 있다고 알려 주죠 보시다시피 Metal-cpp와 Objective-C Metal은 거의 동일합니다 이제 Metal-cpp를 사용하면 언어 구문에 대해 걱정할 필요 없습니다 Metal 설명서를 직접 살펴보고 Metal의 개념과 사용법을 알아볼 수 있습니다 이 디퍼드 Lighting 샘플을 이전에 이미 다룬 적이 있을지도 모릅니다 이제 Metal-cpp를 사용하는 이 디퍼드 Lightning 샘플의 새로운 버전을 제공합니다 이를 통해 여러분이 실제로 Metal-cpp로 코딩하는 방법을 배우기를 바랍니다 또한 Metal API를 소개하고 이 API로 다양한 작업을 수행하는 방법을 보여주는 일련의 증분 C++ 샘플을 여러분에게 소개하게 되어 기쁩니다
이제 Metal-cpp에 대해 조금 알아봤으니 실제로 어떻게 사용할까요? 우리는 작년에 Metal-cpp를 발표했습니다 다음은 다운로드와 지침을 찾을 수 있는 웹 페이지입니다 여러분이 취해야 할 단계를 보여 드릴게요 Metal-cpp를 다운로드한 후 어디서 찾아야 할지 Xcode에 알려 줍니다 여기서는 Metal-cpp를 현재 프로젝트에 넣었죠 이제 C++17 이상을 C++ 언어 방언으로 설정해야 합니다 그런 다음 프로젝트에 프레임워크 3가지를 추가하죠 Foundation과 Quartz Core 그리고 Metal입니다 이제 이러한 프레임워크의 C++ 인터페이스를 사용하기 전에 할 일은 딱 하나뿐입니다 Metal-cpp에는 3개의 헤더가 있습니다 Metal-cpp는 헤더 전용 라이브러리이므로 헤더 파일을 가져오기 전에 구현부터 생성해야 합니다 그러려면 매크로 3개를 정의합니다 NS_PRIVATE_IMPLEMENTATION, CA_PRIVATE_IMPLEMENTATION, AND MTL_PRIVATE_IMPLEMENTATION 만약 Metal-cpp가 매크로로 무엇을 하는지 관심이 있다면 Metal-cpp 폴더에 있는 헤더 브리지 파일을 확인하세요 헤더를 개별적으로 사용하거나 단일 헤더에 넣을 수 있습니다 필요할 때마다 헤더 파일을 가져올 수 있습니다 그러나 NS, CA 또는 MTL_PRIVATE_IMPLEMENTATION 매크로를 두 번 이상 정의하지 마세요 그러면 중복 정의 오류가 발생할 수 있습니다 Metal-cpp를 효과적으로 사용하려면 Cocoa의 메모리 관리 규칙과 객체 수명 주기 관리를 도와주는 우수한 유틸리티 사용 방법 다른 프레임워크와 인터페이스할 때 응용 프로그램 아키텍처를 설계하는 방법을 알아야 합니다 먼저 객체 수명 주기 관리부터 시작해 보죠 응용 프로그램 작업 중에는 일반적으로 메모리를 할당하고 해제해야 합니다 또한 명령 버퍼와 파이프라인 객체 리소스를 관리해야 합니다 이 메모리 관리를 돕기 위해 Objective-C와 Cocoa 객체는 참조 계수를 포함합니다 Metal-cpp에도 있습니다 참조 계수는 메모리를 관리하는 데 도움이 됩니다 참조 계수를 사용하면 모든 객체에는 retainCount 속성이 포함됩니다 앱의 구성 요소는 계수를 증가시켜 상호 작용 중인 객체를 활성 상태로 유지하고 객체가 완료되면 객체를 감소시킵니다 retainCount가 0에 도달하면 런타임은 객체의 할당을 해제합니다 Objective-C에는 2가지 유형의 참조 계수가 있습니다 하나는 Manual Retain Release를 뜻하는 MRR이고 또 하나는 Automatic Reference Counting을 뜻하는 ARC입니다 ARC 기능으로 코드를 컴파일할 때 컴파일러는 여러분이 만든 참조를 가져와서 기본 메모리 관리 메커니즘에 호출을 자동으로 삽입합니다 Metal-cpp 객체는 수동으로 유지 및 해제됩니다 따라서 Cocoa의 규칙을 이해해야만 언제 객체를 유지하고 해제해야 할지 알 수 있죠 C++에서 객체를 만들 때와 달리 Metal-cpp 객체는 새로 생성되거나 삭제로 파괴되지 않습니다 Cocoa 규칙에 따라 alloc, new, copy mutableCopy 또는 create로 시작하는 메서드를 사용하여 만드는 모든 객체를 소유합니다 유지를 사용하여 객체의 소유권을 가져올 수 있죠 더 이상 필요하지 않으면 소유한 객체의 소유권을 포기해야 합니다 즉시 해제하거나 나중에 해제할 수 있습니다 소유하지 않은 객체에 대한 소유권을 포기해선 안 됩니다 더블 프리의 위험이 있기 때문입니다 다음으로 이러한 Cocoa 규칙의 예를 살펴보겠습니다 클래스 A에서 메서드는 할당을 사용하여 객체를 만들고 init을 사용하여 이 객체를 초기화합니다 객체에 init을 두 번 호출하지 마세요 클래스 A가 소유권을 가져가고 객체의 할당 해제를 책임집니다 이제 이 객체의 유지 계수는 1입니다 다음으로 클래스 B는 retain을 사용해 객체를 가져오고 이 객체의 소유권을 가져옵니다 지금까지 저는 주황색 입방체로 대표되는 이 객체의 소유권을 공유하는 두 개의 객체를 갖고 있습니다 유지 계수가 1 증가합니다
클래스 A는 이 객체가 더 이상 필요하지 않아서 수동으로 이 객체의 해제를 호출해야 합니다 결과적으로 유지 계수가 1 감소합니다 이제 클래스 B만 객체를 소유합니다 자, 마지막으로 클래스 B도 이 객체를 해제하기를 원합니다 이제 유지 계수가 0이므로 런타임이 객체를 풀어줍니다 여기 클래스 B의 메서드가 객체를 반환하는 상황이 있습니다 나머지 프로그램에서는 여전히 이 객체가 필요하죠 다시 말해 클래스 B의 메서드에 있는 객체의 소유권은 포기하지만 즉시 할당을 해제하기를 원하지는 않습니다 이 경우 클래스 B에서 자동 해제를 호출해야 합니다 유지 계수는 자동 해제를 호출한 후에도 여전히 1이고 따라서 나중에 객체를 계속 사용할 수 있죠 질문이 있습니다 클래스 B가 더 이상 이 객체를 소유하지 않으면 객체의 할당 해제는 누가 책임질까요? Foundation 프레임워크는 AutoreleasePool이라는 중요한 객체를 제공합니다 자동 해제 API는 객체를 AutoreleasePool에 넣습니다 이제 AutoreleasePool이 객체의 소유권을 가집니다 AutoreleasePool은 파괴될 때 수신기의 유지 계수를 감소시킵니다 여러분만 자동 해제 객체를 만들 수 있는 건 아닙니다 Metal은 작업의 일부로 여러 개의 자동 해제 객체를 생성합니다 임시 객체를 만드는 모든 메서드는 내부에서 자동 해제를 호출하여 해당 객체를 AutoreleasePool에 추가합니다 이 객체들을 해제하는 건 AutoreleasePool의 책임입니다 다시 말해 AutoreleasePool을 사용하면 보다 우아한 방식으로 코딩할 수 있습니다 기본 응용 프로그램에서도 AutoreleasePool을 가질 수 있죠 프로그램의 작업 세트를 줄이기 위해 더 작은 범위에서 추가 AutoreleasePools을 만들고 관리하는 편이 좋습니다 또한 생성하는 모든 스레드에 AutoreleasePool이 필요합니다 다음은 AutoreleasePool과 자동 해제 객체를 사용하는 방법을 보여 주는 예입니다 이 예제에서는 할당을 통해 AutoreleasePool이 생성됐죠 즉, 여러분이 소유권을 가지며 해제는 수동으로 해야 합니다 이제 AutoreleasePool이 있습니다 처음에 얘기했듯이 명령 버퍼를 만들어야 합니다 Alloc 또는 create로 만들어지지 않아서 여러분이 소유하지 않습니다 대신 Metal이 만든 자동 해제 객체입니다 이 명령 버퍼는 AutoreleasePool에 배치되며 이 버퍼를 할당 해제하는 건 AutoreleasePool의 책임입니다 AutoreleasePool을 해제할 때까지는 마음껏 사용할 수 있습니다 이제 RenderPassDescriptor를 생성해야 합니다 이 RenderPassDescriptor도 AutoreleasePool에 배치됩니다 RenderCommandEncoder도 똑같죠 마찬가지로 Metal이 만든 자동 해제 객체입니다 이 currentDrawable 객체도 잊지 마세요 똑같이 AutoreleasePool로 들어갑니다 코드 끝에서 pPool->release를 사용하여 AutoreleasePool을 해제합니다 AutoreleasePool은 할당 해제되기 전에 소유한 모든 것을 해제합니다 이 경우 명령 버퍼와 RenderPassDescriptor RenderPassDescriptor, RenderCommandEncoder, currentDrawable를 해제합니다 이제 AutoreleasePool이 해제됐습니다 지금까지 Cocoa의 규칙 자동 해제된 객체 AutoreleasePools에 대해 배웠습니다 메모리 누수와 좀비 객체를 방지하려면 객체 수명 주기를 올바르게 관리하는 것이 중요합니다 우리는 이러한 문제를 방지하고 디버깅할 수 있는 훌륭한 도구를 제공합니다 두 가지 유틸리티를 주로 다룹니다 NS:SharedPtr와 NSZombie로 NS:SharedPtr은 객체 수명 주기를 관리하는 데 도움이 되는 새로운 유틸리티입니다 Metal-cpp 폴더의 Foundation 프레임워크에서 찾을 수 있습니다 보시다시피 이 값은 std:shared_ptr과 정확히 동일하지 않습니다 따라서 C++ 표준 라이브러리에 의존하지 않으며 참조 계수를 저장하는 데 추가 비용이 들지 않습니다 NS::SharedPtr을 한번 살펴보겠습니다 이전 및 유지 함수는 객체를 소비하려는 의도를 명확하게 나타냅니다 이전은 referenceCount의 포인티를 늘리지 않고 SharedPtr을 생성하여 소유권을 SharedPtr로 효과적으로 이전합니다 유지 함수는 전달된 객체에 유지를 전송합니다 이 함수를 사용하여 AutoreleasePool에 있는 객체를 활성 상태로 유지하고 포인터의 소유자가 포인티의 수명 주기에 대한 기득권을 가지고 있음을 나타냅니다 get 및 operator->를 통해 예상대로 기본 객체에 액세스할 수 있습니다 SharedPtr 복사, 이동 구성, 할당 작업은 예상대로 수행되며 복사는 retainCount를 증가시킵니다 이동은 빠르고 일반적인 경우 유지 계수에 영향을 주지 않습니다 SharedPtr은 항상 정확히 하나의 해제를 파괴의 포인티로 전송합니다 원한다면 분리 함수를 호출하여 이 상황을 방지할 수 있습니다 맨 위로 돌아가면 포인터를 이전하거나 유지하여 포인터를 만드는 것의 차이점을 아는 것이 중요합니다 따라서 TransferPtr의 경우 참조 계수가 1인 MRR 객체가 있다고 가정합니다 TransferPtr 함수에 이 객체를 전달하면 SharedPtr이 객체의 소유권을 가지지만 retainCount는 변경되지 않습니다 포인터가 범위를 벗어나면 SharedPtr의 소멸자가 실행되어 MRR 객체에서 해제를 호출하여 retainCount를 0으로 줄입니다 또 다른 함수는 NS::RetainPtr입니다 나중에 객체를 사용할 예정이어서 객체의 할당 해제를 방지하려면 NS::RetainPtr을 사용해야 합니다 이 MRR 객체가 있다고 가정하고 retainCount는 1입니다 RetainPtr 함수에 이 객체를 전달하면 retainCount가 1씩 증가합니다 범위를 벗어난 후 이 RetainPtr은 이 MRR 객체에 대한 해제를 호출합니다 retainCount는 1입니다 일반적으로 NS::TransferPtr은 여러분 대신 객체의 소유권을 가집니다 그러나 NS::RetainPtr을 사용하면 즉시 할당이 해제되기를 원하지 않을 때 객체를 유지할 수 있습니다 객체를 이 두 함수에 전달할 때 NS::TransferPtr은 참조 계수를 변경하지 않지만 NS::RetainPtr은 내부에서 여러분을 위해 유지를 호출하므로 참조 계수가 1씩 증가합니다 이 두 함수의 소멸자는 모두 전달된 객체에 대한 해제를 호출하므로 참조 계수는 1씩 감소합니다 참조 계수가 0에 도달하면 객체는 런타임에서 풀려납니다 다음은 NS::TransferPtr의 예입니다 단일 삼각형을 그리는 렌더 패스에 대해 얘기할 때 이 렌더 파이프라인 상태가 필요했습니다 다음은 렌더 파이프라인 상태 객체를 만들기 위한 호출입니다 렌더 파이프라인 기술자에 필요한 속성입니다 Cocoa의 규칙에 따르면 이 호출은 new와 alloc으로 시작하므로 제가 이 객체를 소유합니다 그래서 이 객체에 대한 해제를 호출해야 합니다 NS::SharedPtr를 사용하면 이 MRR 객체에 대해 해제를 호출할 필요가 없습니다 NS::SharedPtr가 이 객체의 소유권을 가지기 때문이죠 그래서 여기서 TransferPtr 함수에 원시 포인터를 전달합니다 그러면 이전 슬라이드에서 했던 것처럼 해제를 호출할 필요가 없죠 ARC에 익숙하시다면 NS::SharedPtr와 함께 사용되는 MRR이 ARC와 유사하다는 걸 아실 겁니다 메모리를 수동으로 처리할 때 use-after-free 버그가 발생할 수 있습니다 이 오류는 이미 해제된 객체를 사용하려고 할 때 발생합니다 NSZombie는 이러한 버그를 확인하는 좋은 방법으로 Use-after-free 버그가 발생할 때 중단점을 트리거하고 스택 추적을 제공합니다 환경 변수를 사용하여 좀비를 매우 쉽게 활성화할 수 있습니다 NSZombieEnabled를 ‘예’로 설정하세요 또는 Xcode를 사용하는 경우 스킴에서 좀비를 활성화할 수 있습니다 작동 방식을 보여 드리죠 동일한 렌더 파이프라인 설정을 사용하여 새 렌더 파이프라인 상태 객체를 만들려고 합니다 이제 이 새로운 RenderPipelineState 함수에서 pDesc 객체를 재사용합니다
실행을 클릭하면 Xcode가 중단점을 트리거하고 스택 추적을 표시합니다 제가 뭔가 잘못했다는 뜻이에요 뭐가 문제일까요? NSZombie가 도움이 될 수 있으니 스킴에서 NSZombie를 활성화하죠
프로그램을 다시 실행하면 NSZombie가 중단점을 트리거해요 콘솔 출력에 새로운 내용이 표시됩니다 ‘메시지가 할당 해제된 인스턴스로 전송되었습니다’ 이미 해제한 객체를 제가 다시 사용했군요 이게 렌더 파이프라인 기술자예요 해제를 호출하기 전에 이 렌더 파이프라인 상태를 사용해야 합니다 이렇게 해서 문제를 해결하죠 더 많은 도구와 자세한 내용을 올해의 강연 ’게임 메모리 프로파일링 및 최적화’에서 다룹니다 예를 들어 기구의 할당에서 retainCount를 추적하는 방법을 배울 수 있습니다 Apple 플랫폼에서 다른 도구를 마음껏 확인해 보세요 게임을 디버깅하고 성능을 향상시키는 데 도움이 될 겁니다 Metal-cpp에서 객체 수명 주기를 관리하는 방법을 배웠습니다 하지만 게임 컨트롤러나 오디오 같은 다른 프레임워크와 인터페이스해야 할 수도 있죠 이들은 여전히 Objective-C에 있어요 어떻게 하면 이러한 API와 인터페이스하면서 우아한 응용 프로그램 아키텍처를 설계할 수 있을까요? 예를 들어 Objective-C에 ViewController를 작성했는데 Metal-cpp를 사용해서 C++로 렌더러를 작성했다면 ViewController에서 드로우 같은 렌더러 메서드를 호출해야 합니다 여기서 어려운 점은 두 언어를 잘 분리하되 함께 작동하게 하는 거죠 해결책은 Objective-C 파일에서 C++를 호출하는 어댑터 클래스를 만드는 겁니다 이렇게 하면 함수를 구현하는 파일의 Objective-C 또는 C++에 집중할 수 있죠 예를 들어 Objective-C에서 RendererAdapter 클래스를 만들 수 있습니다 구현 아래에 Objective-C 메서드를 추가하여 ViewController에서 직접 호출할 수 있습니다 인터페이스 내부에서 렌더러 객체에 C++ 포인터를 선언합니다 메서드의 본문에서는 렌더러의 C++ 메서드를 직접 호출합니다 이 메서드는 MTK:View를 C++ 객체로 드로우 메서드에 전달해야 하므로 __Bridge 키워드를 사용해 뷰를 C++ 유형으로 캐스팅합니다 이 캐스팅은 나중에 더 자세히 다루죠 반대로 우리는 C++로 작성된 렌더러에서 Objective-C로 작성된 MTKView를 호출해야 합니다 이것도 어렵죠 마찬가지로 해결책은 어댑터 클래스를 만드는 겁니다 이 클래스를 사용하여 C++ 파일에서 C++ 인터페이스를 사용하여 Objective-C 메서드를 호출할 수 있죠 예를 들어 ViewAdapter 클래스를 만들 수 있어요 인터페이스를 C++로 작성하니까 렌더러 클래스에서 C++ 뷰 메서드를 쉽게 호출할 수 있죠 구현 중에 MTKView에서 currentDrawable과 depthStencilTexture를 포함해 Objective-C 메서드를 호출합니다 여기에 __bridge 키워드가 몇 개 있습니다 Metal-cpp 객체와 Objective-C 객체 사이에 캐스팅하는 데 사용합니다 처음에 학습했듯이 Metal-cpp 객체는 수동으로 유지 및 해제되지만 Objective-C에 의해 생성된 객체는 자동 참조 계수를 사용합니다 MRR에서 ARC로 또 ARC에서 MRR로 객체를 이동해야 합니다 다음은 Objective-C와 C++ 사이에서 캐스팅하는 데 도움이 되는 세 가지 유형의 브리지 캐스팅입니다 또한 Objective-C와 Metal-cpp 객체 간에 _bridge casting 캐스팅의 소유권을 이전하도록 지원할 수 있습니다 이들 사이에는 소유권의 이전이 없습니다 __bridge_retained 캐스팅은 Objective-C 포인터를 Metal-cpp 포인터에 캐스팅하고 ARC로부터 소유권을 가져옵니다 __Bridge_transfer 캐스팅은 Metal-cpp 포인터를 Objective-C로 이동하고 소유권을 ARC로 이전합니다 문제로 돌아가면 우리는 Metal-cpp 객체와 Objective-C 객체 사이에 캐스팅을 해야 합니다 소유권 이전이 없는 경우 __bridge cast를 사용할 수 있습니다 Metal-cpp에서 Objective-C 객체로 캐스팅하고 소유권을 Objective-C로 이전하려면 __bridge_transfer 캐스팅을 사용해야 합니다 Objective-C에서 Metal-cpp 객체로 캐스팅하고 ARC에서 소유권을 가져오려면 __bridge_retained 캐스팅을 사용해야 합니다 자산 로딩 코드를 활용하기 위해 MetalKit을 사용해야 하는 경우가 있습니다 즉, 내 C++ 응용 프로그램에서 Metal-cpp 객체로서 텍스처가 필요하지만 이는 Objective-C 메서드에 의해 생성됩니다 수동으로 해제할 수 있도록 ARC에서 소유권을 이전할 수 있는 기능이 필요합니다 이 경우에는 __bridge_retained 캐스팅을 선택해야 합니다 카탈로그에서 텍스처를 로드하는 C++ 함수가 있는데 Metal-CPP 텍스처를 반환하려고 합니다 하지만 안에서 저는 MetalKit의 Objective-C 함수를 호출하고 있습니다 텍스처 로더에 필요한 옵션을 정의해야 합니다 그런 다음 MetalKit에서 Objective-C 메서드를 호출하여 텍스처 로더를 만듭니다 이 로더를 사용하여 텍스처 객체를 만들고 카탈로그에서 텍스처를 로드할 수 있습니다 이 방법은 MetalKit의 Objective-C 메서드이기도 합니다 이제 Objective-C 유형 텍스처가 생겼으니 Metal-cpp 객체에 캐스팅해서 ARC에서 꺼내야 합니다 이 단계들을 염두에 두고 이제 코딩해 보죠 캐스팅이 실제로 작동하는 방식을 보여 드리겠습니다 1단계는 텍스처 로더에 필요한 텍스처 로더 옵션을 정의하는 겁니다 Metal-cpp 유형은 동일한 값으로 정의하므로 metal-cpp 저장 모드와 사용법을 Objective-C 유형에 안전하게 캐스팅할 수 있습니다 여기서 텍스처 로더를 만듭니다 지금 저는 Metal-CPP 객체인 기기를 가지고 있고 initWithDevice 메서드에 전달해야 합니다 Metal-cpp 객체는 Objective-C 객체이므로 무료 객체처럼 캐스팅할 수 있죠 소유권 이전은 없습니다 이제 텍스처 로더 옵션과 텍스처 로더를 사용하여 텍스처를 만듭니다 로드된 텍스처를 Metal-CPP 객체로 반환하려고 합니다 따라서 ARC에서 꺼내서 해당 포인터 유형에 캐스팅해야 합니다 이 작업은 __bridge_retained 캐스팅으로 수행됩니다 앞으로는 이 텍스처를 어떤 Metal-cpp 객체로도 사용할 수 있습니다 해제는 제가 책임집니다 이 섹션에서는 여러분 프로그램에서 두 가지 언어를 처리하는 데 도움이 되는 어댑터 패턴을 제공했습니다 또한 Objective-C 및 C++와 세 가지 유형의 캐스팅으로 인터페이스하는 방법도 보여 줬죠 요약하자면 metal-cpp는 가볍고 매우 효율적인 Metal C++ 래퍼입니다 Metal-cpp를 사용할 때 객체 수명 주기를 관리하는 방법 우아한 방식으로 Objective-C와 인터페이스하는 방법 우리 개발자 도구가 디버깅을 돕는 방법에 대해 말씀드렸죠 지금 Metal-cpp를 다운로드하고 모든 놀라운 샘플을 누려 보세요! Metal로 무엇을 만들 수 있는지 확인해 보세요 여러분의 C++ 응용 프로그램이 모든 Apple 플랫폼에서 실행되기를 기대합니다 시청해 주셔서 감사합니다! ♪
-
-
3:10 - Draw a single triangle in C++
MTL::CommandBuffer* pCmd = _pCommandQueue->commandBuffer(); MTL::RenderCommandEncoder* pEnc = pCmd->renderCommandEncoder( pRpd ); pEnc->setRenderPipelineState( _pPSO ); pEnc->drawPrimitives( MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3)); pEnc->endEncoding(); pCmd->presentDrawable( pView->currentDrawable() ); pCmd->commit();
-
3:27 - Draw a single triangle in Objective-C
id<MTLCommandBuffer> cmd = [_commandQueue commandBuffer]; id<MTLRenderCommandEncoder> enc = [cmd renderCommandEncoderWithDescriptor:pRpd]; [enc setRenderPipelineState:_pPSO]; [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; [enc endEncoding]; [cmd presentDrawable:view.currentDrawable]; [cmd commit];
-
6:10 - Generate the implementation
#define NS_PRIVATE_IMPLEMENTATION #define CA_PRIVATE_IMPLEMENTATION #define MTL_PRIVATE_IMPLEMENTATION #include <Foundation/Foundation.hpp> #include <Metal/Metal.hpp> #include <QuartzCore/QuartzCore.hpp>
-
11:46 - How to use autoreleased objects and AutoreleasePool
NS::AutoreleasePool* pPool = NS::AutoreleasePool::alloc()->init(); MTL::CommandBuffer* pCmd = _pCommandQueue->commandBuffer(); MTL::RenderPassDescriptor* pRpd = pView->currentRenderPassDescriptor(); MTL::RenderCommandEncoder* pEnc = pCmd->renderCommandEncoder( pRpd ); pEnc->endEncoding(); pCmd->presentDrawable( pView->currentDrawable() ); pCmd->commit(); pPool->release();
-
11:47 - How NS::TransferPtr works
{ auto ptr = NS::TransferPtr( pMRR ); // Do something with ptr . . . }
-
17:19 - How NS::RetainPtr works
{ auto ptr = NS::RetainPtr( pMRR ); // Do something with ptr . . . }
-
20:43 - Create an adapter class calling C++ from Objective-C files
@interface AAPLRendererAdapter () { AAPLRenderer* _pRenderer; } @end @implementation AAPLRendererAdapter - (void)drawInMTKView:(MTKView *)pMtkView { _pRenderer->draw((__bridge MTK::View*)pMtkView); } @end
-
21:49 - Create an adapter class calling Objective-C from C++ files
CA::MetalDrawable* AAPLViewAdapter::currentDrawable() const { return (__bridge CA::MetalDrawable*)[(__bridge MTKView *)m_pMTKView currentDrawable]; } MTL::Texture* AAPLViewAdapter::depthStencilTexture() const { return (__bridge MTL::Texture*)[(__bridge MTKView *)m_pMTKView depthStencilTexture]; }
-
24:59 - Cast between Objective-C and C++ objects and transfer ownership
MTL::Texture* newTextureFromCatalog( MTL::Device* pDevice, const char* name, MTL::StorageMode storageMode, MTL::TextureUsage usage ) { NSDictionary<MTKTextureLoaderOption, id>* options = @{ MTKTextureLoaderOptionTextureStorageMode : @( (MTLStorageMode)storageMode ), MTKTextureLoaderOptionTextureUsage : @( (MTLTextureUsage)usage ) }; MTKTextureLoader* textureLoader = [[MTKTextureLoader alloc] initWithDevice:(__bridge id<MTLDevice>)pDevice]; NSError* __autoreleasing err = nil; id< MTLTexture > texture = [textureLoader newTextureWithName:[NSString stringWithUTF8String:name] scaleFactor:1 bundle:nil options:options error:&err]; return (__bridge_retained MTL::Texture*)texture; }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.