May 17, 2015 - OpenGL 4.3 - Part 4: Rendering Pipeline, Part 1

OpenGL 4.3 rendering pipeline (phần 1)

Rendering pipeline là một loạt các bước cố định mà OpenGL thực hiện để “biến” dữ liệu đầu vào thành những gì mà bạn thấy trên màn hình phẳng trước mặt.

Đây là mục tiêu của chúng ta:

Thực tế là:

Và đây là những gì có trong hộp đen “rendering pipeline”, chúng ta sẽ giải thích từng bước một trong hình.

Programmable pipeline

Fixed function pipeline

Ta sẽ lần lượt nói về 2 pipelines trên, nhưng trong loạt tutorials OpenGL 4.3 này, chúng ta chỉ sử dụng programmable pipeline.

Về programmable pipeline

0. Vertex specification

Ở bước này, việc của chúng ta là cấp dữ liệu đầu vào cho OpenGL. Dữ liệu này có thể là dữ liệu liên quan tới đỉnh (vertex) của các hình cơ bản - tam giác, tứ giác, hoặc chỉ đơn giản là 2 đỉnh (vertices) của một đoạn thẳng. Chúng ta chỉ cần cung cấp tọa độ điểm, và (kèm với một số yếu tố khác), OpenGL sẽ lập ra các tam giác/tứ giác dựa trên những điểm này (việc này sẽ xảy ra ở bước Primitive assembly, xem ở dưới).

Tóm lại, ở bước này, dữ liệu sẽ được đưa vào pipeline.
Sau bước này, chúng ta sẽ thấy:

const GLfloat vertices[] = {
    1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 1.0f,
};

1. Vertex shader

Có thể, bạn đã nghe ở đâu đó 2 cụm từ “vertex shader” và “pixel shader”. Trong OpenGL, “pixel shader” được gọi là “fragment shader”, nó mang nghĩa tương tự. Đây là một trong 2 giai đoạn bắt buộc trong bất cứ chương trình OpenGL nào.

Trong giai đoạn (stage) này (vertex shader), dữ liệu đầu vào (dữ liệu về vị trí của các vertices), sẽ được tính toán để cho ra vị trí cuối cùng của vertices. Well, các vertices này chưa thể nằm được trên màn hình người sử dụng, ít nhất là cho đến giai đoạn “Rasterization” (sẽ nói sau).

Bạn hỏi: “Tại sao không dùng ngay vị trí của vertices ở dữ liệu đầu vào làm dữ liệu tọa độ. Tức là sao không dùng ngay vị trí ở dữ liệu đầu vào đê xác định tọa độ vertices, mà phải cho vào vertex shader để xử lý, rất mất công?”. Vì dữ liệu đầu vào chỉ là tương đối. Có thể, sau này bạn sẽ sửa lại dữ liệu đó. Có nghĩa là, bạn đưa dữ liệu đầu vào là tọa độ của 1 cái hộp, không bị biến dạng. Nhưng bạn muốn nhìn cái hộp đó từ một góc 45 độ, nghĩa là, lúc đó tọa độ các vertices của cái hộp sẽ phải thay đổi, nghĩa là cái hộp sẽ phải bị biến dạng. Như vậy, dữ liệu đầu vào cần được “biến đổi” (transformed) sao cho khi xuất hiện trên màn hình, nó sẽ được đặt ở vị trí phù hợp với góc 45 độ mà bạn muốn nhìn. Như vậy, chúng ta sẽ nhận dữ liệu đầu vào là tọa độ gốc của cái hộp, transform tọa độ đó thành tọa độ mới mà bạn muốn nhìn, và đó là công việc của vertex shader - tính toán vị trí cuối cùng của vertices. Việc transform tọa độ vertices mình sẽ nói ở một bài riêng (cụ thể, ờ phần 2).

Vì vertex shader chỉ process dữ liệu về tọa độ vertices, những dữ liệu khác như colors, normals, textures..sẽ không mất đi mà chỉ đơn giản là bị bỏ qua, nghĩa là vertex shader sẽ truyền thẳng (pass-through) các dữ liệu này cho các stages sau mà không đá động gì tới chúng. Một ví dụ điển hình là fragment shader sẽ phụ trách dữ liệu liên quan tới color và texture của một vertex.

