• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or parseried.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <sstream>
16 
17 #include "gtest/gtest.h"
18 #include "src/amberscript/parser.h"
19 #include "src/shader_data.h"
20 
21 namespace amber {
22 namespace amberscript {
23 
24 namespace {
25 class ThreadEventRecorder : public debug::Thread {
26   std::stringstream& events;
27   std::string indent = "  ";
28 
29  public:
ThreadEventRecorder(std::stringstream & ev)30   explicit ThreadEventRecorder(std::stringstream& ev) : events(ev) {}
31 
StepOver()32   void StepOver() override { events << indent << "STEP_OVER" << std::endl; }
StepIn()33   void StepIn() override { events << indent << "STEP_IN" << std::endl; }
StepOut()34   void StepOut() override { events << indent << "STEP_OUT" << std::endl; }
Continue()35   void Continue() override { events << indent << "CONTINUE" << std::endl; }
ExpectLocation(const debug::Location & location,const std::string & line)36   void ExpectLocation(const debug::Location& location,
37                       const std::string& line) override {
38     events << indent << "EXPECT LOCATION \"" << location.file << "\" "
39            << location.line;
40     if (!line.empty()) {
41       events << " \"" << line << "\"";
42     }
43     events << std::endl;
44   }
ExpectCallstack(const std::vector<debug::StackFrame> & callstack)45   void ExpectCallstack(
46       const std::vector<debug::StackFrame>& callstack) override {
47     events << indent << "EXPECT CALLSTACK";
48     for (auto& frame : callstack) {
49       events << indent << "  " << frame.name << " " << frame.location.file
50              << ":" << frame.location.line << " " << std::endl;
51     }
52     events << std::endl;
53   }
ExpectLocal(const std::string & name,int64_t value)54   void ExpectLocal(const std::string& name, int64_t value) override {
55     events << indent << "EXPECT LOCAL \"" << name << "\" EQ " << value
56            << std::endl;
57   }
ExpectLocal(const std::string & name,double value)58   void ExpectLocal(const std::string& name, double value) override {
59     events << indent << "EXPECT LOCAL \"" << name << "\" EQ " << value
60            << std::endl;
61   }
ExpectLocal(const std::string & name,const std::string & value)62   void ExpectLocal(const std::string& name, const std::string& value) override {
63     events << indent << "EXPECT LOCAL \"" << name << "\" EQ \"" << value << "\""
64            << std::endl;
65   }
66 };
67 
68 class EventRecorder : public debug::Events {
69  public:
70   std::stringstream events;
71 
record(const std::shared_ptr<const debug::ThreadScript> & script)72   void record(const std::shared_ptr<const debug::ThreadScript>& script) {
73     ThreadEventRecorder thread{events};
74     script->Run(&thread);
75   }
BreakOnComputeGlobalInvocation(uint32_t x,uint32_t y,uint32_t z,const std::shared_ptr<const debug::ThreadScript> & script)76   void BreakOnComputeGlobalInvocation(
77       uint32_t x,
78       uint32_t y,
79       uint32_t z,
80       const std::shared_ptr<const debug::ThreadScript>& script) override {
81     events << "THREAD GLOBAL_INVOCATION_ID " << x << " " << y << " " << z
82            << std::endl;
83     record(script);
84     events << "END" << std::endl;
85   }
BreakOnVertexIndex(uint32_t index,const std::shared_ptr<const debug::ThreadScript> & script)86   void BreakOnVertexIndex(
87       uint32_t index,
88       const std::shared_ptr<const debug::ThreadScript>& script) override {
89     events << "THREAD VERTEX_INDEX " << index << std::endl;
90     record(script);
91     events << "END" << std::endl;
92   }
BreakOnFragmentWindowSpacePosition(uint32_t x,uint32_t y,const std::shared_ptr<const debug::ThreadScript> & script)93   void BreakOnFragmentWindowSpacePosition(
94       uint32_t x,
95       uint32_t y,
96       const std::shared_ptr<const debug::ThreadScript>& script) override {
97     events << "THREAD FRAGMENT_WINDOW_SPACE_POSITION " << x << " " << y
98            << std::endl;
99     record(script);
100     events << "END" << std::endl;
101   }
102 };
103 }  // namespace
104 
105 using AmberScriptParserTest = testing::Test;
106 
TEST_F(AmberScriptParserTest,DebugEventsScript)107 TEST_F(AmberScriptParserTest, DebugEventsScript) {
108   std::string dbg = R"(THREAD GLOBAL_INVOCATION_ID 1 2 3
109   EXPECT LOCATION "compute.hlsl" 2
110   STEP_IN
111   EXPECT LOCAL "one" EQ 1
112   STEP_OUT
113   EXPECT LOCAL "pi" EQ 3.14
114   STEP_OVER
115   EXPECT LOCAL "cat" EQ "meow"
116   CONTINUE
117 END
118 THREAD VERTEX_INDEX 2
119   EXPECT LOCATION "vertex.hlsl" 2 "  dog:woof cat:meow duck:quack"
120 END
121 THREAD FRAGMENT_WINDOW_SPACE_POSITION 4 5
122   EXPECT LOCATION "fragment.hlsl" 42
123   CONTINUE
124 END
125 )";
126 
127   std::string in = R"(
128 SHADER compute dbg_compute GLSL
129 void main() {}
130 END
131 
132 PIPELINE compute my_pipeline
133   ATTACH dbg_compute
134 END
135 
136 DEBUG my_pipeline 2 4 5
137 )" + dbg + "END";
138 
139   Parser parser;
140   Result r = parser.Parse(in);
141   ASSERT_TRUE(r.IsSuccess()) << r.Error();
142 
143   auto script = parser.GetScript();
144   const auto& commands = script->GetCommands();
145   ASSERT_EQ(1U, commands.size());
146 
147   auto* cmd = commands[0].get();
148   ASSERT_TRUE(cmd->IsCompute());
149   auto* compute = cmd->AsCompute();
150   EXPECT_EQ(2U, compute->GetX());
151   EXPECT_EQ(4U, compute->GetY());
152   EXPECT_EQ(5U, compute->GetZ());
153 
154   EventRecorder event_recorder;
155   compute->GetDebugScript()->Run(&event_recorder);
156   EXPECT_EQ(dbg, event_recorder.events.str());
157 
158   auto& shaders = compute->GetPipeline()->GetShaders();
159   ASSERT_EQ(1U, shaders.size());
160 
161   EXPECT_EQ(true, shaders[0].GetEmitDebugInfo());
162 }
163 
TEST_F(AmberScriptParserTest,DebugEmitDebugInfoVertex)164 TEST_F(AmberScriptParserTest, DebugEmitDebugInfoVertex) {
165   std::string dbg = R"()";
166 
167   std::string in = R"(
168 SHADER vertex dbg_vertex GLSL
169 void main() {}
170 END
171 
172 SHADER fragment dbg_fragment GLSL
173 void main() {}
174 END
175 
176 BUFFER position_buf DATA_TYPE R8G8_SNORM DATA
177  1 1 2 2 3 3
178 END
179 
180 PIPELINE graphics my_pipeline
181   ATTACH dbg_vertex
182   ATTACH dbg_fragment
183   VERTEX_DATA position_buf LOCATION 0
184 END
185 
186 DEBUG my_pipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 1
187   THREAD VERTEX_INDEX 100
188   END
189 END)";
190 
191   Parser parser;
192   Result r = parser.Parse(in);
193   ASSERT_TRUE(r.IsSuccess()) << r.Error();
194 
195   auto script = parser.GetScript();
196   const auto& commands = script->GetCommands();
197   ASSERT_EQ(1U, commands.size());
198   auto* cmd = commands[0].get();
199   ASSERT_TRUE(cmd->IsDrawArrays());
200   auto* draw = cmd->AsDrawArrays();
201 
202   for (auto& shader : draw->GetPipeline()->GetShaders()) {
203     bool expect_debug_info = shader.GetShaderType() == kShaderTypeVertex;
204     EXPECT_EQ(expect_debug_info, shader.GetEmitDebugInfo())
205         << "Emit debug info for shader type " << shader.GetShaderType();
206   }
207 }
208 
TEST_F(AmberScriptParserTest,DebugEmitDebugInfoFragment)209 TEST_F(AmberScriptParserTest, DebugEmitDebugInfoFragment) {
210   std::string dbg = R"()";
211 
212   std::string in = R"(
213 SHADER vertex dbg_vertex GLSL
214 void main() {}
215 END
216 
217 SHADER fragment dbg_fragment GLSL
218 void main() {}
219 END
220 
221 BUFFER position_buf DATA_TYPE R8G8_SNORM DATA
222  1 1 2 2 3 3
223 END
224 
225 PIPELINE graphics my_pipeline
226   ATTACH dbg_vertex
227   ATTACH dbg_fragment
228   VERTEX_DATA position_buf LOCATION 0
229 END
230 
231 DEBUG my_pipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 1
232   THREAD FRAGMENT_WINDOW_SPACE_POSITION 1 2
233   END
234 END)";
235 
236   Parser parser;
237   Result r = parser.Parse(in);
238   ASSERT_TRUE(r.IsSuccess()) << r.Error();
239 
240   auto script = parser.GetScript();
241   const auto& commands = script->GetCommands();
242   ASSERT_EQ(1U, commands.size());
243   auto* cmd = commands[0].get();
244   ASSERT_TRUE(cmd->IsDrawArrays());
245   auto* draw = cmd->AsDrawArrays();
246 
247   for (auto& shader : draw->GetPipeline()->GetShaders()) {
248     bool expect_debug_info = shader.GetShaderType() == kShaderTypeFragment;
249     EXPECT_EQ(expect_debug_info, shader.GetEmitDebugInfo())
250         << "Emit debug info for shader type " << shader.GetShaderType();
251   }
252 }
253 
TEST_F(AmberScriptParserTest,DebugEmitNoDebugInfo)254 TEST_F(AmberScriptParserTest, DebugEmitNoDebugInfo) {
255   std::string dbg = R"()";
256 
257   std::string in = R"(
258 SHADER vertex dbg_vertex GLSL
259 void main() {}
260 END
261 
262 SHADER fragment dbg_fragment GLSL
263 void main() {}
264 END
265 
266 BUFFER position_buf DATA_TYPE R8G8_SNORM DATA
267  1 1 2 2 3 3
268 END
269 
270 PIPELINE graphics my_pipeline
271   ATTACH dbg_vertex
272   ATTACH dbg_fragment
273   VERTEX_DATA position_buf LOCATION 0
274 END
275 
276 RUN my_pipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 1
277 )";
278 
279   Parser parser;
280   Result r = parser.Parse(in);
281   ASSERT_TRUE(r.IsSuccess()) << r.Error();
282 
283   auto script = parser.GetScript();
284   const auto& commands = script->GetCommands();
285   ASSERT_EQ(1U, commands.size());
286   auto* cmd = commands[0].get();
287   ASSERT_TRUE(cmd->IsDrawArrays());
288   auto* draw = cmd->AsDrawArrays();
289 
290   for (auto& shader : draw->GetPipeline()->GetShaders()) {
291     EXPECT_EQ(false, shader.GetEmitDebugInfo());
292   }
293 }
294 
295 }  // namespace amberscript
296 }  // namespace amber
297