blob: c9d8f4fdb7d7184504ac708d1e98f17081cd5873 [file] [log] [blame]
Marissa Wall5a240aa2016-12-15 12:34:06 -08001/*
2 * Copyright (C) 2016 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 <mutex>
18#include <array>
19#include <sstream>
20#include <algorithm>
21
22#include <gui/Surface.h>
23#include <gui/BufferItemConsumer.h>
24#include <gui/GraphicBufferAlloc.h>
25
26#include <ui/GraphicBuffer.h>
27#include <ui/vec4.h>
28
29#include <GLES3/gl3.h>
30
31#include "Hwc2TestBuffer.h"
32#include "Hwc2TestLayers.h"
33
34using namespace android;
35
36/* Returns a fence from egl */
37typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
38
39/* Returns fence to fence generator */
40static void setFence(int32_t fence, void* fenceGenerator);
41
42
43/* Used to receive the surfaces and fences from egl. The egl buffers are thrown
44 * away. The fences are sent to the requester via a callback */
45class Hwc2TestSurfaceManager {
46public:
47 /* Listens for a new frame, detaches the buffer and returns the fence
48 * through saved callback. */
49 class BufferListener : public ConsumerBase::FrameAvailableListener {
50 public:
51 BufferListener(sp<IGraphicBufferConsumer> consumer,
52 FenceCallback callback, void* callbackArgs)
53 : mConsumer(consumer),
54 mCallback(callback),
55 mCallbackArgs(callbackArgs) { }
56
57 void onFrameAvailable(const BufferItem& /*item*/)
58 {
59 BufferItem item;
60
61 if (mConsumer->acquireBuffer(&item, 0))
62 return;
63 if (mConsumer->detachBuffer(item.mSlot))
64 return;
65
66 mCallback(item.mFence->dup(), mCallbackArgs);
67 }
68
69 private:
70 sp<IGraphicBufferConsumer> mConsumer;
71 FenceCallback mCallback;
72 void* mCallbackArgs;
73 };
74
75 /* Creates a buffer listener that waits on a new frame from the buffer
76 * queue. */
77 void initialize(const Area& bufferArea, android_pixel_format_t format,
78 FenceCallback callback, void* callbackArgs)
79 {
80 sp<IGraphicBufferProducer> producer;
81 sp<IGraphicBufferConsumer> consumer;
82 BufferQueue::createBufferQueue(&producer, &consumer);
83
84 consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
85 consumer->setDefaultBufferFormat(format);
86
87 mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
88
89 mListener = new BufferListener(consumer, callback, callbackArgs);
90 mBufferItemConsumer->setFrameAvailableListener(mListener);
91
92 mSurface = new Surface(producer, true);
93 }
94
95 /* Used by Egl manager. The surface is never displayed. */
96 sp<Surface> getSurface() const
97 {
98 return mSurface;
99 }
100
101private:
102 sp<BufferItemConsumer> mBufferItemConsumer;
103 sp<BufferListener> mListener;
104 /* Used by Egl manager. The surface is never displayed */
105 sp<Surface> mSurface;
106};
107
108
109/* Used to generate valid fences. It is not possible to create a dummy sync
110 * fence for testing. Egl can generate buffers along with a valid fence.
111 * The buffer cannot be guaranteed to be the same format across all devices so
112 * a CPU filled buffer is used instead. The Egl fence is used along with the
113 * CPU filled buffer. */
114class Hwc2TestEglManager {
115public:
116 Hwc2TestEglManager()
117 : mEglDisplay(EGL_NO_DISPLAY),
118 mEglSurface(EGL_NO_SURFACE),
119 mEglContext(EGL_NO_CONTEXT) { }
120
121 ~Hwc2TestEglManager()
122 {
123 cleanup();
124 }
125
126 int initialize(sp<Surface> surface)
127 {
128 mSurface = surface;
129
130 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
131 if (mEglDisplay == EGL_NO_DISPLAY) return false;
132
133 EGLint major;
134 EGLint minor;
135 if (!eglInitialize(mEglDisplay, &major, &minor)) {
136 ALOGW("Could not initialize EGL");
137 return false;
138 }
139
140 /* We're going to use a 1x1 pbuffer surface later on
141 * The configuration distance doesn't really matter for what we're
142 * trying to do */
143 EGLint configAttrs[] = {
144 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
145 EGL_RED_SIZE, 8,
146 EGL_GREEN_SIZE, 8,
147 EGL_BLUE_SIZE, 8,
148 EGL_ALPHA_SIZE, 0,
149 EGL_DEPTH_SIZE, 24,
150 EGL_STENCIL_SIZE, 0,
151 EGL_NONE
152 };
153
154 EGLConfig configs[1];
155 EGLint configCnt;
156 if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
157 &configCnt)) {
158 ALOGW("Could not select EGL configuration");
159 eglReleaseThread();
160 eglTerminate(mEglDisplay);
161 return false;
162 }
163
164 if (configCnt <= 0) {
165 ALOGW("Could not find EGL configuration");
166 eglReleaseThread();
167 eglTerminate(mEglDisplay);
168 return false;
169 }
170
171 /* These objects are initialized below but the default "null" values are
172 * used to cleanup properly at any point in the initialization sequence */
173 EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
174 mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
175 attrs);
176 if (mEglContext == EGL_NO_CONTEXT) {
177 ALOGW("Could not create EGL context");
178 cleanup();
179 return false;
180 }
181
182 EGLint surfaceAttrs[] = { EGL_NONE };
183 mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
184 mSurface.get(), surfaceAttrs);
185 if (mEglSurface == EGL_NO_SURFACE) {
186 ALOGW("Could not create EGL surface");
187 cleanup();
188 return false;
189 }
190
191 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
192 ALOGW("Could not change current EGL context");
193 cleanup();
194 return false;
195 }
196
197 return true;
198 }
199
200 void makeCurrent() const
201 {
202 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
203 }
204
205 void present() const
206 {
207 eglSwapBuffers(mEglDisplay, mEglSurface);
208 }
209
210private:
211 void cleanup()
212 {
213 if (mEglDisplay == EGL_NO_DISPLAY)
214 return;
215 if (mEglSurface != EGL_NO_SURFACE)
216 eglDestroySurface(mEglDisplay, mEglSurface);
217 if (mEglContext != EGL_NO_CONTEXT)
218 eglDestroyContext(mEglDisplay, mEglContext);
219
220 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
221 EGL_NO_CONTEXT);
222 eglReleaseThread();
223 eglTerminate(mEglDisplay);
224 }
225
226 sp<Surface> mSurface;
227 EGLDisplay mEglDisplay;
228 EGLSurface mEglSurface;
229 EGLContext mEglContext;
230};
231
232
233static const std::array<vec2, 4> triangles = {{
234 { 1.0f, 1.0f },
235 { -1.0f, 1.0f },
236 { 1.0f, -1.0f },
237 { -1.0f, -1.0f },
238}};
239
240class Hwc2TestFenceGenerator {
241public:
242
243 Hwc2TestFenceGenerator()
244 {
245 mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
246 setFence, this);
247
248 if (!mEglManager.initialize(mSurfaceManager.getSurface()))
249 return;
250
251 mEglManager.makeCurrent();
252
253 glClearColor(0.0, 0.0, 0.0, 1.0);
254 glEnableVertexAttribArray(0);
255 }
256
257 ~Hwc2TestFenceGenerator()
258 {
259 if (mFence >= 0)
260 close(mFence);
261 mFence = -1;
262
263 mEglManager.makeCurrent();
264 }
265
266 /* It is not possible to simply generate a fence. The easiest way is to
267 * generate a buffer using egl and use the associated fence. The buffer
268 * cannot be guaranteed to be a certain format across all devices using this
269 * method. Instead the buffer is generated using the CPU */
270 int32_t get()
271 {
272 if (mFence >= 0) {
273 return dup(mFence);
274 }
275
276 std::unique_lock<std::mutex> lock(mMutex);
277
278 /* If the pending is still set to false and times out, we cannot recover.
279 * Set an error and return */
280 while (mPending != false) {
281 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
282 return -ETIME;
283 }
284
285 /* Generate a fence. The fence will be returned through the setFence
286 * callback */
287 mEglManager.makeCurrent();
288
289 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
290 glClear(GL_COLOR_BUFFER_BIT);
291
292 mEglManager.present();
293
294 /* Wait for the setFence callback */
295 while (mPending != true) {
296 if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
297 return -ETIME;
298 }
299
300 mPending = false;
301
302 return dup(mFence);
303 }
304
305 /* Callback that sets the fence */
306 void set(int32_t fence)
307 {
308 mFence = fence;
309 mPending = true;
310
311 mCv.notify_all();
312 }
313
314private:
315
316 Hwc2TestSurfaceManager mSurfaceManager;
317 Hwc2TestEglManager mEglManager;
318
319 std::mutex mMutex;
320 std::condition_variable mCv;
321
322 int32_t mFence = -1;
323 bool mPending = false;
324};
325
326
327static void setFence(int32_t fence, void* fenceGenerator)
328{
329 static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
330}
331
332
333Hwc2TestBuffer::Hwc2TestBuffer()
334 : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
335
336Hwc2TestBuffer::~Hwc2TestBuffer() = default;
337
338/* When the buffer changes sizes, save the new size and invalidate the current
339 * buffer */
340void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
341{
342 if (mBufferArea.width == bufferArea.width
343 && mBufferArea.height == bufferArea.height)
344 return;
345
346 mBufferArea.width = bufferArea.width;
347 mBufferArea.height = bufferArea.height;
348
349 mValidBuffer = false;
350}
351
352/* Returns a valid buffer handle and fence. The handle is filled using the CPU
353 * to ensure the correct format across all devices. The fence is created using
354 * egl. */
355int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
356{
357 if (mBufferArea.width == -1 || mBufferArea.height == -1)
358 return -EINVAL;
359
360 /* If the current buffer is valid, the previous buffer can be reused.
361 * Otherwise, create new buffer */
362 if (!mValidBuffer) {
363 int ret = generateBuffer();
364 if (ret)
365 return ret;
366 }
367
368 *outFence = mFenceGenerator->get();
369 *outHandle = mHandle;
370
371 mValidBuffer = true;
372
373 return 0;
374}
375
376/* CPU fills a buffer to guarantee the correct buffer format across all
377 * devices */
378int Hwc2TestBuffer::generateBuffer()
379{
380 int ret;
381
382 /* Create new graphic buffer with correct dimensions */
383 mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer(
384 mBufferArea.width, mBufferArea.height, mFormat,
385 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
386 "hwc2_test_buffer", &ret);
387 if (ret)
388 return ret;
389
390 /* Locks the buffer for writing */
391 uint8_t* img;
392 mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
393
394 uint32_t stride = mGraphicBuffer->getStride();
395
396 /* Iterate from the top row of the buffer to the bottom row */
397 for (int32_t y = 0; y < mBufferArea.height; y++) {
398
399 /* Will be used as R, G and B values for pixel colors */
400 uint8_t max = 255;
401 uint8_t min = 0;
402
403 /* Divide the rows into 3 sections. The first section will contain
404 * the lighest colors. The last section will contain the darkest
405 * colors. */
406 if (y < mBufferArea.height * 1.0 / 3.0) {
407 min = 255 / 2;
408 } else if (y >= mBufferArea.height * 2.0 / 3.0) {
409 max = 255 / 2;
410 }
411
412 /* Divide the columns into 3 sections. The first section is red,
413 * the second is green and the third is blue */
414 int32_t x = 0;
415 for (; x < mBufferArea.width / 3; x++) {
416 setColor(x, y, mFormat, stride, img, max, min, min, 255);
417 }
418
419 for (; x < mBufferArea.width * 2 / 3; x++) {
420 setColor(x, y, mFormat, stride, img, min, max, min, 255);
421 }
422
423 for (; x < mBufferArea.width; x++) {
424 setColor(x, y, mFormat, stride, img, min, min, max, 255);
425 }
426 }
427
428 /* Unlock the buffer for reading */
429 mGraphicBuffer->unlock();
430
431 mHandle = mGraphicBuffer->handle;
432
433 return 0;
434}
435
436/* Sets the pixel of a buffer given the location, format, stride and color.
437 * Currently only supports RGBA_8888 */
438void Hwc2TestBuffer::setColor(int32_t x, int32_t y,
439 android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
440 uint8_t g, uint8_t b, uint8_t a)
441{
442 switch (format) {
443 case HAL_PIXEL_FORMAT_RGBA_8888:
444 img[(y * stride + x) * 4 + 0] = r;
445 img[(y * stride + x) * 4 + 1] = g;
446 img[(y * stride + x) * 4 + 2] = b;
447 img[(y * stride + x) * 4 + 3] = a;
448 break;
449 default:
450 break;
451 }
452}