Commit a779b610 by Jamie Madill Committed by Commit Bot

Smart caching of VAO input layout.

Don't recompute the cached attribute layout for a program if the vertex array info hasn't changed. We can use the Serial class to know when a vertex array has identical state. BUG=angleproject:1156 Change-Id: Ia11f6ac268f63c3299f6d6d80c2866009cb8429c Reviewed-on: https://chromium-review.googlesource.com/529768Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent cab92ee4
...@@ -4649,6 +4649,7 @@ void Context::linkProgram(GLuint program) ...@@ -4649,6 +4649,7 @@ void Context::linkProgram(GLuint program)
Program *programObject = getProgram(program); Program *programObject = getProgram(program);
ASSERT(programObject); ASSERT(programObject);
handleError(programObject->link(this)); handleError(programObject->link(this));
mGLState.onProgramExecutableChange(programObject);
} }
void Context::releaseShaderCompiler() void Context::releaseShaderCompiler()
...@@ -4843,8 +4844,8 @@ void Context::programBinary(GLuint program, GLenum binaryFormat, const void *bin ...@@ -4843,8 +4844,8 @@ void Context::programBinary(GLuint program, GLenum binaryFormat, const void *bin
{ {
Program *programObject = getProgram(program); Program *programObject = getProgram(program);
ASSERT(programObject != nullptr); ASSERT(programObject != nullptr);
handleError(programObject->loadBinary(this, binaryFormat, binary, length)); handleError(programObject->loadBinary(this, binaryFormat, binary, length));
mGLState.onProgramExecutableChange(programObject);
} }
} // namespace gl } // namespace gl
...@@ -1102,6 +1102,8 @@ void State::setProgram(const Context *context, Program *newProgram) ...@@ -1102,6 +1102,8 @@ void State::setProgram(const Context *context, Program *newProgram)
{ {
newProgram->addRef(); newProgram->addRef();
} }
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING);
} }
} }
...@@ -2154,9 +2156,6 @@ void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset) ...@@ -2154,9 +2156,6 @@ void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
ASSERT(mVertexArray); ASSERT(mVertexArray);
mVertexArray->syncImplState(context); mVertexArray->syncImplState(context);
break; break;
case DIRTY_OBJECT_PROGRAM:
// TODO(jmadill): implement this
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
...@@ -2185,9 +2184,6 @@ void State::syncDirtyObject(const Context *context, GLenum target) ...@@ -2185,9 +2184,6 @@ void State::syncDirtyObject(const Context *context, GLenum target)
case GL_VERTEX_ARRAY: case GL_VERTEX_ARRAY:
localSet.set(DIRTY_OBJECT_VERTEX_ARRAY); localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
break; break;
case GL_PROGRAM:
localSet.set(DIRTY_OBJECT_PROGRAM);
break;
} }
syncDirtyObjects(context, localSet); syncDirtyObjects(context, localSet);
...@@ -2210,9 +2206,18 @@ void State::setObjectDirty(GLenum target) ...@@ -2210,9 +2206,18 @@ void State::setObjectDirty(GLenum target)
case GL_VERTEX_ARRAY: case GL_VERTEX_ARRAY:
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY); mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
break; break;
case GL_PROGRAM: }
mDirtyObjects.set(DIRTY_OBJECT_PROGRAM); }
break;
void State::onProgramExecutableChange(Program *program)
{
// OpenGL Spec:
// "If LinkProgram or ProgramBinary successfully re-links a program object
// that was already in use as a result of a previous call to UseProgram, then the
// generated executable code will be installed as part of the current rendering state."
if (program->isLinked() && mProgram == program)
{
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
} }
} }
......
...@@ -362,6 +362,9 @@ class State : angle::NonCopyable ...@@ -362,6 +362,9 @@ class State : angle::NonCopyable
bool hasMappedBuffer(GLenum target) const; bool hasMappedBuffer(GLenum target) const;
bool isRobustResourceInitEnabled() const { return mRobustResourceInit; } bool isRobustResourceInitEnabled() const { return mRobustResourceInit; }
// Sets the dirty bit for the program executable.
void onProgramExecutableChange(Program *program);
enum DirtyBitType enum DirtyBitType
{ {
DIRTY_BIT_SCISSOR_TEST_ENABLED, DIRTY_BIT_SCISSOR_TEST_ENABLED,
...@@ -419,6 +422,7 @@ class State : angle::NonCopyable ...@@ -419,6 +422,7 @@ class State : angle::NonCopyable
DIRTY_BIT_VERTEX_ARRAY_BINDING, DIRTY_BIT_VERTEX_ARRAY_BINDING,
DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING, DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING,
DIRTY_BIT_PROGRAM_BINDING, DIRTY_BIT_PROGRAM_BINDING,
DIRTY_BIT_PROGRAM_EXECUTABLE,
DIRTY_BIT_MULTISAMPLING, DIRTY_BIT_MULTISAMPLING,
DIRTY_BIT_SAMPLE_ALPHA_TO_ONE, DIRTY_BIT_SAMPLE_ALPHA_TO_ONE,
DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples
...@@ -438,7 +442,6 @@ class State : angle::NonCopyable ...@@ -438,7 +442,6 @@ class State : angle::NonCopyable
DIRTY_OBJECT_READ_FRAMEBUFFER, DIRTY_OBJECT_READ_FRAMEBUFFER,
DIRTY_OBJECT_DRAW_FRAMEBUFFER, DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY, DIRTY_OBJECT_VERTEX_ARRAY,
DIRTY_OBJECT_PROGRAM,
DIRTY_OBJECT_UNKNOWN, DIRTY_OBJECT_UNKNOWN,
DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN, DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
}; };
......
...@@ -2389,8 +2389,14 @@ void ProgramD3D::initAttribLocationsToD3DSemantic(const gl::Context *context) ...@@ -2389,8 +2389,14 @@ void ProgramD3D::initAttribLocationsToD3DSemantic(const gl::Context *context)
} }
} }
void ProgramD3D::updateCachedInputLayout(const gl::State &state) void ProgramD3D::updateCachedInputLayout(Serial associatedSerial, const gl::State &state)
{ {
if (mCurrentVertexArrayStateSerial == associatedSerial)
{
return;
}
mCurrentVertexArrayStateSerial = associatedSerial;
mCachedInputLayout.clear(); mCachedInputLayout.clear();
const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes(); const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
......
...@@ -260,7 +260,7 @@ class ProgramD3D : public ProgramImpl ...@@ -260,7 +260,7 @@ class ProgramD3D : public ProgramImpl
return mAttribLocationToD3DSemantic; return mAttribLocationToD3DSemantic;
} }
void updateCachedInputLayout(const gl::State &state); void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; } const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; }
bool isSamplerMappingDirty() { return mDirtySamplerMapping; } bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
...@@ -438,6 +438,8 @@ class ProgramD3D : public ProgramImpl ...@@ -438,6 +438,8 @@ class ProgramD3D : public ProgramImpl
static unsigned int issueSerial(); static unsigned int issueSerial();
static unsigned int mCurrentSerial; static unsigned int mCurrentSerial;
Serial mCurrentVertexArrayStateSerial;
}; };
} }
......
...@@ -288,6 +288,11 @@ bool RendererD3D::isRobustResourceInitEnabled() const ...@@ -288,6 +288,11 @@ bool RendererD3D::isRobustResourceInitEnabled() const
return mDisplay->isRobustResourceInitEnabled(); return mDisplay->isRobustResourceInitEnabled();
} }
Serial RendererD3D::generateSerial()
{
return mSerialFactory.generate();
}
unsigned int GetBlendSampleMask(const gl::State &glState, int samples) unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
{ {
unsigned int mask = 0; unsigned int mask = 0;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/formatutilsD3D.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "platform/WorkaroundsD3D.h" #include "platform/WorkaroundsD3D.h"
namespace egl namespace egl
...@@ -327,6 +328,8 @@ class RendererD3D : public BufferFactoryD3D ...@@ -327,6 +328,8 @@ class RendererD3D : public BufferFactoryD3D
gl::Texture *getIncompleteTexture(const gl::Context *context, GLenum type); gl::Texture *getIncompleteTexture(const gl::Context *context, GLenum type);
Serial generateSerial();
protected: protected:
virtual bool getLUID(LUID *adapterLuid) const = 0; virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual void generateCaps(gl::Caps *outCaps, virtual void generateCaps(gl::Caps *outCaps,
...@@ -365,6 +368,8 @@ class RendererD3D : public BufferFactoryD3D ...@@ -365,6 +368,8 @@ class RendererD3D : public BufferFactoryD3D
bool mDeviceLost; bool mDeviceLost;
angle::WorkerThreadPool mWorkerThreadPool; angle::WorkerThreadPool mWorkerThreadPool;
SerialFactory mSerialFactory;
}; };
unsigned int GetBlendSampleMask(const gl::State &glState, int samples); unsigned int GetBlendSampleMask(const gl::State &glState, int samples);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLe/renderer/d3d/d3d11/VertexArray11.h"
namespace rx namespace rx
{ {
...@@ -284,6 +285,7 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -284,6 +285,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mDirtyCurrentValueAttribs(), mDirtyCurrentValueAttribs(),
mCurrentValueAttribs(), mCurrentValueAttribs(),
mCurrentInputLayout(), mCurrentInputLayout(),
mInputLayoutIsDirty(false),
mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0), mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0),
mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED) mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)
{ {
...@@ -620,6 +622,10 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -620,6 +622,10 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
invalidateRenderTarget(context); invalidateRenderTarget(context);
break; break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
invalidateVertexBuffer();
invalidateRenderTarget(context);
break;
default: default:
if (dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 && if (dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 &&
dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX) dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX)
...@@ -997,6 +1003,7 @@ void StateManager11::invalidateVertexBuffer() ...@@ -997,6 +1003,7 @@ void StateManager11::invalidateVertexBuffer()
unsigned int limit = std::min<unsigned int>(mRenderer->getNativeCaps().maxVertexAttributes, unsigned int limit = std::min<unsigned int>(mRenderer->getNativeCaps().maxVertexAttributes,
gl::MAX_VERTEX_ATTRIBS); gl::MAX_VERTEX_ATTRIBS);
mDirtyVertexBufferRange = gl::RangeUI(0, limit); mDirtyVertexBufferRange = gl::RangeUI(0, limit);
mInputLayoutIsDirty = true;
} }
void StateManager11::setOneTimeRenderTarget(const gl::Context *context, void StateManager11::setOneTimeRenderTarget(const gl::Context *context,
...@@ -1733,9 +1740,11 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod ...@@ -1733,9 +1740,11 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
// This method is called single-threaded. // This method is called single-threaded.
ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized()); ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized());
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
const auto *va11 = GetImplAs<VertexArray11>(glState.getVertexArray());
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram()); ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
programD3D->updateCachedInputLayout(glState); programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
const auto &inputLayout = programD3D->getCachedInputLayout(); const auto &inputLayout = programD3D->getCachedInputLayout();
......
...@@ -303,6 +303,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -303,6 +303,7 @@ class StateManager11 final : angle::NonCopyable
// Current applied input layout. // Current applied input layout.
ResourceSerial mCurrentInputLayout; ResourceSerial mCurrentInputLayout;
bool mInputLayoutIsDirty;
// Current applied vertex states. // Current applied vertex states.
// TODO(jmadill): Figure out how to use ResourceSerial here. // TODO(jmadill): Figure out how to use ResourceSerial here.
......
...@@ -45,6 +45,16 @@ void VertexArray11::destroy(const gl::Context *context) ...@@ -45,6 +45,16 @@ void VertexArray11::destroy(const gl::Context *context)
void VertexArray11::syncState(const gl::Context *context, void VertexArray11::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) const gl::VertexArray::DirtyBits &dirtyBits)
{ {
ASSERT(dirtyBits.any());
// Generate a state serial. This serial is used in the program class to validate the cached
// input layout, and skip recomputation in the fast path.
auto renderer = GetImplAs<Context11>(context)->getRenderer();
mCurrentStateSerial = renderer->generateSerial();
// TODO(jmadill): Individual attribute invalidation.
renderer->getStateManager()->invalidateVertexBuffer();
for (auto dirtyBit : dirtyBits) for (auto dirtyBit : dirtyBits)
{ {
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER) if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
......
...@@ -40,6 +40,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -40,6 +40,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
// SignalReceiver implementation // SignalReceiver implementation
void signal(size_t channelID) override; void signal(size_t channelID) override;
Serial getCurrentStateSerial() const { return mCurrentStateSerial; }
private: private:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex); void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
void flushAttribUpdates(const gl::Context *context); void flushAttribUpdates(const gl::Context *context);
...@@ -60,6 +62,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -60,6 +62,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
std::vector<gl::BindingPointer<gl::Buffer>> mCurrentBuffers; std::vector<gl::BindingPointer<gl::Buffer>> mCurrentBuffers;
std::vector<OnBufferDataDirtyBinding> mOnBufferDataDirty; std::vector<OnBufferDataDirtyBinding> mOnBufferDataDirty;
Serial mCurrentStateSerial;
}; };
} // namespace rx } // namespace rx
......
...@@ -136,6 +136,8 @@ class Context9 : public ContextImpl ...@@ -136,6 +136,8 @@ class Context9 : public ContextImpl
GLuint numGroupsY, GLuint numGroupsY,
GLuint numGroupsZ) override; GLuint numGroupsZ) override;
Renderer9 *getRenderer() const { return mRenderer; }
private: private:
Renderer9 *mRenderer; Renderer9 *mRenderer;
}; };
......
...@@ -1784,7 +1784,8 @@ gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode) ...@@ -1784,7 +1784,8 @@ gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode)
ANGLE_TRY(ensureHLSLCompilerInitialized()); ANGLE_TRY(ensureHLSLCompilerInitialized());
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(state.getProgram()); ProgramD3D *programD3D = GetImplAs<ProgramD3D>(state.getProgram());
programD3D->updateCachedInputLayout(state); VertexArray9 *vao = GetImplAs<VertexArray9>(state.getVertexArray());
programD3D->updateCachedInputLayout(vao->getCurrentStateSerial(), state);
const auto &inputLayout = programD3D->getCachedInputLayout(); const auto &inputLayout = programD3D->getCachedInputLayout();
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ #ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ #define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
#include "libANGLE/Context.h"
#include "libANGLE/renderer/VertexArrayImpl.h" #include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/d3d/d3d9/Context9.h"
#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
namespace rx namespace rx
...@@ -21,7 +23,19 @@ class VertexArray9 : public VertexArrayImpl ...@@ -21,7 +23,19 @@ class VertexArray9 : public VertexArrayImpl
public: public:
VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {} VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {}
virtual ~VertexArray9() { } void syncState(const gl::Context *context, const gl::VertexArray::DirtyBits &dirtyBits) override
{
ASSERT(dirtyBits.any());
Renderer9 *renderer = GetImplAs<Context9>(context)->getRenderer();
mCurrentStateSerial = renderer->generateSerial();
}
~VertexArray9() override {}
Serial getCurrentStateSerial() const { return mCurrentStateSerial; }
private:
Serial mCurrentStateSerial;
}; };
} }
......
...@@ -1696,6 +1696,9 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -1696,6 +1696,9 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_PROGRAM_BINDING: case gl::State::DIRTY_BIT_PROGRAM_BINDING:
// TODO(jmadill): implement this // TODO(jmadill): implement this
break; break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_MULTISAMPLING: case gl::State::DIRTY_BIT_MULTISAMPLING:
setMultisamplingStateEnabled(state.isMultisamplingEnabled()); setMultisamplingStateEnabled(state.isMultisamplingEnabled());
break; break;
......
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