blob: 3dab97878539d4dd28f25c50e08e9636befdc2d9 [file] [log] [blame]
Haoxiang Lib21a13e2019-06-18 13:16:28 -07001/*
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
Haoxiang Lid2454a52019-06-18 13:23:12 -070023namespace android {
24namespace automotive {
25namespace evs {
26namespace support {
27
Haoxiang Lib21a13e2019-06-18 13:16:28 -070028// 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.
31using ::android::GraphicBuffer;
32
33
34// OpenGL state shared among all renderers
35EGLDisplay RenderBase::sDisplay = EGL_NO_DISPLAY;
36EGLContext RenderBase::sContext = EGL_NO_CONTEXT;
37EGLSurface RenderBase::sDummySurface = EGL_NO_SURFACE;
38GLuint RenderBase::sFrameBuffer = -1;
39GLuint RenderBase::sColorBuffer = -1;
40GLuint RenderBase::sDepthBuffer = -1;
41EGLImageKHR RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
42unsigned RenderBase::sWidth = 0;
43unsigned RenderBase::sHeight = 0;
44float RenderBase::sAspectRatio = 0.0f;
45
46
47bool 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
146bool 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
216void 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 }
Haoxiang Lid2454a52019-06-18 13:23:12 -0700222}
223
224} // namespace support
225} // namespace evs
226} // namespace automotive
227} // namespace android