blob: 1d5f57e6dda218ba4fda22ddccd52a0d367805a5 [file] [log] [blame] [view]
Kai Ninomiyaa6429fb32018-03-30 01:30:561# Debugging GPU related code
2
3Chromium's GPU system is multi-process, which can make debugging it rather
4difficult. See [GPU Command Buffer] for some of the nitty gitty. These are just
5a few notes to help with debugging.
6
7[TOC]
8
9<!-- TODO(kainino): update link if the page moves -->
10[GPU Command Buffer]: https://sites.google.com/a/chromium.org/dev/developers/design-documents/gpu-command-buffer
11
12## Renderer Process Code
13
14### `--enable-gpu-client-logging`
15
16If you are trying to track down a bug in a GPU client process (compositing,
17WebGL, Skia/Ganesh, Aura), then in a debug build you can use the
18`--enable-gpu-client-logging` flag, which will show every GL call sent to the
19GPU service process. (From the point of view of a GPU client, it's calling
20OpenGL ES functions - but the real driver calls are made in the GPU process.)
21
22```
23[4782:4782:1219/141706:INFO:gles2_implementation.cc(1026)] [.WebGLRenderingContext] glUseProgram(3)
24[4782:4782:1219/141706:INFO:gles2_implementation_impl_autogen.h(401)] [.WebGLRenderingContext] glGenBuffers(1, 0x7fffc9e1269c)
25[4782:4782:1219/141706:INFO:gles2_implementation_impl_autogen.h(416)] 0: 1
26[4782:4782:1219/141706:INFO:gles2_implementation_impl_autogen.h(23)] [.WebGLRenderingContext] glBindBuffer(GL_ARRAY_BUFFER, 1)
27[4782:4782:1219/141706:INFO:gles2_implementation.cc(1313)] [.WebGLRenderingContext] glBufferData(GL_ARRAY_BUFFER, 36, 0x7fd268580120, GL_STATIC_DRAW)
28[4782:4782:1219/141706:INFO:gles2_implementation.cc(2480)] [.WebGLRenderingContext] glEnableVertexAttribArray(0)
29[4782:4782:1219/141706:INFO:gles2_implementation.cc(1140)] [.WebGLRenderingContext] glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)
30[4782:4782:1219/141706:INFO:gles2_implementation_impl_autogen.h(135)] [.WebGLRenderingContext] glClear(16640)
31[4782:4782:1219/141706:INFO:gles2_implementation.cc(2490)] [.WebGLRenderingContext] glDrawArrays(GL_TRIANGLES, 0, 3)
32```
33
34### Checking about:gpu
35
36The GPU process logs many errors and warnings. You can see these by navigating
37to `about:gpu`. Logs appear at the bottom of the page. You can also see them
38on standard output if Chromium is run from the command line on Linux/Mac.
39On Windows, you need debugging tools (like VS, WinDbg, etc.) to connect to the
40debug output stream.
41
42**Note:** If `about:gpu` is telling you that your GPU is disabled and
43hardware acceleration is unavailable, it might be a problem with your GPU being
44unsupported. To override this and turn on hardware acceleration anyway, you can
45use the `--ignore-gpu-blacklist` command line option when starting Chromium.
46
47### Breaking on GL Error
48
49In <code>[gles2_implementation.h]</code>, there is some code like this:
50
51```cpp
52// Set to 1 to have the client fail when a GL error is generated.
53// This helps find bugs in the renderer since the debugger stops on the error.
54#if DCHECK_IS_ON()
55#if 0
56#define GL_CLIENT_FAIL_GL_ERRORS
57#endif
58#endif
59```
60
61Change that `#if 0` to `#if 1`, build a debug build, then run in a debugger.
62The debugger will break when any renderer code sees a GL error, and you should
63be able to examine the call stack to find the issue.
64
65[gles2_implementation.h]: https://chromium.googlesource.com/chromium/src/+/master/gpu/command_buffer/client/gles2_implementation.h
66
67### Labeling your calls
68
69The output of all of the errors, warnings and debug logs are prefixed. You can
70set this prefix by calling `glPushGroupMarkerEXT`, `glPopGroupMarkerEXT` and
71`glInsertEventMarkerEXT`. `glPushGroupMarkerEXT` appends a string to the end of
72the current log prefix (think namespace in C++). `glPopGroupmarkerEXT` pops off
73the last string appended. `glInsertEventMarkerEXT` sets a suffix for the
74current string. Example:
75
76```cpp
77glPushGroupMarkerEXT(0, "Foo"); // -> log prefix = "Foo"
78glInsertEventMarkerEXT(0, "This"); // -> log prefix = "Foo.This"
79glInsertEventMarkerEXT(0, "That"); // -> log prefix = "Foo.That"
80glPushGroupMarkerEXT(0, "Bar"); // -> log prefix = "Foo.Bar"
81glInsertEventMarkerEXT(0, "Orange"); // -> log prefix = "Foo.Bar.Orange"
82glInsertEventMarkerEXT(0, "Banana"); // -> log prefix = "Foo.Bar.Banana"
83glPopGroupMarkerEXT(); // -> log prefix = "Foo.That"
84```
85
86### Making a reduced test case.
87
88You can often make a simple OpenGL-ES-2.0-only C++ reduced test case that is
89relatively quick to compile and test, by adding tests to the `gl_tests` target.
90Those tests exist in `src/gpu/command_buffer/tests` and are made part of the
91build in `src/gpu/gpu.gyp`. Build with `ninja -C out/Debug gl_tests`. All the
92same command line options listed on this page will work with the `gl_tests`,
93plus `--gtest_filter=NameOfTest` to run a specific test. Note the `gl_tests`
94are not multi-process, so they probably won't help with race conditions, but
95they do go through most of the same code and are much easier to debug.
96
97### Debugging the renderer process
98
99Given that Chrome starts many renderer processes I find it's easier if I either
100have a remote webpage I can access or I make one locally and then use a local
101server to serve it like `python -m SimpleHTTPServer`. Then
102
103On Linux this works for me:
104
105* `out/Debug/chromium --no-sandbox --renderer-cmd-prefix="xterm -e gdb
106 --args" http://localhost:8000/page-to-repro.html`
107
108On OSX this works for me:
109
110* `out/Debug/Chromium.app/Contents/MacOSX/Chromium --no-sandbox
111 --renderer-cmd-prefix="xterm -e gdb --args"
112 http://localhost:8000/page-to-repro.html`
113
114On Windows I use `--renderer-startup-dialog` and then connect to the listed process.
115
116Note 1: On Linux and OSX I use `cgdb` instead of `gdb`.
117
118Note 2: GDB can take minutes to index symbol. To save time, you can precache
119that computation by running `build/gdb-add-index out/Debug/chrome`.
120
121## GPU Process Code
122
123### `--enable-gpu-service-logging`
124
125In a debug build, this will print all actual calls into the GL driver.
126
127```
128[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kEnableVertexAttribArray
129[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(905)] glEnableVertexAttribArray(0)
130[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kVertexAttribPointer
131[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(1573)] glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)
132[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kClear
133[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(746)] glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
134[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(840)] glDepthMask(GL_TRUE)
135[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(900)] glEnable(GL_DEPTH_TEST)
136[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(1371)] glStencilMaskSeparate(GL_FRONT, 4294967295)
137[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(1371)] glStencilMaskSeparate(GL_BACK, 4294967295)
138[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(860)] glDisable(GL_STENCIL_TEST)
139[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(860)] glDisable(GL_CULL_FACE)
140[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(860)] glDisable(GL_SCISSOR_TEST)
141[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(900)] glEnable(GL_BLEND)
142[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(721)] glClear(16640)
143[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kDrawArrays
144[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(870)] glDrawArrays(GL_TRIANGLES, 0, 3)
145```
146
147Note that GL calls into the driver are not currently prefixed (todo?). But, you
148can tell from the commands logged which command, from which context caused the
149following GL calls to be made.
150
151Also note that client resource IDs are virtual IDs, so calls into the real GL
152driver will not match (though some commands print the mapping). Examples:
153
154```
155[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kBindTexture
156[5497:5497:1219/142413:INFO:gles2_cmd_decoder.cc(837)] [.WebGLRenderingContext] glBindTexture: client_id = 2, service_id = 10
157[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(662)] glBindTexture(GL_TEXTURE_2D, 10)
158[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [0052064A367F0000]cmd: kBindBuffer
159[5497:5497:1219/142413:INFO:gles2_cmd_decoder.cc(837)] [0052064A367F0000] glBindBuffer: client_id = 2, service_id = 6
160[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(637)] glBindBuffer(GL_ARRAY_BUFFER, 6)
161[5497:5497:1219/142413:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kBindFramebuffer
162[5497:5497:1219/142413:INFO:gles2_cmd_decoder.cc(837)] [.WebGLRenderingContext] glBindFramebuffer: client_id = 1, service_id = 3
163[5497:5497:1219/142413:INFO:gl_bindings_autogen_gl.cc(652)] glBindFramebufferEXT(GL_FRAMEBUFFER, 3)
164```
165
166etc... so that you can see renderer process code would be using the client IDs
167where as the gpu process is using the service IDs. This is useful for matching
168up calls if you're dumping both client and service GL logs.
169
170### `--enable-gpu-debugging`
171
172In any build, this will call glGetError after each command
173
174### `--enable-gpu-command-logging`
175
176This will print the name of each GPU command before it is executed.
177
178```
179[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kBindBuffer
180[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kBufferData
181[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: SetToken
182[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kEnableVertexAttribArray
183[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kVertexAttribPointer
184[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kClear
185[5234:5234:1219/052139:ERROR:gles2_cmd_decoder.cc(3301)] [.WebGLRenderingContext]cmd: kDrawArrays
186```
187
188### Debugging in the GPU Process
189
190Given the multi-processness of chromium it can be hard to debug both sides.
191Turing on all the logging and having a small test case is useful. One minor
192suggestion, if you have some idea where the bug is happening a call to some
193obscure gl function like `glHint()` can give you a place to catch a command
194being processed in the GPU process (put a break point on
195`gpu::gles2::GLES2DecoderImpl::HandleHint`. Once in you can follow the commands
196after that. All of them go through `gpu::gles2::GLES2DecoderImpl::DoCommand`.
197
198To actually debug the GPU process:
199
200On Linux this works for me:
201
202* `out/Debug/chromium --no-sandbox --gpu-launcher="xterm -e gdb --args"
203 http://localhost:8000/page-to-repro.html`
204
205On OSX this works for me:
206
207* `out/Debug/Chromium.app/Contents/MacOSX/Chromium --no-sandbox
208 --gpu-launcher="xterm -e gdb --args"
209 http://localhost:8000/page-to-repro.html`
210
211On Windows I use `--gpu-startup-dialog` and then connect to the listed process.
212
213### `GPU PARSE ERROR`
214
215If you see this message in `about:gpu` or your console and you didn't cause it
216directly (by calling `glLoseContextCHROMIUM`) and it's something other than 5
217that means there's likely a bug. Please file an issue at <http://crbug.com/new>.
218
219## Debugging Performance
220
221If you have something to add here please add it. Most perf debugging is done
222using `about:tracing` (see [Trace Event Profiling] for details). Otherwise,
223be aware that, since the system is multi-process, calling:
224
225```
226start = GetTime()
227DoSomething()
228glFinish()
229end = GetTime
230printf("elapsedTime = %f\n", end - start);
231```
232
233**will not** give you meaningful results.
234
235[See Trace Event Profiling for details]: https://sites.google.com/a/chromium.org/dev/developers/how-tos/trace-event-profiling-tool