blob: 5145588a64448b9b2f5d776d12fe3a4f40f9d694 [file] [log] [blame]
// Copyright 2019 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/multi_draw_manager.h"
#include <memory>
#include <tuple>
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_bindings.h"
namespace gpu {
namespace gles2 {
namespace {
using Param = std::tuple<MultiDrawManager::IndexStorageType,
MultiDrawManager::DrawFunction>;
} // namespace
class MultiDrawManagerTest : public testing::TestWithParam<Param> {
public:
MultiDrawManagerTest()
: multi_draw_manager_(new MultiDrawManager(std::get<0>(GetParam()))) {}
protected:
bool DoMultiDraw(uint32_t count,
GLenum mode = GL_TRIANGLES,
GLenum type = GL_UNSIGNED_INT) {
std::vector<GLsizei> data(count);
switch (std::get<1>(GetParam())) {
case MultiDrawManager::DrawFunction::DrawArrays:
return multi_draw_manager_->MultiDrawArrays(mode, data.data(),
data.data(), count);
case MultiDrawManager::DrawFunction::DrawArraysInstanced:
return multi_draw_manager_->MultiDrawArraysInstanced(
mode, data.data(), data.data(), data.data(), count);
case MultiDrawManager::DrawFunction::DrawElements:
return multi_draw_manager_->MultiDrawElements(mode, data.data(), type,
data.data(), count);
case MultiDrawManager::DrawFunction::DrawElementsInstanced:
return multi_draw_manager_->MultiDrawElementsInstanced(
mode, data.data(), type, data.data(), data.data(), count);
}
}
void CheckResultSize(uint32_t count,
const MultiDrawManager::ResultData& result) {
MultiDrawManager::DrawFunction draw_function = std::get<1>(GetParam());
EXPECT_TRUE(draw_function == result.draw_function);
switch (draw_function) {
case MultiDrawManager::DrawFunction::DrawArraysInstanced:
EXPECT_TRUE(result.instance_counts.size() == count);
FALLTHROUGH;
case MultiDrawManager::DrawFunction::DrawArrays:
EXPECT_TRUE(result.firsts.size() == count);
EXPECT_TRUE(result.counts.size() == count);
break;
case MultiDrawManager::DrawFunction::DrawElementsInstanced:
EXPECT_TRUE(result.instance_counts.size() == count);
FALLTHROUGH;
case MultiDrawManager::DrawFunction::DrawElements:
EXPECT_TRUE(result.counts.size() == count);
switch (std::get<0>(GetParam())) {
case MultiDrawManager::IndexStorageType::Offset:
EXPECT_TRUE(result.offsets.size() == count);
break;
case MultiDrawManager::IndexStorageType::Pointer:
EXPECT_TRUE(result.indices.size() == count);
break;
}
break;
}
}
std::unique_ptr<MultiDrawManager> multi_draw_manager_;
};
// Test that the simple case succeeds
TEST_P(MultiDrawManagerTest, Success) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(100));
EXPECT_TRUE(multi_draw_manager_->End(&result));
CheckResultSize(100, result);
}
// Test that the internal state of the multi draw manager resets such that
// successive valid multi draws can be executed
TEST_P(MultiDrawManagerTest, SuccessAfterSuccess) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(100));
EXPECT_TRUE(multi_draw_manager_->End(&result));
CheckResultSize(100, result);
EXPECT_TRUE(multi_draw_manager_->Begin(1000));
EXPECT_TRUE(DoMultiDraw(1000));
EXPECT_TRUE(multi_draw_manager_->End(&result));
CheckResultSize(1000, result);
}
// Test that multiple chunked multi draw calls succeed
TEST_P(MultiDrawManagerTest, SuccessMultiple) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(83));
EXPECT_TRUE(DoMultiDraw(4));
EXPECT_TRUE(DoMultiDraw(13));
EXPECT_TRUE(multi_draw_manager_->End(&result));
CheckResultSize(100, result);
}
// Test that it is invalid to submit an empty multi draw
TEST_P(MultiDrawManagerTest, Empty) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(0));
EXPECT_FALSE(multi_draw_manager_->End(&result));
}
// Test that it is invalid to end a multi draw if it has not been started
TEST_P(MultiDrawManagerTest, EndBeforeBegin) {
MultiDrawManager::ResultData result;
EXPECT_FALSE(multi_draw_manager_->End(&result));
}
// Test that it is invalid to begin a multi draw twice
TEST_P(MultiDrawManagerTest, BeginAfterBegin) {
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_FALSE(multi_draw_manager_->Begin(100));
}
// Test that it is invalid to begin a multi draw twice, even if
// the first begin was empty
TEST_P(MultiDrawManagerTest, BeginAfterEmptyBegin) {
EXPECT_TRUE(multi_draw_manager_->Begin(0));
EXPECT_FALSE(multi_draw_manager_->Begin(100));
}
// Test that it is invalid to do a multi draw before begin
TEST_P(MultiDrawManagerTest, DrawBeforeBegin) {
EXPECT_FALSE(DoMultiDraw(1));
}
// Test that it is invalid to end a multi draw twice
TEST_P(MultiDrawManagerTest, DoubleEnd) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(1));
EXPECT_TRUE(DoMultiDraw(1));
EXPECT_TRUE(multi_draw_manager_->End(&result));
EXPECT_FALSE(multi_draw_manager_->End(&result));
}
// Test that it is invalid to end a multi draw before the drawcount
// is saturated
TEST_P(MultiDrawManagerTest, Underflow) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(99));
EXPECT_FALSE(multi_draw_manager_->End(&result));
}
// Test that it is invalid to end a multi draw before the drawcount
// is saturated, using multiple chunks
TEST_P(MultiDrawManagerTest, UnderflowMultiple) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(42));
EXPECT_TRUE(DoMultiDraw(31));
EXPECT_TRUE(DoMultiDraw(26));
EXPECT_FALSE(multi_draw_manager_->End(&result));
}
// Test that it is invalid to do a multi draw that overflows the drawcount
TEST_P(MultiDrawManagerTest, Overflow) {
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_FALSE(DoMultiDraw(101));
}
// Test that it is invalid to do a multi draw that overflows the drawcount,
// using multiple chunks
TEST_P(MultiDrawManagerTest, OverflowMultiple) {
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(31));
EXPECT_TRUE(DoMultiDraw(49));
EXPECT_FALSE(DoMultiDraw(21));
}
// Test that it is invalid to do a multi draw that does not match the first
// chunk's draw mode
TEST_P(MultiDrawManagerTest, DrawModeMismatch) {
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(50, GL_TRIANGLES));
EXPECT_FALSE(DoMultiDraw(50, GL_LINES));
}
// Test that it is invalid to do a multi draw that does not match the first
// chunk's element type
TEST_P(MultiDrawManagerTest, ElementTypeMismatch) {
MultiDrawManager::DrawFunction draw_function = std::get<1>(GetParam());
if (draw_function != MultiDrawManager::DrawFunction::DrawElements &&
draw_function != MultiDrawManager::DrawFunction::DrawElementsInstanced) {
return;
}
MultiDrawManager::ResultData result;
EXPECT_TRUE(multi_draw_manager_->Begin(100));
EXPECT_TRUE(DoMultiDraw(50, GL_TRIANGLES, GL_UNSIGNED_INT));
EXPECT_FALSE(DoMultiDraw(50, GL_TRIANGLES, GL_UNSIGNED_SHORT));
}
INSTANTIATE_TEST_SUITE_P(
,
MultiDrawManagerTest,
testing::Combine(
testing::Values(MultiDrawManager::IndexStorageType::Offset,
MultiDrawManager::IndexStorageType::Pointer),
testing::Values(
MultiDrawManager::DrawFunction::DrawArrays,
MultiDrawManager::DrawFunction::DrawArraysInstanced,
MultiDrawManager::DrawFunction::DrawElements,
MultiDrawManager::DrawFunction::DrawElementsInstanced)));
} // namespace gles2
} // namespace gpu