Commit e25b8006 by Jamie Madill Committed by Commit Bot

Move sampler sync out of syncProgramTextures.

We only need to call the syncState for samplers when they are dirty. Also includes changes to refactor out the sampler sync in GL. Adds observer bindings so sampler sync is handled correctly in resource sharing scenarios. Bug: angleproject:2763 Change-Id: I762f0738ee7572ae29ce6bd5384a30aa9588c848 Reviewed-on: https://chromium-review.googlesource.com/1227797Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent a977acc8
......@@ -306,7 +306,9 @@ enum SubjectIndexes : angle::SubjectIndex
kUniformBuffer0SubjectIndex = kTextureMaxSubjectIndex,
kUniformBufferMaxSubjectIndex =
kUniformBuffer0SubjectIndex + gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
kVertexArraySubjectIndex = kUniformBufferMaxSubjectIndex,
kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex,
kSamplerMaxSubjectIndex = kSampler0SubjectIndex + gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
kVertexArraySubjectIndex = kSamplerMaxSubjectIndex,
kReadFramebufferSubjectIndex,
kDrawFramebufferSubjectIndex
};
......@@ -376,6 +378,12 @@ Context::Context(rx::EGLImplFactory *implFactory,
{
mUniformBufferObserverBindings.emplace_back(this, uboIndex);
}
for (angle::SubjectIndex samplerIndex = kSampler0SubjectIndex;
samplerIndex < kSamplerMaxSubjectIndex; ++samplerIndex)
{
mSamplerObserverBindings.emplace_back(this, samplerIndex);
}
}
void Context::initialize()
......@@ -480,10 +488,12 @@ void Context::initialize()
mDrawDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_TEXTURES);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_TEXTURES);
mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_STATE);
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_BUFFER_BINDING);
......@@ -528,6 +538,7 @@ void Context::initialize()
mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_TEXTURES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_SAMPLERS);
mImplementation->setErrorSet(&mErrors);
......@@ -1150,6 +1161,7 @@ void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle)
Sampler *sampler =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), samplerHandle);
mGLState.setSamplerBinding(this, textureUnit, sampler);
mSamplerObserverBindings[textureUnit].bind(sampler);
}
void Context::bindImageTexture(GLuint unit,
......@@ -2835,16 +2847,14 @@ void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
{
Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameteri(samplerObject, pname, param);
mGLState.setObjectDirty(GL_SAMPLER);
SetSamplerParameteri(this, samplerObject, pname, param);
}
void Context::samplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
{
Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameteriv(samplerObject, pname, param);
mGLState.setObjectDirty(GL_SAMPLER);
SetSamplerParameteriv(this, samplerObject, pname, param);
}
void Context::samplerParameterivRobust(GLuint sampler,
......@@ -2875,16 +2885,14 @@ void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
{
Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterf(samplerObject, pname, param);
mGLState.setObjectDirty(GL_SAMPLER);
SetSamplerParameterf(this, samplerObject, pname, param);
}
void Context::samplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
{
Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
SetSamplerParameterfv(samplerObject, pname, param);
mGLState.setObjectDirty(GL_SAMPLER);
SetSamplerParameterfv(this, samplerObject, pname, param);
}
void Context::samplerParameterfvRobust(GLuint sampler,
......@@ -2900,7 +2908,6 @@ void Context::getSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
const Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameteriv(samplerObject, pname, params);
mGLState.setObjectDirty(GL_SAMPLER);
}
void Context::getSamplerParameterivRobust(GLuint sampler,
......@@ -2935,7 +2942,6 @@ void Context::getSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *param
const Sampler *samplerObject =
mState.mSamplers->checkSamplerAllocation(mImplementation.get(), sampler);
QuerySamplerParameterfv(samplerObject, pname, params);
mGLState.setObjectDirty(GL_SAMPLER);
}
void Context::getSamplerParameterfvRobust(GLuint sampler,
......@@ -7752,12 +7758,16 @@ void Context::onSubjectStateChange(const Context *context,
mGLState.onActiveTextureStateChange(index);
mStateCache.onActiveTextureChange(this);
}
else
else if (index < kUniformBufferMaxSubjectIndex)
{
ASSERT(index < kUniformBufferMaxSubjectIndex);
mGLState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
mStateCache.onUniformBufferStateChange(this);
}
else
{
ASSERT(index < kSamplerMaxSubjectIndex);
mGLState.setSamplerDirty(index - kSampler0SubjectIndex);
}
break;
}
}
......
......@@ -1766,6 +1766,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::ObserverBinding mDrawFramebufferObserverBinding;
angle::ObserverBinding mReadFramebufferObserverBinding;
std::vector<angle::ObserverBinding> mUniformBufferObserverBindings;
std::vector<angle::ObserverBinding> mSamplerObserverBindings;
// Not really a property of context state. The size and contexts change per-api-call.
mutable angle::ScratchBuffer mScratchBuffer;
......
......@@ -10,9 +10,10 @@
#ifndef LIBANGLE_SAMPLER_H_
#define LIBANGLE_SAMPLER_H_
#include "libANGLE/angletypes.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Observer.h"
#include "libANGLE/RefCountObject.h"
#include "libANGLE/angletypes.h"
namespace rx
{
......@@ -23,7 +24,7 @@ class SamplerImpl;
namespace gl
{
class Sampler final : public RefCountObject, public LabeledObject
class Sampler final : public RefCountObject, public LabeledObject, public angle::Subject
{
public:
Sampler(rx::GLImplFactory *factory, GLuint id);
......
......@@ -1112,6 +1112,8 @@ void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sample
mSamplers[textureUnit].set(context, sampler);
mDirtyBits.set(DIRTY_BIT_SAMPLER_BINDINGS);
mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
// This is overly conservative as it assumes the sampler has never been bound.
setSamplerDirty(textureUnit);
}
GLuint State::getSamplerId(GLuint textureUnit) const
......@@ -2679,6 +2681,9 @@ Error State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset
ASSERT(mVertexArray);
ANGLE_TRY(mVertexArray->syncState(context));
break;
case DIRTY_OBJECT_SAMPLERS:
syncSamplers(context);
break;
case DIRTY_OBJECT_PROGRAM_TEXTURES:
ANGLE_TRY(syncProgramTextures(context));
break;
......@@ -2696,6 +2701,24 @@ Error State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset
return NoError();
}
void State::syncSamplers(const Context *context)
{
if (mDirtySamplers.none())
return;
// This could be optimized by tracking which samplers are dirty.
for (size_t samplerIndex : mDirtySamplers)
{
BindingPointer<Sampler> &sampler = mSamplers[samplerIndex];
if (sampler.get())
{
sampler->syncState(context);
}
}
mDirtySamplers.reset();
}
Error State::syncProgramTextures(const Context *context)
{
// TODO(jmadill): Fine-grained updates.
......@@ -2732,7 +2755,8 @@ Error State::syncProgramTextures(const Context *context)
// 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) &&
!mDrawFramebuffer->hasTextureAttachment(texture))
(mProgram->hasLinkedShaderStage(ShaderType::Compute) ||
!mDrawFramebuffer->hasTextureAttachment(texture)))
{
ANGLE_TRY(texture->syncState(context));
mActiveTexturesCache[textureUnitIndex] = texture;
......@@ -2746,11 +2770,6 @@ Error State::syncProgramTextures(const Context *context)
mCompleteTextureBindings[textureUnitIndex].bind(texture->getSubject());
newActiveTextures.set(textureUnitIndex);
if (sampler != nullptr)
{
sampler->syncState(context);
}
if (texture->initState() == InitState::MayNeedInit)
{
mCachedTexturesInitState = InitState::MayNeedInit;
......@@ -2808,8 +2827,11 @@ Error State::syncDirtyObject(const Context *context, GLenum target)
localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
break;
case GL_TEXTURE:
localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
break;
case GL_SAMPLER:
localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
localSet.set(DIRTY_OBJECT_SAMPLERS);
break;
case GL_PROGRAM:
localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
......@@ -2838,7 +2860,6 @@ void State::setObjectDirty(GLenum target)
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
break;
case GL_TEXTURE:
case GL_SAMPLER:
mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
break;
......@@ -2864,6 +2885,12 @@ void State::onProgramExecutableChange(Program *program)
}
}
void State::setSamplerDirty(size_t samplerIndex)
{
mDirtyObjects.set(DIRTY_OBJECT_SAMPLERS);
mDirtySamplers.set(samplerIndex);
}
void State::setImageUnit(const Context *context,
size_t unit,
Texture *texture,
......
......@@ -193,6 +193,9 @@ class State : angle::NonCopyable
Sampler *getSampler(GLuint textureUnit) const { return mSamplers[textureUnit].get(); }
using SamplerBindingVector = std::vector<BindingPointer<Sampler>>;
const SamplerBindingVector &getSamplers() const { return mSamplers; }
void detachSampler(const Context *context, GLuint sampler);
// Renderbuffer binding manipulation
......@@ -441,6 +444,7 @@ class State : angle::NonCopyable
DIRTY_OBJECT_READ_FRAMEBUFFER,
DIRTY_OBJECT_DRAW_FRAMEBUFFER,
DIRTY_OBJECT_VERTEX_ARRAY,
DIRTY_OBJECT_SAMPLERS,
// 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,
......@@ -461,6 +465,7 @@ class State : angle::NonCopyable
Error syncDirtyObjects(const Context *context, const DirtyObjects &bitset);
Error syncDirtyObject(const Context *context, GLenum target);
void setObjectDirty(GLenum target);
void setSamplerDirty(size_t samplerIndex);
// This actually clears the current value dirty bits.
// TODO(jmadill): Pass mutable dirty bits into Impl.
......@@ -492,6 +497,7 @@ class State : angle::NonCopyable
const GLES1State &gles1() const { return mGLES1State; }
private:
void syncSamplers(const Context *context);
Error syncProgramTextures(const Context *context);
// Cached values from Context's caps
......@@ -569,7 +575,6 @@ class State : angle::NonCopyable
InitState mCachedImageTexturesInitState;
using SamplerBindingVector = std::vector<BindingPointer<Sampler>>;
SamplerBindingVector mSamplers;
using ImageUnitVector = std::vector<ImageUnit>;
......@@ -628,6 +633,7 @@ class State : angle::NonCopyable
DirtyBits mDirtyBits;
DirtyObjects mDirtyObjects;
mutable AttributesMask mDirtyCurrentValues;
ActiveTextureMask mDirtySamplers;
};
} // namespace gl
......
......@@ -333,7 +333,10 @@ void QuerySamplerParameterBase(const Sampler *sampler, GLenum pname, ParamType *
}
template <typename ParamType>
void SetSamplerParameterBase(Sampler *sampler, GLenum pname, const ParamType *params)
void SetSamplerParameterBase(Context *context,
Sampler *sampler,
GLenum pname,
const ParamType *params)
{
switch (pname)
{
......@@ -374,6 +377,8 @@ void SetSamplerParameterBase(Sampler *sampler, GLenum pname, const ParamType *pa
UNREACHABLE();
break;
}
sampler->onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
}
// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
......@@ -1404,24 +1409,24 @@ void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const G
SetTexParameterBase(context, texture, pname, params);
}
void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param)
void SetSamplerParameterf(Context *context, Sampler *sampler, GLenum pname, GLfloat param)
{
SetSamplerParameterBase(sampler, pname, &param);
SetSamplerParameterBase(context, sampler, pname, &param);
}
void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params)
void SetSamplerParameterfv(Context *context, Sampler *sampler, GLenum pname, const GLfloat *params)
{
SetSamplerParameterBase(sampler, pname, params);
SetSamplerParameterBase(context, sampler, pname, params);
}
void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param)
void SetSamplerParameteri(Context *context, Sampler *sampler, GLenum pname, GLint param)
{
SetSamplerParameterBase(sampler, pname, &param);
SetSamplerParameterBase(context, sampler, pname, &param);
}
void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params)
void SetSamplerParameteriv(Context *context, Sampler *sampler, GLenum pname, const GLint *params)
{
SetSamplerParameterBase(sampler, pname, params);
SetSamplerParameterBase(context, sampler, pname, params);
}
void SetFramebufferParameteri(const Context *context,
......
......@@ -112,10 +112,10 @@ void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const G
void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param);
void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params);
void SetSamplerParameterf(Sampler *sampler, GLenum pname, GLfloat param);
void SetSamplerParameterfv(Sampler *sampler, GLenum pname, const GLfloat *params);
void SetSamplerParameteri(Sampler *sampler, GLenum pname, GLint param);
void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params);
void SetSamplerParameterf(Context *context, Sampler *sampler, GLenum pname, GLfloat param);
void SetSamplerParameterfv(Context *context, Sampler *sampler, GLenum pname, const GLfloat *params);
void SetSamplerParameteri(Context *context, Sampler *sampler, GLenum pname, GLint param);
void SetSamplerParameteriv(Context *context, Sampler *sampler, GLenum pname, const GLint *params);
void SetFramebufferParameteri(const Context *context,
Framebuffer *framebuffer,
......
......@@ -163,7 +163,7 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions,
mIsMultiviewEnabled(extensions.multiview),
mLocalDirtyBits(),
mMultiviewDirtyBits(),
mProgramTexturesAndSamplersDirty(true),
mProgramTexturesDirty(true),
mProgramStorageBuffersDirty(true),
mProgramUniformBuffersDirty(true),
mProgramAtomicCounterBuffersDirty(true),
......@@ -874,10 +874,10 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context)
mProgramUniformBuffersDirty = false;
}
if (mProgramTexturesAndSamplersDirty)
if (mProgramTexturesDirty)
{
updateProgramTextureAndSamplerBindings(context);
mProgramTexturesAndSamplersDirty = false;
updateProgramTextureBindings(context);
mProgramTexturesDirty = false;
}
if (mProgramStorageBuffersDirty)
......@@ -899,7 +899,7 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context)
}
}
void StateManagerGL::updateProgramTextureAndSamplerBindings(const gl::Context *context)
void StateManagerGL::updateProgramTextureBindings(const gl::Context *context)
{
const gl::State &glState = context->getGLState();
const gl::Program *program = glState.getProgram();
......@@ -920,30 +920,13 @@ void StateManagerGL::updateProgramTextureAndSamplerBindings(const gl::Context *c
ASSERT(!texture->hasAnyDirtyBit());
ASSERT(!textureGL->hasAnyDirtyBit());
if (mTextures[textureType][textureUnitIndex] != textureGL->getTextureID())
{
activeTexture(textureUnitIndex);
bindTexture(textureType, textureGL->getTextureID());
}
activeTexture(textureUnitIndex);
bindTexture(textureType, textureGL->getTextureID());
}
else
{
if (mTextures[textureType][textureUnitIndex] != 0)
{
activeTexture(textureUnitIndex);
bindTexture(textureType, 0);
}
}
const gl::Sampler *sampler = glState.getSampler(static_cast<GLuint>(textureUnitIndex));
if (sampler != nullptr)
{
SamplerGL *samplerGL = GetImplAs<SamplerGL>(sampler);
bindSampler(textureUnitIndex, samplerGL->getSamplerID());
}
else
{
bindSampler(textureUnitIndex, 0);
activeTexture(textureUnitIndex);
bindTexture(textureType, 0);
}
}
}
......@@ -1996,10 +1979,10 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
break;
}
case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
mProgramTexturesAndSamplersDirty = true;
mProgramTexturesDirty = true;
break;
case gl::State::DIRTY_BIT_SAMPLER_BINDINGS:
mProgramTexturesAndSamplersDirty = true;
syncSamplersState(context);
break;
case gl::State::DIRTY_BIT_IMAGE_BINDINGS:
mProgramImagesDirty = true;
......@@ -2008,7 +1991,7 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
syncTransformFeedbackState(context);
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
mProgramTexturesAndSamplersDirty = true;
mProgramTexturesDirty = true;
mProgramImagesDirty = true;
mProgramStorageBuffersDirty = true;
mProgramUniformBuffersDirty = true;
......@@ -2318,6 +2301,26 @@ void StateManagerGL::updateMultiviewBaseViewLayerIndexUniform(
}
}
void StateManagerGL::syncSamplersState(const gl::Context *context)
{
const gl::State::SamplerBindingVector &samplers = context->getGLState().getSamplers();
// This could be optimized by using a separate binding dirty bit per sampler.
for (size_t samplerIndex = 0; samplerIndex < samplers.size(); ++samplerIndex)
{
const gl::Sampler *sampler = samplers[samplerIndex].get();
if (sampler != nullptr)
{
SamplerGL *samplerGL = GetImplAs<SamplerGL>(sampler);
bindSampler(samplerIndex, samplerGL->getSamplerID());
}
else
{
bindSampler(samplerIndex, 0);
}
}
}
void StateManagerGL::syncTransformFeedbackState(const gl::Context *context)
{
// Set the current transform feedback state
......
......@@ -195,7 +195,7 @@ class StateManagerGL final : angle::NonCopyable
const gl::Framebuffer &drawFramebuffer);
void propagateProgramToVAO(const gl::Program *program, VertexArrayGL *vao);
void updateProgramTextureAndSamplerBindings(const gl::Context *context);
void updateProgramTextureBindings(const gl::Context *context);
void updateProgramStorageBufferBindings(const gl::Context *context);
void updateProgramUniformBufferBindings(const gl::Context *context);
void updateProgramAtomicCounterBufferBindings(const gl::Context *context);
......@@ -204,6 +204,7 @@ class StateManagerGL final : angle::NonCopyable
void updateDispatchIndirectBufferBinding(const gl::Context *context);
void updateDrawIndirectBufferBinding(const gl::Context *context);
void syncSamplersState(const gl::Context *context);
void syncTransformFeedbackState(const gl::Context *context);
enum MultiviewDirtyBitType
......@@ -364,7 +365,7 @@ class StateManagerGL final : angle::NonCopyable
// ANGLE_multiview dirty bits.
angle::BitSet<MULTIVIEW_DIRTY_BIT_MAX> mMultiviewDirtyBits;
bool mProgramTexturesAndSamplersDirty;
bool mProgramTexturesDirty;
bool mProgramStorageBuffersDirty;
bool mProgramUniformBuffersDirty;
bool mProgramAtomicCounterBuffersDirty;
......
......@@ -1077,10 +1077,12 @@ TEST_P(LineLoopStateChangeTest, DrawArraysThenDrawElements)
class SimpleStateChangeTest : public ANGLETest
{
protected:
static constexpr int kWindowSize = 64;
SimpleStateChangeTest()
{
setWindowWidth(64);
setWindowHeight(64);
setWindowWidth(kWindowSize);
setWindowHeight(kWindowSize);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
......@@ -1091,6 +1093,10 @@ class SimpleStateChangeTest : public ANGLETest
void simpleDrawWithColor(const GLColor &color);
};
class SimpleStateChangeTestES3 : public SimpleStateChangeTest
{
};
constexpr char kSimpleVertexShader[] = R"(attribute vec2 position;
attribute vec4 color;
varying vec4 vColor;
......@@ -2050,6 +2056,70 @@ TEST_P(SimpleStateChangeTest, ReleaseShaderInUseThatReadsFromUniforms)
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::red);
}
// Tests that sampler sync isn't masked by program textures.
TEST_P(SimpleStateChangeTestES3, SamplerSyncNotTiedToProgram)
{
// Create a sampler with NEAREST filtering.
GLSampler sampler;
glBindSampler(0, sampler);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Draw with a program that uses no textures.
ANGLE_GL_PROGRAM(program1, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
drawQuad(program1, essl1_shaders::PositionAttrib(), 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
// Create a simple texture with four colors and linear filtering.
constexpr GLsizei kSize = 2;
std::array<GLColor, 4> pixels = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture redTex;
glBindTexture(GL_TEXTURE_2D, redTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Create a program that uses the texture.
constexpr char kVS[] = R"(attribute vec4 position;
varying vec2 texCoord;
void main()
{
gl_Position = position;
texCoord = position.xy * 0.5 + vec2(0.5);
})";
constexpr char kFS[] = R"(precision mediump float;
varying vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
})";
// Draw. The sampler should override the clamp wrap mode with nearest.
ANGLE_GL_PROGRAM(program2, kVS, kFS);
ASSERT_EQ(0, glGetUniformLocation(program2, "tex"));
drawQuad(program2, "position", 0.5f);
ASSERT_GL_NO_ERROR();
constexpr int kHalfSize = kWindowSize / 2;
EXPECT_PIXEL_RECT_EQ(0, 0, kHalfSize, kHalfSize, GLColor::red);
EXPECT_PIXEL_RECT_EQ(kHalfSize, 0, kHalfSize, kHalfSize, GLColor::green);
EXPECT_PIXEL_RECT_EQ(0, kHalfSize, kHalfSize, kHalfSize, GLColor::blue);
EXPECT_PIXEL_RECT_EQ(kHalfSize, kHalfSize, kHalfSize, kHalfSize, GLColor::yellow);
}
static constexpr char kColorVS[] = R"(attribute vec2 position;
attribute vec4 color;
varying vec4 vColor;
......@@ -2798,6 +2868,7 @@ ANGLE_INSTANTIATE_TEST(StateChangeRenderTest,
ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(SimpleStateChangeTest, ES2_VULKAN(), ES2_OPENGL());
ANGLE_INSTANTIATE_TEST(SimpleStateChangeTestES3, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(WebGL2ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(ValidationStateChangeTestES31, ES31_OPENGL());
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