Tóm lại, ở giai đoạn này, vertex shader sẽ biến đổi dữ liệu tọa độ đầu vào thành dữ liệu tọa độ cuối cùng, không thể thay đổi được nữa. (Well..không hẵn, hãy chuyển qua bước kế tiếp).

Sau bước này, chúng ta sẽ thấy (lưu ý, đây không phải là những gì sẽ xuất hiện trên màn hình, chỉ là tượng trưng)

2. Tessellation

Như trên mình đã nói, một chương trình OpenGL bắt buộc phải có 2 shader stages là vertex shader và fragment shader. Sau giai đoạn vertex shader, sẽ không có một giai đoạn nào nữa để transform vị trí của các vertices đầu vào. Tuy nhiên, nếu ta sử dụng thêm stage tessellation, data về vertices có thể được thay đổi một lần nữa.

Tessellation là quá trình chia nhỏ các vertices. Thay vì phải tự tay sắp đặt các vertices nhỏ và rất nhỏ để tạo được độ chi tiết (detail, realistic, v..v..) cho model, OpenGL sẽ tự động làm việc này. Tessellation tiết kiệm được rất nhiều thời gian cho artists/level designers khi phải thiết kế nhân vật/màn chơi, cũng như giúp giảm tải GPU do không phải gọi API liên tục với số lượng lớn. Đây là một hình ảnh so sánh:

Nếu có mặt tessellation shader, vertices sau khi qua xử lý từ stage trước (vertex shader) sẽ tiếp tục được xử lý bởi tessellator để cho ra hình thù cuối cùng.

  • Khác với các kiểu dữ liệu cơ bản của OpenGL, vốn dùng tam giác, đoạn thẳng và tứ giác, tessellation sử dụng “patches” để mô tả hình dáng của một vật thể. Patch, nói một cách đơn giản nhất, là một danh sách các vertices có thứ tự. Patches chỉ được sử dụng trong tessellation stage, không thể sử dụng patches trong các stage như vertex và fragment (vì chúng chỉ hoạt động trên các geometric primitives cơ bản của OpenGL đó là đoạn, tam giác, tứ giác).
2.1. Tessellation control shader (TCS)

Giai đoạn này chưa thực sự “tessellate” các vertices. Có thể gọi là “tiền tessellate”. Theo wiki OpenGL, nhiệm vụ của Tessellation Control Shader là:

  • Quyết định bao nhiêu geometric primitives có thể “lôi” ra được từ những patches đầu vào.
  • Thực hiện biến đổi trên các patches đầu vào, vì primitive geometry của tessellation shader là patches, không phải là primitive thường của OpenGL. Chúng bao gồm thêm, bớt patches/nội dung patches (là các primitive geometry của OpenGL), và trả chúng cho stage (2.2) (bên dưới).

Bước này không bắt buộc.

2.2. Tessellate

Ở bước này, OpenGL sẽ tiến hành “tessellate” dựa trên patches đầu vào để tạo ra các primitives mới.

2.3. Tessellation evaluation shader

Bước này sẽ sử dụng kết hợp dữ liệu ra của bước (2.1) và dữ liệu từ sau giai đoạn tessellate (2.2) để tính toán vị trí cuối cùng của vertices. Bước này là bắt buộc vì tọa độ cuối cùng của các vertices sẽ được xuất ra.

Sau giai đoạn này, bạn sẽ thấy:

3. Geometry shader

Trong giai đoạn này, các primitives mới sẽ được tạo ra từ primitives đầu vào. Khác với vertex shader stage chỉ truy cập duy nhất 1 vertex (per-vertex) trong 1 lần chạy shader, geometry shader có thể truy cập một geometric primitive (per-vertex hoặc multi-vertex) và do đó, có thể thực hiện xóa bỏ, tạo, chỉnh sửa các primitives này.

Sau bước này, bạn sẽ thấy:

4. Primitive assembly

Vì dữ liệu chúng ta truyền vào chỉ là tọa độ điểm của các vertices, nên trong stage này, OpenGL sẽ tìm cách nối các điểm đó lại để tạo thành các primitives cơ bản, có thể là điểm, đoạn thẳng, tam giác, hoặc tứ giác.

Sau bước này, bạn sẽ thấy:

5. Post-vertex processing

Đây là một nhóm các bước, nhưng chúng ta chỉ nói riêng clipping.

