void WinEGLView::CreateContext() { EGLint contextAttributes[32]; uint i = 0; switch (mGLESVersion) { case 2: contextAttributes[i++] = EGL_CONTEXT_CLIENT_VERSION; contextAttributes[i++] = 2; break; case 3: contextAttributes[i++] = EGL_CONTEXT_CLIENT_VERSION; contextAttributes[i++] = 3; break; case 1: default: contextAttributes[i++] = EGL_CONTEXT_CLIENT_VERSION; contextAttributes[i++] = 1; break; } contextAttributes[i] = EGL_NONE; mEGLContext = eglCreateContext(mEGLDisplay, mEGLConfig, nullptr, contextAttributes); MEDUSA_ASSERT_NOT_EQUAL(mEGLContext, EGL_NO_CONTEXT, ""); MEDUSA_ASSERT_FALSE(GetEGLError(), ""); }
static int CreateTextureFromHandle(EGLDisplay egl_display, buffer_handle_t handle, AutoEGLImageAndGLTexture *out) { EGLImageKHR image = eglCreateImageKHR( egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX, (EGLClientBuffer)handle, NULL /* no attribs */); if (image == EGL_NO_IMAGE_KHR) { ALOGE("Failed to make image %s %p", GetEGLError(), handle); return -EINVAL; } GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, 0); out->image.reset(image); out->texture.reset(texture); return 0; }
static int EGLFenceWait(EGLDisplay egl_display, int acquireFenceFd) { int ret = 0; EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, acquireFenceFd, EGL_NONE}; EGLSyncKHR egl_sync = eglCreateSyncKHR(egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (egl_sync == EGL_NO_SYNC_KHR) { ALOGE("Failed to make EGLSyncKHR from acquireFenceFd: %s", GetEGLError()); close(acquireFenceFd); return 1; } EGLint success = eglWaitSyncKHR(egl_display, egl_sync, 0); if (success == EGL_FALSE) { ALOGE("Failed to wait for acquire: %s", GetEGLError()); ret = 1; } eglDestroySyncKHR(egl_display, egl_sync); return ret; }
void WinEGLView::CreateSurface() { EGLint surfaceAttributes[16]; uint i = 0; surfaceAttributes[i++] = EGL_NONE; if (mIsNeedPixmap) { mEGLSurface = eglCreatePixmapSurface(mEGLDisplay, mEGLConfig, mBitmapPixmap, surfaceAttributes); } else { mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mEGLNativeWindow, surfaceAttributes); if (mEGLSurface == EGL_NO_SURFACE) { eglGetError(); // Clear error mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, nullptr, surfaceAttributes); } } MEDUSA_ASSERT_NOT_EQUAL(mEGLSurface, EGL_NO_SURFACE, ""); MEDUSA_ASSERT_FALSE(GetEGLError(), ""); }
bool WinEGLView::Initialize() { RETURN_FALSE_IF_FALSE(BaseRenderView::Initialize()); MEDUSA_ASSERT_TRUE(mParent->IsA<IWindow>(), ""); WinWindow* window = (WinWindow*)(INode*)mParent; EGLNativeWindowType eglNativeWindow = window->WindowHandle(); mEGLNativeWindow = eglNativeWindow; mEGLNativeDisplay = EGL_DEFAULT_DISPLAY; mEGLDisplay = EGL_NO_DISPLAY; mEGLConfig = 0; mEGLSurface = EGL_NO_SURFACE; mEGLContext = EGL_NO_CONTEXT; mPixmapDisplay = 0; mBitmapPixmap = 0; mBitmapPixmapOld = 0; /* Step 0 - Create a NativeWindowType that we can use for OpenGL ES output */ /* Step 1 - Get the default display. EGL uses the concept of a "display" which in most environments corresponds to a single physical screen. Since we usually want to draw to the main screen or only have a single screen to begin with, we let EGL pick the default display. Querying other displays is platform specific. */ mEGLNativeDisplay = GetDC(mEGLNativeWindow); mEGLDisplay = eglGetDisplay(mEGLNativeDisplay); if (mEGLDisplay == EGL_NO_DISPLAY) { mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); } MEDUSA_ASSERT_NOT_EQUAL(mEGLDisplay, EGL_NO_DISPLAY, ""); if (mIsNeedPixmap) { mPixmapDisplay = CreateCompatibleDC(mEGLNativeDisplay); Size2F screenSize = ResolutionAdapter::Instance().WinSize(); mBitmapPixmap = CreateCompatibleBitmap(mEGLNativeDisplay, (uint)screenSize.Width, (uint)screenSize.Height); } /* Step 2 - Initialize EGL. EGL has to be initialized with the display obtained in the previous step. We cannot use other EGL functions except eglGetDisplay and eglGetError before eglInitialize has been called. If we're not interested in the EGL version number we can just pass nullptr for the second and third parameters. */ EGLint majorVersion, minorVersion; EGLBoolean result = eglInitialize(mEGLDisplay, &majorVersion, &minorVersion); MEDUSA_ASSERT_NOT_ZERO(result, ""); //ASSERT_NOT_EQUAL(majorVersion,1); /* Step 3 - Specify the required configuration attributes. An EGL "configuration" describes the pixel format and type of surfaces that can be used for drawing. For now we just want to use a 16 bit RGB surface that is a Window surface, i.e. it will be visible on screen. The list has to contain key/value pairs, terminated with EGL_NONE. */ eglBindAPI(EGL_OPENGL_ES_API); MEDUSA_ASSERT_FALSE(GetEGLError(), ""); /* Step 4 - Find a config that matches all requirements. eglChooseConfig provides a list of all available configurations that meet or exceed the requirements given as the second argument. In most cases we just want the first config that meets all criteria, so we can limit the number of configs returned to 1. */ mEGLConfig = ChooseConfig(); /* Step 5 - Create a surface to draw to. Use the config picked in the previous step and the native window handle when available to create a window surface. A window surface is one that will be visible on screen inside the native display (or full screen if there is no windowing system). Pixmaps and pbuffers are surfaces which only exist in off-screen memory. */ CreateSurface(); /* Step 6 - Create a context. EGL has to create a context for OpenGL ES. Our OpenGL ES resources like textures will only be valid inside this context (or shared contexts) */ CreateContext(); /* Step 7 - Bind the context to the current thread and use our window surface for drawing and reading. Contexts are bound to a thread. This means you don't have to worry about other threads and processes interfering with your OpenGL ES application. We need to specify a surface that will be the target of all subsequent drawing operations, and one that will be the source of read operations. They can be the same surface. */ //ASSERT_NOT_EQUAL(eglSurface,EGL_NO_SURFACE,0); eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext); MEDUSA_ASSERT_FALSE(GetEGLError(), ""); /* Step 8 - Draw something with OpenGL ES. At this point everything is initialized and we're ready to use OpenGL ES to draw something on the screen. */ if (mIsNeedPixmap) { mBitmapPixmapOld = (EGLNativePixmapType)SelectObject(mPixmapDisplay, mBitmapPixmap); } //SetForegroundWindow(mEGLNativeWindow); RenderEngine::Instance().Initialize(); return true; }
int GLWorker::Compositor::Composite(hwc_layer_1 *layers, size_t num_layers, sp<GraphicBuffer> framebuffer) { ATRACE_CALL(); int ret = 0; size_t i; std::vector<AutoEGLImageAndGLTexture> layer_textures; std::vector<RenderingCommand> commands; if (num_layers == 0) { return -EALREADY; } GLint frame_width = framebuffer->getWidth(); GLint frame_height = framebuffer->getHeight(); EGLSyncKHR finished_sync; AutoEGLImageKHR egl_fb_image( eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)framebuffer->getNativeBuffer(), NULL /* no attribs */), EGLImageDeleter(egl_display_)); if (egl_fb_image.get() == EGL_NO_IMAGE_KHR) { ALOGE("Failed to make image from target buffer: %s", GetEGLError()); return -EINVAL; } GLuint gl_fb_tex; glGenTextures(1, &gl_fb_tex); AutoGLTexture gl_fb_tex_auto(gl_fb_tex); glBindTexture(GL_TEXTURE_2D, gl_fb_tex); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)egl_fb_image.get()); glBindTexture(GL_TEXTURE_2D, 0); GLuint gl_fb; glGenFramebuffers(1, &gl_fb); AutoGLFramebuffer gl_fb_auto(gl_fb); glBindFramebuffer(GL_FRAMEBUFFER, gl_fb); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_fb_tex, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Failed framebuffer check for created target buffer: %s", GetGLFramebufferError()); return -EINVAL; } for (i = 0; i < num_layers; i++) { const struct hwc_layer_1 *layer = &layers[i]; if (ret) { if (layer->acquireFenceFd >= 0) close(layer->acquireFenceFd); continue; } layer_textures.emplace_back(egl_display_); ret = CreateTextureFromHandle(egl_display_, layer->handle, &layer_textures.back()); if (!ret) { ret = EGLFenceWait(egl_display_, layer->acquireFenceFd); } if (ret) { layer_textures.pop_back(); ret = -EINVAL; } } if (ret) return ret; ConstructCommands(layers, num_layers, &commands); glViewport(0, 0, frame_width, frame_height); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_.get()); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)(sizeof(float) * 2)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnable(GL_SCISSOR_TEST); for (const RenderingCommand &cmd : commands) { if (cmd.texture_count <= 0) { continue; } // TODO(zachr): handle the case of too many overlapping textures for one // area by falling back to rendering as many layers as possible using // multiple blending passes. if (cmd.texture_count > blend_programs_.size()) { ALOGE("Too many layers to render in one area"); continue; } GLint program = blend_programs_[cmd.texture_count - 1].get(); glUseProgram(program); GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport"); GLint gl_tex_loc = glGetUniformLocation(program, "uLayerTextures"); GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop"); GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha"); glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width, cmd.bounds[1] / (float)frame_height, (cmd.bounds[2] - cmd.bounds[0]) / (float)frame_width, (cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height); for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) { const RenderingCommand::TextureSource &src = cmd.textures[src_index]; glUniform1f(gl_alpha_loc + src_index, src.alpha); glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0], src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0], src.crop_bounds[3] - src.crop_bounds[1]); glUniform1i(gl_tex_loc + src_index, src_index); glActiveTexture(GL_TEXTURE0 + src_index); glBindTexture(GL_TEXTURE_2D, layer_textures[src.texture_index].texture.get()); } glScissor(cmd.bounds[0], cmd.bounds[1], cmd.bounds[2] - cmd.bounds[0], cmd.bounds[3] - cmd.bounds[1]); glDrawArrays(GL_TRIANGLES, 0, 3); for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) { glActiveTexture(GL_TEXTURE0 + src_index); glBindTexture(GL_TEXTURE_2D, 0); } } glDisable(GL_SCISSOR_TEST); glActiveTexture(GL_TEXTURE0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glUseProgram(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); return ret; }
GLWorker::Compositor::~Compositor() { if (egl_display_ != EGL_NO_DISPLAY && egl_ctx_ != EGL_NO_CONTEXT) if (eglDestroyContext(egl_display_, egl_ctx_) == EGL_FALSE) ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError()); }
int GLWorker::Compositor::Init() { int ret = 0; const char *egl_extensions; const char *gl_extensions; EGLint num_configs; EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE}; EGLConfig egl_config; // clang-format off const GLfloat verts[] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 2.0f, 2.0f, 0.0f, 2.0f, 0.0f }; // clang-format on const EGLint config_attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_NONE}; const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (egl_display_ == EGL_NO_DISPLAY) { ALOGE("Failed to get egl display"); return 1; } if (!eglInitialize(egl_display_, NULL, NULL)) { ALOGE("Failed to initialize egl: %s", GetEGLError()); return 1; } egl_extensions = eglQueryString(egl_display_, EGL_EXTENSIONS); // These extensions are all technically required but not always reported due // to meta EGL filtering them out. if (!HasExtension("EGL_KHR_image_base", egl_extensions)) ALOGW("EGL_KHR_image_base extension not supported"); if (!HasExtension("EGL_ANDROID_image_native_buffer", egl_extensions)) ALOGW("EGL_ANDROID_image_native_buffer extension not supported"); if (!HasExtension("EGL_ANDROID_native_fence_sync", egl_extensions)) ALOGW("EGL_ANDROID_native_fence_sync extension not supported"); if (!eglChooseConfig(egl_display_, config_attribs, &egl_config, 1, &num_configs)) { ALOGE("eglChooseConfig() failed with error: %s", GetEGLError()); return 1; } egl_ctx_ = eglCreateContext(egl_display_, egl_config, EGL_NO_CONTEXT /* No shared context */, context_attribs); if (egl_ctx_ == EGL_NO_CONTEXT) { ALOGE("Failed to create OpenGL ES Context: %s", GetEGLError()); return 1; } if (!eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_)) { ALOGE("Failed to make the OpenGL ES Context current: %s", GetEGLError()); return 1; } gl_extensions = (const char *)glGetString(GL_EXTENSIONS); if (!HasExtension("GL_OES_EGL_image", gl_extensions)) ALOGW("GL_OES_EGL_image extension not supported"); GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); vertex_buffer_.reset(vertex_buffer); if (GenerateShaders(&blend_programs_)) { return 1; } return 0; }