• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "RenderBase.h"
18 
19 #include "Utils.h"
20 #include "glError.h"
21 
22 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
23 #include <aidlcommonsupport/NativeHandle.h>
24 #include <android-base/logging.h>
25 #include <android-base/scopeguard.h>
26 #include <ui/GraphicBuffer.h>
27 
28 namespace {
29 
30 using aidl::android::hardware::automotive::evs::BufferDesc;
31 
32 // Eventually we shouldn't need this dependency, but for now the
33 // graphics allocator interface isn't fully supported on all platforms
34 // and this is our work around.
35 using ::android::GraphicBuffer;
36 
37 }  // namespace
38 
39 // OpenGL state shared among all renderers
40 EGLDisplay RenderBase::sDisplay = EGL_NO_DISPLAY;
41 EGLContext RenderBase::sContext = EGL_NO_CONTEXT;
42 EGLSurface RenderBase::sMockSurface = EGL_NO_SURFACE;
43 GLuint RenderBase::sFrameBuffer = -1;
44 GLuint RenderBase::sColorBuffer = -1;
45 GLuint RenderBase::sDepthBuffer = -1;
46 EGLImageKHR RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
47 unsigned RenderBase::sWidth = 0;
48 unsigned RenderBase::sHeight = 0;
49 float RenderBase::sAspectRatio = 0.0f;
50 
prepareGL()51 bool RenderBase::prepareGL() {
52     // Just trivially return success if we're already prepared
53     if (sDisplay != EGL_NO_DISPLAY) {
54         return true;
55     }
56 
57     // Hardcoded to RGBx output display
58     const EGLint config_attribs[] = {// Tag                  Value
59                                      EGL_RENDERABLE_TYPE,
60                                      EGL_OPENGL_ES2_BIT,
61                                      EGL_RED_SIZE,
62                                      8,
63                                      EGL_GREEN_SIZE,
64                                      8,
65                                      EGL_BLUE_SIZE,
66                                      8,
67                                      EGL_NONE};
68 
69     // Select OpenGL ES v 3
70     const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
71 
72     // Set up our OpenGL ES context associated with the default display (though we won't be visible)
73     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
74     if (display == EGL_NO_DISPLAY) {
75         LOG(ERROR) << "Failed to get egl display";
76         return false;
77     }
78 
79     EGLint major = 0;
80     EGLint minor = 0;
81     if (!eglInitialize(display, &major, &minor)) {
82         LOG(ERROR) << "Failed to initialize EGL: " << getEGLError();
83         return false;
84     } else {
85         LOG(INFO) << "Intiialized EGL at " << major << "." << minor;
86     }
87 
88     // Select the configuration that "best" matches our desired characteristics
89     EGLConfig egl_config;
90     EGLint num_configs;
91     if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
92         LOG(ERROR) << "eglChooseConfig() failed with error: " << getEGLError();
93         return false;
94     }
95 
96     // Create a temporary pbuffer so we have a surface to bind -- we never intend to draw to this
97     // because attachRenderTarget will be called first.
98     EGLint surface_attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
99     sMockSurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
100     if (sMockSurface == EGL_NO_SURFACE) {
101         LOG(ERROR) << "Failed to create OpenGL ES Mock surface: " << getEGLError();
102         return false;
103     } else {
104         LOG(INFO) << "Mock surface looks good!  :)";
105     }
106 
107     //
108     // Create the EGL context
109     //
110     EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
111     if (context == EGL_NO_CONTEXT) {
112         LOG(ERROR) << "Failed to create OpenGL ES Context: " << getEGLError();
113         return false;
114     }
115 
116     // Activate our render target for drawing
117     if (!eglMakeCurrent(display, sMockSurface, sMockSurface, context)) {
118         LOG(ERROR) << "Failed to make the OpenGL ES Context current: " << getEGLError();
119         return false;
120     } else {
121         LOG(INFO) << "We made our context current!  :)";
122     }
123 
124     // Report the extensions available on this implementation
125     const char* gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
126     LOG(INFO) << "GL EXTENSIONS:\n  " << gl_extensions;
127 
128     // Reserve handles for the color and depth targets we'll be setting up
129     glGenRenderbuffers(1, &sColorBuffer);
130     glGenRenderbuffers(1, &sDepthBuffer);
131 
132     // Set up the frame buffer object we can modify and use for off screen rendering
133     glGenFramebuffers(1, &sFrameBuffer);
134     glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
135 
136     // Now that we're assured success, store object handles we constructed
137     sDisplay = display;
138     sContext = context;
139 
140     return true;
141 }
142 
attachRenderTarget(const BufferDesc & tgtBuffer)143 bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
144     native_handle_t* nativeHandle = getNativeHandle(tgtBuffer);
145     if (nativeHandle == nullptr) {
146         LOG(ERROR) << "Target buffer is invalid.";
147         return false;
148     }
149 
150     const auto handleGuard =
151             android::base::make_scope_guard([nativeHandle] { free(nativeHandle); });
152     const AHardwareBuffer_Desc* pDesc =
153             reinterpret_cast<const AHardwareBuffer_Desc*>(&tgtBuffer.buffer.description);
154     // Hardcoded to RGBx for now
155     if (pDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
156         LOG(ERROR) << "Unsupported target buffer format";
157         return false;
158     }
159 
160     // create a GraphicBuffer from the existing handle
161     android::sp<GraphicBuffer> pGfxBuffer =
162             new GraphicBuffer(nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
163                               pDesc->height, pDesc->format, pDesc->layers, pDesc->usage,
164                               pDesc->stride);
165     if (!pGfxBuffer) {
166         LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
167         return false;
168     }
169 
170     if (auto status = pGfxBuffer->initCheck(); status != android::OK) {
171         LOG(ERROR) << "Failed to initialize the graphic buffer, error = "
172                    << android::statusToString(status);
173         return false;
174     }
175 
176     // Get a GL compatible reference to the graphics buffer we've been given
177     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
178     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
179     sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf,
180                                   eglImageAttributes);
181     if (sKHRimage == EGL_NO_IMAGE_KHR) {
182         LOG(ERROR) << "Error creating EGLImage for target buffer: " << getEGLError();
183         return false;
184     }
185 
186     // Construct a render buffer around the external buffer
187     glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
188     glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
189     if (eglGetError() != EGL_SUCCESS) {
190         LOG(INFO) << "glEGLImageTargetRenderbufferStorageOES => " << getEGLError();
191         return false;
192     }
193 
194     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
195     if (eglGetError() != EGL_SUCCESS) {
196         LOG(ERROR) << "glFramebufferRenderbuffer => " << getEGLError();
197         return false;
198     }
199 
200     GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
201     if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
202         LOG(ERROR) << "Offscreen framebuffer not configured successfully (" << checkResult << ": "
203                    << getGLFramebufferError() << ")";
204         return false;
205     }
206 
207     // Store the size of our target buffer
208     sWidth = pDesc->width;
209     sHeight = pDesc->height;
210     sAspectRatio = (float)sWidth / sHeight;
211 
212     // Set the viewport
213     glViewport(0, 0, sWidth, sHeight);
214 
215     // We don't actually need the clear if we're going to cover the whole screen anyway
216     // Clear the color buffer
217     glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
218     glClear(GL_COLOR_BUFFER_BIT);
219 
220     return true;
221 }
222 
detachRenderTarget()223 void RenderBase::detachRenderTarget() {
224     // Drop our external render target
225     if (sKHRimage != EGL_NO_IMAGE_KHR) {
226         eglDestroyImageKHR(sDisplay, sKHRimage);
227         sKHRimage = EGL_NO_IMAGE_KHR;
228     }
229 }
230