Generate pixel shader output to match the bound framebuffer.
Only generate pixel shader output variables for render targets that are
currently bound. Fixes some performance issues with D3D10 cards that were
slow to discard unused outputs.
Fixed memory leaks in ProgramBinary by refactoring the freeing of the
current state into a reset function.
BUG=angle:670
Change-Id: I40f83e15724fb9a1a9ae61363a056999f1fa26d2
Reviewed-on: https://chromium-review.googlesource.com/202977
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index e3ffa47..63ca3f6 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -10,6 +10,8 @@
#include "libGLESv2/BinaryStream.h"
#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
#include "libGLESv2/renderer/ShaderExecutable.h"
#include "common/debug.h"
@@ -84,8 +86,7 @@
{
}
-ProgramBinary::VertexExecutable::VertexExecutable(rx::Renderer *const renderer,
- const VertexFormat inputLayout[],
+ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[],
const GLenum signature[],
rx::ShaderExecutable *shaderExecutable)
: mShaderExecutable(shaderExecutable)
@@ -99,7 +100,7 @@
ProgramBinary::VertexExecutable::~VertexExecutable()
{
- delete mShaderExecutable;
+ SafeDelete(mShaderExecutable);
}
bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
@@ -115,6 +116,17 @@
return true;
}
+ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable)
+ : mOutputSignature(outputSignature),
+ mShaderExecutable(shaderExecutable)
+{
+}
+
+ProgramBinary::PixelExecutable::~PixelExecutable()
+{
+ SafeDelete(mShaderExecutable);
+}
+
LinkedVarying::LinkedVarying()
{
}
@@ -132,7 +144,7 @@
mRenderer(renderer),
mDynamicHLSL(NULL),
mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
- mPixelExecutable(NULL),
+ mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
mGeometryExecutable(NULL),
mUsedVertexSamplerRange(0),
mUsedPixelSamplerRange(0),
@@ -163,29 +175,7 @@
ProgramBinary::~ProgramBinary()
{
- while (!mVertexExecutables.empty())
- {
- delete mVertexExecutables.back();
- mVertexExecutables.pop_back();
- }
-
- SafeDelete(mGeometryExecutable);
- SafeDelete(mPixelExecutable);
-
- while (!mUniforms.empty())
- {
- delete mUniforms.back();
- mUniforms.pop_back();
- }
-
- while (!mUniformBlocks.empty())
- {
- delete mUniformBlocks.back();
- mUniformBlocks.pop_back();
- }
-
- SafeDelete(mVertexUniformStorage);
- SafeDelete(mFragmentUniformStorage);
+ reset();
SafeDelete(mDynamicHLSL);
}
@@ -204,9 +194,58 @@
return mCurrentSerial++;
}
-rx::ShaderExecutable *ProgramBinary::getPixelExecutable() const
+rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo)
{
- return mPixelExecutable;
+ std::vector<GLenum> outputs(IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ for (size_t i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
+ {
+ FramebufferAttachment *attachment = fbo->getColorbuffer(i);
+ if (attachment)
+ {
+ // Always output floats for now
+ outputs[i] = GL_FLOAT;
+ }
+ else
+ {
+ outputs[i] = GL_NONE;
+ }
+ }
+
+ return getPixelExecutableForOutputLayout(outputs);
+}
+
+rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
+{
+ for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
+ {
+ if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
+ {
+ return mPixelExecutables[executableIndex]->shaderExecutable();
+ }
+ }
+
+ std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
+ outputSignature);
+
+ // Generate new pixel executable
+ InfoLog tempInfoLog;
+ rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+ mPixelWorkarounds);
+
+ if (!pixelExecutable)
+ {
+ std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
+ tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+ ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
+ }
+ else
+ {
+ mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
+ }
+
+ return pixelExecutable;
}
rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
@@ -223,16 +262,11 @@
}
// Generate new dynamic layout with attribute conversions
- const std::string &layoutHLSL = mDynamicHLSL->generateInputLayoutHLSL(inputLayout, mShaderAttributes);
-
- // Generate new shader source by replacing the attributes stub with the defined input layout
- std::string vertexHLSL = mVertexHLSL;
- size_t insertPos = vertexHLSL.find(DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING);
- vertexHLSL.replace(insertPos, DynamicHLSL::VERTEX_ATTRIBUTE_STUB_STRING.length(), layoutHLSL);
+ std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes);
// Generate new vertex executable
InfoLog tempInfoLog;
- rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, vertexHLSL.c_str(),
+ rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL.c_str(),
rx::SHADER_VERTEX,
mTransformFeedbackLinkedVaryings,
(mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
@@ -246,7 +280,7 @@
}
else
{
- mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, signature, vertexExecutable));
+ mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
}
return vertexExecutable;
@@ -1021,6 +1055,8 @@
#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
return false;
#else
+ reset();
+
BinaryInputStream stream(binary, length);
int format = stream.readInt<int>();
@@ -1180,7 +1216,6 @@
stream.readInt(&mVertexWorkarounds);
const unsigned int vertexShaderCount = stream.readInt<unsigned int>();
-
for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
{
VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
@@ -1195,9 +1230,7 @@
}
unsigned int vertexShaderSize = stream.readInt<unsigned int>();
-
- const char *vertexShaderFunction = (const char*) binary + stream.offset();
-
+ const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
vertexShaderSize, rx::SHADER_VERTEX,
mTransformFeedbackLinkedVaryings,
@@ -1213,23 +1246,52 @@
mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
// add new binary
- mVertexExecutables.push_back(new VertexExecutable(mRenderer, inputLayout, signature, shaderExecutable));
+ mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
stream.skip(vertexShaderSize);
}
- unsigned int pixelShaderSize = stream.readInt<unsigned int>();
+ stream.readString(&mPixelHLSL);
+ stream.readInt(&mPixelWorkarounds);
+ stream.readBool(&mUsesFragDepth);
- const char *pixelShaderFunction = (const char*) binary + stream.offset();
- mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
- pixelShaderSize, rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
- if (!mPixelExecutable)
+ const size_t pixelShaderKeySize = stream.readInt<unsigned int>();
+ mPixelShaderKey.resize(pixelShaderKeySize);
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++)
{
- infoLog.append("Could not create pixel shader.");
- return false;
+ stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].type);
+ stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].name);
+ stream.readString(&mPixelShaderKey[pixelShaderKeyIndex].source);
+ stream.readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
}
- stream.skip(pixelShaderSize);
+
+ const size_t pixelShaderCount = stream.readInt<unsigned int>();
+ for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
+ {
+ const size_t outputCount = stream.readInt<unsigned int>();
+ std::vector<GLenum> outputs(outputCount);
+ for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
+ {
+ stream.readInt(&outputs[outputIndex]);
+ }
+
+ const size_t pixelShaderSize = stream.readInt<unsigned int>();
+ const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
+ rx::ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize,
+ rx::SHADER_PIXEL,
+ mTransformFeedbackLinkedVaryings,
+ (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+ if (!shaderExecutable)
+ {
+ infoLog.append("Could not create pixel shader.");
+ return false;
+ }
+
+ // add new binary
+ mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
+
+ stream.skip(pixelShaderSize);
+ }
unsigned int geometryShaderSize = stream.readInt<unsigned int>();
@@ -1242,7 +1304,6 @@
if (!mGeometryExecutable)
{
infoLog.append("Could not create geometry shader.");
- SafeDelete(mPixelExecutable);
return false;
}
stream.skip(geometryShaderSize);
@@ -1391,11 +1452,38 @@
stream.writeBytes(vertexBlob, vertexShaderSize);
}
- size_t pixelShaderSize = mPixelExecutable->getLength();
- stream.writeInt(pixelShaderSize);
+ stream.writeString(mPixelHLSL);
+ stream.writeInt(mPixelWorkarounds);
+ stream.writeInt(mUsesFragDepth);
- unsigned char *pixelBlob = static_cast<unsigned char *>(mPixelExecutable->getFunction());
- stream.writeBytes(pixelBlob, pixelShaderSize);
+ stream.writeInt(mPixelShaderKey.size());
+ for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < mPixelShaderKey.size(); pixelShaderKeyIndex++)
+ {
+ const PixelShaderOuputVariable &variable = mPixelShaderKey[pixelShaderKeyIndex];
+ stream.writeInt(variable.type);
+ stream.writeString(variable.name);
+ stream.writeString(variable.source);
+ stream.writeInt(variable.outputIndex);
+ }
+
+ stream.writeInt(mPixelExecutables.size());
+ for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
+ {
+ PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
+
+ const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
+ stream.writeInt(outputs.size());
+ for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
+ {
+ stream.writeInt(outputs[outputIndex]);
+ }
+
+ size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
+ stream.writeInt(pixelShaderSize);
+
+ unsigned char *pixelBlob = static_cast<unsigned char *>(pixelExecutable->shaderExecutable()->getFunction());
+ stream.writeBytes(pixelBlob, pixelShaderSize);
+ }
size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
stream.writeInt(geometryShaderSize);
@@ -1469,12 +1557,15 @@
return false;
}
- mTransformFeedbackLinkedVaryings.clear();
+ reset();
+
mTransformFeedbackBufferMode = transformFeedbackBufferMode;
mShaderVersion = vertexShader->getShaderVersion();
- std::string pixelHLSL = fragmentShader->getHLSL();
+ mPixelHLSL = fragmentShader->getHLSL();
+ mPixelWorkarounds = fragmentShader->getD3DWorkarounds();
+
mVertexHLSL = vertexShader->getHLSL();
mVertexWorkarounds = vertexShader->getD3DWorkarounds();
@@ -1494,9 +1585,9 @@
mUsesPointSize = vertexShader->usesPointSize();
std::vector<LinkedVarying> linkedVaryings;
- if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, pixelHLSL, mVertexHLSL,
+ if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, registers, packing, mPixelHLSL, mVertexHLSL,
fragmentShader, vertexShader, transformFeedbackVaryings,
- &linkedVaryings, &mOutputVariables))
+ &linkedVaryings, &mOutputVariables, &mPixelShaderKey, &mUsesFragDepth))
{
return false;
}
@@ -1536,12 +1627,14 @@
{
VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
GetInputLayoutFromShader(vertexShader->activeAttributes(), defaultInputLayout);
-
rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
- mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL,
- mTransformFeedbackLinkedVaryings,
- (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
- fragmentShader->getD3DWorkarounds());
+
+ std::vector<GLenum> defaultPixelOutput(IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ for (size_t i = 0; i < defaultPixelOutput.size(); i++)
+ {
+ defaultPixelOutput[i] = (i == 0) ? GL_FLOAT : GL_NONE;
+ }
+ rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
if (usesGeometryShader())
{
@@ -1552,21 +1645,11 @@
rx::ANGLE_D3D_WORKAROUND_NONE);
}
- if (!defaultVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
+ if (!defaultVertexExecutable || !defaultPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
{
infoLog.append("Failed to create D3D shaders.");
success = false;
-
- while (!mVertexExecutables.empty())
- {
- delete mVertexExecutables.back();
- mVertexExecutables.pop_back();
- }
-
- SafeDelete(mGeometryExecutable);
- SafeDelete(mPixelExecutable);
-
- mTransformFeedbackLinkedVaryings.clear();
+ reset();
}
}
@@ -2688,4 +2771,44 @@
mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u);
}
+void ProgramBinary::reset()
+{
+ mVertexHLSL.clear();
+ mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+ SafeDeleteContainer(mVertexExecutables);
+
+ mPixelHLSL.clear();
+ mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+ mUsesFragDepth = false;
+ mPixelShaderKey.clear();
+ SafeDeleteContainer(mPixelExecutables);
+
+ SafeDelete(mGeometryExecutable);
+
+ mTransformFeedbackBufferMode = GL_NONE;
+ mTransformFeedbackLinkedVaryings.clear();
+
+ for (size_t i = 0; i < ArraySize(mSamplersPS); i++)
+ {
+ mSamplersPS[i] = Sampler();
+ }
+ for (size_t i = 0; i < ArraySize(mSamplersVS); i++)
+ {
+ mSamplersVS[i] = Sampler();
+ }
+ mUsedVertexSamplerRange = 0;
+ mUsedPixelSamplerRange = 0;
+ mUsesPointSize = false;
+ mShaderVersion = 0;
+
+ SafeDeleteContainer(mUniforms);
+ SafeDeleteContainer(mUniformBlocks);
+ mUniformIndex.clear();
+ mOutputVariables.clear();
+ SafeDelete(mVertexUniformStorage);
+ SafeDelete(mFragmentUniformStorage);
+
+ mValidated = false;
+}
+
}