D3D11: Update cached dynamically recompiled programs.
This change makes it so that when we need to recompile a program on a
draw call, we also update the cache. It also streamlines the internal
queries of the dynamic vertex and fragment shaders such that we only
update the input and output signatures a single time per draw. This
should also facilitate dirty bit implementations for the D3D11 back-
end.
BUG=angleproject:2116
Change-Id: Iccb0501b700bc894f40a8c68d7f297ff0c8f46bd
Reviewed-on: https://chromium-review.googlesource.com/531798
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 98efef9..2e7ec29 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1837,14 +1837,14 @@
void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawArrays(this, mode, first, count));
MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback());
}
void Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount));
MarkTransformFeedbackBufferUsage(mGLState.getCurrentTransformFeedback());
@@ -1852,7 +1852,7 @@
void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawElements(this, mode, count, type, indices));
}
@@ -1862,7 +1862,7 @@
const void *indices,
GLsizei instances)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawElementsInstanced(this, mode, count, type, indices, instances));
}
@@ -1874,20 +1874,20 @@
GLenum type,
const void *indices)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(
mImplementation->drawRangeElements(this, mode, start, end, count, type, indices));
}
void Context::drawArraysIndirect(GLenum mode, const void *indirect)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawArraysIndirect(this, mode, indirect));
}
void Context::drawElementsIndirect(GLenum mode, GLenum type, const void *indirect)
{
- ANGLE_CONTEXT_TRY(prepareForDraw());
+ ANGLE_CONTEXT_TRY(prepareForDraw(mode));
ANGLE_CONTEXT_TRY(mImplementation->drawElementsIndirect(this, mode, type, indirect));
}
@@ -2170,7 +2170,7 @@
return QueryProgramResourceLocation(programObject, programInterface, name);
}
-void Context::handleError(const Error &error)
+Error Context::handleError(const Error &error)
{
if (error.isError())
{
@@ -2188,6 +2188,8 @@
GL_DEBUG_SEVERITY_HIGH, error.getMessage());
}
}
+
+ return error;
}
// Get one of the recorded errors and clear its flag, if any.
@@ -2820,10 +2822,18 @@
mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
}
-Error Context::prepareForDraw()
+Error Context::prepareForDraw(GLenum drawMode)
{
syncRendererState();
- return NoError();
+
+ InfoLog infoLog;
+ Error err = mImplementation->triggerDrawCallProgramRecompilation(this, &infoLog,
+ mMemoryProgramCache, drawMode);
+ if (err.isError())
+ {
+ WARN() << "Dynamic recompilation error log: " << infoLog.str();
+ }
+ return err;
}
void Context::syncRendererState()
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index a4f32cd..4daf1ee 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -779,7 +779,8 @@
void *binary);
void programBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
- void handleError(const Error &error) override;
+ // Returns the error.
+ Error handleError(const Error &error) override;
GLenum getError();
void markContextLost();
@@ -832,7 +833,7 @@
egl::Surface *getCurrentReadSurface() const { return mCurrentSurface; }
private:
- Error prepareForDraw();
+ Error prepareForDraw(GLenum drawMode);
void syncRendererState();
void syncRendererState(const State::DirtyBits &bitMask, const State::DirtyObjects &objectMask);
void syncStateForReadPixels();
diff --git a/src/libANGLE/ContextState.h b/src/libANGLE/ContextState.h
index 6f6a167..fb95d67 100644
--- a/src/libANGLE/ContextState.h
+++ b/src/libANGLE/ContextState.h
@@ -100,7 +100,7 @@
bool skipValidation);
virtual ~ValidationContext() {}
- virtual void handleError(const Error &error) = 0;
+ virtual Error handleError(const Error &error) = 0;
const ContextState &getContextState() const { return mState; }
GLint getClientMajorVersion() const { return mState.getClientMajorVersion(); }
diff --git a/src/libANGLE/MemoryProgramCache.cpp b/src/libANGLE/MemoryProgramCache.cpp
index 1a93cd8..e34a18a 100644
--- a/src/libANGLE/MemoryProgramCache.cpp
+++ b/src/libANGLE/MemoryProgramCache.cpp
@@ -585,6 +585,13 @@
put(programHash, std::move(binaryProgram));
}
+void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
+{
+ gl::ProgramHash programHash;
+ ComputeHash(context, program, &programHash);
+ putProgram(programHash, context, program);
+}
+
void MemoryProgramCache::putBinary(const ProgramHash &programHash,
const uint8_t *binary,
size_t length)
diff --git a/src/libANGLE/MemoryProgramCache.h b/src/libANGLE/MemoryProgramCache.h
index 039561b..e1166e8 100644
--- a/src/libANGLE/MemoryProgramCache.h
+++ b/src/libANGLE/MemoryProgramCache.h
@@ -82,6 +82,9 @@
// Helper method that serializes a program.
void putProgram(const ProgramHash &programHash, const Context *context, const Program *program);
+ // Same as putProgram but computes the hash.
+ void updateProgram(const Context *context, const Program *program);
+
// Store a binary directly.
void putBinary(const ProgramHash &programHash, const uint8_t *binary, size_t length);
diff --git a/src/libANGLE/renderer/ContextImpl.h b/src/libANGLE/renderer/ContextImpl.h
index b6233c4..406796e 100644
--- a/src/libANGLE/renderer/ContextImpl.h
+++ b/src/libANGLE/renderer/ContextImpl.h
@@ -18,6 +18,7 @@
namespace gl
{
+class MemoryProgramCache;
class Path;
struct Workarounds;
}
@@ -155,6 +156,18 @@
GLuint numGroupsY,
GLuint numGroupsZ) = 0;
+ // This does not correspond to a GL API, but matches a common GL driver behaviour where
+ // draw call states can trigger dynamic shader recompilation. We pass the Program cache
+ // handle as a mutable pointer to this Impl method to both trigger dynamic recompilations
+ // and to allow the back-end to store the refreshed shaders in the cache.
+ virtual gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context,
+ gl::InfoLog *infoLog,
+ gl::MemoryProgramCache *memoryCache,
+ GLenum drawMode)
+ {
+ return gl::NoError();
+ }
+
const gl::ContextState &getContextState() { return mState; }
int getClientMajorVersion() const { return mState.getClientMajorVersion(); }
int getClientMinorVersion() const { return mState.getClientMinorVersion(); }
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 38f7cf9..b7bb3d1 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -34,10 +34,12 @@
namespace
{
-gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Context *context,
- gl::Shader *vertexShader)
+void GetDefaultInputLayoutFromShader(const gl::Context *context,
+ gl::Shader *vertexShader,
+ gl::InputLayout *inputLayoutOut)
{
- gl::InputLayout defaultLayout;
+ inputLayoutOut->clear();
+
for (const sh::Attribute &shaderAttr : vertexShader->getActiveAttributes(context))
{
if (shaderAttr.type != GL_NONE)
@@ -53,26 +55,48 @@
gl::VertexFormatType defaultType =
gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt);
- defaultLayout.push_back(defaultType);
+ inputLayoutOut->push_back(defaultType);
}
}
}
-
- return defaultLayout;
}
-std::vector<GLenum> GetDefaultOutputLayoutFromShader(
- const std::vector<PixelShaderOutputVariable> &shaderOutputVars)
+void GetDefaultOutputLayoutFromShader(
+ const std::vector<PixelShaderOutputVariable> &shaderOutputVars,
+ std::vector<GLenum> *outputLayoutOut)
{
- std::vector<GLenum> defaultPixelOutput;
+ outputLayoutOut->clear();
if (!shaderOutputVars.empty())
{
- defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 +
- static_cast<unsigned int>(shaderOutputVars[0].outputIndex));
+ outputLayoutOut->push_back(GL_COLOR_ATTACHMENT0 +
+ static_cast<unsigned int>(shaderOutputVars[0].outputIndex));
}
+}
- return defaultPixelOutput;
+void GetPixelOutputLayoutFromFramebuffer(const gl::Context *context,
+ const gl::Framebuffer *framebuffer,
+ std::vector<GLenum> *signature)
+{
+ signature->clear();
+
+ FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(framebuffer);
+ const auto &colorbuffers = fboD3D->getColorAttachmentsForRender(context);
+
+ for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
+ {
+ const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
+
+ if (colorbuffer)
+ {
+ signature->push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0
+ : colorbuffer->getBinding());
+ }
+ else
+ {
+ signature->push_back(GL_NONE);
+ }
+ }
}
bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
@@ -1133,49 +1157,20 @@
{
}
-gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Context *context,
- const gl::Framebuffer *fbo,
- ShaderExecutableD3D **outExecutable)
-{
- mPixelShaderOutputFormatCache.clear();
-
- FramebufferD3D *fboD3D = GetImplAs<FramebufferD3D>(fbo);
- const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(context);
-
- for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
- {
- const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
-
- if (colorbuffer)
- {
- mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK
- ? GL_COLOR_ATTACHMENT0
- : colorbuffer->getBinding());
- }
- else
- {
- mPixelShaderOutputFormatCache.push_back(GL_NONE);
- }
- }
-
- return getPixelExecutableForOutputLayout(mPixelShaderOutputFormatCache, outExecutable, nullptr);
-}
-
-gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature,
- ShaderExecutableD3D **outExectuable,
- gl::InfoLog *infoLog)
+gl::Error ProgramD3D::getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExecutable,
+ gl::InfoLog *infoLog)
{
for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
{
- if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
+ if (mPixelExecutables[executableIndex]->matchesSignature(mPixelShaderOutputLayoutCache))
{
- *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable();
+ *outExecutable = mPixelExecutables[executableIndex]->shaderExecutable();
return gl::NoError();
}
}
std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(
- mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature);
+ mPixelHLSL, mPixelShaderKey, mUsesFragDepth, mPixelShaderOutputLayoutCache);
// Generate new pixel executable
ShaderExecutableD3D *pixelExecutable = nullptr;
@@ -1191,7 +1186,7 @@
if (pixelExecutable)
{
mPixelExecutables.push_back(std::unique_ptr<PixelExecutable>(
- new PixelExecutable(outputSignature, pixelExecutable)));
+ new PixelExecutable(mPixelShaderOutputLayoutCache, pixelExecutable)));
}
else if (!infoLog)
{
@@ -1199,16 +1194,13 @@
<< tempInfoLog.str() << std::endl;
}
- *outExectuable = pixelExecutable;
+ *outExecutable = pixelExecutable;
return gl::NoError();
}
-gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout,
- ShaderExecutableD3D **outExectuable,
- gl::InfoLog *infoLog)
+gl::Error ProgramD3D::getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable,
+ gl::InfoLog *infoLog)
{
- VertexExecutable::getSignature(mRenderer, inputLayout, &mCachedVertexSignature);
-
for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
{
if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature))
@@ -1220,7 +1212,7 @@
// Generate new dynamic layout with attribute conversions
std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(
- mVertexHLSL, inputLayout, mState.getAttributes());
+ mVertexHLSL, mCachedInputLayout, mState.getAttributes());
// Generate new vertex executable
ShaderExecutableD3D *vertexExecutable = nullptr;
@@ -1236,7 +1228,7 @@
if (vertexExecutable)
{
mVertexExecutables.push_back(std::unique_ptr<VertexExecutable>(
- new VertexExecutable(inputLayout, mCachedVertexSignature, vertexExecutable)));
+ new VertexExecutable(mCachedInputLayout, mCachedVertexSignature, vertexExecutable)));
}
else if (!infoLog)
{
@@ -1338,11 +1330,9 @@
}
gl::Error run() override
{
- const auto &defaultInputLayout =
- GetDefaultInputLayoutFromShader(mContext, mProgram->mState.getAttachedVertexShader());
+ mProgram->updateCachedInputLayoutFromShader(mContext);
- ANGLE_TRY(
- mProgram->getVertexExecutableForInputLayout(defaultInputLayout, &mResult, &mInfoLog));
+ ANGLE_TRY(mProgram->getVertexExecutableForCachedInputLayout(&mResult, &mInfoLog));
return gl::NoError();
}
@@ -1351,22 +1341,31 @@
const gl::Context *mContext;
};
+void ProgramD3D::updateCachedInputLayoutFromShader(const gl::Context *context)
+{
+ GetDefaultInputLayoutFromShader(context, mState.getAttachedVertexShader(), &mCachedInputLayout);
+ VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature);
+}
+
class ProgramD3D::GetPixelExecutableTask : public ProgramD3D::GetExecutableTask
{
public:
GetPixelExecutableTask(ProgramD3D *program) : GetExecutableTask(program) {}
gl::Error run() override
{
- const auto &defaultPixelOutput =
- GetDefaultOutputLayoutFromShader(mProgram->getPixelShaderKey());
+ mProgram->updateCachedOutputLayoutFromShader();
- ANGLE_TRY(
- mProgram->getPixelExecutableForOutputLayout(defaultPixelOutput, &mResult, &mInfoLog));
+ ANGLE_TRY(mProgram->getPixelExecutableForCachedOutputLayout(&mResult, &mInfoLog));
return gl::NoError();
}
};
+void ProgramD3D::updateCachedOutputLayoutFromShader()
+{
+ GetDefaultOutputLayoutFromShader(mPixelShaderKey, &mPixelShaderOutputLayoutCache);
+}
+
class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTask
{
public:
@@ -2415,6 +2414,14 @@
state.getVertexAttribCurrentValue(locationIndex).Type);
}
}
+
+ VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature);
+}
+
+void ProgramD3D::updateCachedOutputLayout(const gl::Context *context,
+ const gl::Framebuffer *framebuffer)
+{
+ GetPixelOutputLayoutFromFramebuffer(context, framebuffer, &mPixelShaderOutputLayoutCache);
}
void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyingPacking,
@@ -2527,4 +2534,44 @@
UNREACHABLE();
}
+bool ProgramD3D::hasVertexExecutableForCachedInputLayout()
+{
+ VertexExecutable::getSignature(mRenderer, mCachedInputLayout, &mCachedVertexSignature);
+
+ for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
+ {
+ if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProgramD3D::hasGeometryExecutableForPrimitiveType(GLenum drawMode)
+{
+ if (!usesGeometryShader(drawMode))
+ {
+ // No shader necessary mean we have the required (null) executable.
+ return true;
+ }
+
+ gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
+ return mGeometryExecutables[geometryShaderType].get() != nullptr;
+}
+
+bool ProgramD3D::hasPixelExecutableForCachedOutputLayout()
+{
+ for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
+ {
+ if (mPixelExecutables[executableIndex]->matchesSignature(mPixelShaderOutputLayoutCache))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index d638d37..a570f8e 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -165,19 +165,14 @@
void setBinaryRetrievableHint(bool retrievable) override;
void setSeparable(bool separable) override;
- gl::Error getPixelExecutableForFramebuffer(const gl::Context *context,
- const gl::Framebuffer *fbo,
- ShaderExecutableD3D **outExectuable);
- gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout,
- ShaderExecutableD3D **outExectuable,
- gl::InfoLog *infoLog);
- gl::Error getVertexExecutableForInputLayout(const gl::InputLayout &inputLayout,
- ShaderExecutableD3D **outExectuable,
- gl::InfoLog *infoLog);
+ gl::Error getVertexExecutableForCachedInputLayout(ShaderExecutableD3D **outExectuable,
+ gl::InfoLog *infoLog);
gl::Error getGeometryExecutableForPrimitiveType(const gl::ContextState &data,
GLenum drawMode,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
+ gl::Error getPixelExecutableForCachedOutputLayout(ShaderExecutableD3D **outExectuable,
+ gl::InfoLog *infoLog);
gl::Error getComputeExecutable(ShaderExecutableD3D **outExecutable);
gl::LinkResult link(const gl::Context *context,
const gl::VaryingPacking &packing,
@@ -261,10 +256,15 @@
}
void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
- const gl::InputLayout &getCachedInputLayout() const { return mCachedInputLayout; }
+ void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer);
bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
+ // Checks if we need to recompile certain shaders.
+ bool hasVertexExecutableForCachedInputLayout();
+ bool hasGeometryExecutableForPrimitiveType(GLenum drawMode);
+ bool hasPixelExecutableForCachedOutputLayout();
+
private:
// These forward-declared tasks are used for multi-thread shader compiles.
class GetExecutableTask;
@@ -381,6 +381,9 @@
void initUniformBlockInfo(const gl::Context *context, gl::Shader *shader);
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
+ void updateCachedInputLayoutFromShader(const gl::Context *context);
+ void updateCachedOutputLayoutFromShader();
+
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
@@ -417,8 +420,8 @@
GLuint mUsedComputeSamplerRange;
bool mDirtySamplerMapping;
- // Cache for getPixelExecutableForFramebuffer
- std::vector<GLenum> mPixelShaderOutputFormatCache;
+ // Cache for pixel shader output layout to save reallocations.
+ std::vector<GLenum> mPixelShaderOutputLayoutCache;
AttribIndexArray mAttribLocationToD3DSemantic;
@@ -441,6 +444,6 @@
Serial mCurrentVertexArrayStateSerial;
};
-}
+} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
index fc2fcb9..b726c6c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -10,6 +10,8 @@
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "common/string_utils.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/MemoryProgramCache.h"
#include "libANGLE/renderer/d3d/CompilerD3D.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/RenderbufferD3D.h"
@@ -294,4 +296,58 @@
return mRenderer->dispatchCompute(context, numGroupsX, numGroupsY, numGroupsZ);
}
+gl::Error Context11::triggerDrawCallProgramRecompilation(const gl::Context *context,
+ gl::InfoLog *infoLog,
+ gl::MemoryProgramCache *memoryCache,
+ GLenum drawMode)
+{
+ const auto &glState = context->getGLState();
+ const auto *va11 = GetImplAs<VertexArray11>(glState.getVertexArray());
+ const auto *drawFBO = glState.getDrawFramebuffer();
+ gl::Program *program = glState.getProgram();
+ ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
+
+ programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
+ programD3D->updateCachedOutputLayout(context, drawFBO);
+
+ bool recompileVS = !programD3D->hasVertexExecutableForCachedInputLayout();
+ bool recompileGS = !programD3D->hasGeometryExecutableForPrimitiveType(drawMode);
+ bool recompilePS = !programD3D->hasPixelExecutableForCachedOutputLayout();
+
+ if (!recompileVS && !recompileGS && !recompilePS)
+ {
+ return gl::NoError();
+ }
+
+ // Load the compiler if necessary and recompile the programs.
+ ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized());
+
+ if (recompileVS)
+ {
+ ShaderExecutableD3D *vertexExe = nullptr;
+ ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, infoLog));
+ }
+
+ if (recompileGS)
+ {
+ ShaderExecutableD3D *geometryExe = nullptr;
+ ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(
+ context->getContextState(), drawMode, &geometryExe, infoLog));
+ }
+
+ if (recompilePS)
+ {
+ ShaderExecutableD3D *pixelExe = nullptr;
+ ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, infoLog));
+ }
+
+ // Refresh the program cache entry.
+ if (memoryCache)
+ {
+ memoryCache->updateProgram(context, program);
+ }
+
+ return gl::NoError();
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/libANGLE/renderer/d3d/d3d11/Context11.h
index 3e70486..110f5cc 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.h
@@ -135,6 +135,11 @@
GLuint numGroupsY,
GLuint numGroupsZ) override;
+ gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context,
+ gl::InfoLog *infoLog,
+ gl::MemoryProgramCache *memoryCache,
+ GLenum drawMode) override;
+
private:
Renderer11 *mRenderer;
};
diff --git a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
index 1064f86..64d8382 100644
--- a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -35,19 +35,6 @@
return usesPointSpriteEmulation ? 1 : 0;
}
-gl::InputLayout GetInputLayout(const std::vector<const TranslatedAttribute *> &translatedAttributes)
-{
- gl::InputLayout inputLayout(translatedAttributes.size(), gl::VERTEX_FORMAT_INVALID);
-
- for (size_t attributeIndex = 0; attributeIndex < translatedAttributes.size(); ++attributeIndex)
- {
- const TranslatedAttribute *translatedAttribute = translatedAttributes[attributeIndex];
- inputLayout[attributeIndex] = gl::GetVertexFormatType(
- *translatedAttribute->attribute, translatedAttribute->currentValueType);
- }
- return inputLayout;
-}
-
GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes, size_t index)
{
// Count matrices differently
@@ -547,10 +534,8 @@
inputElementCount++;
}
- const gl::InputLayout &shaderInputLayout = GetInputLayout(mCurrentAttributes);
-
ShaderExecutableD3D *shader = nullptr;
- ANGLE_TRY(programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr));
+ ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&shader, nullptr));
ShaderExecutableD3D *shader11 = GetAs<ShaderExecutable11>(shader);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 30367e2..48a3d12 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1709,8 +1709,7 @@
}
rx::ShaderExecutableD3D *pixelExe = nullptr;
- ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(
- context, glState.getDrawFramebuffer(), &pixelExe));
+ ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
// Skip the draw call if rasterizer discard is enabled (or no fragment shader).
if (!pixelExe || glState.getRasterizerState().rasterizerDiscard)
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 02ca154..51c9832 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -1737,23 +1737,22 @@
gl::Error StateManager11::syncProgram(const gl::Context *context, GLenum drawMode)
{
- // This method is called single-threaded.
- ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized());
-
const auto &glState = context->getGLState();
- const auto *va11 = GetImplAs<VertexArray11>(glState.getVertexArray());
+ const auto *va11 = GetImplAs<VertexArray11>(glState.getVertexArray());
+ auto *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
- ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
- const auto &inputLayout = programD3D->getCachedInputLayout();
+ // Binaries must be compiled before the sync.
+ ASSERT(programD3D->hasVertexExecutableForCachedInputLayout());
+ ASSERT(programD3D->hasGeometryExecutableForPrimitiveType(drawMode));
+ ASSERT(programD3D->hasPixelExecutableForCachedOutputLayout());
ShaderExecutableD3D *vertexExe = nullptr;
- ANGLE_TRY(programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr));
+ ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr));
- const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
- ShaderExecutableD3D *pixelExe = nullptr;
- ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(context, drawFramebuffer, &pixelExe));
+ ShaderExecutableD3D *pixelExe = nullptr;
+ ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
ShaderExecutableD3D *geometryExe = nullptr;
ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context->getContextState(),
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 59cc15e..9a1b27a 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -1796,14 +1796,14 @@
VertexArray9 *vao = GetImplAs<VertexArray9>(state.getVertexArray());
programD3D->updateCachedInputLayout(vao->getCurrentStateSerial(), state);
- const auto &inputLayout = programD3D->getCachedInputLayout();
-
ShaderExecutableD3D *vertexExe = nullptr;
- ANGLE_TRY(programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr));
+ ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr));
const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer();
- ShaderExecutableD3D *pixelExe = nullptr;
- ANGLE_TRY(programD3D->getPixelExecutableForFramebuffer(context, drawFramebuffer, &pixelExe));
+ programD3D->updateCachedOutputLayout(context, drawFramebuffer);
+
+ ShaderExecutableD3D *pixelExe = nullptr;
+ ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
IDirect3DVertexShader9 *vertexShader =
(vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr);
diff --git a/src/libANGLE/validationES_unittest.cpp b/src/libANGLE/validationES_unittest.cpp
index 49f6e30..d0e601c 100644
--- a/src/libANGLE/validationES_unittest.cpp
+++ b/src/libANGLE/validationES_unittest.cpp
@@ -52,7 +52,7 @@
{
}
- MOCK_METHOD1(handleError, void(const Error &));
+ MOCK_METHOD1(handleError, Error(const Error &));
};
// Test that ANGLE generates an INVALID_OPERATION when validating index data that uses a value