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