blob: c13de36f3cf636721e23153ddad133608c0ebb65 [file] [log] [blame]
/*
* Copyright (c) 2019-2021, 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 <string>
#include "gl_common.h"
#define __CLASS__ "GLCommon"
namespace sdm {
GLuint GLCommon::LoadProgram(int vertex_entries, const char **vertex, int fragment_entries,
const char **fragment) {
GLuint prog_id = glCreateProgram();
int vert_id = glCreateShader(GL_VERTEX_SHADER);
int frag_id = glCreateShader(GL_FRAGMENT_SHADER);
GL(glShaderSource(vert_id, vertex_entries, vertex, 0));
GL(glCompileShader(vert_id));
DumpShaderLog(vert_id);
GL(glShaderSource(frag_id, fragment_entries, fragment, 0));
GL(glCompileShader(frag_id));
DumpShaderLog(frag_id);
GL(glAttachShader(prog_id, vert_id));
GL(glAttachShader(prog_id, frag_id));
GL(glLinkProgram(prog_id));
GL(glDetachShader(prog_id, vert_id));
GL(glDetachShader(prog_id, frag_id));
GL(glDeleteShader(vert_id));
GL(glDeleteShader(frag_id));
return prog_id;
}
void GLCommon::DumpShaderLog(int shader) {
int success = 0;
GLchar infoLog[512];
GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success));
if (!success) {
glGetShaderInfoLog(shader, 512, NULL, infoLog);
DLOGI("Shader Failed to compile: %s\n", infoLog);
}
}
void GLCommon::MakeCurrent(const GLContext* ctx) {
DTRACE_SCOPED();
EGL(eglMakeCurrent(ctx->egl_display, ctx->egl_surface, ctx->egl_surface, ctx->egl_context));
}
void GLCommon::SetProgram(uint32_t id) {
DTRACE_SCOPED();
GL(glUseProgram(id));
}
void GLCommon::DeleteProgram(uint32_t id) {
DTRACE_SCOPED();
GL(glDeleteProgram(id));
}
void GLCommon::SetSourceBuffer(const native_handle_t *src_hnd) {
DTRACE_SCOPED();
EGLImageBuffer *src_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(src_hnd));
GL(glActiveTexture(GL_TEXTURE0));
if (src_buffer) {
GL(glBindTexture(GL_TEXTURE_2D, src_buffer->getTexture(GL_TEXTURE_2D)));
}
}
void GLCommon::SetDestinationBuffer(const native_handle_t *dst_hnd) {
DTRACE_SCOPED();
EGLImageBuffer *dst_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(dst_hnd));
if (dst_buffer) {
GL(glBindFramebuffer(GL_FRAMEBUFFER, dst_buffer->getFramebuffer()));
}
}
int GLCommon::WaitOnInputFence(const std::vector<shared_ptr<Fence>> &in_fences) {
DTRACE_SCOPED();
shared_ptr<Fence> in_fence = Fence::Merge(in_fences, true /* ignore signaled*/);
if (in_fence == nullptr) {
return 0;
}
int fd = Fence::Dup(in_fence);
EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE};
EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs);
if (sync == EGL_NO_SYNC_KHR) {
DLOGE("Failed to create sync from source fd: %s", Fence::GetStr(in_fence).c_str());
close(fd);
return -1;
}
EGL(eglWaitSyncKHR(eglGetCurrentDisplay(), sync, 0));
EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));
return 0;
}
int GLCommon::CreateOutputFence(shared_ptr<Fence> *out_fence) {
DTRACE_SCOPED();
EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
// Swap buffer.
GL(glFlush());
if (sync == EGL_NO_SYNC_KHR) {
DLOGE("Failed to create egl sync fence");
return -1;
}
int status = 0;
int fd = eglDupNativeFenceFDANDROID(eglGetCurrentDisplay(), sync);
if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
status = -1;
DLOGE("Failed to dup sync");
} else {
*out_fence = Fence::Create(fd, "gl_out_fence");
}
EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));
return status;
}
void GLCommon::DestroyContext(GLContext* ctx) {
DTRACE_SCOPED();
// Clear egl image buffers.
image_wrapper_.Deinit();
EGL(DeleteProgram(ctx->program_id));
EGL(eglMakeCurrent(ctx->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
EGL(eglDestroySurface(ctx->egl_display, ctx->egl_surface));
EGL(eglDestroyContext(ctx->egl_display, ctx->egl_context));
EGL(eglTerminate(ctx->egl_display));
}
void GLCommon::ClearCache() {
// Clear cached handles.
image_wrapper_.Deinit();
image_wrapper_.Init();
}
void GLCommon::SetRealTimePriority() {
// same as composer thread
struct sched_param param = {0};
param.sched_priority = 2;
if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
DLOGE("Couldn't set SCHED_FIFO: %d", errno);
}
}
void GLCommon::SetViewport(const GLRect &dst_rect) {
DTRACE_SCOPED();
float width = dst_rect.right - dst_rect.left;
float height = dst_rect.bottom - dst_rect.top;
GL(glViewport(dst_rect.left, dst_rect.top, width, height));
}
} // namespace sdm