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