ff11704ac1c2bb4363a5568851800bd7812d8d46
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / egl-graphics-controller-debug.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dali/internal/graphics/gles-impl/egl-graphics-controller-debug.h>
18 #include <cstdio>
19 #include <queue>
20
21 namespace Dali::Graphics
22 {
23 std::string DumpCompareOp(Graphics::CompareOp compareOp)
24 {
25   switch(compareOp)
26   {
27     case Graphics::CompareOp::NEVER:
28       return "Graphics::CompareOp::NEVER";
29       break;
30     case Graphics::CompareOp::LESS:
31       return "Graphics::CompareOp::LESS";
32       break;
33     case Graphics::CompareOp::EQUAL:
34       return "Graphics::CompareOp::EQUAL";
35       break;
36     case Graphics::CompareOp::LESS_OR_EQUAL:
37       return "Graphics::CompareOp::LESS_OR_EQUAL";
38       break;
39     case Graphics::CompareOp::GREATER:
40       return "Graphics::CompareOp::GREATER";
41       break;
42     case Graphics::CompareOp::NOT_EQUAL:
43       return "Graphics::CompareOp::NOT_EQUAL";
44       break;
45     case Graphics::CompareOp::GREATER_OR_EQUAL:
46       return "Graphics::CompareOp::GREATER_OR_EQUAL";
47       break;
48     case Graphics::CompareOp::ALWAYS:
49       return "Graphics::CompareOp::ALWAYS";
50       break;
51   }
52   return "UNKNOWN";
53 }
54
55 std::string DumpStencilOp(Graphics::StencilOp stencilOp)
56 {
57   switch(stencilOp)
58   {
59     case Graphics::StencilOp::KEEP:
60       return "Graphics::StencilOp::KEEP";
61       break;
62     case Graphics::StencilOp::ZERO:
63       return "Graphics::StencilOp::ZERO";
64       break;
65     case Graphics::StencilOp::REPLACE:
66       return "Graphics::StencilOp::REPLACE";
67       break;
68     case Graphics::StencilOp::INCREMENT_AND_CLAMP:
69       return "Graphics::StencilOp::INCREMENT_AND_CLAMP";
70       break;
71     case Graphics::StencilOp::DECREMENT_AND_CLAMP:
72       return "Graphics::StencilOp::DECREMENT_AND_CLAMP";
73       break;
74     case Graphics::StencilOp::INVERT:
75       return "Graphics::StencilOp::INVERT";
76       break;
77     case Graphics::StencilOp::INCREMENT_AND_WRAP:
78       return "Graphics::StencilOp::INCREMENT_AND_WRAP";
79       break;
80     case Graphics::StencilOp::DECREMENT_AND_WRAP:
81       return "Graphics::StencilOp::DECREMENT_AND_WRAP";
82       break;
83   }
84   return "UNKNOWN";
85 }
86
87 void DumpCommandBuffer(FILE* output, const GLES::CommandBuffer* commandBuffer)
88 {
89   bool first{true};
90   for(auto& cmd : commandBuffer->GetCommands())
91   {
92     if(!first)
93     {
94       fprintf(output, ",");
95     }
96     first = false;
97     // process command
98     switch(cmd.type)
99     {
100       case GLES::CommandType::FLUSH:
101       {
102         fprintf(output, "{\"Cmd\":\"FLUSH\"}\n");
103         break;
104       }
105       case GLES::CommandType::BIND_TEXTURES:
106       {
107         fprintf(output, "{\"Cmd\":\"BIND_TEXTURES\"}\n");
108         break;
109       }
110       case GLES::CommandType::BIND_VERTEX_BUFFERS:
111       {
112         fprintf(output, "{\"Cmd\":\"BIND_VERTEX_BUFFERS\"}\n");
113         break;
114       }
115       case GLES::CommandType::BIND_UNIFORM_BUFFER:
116       {
117         fprintf(output, "{\"Cmd\":\"BIND_UNIFORM_BUFFERS\"}\n");
118         break;
119       }
120       case GLES::CommandType::BIND_INDEX_BUFFER:
121       {
122         fprintf(output, "{\"Cmd\":\"BIND_INDEX_BUFFERS\"}\n");
123         break;
124       }
125       case GLES::CommandType::BIND_SAMPLERS:
126       {
127         fprintf(output, "{\"Cmd\":\"BIND_SAMPLERS\"}\n");
128         break;
129       }
130       case GLES::CommandType::BIND_PIPELINE:
131       {
132         fprintf(output, "{\"Cmd\":\"BIND_PIPELINE\"}\n");
133         break;
134       }
135       case GLES::CommandType::DRAW:
136       {
137         fprintf(output, "{\"Cmd\":\"DRAW\"}\n");
138         break;
139       }
140       case GLES::CommandType::DRAW_INDEXED:
141       {
142         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED\"}\n");
143         break;
144       }
145       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
146       {
147         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED_INDIRECT\"}\n");
148         break;
149       }
150       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
151       {
152         fprintf(output, "{\"Cmd\":\"SET_SCISSOR\",\n\"region\":[%d,%d,%d,%d]\n}\n", cmd.scissor.region.x, cmd.scissor.region.y, cmd.scissor.region.width, cmd.scissor.region.height);
153         break;
154       }
155       case GLES::CommandType::SET_SCISSOR_TEST:
156       {
157         fprintf(output, "{\"Cmd\":\"SET_SCISSOR_TEST\",\n\"enable\":%s\n}\n", (cmd.scissorTest.enable ? "\"true\"" : "\"false\""));
158         break;
159       }
160       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
161       {
162         fprintf(output, "{\"Cmd\":\"SET_VIEWPORT\",\n\"region\":[%f,%f,%f,%f]\n}\n", cmd.viewport.region.x, cmd.viewport.region.y, cmd.viewport.region.width, cmd.viewport.region.height);
163         break;
164       }
165       case GLES::CommandType::SET_COLOR_MASK:
166       {
167         fprintf(output, "{\"Cmd\":\"SET_COLOR_MASK\",\n\"enable\":%s\n}\n", (cmd.colorMask.enabled ? "\"true\"" : "\"false\""));
168         break;
169       }
170       case GLES::CommandType::CLEAR_STENCIL_BUFFER:
171       {
172         fprintf(output, "{\"Cmd\":\"CLEAR_STENCIL_BUFFER\"}\n");
173         break;
174       }
175       case GLES::CommandType::CLEAR_DEPTH_BUFFER:
176       {
177         fprintf(output, "{\"Cmd\":\"CLEAR_DEPTH_BUFFER\"}\n");
178         break;
179       }
180
181       case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
182       {
183         fprintf(output, "{\"Cmd\":\"SET_STENCIL_TEST_ENABLE\",\n\"enable\":%s\n}\n", (cmd.stencilTest.enabled ? "\"true\"" : "\"false\""));
184         break;
185       }
186
187       case GLES::CommandType::SET_STENCIL_FUNC:
188       {
189         fprintf(output,
190                 "{\"Cmd\":\"STENCIL_FUNC\",\n"
191                 "\"compareOp\":\"%s\",\n"
192                 "\"reference\":\"0x%x\",\n"
193                 "\"compareMask\":\"0x%x\"\n}",
194                 DumpCompareOp(cmd.stencilFunc.compareOp).c_str(),
195                 cmd.stencilFunc.reference,
196                 cmd.stencilFunc.compareMask);
197         break;
198       }
199
200       case GLES::CommandType::SET_STENCIL_WRITE_MASK:
201       {
202         fprintf(output, "{\"Cmd\":\"SET_STENCIL_WRITE_MASK\",\n\"mask\":%d\n}\n", cmd.stencilWriteMask.mask);
203         break;
204       }
205
206       case GLES::CommandType::SET_STENCIL_OP:
207       {
208         fprintf(output,
209                 "{\"Cmd\":\"SET_STENCIL_OP\",\n"
210                 "\"failOp\":\"%s\",\n"
211                 "\"depthFailOp\":\"%s\",\n"
212                 "\"passOp\":\"%s\"\n}",
213
214                 DumpStencilOp(cmd.stencilOp.failOp).c_str(),
215                 DumpStencilOp(cmd.stencilOp.depthFailOp).c_str(),
216                 DumpStencilOp(cmd.stencilOp.passOp).c_str());
217         break;
218       }
219
220       case GLES::CommandType::SET_DEPTH_COMPARE_OP:
221       {
222         fprintf(output,
223                 "{\"Cmd\":\"SET_DEPTH_COMPARE_OP\",\n"
224                 "\"compareOp\":\"%s\"\n}\n",
225                 DumpCompareOp(cmd.depth.compareOp).c_str());
226         break;
227       }
228       case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
229       {
230         fprintf(output, "{\"Cmd\":\"SET_DEPTH_TEST_ENABLE\",\n\"enable\":%s\n}\n", (cmd.depth.testEnabled ? "\"true\"" : "\"false\""));
231         break;
232       }
233       case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
234       {
235         fprintf(output, "{\"Cmd\":\"SET_DEPTH_WRITE_ENABLE\",\n\"enable\":%s\n}\n", (cmd.depth.writeEnabled ? "\"true\"" : "\"false\""));
236         break;
237       }
238
239       case GLES::CommandType::BEGIN_RENDERPASS:
240       {
241         fprintf(output,
242                 "{\"Cmd\":\"BEGIN_RENDER_PASS\",\n"
243                 "\"renderTarget\":\"%p\",\n"
244                 "\"renderPass\":\"%p\",\n"
245                 "\"renderArea\":[%d,%d,%d,%d],\n",
246                 cmd.beginRenderPass.renderTarget,
247                 cmd.beginRenderPass.renderPass,
248                 cmd.beginRenderPass.renderArea.x,
249                 cmd.beginRenderPass.renderArea.y,
250                 cmd.beginRenderPass.renderArea.width,
251                 cmd.beginRenderPass.renderArea.height);
252         fprintf(output, "\"clearValues\":[");
253         bool firstV = true;
254         for(auto& value : cmd.beginRenderPass.clearValues)
255         {
256           if(!firstV)
257           {
258             fprintf(output, ",");
259           }
260           firstV = false;
261           fprintf(output, "[%f,%f,%f,%f]", value.color.r, value.color.g, value.color.b, value.color.a);
262         }
263         fprintf(output, "]\n}");
264         break;
265       }
266       case GLES::CommandType::END_RENDERPASS:
267       {
268         fprintf(output, "{\"Cmd\":\"END_RENDER_PASS\"}\n");
269         break;
270       }
271       case GLES::CommandType::PRESENT_RENDER_TARGET:
272       {
273         fprintf(output, "{\"Cmd\":\"PRESENT_RENDER_TARGET\"}\n");
274         break;
275       }
276       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
277       {
278         fprintf(output, "{\"Cmd\":\"EXECUTE_COMMAND_BUFFERS\",\n\"buffers\":[");
279         bool firstBuf{true};
280         for(auto& buf : cmd.executeCommandBuffers.buffers)
281         {
282           if(!firstBuf)
283           {
284             fprintf(output, ", ");
285           }
286           firstBuf = false;
287           DumpCommandBuffer(output, static_cast<const GLES::CommandBuffer*>(buf));
288         }
289         fprintf(output, "]\n}");
290         break;
291       }
292     }
293   }
294 }
295
296 GraphicsFrameDump::GraphicsFrameDump()
297 : outputStream(nullptr, nullptr)
298 {
299   char* outfile = getenv("GRAPHICS_CMDBUF_OUTFILE");
300   if(outfile)
301   {
302     outputStream = UniqueFilePtr(std::fopen(outfile, "w"), std::fclose);
303     output       = outputStream.get();
304   }
305   if(!output)
306     output = stderr;
307 }
308
309 void GraphicsFrameDump::Start()
310 {
311   if(IsDumpFrame())
312   {
313     if(!firstFrame)
314     {
315       fprintf(output, ", \n");
316     }
317     firstFrame   = false;
318     firstBuffer  = true;
319     dumpingFrame = true;
320     fprintf(output, "{\"Queue #%d\":[\n", frameCount);
321   }
322 }
323
324 void GraphicsFrameDump::DumpCommandBuffer(const GLES::CommandBuffer* cmdBuf)
325 {
326   if(dumpingFrame)
327   {
328     if(!firstBuffer)
329     {
330       fprintf(output, ", \n");
331     }
332     firstBuffer = false;
333     fprintf(output, "[\n");
334     Graphics::DumpCommandBuffer(output, cmdBuf);
335     fprintf(output, "]\n");
336   }
337 }
338
339 void GraphicsFrameDump::End()
340 {
341   if(dumpingFrame)
342   {
343     fprintf(output, "]}\n");
344   }
345   firstBuffer  = true;
346   dumpingFrame = false;
347 }
348
349 bool GraphicsFrameDump::IsDumpFrame()
350 {
351   bool dump = false;
352
353   frameCount++;
354
355   dump = (frameCount < NTH_FRAME);
356
357   // Or, could also use an enviroment variable as a trigger
358   // e.g. if getenv(X) is set, then start dumping again, and clear X.
359
360   return dump;
361 }
362
363 } // namespace Dali::Graphics