• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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