Commit 81c2e253 by Jamie Madill Committed by Commit Bot

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/648053Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent ef97c613
......@@ -505,6 +505,7 @@ egl::Error Context::makeCurrent(egl::Display *display, egl::Surface *surface)
// TODO(jmadill): Rework this when we support ContextImpl
mGLState.setAllDirtyBits();
mGLState.setAllDirtyObjects();
ANGLE_TRY(releaseSurface(display));
......@@ -1723,24 +1724,28 @@ void Context::texParameterf(GLenum target, GLenum pname, GLfloat param)
{
Texture *texture = getTargetTexture(target);
SetTexParameterf(this, texture, pname, param);
onTextureChange(texture);
}
void Context::texParameterfv(GLenum target, GLenum pname, const GLfloat *params)
{
Texture *texture = getTargetTexture(target);
SetTexParameterfv(this, texture, pname, params);
onTextureChange(texture);
}
void Context::texParameteri(GLenum target, GLenum pname, GLint param)
{
Texture *texture = getTargetTexture(target);
SetTexParameteri(this, texture, pname, param);
onTextureChange(texture);
}
void Context::texParameteriv(GLenum target, GLenum pname, const GLint *params)
{
Texture *texture = getTargetTexture(target);
SetTexParameteriv(this, texture, pname, params);
onTextureChange(texture);
}
void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
......@@ -2521,12 +2526,12 @@ void Context::requestExtension(const char *name)
// Release the shader compiler so it will be re-created with the requested extensions enabled.
releaseShaderCompiler();
// Invalidate all cached completenesses for textures and framebuffer. Some extensions make new
// formats renderable or sampleable.
mState.mTextures->invalidateTextureComplenessCache();
// Invalidate all textures and framebuffer. Some extensions make new formats renderable or
// sampleable.
mState.mTextures->signalAllTexturesDirty();
for (auto &zeroTexture : mZeroTextures)
{
zeroTexture.second->invalidateCompletenessCache();
zeroTexture.second->signalDirty();
}
mState.mFramebuffers->invalidateFramebufferComplenessCache();
......@@ -4665,13 +4670,19 @@ void Context::uniform1fv(GLint location, GLsizei count, const GLfloat *v)
void Context::uniform1i(GLint location, GLint x)
{
Program *program = mGLState.getProgram();
program->setUniform1iv(location, 1, &x);
if (program->setUniform1iv(location, 1, &x) == Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
}
void Context::uniform1iv(GLint location, GLsizei count, const GLint *v)
{
Program *program = mGLState.getProgram();
program->setUniform1iv(location, count, v);
if (program->setUniform1iv(location, count, v) == Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
}
void Context::uniform2f(GLint location, GLfloat x, GLfloat y)
......@@ -5248,4 +5259,22 @@ void Context::getInternalformativ(GLenum target,
QueryInternalFormativ(formatCaps, pname, bufSize, params);
}
void Context::programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value)
{
Program *programObject = getProgram(program);
ASSERT(programObject);
if (programObject->setUniform1iv(location, count, value) ==
Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
}
void Context::onTextureChange(const Texture *texture)
{
// Conservatively assume all textures are dirty.
// TODO(jmadill): More fine-grained update.
mGLState.setObjectDirty(GL_TEXTURE);
}
} // namespace gl
......@@ -873,6 +873,8 @@ class Context final : public ValidationContext
GLsizei bufSize,
GLint *params);
void programUniform1iv(GLuint program, GLint location, GLsizei count, const GLint *value);
// Returns the error.
Error handleError(const Error &error) override;
......@@ -922,6 +924,9 @@ class Context final : public ValidationContext
GLsizei height,
GLsizei depth);
// Notification for a state change in a Texture.
void onTextureChange(const Texture *texture);
egl::Display *getCurrentDisplay() const { return mCurrentDisplay; }
egl::Surface *getCurrentDrawSurface() const { return mCurrentSurface; }
egl::Surface *getCurrentReadSurface() const { return mCurrentSurface; }
......
......@@ -123,10 +123,6 @@ class FramebufferState final : angle::NonCopyable
bool mWebGLDepthStencilConsistent;
};
using OnAttachmentDirtyBinding = angle::ChannelBinding<>;
using OnAttachmentDirtyChannel = angle::BroadcastChannel<>;
using OnAttachmentDirtyReceiver = angle::SignalReceiver<>;
class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
{
public:
......
......@@ -328,7 +328,7 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget(
return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut);
}
angle::BroadcastChannel<> *FramebufferAttachmentObject::getDirtyChannel()
OnAttachmentDirtyChannel *FramebufferAttachmentObject::getDirtyChannel()
{
return &mDirtyChannel;
}
......
......@@ -43,6 +43,10 @@ struct Format;
class Renderbuffer;
class Texture;
using OnAttachmentDirtyBinding = angle::ChannelBinding<>;
using OnAttachmentDirtyChannel = angle::BroadcastChannel<>;
using OnAttachmentDirtyReceiver = angle::SignalReceiver<>;
// FramebufferAttachment implements a GL framebuffer attachment.
// Attachments are "light" containers, which store pointers to ref-counted GL objects.
// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments.
......@@ -191,12 +195,12 @@ class FramebufferAttachmentObject
const ImageIndex &imageIndex,
rx::FramebufferAttachmentRenderTarget **rtOut) const;
angle::BroadcastChannel<> *getDirtyChannel();
OnAttachmentDirtyChannel *getDirtyChannel();
protected:
virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
angle::BroadcastChannel<> mDirtyChannel;
OnAttachmentDirtyChannel mDirtyChannel;
};
inline Extents FramebufferAttachment::getSize() const
......
......@@ -1360,17 +1360,20 @@ void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
mProgram->setUniform4fv(location, clampedCount, v);
}
void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
Program::SetUniformResult Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
{
const VariableLocation &locationInfo = mState.mUniformLocations[location];
GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
mProgram->setUniform1iv(location, clampedCount, v);
if (mState.isSamplerUniformIndex(locationInfo.index))
{
updateSamplerUniform(locationInfo, clampedCount, v);
return SetUniformResult::SamplerChanged;
}
mProgram->setUniform1iv(location, clampedCount, v);
return SetUniformResult::NoSamplerChange;
}
void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
......@@ -2966,15 +2969,13 @@ void Program::updateSamplerUniform(const VariableLocation &locationInfo,
const GLint *v)
{
// Invalidate the validation cache only if we modify the sampler data.
if (mState.isSamplerUniformIndex(locationInfo.index))
{
GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
std::vector<GLuint> *boundTextureUnits =
&mState.mSamplerBindings[samplerIndex].boundTextureUnits;
ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
std::vector<GLuint> *boundTextureUnits =
&mState.mSamplerBindings[samplerIndex].boundTextureUnits;
std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
mCachedValidateSamplersResult.reset();
}
std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.element);
mCachedValidateSamplersResult.reset();
}
template <typename T>
......
......@@ -438,13 +438,19 @@ class Program final : angle::NonCopyable, public LabeledObject
const std::vector<VariableLocation> &getUniformLocations() const;
const LinkedUniform &getUniformByIndex(GLuint index) const;
enum SetUniformResult
{
SamplerChanged,
NoSamplerChange,
};
GLint getUniformLocation(const std::string &name) const;
GLuint getUniformIndex(const std::string &name) const;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
void setUniform1iv(GLint location, GLsizei count, const GLint *v);
SetUniformResult setUniform1iv(GLint location, GLsizei count, const GLint *v);
void setUniform2iv(GLint location, GLsizei count, const GLint *v);
void setUniform3iv(GLint location, GLsizei count, const GLint *v);
void setUniform4iv(GLint location, GLsizei count, const GLint *v);
......
......@@ -240,13 +240,13 @@ Texture *TextureManager::getTexture(GLuint handle) const
return mObjectMap.query(handle);
}
void TextureManager::invalidateTextureComplenessCache() const
void TextureManager::signalAllTexturesDirty() const
{
for (const auto &texture : mObjectMap)
{
if (texture.second)
{
texture.second->invalidateCompletenessCache();
texture.second->signalDirty();
}
}
}
......
......@@ -154,7 +154,7 @@ class TextureManager : public TypedResourceManager<Texture, HandleAllocator, Tex
GLuint createTexture();
Texture *getTexture(GLuint handle) const;
void invalidateTextureComplenessCache() const;
void signalAllTexturesDirty() const;
Texture *checkTextureAllocation(rx::GLImplFactory *factory, GLuint handle, GLenum target)
{
......
......@@ -158,6 +158,13 @@ void State::initialize(const Context *context,
{
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 @@ unsigned int State::getActiveSampler() const
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 @@ void State::detachTexture(const Context *context, const TextureMap &zeroTextures
{
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::initializeZeroTextures(const Context *context, const TextureMap &zer
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 @@ void State::detachSampler(const Context *context, GLuint sampler)
// 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 @@ void State::setProgram(const Context *context, Program *newProgram)
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 @@ TransformFeedback *State::getCurrentTransformFeedback() const
bool State::isTransformFeedbackActiveUnpaused() const
{
gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
TransformFeedback *curTransformFeedback = getCurrentTransformFeedback();
return curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused();
}
......@@ -1825,7 +1837,7 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
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 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
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 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
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 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params)
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 @@ bool State::hasMappedBuffer(GLenum target) const
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 @@ void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
ASSERT(mVertexArray);
mVertexArray->syncImplState(context);
break;
case DIRTY_OBJECT_PROGRAM_TEXTURES:
syncProgramTextures(context);
break;
default:
UNREACHABLE();
break;
......@@ -2176,6 +2192,57 @@ void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
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 @@ void State::syncDirtyObject(const Context *context, GLenum target)
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 @@ void State::setObjectDirty(GLenum target)
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 @@ void State::onProgramExecutableChange(Program *program)
if (program->isLinked() && mProgram == program)
{
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
}
}
......@@ -2254,4 +2335,12 @@ const ImageUnit &State::getImageUnit(GLuint unit) const
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
......@@ -35,7 +35,7 @@ struct Caps;
typedef std::map<GLenum, BindingPointer<Texture>> TextureMap;
class State : angle::NonCopyable
class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
{
public:
State();
......@@ -423,6 +423,9 @@ class State : angle::NonCopyable
DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING,
DIRTY_BIT_PROGRAM_BINDING,
DIRTY_BIT_PROGRAM_EXECUTABLE,
// TODO(jmadill): Fine-grained dirty bits for each texture/sampler.
DIRTY_BIT_TEXTURE_BINDINGS,
DIRTY_BIT_SAMPLER_BINDINGS,
DIRTY_BIT_MULTISAMPLING,
DIRTY_BIT_SAMPLE_ALPHA_TO_ONE,
DIRTY_BIT_COVERAGE_MODULATION, // CHROMIUM_framebuffer_mixed_samples
......@@ -442,6 +445,9 @@ class State : angle::NonCopyable
DIRTY_OBJECT_READ_FRAMEBUFFER,
DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY,
// Use a very coarse bit for any program or texture change.
// TODO(jmadill): Fine-grained dirty bits for each texture/sampler.
DIRTY_OBJECT_PROGRAM_TEXTURES,
DIRTY_OBJECT_UNKNOWN,
DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
};
......@@ -470,8 +476,14 @@ class State : angle::NonCopyable
GLenum format);
const ImageUnit &getImageUnit(GLuint unit) const;
const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; }
// Handle a dirty texture event.
void signal(uint32_t textureIndex) override;
private:
void syncProgramTextures(const Context *context);
// Cached values from Context's caps
GLuint mMaxDrawBuffers;
GLuint mMaxCombinedTextureImageUnits;
......@@ -524,6 +536,12 @@ class State : angle::NonCopyable
typedef std::map<GLenum, TextureBindingVector> TextureBindingMap;
TextureBindingMap mSamplerTextures;
// A cache of complete textures. nullptr indicates unbound or incomplete.
// Don't use BindingPointer because this cache is only valid within a draw call.
// Also stores a notification channel to the texture itself to handle texture change events.
std::vector<Texture *> mCompleteTextureCache;
std::vector<OnAttachmentDirtyBinding> mCompleteTextureBindings;
typedef std::vector<BindingPointer<Sampler>> SamplerBindingVector;
SamplerBindingVector mSamplers;
......
......@@ -96,9 +96,7 @@ TextureState::TextureState(GLenum target)
mImmutableFormat(false),
mImmutableLevels(0),
mUsage(GL_NONE),
mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
(target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
mCompletenessCache()
mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1))
{
}
......@@ -157,19 +155,20 @@ bool TextureState::setBaseLevel(GLuint baseLevel)
if (mBaseLevel != baseLevel)
{
mBaseLevel = baseLevel;
invalidateCompletenessCache();
return true;
}
return false;
}
void TextureState::setMaxLevel(GLuint maxLevel)
bool TextureState::setMaxLevel(GLuint maxLevel)
{
if (mMaxLevel != maxLevel)
{
mMaxLevel = maxLevel;
invalidateCompletenessCache();
return true;
}
return false;
}
// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
......@@ -197,25 +196,6 @@ bool TextureState::isCubeComplete() const
return true;
}
bool TextureState::isSamplerComplete(const SamplerState &samplerState,
const ContextState &data) const
{
if (data.getContextID() != mCompletenessCache.context ||
mCompletenessCache.samplerState != samplerState)
{
mCompletenessCache.context = data.getContextID();
mCompletenessCache.samplerState = samplerState;
mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data);
}
return mCompletenessCache.samplerComplete;
}
void TextureState::invalidateCompletenessCache() const
{
mCompletenessCache.context = 0;
}
bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
const ContextState &data) const
{
......@@ -442,7 +422,6 @@ void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &de
size_t descIndex = GetImageDescIndex(target, level);
ASSERT(descIndex < mImageDescs.size());
mImageDescs[descIndex] = desc;
invalidateCompletenessCache();
}
const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
......@@ -500,12 +479,6 @@ void TextureState::clearImageDescs()
{
mImageDescs[descIndex] = ImageDesc();
}
invalidateCompletenessCache();
}
TextureState::SamplerCompletenessCache::SamplerCompletenessCache()
: context(0), samplerState(), samplerComplete(false)
{
}
Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target)
......@@ -742,6 +715,7 @@ Error Texture::setBaseLevel(const Context *context, GLuint baseLevel)
{
ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
invalidateCompletenessCache();
}
return NoError();
......@@ -754,8 +728,11 @@ GLuint Texture::getBaseLevel() const
void Texture::setMaxLevel(GLuint maxLevel)
{
mState.setMaxLevel(maxLevel);
mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
if (mState.setMaxLevel(maxLevel))
{
mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
invalidateCompletenessCache();
}
}
GLuint Texture::getMaxLevel() const
......@@ -868,10 +845,10 @@ egl::Stream *Texture::getBoundStream() const
return mBoundStream;
}
void Texture::invalidateCompletenessCache() const
void Texture::signalDirty() const
{
mState.invalidateCompletenessCache();
mDirtyChannel.signal();
invalidateCompletenessCache();
}
Error Texture::setImage(const Context *context,
......@@ -895,7 +872,7 @@ Error Texture::setImage(const Context *context,
unpackState, pixels));
mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type)));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -934,7 +911,7 @@ Error Texture::setCompressedImage(const Context *context,
unpackState, imageSize, pixels));
mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat)));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -975,7 +952,7 @@ Error Texture::copyImage(const Context *context,
GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
mState.setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
Format(internalFormatInfo)));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1018,7 +995,7 @@ Error Texture::copyTexture(const Context *context,
const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0);
const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
mState.setImageDesc(target, level, ImageDesc(sourceDesc.size, Format(internalFormatInfo)));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1083,7 +1060,7 @@ Error Texture::setStorage(const Context *context,
mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1110,7 +1087,7 @@ Error Texture::setStorageMultisample(const Context *context,
mState.setImageDescChainMultisample(size, Format(internalFormat), samples,
fixedSampleLocations);
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1140,7 +1117,7 @@ Error Texture::generateMipmap(const Context *context)
mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format);
}
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1162,7 +1139,7 @@ Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *sur
Extents size(surface->getWidth(), surface->getHeight(), 1);
ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat));
mState.setImageDesc(mState.mTarget, 0, desc);
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1175,7 +1152,7 @@ Error Texture::releaseTexImageFromSurface(const Context *context)
// Erase the image info for level 0
ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
mState.clearImageDesc(mState.mTarget, 0);
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1205,7 +1182,7 @@ Error Texture::acquireImageFromStream(const Context *context,
Extents size(desc.width, desc.height, 1);
mState.setImageDesc(mState.mTarget, 0, ImageDesc(size, Format(desc.internalFormat)));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1217,7 +1194,7 @@ Error Texture::releaseImageFromStream(const Context *context)
// Set to incomplete
mState.clearImageDesc(mState.mTarget, 0);
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1252,7 +1229,7 @@ Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Ima
mState.clearImageDescs();
mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat()));
mDirtyChannel.signal();
signalDirty();
return NoError();
}
......@@ -1297,4 +1274,33 @@ rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
{
return mTexture;
}
bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
{
const auto &samplerState =
optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
const auto &contextState = context->getContextState();
if (contextState.getContextID() != mCompletenessCache.context ||
mCompletenessCache.samplerState != samplerState)
{
mCompletenessCache.context = context->getContextState().getContextID();
mCompletenessCache.samplerState = samplerState;
mCompletenessCache.samplerComplete =
mState.computeSamplerCompleteness(samplerState, contextState);
}
return mCompletenessCache.samplerComplete;
}
Texture::SamplerCompletenessCache::SamplerCompletenessCache()
: context(0), samplerState(), samplerComplete(false)
{
}
void Texture::invalidateCompletenessCache() const
{
mCompletenessCache.context = 0;
}
} // namespace gl
......@@ -13,10 +13,11 @@
#include <map>
#include "angle_gl.h"
#include "common/Optional.h"
#include "common/debug.h"
#include "libANGLE/Caps.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Constants.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
......@@ -41,6 +42,7 @@ namespace gl
{
class ContextState;
class Framebuffer;
class Sampler;
class Texture;
bool IsMipmapFiltered(const SamplerState &samplerState);
......@@ -95,12 +97,9 @@ struct TextureState final : private angle::NonCopyable
// Returns true if base level changed.
bool setBaseLevel(GLuint baseLevel);
void setMaxLevel(GLuint maxLevel);
bool setMaxLevel(GLuint maxLevel);
bool isCubeComplete() const;
bool isSamplerComplete(const SamplerState &samplerState, const ContextState &data) const;
void invalidateCompletenessCache() const;
const ImageDesc &getImageDesc(GLenum target, size_t level) const;
const ImageDesc &getImageDesc(const ImageIndex &imageIndex) const;
......@@ -156,22 +155,6 @@ struct TextureState final : private angle::NonCopyable
std::vector<ImageDesc> mImageDescs;
struct SamplerCompletenessCache
{
SamplerCompletenessCache();
// Context used to generate this cache entry
ContextID context;
// All values that affect sampler completeness that are not stored within
// the texture itself
SamplerState samplerState;
// Result of the sampler completeness with the above parameters
bool samplerComplete;
};
mutable SamplerCompletenessCache mCompletenessCache;
};
bool operator==(const TextureState &a, const TextureState &b);
......@@ -358,7 +341,9 @@ class Texture final : public egl::ImageSibling,
egl::Surface *getBoundSurface() const;
egl::Stream *getBoundStream() const;
void invalidateCompletenessCache() const;
void signalDirty() const;
bool isSamplerComplete(const Context *context, const Sampler *optionalSampler);
rx::TextureImpl *getImplementation() const { return mTexture; }
......@@ -421,6 +406,8 @@ class Texture final : public egl::ImageSibling,
const egl::Stream::GLTextureDescription &desc);
Error releaseImageFromStream(const Context *context);
void invalidateCompletenessCache() const;
TextureState mState;
DirtyBits mDirtyBits;
rx::TextureImpl *mTexture;
......@@ -431,6 +418,23 @@ class Texture final : public egl::ImageSibling,
egl::Surface *mBoundSurface;
egl::Stream *mBoundStream;
struct SamplerCompletenessCache
{
SamplerCompletenessCache();
// Context used to generate this cache entry
ContextID context;
// All values that affect sampler completeness that are not stored within
// the texture itself
SamplerState samplerState;
// Result of the sampler completeness with the above parameters
bool samplerComplete;
};
mutable SamplerCompletenessCache mCompletenessCache;
};
inline bool operator==(const TextureState &a, const TextureState &b)
......
......@@ -427,6 +427,7 @@ inline GLenum FramebufferBindingToEnum(FramebufferBinding binding)
namespace gl
{
class ContextState;
} // namespace gl
#endif // LIBANGLE_ANGLETYPES_H_
......@@ -1729,6 +1729,8 @@ gl::Error StateManager11::applyTextures(const gl::Context *context,
// TODO(jmadill): Use the Program's sampler bindings.
const auto &completeTextures = glState.getCompleteTextureCache();
unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{
......@@ -1736,20 +1738,18 @@ gl::Error StateManager11::applyTextures(const gl::Context *context,
GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps);
if (textureUnit != -1)
{
gl::Texture *texture = glState.getSamplerTexture(textureUnit, textureType);
ASSERT(texture);
gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
gl::Texture *texture = completeTextures[textureUnit];
// TODO: std::binary_search may become unavailable using older versions of GCC
if (texture->getTextureState().isSamplerComplete(samplerState,
context->getContextState()) &&
// A nullptr texture indicates incomplete.
if (texture &&
!std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture))
{
gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
ANGLE_TRY(
setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture));
......
......@@ -3258,6 +3258,8 @@ gl::Error Renderer9::applyTextures(const gl::Context *context,
// TODO(jmadill): Use the Program's sampler bindings.
const auto &completeTextures = glState.getCompleteTextureCache();
unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{
......@@ -3265,20 +3267,18 @@ gl::Error Renderer9::applyTextures(const gl::Context *context,
GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps);
if (textureUnit != -1)
{
gl::Texture *texture = glState.getSamplerTexture(textureUnit, textureType);
ASSERT(texture);
gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
gl::Texture *texture = completeTextures[textureUnit];
// TODO: std::binary_search may become unavailable using older versions of GCC
if (texture->getTextureState().isSamplerComplete(samplerState,
context->getContextState()) &&
// A nullptr texture indicates incomplete.
if (texture &&
!std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture))
{
gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
ANGLE_TRY(
setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture));
......
......@@ -871,31 +871,28 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context)
}
}
for (const gl::SamplerBinding &samplerUniform : program->getSamplerBindings())
const auto &completeTextures = glState.getCompleteTextureCache();
for (const gl::SamplerBinding &samplerBinding : program->getSamplerBindings())
{
GLenum textureType = samplerUniform.textureType;
for (GLuint textureUnitIndex : samplerUniform.boundTextureUnits)
{
gl::Texture *texture = glState.getSamplerTexture(textureUnitIndex, textureType);
const gl::Sampler *sampler = glState.getSampler(textureUnitIndex);
if (samplerBinding.unreferenced)
continue;
const gl::SamplerState &samplerState =
sampler ? sampler->getSamplerState() : texture->getSamplerState();
GLenum textureType = samplerBinding.textureType;
for (GLuint textureUnitIndex : samplerBinding.boundTextureUnits)
{
gl::Texture *texture = completeTextures[textureUnitIndex];
if (texture != nullptr && texture->getTextureState().isSamplerComplete(
samplerState, context->getContextState()))
// A nullptr texture indicates incomplete.
if (texture != nullptr)
{
const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
ASSERT(!texture->hasAnyDirtyBit());
ASSERT(!textureGL->hasAnyDirtyBit());
if (mTextures.at(textureType)[textureUnitIndex] != textureGL->getTextureID() ||
texture->hasAnyDirtyBit() || textureGL->hasAnyDirtyBit())
if (mTextures.at(textureType)[textureUnitIndex] != textureGL->getTextureID())
{
activeTexture(textureUnitIndex);
bindTexture(textureType, textureGL->getTextureID());
// TODO: Call this from the gl:: layer once other backends use dirty bits for
// texture state.
texture->syncImplState();
}
}
else
......@@ -907,6 +904,7 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context)
}
}
const gl::Sampler *sampler = glState.getSampler(textureUnitIndex);
if (sampler != nullptr)
{
const SamplerGL *samplerGL = GetImplAs<SamplerGL>(sampler);
......@@ -1906,6 +1904,12 @@ 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_TEXTURE_BINDINGS:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
propagateNumViewsToVAO(state.getProgram(),
GetImplAs<VertexArrayGL>(state.getVertexArray()));
......
......@@ -435,9 +435,7 @@ void GL_APIENTRY ProgramUniform1iv(GLuint program,
return;
}
Program *programObject = context->getProgram(program);
ASSERT(programObject);
programObject->setUniform1iv(location, count, value);
context->programUniform1iv(program, location, count, value);
}
}
......
......@@ -7,6 +7,7 @@
#include "test_utils/ANGLETest.h"
#include <vector>
#include "test_utils/gl_raii.h"
using namespace angle;
......@@ -86,42 +87,44 @@ class IncompleteTextureTest : public ANGLETest
TEST_P(IncompleteTextureTest, IncompleteTexture2D)
{
GLuint tex;
glGenTextures(1, &tex);
GLTexture tex;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUseProgram(mProgram);
glUniform1i(mTextureUniformLocation, 0);
const GLsizei textureWidth = 2;
const GLsizei textureHeight = 2;
std::vector<GLubyte> textureData(textureWidth * textureHeight * 4);
fillTextureData(textureData, 255, 0, 0, 255);
constexpr GLsizei kTextureSize = 2;
std::vector<GLColor> textureData(kTextureSize * kTextureSize, GLColor::red);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &textureData[0]);
// Make a complete texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Should be complete - expect red.
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Make texture incomplete.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Should be incomplete - expect black.
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 255);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, textureWidth >> 1, textureHeight >> 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &textureData[0]);
// Make texture complete by defining the second mip.
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, kTextureSize >> 1, kTextureSize >> 1, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData.data());
// Should be complete - expect red.
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
glDeleteTextures(1, &tex);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
TEST_P(IncompleteTextureTest, UpdateTexture)
{
GLuint tex;
glGenTextures(1, &tex);
GLTexture tex;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
......@@ -158,8 +161,6 @@ TEST_P(IncompleteTextureTest, UpdateTexture)
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(getWindowWidth() - greenTextureWidth, getWindowHeight() - greenTextureWidth, 0, 255, 0, 255);
glDeleteTextures(1, &tex);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
......
......@@ -305,15 +305,13 @@ TEST_P(SixteenBppTextureTest, RGBA4444Validation)
// Test uploading RGBA8 data to RGBA4 textures.
TEST_P(SixteenBppTextureTestES3, RGBA4UploadRGBA8)
{
std::vector<GLColor> fourColors;
fourColors.push_back(GLColor::red);
fourColors.push_back(GLColor::green);
fourColors.push_back(GLColor::blue);
fourColors.push_back(GLColor::yellow);
const std::array<GLColor, 4> kFourColors = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, fourColors.data());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
kFourColors.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
......
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