Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d3eca64 authored by Ján Sebechlebský's avatar Ján Sebechlebský Committed by Android (Google) Code Review
Browse files

Merge "Trigger texture update on each submission of input buffer." into main

parents 726dc68b 18ac32cc
Loading
Loading
Loading
Loading
+70 −8
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <memory>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>

#include "Exif.h"
@@ -78,6 +79,15 @@ using ::android::hardware::camera::common::helper::ExifUtils;

namespace {

// helper type for the visitor
template <class... Ts>
struct overloaded : Ts... {
  using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20)
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

using namespace std::chrono_literals;

static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -89,6 +99,8 @@ static constexpr uint8_t kPipelineDepth = 2;

static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024;  // 32 KiB

static constexpr UpdateTextureTask kUpdateTextureTask;

CameraMetadata createCaptureResultMetadata(
    const std::chrono::nanoseconds timestamp,
    const RequestSettings& requestSettings,
@@ -287,6 +299,21 @@ std::chrono::nanoseconds getMaxFrameDuration(
      static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
}

class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
 public:
  FrameAvailableListenerProxy(std::function<void()> callback)
      : mOnFrameAvailableCallback(callback) {
  }

  virtual void onFrameAvailable(const BufferItem&) override {
    ALOGV("%s: onFrameAvailable", __func__);
    mOnFrameAvailableCallback();
  }

 private:
  std::function<void()> mOnFrameAvailableCallback;
};

}  // namespace

CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -345,9 +372,25 @@ const RequestSettings& ProcessCaptureRequestTask::getRequestSettings() const {
  return mRequestSettings;
}

void VirtualCameraRenderThread::requestTextureUpdate() {
  std::lock_guard<std::mutex> lock(mLock);
  // If queue is not empty, we don't need to set the mTextureUpdateRequested
  // flag, since the texture will be updated during ProcessCaptureRequestTask
  // processing anyway.
  if (mQueue.empty()) {
    mTextureUpdateRequested = true;
    mCondVar.notify_one();
  }
}

void VirtualCameraRenderThread::enqueueTask(
    std::unique_ptr<ProcessCaptureRequestTask> task) {
  std::lock_guard<std::mutex> lock(mLock);
  // When enqueving process capture request task, clear the
  // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
  // updated and it will be updated when processing ProcessCaptureRequestTask
  // anyway.
  mTextureUpdateRequested = false;
  mQueue.emplace_back(std::move(task));
  mCondVar.notify_one();
}
@@ -377,8 +420,7 @@ sp<Surface> VirtualCameraRenderThread::getInputSurface() {
  return mInputSurfaceFuture.get();
}

std::unique_ptr<ProcessCaptureRequestTask>
VirtualCameraRenderThread::dequeueTask() {
RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
  std::unique_lock<std::mutex> lock(mLock);
  // Clang's thread safety analysis doesn't perform alias analysis,
  // so it doesn't support moveable std::unique_lock.
@@ -389,12 +431,20 @@ VirtualCameraRenderThread::dequeueTask() {
  ScopedLockAssertion lockAssertion(mLock);

  mCondVar.wait(lock, [this]() REQUIRES(mLock) {
    return mPendingExit || !mQueue.empty();
    return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
  });
  if (mPendingExit) {
    return nullptr;
    // Render thread task with null task signals render thread to terminate.
    return RenderThreadTask(nullptr);
  }
  std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
  if (mTextureUpdateRequested) {
    // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
    // kUpdateTextureTask to signal we want render thread to update the texture
    // (consume buffer from the queue).
    mTextureUpdateRequested = false;
    return RenderThreadTask(kUpdateTextureTask);
  }
  RenderThreadTask task(std::move(mQueue.front()));
  mQueue.pop_front();
  return task;
}
@@ -409,11 +459,23 @@ void VirtualCameraRenderThread::threadLoop() {
      EglTextureProgram::TextureFormat::RGBA);
  mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
      mInputSurfaceSize.width, mInputSurfaceSize.height);
  sp<FrameAvailableListenerProxy> frameAvailableListener =
      sp<FrameAvailableListenerProxy>::make(
          [this]() { requestTextureUpdate(); });
  mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);

  mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());

  while (std::unique_ptr<ProcessCaptureRequestTask> task = dequeueTask()) {
    processCaptureRequest(*task);
  while (RenderThreadTask task = dequeueTask()) {
    std::visit(
        overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
                     processTask(*t);
                   },
                   [this](const UpdateTextureTask&) {
                     ALOGV("Idle update of the texture");
                     mEglSurfaceTexture->updateTexture();
                   }},
        task);
  }

  // Destroy EGL utilities still on the render thread.
