Nội dung trên trang web này đã được dịch bằng trí tuệ nhân tạo (AI) hoặc công nghệ dịch máy và có thể có lỗi.

Skip to content

3 Năm Âm nhạc Kim loại

Ba năm trước, chúng tôi đã chuyển đổi trình hiển thị của mình sang Metal. Quá trình này không mất nhiều thời gian, rất thú vị và hoạt động rất tốt trên iOS. Vì vậy, chúng tôi đã viết một bài báo trình bày về cách chúng tôi đưa ra quyết định và kết quả cuối cùng (tiết lộ trước: rất tốt!). Phần lớn nội dung hồi tưởng ban đầu đó vẫn còn phù hợp, nhưng hiện nay Metal đang ở trạng thái tốt hơn bao giờ hết – vì vậy, chúng tôi đã quyết định xuất bản lại bài báo này kèm theo bản cập nhật sau ba năm.

Vì vậy, hãy quay ngược thời gian, giả sử rằng đang là tháng 12 năm 2016 và chúng tôi vừa phát hành một phiên bản trình kết xuất Metal trên iOS.

Tại sao lại là Metal?

Khi Apple công bố Metal tại WWDC năm 2014, phản ứng ban đầu của tôi là bỏ qua nó. Nó chỉ có sẵn trên phần cứng mới nhất mà phần lớn người dùng của chúng tôi không sở hữu, và mặc dù Apple cho biết nó giải quyết các vấn đề về hiệu suất CPU, việc tối ưu hóa cho thị trường nhỏ nhất sẽ khiến khoảng cách giữa các thiết bị nhanh nhất và chậm nhất ngày càng gia tăng. Lúc đó, chúng tôi chỉ chạy OpenGL ES 2 trên Apple và cũng đang bắt đầu port sang Android.

Hai năm rưỡi sau, đây là thị phần của Metal đối với người dùng của chúng tôi:

Điều này hấp dẫn hơn nhiều so với trước đây. Việc triển khai Metal vẫn không giúp ích gì cho các thiết bị cũ nhất, nhưng thị trường GL trên iOS đang ngày càng thu hẹp, và nội dung mà chúng tôi chạy trên các thiết bị cũ này thường khác với nội dung chạy trên các thiết bị mới nhất, vì vậy việc dành một chút nỗ lực để làm cho nó nhanh hơn là điều hợp lý. Vì mã Metal iOS của bạn sẽ chạy trên Mac với rất ít thay đổi, nên việc sử dụng nó trên Mac cũng có ý nghĩa ngay cả khi bạn tập trung vào thiết bị di động (hiện tại chúng tôi chỉ cung cấp các bản dựng Metal trên iOS).

Tôi nghĩ việc phân tích thị phần chi tiết hơn là đáng giá. Trên iOS, chúng tôi hỗ trợ Metal cho iOS 8.3 trở lên; mặc dù có một số người dùng không thể chạy Metal do hạn chế phiên bản hệ điều hành, nhưng phần lớn 25% người dùng vẫn chạy GL chỉ đơn giản là đang sử dụng các thiết bị cũ có phần cứng SGX. Họ cũng không có bất kỳ tính năng OpenGL ES 3 nào, và chúng tôi hài lòng với việc chạy một đường dẫn hiển thị cấp thấp hơn ở đó (mặc dù chúng tôi rất muốn tất cả các thiết bị đều chuyển sang Metal - may mắn thay, sự phân chia GL/Metal sẽ chỉ ngày càng cải thiện). Trên Mac, API Metal mới hơn và hệ điều hành đóng vai trò khá quan trọng - bạn phải sử dụng OS X 10.11 trở lên để dùng Metal, và một nửa người dùng của chúng tôi đơn giản là đang dùng hệ điều hành cũ hơn - vấn đề chủ yếu nằm ở phần mềm chứ không phải phần cứng (95% người dùng Mac của chúng tôi chạy OpenGL 3.2 trở lên).

