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)
{
......
......@@ -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