Commit c9e34c6e authored by Vasiliy Telezhnikov's avatar Vasiliy Telezhnikov Committed by Chromium LUCI CQ

Delay getting FrameInfo until buffer is available

When resolution changes midstread in ImageReader/SurfaceControl mode it
is possible that ImageReader currently have no buffers available. We
request 3 buffers and they can be:
* One is on screen, owned by SurfaceFlinger
* One is in pending transaction to be presented.
* One is queued by Chrome to submit when pending one will be presented.

This CL delays rendering of the frame for getting FrameInfo until we
will have slot available.

Bug: 1115307
Change-Id: I65d5002e338f4a445e7cd15a5b975954a5e64912
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2563280Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#832339}
parent 3782ec05
......@@ -401,6 +401,9 @@ void ImageReaderGLOwner::ReleaseRefOnImage(AImage* image,
}
image_refs_.erase(it);
DCHECK_GT(max_images_, static_cast<int32_t>(image_refs_.size()));
if (buffer_available_cb_)
std::move(buffer_available_cb_).Run();
}
void ImageReaderGLOwner::ReleaseBackBuffers() {
......@@ -428,6 +431,20 @@ void ImageReaderGLOwner::OnFrameAvailable(void* context, AImageReader* reader) {
image_reader_ptr->frame_available_cb_.Run();
}
void ImageReaderGLOwner::RunWhenBufferIsAvailable(base::OnceClosure callback) {
// Note that we handle only one simultaneous request, this is not issue
// because FrameInfoHelper maintain request queue and has only single
// outstanding request on GPU thread.
DCHECK(!buffer_available_cb_);
// If `max_images` == 1 we will drop it before acquiring new buffer. Note that
// this must never happen with SurfaceControl and the ImageReaderGLOwner is
// the sole owner of the images.
if (max_images_ == 1 || static_cast<int>(image_refs_.size()) < max_images_)
std::move(callback).Run();
else
buffer_available_cb_ = std::move(callback);
}
bool ImageReaderGLOwner::GetCodedSizeAndVisibleRect(
gfx::Size rotated_visible_size,
gfx::Size* coded_size,
......
......@@ -44,6 +44,7 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner {
bool GetCodedSizeAndVisibleRect(gfx::Size rotated_visible_size,
gfx::Size* coded_size,
gfx::Rect* visible_rect) override;
void RunWhenBufferIsAvailable(base::OnceClosure callback) override;
const AImageReader* image_reader_for_testing() const { return image_reader_; }
int32_t max_images_for_testing() const { return max_images_; }
......@@ -131,6 +132,9 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner {
// in turns runs the callback function.
base::RepeatingClosure frame_available_cb_;
// Runs when free buffer is available.
base::OnceClosure buffer_available_cb_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<ImageReaderGLOwner> weak_factory_{this};
......
......@@ -8,6 +8,7 @@
namespace gpu {
using testing::_;
using testing::Invoke;
using testing::Return;
......@@ -26,6 +27,8 @@ MockTextureOwner::MockTextureOwner(GLuint fake_texture_id,
ON_CALL(*this, EnsureTexImageBound()).WillByDefault(Invoke([this] {
CHECK(expect_update_tex_image);
}));
ON_CALL(*this, RunWhenBufferIsAvailable(_))
.WillByDefault(Invoke([](base::OnceClosure cb) { std::move(cb).Run(); }));
}
MockTextureOwner::~MockTextureOwner() {
......
......@@ -40,6 +40,7 @@ class MockTextureOwner : public TextureOwner {
bool(gfx::Size rotated_visible_size,
gfx::Size* coded_size,
gfx::Rect* visible_rect));
MOCK_METHOD1(RunWhenBufferIsAvailable, void(base::OnceClosure));
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override {
......
......@@ -57,6 +57,12 @@ void SurfaceTextureGLOwner::SetFrameAvailableCallback(
surface_texture_->SetFrameAvailableCallbackOnAnyThread(frame_available_cb);
}
void SurfaceTextureGLOwner::RunWhenBufferIsAvailable(
base::OnceClosure callback) {
// SurfaceTexture can always render to front buffer.
std::move(callback).Run();
}
gl::ScopedJavaSurface SurfaceTextureGLOwner::CreateJavaSurface() const {
// |surface_texture_| might be null, but that's okay.
return gl::ScopedJavaSurface(surface_texture_.get());
......
......@@ -40,6 +40,8 @@ class GPU_GLES2_EXPORT SurfaceTextureGLOwner : public TextureOwner {
gfx::Size* coded_size,
gfx::Rect* visible_rect) override;
void RunWhenBufferIsAvailable(base::OnceClosure callback) override;
protected:
void OnTextureDestroyed(gles2::AbstractTexture*) override;
......
......@@ -115,6 +115,10 @@ class GPU_GLES2_EXPORT TextureOwner
virtual void SetFrameAvailableCallback(
const base::RepeatingClosure& frame_available_cb) = 0;
// Runs callback when the free buffer is available to render to front buffer.
// Can be run before returning from the function.
virtual void RunWhenBufferIsAvailable(base::OnceClosure callback) = 0;
bool binds_texture_on_update() const { return binds_texture_on_update_; }
protected:
......
......@@ -68,7 +68,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
stub_ = nullptr;
}
void GetFrameInfo(
void GetFrameInfoImpl(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
base::Optional<FrameInfo>)> cb) {
......@@ -95,6 +95,21 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
std::move(cb).Run(std::move(buffer_renderer), info);
}
void GetFrameInfo(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
base::Optional<FrameInfo>)> cb) {
DCHECK(buffer_renderer);
auto texture_owner = buffer_renderer->texture_owner();
DCHECK(texture_owner);
auto buffer_available_cb =
base::BindOnce(&OnGpu::GetFrameInfoImpl, weak_factory_.GetWeakPtr(),
std::move(buffer_renderer), std::move(cb));
texture_owner->RunWhenBufferIsAvailable(std::move(buffer_available_cb));
}
private:
// Gets YCbCrInfo from last rendered frame.
base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo(
......@@ -117,6 +132,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
}
gpu::CommandBufferStub* stub_ = nullptr;
base::WeakPtrFactory<OnGpu> weak_factory_{this};
};
FrameInfo GetFrameInfoWithVisibleSize(const gfx::Size& visible_size) {
......
......@@ -12,6 +12,7 @@
using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::Mock;
using testing::Return;
using testing::SetArgPointee;
......@@ -245,4 +246,50 @@ TEST_F(FrameInfoHelperTest, FailedGetCodedSize) {
Mock::VerifyAndClearExpectations(texture_owner.get());
}
TEST_F(FrameInfoHelperTest, TextureOwnerBufferNotAvailable) {
auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
0, nullptr, nullptr, true);
// Return CodedSize when GetCodedSizeAndVisibleRect is called.
ON_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _))
.WillByDefault(DoAll(SetArgPointee<1>(kTestCodedSize), Return(true)));
// Save buffer available callback, we will run it manually.
base::OnceClosure buffer_available_cb;
EXPECT_CALL(*texture_owner, RunWhenBufferIsAvailable(_))
.WillOnce(Invoke([&buffer_available_cb](base::OnceClosure cb) {
buffer_available_cb = std::move(cb);
}));
// Verify that no GetCodedSizeAndVisibleRect will be called until buffer is
// available.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
// Note that we can't use helper above because the callback won't run until a
// buffer is available.
auto buffer_renderer = CreateBufferRenderer(kTestVisibleSize, texture_owner);
const auto* buffer_renderer_raw = buffer_renderer.get();
bool called = false;
auto callback = base::BindLambdaForTesting(
[&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
FrameInfoHelper::FrameInfo info) {
ASSERT_EQ(buffer_renderer_raw, buffer_renderer.get());
called = true;
last_frame_info_ = info;
});
helper_->GetFrameInfo(std::move(buffer_renderer), callback);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(buffer_available_cb);
Mock::VerifyAndClearExpectations(texture_owner.get());
// When buffer is available we expect GetCodedSizeAndVisibleRect to be called
// and result should be kTestCodedSize.
EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
std::move(buffer_available_cb).Run();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
ASSERT_TRUE(called);
Mock::VerifyAndClearExpectations(texture_owner.get());
}
} // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment