/* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of The Linux Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "gl_layer_stitch_impl.h" #define __CLASS__ "GLLayerStitchImpl" namespace sdm { const float kFullScreenVertices[] = { -1.0f, 3.0f, -1.0f, -1.0f, 3.0f, -1.0f }; const float kFullScreenTexCoords[] = { 0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 0.0f }; const char *kVertexShader1 = "" "#version 300 es \n" "precision highp float; \n" "layout(location = 0) in vec2 in_pos; \n" "layout(location = 1) in vec2 in_uv; \n" " \n" "out vec2 uv; \n" " \n" "void main() \n" "{ \n" " gl_Position = vec4(in_pos, 0.0, 1.0); \n" " uv = in_uv; \n" "} \n"; const char *kConvertRenderRGBShader = "" "precision highp float; \n" " \n" "layout(binding = 0) uniform sampler2D u_sTexture; \n" " \n" "in vec2 uv; \n" "out vec4 color; \n" " \n" "void main() \n" "{ \n" " color = texture(u_sTexture, uv); \n" "} \n"; static bool IsValid(const GLRect &rect) { return ((rect.right - rect.left) && (rect.bottom - rect.top)); } int GLLayerStitchImpl::CreateContext(bool secure) { ctx_.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGL(eglBindAPI(EGL_OPENGL_ES_API)); // Initialize current display. EGL(eglInitialize(ctx_.egl_display, nullptr, nullptr)); // Get attributes corresponing to render target. // Describes Framebuffer attributes like buffer depth, color space etc; EGLConfig eglConfig; int numConfig = 0; EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE}; EGL(eglChooseConfig(ctx_.egl_display, eglConfigAttribList, &eglConfig, 1, &numConfig)); // When GPU runs in protected context it can read from // - Protected sources // - UnProtected source // and writes into Protected buffer. // VS in UnProtected context it can read/write happen from/to Unprotected sources. EGLint egl_contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, secure ? EGL_TRUE : EGL_NONE, EGL_NONE}; ctx_.egl_context = eglCreateContext(ctx_.egl_display, eglConfig, NULL, egl_contextAttribList); // eglCreatePbufferSurface creates an off-screen pixel buffer surface and returns its handle EGLint egl_surfaceAttribList[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, secure ? EGL_TRUE : EGL_NONE, EGL_NONE}; ctx_.egl_surface = eglCreatePbufferSurface(ctx_.egl_display, eglConfig, egl_surfaceAttribList); // eglMakeCurrent attaches rendering context to rendering surface. MakeCurrent(&ctx_); DLOGI("Created context = %p", (void *)(&ctx_.egl_context)); // Load Vertex and Fragment shaders. const char *fragment_shaders[2] = { }; int count = 0; const char *version = "#version 300 es\n"; fragment_shaders[count++] = version; // ToDo: Add support to yuv_to_rgb shader. fragment_shaders[count++] = kConvertRenderRGBShader; ctx_.program_id = LoadProgram(1, &kVertexShader1, count, fragment_shaders); SetRealTimePriority(); InitContext(); return 0; } int GLLayerStitchImpl::Blit(const std::vector &stitch_params, shared_ptr *release_fence) { DTRACE_SCOPED(); std::vector> acquire_fences; std::vector> release_fences; bool can_batch = !NeedsGLScissor(stitch_params); for (auto &info : stitch_params) { SetSourceBuffer(info.src_hnd); SetDestinationBuffer(info.dst_hnd); SetViewport(info.dst_rect); ClearWithTransparency(info.scissor_rect); glDrawArrays(GL_TRIANGLES, 0, 3); acquire_fences.push_back(info.src_acquire_fence); if (!can_batch) { // Trigger flush and cache release fence. WaitOnInputFence(acquire_fences); shared_ptr temp_release_fence = nullptr; CreateOutputFence(&temp_release_fence); release_fences.push_back(temp_release_fence); acquire_fences = {}; } } if (can_batch) { // Create output fence for client to wait on. WaitOnInputFence(acquire_fences); CreateOutputFence(release_fence); } else { // Merge all fd's and return one. *release_fence = Fence::Merge(release_fences, false); } return 0; } int GLLayerStitchImpl::NeedsGLScissor(const std::vector &stitch_params) { for (auto &info : stitch_params) { if (IsValid(info.scissor_rect)) { return true; } } return false; } int GLLayerStitchImpl::Init() { return CreateContext(secure_); } int GLLayerStitchImpl::Deinit() { MakeCurrent(&ctx_); DestroyContext(&ctx_); return 0; } void GLLayerStitchImpl::ClearWithTransparency(const GLRect &scissor_rect) { if (!IsValid(scissor_rect)) { // Disable scissor. GL(glDisable(GL_SCISSOR_TEST)); return; } DTRACE_SCOPED(); // Enable scissor test. GL(glEnable(GL_SCISSOR_TEST)); GL(glScissor(scissor_rect.left, scissor_rect.top, scissor_rect.right - scissor_rect.left, scissor_rect.bottom - scissor_rect.top)); GL(glClearColor(0, 0, 0, 0)); GL(glClear(GL_COLOR_BUFFER_BIT)); } void GLLayerStitchImpl::InitContext() { // eglMakeCurrent attaches rendering context to rendering surface. MakeCurrent(&ctx_); SetProgram(ctx_.program_id); SetRealTimePriority(); // Set vertices. glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenVertices); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenTexCoords); } GLLayerStitchImpl::~GLLayerStitchImpl() {} GLLayerStitchImpl::GLLayerStitchImpl(bool secure) { secure_ = secure; } } // namespace sdm