Ở bước này, OpenGL sẽ cắt bớt những gì nằm bên ngoài khung nhìn (viewport).
Khung nhìn mặc định là hình chữ nhật áp sát màn hình của bạn, và bị giới hạn bởi cửa sổ nơi mà việc render được thực hiện.
Vị trí và kích thước khung nhìn được định nghĩa bởi 1 API call, “glViewport()”, nhưng nếu không gọi, thì viewport mặc định là toàn bộ hình chữ nhật trong phạm vi cửa sổ chương trình.

Clipping được thực hiện tự động bởi OpenGL.
Tóm lại, ở bước này, những vertices nằm ngoài viewport sẽ bị xóa bỏ và các vertices liên quan tới vertices bị xóa sẽ được điều chỉnh và tạo thành primitive mới sao cho khớp, giống như đang bị cắt thật sự. Nói một cách chính xác hơn, geometry sẽ được cắt khỏi view frustum. Mình sẽ nói rõ hơn về vấn đề này ở phần 2.

Sau bước này, bạn sẽ thấy:

6. Rasterization

Vậy là công việc với vertices đầu vào đã hoàn tất. Việc tiếp theo là biểu diễn vị trí các vertices này trên màn hình. Đó là công việc của rastersizer.
Rastersizer sẽ nhận tọa độ vertices đầu vào (đã được transformed từ các stages trước) và generates fragment(s) cho các vertices đó.

Nói thêm về fragment:

  • Dữ liệu thuộc về một pixel chỉ bao gồm màu RGBA. (RGB và thêm một 8-bit alpha channel).
  • Dữ liệu thuộc về một fragment bao gồm tất cả những thông tin cần thiết để sinh pixel(s).

Sau bước này, bạn sẽ thấy:

7. Fragment shader

Stage thứ hai và cũng là stage bắt buộc cuối cùng trong rendering pipeline.
Trong stage này, fragment shader sẽ lấy từng fragment từ rastersizer và tính toán các giá trị depth, stencil và màu của fragment đó. Trong stage này, màu của một fragment sẽ được quyết định, dù trong stage sau (8), màu có thể bị biến đổi một lần nữa.

Một điểm mạnh của fragment shader là chúng có thể được dùng với kĩ thuật texture mapping để áp texture lên bề mặt vật thể. Thay vì tô màu, chúng ta có thể “tô” texture.

Tóm lại, trong giai đoạn này, màu của một fragment sẽ được quyết định. Lưu ý, fragment khác với pixel (đọc lại (6)).

Sau bước này, bạn sẽ thấy:

8. Per-fragment/per-sample processing, testing, blending

Trong stage trước, như đã nói, output của fragment shader là tính toán màu, depth và stencil.

Các fragments đầu vào cho stage này sẽ phải qua một loạt tests. Nếu thành công ở tất cả tests, một fragment sẽ trở thành pixel và có một chỗ riêng trên framebuffer (màn hình), và các giá trị của nó (màu, depth) sẽ được viết vào các buffer tương ứng (color buffer và depth buffer).

Các tests mà một fragment phải trải qua bao gồm:

  • Scissor test: Kiểm tra một fragment có nằm ngoài vùng render không. Nếu nằm ngoài, fragment sẽ bị loại (discarded). Nếu fragment bị loại, các tests sau cho fragment đó sẽ không được thực hiện. Vùng render được xác định bằng glScissor().
  • Stencil test: Kiểm tra một fragment có nằm ngoài vùng render không. Nghe có vẻ giống với scissor test. Nhưng ta dùng stencil buffer/test, ví dụ, để render lên một cái cửa kính xe chẳng hạn, và tất cả những gì nằm ngoài cái cửa kính xe sẽ không được rendered. Ngược lại với scissor test, chỉ hoạt động với các vùng vuông, chữ nhật. Ta có thể dùng scissor để chia viewports ra làm nhiều vùng (giống split-screen co-op shooter), và render riêng trên mỗi vùng được chia ra, thì lúc này scissor test sẽ có ích.
  • Depth test: Test độ sâu của một fragment. Depth của một fragment nếu bé hơn giá trị của cùng một điểm trong depth buffer sẽ bị discarded.
  • <…>

Những fragment còn sống sọt sẽ là những gì sẽ được render lên màn hình.

Về fixed function pipeline