Vì vậy, xét về thị phần, chúng tôi vẫn có các lựa chọn không cần chuyển sang Metal. Một trong số đó là sử dụng MoltenGL, vốn sẽ tận dụng mã OpenGL hiện có nhưng được cho là nhanh hơn; lựa chọn khác là chuyển sang Vulkan (để cải thiện hiệu năng trên PC và sau này là Android) và sử dụng MoltenVK. Tôi đã đánh giá sơ bộ MoltenGL và không thực sự hài lòng với kết quả - phải tốn khá nhiều công sức để làm cho mã nguồn của chúng tôi chạy được, và mặc dù hiệu suất tốt hơn một chút so với OpenGL tiêu chuẩn, tôi vẫn mong đợi nhiều hơn. Về MoltenVK, tôi cho rằng việc cố gắng triển khai một API cấp thấp như một lớp trên một API khác là sai lầm - bạn sẽ gặp phải sự không tương thích về mức độ trừu tượng, dẫn đến hiệu suất không tối ưu - có thể nó sẽ tốt hơn so với API cấp cao mà bạn từng sử dụng, nhưng khó có thể đạt được tốc độ tối đa, điều mà lẽ ra là lý do bạn chọn API cấp thấp ngay từ đầu! Một khía cạnh quan trọng khác là việc triển khai Metal đơn giản hơn nhiều so với Vulkan - sẽ nói thêm về điều này sau - vì vậy theo một nghĩa nào đó, tôi sẽ ưa chuộng một lớp bọc Metal -> Vulkan hơn là Vulkan -> Metal.

Cũng cần lưu ý rằng rõ ràng trên iOS 10 trên các iPhone mới nhất không có trình điều khiển GL - GL được triển khai trên nền tảng Metal. Điều này có nghĩa là việc sử dụng OpenGL thực sự chỉ giúp bạn tiết kiệm một chút công sức phát triển - không nhiều lắm, vì lời hứa “viết một lần, chạy mọi nơi” của OpenGL không thực sự hiệu quả trên thiết bị di động.

Chuyển đổi

Nhìn chung, việc chuyển đổi sang Metal diễn ra rất suôn sẻ. Chúng tôi có nhiều kinh nghiệm làm việc với các API đồ họa khác nhau, từ các API cấp cao như Direct3D 9/11 đến các API cấp thấp như PS4 GNM. Điều này mang lại lợi thế độc đáo là có thể sử dụng thoải mái một API như Metal, vốn vừa có mức độ trừu tượng hợp lý nhưng vẫn để lại một số tác vụ như đồng bộ hóa CPU-GPU cho nhà phát triển ứng dụng thực hiện.

Rào cản duy nhất thực sự là việc biên dịch các shader - một khi việc đó hoàn tất và đến lúc viết mã, rõ ràng API này đơn giản và dễ hiểu đến mức mã gần như tự viết ra. Tôi đã làm cho phiên bản port hiển thị hầu hết các thành phần một cách chưa tối ưu chạy được trong khoảng 10 giờ trong một ngày, và dành thêm hai tuần để dọn dẹp mã nguồn, sửa các vấn đề xác thực, phân tích hiệu suất và tối ưu hóa, cũng như hoàn thiện chung. Việc triển khai API trong khung thời gian này nói lên rất nhiều về chất lượng của API và bộ công cụ. Tôi tin rằng có một số yếu tố góp phần:

  • Bạn có thể phát triển mã theo từng bước, với phản hồi tốt ở mọi giai đoạn. Mã của chúng tôi ban đầu bỏ qua toàn bộ đồng bộ hóa CPU-GPU, xử lý một số phần thiết lập trạng thái một cách không tối ưu, sử dụng theo dõi tham chiếu tích hợp cho tài nguyên và không bao giờ chạy CPU và GPU song song để tránh gặp sự cố; giai đoạn tối ưu hóa/hoàn thiện sau đó đã chuyển đổi điều này thành một sản phẩm có thể phát hành, mà không bao giờ mất khả năng hiển thị trong quá trình đó.
  • Các công cụ đã sẵn sàng cho bạn, chúng hoạt động và hoạt động tốt. Điều này không quá bất ngờ đối với những người quen với Direct3D 11 - nhưng đây là lần đầu tiên trên nền tảng di động mà tôi có trình phân tích hiệu suất CPU, trình phân tích hiệu suất GPU, trình gỡ lỗi GPU và lớp xác thực API GPU, tất cả đều hoạt động ăn ý với nhau, phát hiện hầu hết các vấn đề trong quá trình phát triển và hỗ trợ tối ưu hóa mã nguồn.
  • Mặc dù API này ở mức độ thấp hơn so với Direct3D 11 và để lại một số quyết định cấp thấp quan trọng cho nhà phát triển (như cấu hình pass render hoặc đồng bộ hóa), nó vẫn sử dụng mô hình tài nguyên truyền thống, trong đó mỗi tài nguyên được tạo ra với các "cờ sử dụng" nhất định nhưng không yêu cầu rào cản pipeline hay chuyển đổi bố cục, cùng với mô hình gán truyền thống, nơi mỗi giai đoạn shader có nhiều khe cắm mà bạn có thể gán tài nguyên một cách tự do. Cả hai mô hình này đều quen thuộc, dễ hiểu và chỉ cần một lượng mã rất hạn chế để bắt đầu nhanh chóng.

