blob: e37ce628fabce56e48eb81f2163282501c82b087 [file] [log] [blame]
/*
* 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 <vector>
#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<StitchParams> &stitch_params,
shared_ptr<Fence> *release_fence) {
DTRACE_SCOPED();
std::vector<shared_ptr<Fence>> acquire_fences;
std::vector<shared_ptr<Fence>> 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<Fence> 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<StitchParams> &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