[!] Bạn nên đọc programmable pipeline trước khi đọc fixed function pipeline, vì chúng ta sẽ không dùng fixed function pipeline nên mình sẽ rút lại phần này còn rất ngắn, chỉ nói sơ qua.

Fixed function pipeline là pipeline cũ dùng từ legacy OpenGL (1.5 trở về trước), lúc mà phần cứng còn hạn chế. Ở programmable pipeline, chúng ta được tự do quyền kiểm soát các stage vertex, fragment, tesellation và geometry, nên ta có thể biến đổi vertices/fragments/.. tùy ý muốn, thông qua ngôn ngữ đổ bóng của OpenGL - GLSL (OpenGL Shading Language). Ví dụ, vì fragment shader có thể điều khiển được màu của fragment, ta có thể sử dụng nó để viết các post-process effects như HDR, Bloom, tone mapping, depth of field (chắc chắn ít nhiều bạn cũng đã từng nghe tới những khái niệm này trong games). Tương tự với vertex shader và tessellation shader, nên pipeline của modern OpenGL mới có tên gọi “programmable pipeline”.

Fixed function, một cách ngược lại, chúng ta không có quyền điều khiển các shader stages, mà chúng sẽ được điều khiển trực tiếp bới GPU. Như vậy, ta không có quyền điều khiển các stages này, đồng nghĩa với việc không có những hiệu ứng post-process (nói ở trên), normal mapping (sử dụng normals của vật thể để tạo hiệu ứng bề nổi), shadow mapping (bóng đổ), v..v….

Hầu hết những GPUs hiện nay đều có hỗ trợ programmable pipeline.

May 16, 2015 - OpenGL 4.3 - Part 3: Configuring SOIL2

Cài đặt SOIL2 - Simple OpenGL Image Library

Trong riêng bài viết này, mình sẽ hướng dẫn cài đặt và sử dụng SOIL2 cho Visual Studio 2013 (Community Edition), một phần là vì cách cài đặt SOIL2 vào project sẽ hơi khác (chúng ta sẽ biên dịch SOIL2 từ source code..rất dễ xD~) so với việc download thư viện pre-built từ source và sử dụng; phần còn lại là vì mình không muốn làm rối bài hướng dẫn gốc.

Về SOIL2

SOIL2 là một thư viện cho phép người dùng có thể load textures vào OpenGL một cách dễ dàng. Textures, theo cách dễ hiểu, là một hình ảnh. Cỏ, cây, lá, mặt bàn, mặt đất, bầu trời. Chúng ta có thể dán những textures này vào bề mặt vật thể. Việc “dán” texture vào bề mặt vật thể được gọi là texture mapping (ánh xạ texture). Textures có thể là 1D, 2D hoặc 3D, trong đó 2D textures phổ biến nhất, chúng dùng để “dán” (ánh xạ - gọi là map, nên có tên “texture mapping”) hình ảnh vào vật thể, trong khi đó 1D textures có thể được dùng làm một bảng lookup (bảng màu có sẵn), và 3D có thể được dùng để tạo những thứ như volumetric particles. Well, ta sẽ không đi vào quá sâu, nhưng 2D textures là ứng dụng chính của textures, hết. xD~

Có sẵn các thư viện riêng khác cũng cung cấp chức năng load textures từ nhiều loại ảnh, tương tự như SOIL: DevIL, ResIL, FreeImage, v..v…, nhưng có vài lý do sau đây ta chọn SOIL2:

  • Không phụ thuộc DLL ngoài, dung lượng nhỏ, viết trên C.
  • Thích hợp dùng trong OpenGL: SOIL = Simple OpenGL Image Library. Ngoài load hình ảnh nó có thể thực hiện các thao tác load textures trong OpenGL, vốn là việc mà nếu dùng DevIL hay FreeImage, chúng ta phải load hình trước (bằng các thư viện này) rồi load textures từ ảnh này vào OpenGL.
  • Đọc được các loại định dạng ảnh thông dụng, giống như các thư viện cùng “loài”.

Tải và biên dịch SOIL2

Tác giả SOIL2 không cung cấp phiên bản thư viện cho nó, nên chúng ta sẽ tự compile source code để lấy thư viện. Một điều may mắn là chúng ta có thể generate project files cho Visual Studio bằng premake để có thể biên dịch rất dễ dàng.

