Home | History | Annotate | Download | only in service
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Tests for the command parser.
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "gpu/command_buffer/service/cmd_parser.h"
     10 #include "gpu/command_buffer/service/mocks.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace gpu {
     14 
     15 using testing::_;
     16 using testing::Invoke;
     17 using testing::Mock;
     18 using testing::Return;
     19 using testing::Sequence;
     20 using testing::SetArgPointee;
     21 using testing::Truly;
     22 
     23 // Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
     24 // a fixed size memory buffer. Also provides a simple API to create a
     25 // CommandParser.
     26 class CommandParserTest : public testing::Test {
     27  protected:
     28   virtual void SetUp() {
     29     api_mock_.reset(new AsyncAPIMock(false));
     30     buffer_entry_count_ = 20;
     31     buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
     32   }
     33   virtual void TearDown() {}
     34 
     35   void AddDoCommandsExpect(error::Error _return,
     36                            unsigned int num_commands,
     37                            int num_entries,
     38                            int num_processed) {
     39     EXPECT_CALL(*api_mock_, DoCommands(num_commands, _, num_entries, _))
     40         .InSequence(sequence_)
     41         .WillOnce(DoAll(SetArgPointee<3>(num_processed), Return(_return)));
     42   }
     43 
     44   // Creates a parser, with a buffer of the specified size (in entries).
     45   CommandParser *MakeParser(unsigned int entry_count) {
     46     size_t shm_size = buffer_entry_count_ *
     47                       sizeof(CommandBufferEntry);  // NOLINT
     48     size_t command_buffer_size = entry_count *
     49                                  sizeof(CommandBufferEntry);  // NOLINT
     50     DCHECK_LE(command_buffer_size, shm_size);
     51     CommandParser* parser = new CommandParser(api_mock());
     52 
     53     parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size);
     54     return parser;
     55   }
     56 
     57   unsigned int buffer_entry_count() { return 20; }
     58   AsyncAPIMock *api_mock() { return api_mock_.get(); }
     59   CommandBufferEntry *buffer() { return buffer_.get(); }
     60  private:
     61   unsigned int buffer_entry_count_;
     62   scoped_ptr<AsyncAPIMock> api_mock_;
     63   scoped_ptr<CommandBufferEntry[]> buffer_;
     64   Sequence sequence_;
     65 };
     66 
     67 // Tests initialization conditions.
     68 TEST_F(CommandParserTest, TestInit) {
     69   scoped_ptr<CommandParser> parser(MakeParser(10));
     70   EXPECT_EQ(0, parser->get());
     71   EXPECT_EQ(0, parser->put());
     72   EXPECT_TRUE(parser->IsEmpty());
     73 }
     74 
     75 // Tests simple commands.
     76 TEST_F(CommandParserTest, TestSimple) {
     77   scoped_ptr<CommandParser> parser(MakeParser(10));
     78   CommandBufferOffset put = parser->put();
     79   CommandHeader header;
     80 
     81   // add a single command, no args
     82   header.size = 1;
     83   header.command = 123;
     84   buffer()[put++].value_header = header;
     85   parser->set_put(put);
     86   EXPECT_EQ(put, parser->put());
     87 
     88   AddDoCommandsExpect(error::kNoError, 1, 1, 1);
     89   EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
     90   EXPECT_EQ(put, parser->get());
     91   Mock::VerifyAndClearExpectations(api_mock());
     92 
     93   // add a single command, 2 args
     94   header.size = 3;
     95   header.command = 456;
     96   buffer()[put++].value_header = header;
     97   buffer()[put++].value_int32 = 2134;
     98   buffer()[put++].value_float = 1.f;
     99   parser->set_put(put);
    100   EXPECT_EQ(put, parser->put());
    101 
    102   AddDoCommandsExpect(error::kNoError, 1, 3, 3);
    103   EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
    104   EXPECT_EQ(put, parser->get());
    105   Mock::VerifyAndClearExpectations(api_mock());
    106 }
    107 
    108 // Tests having multiple commands in the buffer.
    109 TEST_F(CommandParserTest, TestMultipleCommands) {
    110   scoped_ptr<CommandParser> parser(MakeParser(10));
    111   CommandBufferOffset put = parser->put();
    112   CommandHeader header;
    113 
    114   // add 2 commands, test with single ProcessCommands()
    115   header.size = 2;
    116   header.command = 789;
    117   buffer()[put++].value_header = header;
    118   buffer()[put++].value_int32 = 5151;
    119 
    120   CommandBufferOffset put_cmd2 = put;
    121   header.size = 2;
    122   header.command = 876;
    123   buffer()[put++].value_header = header;
    124   buffer()[put++].value_int32 = 3434;
    125   parser->set_put(put);
    126   EXPECT_EQ(put, parser->put());
    127 
    128   // Process up to 1 command.  4 entries remaining.
    129   AddDoCommandsExpect(error::kNoError, 1, 4, 2);
    130   EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
    131   EXPECT_EQ(put_cmd2, parser->get());
    132 
    133   // Process up to 1 command.  2 entries remaining.
    134   AddDoCommandsExpect(error::kNoError, 1, 2, 2);
    135   EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
    136   EXPECT_EQ(put, parser->get());
    137   Mock::VerifyAndClearExpectations(api_mock());
    138 
    139   // add 2 commands again, test with ProcessAllCommands()
    140   header.size = 2;
    141   header.command = 123;
    142   buffer()[put++].value_header = header;
    143   buffer()[put++].value_int32 = 5656;
    144 
    145   header.size = 2;
    146   header.command = 321;
    147   buffer()[put++].value_header = header;
    148   buffer()[put++].value_int32 = 7878;
    149   parser->set_put(put);
    150   EXPECT_EQ(put, parser->put());
    151 
    152   // 4 entries remaining.
    153   AddDoCommandsExpect(
    154       error::kNoError, CommandParser::kParseCommandsSlice, 4, 4);
    155   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    156   EXPECT_EQ(put, parser->get());
    157   Mock::VerifyAndClearExpectations(api_mock());
    158 }
    159 
    160 // Tests that the parser will wrap correctly at the end of the buffer.
    161 TEST_F(CommandParserTest, TestWrap) {
    162   scoped_ptr<CommandParser> parser(MakeParser(5));
    163   CommandBufferOffset put = parser->put();
    164   CommandHeader header;
    165 
    166   // add 3 commands with no args (1 word each)
    167   for (unsigned int i = 0; i < 3; ++i) {
    168     header.size = 1;
    169     header.command = i;
    170     buffer()[put++].value_header = header;
    171   }
    172   parser->set_put(put);
    173   EXPECT_EQ(put, parser->put());
    174 
    175   // Process up to 10 commands.  3 entries remaining to put.
    176   AddDoCommandsExpect(error::kNoError, 10, 3, 3);
    177   EXPECT_EQ(error::kNoError, parser->ProcessCommands(10));
    178   EXPECT_EQ(put, parser->get());
    179   Mock::VerifyAndClearExpectations(api_mock());
    180 
    181   // add 1 command with 1 arg (2 words). That should put us at the end of the
    182   // buffer.
    183   header.size = 2;
    184   header.command = 3;
    185   buffer()[put++].value_header = header;
    186   buffer()[put++].value_int32 = 5;
    187 
    188   DCHECK_EQ(5, put);
    189   put = 0;
    190 
    191   // add 1 command with 1 arg (2 words).
    192   header.size = 2;
    193   header.command = 4;
    194   buffer()[put++].value_header = header;
    195   buffer()[put++].value_int32 = 6;
    196 
    197   // 2 entries remaining to end of buffer.
    198   AddDoCommandsExpect(
    199       error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
    200   // 2 entries remaining to put.
    201   AddDoCommandsExpect(
    202       error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
    203   parser->set_put(put);
    204   EXPECT_EQ(put, parser->put());
    205 
    206   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    207   EXPECT_EQ(put, parser->get());
    208   Mock::VerifyAndClearExpectations(api_mock());
    209 }
    210 
    211 // Tests error conditions.
    212 TEST_F(CommandParserTest, TestError) {
    213   const unsigned int kNumEntries = 5;
    214   scoped_ptr<CommandParser> parser(MakeParser(kNumEntries));
    215   CommandBufferOffset put = parser->put();
    216   CommandHeader header;
    217 
    218   EXPECT_FALSE(parser->set_get(-1));
    219   EXPECT_FALSE(parser->set_get(kNumEntries));
    220 
    221   // Generate a command with size 0.
    222   header.size = 0;
    223   header.command = 3;
    224   buffer()[put++].value_header = header;
    225 
    226   parser->set_put(put);
    227   EXPECT_EQ(put, parser->put());
    228 
    229   AddDoCommandsExpect(
    230       error::kInvalidSize, CommandParser::kParseCommandsSlice, 1, 0);
    231   EXPECT_EQ(error::kInvalidSize,
    232             parser->ProcessAllCommands());
    233   // check that no DoCommand call was made.
    234   Mock::VerifyAndClearExpectations(api_mock());
    235 
    236   parser.reset(MakeParser(5));
    237   put = parser->put();
    238 
    239   // Generate a command with size 6, extends beyond the end of the buffer.
    240   header.size = 6;
    241   header.command = 3;
    242   buffer()[put++].value_header = header;
    243 
    244   parser->set_put(put);
    245   EXPECT_EQ(put, parser->put());
    246 
    247   AddDoCommandsExpect(
    248       error::kOutOfBounds, CommandParser::kParseCommandsSlice, 1, 0);
    249   EXPECT_EQ(error::kOutOfBounds,
    250             parser->ProcessAllCommands());
    251   // check that no DoCommand call was made.
    252   Mock::VerifyAndClearExpectations(api_mock());
    253 
    254   parser.reset(MakeParser(5));
    255   put = parser->put();
    256 
    257   // Generates 2 commands.
    258   header.size = 1;
    259   header.command = 3;
    260   buffer()[put++].value_header = header;
    261   CommandBufferOffset put_post_fail = put;
    262   header.size = 1;
    263   header.command = 4;
    264   buffer()[put++].value_header = header;
    265 
    266   parser->set_put(put);
    267   EXPECT_EQ(put, parser->put());
    268   // have the first command fail to parse.
    269   AddDoCommandsExpect(
    270       error::kUnknownCommand, CommandParser::kParseCommandsSlice, 2, 1);
    271   EXPECT_EQ(error::kUnknownCommand,
    272             parser->ProcessAllCommands());
    273   // check that only one command was executed, and that get reflects that
    274   // correctly.
    275   EXPECT_EQ(put_post_fail, parser->get());
    276   Mock::VerifyAndClearExpectations(api_mock());
    277   // make the second one succeed, and check that the parser recovered fine.
    278   AddDoCommandsExpect(
    279       error::kNoError, CommandParser::kParseCommandsSlice, 1, 1);
    280   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    281   EXPECT_EQ(put, parser->get());
    282   Mock::VerifyAndClearExpectations(api_mock());
    283 }
    284 
    285 TEST_F(CommandParserTest, SetBuffer) {
    286   scoped_ptr<CommandParser> parser(MakeParser(3));
    287   CommandBufferOffset put = parser->put();
    288   CommandHeader header;
    289 
    290   // add a single command, no args
    291   header.size = 2;
    292   header.command = 123;
    293   buffer()[put++].value_header = header;
    294   buffer()[put++].value_int32 = 456;
    295   parser->set_put(put);
    296 
    297   AddDoCommandsExpect(
    298       error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
    299   EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
    300   // We should have advanced 2 entries
    301   EXPECT_EQ(2, parser->get());
    302   Mock::VerifyAndClearExpectations(api_mock());
    303 
    304   scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]);
    305   parser->SetBuffer(
    306       buffer2.get(), sizeof(CommandBufferEntry) * 2, 0,
    307       sizeof(CommandBufferEntry) * 2);
    308   // The put and get should have reset to 0.
    309   EXPECT_EQ(0, parser->get());
    310   EXPECT_EQ(0, parser->put());
    311 }
    312 
    313 }  // namespace gpu
    314