BufferGenerator.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. * Copyright 2018 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. #include <gui/BufferItemConsumer.h>
  17. #include <gui/Surface.h>
  18. #include <GLES3/gl3.h>
  19. #include <math/vec2.h>
  20. #include <math/vec3.h>
  21. #include <math/vec4.h>
  22. #include "BufferGenerator.h"
  23. #include "BufferGeneratorShader.h"
  24. namespace android {
  25. /* Used to receive the surfaces and fences from egl. The egl buffers are thrown
  26. * away. The fences are sent to the requester via a callback */
  27. class SurfaceManager {
  28. public:
  29. /* Returns a fence from egl */
  30. using BufferCallback = std::function<void(const sp<GraphicBuffer>& buffer, int32_t fence)>;
  31. /* Listens for a new frame, detaches the buffer and returns the fence
  32. * through saved callback. */
  33. class BufferListener : public ConsumerBase::FrameAvailableListener {
  34. public:
  35. BufferListener(sp<IGraphicBufferConsumer> consumer, BufferCallback callback)
  36. : mConsumer(consumer), mCallback(callback) {}
  37. void onFrameAvailable(const BufferItem& /*item*/) {
  38. BufferItem item;
  39. if (mConsumer->acquireBuffer(&item, 0)) return;
  40. if (mConsumer->detachBuffer(item.mSlot)) return;
  41. mCallback(item.mGraphicBuffer, item.mFence->dup());
  42. }
  43. private:
  44. sp<IGraphicBufferConsumer> mConsumer;
  45. BufferCallback mCallback;
  46. };
  47. /* Creates a buffer listener that waits on a new frame from the buffer
  48. * queue. */
  49. void initialize(uint32_t width, uint32_t height, android_pixel_format_t format,
  50. BufferCallback callback) {
  51. sp<IGraphicBufferProducer> producer;
  52. sp<IGraphicBufferConsumer> consumer;
  53. BufferQueue::createBufferQueue(&producer, &consumer);
  54. consumer->setDefaultBufferSize(width, height);
  55. consumer->setDefaultBufferFormat(format);
  56. mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
  57. mListener = new BufferListener(consumer, callback);
  58. mBufferItemConsumer->setFrameAvailableListener(mListener);
  59. mSurface = new Surface(producer, true);
  60. }
  61. /* Used by Egl manager. The surface is never displayed. */
  62. sp<Surface> getSurface() const { return mSurface; }
  63. private:
  64. sp<BufferItemConsumer> mBufferItemConsumer;
  65. sp<BufferListener> mListener;
  66. /* Used by Egl manager. The surface is never displayed */
  67. sp<Surface> mSurface;
  68. };
  69. /* Used to generate valid fences. It is not possible to create a dummy sync
  70. * fence for testing. Egl can generate buffers along with a valid fence.
  71. * The buffer cannot be guaranteed to be the same format across all devices so
  72. * a CPU filled buffer is used instead. The Egl fence is used along with the
  73. * CPU filled buffer. */
  74. class EglManager {
  75. public:
  76. EglManager()
  77. : mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT) {}
  78. ~EglManager() { cleanup(); }
  79. int initialize(sp<Surface> surface) {
  80. mSurface = surface;
  81. mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  82. if (mEglDisplay == EGL_NO_DISPLAY) return false;
  83. EGLint major;
  84. EGLint minor;
  85. if (!eglInitialize(mEglDisplay, &major, &minor)) {
  86. ALOGW("Could not initialize EGL");
  87. return false;
  88. }
  89. /* We're going to use a 1x1 pbuffer surface later on
  90. * The configuration distance doesn't really matter for what we're
  91. * trying to do */
  92. EGLint configAttrs[] = {EGL_RENDERABLE_TYPE,
  93. EGL_OPENGL_ES2_BIT,
  94. EGL_RED_SIZE,
  95. 8,
  96. EGL_GREEN_SIZE,
  97. 8,
  98. EGL_BLUE_SIZE,
  99. 8,
  100. EGL_ALPHA_SIZE,
  101. 0,
  102. EGL_DEPTH_SIZE,
  103. 24,
  104. EGL_STENCIL_SIZE,
  105. 0,
  106. EGL_NONE};
  107. EGLConfig configs[1];
  108. EGLint configCnt;
  109. if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, &configCnt)) {
  110. ALOGW("Could not select EGL configuration");
  111. eglReleaseThread();
  112. eglTerminate(mEglDisplay);
  113. return false;
  114. }
  115. if (configCnt <= 0) {
  116. ALOGW("Could not find EGL configuration");
  117. eglReleaseThread();
  118. eglTerminate(mEglDisplay);
  119. return false;
  120. }
  121. /* These objects are initialized below but the default "null" values are
  122. * used to cleanup properly at any point in the initialization sequence */
  123. EGLint attrs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
  124. mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, attrs);
  125. if (mEglContext == EGL_NO_CONTEXT) {
  126. ALOGW("Could not create EGL context");
  127. cleanup();
  128. return false;
  129. }
  130. EGLint majorVersion;
  131. if (!eglQueryContext(mEglDisplay, mEglContext, EGL_CONTEXT_CLIENT_VERSION, &majorVersion)) {
  132. ALOGW("Could not query EGL version");
  133. cleanup();
  134. return false;
  135. }
  136. if (majorVersion != 3) {
  137. ALOGW("Unsupported EGL version");
  138. cleanup();
  139. return false;
  140. }
  141. EGLint surfaceAttrs[] = {EGL_NONE};
  142. mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], mSurface.get(), surfaceAttrs);
  143. if (mEglSurface == EGL_NO_SURFACE) {
  144. ALOGW("Could not create EGL surface");
  145. cleanup();
  146. return false;
  147. }
  148. if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
  149. ALOGW("Could not change current EGL context");
  150. cleanup();
  151. return false;
  152. }
  153. return true;
  154. }
  155. void makeCurrent() const { eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); }
  156. void present() const { eglSwapBuffers(mEglDisplay, mEglSurface); }
  157. private:
  158. void cleanup() {
  159. if (mEglDisplay == EGL_NO_DISPLAY) return;
  160. if (mEglSurface != EGL_NO_SURFACE) eglDestroySurface(mEglDisplay, mEglSurface);
  161. if (mEglContext != EGL_NO_CONTEXT) eglDestroyContext(mEglDisplay, mEglContext);
  162. eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  163. eglReleaseThread();
  164. eglTerminate(mEglDisplay);
  165. }
  166. sp<Surface> mSurface;
  167. EGLDisplay mEglDisplay;
  168. EGLSurface mEglSurface;
  169. EGLContext mEglContext;
  170. };
  171. class Program {
  172. public:
  173. ~Program() {
  174. if (mInitialized) {
  175. glDetachShader(mProgram, mVertexShader);
  176. glDetachShader(mProgram, mFragmentShader);
  177. glDeleteShader(mVertexShader);
  178. glDeleteShader(mFragmentShader);
  179. glDeleteProgram(mProgram);
  180. }
  181. }
  182. bool initialize(const char* vertex, const char* fragment) {
  183. mVertexShader = buildShader(vertex, GL_VERTEX_SHADER);
  184. if (!mVertexShader) {
  185. return false;
  186. }
  187. mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
  188. if (!mFragmentShader) {
  189. return false;
  190. }
  191. mProgram = glCreateProgram();
  192. glAttachShader(mProgram, mVertexShader);
  193. glAttachShader(mProgram, mFragmentShader);
  194. glLinkProgram(mProgram);
  195. GLint status;
  196. glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
  197. if (status != GL_TRUE) {
  198. GLint length = 0;
  199. glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);
  200. if (length > 1) {
  201. GLchar log[length];
  202. glGetProgramInfoLog(mProgram, length, nullptr, &log[0]);
  203. ALOGE("%s", log);
  204. }
  205. ALOGE("Error while linking shaders");
  206. return false;
  207. }
  208. mInitialized = true;
  209. return true;
  210. }
  211. void use() const { glUseProgram(mProgram); }
  212. void bindVec4(GLint location, vec4 v) const { glUniform4f(location, v.x, v.y, v.z, v.w); }
  213. void bindVec3(GLint location, const vec3* v, uint32_t count) const {
  214. glUniform3fv(location, count, &(v->x));
  215. }
  216. void bindFloat(GLint location, float v) { glUniform1f(location, v); }
  217. private:
  218. GLuint buildShader(const char* source, GLenum type) const {
  219. GLuint shader = glCreateShader(type);
  220. glShaderSource(shader, 1, &source, nullptr);
  221. glCompileShader(shader);
  222. GLint status;
  223. glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
  224. if (status != GL_TRUE) {
  225. ALOGE("Error while compiling shader of type 0x%x:\n===\n%s\n===", type, source);
  226. // Some drivers return wrong values for GL_INFO_LOG_LENGTH
  227. // use a fixed size instead
  228. GLchar log[512];
  229. glGetShaderInfoLog(shader, sizeof(log), nullptr, &log[0]);
  230. ALOGE("Shader info log: %s", log);
  231. return 0;
  232. }
  233. return shader;
  234. }
  235. GLuint mProgram = 0;
  236. GLuint mVertexShader = 0;
  237. GLuint mFragmentShader = 0;
  238. bool mInitialized = false;
  239. };
  240. BufferGenerator::BufferGenerator()
  241. : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) {
  242. const float width = 1000.0;
  243. const float height = 1000.0;
  244. auto setBufferWithContext =
  245. std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this);
  246. mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext);
  247. if (!mEglManager->initialize(mSurfaceManager->getSurface())) return;
  248. mEglManager->makeCurrent();
  249. if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return;
  250. mProgram->use();
  251. mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height});
  252. mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4);
  253. glEnableVertexAttribArray(0);
  254. glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &TRIANGLE[0]);
  255. mInitialized = true;
  256. }
  257. BufferGenerator::~BufferGenerator() {
  258. mEglManager->makeCurrent();
  259. }
  260. status_t BufferGenerator::get(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
  261. // mMutex is used to protect get() from getting called by multiple threads at the same time
  262. static std::mutex mMutex;
  263. std::lock_guard lock(mMutex);
  264. if (!mInitialized) {
  265. if (outBuffer) {
  266. *outBuffer = nullptr;
  267. }
  268. if (*outFence) {
  269. *outFence = nullptr;
  270. }
  271. return -EINVAL;
  272. }
  273. // Generate a buffer and fence. They will be returned through the setBuffer callback
  274. mEglManager->makeCurrent();
  275. glClear(GL_COLOR_BUFFER_BIT);
  276. const std::chrono::duration<float> time = std::chrono::steady_clock::now() - mEpoch;
  277. mProgram->bindFloat(1, time.count());
  278. glDrawArrays(GL_TRIANGLES, 0, 3);
  279. mPending = true;
  280. mEglManager->present();
  281. // Wait for the setBuffer callback
  282. if (!mConditionVariable.wait_for(mMutex, std::chrono::seconds(2),
  283. [this] { return !mPending; })) {
  284. ALOGE("failed to set buffer and fence");
  285. return -ETIME;
  286. }
  287. // Return buffer and fence
  288. if (outBuffer) {
  289. *outBuffer = mGraphicBuffer;
  290. }
  291. if (outFence) {
  292. *outFence = new Fence(mFence);
  293. } else {
  294. close(mFence);
  295. }
  296. mGraphicBuffer = nullptr;
  297. mFence = -1;
  298. return NO_ERROR;
  299. }
  300. // static
  301. void BufferGenerator::setBuffer(const sp<GraphicBuffer>& buffer, int32_t fence,
  302. void* bufferGenerator) {
  303. BufferGenerator* generator = static_cast<BufferGenerator*>(bufferGenerator);
  304. generator->mGraphicBuffer = buffer;
  305. generator->mFence = fence;
  306. generator->mPending = false;
  307. generator->mConditionVariable.notify_all();
  308. }
  309. } // namespace android