Commit c8bee335 by Jamie Madill Committed by Commit Bot

D3D11: Implement a dirty bit for Shaders.

This allows us to skip calling the dynamic shader generation and program shader application when there haven't been any state changes. It builds on the previous work that immediately update state caches in the VertexArray11 and Framebuffer11. It should improve performance in draw-call limited applications by a small margin. For reference, here are the conditions under which the shaders are refreshed: 1. Directly changing the program executable 2. The vertex attribute layout 3. The fragment shader's rendertargets 4. Enabling/disabling rasterizer discard 5. Enabling/disabling transform feedback 6. An internal shader was used 7. Drawing with/without point sprites Improves the score of the draw call stress test for the D3D11 back-end (with null driver) by about 40% on my test machine. The 9_3 back-end seems to have an issue where the getSRV call to a texture storage can change the "use level zero workaround" status of the storage, which in turn will invalidate the state. Since this is localized to 9_3 only, put in a hack to disable an assert check for now. BUG=angleproject:2151 Change-Id: Idbd0a31376691b33972e735d5833a9b02a8a4aa9 Reviewed-on: https://chromium-review.googlesource.com/666278Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent fb997ec1
......@@ -386,11 +386,7 @@ gl::Error Context11::triggerDrawCallProgramRecompilation(const gl::Context *cont
gl::Error Context11::prepareForDrawCall(const gl::Context *context, GLenum drawMode)
{
ANGLE_TRY(triggerDrawCallProgramRecompilation(context, drawMode));
// TODO(jmadill): Update state in syncState before the draw call.
ANGLE_TRY(mRenderer->getStateManager()->updateState(context, drawMode));
return gl::NoError();
}
......
......@@ -138,8 +138,9 @@ class Context11 : public ContextImpl
GLuint numGroupsY,
GLuint numGroupsZ) override;
private:
gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context, GLenum drawMode);
private:
gl::Error prepareForDrawCall(const gl::Context *context, GLenum drawMode);
Renderer11 *mRenderer;
......
......@@ -459,6 +459,10 @@ void Framebuffer11::signal(size_t channelID, const gl::Context *context)
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + channelID);
mCachedColorRenderTargets[channelID] = nullptr;
}
// Notify the context we need to re-validate the RenderTarget.
// TODO(jmadill): Check that we're the active draw framebuffer.
mRenderer->getStateManager()->invalidateRenderTarget(context);
}
gl::Error Framebuffer11::getSamplePosition(size_t index, GLfloat *xy) const
......
......@@ -15,6 +15,7 @@
#include "libANGLE/VertexArray.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
......@@ -551,7 +552,8 @@ StateManager11::StateManager11(Renderer11 *renderer)
mVertexDataManager(renderer),
mIndexDataManager(renderer, RENDERER_D3D11),
mIsMultiviewEnabled(false),
mEmptySerial(mRenderer->generateSerial())
mEmptySerial(mRenderer->generateSerial()),
mIsTransformFeedbackCurrentlyActiveUnpaused(false)
{
mCurBlendState.blend = false;
mCurBlendState.sourceBlendRGB = GL_ONE;
......@@ -893,6 +895,9 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
mCurRasterState.rasterizerDiscard)
{
mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE);
// Enabling/disabling rasterizer discard affects the pixel shader.
invalidateShaders();
}
break;
case gl::State::DIRTY_BIT_SCISSOR:
......@@ -943,6 +948,7 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{
mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
invalidateVertexBuffer();
invalidateRenderTarget(context);
invalidateTexturesAndSamplers();
......@@ -1287,6 +1293,9 @@ void StateManager11::invalidateRenderTarget(const gl::Context *context)
{
mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET);
// The pixel shader is dependent on the output layout.
invalidateShaders();
// The D3D11 blend state is heavily dependent on the current render target.
mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE);
......@@ -1332,11 +1341,14 @@ void StateManager11::invalidateRenderTarget(const gl::Context *context)
if (mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3)
{
const auto *firstAttachment = fbo->getFirstNonNullAttachment();
const auto &size = firstAttachment->getSize();
if (mViewportBounds.width != size.width || mViewportBounds.height != size.height)
if (firstAttachment)
{
mViewportBounds = gl::Extents(size.width, size.height, 1);
invalidateViewport(context);
const auto &size = firstAttachment->getSize();
if (mViewportBounds.width != size.width || mViewportBounds.height != size.height)
{
mViewportBounds = gl::Extents(size.width, size.height, 1);
invalidateViewport(context);
}
}
}
}
......@@ -1410,6 +1422,11 @@ void StateManager11::invalidateConstantBuffer(unsigned int slot)
}
}
void StateManager11::invalidateShaders()
{
mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
}
void StateManager11::setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv)
{
if ((rtv && unsetConflictingView(rtv)) || (dsv && unsetConflictingView(dsv)))
......@@ -1829,6 +1846,14 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS);
}
// Transform feedback affects the stream-out geometry shader.
// TODO(jmadill): Use dirty bits.
if (glState.isTransformFeedbackActiveUnpaused() != mIsTransformFeedbackCurrentlyActiveUnpaused)
{
mIsTransformFeedbackCurrentlyActiveUnpaused = glState.isTransformFeedbackActiveUnpaused();
invalidateShaders();
}
// Swizzling can cause internal state changes with blit shaders.
if (mDirtySwizzles)
{
......@@ -1836,9 +1861,6 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
mDirtySwizzles = false;
}
// TODO(jmadill): Use dirty bits.
ANGLE_TRY(syncProgram(context, drawMode));
gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
ANGLE_TRY(framebuffer11->markAttachmentsDirty(context));
......@@ -1853,6 +1875,9 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
if (pointDrawMode != mCurRasterState.pointDrawMode)
{
mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE);
// Changing from points to not points (or vice-versa) affects the geometry shader.
invalidateShaders();
}
// TODO(jmadill): This can be recomputed only on framebuffer changes.
......@@ -1864,6 +1889,14 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE);
}
// Changing the vertex attribute state can affect the vertex shader.
gl::VertexArray *vao = glState.getVertexArray();
VertexArray11 *vao11 = GetImplAs<VertexArray11>(vao);
if (vao11->flushAttribUpdates(context))
{
mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
}
auto dirtyBitsCopy = mInternalDirtyBits;
mInternalDirtyBits.reset();
......@@ -1902,9 +1935,11 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
ANGLE_TRY(applyDriverUniforms(*programD3D));
break;
case DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS:
// TOOD(jmadill): Use dirty bits.
ANGLE_TRY(syncUniformBuffers(context, programD3D));
break;
case DIRTY_BIT_SHADERS:
ANGLE_TRY(syncProgram(context, drawMode));
break;
default:
UNREACHABLE();
break;
......@@ -1914,7 +1949,9 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
ANGLE_TRY(syncTransformFeedbackBuffers(context));
// Check that we haven't set any dirty bits in the flushing of the dirty bits loop.
ASSERT(mInternalDirtyBits.none());
// TODO(jmadill): Fix FL 9_3 RenderTarget dirtying in call to syncTextures.
ASSERT(mInternalDirtyBits.none() ||
mRenderer->getRenderer11DeviceCaps().featureLevel <= D3D_FEATURE_LEVEL_9_3);
return gl::NoError();
}
......@@ -1966,6 +2003,7 @@ void StateManager11::setVertexShader(const d3d11::VertexShader *shader)
ID3D11VertexShader *appliedShader = shader ? shader->get() : nullptr;
mRenderer->getDeviceContext()->VSSetShader(appliedShader, nullptr, 0);
mAppliedVertexShader = serial;
invalidateShaders();
}
}
......@@ -1978,6 +2016,7 @@ void StateManager11::setGeometryShader(const d3d11::GeometryShader *shader)
ID3D11GeometryShader *appliedShader = shader ? shader->get() : nullptr;
mRenderer->getDeviceContext()->GSSetShader(appliedShader, nullptr, 0);
mAppliedGeometryShader = serial;
invalidateShaders();
}
}
......@@ -1990,6 +2029,7 @@ void StateManager11::setPixelShader(const d3d11::PixelShader *shader)
ID3D11PixelShader *appliedShader = shader ? shader->get() : nullptr;
mRenderer->getDeviceContext()->PSSetShader(appliedShader, nullptr, 0);
mAppliedPixelShader = serial;
invalidateShaders();
}
}
......@@ -2002,6 +2042,7 @@ void StateManager11::setComputeShader(const d3d11::ComputeShader *shader)
ID3D11ComputeShader *appliedShader = shader ? shader->get() : nullptr;
mRenderer->getDeviceContext()->CSSetShader(appliedShader, nullptr, 0);
mAppliedComputeShader = serial;
// TODO(jmadill): Dirty bits for compute.
}
}
......@@ -2364,8 +2405,20 @@ gl::Error StateManager11::setTexture(const gl::Context *context,
return gl::NoError();
}
// Things that affect a program's dirtyness:
// 1. Directly changing the program executable -> triggered in StateManager11::syncState.
// 2. The vertex attribute layout -> triggered in VertexArray11::syncState/signal.
// 3. The fragment shader's rendertargets -> triggered in Framebuffer11::syncState/signal.
// 4. Enabling/disabling rasterizer discard. -> triggered in StateManager11::syncState.
// 5. Enabling/disabling transform feedback. -> checked in StateManager11::updateState.
// 6. An internal shader was used. -> triggered in StateManager11::set*Shader.
// 7. Drawing with/without point sprites. -> checked in StateManager11::updateState.
// TODO(jmadill): Use dirty bits for transform feedback.
gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMode)
{
Context11 *context11 = GetImplAs<Context11>(context);
ANGLE_TRY(context11->triggerDrawCallProgramRecompilation(context, drawMode));
const auto &glState = context->getGLState();
const auto *va11 = GetImplAs<VertexArray11>(glState.getVertexArray());
auto *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
......@@ -2410,6 +2463,10 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
}
setDrawShaders(vertexShader, geometryShader, pixelShader);
// Explicitly clear the shaders dirty bit.
mInternalDirtyBits.reset(DIRTY_BIT_SHADERS);
return gl::NoError();
}
......
......@@ -179,6 +179,9 @@ class StateManager11 final : angle::NonCopyable
// Called by TextureStorage11::markLevelDirty.
void invalidateSwizzles();
// Called by the Framebuffer11 and VertexArray11.
void invalidateShaders();
void setRenderTarget(ID3D11RenderTargetView *rtv, ID3D11DepthStencilView *dsv);
void setRenderTargets(ID3D11RenderTargetView **rtvs, UINT numRtvs, ID3D11DepthStencilView *dsv);
......@@ -326,6 +329,9 @@ class StateManager11 final : angle::NonCopyable
void invalidateProgramUniformBuffers();
void invalidateConstantBuffer(unsigned int slot);
// Called by the Framebuffer11 directly.
void dirtyDrawFramebuffer();
enum DirtyBitType
{
DIRTY_BIT_RENDER_TARGET,
......@@ -338,6 +344,7 @@ class StateManager11 final : angle::NonCopyable
DIRTY_BIT_PROGRAM_UNIFORMS,
DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS,
DIRTY_BIT_SHADERS,
DIRTY_BIT_INVALID,
DIRTY_BIT_MAX = DIRTY_BIT_INVALID,
};
......@@ -510,6 +517,8 @@ class StateManager11 final : angle::NonCopyable
Serial mAppliedTFSerial;
Serial mEmptySerial;
bool mIsTransformFeedbackCurrentlyActiveUnpaused;
};
} // namespace rx
......
......@@ -68,7 +68,7 @@ void VertexArray11::syncState(const gl::Context *context,
}
}
void VertexArray11::flushAttribUpdates(const gl::Context *context)
bool VertexArray11::flushAttribUpdates(const gl::Context *context)
{
const gl::Program *program = context->getGLState().getProgram();
const auto &activeLocations = program->getActiveAttribLocationsMask();
......@@ -83,7 +83,11 @@ void VertexArray11::flushAttribUpdates(const gl::Context *context)
mAttribsToUpdate.reset(toUpdateIndex);
updateVertexAttribStorage(context, toUpdateIndex);
}
return true;
}
return false;
}
void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t attribIndex)
......@@ -258,6 +262,10 @@ void VertexArray11::signal(size_t channelID, const gl::Context *context)
// This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(channelID);
// Changing the vertex attribute state can affect the vertex shader.
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
renderer->getStateManager()->invalidateShaders();
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::Context *context, GLsizei count)
......
......@@ -47,9 +47,10 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
// is adjusted.
void markAllAttributeDivisorsForAdjustment(int numViews);
bool flushAttribUpdates(const gl::Context *context);
private:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
void flushAttribUpdates(const gl::Context *context);
std::vector<VertexStorageType> mAttributeStorageTypes;
std::vector<TranslatedAttribute> mTranslatedAttribs;
......
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