• 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 #include "glError.h"
19 
20 #include <log/log.h>
21 #include <ui/GraphicBuffer.h>
22 
23 namespace android {
24 namespace automotive {
25 namespace evs {
26 namespace support {
27 
28 // Eventually we shouldn't need this dependency, but for now the
29 // graphics allocator interface isn't fully supported on all platforms
30 // and this is our work around.
31 using ::android::GraphicBuffer;
32 
33 
34 // OpenGL state shared among all renderers
35 EGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
36 EGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
37 EGLSurface   RenderBase::sDummySurface = EGL_NO_SURFACE;
38 GLuint       RenderBase::sFrameBuffer = -1;
39 GLuint       RenderBase::sColorBuffer = -1;
40 GLuint       RenderBase::sDepthBuffer = -1;
41 EGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
42 unsigned     RenderBase::sWidth  = 0;
43 unsigned     RenderBase::sHeight = 0;
44 float        RenderBase::sAspectRatio = 0.0f;
45 
46 
prepareGL()47 bool RenderBase::prepareGL() {
48     // Just trivially return success if we're already prepared
49     if (sDisplay != EGL_NO_DISPLAY) {
50         return true;
51     }
52 
53     // Hardcoded to RGBx output display
54     const EGLint config_attribs[] = {
55         // Tag                  Value
56         EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
57         EGL_RED_SIZE,           8,
58         EGL_GREEN_SIZE,         8,
59         EGL_BLUE_SIZE,          8,
60         EGL_NONE
61     };
62 
63     // Select OpenGL ES v 3
64     const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
65 
66 
67     // Set up our OpenGL ES context associated with the default display (though we won't be visible)
68     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
69     if (display == EGL_NO_DISPLAY) {
70         ALOGE("Failed to get egl display");
71         return false;
72     }
73 
74     EGLint major = 0;
75     EGLint minor = 0;
76     if (!eglInitialize(display, &major, &minor)) {
77         ALOGE("Failed to initialize EGL: %s", getEGLError());
78         return false;
79     } else {
80         ALOGI("Intiialized EGL at %d.%d", major, minor);
81     }
82 
83 
84     // Select the configuration that "best" matches our desired characteristics
85     EGLConfig egl_config;
86     EGLint num_configs;
87     if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
88         ALOGE("eglChooseConfig() failed with error: %s", getEGLError());
89         return false;
90     }
91 
92 
93     // Create a dummy pbuffer so we have a surface to bind -- we never intend to draw to this
94     // because attachRenderTarget will be called first.
95     EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
96     sDummySurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
97     if (sDummySurface == EGL_NO_SURFACE) {
98         ALOGE("Failed to create OpenGL ES Dummy surface: %s", getEGLError());
99         return false;
100     } else {
101         ALOGI("Dummy surface looks good!  :)");
102     }
103 
104 
105     //
106     // Create the EGL context
107     //
108     EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
109     if (context == EGL_NO_CONTEXT) {
110         ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
111         return false;
112     }
113 
114 
115     // Activate our render target for drawing
116     if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
117         ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
118         return false;
119     } else {
120         ALOGI("We made our context current!  :)");
121     }
122 
123 
124     // Report the extensions available on this implementation
125     const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
126     ALOGI("GL EXTENSIONS:\n  %s", gl_extensions);
127 
128 
129     // Reserve handles for the color and depth targets we'll be setting up
130     glGenRenderbuffers(1, &sColorBuffer);
131     glGenRenderbuffers(1, &sDepthBuffer);
132 
133     // Set up the frame buffer object we can modify and use for off screen rendering
134     glGenFramebuffers(1, &sFrameBuffer);
135     glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
136 
137 
138     // Now that we're assured success, store object handles we constructed
139     sDisplay = display;
140     sContext = context;
141 
142     return true;
143 }
144 
145 
attachRenderTarget(const BufferDesc & tgtBuffer)146 bool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
147     // Hardcoded to RGBx for now
148     if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
149         ALOGE("Unsupported target buffer format");
150         return false;
151     }
152 
153     // create a GraphicBuffer from the existing handle
154     sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.memHandle,
155                                                      GraphicBuffer::CLONE_HANDLE,
156                                                      tgtBuffer.width, tgtBuffer.height,
157                                                      tgtBuffer.format, 1, // layer count
158                                                      GRALLOC_USAGE_HW_RENDER,
159                                                      tgtBuffer.stride);
160     if (pGfxBuffer.get() == nullptr) {
161         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
162         return false;
163     }
164 
165     // Get a GL compatible reference to the graphics buffer we've been given
166     EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
167     EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
168     sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
169                                   EGL_NATIVE_BUFFER_ANDROID, clientBuf,
170                                   eglImageAttributes);
171     if (sKHRimage == EGL_NO_IMAGE_KHR) {
172         ALOGE("error creating EGLImage for target buffer: %s", getEGLError());
173         return false;
174     }
175 
176     // Construct a render buffer around the external buffer
177     glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
178     glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
179     if (eglGetError() != EGL_SUCCESS) {
180         ALOGI("glEGLImageTargetRenderbufferStorageOES => %s", getEGLError());
181         return false;
182     }
183 
184     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
185     if (eglGetError() != EGL_SUCCESS) {
186         ALOGE("glFramebufferRenderbuffer => %s", getEGLError());
187         return false;
188     }
189 
190     GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
191     if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
192         ALOGE("Offscreen framebuffer not configured successfully (%d: %s)",
193               checkResult, getGLFramebufferError());
194         return false;
195     }
196 
197     // Store the size of our target buffer
198     sWidth = tgtBuffer.width;
199     sHeight = tgtBuffer.height;
200     sAspectRatio = (float)sWidth / sHeight;
201 
202     // Set the viewport
203     glViewport(0, 0, sWidth, sHeight);
204 
205 #if 1   // We don't actually need the clear if we're going to cover the whole screen anyway
206     // Clear the color buffer
207     glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
208     glClear(GL_COLOR_BUFFER_BIT);
209 #endif
210 
211 
212     return true;
213 }
214 
215 
detachRenderTarget()216 void RenderBase::detachRenderTarget() {
217     // Drop our external render target
218     if (sKHRimage != EGL_NO_IMAGE_KHR) {
219         eglDestroyImageKHR(sDisplay, sKHRimage);
220         sKHRimage = EGL_NO_IMAGE_KHR;
221     }
222 }
223 
224 }  // namespace support
225 }  // namespace evs
226 }  // namespace automotive
227 }  // namespace android
228