Một điều khác cũng giúp ích là giao diện API của chúng tôi đã sẵn sàng cho các API giống như Metal - nó rất gọn gàng nhưng lại cung cấp đủ chi tiết (chẳng hạn như các lần hiển thị) để có thể dễ dàng viết ra một bản triển khai hiệu suất cao. Trong suốt quá trình triển khai, tôi không cần phải lưu/khôi phục trạng thái (nhiều giao diện API gặp vấn đề này, đặc biệt do coi việc thiết lập mục tiêu render là thay đổi trạng thái và việc gán tài nguyên/trạng thái duy trì qua các lần đó) hoặc đưa ra các quyết định phức tạp về vòng đời tài nguyên/đồng bộ hóa. Phần mã “phức tạp” duy nhất cần thiết để hiển thị là phần tạo trạng thái đường ống hiển thị bằng cách băm các bit cần thiết để tạo ra nó - các đối tượng trạng thái đường ống không phải là một phần của trừu tượng hóa API của chúng tôi. Ngay cả điều đó cũng khá đơn giản và nhanh chóng. Tôi sẽ viết thêm về giao diện API của chúng tôi trong một bài đăng riêng.

Vậy, một tuần để biên dịch các shader, hai tuần để có được một bản triển khai được tối ưu hóa và hoàn thiện1 - kết quả ra sao? Kết quả rất tuyệt vời - Metal hoàn toàn đáp ứng được lời hứa về hiệu suất. Thứ nhất, hiệu suất phân phối luồng đơn rõ ràng tốt hơn so với OpenGL (giảm 2-3 lần phần phân phối vẽ của khung hình hiển thị tùy thuộc vào khối lượng công việc), và điều này là do triển khai OpenGL của chúng tôi đã được điều chỉnh khá tốt về mặt giảm thiết lập trạng thái dư thừa và hoạt động tốt với trình điều khiển bằng cách sử dụng các đường dẫn nhanh. Nhưng điều đó không dừng lại ở đó - việc sử dụng đa luồng trong Metal rất đơn giản miễn là mã hiển thị của bạn đã sẵn sàng cho việc đó. Chúng tôi chưa chuyển sang phân phối vẽ đa luồng nhưng đã bắt đầu chuyển đổi một số phần khác chuẩn bị tài nguyên để thực hiện ngoài luồng render, điều này, khác với OpenGL, gần như không tốn công sức.

Ngoài ra, Metal cho phép chúng tôi khắc phục một số vấn đề hiệu suất khác bằng cách cung cấp các công cụ dễ tiếp cận và đáng tin cậy. Một trong những phần trung tâm của mã render của chúng tôi là hệ thống tính toán dữ liệu ánh sáng trên CPU trong không gian thế giới và tải nó lên các vùng của một texture 3D (điều mà chúng tôi phải mô phỏng trên phần cứng OpenGL ES 2). Các bản cập nhật là từng phần nên chúng tôi không thể sao chép toàn bộ texture và phải dựa vào cách trình điều khiển triển khai glTexSubImage3D. Tại một thời điểm, chúng tôi đã thử sử dụng PBO để cải thiện hiệu suất cập nhật nhưng gặp phải các vấn đề ổn định nghiêm trọng trên cả Android và iOS. Trên Metal, có hai cách tích hợp sẵn để tải lên một vùng - MTLTexture.replaceRegion mà bạn có thể sử dụng nếu GPU hiện không đang đọc kết cấu, hoặc MTLBlitCommandEncoder (copyFromBufferToTexture hoặc copyFromTextureToTexture) có thể tải lên vùng đó một cách không đồng bộ, vừa kịp lúc để GPU bắt đầu sử dụng kết cấu.

