Add top-level dirty bits for texture and samplers.
These will have to be fleshed out in the back-ends.
Also currently uses a single bit for all the bindings, and we can
extend this to more fine-grained updates in the future.
This patch implements top-level updates for texture completeness.
Sampler completeness caches are removed from the Texture class, and
replaced by a cache in the gl::State class. The State class also
keeps a channel binding to the bound textures so it can be notified
when textures might change from complete <-> incomplete.
In future CLs we skip updating back-ends if texture state doesn't
change.
BUG=angleproject:1387
Change-Id: If580b4851303c86f3240e62891f5f6047eefb6a2
Reviewed-on: https://chromium-review.googlesource.com/648053
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 017a054..2d4b07a 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -158,6 +158,13 @@
{
mSamplerTextures[GL_TEXTURE_EXTERNAL_OES].resize(caps.maxCombinedTextureImageUnits);
}
+ mCompleteTextureCache.resize(caps.maxCombinedTextureImageUnits, nullptr);
+ mCompleteTextureBindings.reserve(caps.maxCombinedTextureImageUnits);
+ for (uint32_t textureIndex = 0; textureIndex < caps.maxCombinedTextureImageUnits;
+ ++textureIndex)
+ {
+ mCompleteTextureBindings.emplace_back(OnAttachmentDirtyBinding(this, textureIndex));
+ }
mSamplers.resize(caps.maxCombinedTextureImageUnits);
@@ -764,6 +771,8 @@
void State::setSamplerTexture(const Context *context, GLenum type, Texture *texture)
{
mSamplerTextures[type][mActiveSampler].set(context, texture);
+ mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
}
Texture *State::getTargetTexture(GLenum target) const
@@ -802,15 +811,15 @@
{
GLenum textureType = bindingVec.first;
TextureBindingVector &textureVector = bindingVec.second;
- for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++)
+ for (BindingPointer<Texture> &binding : textureVector)
{
- BindingPointer<Texture> &binding = textureVector[textureIdx];
if (binding.id() == texture)
{
auto it = zeroTextures.find(textureType);
ASSERT(it != zeroTextures.end());
// Zero textures are the "default" textures instead of NULL
binding.set(context, it->second.get());
+ mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
}
}
}
@@ -861,6 +870,8 @@
void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sampler *sampler)
{
mSamplers[textureUnit].set(context, sampler);
+ mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS);
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
}
GLuint State::getSamplerId(GLuint textureUnit) const
@@ -880,12 +891,12 @@
// If a sampler object that is currently bound to one or more texture units is
// deleted, it is as though BindSampler is called once for each texture unit to
// which the sampler is bound, with unit set to the texture unit and sampler set to zero.
- for (size_t textureUnit = 0; textureUnit < mSamplers.size(); textureUnit++)
+ for (BindingPointer<Sampler> &samplerBinding : mSamplers)
{
- BindingPointer<Sampler> &samplerBinding = mSamplers[textureUnit];
if (samplerBinding.id() == sampler)
{
samplerBinding.set(context, nullptr);
+ mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS);
}
}
}
@@ -1107,6 +1118,7 @@
if (mProgram)
{
newProgram->addRef();
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
}
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING);
@@ -1131,7 +1143,7 @@
bool State::isTransformFeedbackActiveUnpaused() const
{
- gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
+ TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
return curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused();
}
@@ -1825,7 +1837,7 @@
case GL_SAMPLE_BUFFERS:
case GL_SAMPLES:
{
- gl::Framebuffer *framebuffer = mDrawFramebuffer;
+ Framebuffer *framebuffer = mDrawFramebuffer;
if (framebuffer->checkStatus(context) == GL_FRAMEBUFFER_COMPLETE)
{
switch (pname)
@@ -1870,8 +1882,8 @@
case GL_BLUE_BITS:
case GL_ALPHA_BITS:
{
- gl::Framebuffer *framebuffer = getDrawFramebuffer();
- const gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer();
+ Framebuffer *framebuffer = getDrawFramebuffer();
+ const FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer();
if (colorbuffer)
{
@@ -1891,8 +1903,8 @@
break;
case GL_DEPTH_BITS:
{
- const gl::Framebuffer *framebuffer = getDrawFramebuffer();
- const gl::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer();
+ const Framebuffer *framebuffer = getDrawFramebuffer();
+ const FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer();
if (depthbuffer)
{
@@ -1906,8 +1918,8 @@
break;
case GL_STENCIL_BITS:
{
- const gl::Framebuffer *framebuffer = getDrawFramebuffer();
- const gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer();
+ const Framebuffer *framebuffer = getDrawFramebuffer();
+ const FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer();
if (stencilbuffer)
{
@@ -2124,7 +2136,7 @@
size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
for (size_t attribIndex = 0; attribIndex < maxEnabledAttrib; attribIndex++)
{
- const gl::VertexAttribute &vertexAttrib = vertexAttribs[attribIndex];
+ const VertexAttribute &vertexAttrib = vertexAttribs[attribIndex];
auto *boundBuffer = vertexBindings[vertexAttrib.bindingIndex].getBuffer().get();
if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped())
{
@@ -2167,6 +2179,10 @@
ASSERT(mVertexArray);
mVertexArray->syncImplState(context);
break;
+ case DIRTY_OBJECT_PROGRAM_TEXTURES:
+ syncProgramTextures(context);
+ break;
+
default:
UNREACHABLE();
break;
@@ -2176,6 +2192,57 @@
mDirtyObjects &= ~bitset;
}
+void State::syncProgramTextures(const Context *context)
+{
+ std::fill(mCompleteTextureCache.begin(), mCompleteTextureCache.end(), nullptr);
+ for (auto &binding : mCompleteTextureBindings)
+ {
+ binding.reset();
+ }
+
+ // TODO(jmadill): Fine-grained updates.
+ if (!mProgram)
+ {
+ return;
+ }
+
+ ASSERT(mDirtyObjects[DIRTY_OBJECT_PROGRAM_TEXTURES]);
+ mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
+
+ for (const SamplerBinding &samplerBinding : mProgram->getSamplerBindings())
+ {
+ if (samplerBinding.unreferenced)
+ continue;
+
+ GLenum textureType = samplerBinding.textureType;
+ for (GLuint textureUnitIndex : samplerBinding.boundTextureUnits)
+ {
+ Texture *texture = getSamplerTexture(textureUnitIndex, textureType);
+
+ if (texture != nullptr)
+ {
+ const Sampler *sampler = getSampler(textureUnitIndex);
+
+ // Mark the texture binding bit as dirty if the texture completeness changes.
+ // TODO(jmadill): Use specific dirty bit for completeness change.
+ if (texture->isSamplerComplete(context, sampler))
+ {
+ texture->syncImplState();
+ ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size());
+ ASSERT(mCompleteTextureCache[textureUnitIndex] == nullptr ||
+ mCompleteTextureCache[textureUnitIndex] == texture);
+ mCompleteTextureCache[textureUnitIndex] = texture;
+ }
+
+ // Bind the texture unconditionally, to recieve completeness change notifications.
+ mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel());
+ }
+
+ // TODO(jmadill): Sync sampler state.
+ }
+ }
+}
+
void State::syncDirtyObject(const Context *context, GLenum target)
{
DirtyObjects localSet;
@@ -2195,6 +2262,11 @@
case GL_VERTEX_ARRAY:
localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
break;
+ case GL_TEXTURE:
+ case GL_SAMPLER:
+ case GL_PROGRAM:
+ localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+ break;
}
syncDirtyObjects(context, localSet);
@@ -2217,6 +2289,14 @@
case GL_VERTEX_ARRAY:
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
break;
+ case GL_TEXTURE:
+ case GL_SAMPLER:
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+ break;
+ case GL_PROGRAM:
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+ mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
+ break;
}
}
@@ -2229,6 +2309,7 @@
if (program->isLinked() && mProgram == program)
{
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
}
}
@@ -2254,4 +2335,12 @@
return mImageUnits[unit];
}
+// Handle a dirty texture event.
+void State::signal(uint32_t textureIndex)
+{
+ // Conservatively assume all textures are dirty.
+ // TODO(jmadill): More fine-grained update.
+ mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+}
+
} // namespace gl