Commit df3372b9 by Jamie Madill

Add markdown documentation for dirty bits.

Bug: angleproject:3002 Change-Id: I35df4e9f2af909f175402ce96773afb885bce595 Reviewed-on: https://chromium-review.googlesource.com/c/1455536Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent e03498f2
# Dirty Bits and State Changes
OpenGL render loops typically involve changing some render states followed by
a draw call. For instance the app might change a few uniforms and invoke
`glDrawElements`:
```
for (const auto &obj : scene) {
for (const auto &uni : obj.uniforms) {
glUniform4fv(uni.loc, uni.data);
}
glDrawElements(GL_TRIANGLES, obj.eleCount, GL_UNSIGNED_SHORT, obj.eleOffset);
}
```
Another update loop may change Texture and Vertex Array state before the draw:
```
for (const auto &obj : scene) {
glBindBuffer(GL_ARRAY_BUFFER, obj.arrayBuffer);
glBufferSubData(GL_ARRAY_BUFFER, obj.bufferOffset, obj.bufferSize, obj.bufferData);
glVertexAttribPointer(obj.arrayIndex, obj.arraySize, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindTexture(GL_TEXTURE_2D, obj.texture);
glDrawElements(GL_TRIANGLES, obj.eleCount, GL_UNSIGNED_SHORT, obj.eleOffset);
}
```
Other update loops may change render states like the blending modes, the depth test, or Framebuffer
attachments. In each case ANGLE needs to validate, track, and translate these state changes to the
back-end as efficiently as possible.
## Dirty Bits
Each OpenGL Context state value is stored in [`gl::State`](../src/libANGLE/State.h). For instance
the blending state, depth/stencil state, and current object bindings. Our problem is deciding how to
notify the back-end when app changes front-end state. We decided to bundle changed state into
bitsets. Each 1 bit indicates a specific changed state value. We call these bitsets "*dirty bits*".
See [`gl::State::DirtyBitType`][DirtyBitType].
Each back-end handles state changes in a `syncState` implementation function that takes a dirty
bitset. See examples in the [GL back-end][GLSyncState], [D3D11 back-end][D3D11SyncState] and
[Vulkan back-end][VulkanSyncState].
Container objects such as Vertex Array Objects and Framebuffers also have their own OpenGL front-end
state. [VAOs][VAOState] store vertex arrays and array buffer bindings. [Framebuffers][FBOState]
store attachment state and the active read and draw buffers. These containers also have internal
dirty bits and `syncState` methods. See [`gl::Framebuffer::DirtyBitType`][FBODirtyBits] and
[`rx::FramebufferVk::syncState`][FBOVkSyncState] for example.
Dirty bits allow us to efficiently process groups of state updates. We use fast instrinsic functions
to scan the bitsets for 1 bits. See [`bitset_utils.h`](../src/common/bitset_utils.h) for more
information.
## Cached Validation and State Change Notifications
To optimize validation we cache many checks. See [`gl::StateCache`][StateCache] for examples. We
need to refresh cached values on state changes. For instance, enabling a generic vertex array
changes a cached mask of active vertex arrays. Changes to a texture's images could change a cached
framebuffer's completeness when the texture is bound as an attachment. And if the draw framebuffer
becomes incomplete it changes a cached draw call validation check.
See a below example of a call to `glTexImage2D` that can affect draw call validation:
<!-- Generated from https://bramp.github.io/js-sequence-diagrams/
participant App
participant Context
participant Framebuffer
participant Texture
App->Context: glTexImage2D
Context->Texture: setImage
Texture- ->Framebuffer: onSubjectStateChange
Note over Framebuffer: cache update
Framebuffer- ->Context: onSubjectStateChange
Note over Context: cache update
-->
![State Change Example](https://chromium.googlesource.com/angle/angle/+/master/doc/image/StateNotificationExample.svg)
We use the [Observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) to implement cache
invalidation notifications. See [`Observer.h`](../src/libANGLE/Observer.h). In the example the
`Framebuffer` observes `Texture` attachments via [`angle::ObserverBinding`][ObserverBinding].
`Framebuffer` implements [`angle::ObserverInterface::onSubjectStateChange`][FBOStateChange] to
receive a notification to update its completeness cache. The `STORAGE_CHANGED` message triggers a
call to [`gl::Context::onSubjectStateChange`][ContextStateChange] which in turn calls
[`gl::StateCache::updateBasicDrawStatesError`][StateCacheUpdate] to re-validate the draw
framebuffer's completeness. On subsequent draw calls we skip re-validation at minimal cost.
## Back-end specific Optimizations
See the [Vulkan README][VulkanREADME] for additional information for how we implement state change
optimization on the Vulkan back-end.
[DirtyBitType]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/State.h#483
[GLSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/gl/StateManagerGL.cpp#1576
[D3D11SyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp#852
[VulkanSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/vulkan/ContextVk.cpp#642
[VAOState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/VertexArray.h#35
[FBOState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.h#52
[FBODirtyBits]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.h#319
[FBOVkSyncState]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/renderer/vulkan/FramebufferVk.cpp#726
[StateCache]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.h#98
[ObserverBinding]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Observer.h#103
[FBOStateChange]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Framebuffer.cpp#1811
[ContextStateChange]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.cpp#7981
[StateCacheUpdate]: https://chromium.googlesource.com/angle/angle/+/5f662c0042703344eb0eef6d1c123e902e3aefbf/src/libANGLE/Context.cpp#8190
[VulkanREADME]: ../src/libANGLE/renderer/vulkan/README.md#fast-opengl-state-transitions
<?xml version="1.0" encoding="utf-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg" width="621" height="390" xmlns:xlink="http://www.w3.org/1999/xlink"><source><![CDATA[participant App
participant Context
participant Framebuffer
participant Texture
App->Context: glTexImage2D
Context->Texture: setImage
Texture-->Framebuffer: onSubjectStateChange
Note over Framebuffer: cache update
Framebuffer-->Context: onSubjectStateChange
Note over Context: cache update
]]></source><desc></desc><defs><marker viewBox="0 0 5 5" markerWidth="5" markerHeight="5" orient="auto" refX="5" refY="2.5" id="markerArrowBlock"><path d="M 0 0 L 5 2.5 L 0 5 z"></path></marker><marker viewBox="0 0 9.6 16" markerWidth="4" markerHeight="16" orient="auto" refX="9.6" refY="8" id="markerArrowOpen"><path d="M 9.6,8 1.92,16 0,13.7 5.76,8 0,2.286 1.92,0 9.6,8 z"></path></marker></defs><g class="title"></g><g class="actor"><rect x="10" y="20" width="46.953125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="20.5625" y="44.84375" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="20">App</tspan></text></g><g class="actor"><rect x="10" y="331.90625" width="46.953125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="20.5625" y="356.75" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="20">App</tspan></text></g><line x1="33.4765625" x2="33.4765625" y1="58.84375" y2="331.90625" stroke="#000000" fill="none" style="stroke-width: 2;"></line><g class="actor"><rect x="118.25" y="20" width="81.578125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="128.25" y="44.84375" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="128.25">Context</tspan></text></g><g class="actor"><rect x="118.25" y="331.90625" width="81.578125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="128.25" y="356.75" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="128.25">Context</tspan></text></g><line x1="159.0390625" x2="159.0390625" y1="58.84375" y2="331.90625" stroke="#000000" fill="none" style="stroke-width: 2;"></line><g class="actor"><rect x="296.59375" y="20" width="116.765625" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="306.59375" y="44.84375" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="306.59375">Framebuffer</tspan></text></g><g class="actor"><rect x="296.59375" y="331.90625" width="116.765625" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="306.59375" y="356.75" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="306.59375">Framebuffer</tspan></text></g><line x1="354.9765625" x2="354.9765625" y1="58.84375" y2="331.90625" stroke="#000000" fill="none" style="stroke-width: 2;"></line><g class="actor"><rect x="510.125" y="20" width="81.578125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="520.125" y="44.84375" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="520.125">Texture</tspan></text></g><g class="actor"><rect x="510.125" y="331.90625" width="81.578125" height="38.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="520.125" y="356.75" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="520.125">Texture</tspan></text></g><line x1="550.9140625" x2="550.9140625" y1="58.84375" y2="331.90625" stroke="#000000" fill="none" style="stroke-width: 2;"></line><g class="signal"><text x="43.4765625" y="89.265625" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="43.4765625">glTexImage2D</tspan></text><line x1="33.4765625" x2="159.0390625" y1="97.6875" y2="97.6875" stroke="#000000" fill="none" style="stroke-width: 2; marker-end: url(&quot;#markerArrowBlock&quot;);"></line></g><g class="signal"><text x="319.7890625" y="128.109375" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="319.7890625">setImage</tspan></text><line x1="159.0390625" x2="550.9140625" y1="136.53125" y2="136.53125" stroke="#000000" fill="none" style="stroke-width: 2; marker-end: url(&quot;#markerArrowBlock&quot;);"></line></g><g class="signal"><text x="364.9765625" y="166.953125" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="364.9765625">onSubjectStateChange</tspan></text><line x1="550.9140625" x2="354.9765625" y1="175.375" y2="175.375" stroke="#000000" fill="none" style="stroke-width: 2; stroke-dasharray: 6, 2; marker-end: url(&quot;#markerArrowBlock&quot;);"></line></g><g class="note"><rect x="297.1953125" y="195.375" width="115.5625" height="28.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="302.1953125" y="215.21875" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="302.1953125">cache update</tspan></text></g><g class="signal"><text x="169.0390625" y="254.640625" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="169.0390625">onSubjectStateChange</tspan></text><line x1="354.9765625" x2="159.0390625" y1="263.0625" y2="263.0625" stroke="#000000" fill="none" style="stroke-width: 2; stroke-dasharray: 6, 2; marker-end: url(&quot;#markerArrowBlock&quot;);"></line></g><g class="note"><rect x="101.2578125" y="283.0625" width="115.5625" height="28.84375" stroke="#000000" fill="#ffffff" style="stroke-width: 2;"></rect><text x="106.2578125" y="302.90625" style="font-size: 16px; font-family: &quot;Andale Mono&quot;, monospace;"><tspan x="106.2578125">cache update</tspan></text></g></svg>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment