1 /*
2 * Copyright (C) 2023 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 // #define LOG_NDEBUG 0
18 #define LOG_TAG "EglSurfaceTexture"
19
20 #include "EglSurfaceTexture.h"
21
22 #include <GLES/gl.h>
23 #include <com_android_graphics_libgui_flags.h>
24 #include <gui/BufferQueue.h>
25 #include <gui/GLConsumer.h>
26 #include <hardware/gralloc.h>
27
28 #include <chrono>
29 #include <cstdint>
30 #include <mutex>
31
32 #include "EglUtil.h"
33
34 namespace android {
35 namespace companion {
36 namespace virtualcamera {
37 namespace {
38
39 // Maximal number of buffers producer can dequeue without blocking.
40 constexpr int kBufferProducerMaxDequeueBufferCount = 64;
41
42 } // namespace
43
FrameAvailableListenerProxy(EglSurfaceTexture * surface)44 EglSurfaceTexture::FrameAvailableListenerProxy::FrameAvailableListenerProxy(
45 EglSurfaceTexture* surface)
46 : mSurface(*surface) {
47 }
48
setCallback(const std::function<void ()> & callback)49 void EglSurfaceTexture::FrameAvailableListenerProxy::setCallback(
50 const std::function<void()>& callback) {
51 mOnFrameAvailableCallback = callback;
52 }
53
onFrameAvailable(const BufferItem &)54 void EglSurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(
55 const BufferItem&) {
56 long frameNumber = mSurface.mGlConsumer->getFrameNumber();
57 ALOGV("%s: onFrameAvailable frameNumber %ld", __func__, frameNumber);
58 mSurface.mFrameAvailableCondition.notify_all();
59 if (mOnFrameAvailableCallback) {
60 mOnFrameAvailableCallback();
61 }
62 }
63
EglSurfaceTexture(const uint32_t width,const uint32_t height)64 EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height)
65 : mWidth(width), mHeight(height) {
66 glGenTextures(1, &mTextureId);
67 if (checkEglError("EglSurfaceTexture(): glGenTextures")) {
68 ALOGE("Failed to generate texture");
69 return;
70 }
71
72 std::tie(mGlConsumer, mSurface) = GLConsumer::create(
73 mTextureId, GLConsumer::TEXTURE_EXTERNAL, false, false);
74 mGlConsumer->setName(String8("VirtualCameraEglSurfaceTexture"));
75 mGlConsumer->setDefaultBufferSize(mWidth, mHeight);
76 mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
77 mGlConsumer->setDefaultBufferFormat(AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420);
78
79 mSurface->setMaxDequeuedBufferCount(kBufferProducerMaxDequeueBufferCount);
80
81 mFrameAvailableListenerProxy = sp<FrameAvailableListenerProxy>::make(this);
82 mGlConsumer->setFrameAvailableListener(mFrameAvailableListenerProxy);
83 }
84
~EglSurfaceTexture()85 EglSurfaceTexture::~EglSurfaceTexture() {
86 if (mTextureId != 0) {
87 glDeleteTextures(1, &mTextureId);
88 }
89 }
90
getSurface()91 sp<Surface> EglSurfaceTexture::getSurface() {
92 return mSurface;
93 }
94
getCurrentBuffer()95 sp<GraphicBuffer> EglSurfaceTexture::getCurrentBuffer() {
96 return mGlConsumer->getCurrentBuffer();
97 }
98
setFrameAvailableListener(const std::function<void ()> & listener)99 void EglSurfaceTexture::setFrameAvailableListener(
100 const std::function<void()>& listener) {
101 mFrameAvailableListenerProxy->setCallback(listener);
102 }
103
waitForNextFrame(const std::chrono::nanoseconds timeout)104 bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
105 std::unique_lock<std::mutex> lock(mWaitForFrameMutex);
106 mGlConsumer->updateTexImage();
107 const long lastRenderedFrame = mGlConsumer->getFrameNumber();
108 const long lastWaitedForFrame = mLastWaitedFrame.exchange(lastRenderedFrame);
109 ALOGV("%s lastRenderedFrame:%ld lastWaitedForFrame: %ld", __func__,
110 lastRenderedFrame, lastWaitedForFrame);
111 if (lastRenderedFrame > lastWaitedForFrame) {
112 return true;
113 }
114 ALOGV(
115 "%s waiting for max %lld ns. Last waited frame:%ld, last rendered "
116 "frame:%ld",
117 __func__, timeout.count(), lastWaitedForFrame, lastRenderedFrame);
118 return mFrameAvailableCondition.wait_for(lock, timeout, [this]() {
119 // Call updateTexImage to update the frame number.
120 mGlConsumer->updateTexImage();
121 const long lastRenderedFrame = mGlConsumer->getFrameNumber();
122 return lastRenderedFrame > mLastWaitedFrame.exchange(lastRenderedFrame);
123 });
124 }
125
getTimestamp()126 std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
127 return std::chrono::nanoseconds(mGlConsumer->getTimestamp());
128 }
129
isFirstFrameDrawn()130 bool EglSurfaceTexture::isFirstFrameDrawn() {
131 return mGlConsumer->getFrameNumber() > 0;
132 }
133
updateTexture()134 GLuint EglSurfaceTexture::updateTexture() {
135 int previousFrameId;
136 int framesAdvance = 0;
137 // Consume buffers one at the time.
138 // Contrary to the code comments in GLConsumer, the GLConsumer acquires
139 // next queued buffer (not the most recently queued buffer).
140 while (true) {
141 previousFrameId = mGlConsumer->getFrameNumber();
142 mGlConsumer->updateTexImage();
143 int currentFrameId = mGlConsumer->getFrameNumber();
144 if (previousFrameId == currentFrameId) {
145 // Frame number didn't change after updating the texture,
146 // this means we're at the end of the queue and current attached
147 // buffer is the most recent buffer.
148 break;
149 }
150
151 framesAdvance++;
152 previousFrameId = currentFrameId;
153 }
154 ALOGV("%s: Advanced %d frames", __func__, framesAdvance);
155 return mTextureId;
156 }
157
getTextureId() const158 GLuint EglSurfaceTexture::getTextureId() const {
159 return mTextureId;
160 }
161
getTransformMatrix()162 std::array<float, 16> EglSurfaceTexture::getTransformMatrix() {
163 std::array<float, 16> matrix;
164 mGlConsumer->getTransformMatrix(matrix.data());
165 return matrix;
166 }
167
getWidth() const168 uint32_t EglSurfaceTexture::getWidth() const {
169 return mWidth;
170 }
171
getHeight() const172 uint32_t EglSurfaceTexture::getHeight() const {
173 return mHeight;
174 }
175
176 } // namespace virtualcamera
177 } // namespace companion
178 } // namespace android
179