Cả hai phương pháp này đều chậm hơn tôi mong muốn - phương pháp đầu tiên thực sự không khả thi vì chúng tôi phải hỗ trợ cập nhật từng phần hiệu quả, và nó chỉ hoạt động trên CPU bằng cách sử dụng một cơ chế dịch địa chỉ trông có vẻ rất chậm. Phương pháp thứ hai hoạt động được nhưng dường như sử dụng một loạt các thao tác sao chép 2D để điền vào texture 3D, điều này không chỉ tốn kém khi thiết lập lệnh trên CPU mà còn gây ra chi phí GPU rất cao vì lý do nào đó. Nếu đây là OpenGL thì mọi chuyện đã kết thúc - trên thực tế, hiệu suất của hai phương pháp này gần như tương đương với chi phí quan sát được của một cập nhật tương tự trong OpenGL. May mắn thay, vì đây là Metal, nên có thể dễ dàng truy cập vào các bộ tạo bóng tính toán - và một bộ tạo bóng tính toán siêu đơn giản đã cho chúng tôi khả năng thực hiện tải lên từ bộ đệm -> kết cấu 3D rất nhanh trên CPU và GPU, và về cơ bản đã giải quyết triệt để các vấn đề về hiệu suất trong phần mã này2:

Như một nhận xét chung cuối cùng, việc duy trì mã Metal cũng khá dễ dàng - tất cả các tính năng bổ sung mà chúng tôi phải thêm vào cho đến nay đều dễ dàng hơn so với bất kỳ API nào khác mà chúng tôi hỗ trợ, và tôi kỳ vọng xu hướng này sẽ tiếp tục. Có một chút lo ngại rằng việc thêm một API nữa sẽ đòi hỏi phải bảo trì liên tục, nhưng so với OpenGL thì việc này thực sự không đòi hỏi nhiều công sức; trên thực tế, vì chúng tôi sẽ không phải hỗ trợ OpenGL ES 3 trên iOS nữa, điều này có nghĩa là chúng tôi cũng có thể đơn giản hóa một số mã OpenGL mà chúng tôi đang có.

Tính ổn định

Hiện tại trên iOS, Metal hoạt động rất ổn định. Tôi không chắc tình hình lúc ra mắt vào năm 2014 như thế nào, hay tình hình trên Mac hiện nay ra sao, nhưng cả trình điều khiển lẫn công cụ cho iOS đều khá vững chắc.

Chúng tôi đã gặp một vấn đề về trình điều khiển trên iOS 10 liên quan đến việc tải các shader được biên dịch bằng Xcode 7 (chúng tôi đã khắc phục bằng cách chuyển sang Xcode 8), và một lỗi treo trình điều khiển trên iOS 9 do sử dụng sai API nextDrawable. Ngoài ra, chúng tôi chưa gặp bất kỳ lỗi hành vi nào hay lỗi treo - đối với một API tương đối mới, Metal đã rất ổn định trên mọi mặt.

