1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
media / gpu / vaapi / vaapi_wrapper_unittest.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <va/va.h>
#include "media/gpu/vaapi/vaapi_wrapper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
namespace media {
namespace {
VaapiWrapper::VABufferDescriptor CreateVABufferDescriptor() {
constexpr static char kData[] = "vaBufferData";
return VaapiWrapper::VABufferDescriptor{VAProcPipelineParameterBufferType,
sizeof(kData), kData};
}
class MockVaapiWrapper : public VaapiWrapper {
public:
MockVaapiWrapper() : VaapiWrapper(VADisplayStateHandle(), kVideoProcess) {}
MOCK_METHOD1(SubmitBuffer_Locked, bool(const VABufferDescriptor&));
MOCK_METHOD0(DestroyPendingBuffers_Locked, void());
protected:
~MockVaapiWrapper() override = default;
};
} // namespace
class VaapiWrapperTest : public testing::Test {
public:
VaapiWrapperTest() = default;
void SetUp() override {
// Create a VaapiWrapper for testing.
mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>();
ASSERT_TRUE(mock_vaapi_wrapper_);
ON_CALL(*mock_vaapi_wrapper_, SubmitBuffer_Locked)
.WillByDefault(
Invoke(this, &VaapiWrapperTest::DefaultSubmitBuffer_Locked));
ON_CALL(*mock_vaapi_wrapper_, DestroyPendingBuffers_Locked)
.WillByDefault(Invoke(
this, &VaapiWrapperTest::DefaultDestroyPendingBuffers_Locked));
}
void TearDown() override {
VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(
mock_vaapi_wrapper_->sequence_checker_);
// The VaapiWrapper destructor calls DestroyPendingBuffers_Locked(). Since
// MockVaapiWrapper is a derived class,
// MockVaapiWrapper::DestroyPendingBuffers_Locked() won't get called during
// destruction even though it's a virtual function. Instead,
// VaapiWrapper::DestroyPendingBuffers_Locked() will get called. Therefore,
// we need to clear |pending_va_buffers_| before this happens so that
// VaapiWrapper::DestroyPendingBuffers_Locked() doesn't call
// vaDestroyBuffer().
mock_vaapi_wrapper_->pending_va_buffers_.clear();
mock_vaapi_wrapper_.reset();
}
bool DefaultSubmitBuffer_Locked(
const VaapiWrapper::VABufferDescriptor& va_buffer)
EXCLUSIVE_LOCKS_REQUIRED(mock_vaapi_wrapper_->va_lock_) {
VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(
mock_vaapi_wrapper_->sequence_checker_);
if (va_buffer.data) {
constexpr VABufferID kFakeBufferId = 1234;
mock_vaapi_wrapper_->pending_va_buffers_.push_back(kFakeBufferId);
return true;
}
// When |va_buffer|.data is null, the base method should return false and
// no libva calls should be made.
const bool submit_buffer_res =
(*mock_vaapi_wrapper_).VaapiWrapper::SubmitBuffer_Locked(va_buffer);
if (submit_buffer_res)
ADD_FAILURE();
return false;
}
void DefaultDestroyPendingBuffers_Locked()
EXCLUSIVE_LOCKS_REQUIRED(mock_vaapi_wrapper_->va_lock_) {
VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(
mock_vaapi_wrapper_->sequence_checker_);
mock_vaapi_wrapper_->pending_va_buffers_.clear();
}
size_t GetPendingBuffersSize() const {
VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(
mock_vaapi_wrapper_->sequence_checker_);
return mock_vaapi_wrapper_->pending_va_buffers_.size();
}
protected:
scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_;
};
// This test ensures SubmitBuffer() calls SubmitBuffer_Locked().
TEST_F(VaapiWrapperTest, SubmitBuffer) {
constexpr size_t kNumBuffers = 3;
auto va_buffer = CreateVABufferDescriptor();
EXPECT_CALL(*mock_vaapi_wrapper_, SubmitBuffer_Locked(_)).Times(kNumBuffers);
for (size_t i = 0; i < kNumBuffers; ++i) {
EXPECT_TRUE(mock_vaapi_wrapper_->SubmitBuffer(
va_buffer.type, va_buffer.size, va_buffer.data));
}
EXPECT_EQ(GetPendingBuffersSize(), kNumBuffers);
}
// This test ensures SubmitBuffers() calls SubmitBuffer_Locked() as many times
// as the number of passed buffers.
TEST_F(VaapiWrapperTest, SubmitBuffers) {
constexpr size_t kNumBuffers = 3;
auto va_buffer = CreateVABufferDescriptor();
std::vector<VaapiWrapper::VABufferDescriptor> buffers(kNumBuffers, va_buffer);
EXPECT_CALL(*mock_vaapi_wrapper_, SubmitBuffer_Locked(_)).Times(kNumBuffers);
EXPECT_TRUE(mock_vaapi_wrapper_->SubmitBuffers(buffers));
EXPECT_EQ(GetPendingBuffersSize(), kNumBuffers);
}
// This test ensures DestroyPendingBuffers_Locked() is executed on a failure of
// SubmitBuffer().
TEST_F(VaapiWrapperTest, FailOnSubmitBuffer) {
auto va_buffer = CreateVABufferDescriptor();
::testing::InSequence s;
EXPECT_CALL(*mock_vaapi_wrapper_, SubmitBuffer_Locked(_)).Times(2);
EXPECT_CALL(*mock_vaapi_wrapper_, DestroyPendingBuffers_Locked);
EXPECT_TRUE(mock_vaapi_wrapper_->SubmitBuffer(va_buffer.type, va_buffer.size,
va_buffer.data));
EXPECT_FALSE(mock_vaapi_wrapper_->SubmitBuffer(va_buffer.type, va_buffer.size,
/*data=*/nullptr));
EXPECT_EQ(GetPendingBuffersSize(), 0u);
}
// This test ensures DestroyPendingBuffers_Locked() is executed on a failure of
// SubmitBuffers().
TEST_F(VaapiWrapperTest, FailOnSubmitBuffers) {
constexpr size_t kNumBuffers = 3;
auto va_buffer = CreateVABufferDescriptor();
std::vector<VaapiWrapper::VABufferDescriptor> buffers(kNumBuffers, va_buffer);
// Set data to nullptr so that VaapiWrapper::SubmitBuffer_Locked() fails.
buffers[1].data = nullptr;
::testing::InSequence s;
EXPECT_CALL(*mock_vaapi_wrapper_, SubmitBuffer_Locked(_))
.Times(kNumBuffers - 1);
EXPECT_CALL(*mock_vaapi_wrapper_, DestroyPendingBuffers_Locked);
EXPECT_FALSE(mock_vaapi_wrapper_->SubmitBuffers(buffers));
EXPECT_EQ(GetPendingBuffersSize(), 0u);
}
} // namespace media