Giải nén source code của SOIL2, chép file executable của premake vào thư mục SOIL2 và mở một command prompt.


premake4 vs2012
để generate project cho VS2012. Kết quả nằm trong ./make/windows/. Mở nó ra, và bạn sẽ nhận được thông báo cần update compilers cho project này. Chúng ta không sử dụng vs2013 mà dùng vs2012 vì tạm thời SOIL2 chưa hỗ trợ generate project trên VS2013, nên ta sẽ generate cho VS2012 và upgrade lên VS2013.

Bấm OK và chọn Build -> Build Solution hoặc nhấn F7. Nhớ trỏ configuration về “release”.

Kết quả sẽ nằm trong ./lib/windows/. Chép nó vào thư mục Dependencies cùng với headers của SOIL2 (nằm ở ./src/, bạn chỉ cần dùng thư mục SOIL2).

Cuối cùng là mở project, link thư viện của SOIL2 và include headers, thế là xong:

#include <SOIL2/SOIL2.h>
...
#pragma comment(lib, "soil2.lib")

Bạn có thể test bằng cách load 1 ảnh mẫu và trả kết quả: (thay img.jpg với một ảnh bất kì)

printf("%i", (GLuint) SOIL_load_OGL_texture("img.jpg", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_NTSC_SAFE_RGB));

Nếu printf() in ra 1, ta đã thành công.

Trong bài viết tiếp theo sẽ nói một cách tổng quát về rendering pipeline của OpenGL 4.3, là cách mà OpenGL biến đổi dữ liệu 3D thành dữ liệu 2D có thể hiển thị được trên màn hình.

May 13, 2015 - OpenGL 4.3 - Part 1: Introduction

Loạt OpenGL tutorials này mình viết ra cho những ai có hứng thú tìm hiểu, và sử dụng nó, chỉ đơn giản có vậy. Nếu bạn đã có một khái niệm nhất định về OpenGL sẵn, bạn nên bỏ qua chương này. Nếu không, hãy tìm tới trang này và đọc.

SOMA - một game kinh dị pha khoa học viễn tưởng, phát triển bởi Frictional Games, sử dụng OpenGL.

Đầu tiên mình sẽ giải thích ý nghĩa của “specification/standard”. Trong phạm vi công nghệ thông tin (và cả hiểu biết của mình), đây là một văn bản chỉ rõ các thành phần, cấu trúc và tổ chức của một công nghệ nhất định, nhằm tạo ra sự nhất quán trong việc phát triển và sử dụng công nghệ đó. Một ví dụ điển hình là C++. Sau khi Bjarne cho ra cuốn “The C++ Programming Language” lần thứ hai vào năm 1991, mọi thứ bắt đầu trở nên lộn xộn. Chương trình viết và biên dịch được trên compiler này không thể dịch được bằng compiler khác, đơn giản chỉ là vì compiler đó thiếu một số thư viện/chức năng sử dụng trong chương trình (vốn có sẵn trong compiler kia). Năm 1998, JTC1/SC22/WG21 phát hành bản C++ standard đầu tiên với tên C++ 98. Thực chất nó là một văn bản định nghĩa lõi, cấu trúc và các thành phần cơ bản nhất của C++, và compiler writers sẽ viết compiler theo chuẩn (standard) này, tạo ra sự nhất quán và linh động trong việc viết phần mềm. Sau đó, nhóm này đã lần lượt phát hành các standards cho C++, lần lượt: C++ 03, C++ TR1, C++ 11 (C++ 0x) và sắp tới là C++ 14.

OpenGL cũng không phải là ngoại lệ. Mình sẽ không đi sâu vào chi tiết: bản thân OpenGL không phải là một phần mềm, nó chỉ là một specification, và các nhà sản xuất card đồ họa (NVIDIA/AMD/Intel/..) sẽ phát triển API dựa trên specification này. OpenGL hiện được quản lý bởi Khronos Group (đồng tác giả OpenCL/OpenGL ES/WebGL/COLLADA và sắp tới là Vulkan, một revision lớn của OpenGL với nhiều thay đổi).