Ngoài ra, các công cụ đi kèm với Metal rất đa dạng và phong phú; cụ thể, bạn có thể sử dụng:

  • Một lớp kiểm tra khá toàn diện giúp phát hiện các vấn đề phổ biến khi sử dụng API. Về cơ bản, nó giống như chế độ gỡ lỗi Direct3D - điều này quen thuộc với Direct3D nhưng gần như chưa từng có trong thế giới OpenGL (trên lý thuyết, ARB_debug_callback được thiết kế để giải quyết vấn đề này, nhưng trên thực tế, nó hầu như không khả dụng và khi có, cũng không thực sự hữu ích)
  • Một công cụ gỡ lỗi GPU hoạt động, hiển thị tất cả các lệnh đã được gửi đi cùng trạng thái của chúng, nội dung của render target, nội dung của texture, v.v. Tôi không biết liệu nó có công cụ gỡ lỗi shader hoạt động hay không vì tôi chưa bao giờ cần đến, và việc kiểm tra bộ đệm có thể dễ dàng hơn một chút, nhưng nó chủ yếu hoàn thành công việc.
  • Một công cụ phân tích hiệu suất GPU hoạt động, hiển thị thống kê hiệu suất theo từng bước (thời gian, băng thông) và thời gian thực thi theo từng shader. Vì GPU hoạt động theo cơ chế chia lưới (tiler), bạn không thể mong đợi thời gian thực thi theo từng lệnh vẽ (drawcall), tất nhiên. Việc có mức độ hiển thị này - đặc biệt khi xem xét sự thiếu hụt hoàn toàn thông tin thời gian GPU trong các API đồ họa trên iOS - là rất tuyệt vời.
  • Một công cụ theo dõi dòng thời gian CPU/GPU (Metal System Trace) hoạt động tốt, hiển thị lịch trình công việc render của CPU và GPU, tương tự như GPUView nhưng thực sự dễ sử dụng, ngoại trừ một số đặc thù giao diện người dùng.
  • Một trình biên dịch shader ngoại tuyến giúp xác thực cú pháp shader của bạn, thỉnh thoảng đưa ra các cảnh báo hữu ích, chuyển đổi shader của bạn thành một blob nhị phân có thể tải khá nhanh trong thời gian chạy và được tối ưu hóa khá tốt trước đó, giúp giảm thời gian tải vì trình biên dịch trình điều khiển có thể nhanh hơn.

Nếu bạn đến từ thế giới Direct3D hoặc console, bạn có thể coi tất cả những điều này là điều hiển nhiên - tin tôi đi, trong OpenGL, mỗi tính năng này đều là điều bất thường và được đón nhận với sự hào hứng, đặc biệt trên nền tảng di động nơi bạn thường phải đối mặt với trình điều khiển đôi khi bị lỗi, không có kiểm tra cú pháp, không có công cụ gỡ lỗi GPU, không có công cụ phân tích hiệu suất GPU hữu ích, không thể thu thập dữ liệu lịch trình GPU và buộc phải làm việc với ngôn ngữ shader dựa trên văn bản mà mỗi nhà cung cấp lại có trình phân tích cú pháp hơi khác nhau.

Metal là một API tuyệt vời để viết mã và phân phối ứng dụng. Nó dễ sử dụng, có hiệu suất dự đoán được, có trình điều khiển mạnh mẽ và bộ công cụ vững chắc. Nó vượt trội hơn OpenGL ở mọi khía cạnh ngoại trừ tính tương thích, nhưng thực tế với OpenGL là bạn thực sự chỉ nên sử dụng nó trên ba nền tảng (iOS, Android và Mac), và hai trong số đó hiện đã hỗ trợ Metal; hơn nữa, lời hứa về tính tương thích của OpenGL chủ yếu không được thực hiện, vì mã bạn viết trên một nền tảng thường không hoạt động trên nền tảng khác vì nhiều lý do khác nhau.

Nếu bạn đang sử dụng một công cụ của bên thứ ba như Unity hoặc UE4, Metal đã được hỗ trợ ở đó; nếu bạn không sử dụng và thích lập trình đồ họa hoặc quan tâm sâu sắc đến hiệu suất và coi trọng iOS hoặc Mac, tôi khuyên bạn nên thử Metal. Bạn sẽ không thất vọng.

Metal hiện nay

Những thay đổi lớn nhất đối với Metal từ quan điểm của chúng tôi trong ba năm qua là về việc áp dụng trên quy mô lớn.

Ba năm trước, một phần tư số thiết bị phải sử dụng OpenGL. Ngày nay, đối với đối tượng người dùng của chúng tôi, con số này là ~2% - điều này có nghĩa là backend OpenGL của chúng tôi hầu như không còn quan trọng nữa. Chúng tôi vẫn duy trì nó nhưng điều này sẽ không kéo dài lâu.

Các trình điều khiển cũng tốt hơn bao giờ hết - nói chung, chúng tôi không thấy có vấn đề về trình điều khiển trên iOS, và khi có, chúng thường xảy ra trên các bản mẫu ban đầu, và đến khi các bản mẫu này được đưa vào sản xuất, các vấn đề thường đã được khắc phục.

Chúng tôi cũng đã dành thời gian để cải thiện backend Metal, tập trung vào ba lĩnh vực:

Tái cấu trúc chuỗi công cụ biên dịch shader

