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, ...@@ -401,6 +401,9 @@ void ImageReaderGLOwner::ReleaseRefOnImage(AImage* image,
} }
image_refs_.erase(it); 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() { void ImageReaderGLOwner::ReleaseBackBuffers() {
...@@ -428,6 +431,20 @@ void ImageReaderGLOwner::OnFrameAvailable(void* context, AImageReader* reader) { ...@@ -428,6 +431,20 @@ void ImageReaderGLOwner::OnFrameAvailable(void* context, AImageReader* reader) {
image_reader_ptr->frame_available_cb_.Run(); 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( bool ImageReaderGLOwner::GetCodedSizeAndVisibleRect(
gfx::Size rotated_visible_size, gfx::Size rotated_visible_size,
gfx::Size* coded_size, gfx::Size* coded_size,
......
...@@ -44,6 +44,7 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner { ...@@ -44,6 +44,7 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner {
bool GetCodedSizeAndVisibleRect(gfx::Size rotated_visible_size, bool GetCodedSizeAndVisibleRect(gfx::Size rotated_visible_size,
gfx::Size* coded_size, gfx::Size* coded_size,
gfx::Rect* visible_rect) override; gfx::Rect* visible_rect) override;
void RunWhenBufferIsAvailable(base::OnceClosure callback) override;
const AImageReader* image_reader_for_testing() const { return image_reader_; } const AImageReader* image_reader_for_testing() const { return image_reader_; }
int32_t max_images_for_testing() const { return max_images_; } int32_t max_images_for_testing() const { return max_images_; }
...@@ -131,6 +132,9 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner { ...@@ -131,6 +132,9 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner {
// in turns runs the callback function. // in turns runs the callback function.
base::RepeatingClosure frame_available_cb_; base::RepeatingClosure frame_available_cb_;
// Runs when free buffer is available.
base::OnceClosure buffer_available_cb_;
THREAD_CHECKER(thread_checker_); THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<ImageReaderGLOwner> weak_factory_{this}; base::WeakPtrFactory<ImageReaderGLOwner> weak_factory_{this};
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace gpu { namespace gpu {
using testing::_;
using testing::Invoke; using testing::Invoke;
using testing::Return; using testing::Return;
...@@ -26,6 +27,8 @@ MockTextureOwner::MockTextureOwner(GLuint fake_texture_id, ...@@ -26,6 +27,8 @@ MockTextureOwner::MockTextureOwner(GLuint fake_texture_id,
ON_CALL(*this, EnsureTexImageBound()).WillByDefault(Invoke([this] { ON_CALL(*this, EnsureTexImageBound()).WillByDefault(Invoke([this] {
CHECK(expect_update_tex_image); CHECK(expect_update_tex_image);
})); }));
ON_CALL(*this, RunWhenBufferIsAvailable(_))
.WillByDefault(Invoke([](base::OnceClosure cb) { std::move(cb).Run(); }));
} }
MockTextureOwner::~MockTextureOwner() { MockTextureOwner::~MockTextureOwner() {
......
...@@ -40,6 +40,7 @@ class MockTextureOwner : public TextureOwner { ...@@ -40,6 +40,7 @@ class MockTextureOwner : public TextureOwner {
bool(gfx::Size rotated_visible_size, bool(gfx::Size rotated_visible_size,
gfx::Size* coded_size, gfx::Size* coded_size,
gfx::Rect* visible_rect)); gfx::Rect* visible_rect));
MOCK_METHOD1(RunWhenBufferIsAvailable, void(base::OnceClosure));
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override { GetAHardwareBuffer() override {
......
...@@ -57,6 +57,12 @@ void SurfaceTextureGLOwner::SetFrameAvailableCallback( ...@@ -57,6 +57,12 @@ void SurfaceTextureGLOwner::SetFrameAvailableCallback(
surface_texture_->SetFrameAvailableCallbackOnAnyThread(frame_available_cb); 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 { gl::ScopedJavaSurface SurfaceTextureGLOwner::CreateJavaSurface() const {
// |surface_texture_| might be null, but that's okay. // |surface_texture_| might be null, but that's okay.
return gl::ScopedJavaSurface(surface_texture_.get()); return gl::ScopedJavaSurface(surface_texture_.get());
......
...@@ -40,6 +40,8 @@ class GPU_GLES2_EXPORT SurfaceTextureGLOwner : public TextureOwner { ...@@ -40,6 +40,8 @@ class GPU_GLES2_EXPORT SurfaceTextureGLOwner : public TextureOwner {
gfx::Size* coded_size, gfx::Size* coded_size,
gfx::Rect* visible_rect) override; gfx::Rect* visible_rect) override;
void RunWhenBufferIsAvailable(base::OnceClosure callback) override;
protected: protected:
void OnTextureDestroyed(gles2::AbstractTexture*) override; void OnTextureDestroyed(gles2::AbstractTexture*) override;
......
...@@ -115,6 +115,10 @@ class GPU_GLES2_EXPORT TextureOwner ...@@ -115,6 +115,10 @@ class GPU_GLES2_EXPORT TextureOwner
virtual void SetFrameAvailableCallback( virtual void SetFrameAvailableCallback(
const base::RepeatingClosure& frame_available_cb) = 0; 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_; } bool binds_texture_on_update() const { return binds_texture_on_update_; }
protected: protected:
......
...@@ -68,7 +68,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper { ...@@ -68,7 +68,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
stub_ = nullptr; stub_ = nullptr;
} }
void GetFrameInfo( void GetFrameInfoImpl(
std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>,
base::Optional<FrameInfo>)> cb) { base::Optional<FrameInfo>)> cb) {
...@@ -95,6 +95,21 @@ class FrameInfoHelperImpl : public FrameInfoHelper { ...@@ -95,6 +95,21 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
std::move(cb).Run(std::move(buffer_renderer), info); 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: private:
// Gets YCbCrInfo from last rendered frame. // Gets YCbCrInfo from last rendered frame.
base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo( base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo(
...@@ -117,6 +132,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper { ...@@ -117,6 +132,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper {
} }
gpu::CommandBufferStub* stub_ = nullptr; gpu::CommandBufferStub* stub_ = nullptr;
base::WeakPtrFactory<OnGpu> weak_factory_{this};
}; };
FrameInfo GetFrameInfoWithVisibleSize(const gfx::Size& visible_size) { FrameInfo GetFrameInfoWithVisibleSize(const gfx::Size& visible_size) {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
using testing::_; using testing::_;
using testing::DoAll; using testing::DoAll;
using testing::Invoke;
using testing::Mock; using testing::Mock;
using testing::Return; using testing::Return;
using testing::SetArgPointee; using testing::SetArgPointee;
...@@ -245,4 +246,50 @@ TEST_F(FrameInfoHelperTest, FailedGetCodedSize) { ...@@ -245,4 +246,50 @@ TEST_F(FrameInfoHelperTest, FailedGetCodedSize) {
Mock::VerifyAndClearExpectations(texture_owner.get()); 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 } // 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