blob: ddc219d3f9e2d677725d9067f06affba66239d7e [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include "media/gpu/ipc/service/picture_buffer_manager.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
#include "media/gpu/fake_command_buffer_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace {
// TODO(sandersd): Should be part of //media, as it is used by
// MojoVideoDecoderService (production code) as well.
class StaticSyncTokenClient : public VideoFrame::SyncTokenClient {
public:
explicit StaticSyncTokenClient(const gpu::SyncToken& sync_token)
: sync_token_(sync_token) {}
void GenerateSyncToken(gpu::SyncToken* sync_token) final {
*sync_token = sync_token_;
}
void WaitSyncToken(const gpu::SyncToken& sync_token) final {}
private:
gpu::SyncToken sync_token_;
DISALLOW_COPY_AND_ASSIGN(StaticSyncTokenClient);
};
} // namespace
class PictureBufferManagerImplTest : public testing::Test {
public:
explicit PictureBufferManagerImplTest() {
// TODO(sandersd): Use a separate thread for the GPU task runner.
cbh_ = base::MakeRefCounted<FakeCommandBufferHelper>(
environment_.GetMainThreadTaskRunner());
pbm_ = PictureBufferManager::Create(reuse_cb_.Get());
}
~PictureBufferManagerImplTest() override {}
protected:
void Initialize() {
pbm_->Initialize(environment_.GetMainThreadTaskRunner(), cbh_);
}
std::vector<PictureBuffer> CreateARGBPictureBuffers(uint32_t count) {
return pbm_->CreatePictureBuffers(count, PIXEL_FORMAT_ARGB, 1,
gfx::Size(320, 240), GL_TEXTURE_2D);
}
PictureBuffer CreateARGBPictureBuffer() {
std::vector<PictureBuffer> picture_buffers = CreateARGBPictureBuffers(1);
DCHECK_EQ(picture_buffers.size(), 1U);
return picture_buffers[0];
}
scoped_refptr<VideoFrame> CreateVideoFrame(int32_t picture_buffer_id) {
return pbm_->CreateVideoFrame(
Picture(picture_buffer_id, // picture_buffer_id
0, // bitstream_buffer_id
gfx::Rect(), // visible_rect (ignored)
gfx::ColorSpace::CreateSRGB(), // color_space
false), // allow_overlay
base::TimeDelta(), // timestamp
gfx::Rect(), // visible_rect
gfx::Size()); // natural_size
}
gpu::SyncToken GenerateSyncToken(scoped_refptr<VideoFrame> video_frame) {
gpu::SyncToken sync_token(gpu::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(1),
next_release_count_++);
StaticSyncTokenClient sync_token_client(sync_token);
video_frame->UpdateReleaseSyncToken(&sync_token_client);
return sync_token;
}
base::test::ScopedTaskEnvironment environment_;
uint64_t next_release_count_ = 1;
testing::StrictMock<
base::MockCallback<PictureBufferManager::ReusePictureBufferCB>>
reuse_cb_;
scoped_refptr<FakeCommandBufferHelper> cbh_;
scoped_refptr<PictureBufferManager> pbm_;
DISALLOW_COPY_AND_ASSIGN(PictureBufferManagerImplTest);
};
TEST_F(PictureBufferManagerImplTest, CreateAndDestroy) {}
TEST_F(PictureBufferManagerImplTest, Initialize) {
Initialize();
}
TEST_F(PictureBufferManagerImplTest, CreatePictureBuffer) {
Initialize();
PictureBuffer pb = CreateARGBPictureBuffer();
EXPECT_TRUE(cbh_->HasTexture(pb.client_texture_ids()[0]));
}
TEST_F(PictureBufferManagerImplTest, CreatePictureBuffer_ContextLost) {
Initialize();
cbh_->ContextLost();
std::vector<PictureBuffer> pbs = CreateARGBPictureBuffers(1);
EXPECT_TRUE(pbs.empty());
}
TEST_F(PictureBufferManagerImplTest, ReusePictureBuffer) {
Initialize();
PictureBuffer pb = CreateARGBPictureBuffer();
scoped_refptr<VideoFrame> frame = CreateVideoFrame(pb.id());
// Dropping the frame does not immediately trigger reuse.
gpu::SyncToken sync_token = GenerateSyncToken(frame);
frame = nullptr;
environment_.RunUntilIdle();
// Completing the SyncToken wait does.
EXPECT_CALL(reuse_cb_, Run(pb.id()));
cbh_->ReleaseSyncToken(sync_token);
environment_.RunUntilIdle();
}
TEST_F(PictureBufferManagerImplTest, DismissPictureBuffer_Available) {
Initialize();
PictureBuffer pb = CreateARGBPictureBuffer();
pbm_->DismissPictureBuffer(pb.id());
// Allocated textures should be deleted soon.
environment_.RunUntilIdle();
EXPECT_FALSE(cbh_->HasTexture(pb.client_texture_ids()[0]));
}
TEST_F(PictureBufferManagerImplTest, DismissPictureBuffer_Output) {
Initialize();
PictureBuffer pb = CreateARGBPictureBuffer();
scoped_refptr<VideoFrame> frame = CreateVideoFrame(pb.id());
pbm_->DismissPictureBuffer(pb.id());
// Allocated textures should not be deleted while the VideoFrame exists.
environment_.RunUntilIdle();
EXPECT_TRUE(cbh_->HasTexture(pb.client_texture_ids()[0]));
// Or after it has been returned.
gpu::SyncToken sync_token = GenerateSyncToken(frame);
frame = nullptr;
environment_.RunUntilIdle();
EXPECT_TRUE(cbh_->HasTexture(pb.client_texture_ids()[0]));
// Until the SyncToken has been waited for. (Reuse callback should not be
// called for a dismissed picture buffer.)
cbh_->ReleaseSyncToken(sync_token);
environment_.RunUntilIdle();
EXPECT_FALSE(cbh_->HasTexture(pb.client_texture_ids()[0]));
}
TEST_F(PictureBufferManagerImplTest, CanReadWithoutStalling) {
// Works before Initialize().
EXPECT_TRUE(pbm_->CanReadWithoutStalling());
// True before any picture buffers are allocated.
Initialize();
EXPECT_TRUE(pbm_->CanReadWithoutStalling());
// True when a picture buffer is available.
PictureBuffer pb = CreateARGBPictureBuffer();
EXPECT_TRUE(pbm_->CanReadWithoutStalling());
// False when all picture buffers are used.
scoped_refptr<VideoFrame> frame = CreateVideoFrame(pb.id());
EXPECT_FALSE(pbm_->CanReadWithoutStalling());
// True once a picture buffer is returned.
frame = nullptr;
EXPECT_TRUE(pbm_->CanReadWithoutStalling());
// True after all picture buffers have been dismissed.
pbm_->DismissPictureBuffer(pb.id());
EXPECT_TRUE(pbm_->CanReadWithoutStalling());
}
} // namespace media