renderer_test.cxx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. //
  2. // direct_renderer_test.cxx
  3. // graphics-test
  4. //
  5. // Created by Sam Jaffe on 6/1/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include "game/graphics/renderer.hpp"
  9. #include <testing/xcode_gtest_helper.h>
  10. #include <game/math/shape.hpp>
  11. #include <math/matrix/matrix.hpp>
  12. #include <math/matrix/matrix_helpers.hpp>
  13. #include "../src/renderer_impl.hpp"
  14. #include "game/graphics/exception.h"
  15. #include "game/graphics/object.hpp"
  16. #include "game/graphics/vertex.h"
  17. using testing::_;
  18. using testing::AnyNumber;
  19. using testing::IsEmpty;
  20. using testing::SizeIs;
  21. struct mock_renderer_impl : graphics::renderer_impl {
  22. MOCK_CONST_METHOD0(manager, std::shared_ptr<graphics::manager const>());
  23. MOCK_METHOD3(draw, void(identity<graphics::material>, math::matr4 const &,
  24. std::vector<graphics::vertex> const &));
  25. MOCK_METHOD0(clear, void());
  26. MOCK_METHOD0(flush, void());
  27. };
  28. identity<graphics::material> cast(unsigned int id) {
  29. return *reinterpret_cast<identity<graphics::material> *>(&id);
  30. }
  31. struct DirectRendererTest : testing::Test {
  32. void SetUp() override;
  33. void TearDown() override;
  34. std::unique_ptr<graphics::direct_renderer> renderer;
  35. mock_renderer_impl * mock;
  36. };
  37. void DirectRendererTest::SetUp() {
  38. mock = new mock_renderer_impl;
  39. renderer.reset(new graphics::direct_renderer(mock));
  40. }
  41. void DirectRendererTest::TearDown() {
  42. renderer.reset();
  43. delete mock;
  44. }
  45. graphics::object DemoObject(unsigned int id = 1) {
  46. math::dim2::rectangle const size{{{-1.f, -1.f}}, {{2.f, 2.f}}};
  47. math::dim2::rectangle const tex{{{0.f, 0.f}}, {{1.f, 1.f}}};
  48. return {size, size, cast(id), tex};
  49. }
  50. TEST_F(DirectRendererTest, DrawPassesToDraw) {
  51. EXPECT_CALL(*mock, draw(cast(1), math::matr4(), IsEmpty())).Times(1);
  52. renderer->draw(cast(1), math::matr4(), {});
  53. }
  54. TEST_F(DirectRendererTest, DrawObjectHasIdenTranslation) {
  55. auto identity = math::matrix::identity<float, 4>();
  56. EXPECT_CALL(*mock, draw(cast(1), identity, _)).Times(1);
  57. renderer->draw(DemoObject());
  58. }
  59. TEST_F(DirectRendererTest, DrawObjectHasSixVertices) {
  60. EXPECT_CALL(*mock, draw(_, _, SizeIs(6))).Times(1);
  61. renderer->draw(DemoObject());
  62. }
  63. TEST_F(DirectRendererTest, MultipleDrawCallsDispatchMultipleDraws) {
  64. EXPECT_CALL(*mock, draw(_, _, SizeIs(6))).Times(2);
  65. renderer->draw(DemoObject());
  66. renderer->draw(DemoObject());
  67. }
  68. TEST_F(DirectRendererTest, ClearPassesToClear) {
  69. EXPECT_CALL(*mock, clear()).Times(1);
  70. renderer->clear();
  71. }
  72. TEST_F(DirectRendererTest, FlushPassesToFlush) {
  73. EXPECT_CALL(*mock, flush()).Times(1);
  74. renderer->flush();
  75. }
  76. struct BatchRendererTest : testing::Test {
  77. void SetUp() override;
  78. void TearDown() override;
  79. std::unique_ptr<graphics::batch_renderer> renderer;
  80. std::unique_ptr<graphics::direct_renderer> drenderer;
  81. mock_renderer_impl * mock;
  82. };
  83. void BatchRendererTest::SetUp() {
  84. mock = new mock_renderer_impl;
  85. drenderer.reset(new graphics::direct_renderer(mock));
  86. renderer.reset(new graphics::batch_renderer(drenderer.get()));
  87. }
  88. void BatchRendererTest::TearDown() {
  89. renderer.reset();
  90. drenderer.reset();
  91. delete mock;
  92. }
  93. TEST_F(BatchRendererTest, DoesNotCallFlushOnDestructor) {
  94. EXPECT_CALL(*mock, flush()).Times(0);
  95. renderer.reset();
  96. testing::Mock::VerifyAndClearExpectations(mock);
  97. }
  98. TEST_F(BatchRendererTest, ClearPassesToClear) {
  99. EXPECT_CALL(*mock, flush()).Times(AnyNumber());
  100. EXPECT_CALL(*mock, clear()).Times(1);
  101. renderer->clear();
  102. }
  103. TEST_F(BatchRendererTest, FlushDoesNotPassToFlush) {
  104. EXPECT_CALL(*mock, flush()).Times(0);
  105. renderer->flush();
  106. }
  107. TEST_F(BatchRendererTest, DoesNotWriteImmediately) {
  108. EXPECT_CALL(*mock, draw(_, _, _)).Times(0);
  109. renderer->draw(cast(1), math::matr4(), {});
  110. testing::Mock::VerifyAndClearExpectations(mock);
  111. // We need to re-enact this expectation
  112. EXPECT_CALL(*mock, flush()).Times(AnyNumber());
  113. EXPECT_CALL(*mock, draw(_, _, _)).Times(1);
  114. }
  115. TEST_F(BatchRendererTest, GroupsDataTogetherByMaterial) {
  116. EXPECT_CALL(*mock, flush()).Times(AnyNumber());
  117. EXPECT_CALL(*mock, draw(cast(1), _, SizeIs(12))).Times(1);
  118. EXPECT_CALL(*mock, draw(cast(2), _, SizeIs(6))).Times(1);
  119. renderer->draw(DemoObject());
  120. renderer->draw(DemoObject());
  121. renderer->draw(DemoObject(2));
  122. }
  123. TEST_F(BatchRendererTest, BatchLimitingCanSplitTheWrites) {
  124. EXPECT_CALL(*mock, flush()).Times(AnyNumber());
  125. renderer.reset(new graphics::batch_renderer(drenderer.get(), 15));
  126. // This sometimes occurs...
  127. EXPECT_CALL(*mock, draw(_, _, SizeIs(0))).Times(AnyNumber());
  128. EXPECT_CALL(*mock, draw(cast(1), _, SizeIs(12))).Times(1);
  129. EXPECT_CALL(*mock, draw(cast(2), _, SizeIs(6))).Times(2);
  130. renderer->draw(DemoObject());
  131. renderer->draw(DemoObject());
  132. renderer->draw(DemoObject(2));
  133. renderer->draw(DemoObject(2));
  134. }
  135. struct InjectRendererTest : testing::Test {
  136. protected:
  137. void SetUp() override;
  138. void TearDown() override;
  139. mock_renderer_impl * mock;
  140. private:
  141. graphics::renderer_impl_factory::scoped_binding scope_;
  142. };
  143. void InjectRendererTest::SetUp() {
  144. mock = new mock_renderer_impl;
  145. auto & factory = graphics::renderer_impl_factory::instance();
  146. scope_ = factory.bind_scoped("mock", [this]() { return mock; });
  147. }
  148. void InjectRendererTest::TearDown() { delete mock; }
  149. TEST_F(InjectRendererTest, ThrowsOnRequestOfBlank) {
  150. EXPECT_THROW(graphics::direct_renderer(""),
  151. graphics::unmapped_enum<graphics::driver>);
  152. }
  153. TEST(UnboundRendererTest, ThrowsOnRequestOfUnboundDriver) {
  154. EXPECT_THROW(graphics::direct_renderer("mock"),
  155. graphics::unmapped_enum<graphics::driver>);
  156. }
  157. TEST_F(InjectRendererTest, SuccessfulConstructionWithBoundImpl) {
  158. EXPECT_NO_THROW(graphics::direct_renderer("mock"));
  159. }
  160. TEST_F(InjectRendererTest, BoundImplIsSamePointed) {
  161. graphics::direct_renderer renderer("mock");
  162. EXPECT_CALL(*mock, draw(cast(1), math::matr4(), IsEmpty())).Times(1);
  163. renderer.draw(cast(1), math::matr4(), {});
  164. }