1e41f4b71Sopenharmony_ci# OpenGL ES 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciOpenGL is a cross-platform graphics API that specifies a standard software interface for 3D graphics processing hardware. [OpenGL ES](https://www.khronos.org/opengles/) is a flavor of the OpenGL specification intended for embedded devices. OpenHarmony now supports OpenGL ES 3.2. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci## Supported Capabilities 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciOpenGL ES 3.2 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci## Symbols Exported from the Standard Library 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci[OpenGL ES 3.2 Symbols Exported](openglesv3-symbol.md) 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci## Introducing OpenGL 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ciTo use OpenGL capabilities, you must add related dynamic link libraries (DLLs) and header files. 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci**Adding Dynamic Link Libraries** 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ciAdd the following libraries to **CMakeLists.txt**. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci```txt 22e41f4b71Sopenharmony_cilibace_ndk.z.so 23e41f4b71Sopenharmony_cilibace_napi.z.so 24e41f4b71Sopenharmony_cilibGLESv3.so 25e41f4b71Sopenharmony_cilibEGL.so 26e41f4b71Sopenharmony_ci``` 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci**Including Header Files** 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ci```c++ 31e41f4b71Sopenharmony_ci#include <ace/xcomponent/native_interface_xcomponent.h> 32e41f4b71Sopenharmony_ci#include <EGL/egl.h> 33e41f4b71Sopenharmony_ci#include <EGL/eglext.h> 34e41f4b71Sopenharmony_ci#include <EGL/eglplatform.h> 35e41f4b71Sopenharmony_ci#include <GLES3/gl3.h> 36e41f4b71Sopenharmony_ci``` 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci## References 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ciTo use the OpenGL ES API in your application development, familiarize yourself with the NDK development process and the **\<XComponent>** usage, which are described in the following topics: 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci- [Getting Started with the NDK](../../napi/ndk-development-overview.md) 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci- [Node-API](./napi.md) 45e41f4b71Sopenharmony_ci 46e41f4b71Sopenharmony_ci- [XComponentNode](../apis-arkui/js-apis-arkui-xcomponentNode.md) 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci- [XComponent](../apis-arkui/arkui-ts/ts-basic-components-xcomponent.md) 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ci## OpenGL ES Extensions 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci- To obtain the official reference document for OpenGL ES extensions, visit [Khronos OpenGL ES Registry](https://registry.khronos.org/OpenGL/index_es.php). 53e41f4b71Sopenharmony_ci- You can call **glGetString** to query the extensions supported by the chip. Before calling **glGetString**, you must initialize the context. The following is an example: 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci```c++ 56e41f4b71Sopenharmony_ciEGLDisplay display; 57e41f4b71Sopenharmony_ciEGLConfig config; 58e41f4b71Sopenharmony_ciEGLContext context; 59e41f4b71Sopenharmony_ciEGLSurface surface; 60e41f4b71Sopenharmony_ciEGLint majorVersion; 61e41f4b71Sopenharmony_ciEGLint minorVersion; 62e41f4b71Sopenharmony_ciEGLNativeWindowType win; 63e41f4b71Sopenharmony_cidisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 64e41f4b71Sopenharmony_cieglInitialize(display, &majorVersion, &minorVersion); 65e41f4b71Sopenharmony_cidisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 66e41f4b71Sopenharmony_cieglInitialize(display, &majorVersion, &minorVersion); 67e41f4b71Sopenharmony_ciEGLint attribs[] = { 68e41f4b71Sopenharmony_ci EGL_RENDERABLE_TYPE, 69e41f4b71Sopenharmony_ci EGL_OPENGL_ES2_BIT, 70e41f4b71Sopenharmony_ci EGL_BLUE_SIZE, 8, 71e41f4b71Sopenharmony_ci EGL_GREEN_SIZE, 8, 72e41f4b71Sopenharmony_ci EGL_RED_SIZE, 8, 73e41f4b71Sopenharmony_ci EGL_NONE 74e41f4b71Sopenharmony_ci}; 75e41f4b71Sopenharmony_cieglChooseConfig(display, attribs, &config, 1, &numConfigs); 76e41f4b71Sopenharmony_cicontext = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); 77e41f4b71Sopenharmony_cisurface = eglCreatePbufferSurface(display, config, NULL); 78e41f4b71Sopenharmony_cieglMakeCurrent(display, surface, surface, context); 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_cichar *strTest = new char[1024]; 81e41f4b71Sopenharmony_cistrTest = (char *)glGetString(GL_EXTENSIONS); // The return value of strTest lists all extensions supported, separated by spaces. 82e41f4b71Sopenharmony_cibool isHave = strTest.find("GL_OES_matrix_palette") != -1 ? 83e41f4b71Sopenharmony_ci true : 84e41f4b71Sopenharmony_ci false; // Check whether an extension exists. If yes, the value of isHave is true. If no, the value of isHave is false. 85e41f4b71Sopenharmony_ci``` 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci## Example 88e41f4b71Sopenharmony_ci 89e41f4b71Sopenharmony_ci```cpp 90e41f4b71Sopenharmony_ci#include <EGL/egl.h> 91e41f4b71Sopenharmony_ci#include <GLES3/gl3.h> 92e41f4b71Sopenharmony_ci#include <iostream> 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci#define WINDOW_WIDTH 800 95e41f4b71Sopenharmony_ci#define WINDOW_HEIGHT 600 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ciint main() { 98e41f4b71Sopenharmony_ci // Initialize EGL. 99e41f4b71Sopenharmony_ci EGLDisplay display; 100e41f4b71Sopenharmony_ci EGLConfig config; 101e41f4b71Sopenharmony_ci EGLContext context; 102e41f4b71Sopenharmony_ci EGLSurface surface; 103e41f4b71Sopenharmony_ci EGLint numConfigs; 104e41f4b71Sopenharmony_ci EGLint majorVersion; 105e41f4b71Sopenharmony_ci EGLint minorVersion; 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci // Initialize the EGL display. 108e41f4b71Sopenharmony_ci display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 109e41f4b71Sopenharmony_ci eglInitialize(display, &majorVersion, &minorVersion); 110e41f4b71Sopenharmony_ci 111e41f4b71Sopenharmony_ci // Configure EGL. 112e41f4b71Sopenharmony_ci EGLint attribs[] = { 113e41f4b71Sopenharmony_ci EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, 114e41f4b71Sopenharmony_ci EGL_BLUE_SIZE, 6, 115e41f4b71Sopenharmony_ci EGL_GREEN_SIZE, 8, 116e41f4b71Sopenharmony_ci EGL_RED_SIZE, 8, 117e41f4b71Sopenharmony_ci EGL_NONE 118e41f4b71Sopenharmony_ci }; 119e41f4b71Sopenharmony_ci eglChooseConfig(display, attribs, &config, 1, &numConfigs); 120e41f4b71Sopenharmony_ci 121e41f4b71Sopenharmony_ci // Create an EGL context. 122e41f4b71Sopenharmony_ci EGLint contextAttribs[] = { 123e41f4b71Sopenharmony_ci EGL_CONTEXT_CLIENT_VERSION, 3, 124e41f4b71Sopenharmony_ci EGL_NONE 125e41f4b71Sopenharmony_ci }; 126e41f4b71Sopenharmony_ci 127e41f4b71Sopenharmony_ci // Create an EGL surface. 128e41f4b71Sopenharmony_ci surface = eglCreateWindowSurface(display, config, nativeWindow, NULL); 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci // Bind the EGL context to the surface. 133e41f4b71Sopenharmony_ci eglMakeCurrent(display, surface, surface, context); 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci // Set the viewport. 136e41f4b71Sopenharmony_ci glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); 137e41f4b71Sopenharmony_ci 138e41f4b71Sopenharmony_ci // Clear the color buffer. 139e41f4b71Sopenharmony_ci glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 140e41f4b71Sopenharmony_ci glClear(GL_COLOR_BUFFER_BIT); 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci // Define vertex data. 143e41f4b71Sopenharmony_ci GLfloat vertices[] = { 144e41f4b71Sopenharmony_ci -0.5f, -0.5f, 0.0f, // Lower left corner. 145e41f4b71Sopenharmony_ci 0.5f, -0.5f, 0.0f, // Lower right corner. 146e41f4b71Sopenharmony_ci 0.0f, 0.5f, 0.0f // Top. 147e41f4b71Sopenharmony_ci }; 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ci // Create and bind a Vertex Buffer Object (VBO). 150e41f4b71Sopenharmony_ci GLuint VAO[0]; 151e41f4b71Sopenharmony_ci GLuint VBO; 152e41f4b71Sopenharmony_ci glGenVertexArrays(1, VAO); 153e41f4b71Sopenharmony_ci glBindVertexArray(VAO[0]); 154e41f4b71Sopenharmony_ci glGenBuffers(1, &VBO); 155e41f4b71Sopenharmony_ci glBindBuffer(GL_ARRAY_BUFFER, VBO); 156e41f4b71Sopenharmony_ci glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci // Create a shader program. 159e41f4b71Sopenharmony_ci const char* vertexShaderSource = R"( 160e41f4b71Sopenharmony_ci #version 300 es 161e41f4b71Sopenharmony_ci precision mediump float; 162e41f4b71Sopenharmony_ci layout (location = 0) in vec3 aPos; 163e41f4b71Sopenharmony_ci void main() { 164e41f4b71Sopenharmony_ci gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); 165e41f4b71Sopenharmony_ci } 166e41f4b71Sopenharmony_ci )"; 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci const char* fragmentShaderSource = R"( 169e41f4b71Sopenharmony_ci #version 300 es 170e41f4b71Sopenharmony_ci precision mediump float; 171e41f4b71Sopenharmony_ci out vec4 FragColor; 172e41f4b71Sopenharmony_ci void main() { 173e41f4b71Sopenharmony_ci FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); 174e41f4b71Sopenharmony_ci } 175e41f4b71Sopenharmony_ci )"; 176e41f4b71Sopenharmony_ci 177e41f4b71Sopenharmony_ci GLuint vertexShader, fragmentShader, shaderProgram; 178e41f4b71Sopenharmony_ci // Create a vertex shader. 179e41f4b71Sopenharmony_ci vertexShader = glCreateShader(GL_VERTEX_SHADER); 180e41f4b71Sopenharmony_ci glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); 181e41f4b71Sopenharmony_ci glCompileShader(vertexShader); 182e41f4b71Sopenharmony_ci 183e41f4b71Sopenharmony_ci // Create a fragment shader. 184e41f4b71Sopenharmony_ci fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 185e41f4b71Sopenharmony_ci glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); 186e41f4b71Sopenharmony_ci glCompileShader(fragmentShader); 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci // Create a shader program. 189e41f4b71Sopenharmony_ci shaderProgram = glCreateProgram(); 190e41f4b71Sopenharmony_ci glAttachShader(shaderProgram, vertexShader); 191e41f4b71Sopenharmony_ci glAttachShader(shaderProgram, fragmentShader); 192e41f4b71Sopenharmony_ci glLinkProgram(shaderProgram); 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci // Use the shader program. 195e41f4b71Sopenharmony_ci glUseProgram(shaderProgram); 196e41f4b71Sopenharmony_ci 197e41f4b71Sopenharmony_ci // Bind the vertex data. 198e41f4b71Sopenharmony_ci glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); 199e41f4b71Sopenharmony_ci glEnableVertexAttribArray(0); 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci // Draw a triangle. 202e41f4b71Sopenharmony_ci glDrawArrays(GL_TRIANGLES, 0, 3); 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci // Swap the buffers. 205e41f4b71Sopenharmony_ci eglSwapBuffers(display, surface); 206e41f4b71Sopenharmony_ci 207e41f4b71Sopenharmony_ci // Clear the resources. 208e41f4b71Sopenharmony_ci glDeleteShader(vertexShader); 209e41f4b71Sopenharmony_ci glDeleteShader(fragmentShader); 210e41f4b71Sopenharmony_ci glDeleteBuffers(1, &VBO); 211e41f4b71Sopenharmony_ci 212e41f4b71Sopenharmony_ci // Wait for exit. 213e41f4b71Sopenharmony_ci std::cout << "Press Enter to exit..." << std::endl; 214e41f4b71Sopenharmony_ci std::cin.get(); 215e41f4b71Sopenharmony_ci 216e41f4b71Sopenharmony_ci // Clear EGL. 217e41f4b71Sopenharmony_ci eglDestroyContext(display, context); 218e41f4b71Sopenharmony_ci eglDestroySurface(display, surface); 219e41f4b71Sopenharmony_ci eglTerminate(display); 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ci return 0; 222e41f4b71Sopenharmony_ci} 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci``` 225e41f4b71Sopenharmony_ci 226e41f4b71Sopenharmony_ciThis example uses EGL to create a render surface, which can be a window surface, pbuffer, or pixmap. The following explains every step in detail. 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci### Using eglGetDisplay to Obtain an EGL Display Connection 229e41f4b71Sopenharmony_ci```cpp 230e41f4b71Sopenharmony_ciEGLDisplay eglGetDisplay(EGLNativeDisplayType display_id); 231e41f4b71Sopenharmony_ci``` 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ciThe **eglGetDisplay** function returns an **EGLDisplay** object, which represents the connection to an EGL display. If no connection is available, **EGL_NO_DISPLAY** is returned. 234e41f4b71Sopenharmony_ci 235e41f4b71Sopenharmony_ciThe **display_id** parameter indicates the local display type of the display. The **EGLNativeDisplayType** parameter is the native window display type, which has different definitions on different platforms. If you just want to use the default display, use **EGL_DEFAULT_DISPLAY** without explicitly specifying **display_id**. 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_ci### Using eglInitialize to Initialize the EGL Display Connection 238e41f4b71Sopenharmony_ciCall **eglInitialize** to initialize the EGL display connection obtained. 239e41f4b71Sopenharmony_ci```cpp 240e41f4b71Sopenharmony_ciEGLBoolean eglInitialize(EGLDisplay display, // EGL display connection. 241e41f4b71Sopenharmony_ci EGLint *majorVersion, // Major version number of the EGL implementation. The value may be NULL. 242e41f4b71Sopenharmony_ci EGLint *minorVersion);// Minor version number of the EGL implementation. The value may be NULL. 243e41f4b71Sopenharmony_ci``` 244e41f4b71Sopenharmony_ciThe function is used to initialize the internal data structure of the EGL, return the EGL version numbers, and save them in **majorVersion** and **minorVersion**. 245e41f4b71Sopenharmony_ciIf the initialization is successful, **EGL_TRUE** is returned. Otherwise, **EGL_FALSE** is returned. You can also call **EGLint eglGetError()** to query the EGL error status. 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ci- **EGL_BAD_DISPLAY**: The specified EGL display is invalid. 248e41f4b71Sopenharmony_ci 249e41f4b71Sopenharmony_ci- **EGL_NOT_INITIALIZED**: EGL cannot be initialized. 250e41f4b71Sopenharmony_ci 251e41f4b71Sopenharmony_ci### Using eglChooseConfig to Determine the Rendering Configuration 252e41f4b71Sopenharmony_ciAfter the EGL display connection is initialized, determine the type and configuration of the available surface in either of the following ways: 253e41f4b71Sopenharmony_ci- Specify a set of required configurations and use **eglChooseConfig** to enable EGL to recommend the optimal configuration. 254e41f4b71Sopenharmony_ciGenerally, you can use this method because it is easier to obtain the optimal configuration. 255e41f4b71Sopenharmony_ci 256e41f4b71Sopenharmony_ci ```cpp 257e41f4b71Sopenharmony_ci EGLBoolean eglChooseConfig(EGLDisplay dpy, // Handle to the EGL display connection for which configurations are selected. 258e41f4b71Sopenharmony_ci const EGLint *attrib_list, // An integer array of pointers to attributes. Each element in the array consists of an attribute name (for example, EGL_RED_SIZE) and attribute value, and the array is terminated with EGL_NONE. An example attribute array is {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_NONE}. 259e41f4b71Sopenharmony_ci EGLConfig *configs, // An array of pointers to the selected configurations. The eglChooseConfig function selects the configurations that match the attributes from the available configurations and stores them in this array. 260e41f4b71Sopenharmony_ci EGLint config_size,// Size of the configs array. 261e41f4b71Sopenharmony_ci EGLint *num_config); // Number of configurations that match the attributes. 262e41f4b71Sopenharmony_ci ``` 263e41f4b71Sopenharmony_ci 264e41f4b71Sopenharmony_ci ```cpp 265e41f4b71Sopenharmony_ci // Here, the following attributes are used: 266e41f4b71Sopenharmony_ci EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, -// The renderable type is OpenGL ES 3. 267e41f4b71Sopenharmony_ci EGL_BLUE_SIZE, 6, // The number of bits in the blue buffer is 6. 268e41f4b71Sopenharmony_ci EGL_GREEN_SIZE, 8, // The number of bits in the green buffer is 8. 269e41f4b71Sopenharmony_ci EGL_RED_SIZE, 8, // The number of bits in the red buffer is 8. 270e41f4b71Sopenharmony_ci EGL_NONE}; 271e41f4b71Sopenharmony_ci eglChooseConfig(display, attribs, &config, 1, &numConfigs); 272e41f4b71Sopenharmony_ci ``` 273e41f4b71Sopenharmony_ci In this example, the number of bits in the blue buffer is 6. To use six bits to represent the blue value 200 in the case of 8-bit RGB (ranging from 0 to 255), use the following formula for calculation: 64 x 200/256, where 64 is the maximum value that can be represented by six bits (2^6 = 64). After **eglChooseConfig** is called, the configurations that match the attributes are returned and stored in the **config** array. In the sample code, **config_size** is set to **1**, indicating that the size of the **config** array is 1. Only one set of configurations can be stored, but that's enough. **numconfigs** specifies the number of configurations that match the attributes. In this way, the desired **config** array is obtained. 274e41f4b71Sopenharmony_ci 275e41f4b71Sopenharmony_ci- Use **eglGetConfigs** to query all supported configurations and use **eglGetConfigAttrib** to filter the desired ones. 276e41f4b71Sopenharmony_ci The following describes how to use this method to obtain the desired configurations. 277e41f4b71Sopenharmony_ci 278e41f4b71Sopenharmony_ci ```cpp 279e41f4b71Sopenharmony_ci #include <EGL/egl.h> 280e41f4b71Sopenharmony_ci #include <iostream> 281e41f4b71Sopenharmony_ci #include <vector> 282e41f4b71Sopenharmony_ci int main() { 283e41f4b71Sopenharmony_ci // Initialize EGL. 284e41f4b71Sopenharmony_ci EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 285e41f4b71Sopenharmony_ci eglInitialize(display, nullptr, nullptr); 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci // Obtain all the configurations. 288e41f4b71Sopenharmony_ci EGLint numConfigs; 289e41f4b71Sopenharmony_ci eglGetConfigs(display, nullptr, 0, &numConfigs); 290e41f4b71Sopenharmony_ci std::vector<EGLConfig> configs(numConfigs); 291e41f4b71Sopenharmony_ci eglGetConfigs(display, configs.data(), numConfigs, &numConfigs); 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci // Select a proper configuration. 294e41f4b71Sopenharmony_ci EGLConfig chosenConfig = nullptr; 295e41f4b71Sopenharmony_ci for (const auto& config : configs) { 296e41f4b71Sopenharmony_ci EGLint redSize, greenSize, blueSize; 297e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); 298e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); 299e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); 300e41f4b71Sopenharmony_ci if (redSize == 8 && greenSize == 8 && blueSize == 6) { 301e41f4b71Sopenharmony_ci chosenConfig = config; 302e41f4b71Sopenharmony_ci break; 303e41f4b71Sopenharmony_ci } 304e41f4b71Sopenharmony_ci } 305e41f4b71Sopenharmony_ci 306e41f4b71Sopenharmony_ci // If no configuration is selected, print the error information and exit. 307e41f4b71Sopenharmony_ci if (!chosenConfig) { 308e41f4b71Sopenharmony_ci std::cerr << "Failed to find a suitable EGL configuration." << std::endl; 309e41f4b71Sopenharmony_ci return 1; 310e41f4b71Sopenharmony_ci } 311e41f4b71Sopenharmony_ci return 0; 312e41f4b71Sopenharmony_ci } 313e41f4b71Sopenharmony_ci ``` 314e41f4b71Sopenharmony_ci 315e41f4b71Sopenharmony_ci ```cpp 316e41f4b71Sopenharmony_ci EGLBoolean eglGetConfigs(EGLDisplay display, // Handle to the EGL display connection for which configurations are selected. 317e41f4b71Sopenharmony_ci EGLConfig *configs, // Array for storing the obtained configurations. 318e41f4b71Sopenharmony_ci EGLint config_size, // Size of the configs array. 319e41f4b71Sopenharmony_ci EGLint *num_config); // Number of available configurations. 320e41f4b71Sopenharmony_ci ``` 321e41f4b71Sopenharmony_ci 322e41f4b71Sopenharmony_ci The **eglGetConfigs** function can be used in either of the following ways: 323e41f4b71Sopenharmony_ci 324e41f4b71Sopenharmony_ci - If a null pointer is passed in to **configs**, **EGL_TRUE** is returned and the number of available configurations obtained is saved in **num_config**. In this case, **configs** can be initialized based on the number to store the configurations. For details, see the preceding code. 325e41f4b71Sopenharmony_ci - If **configs** is configured to accept all configurations, all configurations obtained are saved in **configs**. You can filter them as required and store the desired ones. 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci ```cpp 328e41f4b71Sopenharmony_ci // Select a proper configuration. 329e41f4b71Sopenharmony_ci EGLConfig chosenConfig = nullptr; 330e41f4b71Sopenharmony_ci for (const auto& config : configs) { 331e41f4b71Sopenharmony_ci EGLint redSize, greenSize, blueSize; 332e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); 333e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); 334e41f4b71Sopenharmony_ci eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); 335e41f4b71Sopenharmony_ci if (redSize == 8 && greenSize == 8 && blueSize == 6) { 336e41f4b71Sopenharmony_ci chosenConfig = config; 337e41f4b71Sopenharmony_ci break; 338e41f4b71Sopenharmony_ci } 339e41f4b71Sopenharmony_ci } 340e41f4b71Sopenharmony_ci ``` 341e41f4b71Sopenharmony_ci 342e41f4b71Sopenharmony_ci The preceding code snippet traverses each configuration in **configs** and uses **eglGetConfigAttrib** to query the value of a specific attribute in the configuration, save the value in the fourth parameter, check whether the configuration is the desired one, and if yes, save the configuration. If the call is successful, **EGL_TRUE** is returned. Otherwise, **EGL_FALSE** is returned. In the latter case, you can use **eglGetError** to obtain the failure cause. If **EGL_BAD ATTRIBUTE** is returned, the attribute is invalid. 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci ```cpp 345e41f4b71Sopenharmony_ci EGLBoolean eglGetConfigAttrib(EGLDisplay display, // Handle to the EGL display connection for which configurations are selected. 346e41f4b71Sopenharmony_ci EGLConfig config, // EGL configuration to query. 347e41f4b71Sopenharmony_ci EGLint attribute, // Attribute identifier of the EGLint type, indicating the attribute to query. 348e41f4b71Sopenharmony_ci EGLint *value); // Pointer to the variable of the EGLint type, which is used to store the attribute value obtained. 349e41f4b71Sopenharmony_ci ``` 350e41f4b71Sopenharmony_ci 351e41f4b71Sopenharmony_ci 352e41f4b71Sopenharmony_ci### Using eglCreateWindowSurface to Create a Window Surface 353e41f4b71Sopenharmony_ci 354e41f4b71Sopenharmony_ciAfter obtaining the EGL configurations that meet the rendering requirements, use **eglCreateWindowSurface** to create a window surface. 355e41f4b71Sopenharmony_ci```cpp 356e41f4b71Sopenharmony_ciEGLSurface eglCreateWindowSurface(EGLDisplay dpy, // EGL display connection to be associated with the window surface. 357e41f4b71Sopenharmony_ci EGLConfig config, // EGL configuration of the window surface to create. 358e41f4b71Sopenharmony_ci EGLNativeWindowType win, // Parameter of the EGLNativeWindowType type. It is the handle or identifier of the native window and is used to associate with the EGL surface. 359e41f4b71Sopenharmony_ci const EGLint *attrib_list); // Pointer to the EGL attribute list. It specifies the attributes of the window surface. It is an integer array terminating with EGL_NONE. 360e41f4b71Sopenharmony_ci``` 361e41f4b71Sopenharmony_ciThe following values can be passed in to **attrib_list** of **eglCreateWindowSurface**: 362e41f4b71Sopenharmony_ci 363e41f4b71Sopenharmony_ci```cpp 364e41f4b71Sopenharmony_ciEGL_RENDER_BUFFER EGL_SINGLE_BUFFER or EGL_BACK_BUFFER 365e41f4b71Sopenharmony_ciEGL_SINGLE_BUFFER // There is only one render buffer on the EGL surface. After the rendering is complete, the content in the render buffer is directly displayed on the screen. As a result, screen flickering or tearing may occur. 366e41f4b71Sopenharmony_ciEGL_BACK_BUFFER // There are a front buffer and a back buffer. After the rendering is complete, the content in the render buffer is first rendered to the back buffer, and then the content in the back buffer is displayed on the screen by means of buffer swapping. In this way, screen flickering or tearing can be avoided. 367e41f4b71Sopenharmony_ci// The default value is EGL_BACK_BUFFER. If this parameter is set to null, the default value is used. 368e41f4b71Sopenharmony_ci``` 369e41f4b71Sopenharmony_ciThe possible causes of a failure to call **eglCreateWindowSurface** are as follows: 370e41f4b71Sopenharmony_ci 371e41f4b71Sopenharmony_ci- **EGL_BAD_MATCH**: The native window attributes do not match the EGL configuration. This may be because the EGL configuration does not support rendering to the window (the **EGL_SURFACE_TYPE** attribute is not set to **EGL_WINDOW_BIT**). 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci- **EGL_BAD_CONFIG**: The EGL configuration is not supported by the system. 374e41f4b71Sopenharmony_ci 375e41f4b71Sopenharmony_ci- **EGL_BAD_NATIVE_WINDOW**: The native window handle is invalid. 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci- **EGL_BAD_ALLOC**: Resources cannot be created for a new EGL window or there is already an EGL configuration associated with the native window. 378e41f4b71Sopenharmony_ci 379e41f4b71Sopenharmony_ci 380e41f4b71Sopenharmony_ci 381e41f4b71Sopenharmony_ci```cpp 382e41f4b71Sopenharmony_ciEGLint attribList[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE }; 383e41f4b71Sopenharmony_ciEGLSurface surface = eglCreateWindowSurface(display, config, nativeWindow, attribList); 384e41f4b71Sopenharmony_ciif (surface == EGL_NO_SURFACE) { 385e41f4b71Sopenharmony_ci switch (eglGetError()) { 386e41f4b71Sopenharmony_ci case EGL_BAD_MATCH: 387e41f4b71Sopenharmony_ci // Check the window and EGL configuration to determine the compatibility, or check whether the EGL configuration supports rendering to the window. 388e41f4b71Sopenharmony_ci break; 389e41f4b71Sopenharmony_ci case EGL_BAD_CONFIG: 390e41f4b71Sopenharmony_ci // Check whether the EGL configuration is valid. 391e41f4b71Sopenharmony_ci break; 392e41f4b71Sopenharmony_ci case EGL_BAD_NATIVE_WINDOW: 393e41f4b71Sopenharmony_ci // Check whether the EGL native window is valid. 394e41f4b71Sopenharmony_ci break; 395e41f4b71Sopenharmony_ci case EGL_BAD_ALLOC: 396e41f4b71Sopenharmony_ci // Resources are insufficient. Handle and rectify the fault. 397e41f4b71Sopenharmony_ci break; 398e41f4b71Sopenharmony_ci default: 399e41f4b71Sopenharmony_ci // Handle other errors. 400e41f4b71Sopenharmony_ci break; 401e41f4b71Sopenharmony_ci } 402e41f4b71Sopenharmony_ci} 403e41f4b71Sopenharmony_ci``` 404e41f4b71Sopenharmony_ci 405e41f4b71Sopenharmony_ci### Using eglCreateContext to Create a Rendering Context 406e41f4b71Sopenharmony_ci 407e41f4b71Sopenharmony_ciThe **eglCreateContext** function is used to create an EGL rendering context and associate it with a specific display and configuration. You can specify a shared context to share status information with an existing OpenGL context. The parameters in the function are described as follows: 408e41f4b71Sopenharmony_ci 409e41f4b71Sopenharmony_ci```cpp 410e41f4b71Sopenharmony_ciEGLContext eglCreateContext(EGLDisplay display, // Type of the EGL display connection for which the context is to be created. 411e41f4b71Sopenharmony_ci EGLConfig config, // Type of the EGL configuration associated with the context. 412e41f4b71Sopenharmony_ci EGLContext shareContext, // Type of the EGL context whose status information is to be shared with the newly created context. If you do not want to share the status information, pass in EGL_NO_CONTEXT. 413e41f4b71Sopenharmony_ci const EGLint *attribList); // Pointer to the attribute list. It specifies the attributes of the context. An attribute list is a series of attribute-value pairs terminating with EGL_NONE. 414e41f4b71Sopenharmony_ci``` 415e41f4b71Sopenharmony_ciThe value of **attribList** in **eglCreateContext** is as follows: 416e41f4b71Sopenharmony_ci```cpp 417e41f4b71Sopenharmony_ciEGLint contextAttribs[] = { 418e41f4b71Sopenharmony_ci EGL_CONTEXT_CLIENT_VERSION, 3, // Context type related to OpenGL ES version 3. 419e41f4b71Sopenharmony_ci}; 420e41f4b71Sopenharmony_ci``` 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_ciIf **eglCreateContext** fails to create the rendering context, the possible cause is **EGL_BAD_CONFIG**, which means that the EGL configuration is invalid. 423e41f4b71Sopenharmony_ci 424e41f4b71Sopenharmony_ci### Using eglMakeCurrent to Attach the EGL Rendering Context to the EGL Surface 425e41f4b71Sopenharmony_ci 426e41f4b71Sopenharmony_ci```cpp 427e41f4b71Sopenharmony_ciEGLBoolean eglMakeCurrent(EGLDisplay display, // Handle to the EGL display connection. 428e41f4b71Sopenharmony_ci EGLSurface draw, // Handle to the EGL draw surface. 429e41f4b71Sopenharmony_ci EGLSurface read, // Handle to the EGL read surface. It is used to read pixels. Generally, you can set this parameter to the same value as draw. 430e41f4b71Sopenharmony_ci EGLContext context); // Handle to the EGL rendering context to be attached to the surface. 431e41f4b71Sopenharmony_ci``` 432e41f4b71Sopenharmony_ci 433e41f4b71Sopenharmony_ci### Using glViewport to Set the Viewport 434e41f4b71Sopenharmony_ci 435e41f4b71Sopenharmony_ci```cpp 436e41f4b71Sopenharmony_civoid glViewport(GLint x, GLint y, GLsizei width, GLsizei height) 437e41f4b71Sopenharmony_ci``` 438e41f4b71Sopenharmony_ci 439e41f4b71Sopenharmony_ciThe **glViewport** function is used to set the viewport and specify the position and size of the OpenGL ES rendering area in the window. The **x** and **y** parameters specify the coordinates of the lower left corner of the viewport in the window. The **width** and **height** parameters specify the width and height of the viewport. 440e41f4b71Sopenharmony_ci 441e41f4b71Sopenharmony_ci### Using glClearColor to Set the Color Used to Clear the Color Buffer 442e41f4b71Sopenharmony_ci 443e41f4b71Sopenharmony_ci```cpp 444e41f4b71Sopenharmony_civoid glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); 445e41f4b71Sopenharmony_ci``` 446e41f4b71Sopenharmony_ciIn the **glClearColor(0.2f, 0.3f, 0.3f, 1.0f)** function, the color used for clearing the color buffer is set to (0.2, 0.3, 0.3). That is, the red component is 0.2, the green component is 0.3, the blue component is 0.3, and the alpha value is 1.0 (opaque). 447e41f4b71Sopenharmony_ci 448e41f4b71Sopenharmony_ci### Using glClear to Clear Buffers 449e41f4b71Sopenharmony_ci 450e41f4b71Sopenharmony_ci```cpp 451e41f4b71Sopenharmony_civoid glClear(GLbitfield mask); 452e41f4b71Sopenharmony_ci``` 453e41f4b71Sopenharmony_ciThe **glClear** function is used to clear a buffer. The **mask** parameter specifies the buffer to clear. It can be a combination of the following values: 454e41f4b71Sopenharmony_ci- **GL_COLOR_BUFFER_BIT**: clears the color buffer. 455e41f4b71Sopenharmony_ci- **GL_DEPTH_BUFFER_BIT**: clears the depth buffer. 456e41f4b71Sopenharmony_ci- **GL_STENCIL_BUFFER_BIT**: clears the stencil buffer. 457e41f4b71Sopenharmony_ci 458e41f4b71Sopenharmony_ciYou can call **glClear(GL_COLOR_BUFFER_BIT)** to clear the color buffer and fill the buffer with the color set by **glClearColor**. Clearing the color buffer is a common operation before you start frame rendering. This operation ensures that each pixel on the screen is initialized to the specified color value. It is also a mandatory preparation for drawing a new frame, similar to painting a background color on the canvas to start a new painting. 459e41f4b71Sopenharmony_ci 460e41f4b71Sopenharmony_ci### Defining Vertex Data 461e41f4b71Sopenharmony_ci```cpp 462e41f4b71Sopenharmony_ci // Define vertex data. 463e41f4b71Sopenharmony_ci GLfloat vertices[] = { 464e41f4b71Sopenharmony_ci -0.5f, -0.5f, 0.0f, // Lower left corner. 465e41f4b71Sopenharmony_ci 0.5f, -0.5f, 0.0f, // Lower right corner. 466e41f4b71Sopenharmony_ci 0.0f, 0.5f, 0.0f // Top. 467e41f4b71Sopenharmony_ci }; 468e41f4b71Sopenharmony_ci``` 469e41f4b71Sopenharmony_ci 470e41f4b71Sopenharmony_ciIn OpenGL, Normalized Device Coordinates (NDCs) are usually used to represent the position of a vertex. NDC is a coordinate space in the screen. In this space, the lower left corner is (-1, -1), and the upper right corner is (1, 1). This coordinate space makes the position of the vertex independent of the size and aspect ratio of the screen. 471e41f4b71Sopenharmony_ci### Managing Vertex Data 472e41f4b71Sopenharmony_ci 473e41f4b71Sopenharmony_ciYou can save the vertex data on the GPU to minimize data transfer between the CPU and GPU. 474e41f4b71Sopenharmony_ci 475e41f4b71Sopenharmony_ci```cpp 476e41f4b71Sopenharmony_ciGLuint VAO[1]; 477e41f4b71Sopenharmony_ciGLuint VBO; 478e41f4b71Sopenharmony_ciglGenVertexArrays(1, VAO); // Generate Vertex Array Object (VAO) names. In this example, one VBO is generated. 479e41f4b71Sopenharmony_ciglBindVertexArray(VAO[0]); // Bind the VAO to the current OpenGL context. 480e41f4b71Sopenharmony_ciglGenBuffers(1, &VBO); // Generate VBO names. The first parameter indicates the number of VBO names to generate, and it is set to 1 in this example. The passed-in value &VBO is the pointer to the array that stores the generated VBO names. 481e41f4b71Sopenharmony_ciglBindBuffer(GL_ARRAY_BUFFER, VBO); // void glBindBuffer(GLenum target, GLuint buffer), where target indicates the buffer to be bound and can be one of the following values: 482e41f4b71Sopenharmony_ci // GL_ARRAY_BUFFER: stores vertex attribute data. 483e41f4b71Sopenharmony_ci // GL_ELEMENT_ARRAY_BUFFER: stores index data and other data. 484e41f4b71Sopenharmony_ci // buffer is the name of the VBO to be bound. 485e41f4b71Sopenharmony_ciglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 486e41f4b71Sopenharmony_ci``` 487e41f4b71Sopenharmony_ci```cpp 488e41f4b71Sopenharmony_civoid glBufferData(GLenum target, // target specifies the type of the buffer object. The value can be one of the following: 489e41f4b71Sopenharmony_ci // GL_ARRAY_BUFFER: stores vertex attribute data. 490e41f4b71Sopenharmony_ci // GL_ELEMENT_ARRAY_BUFFER: stores index data. 491e41f4b71Sopenharmony_ci GLsizeiptr size, // Size (in bytes) of the buffer to be allocated. 492e41f4b71Sopenharmony_ci const GLvoid* data, // Pointer to the initial data to be copied to the buffer. 493e41f4b71Sopenharmony_ci GLenum usage); // Expected buffer usage mode. The value can be one of the following: 494e41f4b71Sopenharmony_ci // GL_STATIC_DRAW: The data is not or almost not modified and is used many times as the source for the drawing commands. 495e41f4b71Sopenharmony_ci // GL_DYNAMIC_DRAW: The data is frequently modified and used many times as the source for the drawing commands. 496e41f4b71Sopenharmony_ci // GL_STREAM_DRAW: The data is modified and is seldom used as the source for the drawing commands. 497e41f4b71Sopenharmony_ci``` 498e41f4b71Sopenharmony_ci 499e41f4b71Sopenharmony_ciOnce the **glBufferData** function is called, the data is copied to the OpenGL buffer object and stored in the GPU memory. This means that data can be efficiently accessed and processed on the GPU without frequent data transfer with the CPU memory. 500e41f4b71Sopenharmony_ci 501e41f4b71Sopenharmony_ci```cpp 502e41f4b71Sopenharmony_ci const char* vertexShaderSource = R"( 503e41f4b71Sopenharmony_ci #version 320 es // Shader of OpenGL ES 3.2 is used. 504e41f4b71Sopenharmony_ci precision mediump float; // The floating point number uses the medium precision. 505e41f4b71Sopenharmony_ci layout (location = 0) in vec3 aPos; // Vertex attribute variable. The variable name is aPos, the type is vec3, and the index in the vertex shader is 0. This variable receives the vertex data from the VBO. Each time the vertex shader is called, aPos is set to the position of the currently processed vertex. (The data is obtained from the VBO and stored in the GPU.) 506e41f4b71Sopenharmony_ci void main() { 507e41f4b71Sopenharmony_ci // gl_Position, a built-in variable of OpenGL ES, specifies the final position of each vertex. The position is the coordinates in the clip space after perspective projection transformation. 508e41f4b71Sopenharmony_ci // After a value is assigned to gl_Position in the vertex shader, the rendering pipeline further processes the vertex and projects the vertex to the two-dimensional coordinates on the screen. 509e41f4b71Sopenharmony_ci // When w is a non-zero value, perspective division is performed on the vertex coordinates. That is, (x/w, y/w, z/w) in (x, y, z, w) is used as the final coordinates in the clip space. 510e41f4b71Sopenharmony_ci // Therefore, when the value of w is 1.0, perspective division does not change the coordinates. 511e41f4b71Sopenharmony_ci gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); 512e41f4b71Sopenharmony_ci } 513e41f4b71Sopenharmony_ci )"; 514e41f4b71Sopenharmony_ci``` 515e41f4b71Sopenharmony_ci- Fragment is an element generated by rasterization. It represents a potential screen pixel, including all information related to the pixel, such as the color, depth, and stencil value. Each fragment is processed by a fragment shader, which also determines whether to write the fragment to the frame buffer. 516e41f4b71Sopenharmony_ci- A fragment shader runs on each fragment. In this example, it is used to calculate the final color value of the fragment. It can access the interpolated vertex data and perform complex operations such as lighting calculation and texture sampling. 517e41f4b71Sopenharmony_ci 518e41f4b71Sopenharmony_ci```cpp 519e41f4b71Sopenharmony_ci 520e41f4b71Sopenharmony_ciconst char* fragmentShaderSource = R"( 521e41f4b71Sopenharmony_ci #version 320 es // Shader of OpenGL ES 3.2 is used. 522e41f4b71Sopenharmony_ci precision mediump float; // The floating point number uses the medium precision. 523e41f4b71Sopenharmony_ci out vec4 FragColor; // Color of the output fragment. 524e41f4b71Sopenharmony_ci 525e41f4b71Sopenharmony_ci void main() { 526e41f4b71Sopenharmony_ci // Set the color of each fragment to vec4(1.0f, 0.5f, 0.2f, 1.0f), 527e41f4b71Sopenharmony_ci // indicating the red, green, blue, and alpha values, respectively. 528e41f4b71Sopenharmony_ci // This means that the output color is light orange, completely opaque. 529e41f4b71Sopenharmony_ci // The color here is not obtained from the vertex shader through rasterization by linear interpolation. It is directly assigned. 530e41f4b71Sopenharmony_ci FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); 531e41f4b71Sopenharmony_ci } 532e41f4b71Sopenharmony_ci)"; 533e41f4b71Sopenharmony_ci 534e41f4b71Sopenharmony_ci``` 535e41f4b71Sopenharmony_ciIn the OpenGL ES rendering pipeline, the following steps describe the entire process from vertex data to pixel output: 536e41f4b71Sopenharmony_ci 537e41f4b71Sopenharmony_ci1. Vertex shader processing 538e41f4b71Sopenharmony_ci 539e41f4b71Sopenharmony_ci The vertex data in the buffer is passed into the vertex shader program and undergone the following processing: 540e41f4b71Sopenharmony_ci 541e41f4b71Sopenharmony_ci - Matrix transformation: uses the model view (MV) matrix and projection matrix to transform the vertex position. 542e41f4b71Sopenharmony_ci 543e41f4b71Sopenharmony_ci - Lighting calculation: calculates the color or other attributes of vertices based on the lighting formula. 544e41f4b71Sopenharmony_ci 545e41f4b71Sopenharmony_ci2. Primitive assembly 546e41f4b71Sopenharmony_ci 547e41f4b71Sopenharmony_ci In the primitive assembly phase, the vertex data is assembled into geometric primitive, such as points, line segments, or triangles. 548e41f4b71Sopenharmony_ci 549e41f4b71Sopenharmony_ci3. Rasterization 550e41f4b71Sopenharmony_ci 551e41f4b71Sopenharmony_ci Rasterization is performed to convert a geometric primitive (for example, a triangle) into a set of pixels on the screen. This process includes interpolation. Specifically, if a color or other attributes are set for a vertex, linear interpolation is performed on these attributes in the rasterization phase to generate fragment (pixel) data. 552e41f4b71Sopenharmony_ci 553e41f4b71Sopenharmony_ci4. Fragment shader processing 554e41f4b71Sopenharmony_ci 555e41f4b71Sopenharmony_ci The fragment data output by rasterization is used as the input variable of the fragment shader. The following operations are carried out in the fragment shader: 556e41f4b71Sopenharmony_ci 557e41f4b71Sopenharmony_ci - Lighting calculation: calculates the lighting effect of a fragment. 558e41f4b71Sopenharmony_ci 559e41f4b71Sopenharmony_ci - Texture sampling: obtains color data from textures. 560e41f4b71Sopenharmony_ci 561e41f4b71Sopenharmony_ci - Color mixing: generates new colors, depths, and screen coordinates based on lighting and texture data. 562e41f4b71Sopenharmony_ci 563e41f4b71Sopenharmony_ci5. Fragment-by-fragment processing 564e41f4b71Sopenharmony_ci 565e41f4b71Sopenharmony_ci The output of the fragment shader is then undergone fragment-by-fragment processing as follows: 566e41f4b71Sopenharmony_ci 567e41f4b71Sopenharmony_ci - Pixel ownership test: determines whether the fragment belongs to the current pixel area to draw. 568e41f4b71Sopenharmony_ci 569e41f4b71Sopenharmony_ci - Scissor test: determines whether the fragment is in the visible area. 570e41f4b71Sopenharmony_ci 571e41f4b71Sopenharmony_ci - Stencil test: uses the stencil buffer for test. 572e41f4b71Sopenharmony_ci 573e41f4b71Sopenharmony_ci - Depth-buffer test: compares the depth values of the fragment to determine whether it visible. 574e41f4b71Sopenharmony_ci 575e41f4b71Sopenharmony_ci - Blending: combines the newly calculated color with the existing color in the frame buffer. 576e41f4b71Sopenharmony_ci 577e41f4b71Sopenharmony_ci - Dithering: reduces color quantization errors by applying small, random, or ordered noise to the original image to distribute these quantization errors. 578e41f4b71Sopenharmony_ci 579e41f4b71Sopenharmony_ci6. Writing the frame to the buffer 580e41f4b71Sopenharmony_ci 581e41f4b71Sopenharmony_ci After all the preceding tests and processing, the final fragment data is written into the frame buffer and displayed as an image on the screen. 582e41f4b71Sopenharmony_ci 583e41f4b71Sopenharmony_ci### Creating and Using a Shader Program 584e41f4b71Sopenharmony_ci 585e41f4b71Sopenharmony_ci```cpp 586e41f4b71Sopenharmony_ciGLuint vertexShader, fragmentShader, shaderProgram; 587e41f4b71Sopenharmony_ci// Create a vertex shader. 588e41f4b71Sopenharmony_civertexShader = glCreateShader(GL_VERTEX_SHADER); 589e41f4b71Sopenharmony_ciglShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); 590e41f4b71Sopenharmony_ciglCompileShader(vertexShader); 591e41f4b71Sopenharmony_ci 592e41f4b71Sopenharmony_ci// Create a fragment shader. 593e41f4b71Sopenharmony_cifragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 594e41f4b71Sopenharmony_ciglShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); 595e41f4b71Sopenharmony_ciglCompileShader(fragmentShader); 596e41f4b71Sopenharmony_ci 597e41f4b71Sopenharmony_ci// Create a shader program. 598e41f4b71Sopenharmony_cishaderProgram = glCreateProgram(); 599e41f4b71Sopenharmony_ciglAttachShader(shaderProgram, vertexShader); 600e41f4b71Sopenharmony_ciglAttachShader(shaderProgram, fragmentShader); 601e41f4b71Sopenharmony_ciglLinkProgram(shaderProgram); 602e41f4b71Sopenharmony_ci 603e41f4b71Sopenharmony_ci// Use the shader program. 604e41f4b71Sopenharmony_ciglUseProgram(shaderProgram); 605e41f4b71Sopenharmony_ci``` 606e41f4b71Sopenharmony_ci 607e41f4b71Sopenharmony_ci```cpp 608e41f4b71Sopenharmony_ciGLuint glCreateShader(GLenum shaderType); 609e41f4b71Sopenharmony_ci``` 610e41f4b71Sopenharmony_ciThe **glCreateShader** function is used to create a shader object of a specified type and return a handle to the object. The **shaderType** parameter specifies the type of shader to create, which can be **GL_VERTEX_SHADER** (vertex shader) or **GL_FRAGMENT_SHADER** (fragment shader). 611e41f4b71Sopenharmony_ci 612e41f4b71Sopenharmony_ci```cpp 613e41f4b71Sopenharmony_civoid glShaderSource(GLuint shader, GLsizei count, const GLchar \**string, const GLint *length); 614e41f4b71Sopenharmony_ci``` 615e41f4b71Sopenharmony_ci 616e41f4b71Sopenharmony_ciThe **glShaderSource** function is used to set the source code of the shader object. The following parameters are available in the function: 617e41f4b71Sopenharmony_ci 618e41f4b71Sopenharmony_ci- **shader**: identifier of the shader object for which the source code is set. 619e41f4b71Sopenharmony_ci- **count**: number of source code strings. 620e41f4b71Sopenharmony_ci- **string**: array of pointers to the source code strings. 621e41f4b71Sopenharmony_ci- **length**: pointer to an integer array that contains the length of each source code string. The value can be a null pointer, indicating that each string ends with **null**. 622e41f4b71Sopenharmony_ci 623e41f4b71Sopenharmony_ci```cpp 624e41f4b71Sopenharmony_civoid glCompileShader(GLuint shader); 625e41f4b71Sopenharmony_ci``` 626e41f4b71Sopenharmony_ci 627e41f4b71Sopenharmony_ciThe **glCompileShader** function is used to compile a shader object, where the **shader** parameter is the identifier of the target shader object. 628e41f4b71Sopenharmony_ci 629e41f4b71Sopenharmony_ci```cpp 630e41f4b71Sopenharmony_ciGLuint glCreateProgram(void); 631e41f4b71Sopenharmony_ci``` 632e41f4b71Sopenharmony_ci 633e41f4b71Sopenharmony_ciThe **glCreateProgram** function is used to create a shader program object and return the object identifier. 634e41f4b71Sopenharmony_ci 635e41f4b71Sopenharmony_ci```cpp 636e41f4b71Sopenharmony_civoid glAttachShader(GLuint program, GLuint shader); 637e41f4b71Sopenharmony_ci``` 638e41f4b71Sopenharmony_ci 639e41f4b71Sopenharmony_ciThe **glAttachShader** function is used to attach a shader object to a shader program object. The **program** parameter is the identifier of the target shader program object, and the **shader** parameter is the identifier of the target shader object. 640e41f4b71Sopenharmony_ci 641e41f4b71Sopenharmony_ci```cpp 642e41f4b71Sopenharmony_civoid glLinkProgram(GLuint program); 643e41f4b71Sopenharmony_ci``` 644e41f4b71Sopenharmony_ci 645e41f4b71Sopenharmony_ciThe **glLinkProgram** function is used to link a shader program object, that is, to link the shader attached to the program object to an executable rendering pipeline. The **program** parameter is the identifier of the target shader program object. 646e41f4b71Sopenharmony_ci 647e41f4b71Sopenharmony_ciAfter the shader program is linked, OpenGL merges the code in each individual shader object into an executable rendering pipeline, performs connector optimization to optimize the performance of the rendering pipeline, and binds the **Uniform** variable to the information about the Uniform block. 648e41f4b71Sopenharmony_ci 649e41f4b71Sopenharmony_ci```cpp 650e41f4b71Sopenharmony_civoid glUseProgram(GLuint program); 651e41f4b71Sopenharmony_ci``` 652e41f4b71Sopenharmony_ciThe **glUseProgram** function is used to activate a shader program object. After **glUseProgram** is called, all rendering calls are processed using the activated shader program. 653e41f4b71Sopenharmony_ci 654e41f4b71Sopenharmony_ciYou can use the following code to check whether the call of **glCompileShader** is normal: 655e41f4b71Sopenharmony_ci 656e41f4b71Sopenharmony_ci```cpp 657e41f4b71Sopenharmony_ci// Compile the shader. 658e41f4b71Sopenharmony_ciglCompileShader(shader); 659e41f4b71Sopenharmony_ci 660e41f4b71Sopenharmony_ci// Check the compilation status. 661e41f4b71Sopenharmony_ciglGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 662e41f4b71Sopenharmony_ci 663e41f4b71Sopenharmony_ciif (!compiled) 664e41f4b71Sopenharmony_ci{ 665e41f4b71Sopenharmony_ci GLint infoLen = 0; 666e41f4b71Sopenharmony_ci 667e41f4b71Sopenharmony_ci // Obtain the length of the shader information log. 668e41f4b71Sopenharmony_ci glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 669e41f4b71Sopenharmony_ci 670e41f4b71Sopenharmony_ci if ( infoLen > 1 ) 671e41f4b71Sopenharmony_ci { 672e41f4b71Sopenharmony_ci // Allocate the memory for storing the information log. 673e41f4b71Sopenharmony_ci char *infoLog = malloc(sizeof(char) * infoLen); 674e41f4b71Sopenharmony_ci 675e41f4b71Sopenharmony_ci // Obtain and print the shader information log. 676e41f4b71Sopenharmony_ci glGetShaderInfoLog(shader, infoLen, NULL, infoLog); 677e41f4b71Sopenharmony_ci esLogMessage("Error compiling shader:\n%s\n", infoLog); 678e41f4b71Sopenharmony_ci 679e41f4b71Sopenharmony_ci // Release the allocated memory. 680e41f4b71Sopenharmony_ci free(infoLog); 681e41f4b71Sopenharmony_ci } 682e41f4b71Sopenharmony_ci 683e41f4b71Sopenharmony_ci // Delete the shader that fails to be compiled. 684e41f4b71Sopenharmony_ci glDeleteShader(shader); 685e41f4b71Sopenharmony_ci return 0; 686e41f4b71Sopenharmony_ci} 687e41f4b71Sopenharmony_ci``` 688e41f4b71Sopenharmony_ci 689e41f4b71Sopenharmony_ciYou can use the following code to check whether the call of **glLinkProgram** is normal: 690e41f4b71Sopenharmony_ci 691e41f4b71Sopenharmony_ci```cpp 692e41f4b71Sopenharmony_ci// Link the program object. 693e41f4b71Sopenharmony_ciglLinkProgram(programObject); 694e41f4b71Sopenharmony_ci 695e41f4b71Sopenharmony_ci// Check the linking status. 696e41f4b71Sopenharmony_ciglGetProgramiv(programObject, GL_LINK_STATUS, &linked); 697e41f4b71Sopenharmony_ci 698e41f4b71Sopenharmony_ciif (!linked) 699e41f4b71Sopenharmony_ci{ 700e41f4b71Sopenharmony_ci GLint infoLen = 0; 701e41f4b71Sopenharmony_ci 702e41f4b71Sopenharmony_ci // Obtain the length of the program object information log. 703e41f4b71Sopenharmony_ci glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen); 704e41f4b71Sopenharmony_ci 705e41f4b71Sopenharmony_ci if (infoLen > 1) 706e41f4b71Sopenharmony_ci { 707e41f4b71Sopenharmony_ci // Allocate the memory for storing the information log. 708e41f4b71Sopenharmony_ci char *infoLog = malloc(sizeof(char) * infoLen); 709e41f4b71Sopenharmony_ci 710e41f4b71Sopenharmony_ci // Obtain and print the information log of the program object. 711e41f4b71Sopenharmony_ci glGetProgramInfoLog(programObject, infoLen, NULL, infoLog); 712e41f4b71Sopenharmony_ci esLogMessage("Error linking program:\n%s\n", infoLog); 713e41f4b71Sopenharmony_ci 714e41f4b71Sopenharmony_ci // Release the allocated memory. 715e41f4b71Sopenharmony_ci free(infoLog); 716e41f4b71Sopenharmony_ci } 717e41f4b71Sopenharmony_ci 718e41f4b71Sopenharmony_ci // Delete the program object that fails to be linked. 719e41f4b71Sopenharmony_ci glDeleteProgram(programObject); 720e41f4b71Sopenharmony_ci return FALSE; 721e41f4b71Sopenharmony_ci} 722e41f4b71Sopenharmony_ci``` 723e41f4b71Sopenharmony_ci 724e41f4b71Sopenharmony_ci### Determining the Configuration of the Vertex Attribute Array 725e41f4b71Sopenharmony_ci 726e41f4b71Sopenharmony_ciDetermine the layout and format of the vertex attributes in the buffer. 727e41f4b71Sopenharmony_ci 728e41f4b71Sopenharmony_ci```cpp 729e41f4b71Sopenharmony_civoid glVertexAttribPointer(GLuint index, // Start index of the vertex array. The index is bound to the attribute variable in the vertex shader. (layout (location = 0) in vec3 aPos;) 730e41f4b71Sopenharmony_ci GLint size, // Number of components of each vertex attribute. 731e41f4b71Sopenharmony_ci GLenum type, // Type of each component. 732e41f4b71Sopenharmony_ci GLboolean normalized, // Whether to map the vertex data to [0, 1] or [-1, 1] when accessing the data. 733e41f4b71Sopenharmony_ci GLsizei stride, // Stride between the vertex attributes. For precision arrangement, set this parameter to 0. 734e41f4b71Sopenharmony_ci const void *offset); // Offset of the attribute in the buffer. It is the position from which data reading starts in the buffer. 735e41f4b71Sopenharmony_ci``` 736e41f4b71Sopenharmony_ci 737e41f4b71Sopenharmony_ci```cpp 738e41f4b71Sopenharmony_civoid glEnableVertexAttribArray(GLuint index); 739e41f4b71Sopenharmony_ci``` 740e41f4b71Sopenharmony_ci 741e41f4b71Sopenharmony_ciThe **glEnableVertexAttribArray** function is used to enable an array of vertex attributes with a specified index. For example, call **glEnableVertexAttribArray(0)** to enable an array of vertex attributes with index 0. This array is associated with layout (location = 0) in vec3 aPos in the vertex shader program. 742e41f4b71Sopenharmony_ci 743e41f4b71Sopenharmony_ciIn the sample code, the first parameter **index** of **glVertexAttribPointer** corresponds to **aPos** in the vertex shader, that is, position 0. The other parameters set the format of the vertex attribute, telling OpenGL that the attribute contains three components (x, y, and z), the data type is GL_FLOAT, and the first attribute of each vertex starts from offset 0. 744e41f4b71Sopenharmony_ci 745e41f4b71Sopenharmony_ciThe **glBindBuffer** function binds the current VBO, **glBufferData** transfers vertex data to the GPU, and **glVertexAttribPointer** describes how to interpret the data. When using the VBO, vertex data is usually stored in a buffer. It is not automatically passed to the vertex shader. Therefore, the vertex attribute pointer is required to tell OpenGL ES how to interpret the data. The **glEnableVertexAttribArray** function is used to enable an array of vertex attributes at a specified position. For example, to enable an array of vertex properties at position 0, you can call **glEnableVertexAttribArray(0)**. 746e41f4b71Sopenharmony_ci 747e41f4b71Sopenharmony_ci 748e41f4b71Sopenharmony_ci### Drawing and Displaying Graphics 749e41f4b71Sopenharmony_ci 750e41f4b71Sopenharmony_ci```cpp 751e41f4b71Sopenharmony_civoid glDrawArrays(GLenum mode, // Type of the graphic to draw. For example, GL_TRIANGLES indicates that a triangle will be drawn. 752e41f4b71Sopenharmony_ci GLint first, // Start index of the vertex array to draw. 753e41f4b71Sopenharmony_ci GLsizei count // Number of vertices to draw. 754e41f4b71Sopenharmony_ci ); 755e41f4b71Sopenharmony_ci``` 756e41f4b71Sopenharmony_ci 757e41f4b71Sopenharmony_ciThe **glDrawArrays** function is used to draw graphics based on the currently bound vertex array, vertex attributes, and other settings. 758e41f4b71Sopenharmony_ci 759e41f4b71Sopenharmony_ci```cpp 760e41f4b71Sopenharmony_ciEGLBoolean eglSwapBuffers(EGLDisplay dpy, // EGL display connection. 761e41f4b71Sopenharmony_ci EGLSurface surface); // EGL surface whose buffers are to be swapped. 762e41f4b71Sopenharmony_ci``` 763e41f4b71Sopenharmony_ci 764e41f4b71Sopenharmony_ciThe **eglSwapBuffers** function is used to swap the front and back buffers and display the rendering result on the screen. 765