1 /*
2  * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above
10       copyright notice, this list of conditions and the following
11       disclaimer in the documentation and/or other materials provided
12       with the distribution.
13     * Neither the name of The Linux Foundation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <vector>
31 
32 #include "gl_color_convert_impl.h"
33 
34 #define __CLASS__ "GLColorConvertImpl"
35 
36 namespace sdm {
37 
38 const float kFullScreenVertices[] = {
39   -1.0f,  3.0f,
40   -1.0f, -1.0f,
41   3.0f, -1.0f
42 };
43 
44 const float kFullScreenTexCoords[] = {
45   0.0f, 2.0f,
46   0.0f, 0.0f,
47   2.0f, 0.0f
48 };
49 
50 const char* kVertexShader = ""
51   "#version 300 es                                                       \n"
52   "precision highp float;                                                \n"
53   "layout(location = 0) in vec2 in_pos;                                  \n"
54   "layout(location = 1) in vec2 in_uv;                                   \n"
55   "                                                                      \n"
56   "out vec2 uv;                                                          \n"
57   "                                                                      \n"
58   "void main()                                                           \n"
59   "{                                                                     \n"
60   "    gl_Position = vec4(in_pos, 0.0, 1.0);                             \n"
61   "    uv = in_uv;                                                       \n"
62   "}                                                                     \n";
63 
64 const char* kConvertRgbToYuvShader = ""
65   "#extension GL_EXT_YUV_target : require                                \n"
66   "precision highp float;                                                \n"
67   "                                                                      \n"
68   "layout(binding = 0) uniform sampler2D u_sTexture;                     \n"
69   "                                                                      \n"
70   "in vec2 uv;                                                           \n"
71   "layout (yuv) out vec4 color;                                          \n"
72   "                                                                      \n"
73   "void main()                                                           \n"
74   "{                                                                     \n"
75   "    vec3 rgbColor = texture(u_sTexture, uv).rgb;                      \n"
76   "    color = vec4(rgb_2_yuv(rgbColor, itu_601_full_range), 1.0);       \n"
77   "}                                                                     \n";
78 
CreateContext(GLRenderTarget target,bool secure)79 int GLColorConvertImpl::CreateContext(GLRenderTarget target, bool secure) {
80   if (target != kTargetRGBA && target != kTargetYUV) {
81     DLOGE("Invalid GLRenderTarget: %d", target);
82     return -1;
83   }
84 
85   ctx_.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
86   EGL(eglBindAPI(EGL_OPENGL_ES_API));
87 
88   // Initialize current display.
89   EGL(eglInitialize(ctx_.egl_display, nullptr, nullptr));
90 
91   // Get attributes corresponing to render target.
92   // Describes Framebuffer attributes like buffer depth, color space etc;
93   EGLConfig eglConfig;
94   int numConfig = 0;
95   if (target == kTargetRGBA) {
96     EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
97                                     EGL_RED_SIZE,     8,
98                                     EGL_GREEN_SIZE,   8,
99                                     EGL_BLUE_SIZE,    8,
100                                     EGL_ALPHA_SIZE,   8,
101                                     EGL_NONE};
102     EGL(eglChooseConfig(ctx_.egl_display, eglConfigAttribList, &eglConfig, 1, &numConfig));
103   } else {
104     EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
105                                     EGL_RENDERABLE_TYPE,           EGL_OPENGL_ES2_BIT,
106                                     EGL_COLOR_BUFFER_TYPE,         EGL_YUV_BUFFER_EXT,
107                                     EGL_YUV_ORDER_EXT,             EGL_YUV_ORDER_YUV_EXT,
108                                     EGL_YUV_NUMBER_OF_PLANES_EXT,  2,
109                                     EGL_YUV_SUBSAMPLE_EXT,         EGL_YUV_SUBSAMPLE_4_2_0_EXT,
110                                     EGL_YUV_DEPTH_RANGE_EXT,       EGL_YUV_DEPTH_RANGE_LIMITED_EXT,
111                                     EGL_YUV_CSC_STANDARD_EXT,      EGL_YUV_CSC_STANDARD_601_EXT,
112                                     EGL_YUV_PLANE_BPP_EXT,         EGL_YUV_PLANE_BPP_8_EXT,
113                                     EGL_NONE};
114     EGL(eglChooseConfig(ctx_.egl_display, eglConfigAttribList, &eglConfig, 1, &numConfig));
115   }
116 
117   // When GPU runs in protected context it can read from
118   //  - Protected sources
119   //  - UnProtected source
120   // and writes into Protected buffer.
121   // VS in UnProtected context it can read/write happen from/to Unprotected sources.
122   EGLint egl_contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
123                                     secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
124                                     secure ? EGL_TRUE : EGL_NONE,
125                                     EGL_NONE};
126   ctx_.egl_context = eglCreateContext(ctx_.egl_display, eglConfig, NULL, egl_contextAttribList);
127 
128   // eglCreatePbufferSurface creates an off-screen pixel buffer surface and returns its handle
129   EGLint egl_surfaceAttribList[] = {EGL_WIDTH, 1,
130                                     EGL_HEIGHT, 1,
131                                     secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
132                                     secure ? EGL_TRUE : EGL_NONE,
133                                     EGL_NONE};
134   ctx_.egl_surface = eglCreatePbufferSurface(ctx_.egl_display, eglConfig, egl_surfaceAttribList);
135 
136   // eglMakeCurrent attaches rendering context to rendering surface.
137   MakeCurrent(&ctx_);
138 
139   DLOGI("Created context = %p", (void *)(&ctx_.egl_context));
140 
141   // Load Vertex and Fragment shaders.
142   const char *fragment_shaders[2] = { };
143   int count = 0;
144   const char *version = "#version 300 es\n";
145 
146   fragment_shaders[count++] = version;
147 
148   // ToDo: Add support to yuv_to_rgb shader.
149   fragment_shaders[count++] = kConvertRgbToYuvShader;
150 
151   ctx_.program_id = LoadProgram(1, &kVertexShader, count, fragment_shaders);
152 
153   SetRealTimePriority();
154 
155   return 0;
156 }
157 
Blit(const private_handle_t * src_hnd,const private_handle_t * dst_hnd,const GLRect & src_rect,const GLRect & dst_rect,const shared_ptr<Fence> & src_acquire_fence,const shared_ptr<Fence> & dst_acquire_fence,shared_ptr<Fence> * release_fence)158 int GLColorConvertImpl::Blit(const private_handle_t *src_hnd, const private_handle_t *dst_hnd,
159                              const GLRect &src_rect, const GLRect &dst_rect,
160                              const shared_ptr<Fence> &src_acquire_fence,
161                              const shared_ptr<Fence> &dst_acquire_fence,
162                              shared_ptr<Fence> *release_fence) {
163   DTRACE_SCOPED();
164   // eglMakeCurrent attaches rendering context to rendering surface.
165   MakeCurrent(&ctx_);
166 
167   SetProgram(ctx_.program_id);
168 
169   SetSourceBuffer(src_hnd);
170   SetDestinationBuffer(dst_hnd);
171   SetViewport(dst_rect);
172 
173   glEnableVertexAttribArray(0);
174   glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenVertices);
175   glEnableVertexAttribArray(1);
176   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenTexCoords);
177   glDrawArrays(GL_TRIANGLES, 0, 3);
178 
179   std::vector<shared_ptr<Fence>> in_fence = {Fence::Merge(src_acquire_fence, dst_acquire_fence)};
180   WaitOnInputFence(in_fence);
181 
182   // Create output fence for client to wait on.
183   CreateOutputFence(release_fence);
184 
185   return 0;
186 }
187 
Init()188 int GLColorConvertImpl::Init() {
189   return CreateContext(target_, secure_);
190 }
191 
Deinit()192 int GLColorConvertImpl::Deinit() {
193   MakeCurrent(&ctx_);
194   DestroyContext(&ctx_);
195 
196   return 0;
197 }
198 
~GLColorConvertImpl()199 GLColorConvertImpl::~GLColorConvertImpl() {}
200 
GLColorConvertImpl(GLRenderTarget target,bool secure)201 GLColorConvertImpl::GLColorConvertImpl(GLRenderTarget target, bool secure) {
202   target_ = target;
203   secure_ = secure;
204 }
205 
Reset()206 void GLColorConvertImpl::Reset() {
207   ClearCache();
208 }
209 
210 }  // namespace sdm
211 
212