xref: /aosp_15_r20/external/angle/doc/DirtyBits.md (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1# Dirty Bits and State Changes
2
3OpenGL render loops typically involve changing some render states followed by
4a draw call. For instance the app might change a few uniforms and invoke
5`glDrawElements`:
6
7```
8for (const auto &obj : scene) {
9    for (const auto &uni : obj.uniforms) {
10        glUniform4fv(uni.loc, uni.data);
11    }
12    glDrawElements(GL_TRIANGLES, obj.eleCount, GL_UNSIGNED_SHORT, obj.eleOffset);
13}
14```
15
16Another update loop may change Texture and Vertex Array state before the draw:
17
18```
19for (const auto &obj : scene) {
20    glBindBuffer(GL_ARRAY_BUFFER, obj.arrayBuffer);
21    glBufferSubData(GL_ARRAY_BUFFER, obj.bufferOffset, obj.bufferSize, obj.bufferData);
22    glVertexAttribPointer(obj.arrayIndex, obj.arraySize, GL_FLOAT, GL_FALSE, 0, nullptr);
23    glBindTexture(GL_TEXTURE_2D, obj.texture);
24    glDrawElements(GL_TRIANGLES, obj.eleCount, GL_UNSIGNED_SHORT, obj.eleOffset);
25}
26```
27
28Other update loops may change render states like the blending modes, the depth test, or Framebuffer
29attachments. In each case ANGLE needs to validate, track, and translate these state changes to the
30back-end as efficiently as possible.
31
32## Dirty Bits
33
34Each OpenGL Context state value is stored in [`gl::State`](../src/libANGLE/State.h). For instance
35the blending state, depth/stencil state, and current object bindings. Our problem is deciding how to
36notify the back-end when app changes front-end state. We decided to bundle changed state into
37bitsets. Each 1 bit indicates a specific changed state value. We call these bitsets "*dirty bits*".
38See [`gl::State::DirtyBitType`][DirtyBitType].
39
40Each back-end handles state changes in a `syncState` implementation function that takes a dirty
41bitset. See examples in the [GL back-end][GLSyncState], [D3D11 back-end][D3D11SyncState] and
42[Vulkan back-end][VulkanSyncState].
43
44Container objects such as Vertex Array Objects and Framebuffers also have their own OpenGL front-end
45state. [VAOs][VAOState] store vertex arrays and array buffer bindings. [Framebuffers][FBOState]
46store attachment state and the active read and draw buffers. These containers also have internal
47dirty bits and `syncState` methods. See [`gl::Framebuffer::DirtyBitType`][FBODirtyBits] and
48[`rx::FramebufferVk::syncState`][FBOVkSyncState] for example.
49
50Dirty bits allow us to efficiently process groups of state updates. We use fast instrinsic functions
51to scan the bitsets for 1 bits. See [`bitset_utils.h`](../src/common/bitset_utils.h) for more
52information.
53
54## Cached Validation and State Change Notifications
55
56To optimize validation we cache many checks. See [`gl::StateCache`][StateCache] for examples. We
57need to refresh cached values on state changes. For instance, enabling a generic vertex array
58changes a cached mask of active vertex arrays. Changes to a texture's images could change a cached
59framebuffer's completeness when the texture is bound as an attachment. And if the draw framebuffer
60becomes incomplete it changes a cached draw call validation check.
61
62See a below example of a call to `glTexImage2D` that can affect draw call validation:
63
64<!-- Generated from https://bramp.github.io/js-sequence-diagrams/
65participant App
66participant Context
67participant Framebuffer
68participant Texture
69App->Context: glTexImage2D
70Context->Texture: setImage
71Texture- ->Framebuffer: onSubjectStateChange
72Note over Framebuffer: cache update
73Framebuffer- ->Context: onSubjectStateChange
74Note over Context: cache update
75-->
76
77![State Change Example](https://raw.githubusercontent.com/google/angle/main/doc/img/StateNotificationExample.svg?sanitize=true)
78
79We use the [Observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) to implement cache
80invalidation notifications. See [`Observer.h`](../src/libANGLE/Observer.h). In the example the
81`Framebuffer` observes `Texture` attachments via [`angle::ObserverBinding`][ObserverBinding].
82`Framebuffer` implements [`angle::ObserverInterface::onSubjectStateChange`][FBOStateChange] to
83receive a notification to update its completeness cache. The `STORAGE_CHANGED` message triggers a
84call to [`gl::Context::onSubjectStateChange`][ContextStateChange] which in turn calls
85[`gl::StateCache::updateBasicDrawStatesError`][StateCacheUpdate] to re-validate the draw
86framebuffer's completeness. On subsequent draw calls we skip re-validation at minimal cost.
87
88See the below diagram for the dependency relations between Subjects and Observers.
89
90![State Change Notification Flow](https://raw.githubusercontent.com/google/angle/main/doc/img/StateChangeNotificationFlow.svg?sanitize=true)
91
92## Back-end specific Optimizations
93
94See [Fast OpenGL State Transitions][FastStateTransitions] in [Vulkan documents][VulkanREADME] for
95additional information for how we implement state change optimization on the Vulkan back-end.
96
97[DirtyBitType]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/State.h#483
98[GLSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/gl/StateManagerGL.cpp#1576
99[D3D11SyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp#852
100[VulkanSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/vulkan/ContextVk.cpp#642
101[VAOState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/VertexArray.h#35
102[FBOState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.h#52
103[FBODirtyBits]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.h#319
104[FBOVkSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/vulkan/FramebufferVk.cpp#726
105[StateCache]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.h#98
106[ObserverBinding]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Observer.h#103
107[FBOStateChange]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.cpp#1811
108[ContextStateChange]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.cpp#7981
109[StateCacheUpdate]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.cpp#8190
110[FastStateTransitions]: ../src/libANGLE/renderer/vulkan/doc/FastOpenGLStateTransitions.md
111[VulkanREADME]: ../src/libANGLE/renderer/vulkan/README.md
112