9ee5721720004710003b29197e4a7ca141c149f8
[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   uint32_t   count   = 0u;
91   const auto command = commandBuffer->GetCommands(count);
92   for(auto i = 0u; i < count; ++i)
93   {
94     auto& cmd = command[i];
95     if(!first)
96     {
97       fprintf(output, ",");
98     }
99     first = false;
100     // process command
101     switch(cmd.type)
102     {
103       case GLES::CommandType::FLUSH:
104       {
105         fprintf(output, "{\"Cmd\":\"FLUSH\"}\n");
106         break;
107       }
108       case GLES::CommandType::BIND_TEXTURES:
109       {
110         fprintf(output, "{\"Cmd\":\"BIND_TEXTURES\"}\n");
111         break;
112       }
113       case GLES::CommandType::BIND_VERTEX_BUFFERS:
114       {
115         fprintf(output, "{\"Cmd\":\"BIND_VERTEX_BUFFERS\"}\n");
116         break;
117       }
118       case GLES::CommandType::BIND_UNIFORM_BUFFER:
119       {
120         fprintf(output, "{\"Cmd\":\"BIND_UNIFORM_BUFFERS\"}\n");
121         break;
122       }
123       case GLES::CommandType::BIND_INDEX_BUFFER:
124       {
125         fprintf(output, "{\"Cmd\":\"BIND_INDEX_BUFFERS\"}\n");
126         break;
127       }
128       case GLES::CommandType::BIND_SAMPLERS:
129       {
130         fprintf(output, "{\"Cmd\":\"BIND_SAMPLERS\"}\n");
131         break;
132       }
133       case GLES::CommandType::BIND_PIPELINE:
134       {
135         fprintf(output, "{\"Cmd\":\"BIND_PIPELINE\"}\n");
136         break;
137       }
138       case GLES::CommandType::DRAW:
139       {
140         fprintf(output, "{\"Cmd\":\"DRAW\"}\n");
141         break;
142       }
143       case GLES::CommandType::DRAW_INDEXED:
144       {
145         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED\"}\n");
146         break;
147       }
148       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
149       {
150         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED_INDIRECT\"}\n");
151         break;
152       }
153       case GLES::CommandType::SET_SCISSOR: // @todo Consider correcting for orientation here?
154       {
155         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);
156         break;
157       }
158       case GLES::CommandType::SET_SCISSOR_TEST:
159       {
160         fprintf(output, "{\"Cmd\":\"SET_SCISSOR_TEST\",\n\"enable\":%s\n}\n", (cmd.scissorTest.enable ? "\"true\"" : "\"false\""));
161         break;
162       }
163       case GLES::CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
164       {
165         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);
166         break;
167       }
168       case GLES::CommandType::SET_COLOR_MASK:
169       {
170         fprintf(output, "{\"Cmd\":\"SET_COLOR_MASK\",\n\"enable\":%s\n}\n", (cmd.colorMask.enabled ? "\"true\"" : "\"false\""));
171         break;
172       }
173       case GLES::CommandType::CLEAR_STENCIL_BUFFER:
174       {
175         fprintf(output, "{\"Cmd\":\"CLEAR_STENCIL_BUFFER\"}\n");
176         break;
177       }
178       case GLES::CommandType::CLEAR_DEPTH_BUFFER:
179       {
180         fprintf(output, "{\"Cmd\":\"CLEAR_DEPTH_BUFFER\"}\n");
181         break;
182       }
183
184       case GLES::CommandType::SET_STENCIL_TEST_ENABLE:
185       {
186         fprintf(output, "{\"Cmd\":\"SET_STENCIL_TEST_ENABLE\",\n\"enable\":%s\n}\n", (cmd.stencilTest.enabled ? "\"true\"" : "\"false\""));
187         break;
188       }
189
190       case GLES::CommandType::SET_STENCIL_FUNC:
191       {
192         fprintf(output,
193                 "{\"Cmd\":\"STENCIL_FUNC\",\n"
194                 "\"compareOp\":\"%s\",\n"
195                 "\"reference\":\"0x%x\",\n"
196                 "\"compareMask\":\"0x%x\"\n}",
197                 DumpCompareOp(cmd.stencilFunc.compareOp).c_str(),
198                 cmd.stencilFunc.reference,
199                 cmd.stencilFunc.compareMask);
200         break;
201       }
202
203       case GLES::CommandType::SET_STENCIL_WRITE_MASK:
204       {
205         fprintf(output, "{\"Cmd\":\"SET_STENCIL_WRITE_MASK\",\n\"mask\":%d\n}\n", cmd.stencilWriteMask.mask);
206         break;
207       }
208
209       case GLES::CommandType::SET_STENCIL_OP:
210       {
211         fprintf(output,
212                 "{\"Cmd\":\"SET_STENCIL_OP\",\n"
213                 "\"failOp\":\"%s\",\n"
214                 "\"depthFailOp\":\"%s\",\n"
215                 "\"passOp\":\"%s\"\n}",
216
217                 DumpStencilOp(cmd.stencilOp.failOp).c_str(),
218                 DumpStencilOp(cmd.stencilOp.depthFailOp).c_str(),
219                 DumpStencilOp(cmd.stencilOp.passOp).c_str());
220         break;
221       }
222
223       case GLES::CommandType::SET_DEPTH_COMPARE_OP:
224       {
225         fprintf(output,
226                 "{\"Cmd\":\"SET_DEPTH_COMPARE_OP\",\n"
227                 "\"compareOp\":\"%s\"\n}\n",
228                 DumpCompareOp(cmd.depth.compareOp).c_str());
229         break;
230       }
231       case GLES::CommandType::SET_DEPTH_TEST_ENABLE:
232       {
233         fprintf(output, "{\"Cmd\":\"SET_DEPTH_TEST_ENABLE\",\n\"enable\":%s\n}\n", (cmd.depth.testEnabled ? "\"true\"" : "\"false\""));
234         break;
235       }
236       case GLES::CommandType::SET_DEPTH_WRITE_ENABLE:
237       {
238         fprintf(output, "{\"Cmd\":\"SET_DEPTH_WRITE_ENABLE\",\n\"enable\":%s\n}\n", (cmd.depth.writeEnabled ? "\"true\"" : "\"false\""));
239         break;
240       }
241
242       case GLES::CommandType::BEGIN_RENDERPASS:
243       {
244         fprintf(output,
245                 "{\"Cmd\":\"BEGIN_RENDER_PASS\",\n"
246                 "\"renderTarget\":\"%p\",\n"
247                 "\"renderPass\":\"%p\",\n"
248                 "\"renderArea\":[%d,%d,%d,%d],\n",
249                 cmd.beginRenderPass.renderTarget,
250                 cmd.beginRenderPass.renderPass,
251                 cmd.beginRenderPass.renderArea.x,
252                 cmd.beginRenderPass.renderArea.y,
253                 cmd.beginRenderPass.renderArea.width,
254                 cmd.beginRenderPass.renderArea.height);
255         fprintf(output, "\"clearValues\":[");
256         bool firstV = true;
257         for(auto i = 0u; i < cmd.beginRenderPass.clearValuesCount; ++i)
258         {
259           auto value = cmd.beginRenderPass.clearValues.Ptr()[i];
260           if(!firstV)
261           {
262             fprintf(output, ",");
263           }
264           firstV = false;
265           fprintf(output, "[%f,%f,%f,%f]", value.color.r, value.color.g, value.color.b, value.color.a);
266         }
267         fprintf(output, "]\n}");
268         break;
269       }
270       case GLES::CommandType::END_RENDERPASS:
271       {
272         fprintf(output, "{\"Cmd\":\"END_RENDER_PASS\"}\n");
273         break;
274       }
275       case GLES::CommandType::PRESENT_RENDER_TARGET:
276       {
277         fprintf(output, "{\"Cmd\":\"PRESENT_RENDER_TARGET\"}\n");
278         break;
279       }
280       case GLES::CommandType::EXECUTE_COMMAND_BUFFERS:
281       {
282         fprintf(output, "{\"Cmd\":\"EXECUTE_COMMAND_BUFFERS\",\n\"buffers\":[");
283         bool firstBuf{true};
284         for(auto i = 0u; i < cmd.executeCommandBuffers.buffersCount; ++i)
285         {
286           const auto buf = cmd.executeCommandBuffers.buffers.Ptr()[i];
287           if(!firstBuf)
288           {
289             fprintf(output, ", ");
290           }
291           firstBuf = false;
292           DumpCommandBuffer(output, buf);
293         }
294         fprintf(output, "]\n}");
295         break;
296       }
297     }
298   }
299 }
300
301 GraphicsFrameDump::GraphicsFrameDump()
302 : outputStream(nullptr, nullptr)
303 {
304   char* outfile = getenv("GRAPHICS_CMDBUF_OUTFILE");
305   if(outfile)
306   {
307     outputStream = UniqueFilePtr(std::fopen(outfile, "w"), std::fclose);
308     output       = outputStream.get();
309   }
310   if(!output)
311     output = stderr;
312 }
313
314 void GraphicsFrameDump::Start()
315 {
316   if(IsDumpFrame())
317   {
318     if(!firstFrame)
319     {
320       fprintf(output, ", \n");
321     }
322     firstFrame   = false;
323     firstBuffer  = true;
324     dumpingFrame = true;
325     fprintf(output, "{\"Queue #%d\":[\n", frameCount);
326   }
327 }
328
329 void GraphicsFrameDump::DumpCommandBuffer(const GLES::CommandBuffer* cmdBuf)
330 {
331   if(dumpingFrame)
332   {
333     if(!firstBuffer)
334     {
335       fprintf(output, ", \n");
336     }
337     firstBuffer = false;
338     fprintf(output, "[\n");
339     Graphics::DumpCommandBuffer(output, cmdBuf);
340     fprintf(output, "]\n");
341   }
342 }
343
344 void GraphicsFrameDump::End()
345 {
346   if(dumpingFrame)
347   {
348     fprintf(output, "]}\n");
349   }
350   firstBuffer  = true;
351   dumpingFrame = false;
352 }
353
354 bool GraphicsFrameDump::IsDumpFrame()
355 {
356   bool dump = false;
357
358   frameCount++;
359
360   dump = (frameCount < NTH_FRAME);
361
362   // Or, could also use an enviroment variable as a trigger
363   // e.g. if getenv(X) is set, then start dumping again, and clear X.
364
365   return dump;
366 }
367
368 } // namespace Dali::Graphics