Tại sao là OpenGL mà không phải là Direct3D?

  • OpenGL không bị giới hạn chỉ trong Windows và các sản phẩm tương tự của Microsoft (Xbox 360/One, Windows Phone).
  • Tốc độ xử lý (có thể) ngang bằng Windows trên chính nền tảng của nó với drivers tốt. Làm mình nhớ tới bài viết 3 năm trước đây của Valve.
  • Cross-platform. Linux, Mac. Một điều ngớ ngẩn mà hầu như ai cũng mắc phải đó là PS3/PS4 dùng OpenGL. Không. PSGL và GNM/GNMX không sử dụng OpenGL. Nói cách khác, OpenGL sẽ chạy trên bất cứ thứ gì đã được viết driver để hỗ trợ nó.

Những thứ còn lại đều do mỗi cá nhân. OpenGL không được sử dụng phổ biến trong games (Windows rất phổ biến với Direct3D). Có, nhưng không nhiều. Gần đây có dịp thử Grand Theft Auto V, mới biết game engine của họ không hỗ trợ OpenGL (DirectX 10/10.1/11). Tương tự với những series games lớn (hầu hết, trừ Valve, id Software, Frictional Games và một vài nhà phát triển nữa, xem ở đây), nhưng có chỗ đứng rất chắc trong các nhóm phần mềm về mô phỏng (simulation), dựng/xử lý hình ảnh (rendering/image processing/modelers) - Blender, Adobe After Effects, Photoshop, 3DS Max, Maya, AutoCAD; kiến trúc (architecture/visualisation) - Google Earth, Google Sketchup. Và đừng quên những bộ phim của Pixar đều được dựng trên OpenGL.

Ngoài ra, OpenGL có thể được gắn thêm các “plugins” (gọi là extensions). Các extensions này, nếu đủ phổ biến, sẽ được thêm vào specification của phiên bản OpenGL tiếp theo, còn không, người sử dụng vẫn có thể tiếp tục dùng chúng (tuy chỉ dưới dạng extensions và không chính thức). Ngược lại, với Direct3D, bạn chỉ có thể chờ đợi Microsoft thêm một (vài) năm cho một bản DirectX mới.

Một vài điểm phụ:

  • Direct3D dễ sử dụng. Với bộ DirectX, bạn có trong tay renderer API (Direct3D), DirectInput, DirectCompute, DirectSound3D. Trong khi đó, OpenGL chỉ là một renderer API thuần. Các thứ như input, sound, network, physics, bạn có thể sử dụng các thư viện ngoài.
  • Intel thường hỗ trợ OpenGL kém. NVIDIA và AMD hỗ trợ OpenGL trong drivers của họ bằng những cách khác nhau, nên sẽ có trường hợp một phần mềm viết bằng OpenGL chạy ổn định trên card NVIDIA nhưng lỗi và/hoặc chạy rất kém trên AMD. Đó là do sự không nhất quán trong việc viết API của họ, không phải vì OpenGL là một API tồi.
  • Vấn đề không nằm ở chỗ bạn chọn API nào. Tất nhiên, hiện nay thì điều này đã trở nên đúng đắn hơn. Cách viết drivers để utilize API đó là một phần, cách viết phần mềm của programmers một phần, và tốc độ/hỗ trợ của card màn hình là một phần.
  • OpenGL có một phân nhánh cho mobile, gọi là OpenGL ES (Embedded systems) - Android, iOS, BlackBerry, Symbian đều sử dụng OpenGL ES làm thư viện đồ họa chính, Direct3D có các phiên bản dành riêng cho Windows Embedded, Xbox, Windows CE.

Legacy OpenGL và Modern OpenGL

Hầu hết các tutorials trên mạng sẽ hướng dẫn bạn sử dụng legacy OpenGL, nghĩa là các phiên bản OpenGL 2.1 trở về trước. Đây là những bản OpenGL rất cũ và không còn được sử dụng nữa, lý do chúng rất chậm và khó viết, sử dụng extensions với mật độ dày đặc, cú pháp không nhất quán và chỉ sử dụng fixed function pipeline (OpenGL 1.5 trở xuống chỉ dùng fixed function) (sẽ nói về vấn đề này ở những chương sau).

Trong loạt tutorials này mình sẽ nhắm tới OpenGL 4.3, core profile, tương đương DirectX 11. Profiles trong OpenGL có hai loại: core và compatibility. Sử dụng compatibility profile nếu bạn muốn sử dụng (lại) các chức năng cũ, sử dụng fixed function pipeline, ngược lại, hãy dùng core profile.