blob: e1173d2b7dffcf128aabb124865205aeb370d1b0 [file] [log] [blame]
// Copyright (c) 2015 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 "gpu/command_buffer/service/path_manager.h"
#include <memory>
#include "gpu/command_buffer/service/gpu_service_test.h"
#include "gpu/command_buffer/service/mocks.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
namespace gpu {
namespace gles2 {
class PathManagerTest : public GpuServiceTest {
public:
PathManagerTest() = default;
protected:
void SetUp() override {
SetUpWithGLVersion("3.0", "GL_NV_path_rendering");
manager_.reset(new PathManager());
}
void TearDown() override {
manager_->Destroy(true);
manager_.reset();
GpuServiceTest::TearDown();
}
std::unique_ptr<PathManager> manager_;
};
TEST_F(PathManagerTest, Basic) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
const GLuint kClient2Id = 2;
GLuint service_id = 0;
manager_->CreatePathRange(kClient1Id, kClient1Id, kService1Id);
ASSERT_TRUE(manager_->HasPathsInRange(kClient1Id, kClient1Id));
EXPECT_TRUE(manager_->GetPath(kClient1Id, &service_id));
EXPECT_EQ(kService1Id, service_id);
// Check we get nothing for a non-existent path.
service_id = 123u;
ASSERT_FALSE(manager_->HasPathsInRange(kClient2Id, kClient2Id));
EXPECT_FALSE(manager_->GetPath(kClient2Id, &service_id));
EXPECT_EQ(123u, service_id);
// Check trying to remove non-existent paths does not crash.
manager_->RemovePaths(kClient2Id, kClient2Id);
// Check that it gets deleted when the last reference is released.
EXPECT_CALL(*gl_, DeletePathsNV(kService1Id, 1))
.Times(1)
.RetiresOnSaturation();
// Check we can't get the path after we remove it.
manager_->RemovePaths(kClient1Id, kClient1Id);
ASSERT_FALSE(manager_->HasPathsInRange(kClient1Id, kClient1Id));
EXPECT_FALSE(manager_->GetPath(kClient1Id, &service_id));
}
// Tests that path manager does not merge ranges that contain service ids that
// prevent the merging. Path ranges A and B can be merged if
// * client ids of B start immediately after the last client id of A
// * service ids of B start immediately after the last service id of A
// and similarly for the 'before' case.
TEST_F(PathManagerTest, NonContiguousServiceIds) {
const GLuint kMergeCheckRange = 54;
const struct {
GLuint first_client_id;
GLuint last_client_id;
GLuint first_service_id;
} kIdRanges[] = {{500, 1000, 900}, {1001, 1155, 1}, {200, 499, 4888}};
for (auto& range : kIdRanges) {
manager_->CreatePathRange(range.first_client_id, range.last_client_id,
range.first_service_id);
ASSERT_TRUE(manager_->HasPathsInRange(range.first_client_id,
range.first_client_id));
ASSERT_TRUE(
manager_->HasPathsInRange(range.last_client_id, range.last_client_id));
ASSERT_TRUE(
manager_->HasPathsInRange(range.first_client_id, range.last_client_id));
GLuint service_id = 0u;
EXPECT_TRUE(manager_->GetPath(range.first_client_id + 5u, &service_id));
EXPECT_EQ(range.first_service_id + 5u, service_id);
}
// Insert a mergeable range last, to check that merges
// work. Otherwise the test could succeed because merges were not
// working.
auto& merge_candidate = kIdRanges[1];
GLuint merge_candidate_range =
merge_candidate.last_client_id - merge_candidate.first_client_id + 1;
manager_->CreatePathRange(
merge_candidate.last_client_id + 1,
merge_candidate.last_client_id + kMergeCheckRange,
merge_candidate.first_service_id + merge_candidate_range);
// We detect that ranges were not merged accidentally by detecting individual
// deletes.
for (auto& range : kIdRanges) {
if (&range == &merge_candidate)
continue;
GLsizei range_amount = range.last_client_id - range.first_client_id + 1;
EXPECT_CALL(*gl_, DeletePathsNV(range.first_service_id, range_amount))
.Times(1)
.RetiresOnSaturation();
}
// Just a check that merges work.
EXPECT_CALL(*gl_, DeletePathsNV(merge_candidate.first_service_id,
merge_candidate_range + kMergeCheckRange))
.Times(1)
.RetiresOnSaturation();
// Remove all ids. This should cause the expected amount of DeletePathsNV
// calls.
manager_->RemovePaths(1, std::numeric_limits<GLsizei>::max());
for (auto& range : kIdRanges) {
ASSERT_FALSE(
manager_->HasPathsInRange(range.first_client_id, range.last_client_id));
}
}
TEST_F(PathManagerTest, DeleteBigRange) {
// Allocates two ranges which in path manager end up merging as one
// big range. The range will be too big to fit in one DeletePaths
// call. Test that the range is deleted correctly with two calls.
const GLuint kFirstClientId1 = 1;
const GLsizei kRange1 = std::numeric_limits<GLsizei>::max() - 3;
const GLuint kLastClientId1 = kFirstClientId1 + kRange1 - 1;
const GLuint kFirstServiceId1 = 77;
const GLuint kLastServiceId1 = kFirstServiceId1 + kRange1 - 1;
const GLuint kFirstClientId2 = kLastClientId1 + 1;
const GLsizei kRange2 = 15;
const GLuint kLastClientId2 = kFirstClientId2 + kRange2 - 1;
const GLuint kFirstServiceId2 = kLastServiceId1 + 1;
const GLsizei kFirstDeleteRange = std::numeric_limits<GLsizei>::max();
const GLsizei kSecondDeleteRange = kRange2 - (kFirstDeleteRange - kRange1);
const GLuint kSecondDeleteFirstServiceId =
kFirstServiceId1 + kFirstDeleteRange;
EXPECT_CALL(*gl_, DeletePathsNV(kFirstServiceId1,
std::numeric_limits<GLsizei>::max()))
.RetiresOnSaturation();
EXPECT_CALL(*gl_, DeletePathsNV(kSecondDeleteFirstServiceId,
kSecondDeleteRange)).RetiresOnSaturation();
manager_->CreatePathRange(kFirstClientId1, kLastClientId1, kFirstServiceId1);
manager_->CreatePathRange(kFirstClientId2, kLastClientId2, kFirstServiceId2);
manager_->RemovePaths(0, std::numeric_limits<GLuint>::max());
}
} // namespace gles2
} // namespace gpu