@@ -425,7 +487,7 @@ void VirtualCameraRenderThread::threadLoop() {
  ALOGV("Render thread exiting");
}

void VirtualCameraRenderThread::processCaptureRequest(
void VirtualCameraRenderThread::processTask(
    const ProcessCaptureRequestTask& request) {
  std::chrono::nanoseconds timestamp =
      std::chrono::duration_cast<std::chrono::nanoseconds>(
+28 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <future>
#include <memory>
#include <thread>
#include <variant>
#include <vector>

#include "VirtualCameraDevice.h"
@@ -34,7 +35,6 @@
#include "util/EglFramebuffer.h"
#include "util/EglProgram.h"
#include "util/EglSurfaceTexture.h"
#include "util/MetadataUtil.h"
#include "util/Util.h"

namespace android {
@@ -94,6 +94,24 @@ class ProcessCaptureRequestTask {
  const RequestSettings mRequestSettings;
};

struct UpdateTextureTask {};

struct RenderThreadTask
    : public std::variant<std::unique_ptr<ProcessCaptureRequestTask>,
                          UpdateTextureTask> {
  // Allow implicit conversion to bool.
  //
  // Returns false, if the RenderThreadTask consist of null
  // ProcessCaptureRequestTask, which signals that the thread should terminate.
  operator bool() const {
    const bool isExitSignal =
        std::holds_alternative<std::unique_ptr<ProcessCaptureRequestTask>>(
            *this) &&
        std::get<std::unique_ptr<ProcessCaptureRequestTask>>(*this) == nullptr;
    return !isExitSignal;
  }
};

// Wraps dedicated rendering thread and rendering business with corresponding
// input surface.
class VirtualCameraRenderThread {
@@ -120,6 +138,12 @@ class VirtualCameraRenderThread {
  // Stop rendering thread.
  void stop();

  // Send request to render thread to update the texture.
  // Currently queued buffers in the input surface will be consumed and the most
  // recent buffer in the input surface will be attached to the texture), all
  // other buffers will be returned to the buffer queue.
  void requestTextureUpdate() EXCLUDES(mLock);

  // Equeue capture task for processing on render thread.
  void enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)
      EXCLUDES(mLock);
@@ -131,13 +155,13 @@ class VirtualCameraRenderThread {
  sp<Surface> getInputSurface();

 private:
  std::unique_ptr<ProcessCaptureRequestTask> dequeueTask() EXCLUDES(mLock);
  RenderThreadTask dequeueTask() EXCLUDES(mLock);

  // Rendering thread entry point.
  void threadLoop();

  // Process single capture request task (always called on render thread).
  void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
  void processTask(const ProcessCaptureRequestTask& captureRequestTask);

  // Flush single capture request task returning the error status immediately.
  void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -192,6 +216,7 @@ class VirtualCameraRenderThread {
  std::mutex mLock;
  std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
  std::condition_variable mCondVar;
  volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
  volatile bool mPendingExit GUARDED_BY(mLock);

  // Acquisition timestamp of last frame.
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ sp<GraphicBuffer> EglSurfaceTexture::getCurrentBuffer() {
  return mGlConsumer->getCurrentBuffer();
}

void EglSurfaceTexture::setFrameAvailableListener(
    const wp<ConsumerBase::FrameAvailableListener>& listener) {
  mGlConsumer->setFrameAvailableListener(listener);
}

bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
  return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
                                    static_cast<nsecs_t>(timeout.count()));
+4 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <cstdint>

#include "GLES/gl.h"
#include "gui/ConsumerBase.h"
#include "gui/Surface.h"
#include "utils/RefBase.h"

@@ -58,6 +59,9 @@ class EglSurfaceTexture {
  // Returns false on timeout, true if new frame was received before timeout.
  bool waitForNextFrame(std::chrono::nanoseconds timeout);

  void setFrameAvailableListener(
      const wp<ConsumerBase::FrameAvailableListener>& listener);

  // Update the texture with the most recent submitted buffer.
  // Most be called on thread with EGL context.
  //