Một điều khác xảy ra trong ba năm qua là việc phát hành và phát triển Vulkan. Mặc dù các API có vẻ hoàn toàn khác biệt (và thực tế là vậy), hệ sinh thái Vulkan đã mang đến cho cộng đồng rendering một bộ công cụ nguồn mở tuyệt vời, khi kết hợp lại, tạo thành một bộ công cụ biên dịch chất lượng sản xuất dễ sử dụng.

Chúng tôi đã sử dụng các thư viện này để xây dựng một chuỗi công cụ biên dịch có thể nhận mã nguồn HLSL (sử dụng các tính năng DX11 bao gồm shader tính toán), biên dịch nó thành SPIRV, tối ưu hóa SPIRV đó và chuyển đổi SPIRV kết quả thành MSL (Metal Shading Language). Nó thay thế chuỗi công cụ trước đây của chúng tôi, vốn chỉ có thể sử dụng mã nguồn HLSL DX9 làm đầu vào và gặp nhiều vấn đề về độ chính xác đối với các shader phức tạp.

Thật là một sự trớ trêu khi Apple không liên quan gì đến điều này, nhưng đây là kết quả chúng tôi đạt được. Xin gửi lời cảm ơn sâu sắc đến những người đóng góp và quản trị viên của glslang (https://github.com/KhronosGroup/glslang), spirv-opt (https://github.com/KhronosGroup/SPIRV-Tools) và SPIRV-Cross (https://github.com/KhronosGroup/SPIRV-Cross). Chúng tôi đã đóng góp một bộ bản vá cho các thư viện này để giúp chúng tôi phát hành chuỗi công cụ mới, đồng thời sử dụng nó để chuyển hướng các shader của chúng tôi sang các API Vulkan, Metal và OpenGL.

Hỗ trợ macOS

Việc port sang macOS luôn là một khả năng nhưng không phải là ưu tiên hàng đầu của chúng tôi cho đến khi chúng tôi bắt đầu thiếu một số tính năng. Vì vậy, chúng tôi quyết định đầu tư vào Metal trên macOS để có tốc độ render nhanh hơn và mở ra một số khả năng cho tương lai.

Từ góc độ triển khai, điều này không hề khó khăn. Hầu hết các API đều giống hệt nhau; ngoại trừ quản lý cửa sổ, khu vực duy nhất yêu cầu điều chỉnh đáng kể là phân bổ bộ nhớ. Trên thiết bị di động, có không gian bộ nhớ chung cho các bộ đệm và texture, trong khi trên máy tính để bàn, API giả định GPU chuyên dụng với bộ nhớ video riêng.

Có thể nhanh chóng khắc phục điều này bằng cách sử dụng tài nguyên được quản lý, nơi runtime Metal sẽ tự động sao chép dữ liệu cho bạn. Đây là cách chúng tôi phát hành phiên bản đầu tiên, nhưng sau đó chúng tôi đã tái cấu trúc triển khai để sao chép dữ liệu tài nguyên một cách rõ ràng hơn thông qua các bộ đệm tạm thời, nhằm giảm thiểu gánh nặng bộ nhớ hệ thống.

Sự khác biệt lớn nhất giữa macOS và iOS là tính ổn định. Trên iOS, chúng tôi chỉ phải đối phó với một nhà cung cấp trình điều khiển trên một kiến trúc, trong khi trên macOS, chúng tôi phải hỗ trợ cả ba nhà cung cấp (Intel, AMD, NVidia). Ngoài ra, trên iOS, chúng tôi - may mắn thay! - đã bỏ qua phiên bản *đầu tiên* của iOS có hỗ trợ Metal, tức iOS 8, trong khi trên macOS điều này không khả thi vì lúc đó sẽ có quá ít người dùng sử dụng Metal. Do sự kết hợp của các vấn đề này, chúng tôi đã gặp phải nhiều vấn đề liên quan đến trình điều khiển hơn ở cả những khu vực tương đối đơn giản lẫn những khu vực tương đối phức tạp của API trên macOS.

Chúng tôi vẫn hỗ trợ tất cả các phiên bản macOS Metal (10.11+), mặc dù chúng tôi đã bắt đầu loại bỏ hỗ trợ và chuyển sang backend OpenGL cũ cho một số phiên bản có lỗi biên dịch shader đã biết mà chúng tôi khó có thể khắc phục, ví dụ: trên 10.11, hiện chúng tôi yêu cầu macOS 10.11.6 để Metal hoạt động.

Lợi ích về hiệu suất nằm trong dự kiến của chúng tôi; về thị phần, hiện tại chúng tôi có khoảng 25% người dùng OpenGL và 75% người dùng Metal trên nền tảng macOS, đây là tỷ lệ phân chia khá lành mạnh. Điều này có nghĩa là trong tương lai, có thể sẽ hợp lý để chúng tôi ngừng hỗ trợ OpenGL trên desktop hoàn toàn, vì không có nền tảng nào khác mà chúng tôi hỗ trợ sử dụng nó, điều này rất tốt để tập trung vào các API dễ hỗ trợ hơn và đạt được hiệu suất tốt.

Cải thiện hiệu suất và tiêu thụ bộ nhớ

Chúng tôi luôn khá thận trọng trong việc sử dụng các tính năng của API đồ họa, và Metal cũng không phải là ngoại lệ. Trong những năm qua, Metal đã có nhiều bản cập nhật tính năng lớn, bao gồm các API phân bổ tài nguyên cải tiến với bộ nhớ heap rõ ràng, shader ô với Metal 2, bộ đệm tham số và sinh lệnh phía GPU, v.v.

Chúng tôi hầu như không sử dụng bất kỳ tính năng mới nào. Đến nay, hiệu suất vẫn ở mức hợp lý, và chúng tôi muốn tập trung vào các cải tiến áp dụng cho toàn bộ hệ thống, vì vậy những tính năng như shader theo ô - đòi hỏi phải triển khai hỗ trợ đặc biệt trong toàn bộ trình render và chỉ khả dụng trên phần cứng mới - không thực sự hấp dẫn.

Dù vậy, chúng tôi vẫn dành một lượng thời gian để tối ưu hóa các phần khác nhau của hệ thống backend nhằm chạy *nhanh hơn* - sử dụng tải texture hoàn toàn không đồng bộ để giảm hiện tượng giật lag khi tải cấp độ, điều này diễn ra rất suôn sẻ, thực hiện các tối ưu hóa bộ nhớ đã đề cập trên macOS, tối ưu hóa việc phân phối CPU ở nhiều vị trí trong hệ thống backend bằng cách giảm các lần truy cập bộ nhớ đệm thất bại, v.v., và - một trong những tính năng mới duy nhất mà chúng tôi hỗ trợ rõ ràng - sử dụng bộ nhớ texture không chiếm dung lượng khi có sẵn để giảm đáng kể dung lượng bộ nhớ cần thiết cho hệ thống bóng mới của chúng tôi.

Tương lai

Nhìn chung, việc chúng tôi không phải dành quá nhiều thời gian cho các cải tiến Metal thực sự là điều tốt - mã nguồn được viết cách đây 3 năm, nói chung, vẫn hoạt động tốt, nhanh và ổn định, đây là dấu hiệu tích cực của một API đã trưởng thành. Việc chuyển sang Metal là một khoản đầu tư đáng giá, xét về thời gian đã bỏ ra và những lợi ích liên tục mà nó mang lại cho chúng tôi và người dùng.

Chúng tôi liên tục đánh giá lại sự cân bằng giữa khối lượng công việc dành cho các API khác nhau - rất có thể chúng tôi sẽ cần đi sâu hơn vào các phần hiện đại hơn của API Metal cho một số dự án hiển thị trong tương lai; nếu điều đó xảy ra, chúng tôi sẽ đảm bảo viết một bài đăng khác về chủ đề này!

  1. Ừ, được rồi, và có lẽ mất khoảng một tuần để sửa một vài lỗi được phát hiện trong quá trình thử nghiệm
  2. Các con số này áp dụng cho 128 KB dữ liệu được cập nhật mỗi khung hình (hai vùng 32x16x32 RGBA8) trên A10

Cả Roblox Corporation lẫn blog này đều không ủng hộ hay hỗ trợ bất kỳ công ty hay dịch vụ nào. Ngoài ra, không có bất kỳ đảm bảo hay cam kết nào được đưa ra về tính chính xác, độ tin cậy hoặc tính đầy đủ của thông tin trong blog này.

Bài đăng trên blog này ban đầu được xuất bản trên Roblox Tech Blog.