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)
Program *programObject = getProgram(program);
ASSERT(programObject);
handleError(programObject->link(this));
mGLState.onProgramExecutableChange(programObject);
}
void Context::releaseShaderCompiler()
......@@ -4843,8 +4844,8 @@ void Context::programBinary(GLuint program, GLenum binaryFormat, const void *bin
{
Program *programObject = getProgram(program);
ASSERT(programObject != nullptr);
handleError(programObject->loadBinary(this, binaryFormat, binary, length));
mGLState.onProgramExecutableChange(programObject);
}
} // namespace gl
......@@ -1102,6 +1102,8 @@ void State::setProgram(const Context *context, Program *newProgram)
{
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)
ASSERT(mVertexArray);
mVertexArray->syncImplState(context);
break;
case DIRTY_OBJECT_PROGRAM:
// TODO(jmadill): implement this
break;
default:
UNREACHABLE();
break;
......@@ -2185,9 +2184,6 @@ void State::syncDirtyObject(const Context *context, GLenum target)
case GL_VERTEX_ARRAY:
localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
break;
case GL_PROGRAM:
localSet.set(DIRTY_OBJECT_PROGRAM);
break;
}
syncDirtyObjects(context, localSet);
......@@ -2210,9 +2206,18 @@ void State::setObjectDirty(GLenum target)
case GL_VERTEX_ARRAY:
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
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
bool hasMappedBuffer(GLenum target) const;
bool isRobustResourceInitEnabled() const { return mRobustResourceInit; }
// Sets the dirty bit for the program executable.
void onProgramExecutableChange(Program *program);
enum DirtyBitType
{
DIRTY_BIT_SCISSOR_TEST_ENABLED,
......@@ -419,6 +422,7 @@ class State : angle::NonCopyable
DIRTY_BIT_VERTEX_ARRAY_BINDING,
DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING,
DIRTY_BIT_PROGRAM_BINDING,
DIRTY_BIT_PROGRAM_EXECUTABLE,
DIRTY_BIT_MULTISAMPLING,
DIRTY_BIT_SAMPLE_ALPHA_TO_ONE,
DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples
......@@ -438,7 +442,6 @@ class State : angle::NonCopyable
DIRTY_OBJECT_READ_FRAMEBUFFER,
DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY,
DIRTY_OBJECT_PROGRAM,
DIRTY_OBJECT_UNKNOWN,
DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
};
......
......@@ -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();
const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
......
......@@ -260,7 +260,7 @@ class ProgramD3D : public ProgramImpl
return mAttribLocationToD3DSemantic;
}
void updateCachedInputLayout(const gl::State &state);
void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; }
bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
......@@ -438,6 +438,8 @@ class ProgramD3D : public ProgramImpl
static unsigned int issueSerial();
static unsigned int mCurrentSerial;
Serial mCurrentVertexArrayStateSerial;
};
}
......
......@@ -288,6 +288,11 @@ bool RendererD3D::isRobustResourceInitEnabled() const
return mDisplay->isRobustResourceInitEnabled();
}
Serial RendererD3D::generateSerial()
{
return mSerialFactory.generate();
}
unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
{
unsigned int mask = 0;
......
......@@ -21,6 +21,7 @@
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/formatutilsD3D.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "platform/WorkaroundsD3D.h"
namespace egl
......@@ -327,6 +328,8 @@ class RendererD3D : public BufferFactoryD3D
gl::Texture *getIncompleteTexture(const gl::Context *context, GLenum type);
Serial generateSerial();
protected:
virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual void generateCaps(gl::Caps *outCaps,
......@@ -365,6 +368,8 @@ class RendererD3D : public BufferFactoryD3D
bool mDeviceLost;
angle::WorkerThreadPool mWorkerThreadPool;
SerialFactory mSerialFactory;
};
unsigned int GetBlendSampleMask(const gl::State &glState, int samples);
......
......@@ -19,6 +19,7 @@
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLe/renderer/d3d/d3d11/VertexArray11.h"
namespace rx
{
......@@ -284,6 +285,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mDirtyCurrentValueAttribs(),
mCurrentValueAttribs(),
mCurrentInputLayout(),
mInputLayoutIsDirty(false),
mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0),
mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)
{
......@@ -620,6 +622,10 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
invalidateRenderTarget(context);
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
invalidateVertexBuffer();
invalidateRenderTarget(context);
break;
default:
if (dirtyBit >= gl::State::DIRTY_BIT_CURRENT_VALUE_0 &&
dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX)
......@@ -997,6 +1003,7 @@ void StateManager11::invalidateVertexBuffer()
unsigned int limit = std::min<unsigned int>(mRenderer->getNativeCaps().maxVertexAttributes,
gl::MAX_VERTEX_ATTRIBS);
mDirtyVertexBufferRange = gl::RangeUI(0, limit);
mInputLayoutIsDirty = true;
}
void StateManager11::setOneTimeRenderTarget(const gl::Context *context,
......@@ -1733,9 +1740,11 @@ gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMod
// This method is called single-threaded.
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->updateCachedInputLayout(glState);
programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
const auto &inputLayout = programD3D->getCachedInputLayout();
......
......@@ -303,6 +303,7 @@ class StateManager11 final : angle::NonCopyable
// Current applied input layout.
ResourceSerial mCurrentInputLayout;
bool mInputLayoutIsDirty;
// Current applied vertex states.
// TODO(jmadill): Figure out how to use ResourceSerial here.
......
......@@ -45,6 +45,16 @@ void VertexArray11::destroy(const gl::Context *context)
void VertexArray11::syncState(const gl::Context *context,
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)
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
......
......@@ -40,6 +40,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
// SignalReceiver implementation
void signal(size_t channelID) override;
Serial getCurrentStateSerial() const { return mCurrentStateSerial; }
private:
void updateVertexAttribStorage(const gl::Context *context, size_t attribIndex);
void flushAttribUpdates(const gl::Context *context);
......@@ -60,6 +62,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
std::vector<gl::BindingPointer<gl::Buffer>> mCurrentBuffers;
std::vector<OnBufferDataDirtyBinding> mOnBufferDataDirty;
Serial mCurrentStateSerial;
};
} // namespace rx
......
......@@ -136,6 +136,8 @@ class Context9 : public ContextImpl
GLuint numGroupsY,
GLuint numGroupsZ) override;
Renderer9 *getRenderer() const { return mRenderer; }
private:
Renderer9 *mRenderer;
};
......
......@@ -1784,7 +1784,8 @@ gl::Error Renderer9::applyShaders(const gl::Context *context, GLenum drawMode)
ANGLE_TRY(ensureHLSLCompilerInitialized());
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();
......
......@@ -9,7 +9,9 @@
#ifndef 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/d3d/d3d9/Context9.h"
#include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
namespace rx
......@@ -21,7 +23,19 @@ class VertexArray9 : public VertexArrayImpl
public:
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
case gl::State::DIRTY_BIT_PROGRAM_BINDING:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_MULTISAMPLING:
setMultisamplingStateEnabled(state.isMultisamplingEnabled());
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