Commit 3aa23a7c by Jamie Madill

Revert "Move sampler validation to the GL layer."

Probably causing failures in the dEQP-GLES2 GL back-end tests: dEQP-GLES2.functional.uniform_api.info_query.basic.sampler2D_both BUG=angleproject:1123 This reverts commit 6fa156b6. Change-Id: I3cc993c34aae4a108037ce81709b71d16ece814e Reviewed-on: https://chromium-review.googlesource.com/301580Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6fa156b6
......@@ -359,8 +359,7 @@ Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint hand
mDeleteStatus(false),
mRefCount(0),
mResourceManager(manager),
mHandle(handle),
mSamplerUniformRange(0, 0)
mHandle(handle)
{
ASSERT(mProgram);
......@@ -675,15 +674,12 @@ Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei lengt
{
int locationIndex = stream.readInt<int>();
VariableLocation locationData;
stream.readInt(&locationData.element);
stream.readInt(&locationData.index);
stream.readString(&locationData.name);
locationData.element = stream.readInt<unsigned int>();
locationData.index = stream.readInt<unsigned int>();
locationData.name = stream.readString();
mData.mOutputVariables[locationIndex] = locationData;
}
stream.readInt(&mSamplerUniformRange.start);
stream.readInt(&mSamplerUniformRange.end);
rx::LinkResult result = mProgram->load(mInfoLog, &stream);
if (result.error.isError() || !result.linkSuccess)
{
......@@ -773,9 +769,6 @@ Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, G
stream.writeString(outputPair.second.name);
}
stream.writeInt(mSamplerUniformRange.start);
stream.writeInt(mSamplerUniformRange.end);
gl::Error error = mProgram->save(&stream);
if (error.isError())
{
......@@ -1304,78 +1297,7 @@ void Program::validate(const Caps &caps)
bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
{
// Skip cache if we're using an infolog, so we get the full error.
// Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
{
return mCachedValidateSamplersResult.value();
}
if (mTextureUnitTypesCache.empty())
{
mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, GL_NONE);
}
else
{
std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
}
// if any two active samplers in a program are of different types, but refer to the same
// texture image unit, and this is the current program, then ValidateProgram will fail, and
// DrawArrays and DrawElements will issue the INVALID_OPERATION error.
for (unsigned int samplerIndex = mSamplerUniformRange.start;
samplerIndex < mSamplerUniformRange.end; ++samplerIndex)
{
const LinkedUniform &uniform = mData.mUniforms[samplerIndex];
ASSERT(uniform.isSampler());
if (!uniform.staticUse)
continue;
const GLuint *dataPtr = reinterpret_cast<const GLuint *>(uniform.getDataPtrToElement(0));
GLenum textureType = SamplerTypeToTextureType(uniform.type);
for (unsigned int arrayElement = 0; arrayElement < uniform.elementCount(); ++arrayElement)
{
GLuint textureUnit = dataPtr[arrayElement];
if (textureUnit >= caps.maxCombinedTextureImageUnits)
{
if (infoLog)
{
(*infoLog) << "Sampler uniform (" << textureUnit
<< ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
<< caps.maxCombinedTextureImageUnits << ")";
}
mCachedValidateSamplersResult = false;
return false;
}
if (mTextureUnitTypesCache[textureUnit] != GL_NONE)
{
if (textureType != mTextureUnitTypesCache[textureUnit])
{
if (infoLog)
{
(*infoLog) << "Samplers of conflicting types refer to the same texture "
"image unit ("
<< textureUnit << ").";
}
mCachedValidateSamplersResult = false;
return false;
}
}
else
{
mTextureUnitTypesCache[textureUnit] = textureType;
}
}
}
mCachedValidateSamplersResult = true;
return true;
return mProgram->validateSamplers(infoLog, caps);
}
bool Program::isValidated() const
......@@ -2164,13 +2086,11 @@ bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
const gl::Shader *vertexShader = mData.getAttachedVertexShader();
VectorAndSamplerCount vsCounts;
std::vector<LinkedUniform> samplerUniforms;
for (const sh::Uniform &uniform : vertexShader->getUniforms())
{
if (uniform.staticUse)
{
vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
vsCounts += flattenUniform(uniform, uniform.name);
}
}
......@@ -2195,7 +2115,7 @@ bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
{
if (uniform.staticUse)
{
fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
fsCounts += flattenUniform(uniform, uniform.name);
}
}
......@@ -2213,18 +2133,11 @@ bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
return false;
}
mSamplerUniformRange.start = static_cast<unsigned int>(mData.mUniforms.size());
mSamplerUniformRange.end =
mSamplerUniformRange.start + static_cast<unsigned int>(samplerUniforms.size());
mData.mUniforms.insert(mData.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
return true;
}
Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable &uniform,
const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms)
const std::string &fullName)
{
VectorAndSamplerCount vectorAndSamplerCount;
......@@ -2239,7 +2152,7 @@ Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable
const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name);
vectorAndSamplerCount += flattenUniform(field, fieldFullName, samplerUniforms);
vectorAndSamplerCount += flattenUniform(field, fieldFullName);
}
}
......@@ -2247,28 +2160,18 @@ Program::VectorAndSamplerCount Program::flattenUniform(const sh::ShaderVariable
}
// Not a struct
bool isSampler = IsSamplerType(uniform.type);
if (mData.getUniformByName(fullName) == nullptr)
{
gl::LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName,
uniform.arraySize, -1,
sh::BlockMemberInfo::getDefaultBlockInfo());
linkedUniform.staticUse = true;
// Store sampler uniforms separately, so we'll append them to the end of the list.
if (isSampler)
{
samplerUniforms->push_back(linkedUniform);
}
else
{
mData.mUniforms.push_back(linkedUniform);
}
mData.mUniforms.push_back(linkedUniform);
}
unsigned int elementCount = uniform.elementCount();
vectorAndSamplerCount.vectorCount = (VariableRegisterCount(uniform.type) * elementCount);
vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
vectorAndSamplerCount.vectorCount =
(VariableRegisterCount(uniform.type) * uniform.elementCount());
vectorAndSamplerCount.samplerCount = (IsSamplerType(uniform.type) ? uniform.elementCount() : 0);
return vectorAndSamplerCount;
}
......@@ -2391,12 +2294,6 @@ void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
}
else
{
// Invalide the validation cache if we modify the sampler data.
if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
{
mCachedValidateSamplersResult.reset();
}
memcpy(destPointer, v, sizeof(T) * count);
}
}
......
......@@ -10,6 +10,13 @@
#ifndef LIBANGLE_PROGRAM_H_
#define LIBANGLE_PROGRAM_H_
#include "libANGLE/angletypes.h"
#include "libANGLE/Constants.h"
#include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h"
#include "common/angleutils.h"
#include <GLES2/gl2.h>
#include <GLSLANG/ShaderLang.h>
......@@ -18,15 +25,6 @@
#include <string>
#include <vector>
#include "common/angleutils.h"
#include "common/mathutil.h"
#include "common/Optional.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Constants.h"
#include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h"
namespace rx
{
class ImplFactory;
......@@ -217,11 +215,6 @@ class Program : angle::NonCopyable
std::vector<sh::Attribute> mAttributes;
std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
// Uniforms are sorted in order:
// 1. Non-sampler uniforms
// 2. Sampler uniforms
// 3. Uniform block uniforms
// This makes sampler validation easier, since we don't need a separate list.
std::vector<LinkedUniform> mUniforms;
std::vector<VariableLocation> mUniformLocations;
std::vector<UniformBlock> mUniformBlocks;
......@@ -391,8 +384,7 @@ class Program : angle::NonCopyable
};
VectorAndSamplerCount flattenUniform(const sh::ShaderVariable &uniform,
const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms);
const std::string &fullName);
void gatherInterfaceBlockInfo();
void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
......@@ -422,11 +414,6 @@ class Program : angle::NonCopyable
const GLuint mHandle;
InfoLog mInfoLog;
// Cache for sampler validation
Optional<bool> mCachedValidateSamplersResult;
std::vector<GLenum> mTextureUnitTypesCache;
RangeUI mSamplerUniformRange;
};
}
......
......@@ -633,7 +633,6 @@ Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const
{
const auto it = mSamplerTextures.find(type);
ASSERT(it != mSamplerTextures.end());
ASSERT(sampler < it->second.size());
return it->second[sampler].get();
}
......@@ -641,7 +640,6 @@ GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const
{
const auto it = mSamplerTextures.find(type);
ASSERT(it != mSamplerTextures.end());
ASSERT(sampler < it->second.size());
return it->second[sampler].id();
}
......
......@@ -64,7 +64,6 @@ struct UniformBlock
std::vector<unsigned int> memberUniformIndexes;
// TODO(jmadill): Make D3D-only.
unsigned int psRegisterIndex;
unsigned int vsRegisterIndex;
};
......
......@@ -66,6 +66,10 @@ class ProgramImpl : angle::NonCopyable
virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
// TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to
// determine if they can be removed from this interface.
virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0;
// Gather uniform block active uniform indices, and uniform block offset info.
virtual void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
std::vector<gl::LinkedUniform> *uniforms) = 0;
......
......@@ -28,6 +28,36 @@ namespace rx
namespace
{
GLenum GetTextureType(GLenum samplerType)
{
switch (samplerType)
{
case GL_SAMPLER_2D:
case GL_INT_SAMPLER_2D:
case GL_UNSIGNED_INT_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW:
return GL_TEXTURE_2D;
case GL_SAMPLER_3D:
case GL_INT_SAMPLER_3D:
case GL_UNSIGNED_INT_SAMPLER_3D:
return GL_TEXTURE_3D;
case GL_SAMPLER_CUBE:
case GL_SAMPLER_CUBE_SHADOW:
return GL_TEXTURE_CUBE_MAP;
case GL_INT_SAMPLER_CUBE:
case GL_UNSIGNED_INT_SAMPLER_CUBE:
return GL_TEXTURE_CUBE_MAP;
case GL_SAMPLER_2D_ARRAY:
case GL_INT_SAMPLER_2D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case GL_SAMPLER_2D_ARRAY_SHADOW:
return GL_TEXTURE_2D_ARRAY;
default: UNREACHABLE();
}
return GL_TEXTURE_2D;
}
gl::InputLayout GetDefaultInputLayoutFromShader(const gl::Shader *vertexShader)
{
gl::InputLayout defaultLayout;
......@@ -308,6 +338,7 @@ ProgramD3D::ProgramD3D(const gl::Program::Data &data, RendererD3D *renderer)
mUsedVertexSamplerRange(0),
mUsedPixelSamplerRange(0),
mDirtySamplerMapping(true),
mTextureUnitTypesCache(renderer->getRendererCaps().maxCombinedTextureImageUnits),
mShaderVersion(100),
mSerial(issueSerial())
{
......@@ -455,6 +486,106 @@ void ProgramD3D::updateSamplerMapping()
}
}
bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps)
{
// Skip cache if we're using an infolog, so we get the full error.
// Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
if (!mDirtySamplerMapping && infoLog == nullptr && mCachedValidateSamplersResult.valid())
{
return mCachedValidateSamplersResult.value();
}
// if any two active samplers in a program are of different types, but refer to the same
// texture image unit, and this is the current program, then ValidateProgram will fail, and
// DrawArrays and DrawElements will issue the INVALID_OPERATION error.
updateSamplerMapping();
std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE);
for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
{
if (mSamplersPS[i].active)
{
unsigned int unit = mSamplersPS[i].logicalTextureUnit;
if (unit >= caps.maxCombinedTextureImageUnits)
{
if (infoLog)
{
(*infoLog) << "Sampler uniform (" << unit
<< ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
<< caps.maxCombinedTextureImageUnits << ")";
}
mCachedValidateSamplersResult = false;
return false;
}
if (mTextureUnitTypesCache[unit] != GL_NONE)
{
if (mSamplersPS[i].textureType != mTextureUnitTypesCache[unit])
{
if (infoLog)
{
(*infoLog) << "Samplers of conflicting types refer to the same texture image unit ("
<< unit << ").";
}
mCachedValidateSamplersResult = false;
return false;
}
}
else
{
mTextureUnitTypesCache[unit] = mSamplersPS[i].textureType;
}
}
}
for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
{
if (mSamplersVS[i].active)
{
unsigned int unit = mSamplersVS[i].logicalTextureUnit;
if (unit >= caps.maxCombinedTextureImageUnits)
{
if (infoLog)
{
(*infoLog) << "Sampler uniform (" << unit
<< ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
<< caps.maxCombinedTextureImageUnits << ")";
}
mCachedValidateSamplersResult = false;
return false;
}
if (mTextureUnitTypesCache[unit] != GL_NONE)
{
if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit])
{
if (infoLog)
{
(*infoLog) << "Samplers of conflicting types refer to the same texture image unit ("
<< unit << ").";
}
mCachedValidateSamplersResult = false;
return false;
}
}
else
{
mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType;
}
}
}
mCachedValidateSamplersResult = true;
return true;
}
LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
{
reset();
......@@ -1042,7 +1173,7 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
initSemanticIndex();
defineUniformsAndAssignRegisters();
assignUniformRegisters();
gatherTransformFeedbackVaryings(linkedVaryings);
......@@ -1056,10 +1187,10 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
return LinkResult(true, gl::Error(GL_NO_ERROR));
}
GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLog*/)
GLboolean ProgramD3D::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
{
// TODO(jmadill): Do something useful here?
return GL_TRUE;
applyUniforms();
return validateSamplers(infoLog, caps);
}
void ProgramD3D::gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
......@@ -1344,19 +1475,17 @@ void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
}
void ProgramD3D::defineUniformsAndAssignRegisters()
void ProgramD3D::assignUniformRegisters()
{
const gl::Shader *vertexShader = mData.getAttachedVertexShader();
const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(vertexShader);
D3DUniformMap uniformMap;
for (const sh::Uniform &vertexUniform : vertexShader->getUniforms())
{
if (vertexUniform.staticUse)
{
defineUniformBase(vertexShaderD3D, vertexUniform, &uniformMap);
assignUniformRegistersBase(vertexShaderD3D, vertexUniform);
}
}
......@@ -1367,32 +1496,19 @@ void ProgramD3D::defineUniformsAndAssignRegisters()
{
if (fragmentUniform.staticUse)
{
defineUniformBase(fragmentShaderD3D, fragmentUniform, &uniformMap);
assignUniformRegistersBase(fragmentShaderD3D, fragmentUniform);
}
}
// Initialize the D3DUniform list to mirror the indexing of the GL layer.
for (const gl::LinkedUniform &glUniform : mData.getUniforms())
{
if (!glUniform.isInDefaultBlock())
continue;
auto mapEntry = uniformMap.find(glUniform.name);
ASSERT(mapEntry != uniformMap.end());
mD3DUniforms.push_back(mapEntry->second);
}
assignAllSamplerRegisters();
initializeUniformStorage();
}
void ProgramD3D::defineUniformBase(const ShaderD3D *shader,
const sh::Uniform &uniform,
D3DUniformMap *uniformMap)
void ProgramD3D::assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform)
{
if (uniform.isBuiltIn())
{
defineUniform(shader, uniform, uniform.name, nullptr, uniformMap);
assignUniformRegisters(shader, uniform, uniform.name, nullptr);
return;
}
......@@ -1401,7 +1517,7 @@ void ProgramD3D::defineUniformBase(const ShaderD3D *shader,
sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
encoder.skipRegisters(startRegister);
defineUniform(shader, uniform, uniform.name, &encoder, uniformMap);
assignUniformRegisters(shader, uniform, uniform.name, &encoder);
}
D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
......@@ -1417,11 +1533,10 @@ D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
return nullptr;
}
void ProgramD3D::defineUniform(const ShaderD3D *shader,
const sh::ShaderVariable &uniform,
const std::string &fullName,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
void ProgramD3D::assignUniformRegisters(const ShaderD3D *shader,
const sh::ShaderVariable &uniform,
const std::string &fullName,
sh::HLSLBlockEncoder *encoder)
{
if (uniform.isStruct())
{
......@@ -1437,7 +1552,7 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader,
const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name);
defineUniform(shader, field, fieldFullName, encoder, uniformMap);
assignUniformRegisters(shader, field, fieldFullName, encoder);
}
if (encoder)
......@@ -1457,23 +1572,27 @@ void ProgramD3D::defineUniform(const ShaderD3D *shader,
encoder ? encoder->encodeType(uniform.type, uniform.arraySize, false)
: sh::BlockMemberInfo::getDefaultBlockInfo();
auto uniformMapEntry = uniformMap->find(fullName);
D3DUniform *d3dUniform = nullptr;
D3DUniform *d3dUniform = getD3DUniformByName(fullName);
if (uniformMapEntry != uniformMap->end())
{
d3dUniform = uniformMapEntry->second;
}
else
if (!d3dUniform)
{
// We're building the list twice, make sure we use the same indexing. Special case
// built-ins.
ASSERT(fullName.compare(0, 3, "gl_") == 0 ||
mData.getUniformIndex(fullName) == static_cast<GLint>(mD3DUniforms.size()));
d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySize, true);
(*uniformMap)[fullName] = d3dUniform;
mD3DUniforms.push_back(d3dUniform);
if (encoder)
{
d3dUniform->registerElement =
static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
}
}
if (encoder)
{
d3dUniform->registerElement =
static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
unsigned int reg =
static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
if (shader->getShaderType() == GL_FRAGMENT_SHADER)
......@@ -1752,7 +1871,7 @@ void ProgramD3D::AssignSamplers(unsigned int startSamplerIndex,
ASSERT(samplerIndex < outSamplers.size());
Sampler *sampler = &outSamplers[samplerIndex];
sampler->active = true;
sampler->textureType = gl::SamplerTypeToTextureType(samplerType);
sampler->textureType = GetTextureType(samplerType);
sampler->logicalTextureUnit = 0;
*outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
samplerIndex++;
......
......@@ -12,6 +12,7 @@
#include <string>
#include <vector>
#include "common/Optional.h"
#include "compiler/translator/blocklayoutHLSL.h"
#include "libANGLE/Constants.h"
#include "libANGLE/formatutils.h"
......@@ -83,6 +84,7 @@ class ProgramD3D : public ProgramImpl
GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const;
GLint getUsedSamplerRange(gl::SamplerType type) const;
void updateSamplerMapping();
bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps);
bool usesPointSize() const { return mUsesPointSize; }
bool usesPointSpriteEmulation() const;
......@@ -196,18 +198,14 @@ class ProgramD3D : public ProgramImpl
GLenum textureType;
};
typedef std::map<std::string, D3DUniform *> D3DUniformMap;
typedef std::map<std::string, sh::BlockMemberInfo> BlockInfoMap;
void defineUniformsAndAssignRegisters();
void defineUniformBase(const ShaderD3D *shader,
const sh::Uniform &uniform,
D3DUniformMap *uniformMap);
void defineUniform(const ShaderD3D *shader,
const sh::ShaderVariable &uniform,
const std::string &fullName,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void assignUniformRegisters();
void assignUniformRegistersBase(const ShaderD3D *shader, const sh::Uniform &uniform);
void assignUniformRegisters(const ShaderD3D *shader,
const sh::ShaderVariable &uniform,
const std::string &fullName,
sh::HLSLBlockEncoder *encoder);
void assignAllSamplerRegisters();
void assignSamplerRegisters(const D3DUniform *d3dUniform);
......@@ -264,6 +262,9 @@ class ProgramD3D : public ProgramImpl
GLuint mUsedPixelSamplerRange;
bool mDirtySamplerMapping;
// Cache for validateSamplers
std::vector<GLenum> mTextureUnitTypesCache;
// Cache for getPixelExecutableForFramebuffer
std::vector<GLenum> mPixelShaderOutputFormatCache;
......@@ -274,6 +275,8 @@ class ProgramD3D : public ProgramImpl
unsigned int mSerial;
Optional<bool> mCachedValidateSamplersResult;
std::vector<GLint> mVertexUBOCache;
std::vector<GLint> mFragmentUBOCache;
VertexExecutable::Signature mCachedVertexSignature;
......
......@@ -299,6 +299,12 @@ void ProgramGL::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean t
mFunctions->uniformMatrix4x3fv(uniLoc(location), count, transpose, value);
}
bool ProgramGL::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps)
{
//UNIMPLEMENTED();
return true;
}
void ProgramGL::reset()
{
mUniformRealLocationMap.clear();
......
......@@ -62,6 +62,8 @@ class ProgramGL : public ProgramImpl
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) override;
void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
std::vector<gl::LinkedUniform> *uniforms) override;
......
......@@ -703,366 +703,8 @@ TEST_P(TextureTestES3, RedefineInittableArray)
ASSERT_GL_NO_ERROR();
}
class TextureLimitsTest : public ANGLETest
{
protected:
struct RGBA8
{
uint8_t R, G, B, A;
};
TextureLimitsTest()
: mProgram(0), mMaxVertexTextures(0), mMaxFragmentTextures(0), mMaxCombinedTextures(0)
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
~TextureLimitsTest()
{
if (mProgram != 0)
{
glDeleteProgram(mProgram);
mProgram = 0;
if (!mTextures.empty())
{
glDeleteTextures(static_cast<GLsizei>(mTextures.size()), &mTextures[0]);
}
}
}
void SetUp() override
{
ANGLETest::SetUp();
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mMaxVertexTextures);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mMaxFragmentTextures);
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxCombinedTextures);
ASSERT_GL_NO_ERROR();
}
void compileProgramWithTextureCounts(const std::string &vertexPrefix,
GLint vertexTextureCount,
GLint vertexActiveTextureCount,
const std::string &fragPrefix,
GLint fragmentTextureCount,
GLint fragmentActiveTextureCount)
{
std::stringstream vertexShaderStr;
vertexShaderStr << "attribute vec2 position;\n"
<< "varying vec4 color;\n"
<< "varying vec2 texCoord;\n";
for (GLint textureIndex = 0; textureIndex < vertexTextureCount; ++textureIndex)
{
vertexShaderStr << "uniform sampler2D " << vertexPrefix << textureIndex << ";\n";
}
vertexShaderStr << "void main() {\n"
<< " gl_Position = vec4(position, 0, 1);\n"
<< " texCoord = (position * 0.5) + 0.5;\n"
<< " color = vec4(0);\n";
for (GLint textureIndex = 0; textureIndex < vertexActiveTextureCount; ++textureIndex)
{
vertexShaderStr << " color += texture2D(" << vertexPrefix << textureIndex
<< ", texCoord);\n";
}
vertexShaderStr << "}";
std::stringstream fragmentShaderStr;
fragmentShaderStr << "varying mediump vec4 color;\n"
<< "varying mediump vec2 texCoord;\n";
for (GLint textureIndex = 0; textureIndex < fragmentTextureCount; ++textureIndex)
{
fragmentShaderStr << "uniform sampler2D " << fragPrefix << textureIndex << ";\n";
}
fragmentShaderStr << "void main() {\n"
<< " gl_FragColor = color;\n";
for (GLint textureIndex = 0; textureIndex < fragmentActiveTextureCount; ++textureIndex)
{
fragmentShaderStr << " gl_FragColor += texture2D(" << fragPrefix << textureIndex
<< ", texCoord);\n";
}
fragmentShaderStr << "}";
const std::string &vertexShaderSource = vertexShaderStr.str();
const std::string &fragmentShaderSource = fragmentShaderStr.str();
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
}
RGBA8 getPixel(GLint texIndex)
{
RGBA8 pixel = {static_cast<uint8_t>(texIndex & 0x7u), static_cast<uint8_t>(texIndex >> 3),
0, 255u};
return pixel;
}
void initTextures(GLint tex2DCount, GLint texCubeCount)
{
GLint totalCount = tex2DCount + texCubeCount;
mTextures.assign(totalCount, 0);
glGenTextures(totalCount, &mTextures[0]);
ASSERT_GL_NO_ERROR();
std::vector<RGBA8> texData(16 * 16);
GLint texIndex = 0;
for (; texIndex < tex2DCount; ++texIndex)
{
texData.assign(texData.size(), getPixel(texIndex));
glActiveTexture(GL_TEXTURE0 + texIndex);
glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
&texData[0]);
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_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
ASSERT_GL_NO_ERROR();
for (; texIndex < texCubeCount; ++texIndex)
{
texData.assign(texData.size(), getPixel(texIndex));
glActiveTexture(GL_TEXTURE0 + texIndex);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[texIndex]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
GL_UNSIGNED_BYTE, &texData[0]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
ASSERT_GL_NO_ERROR();
}
void testWithTextures(GLint vertexTextureCount,
const std::string &vertexTexturePrefix,
GLint fragmentTextureCount,
const std::string &fragmentTexturePrefix)
{
// Generate textures
initTextures(vertexTextureCount + fragmentTextureCount, 0);
glUseProgram(mProgram);
RGBA8 expectedSum = {0};
for (GLint texIndex = 0; texIndex < vertexTextureCount; ++texIndex)
{
std::stringstream uniformNameStr;
uniformNameStr << vertexTexturePrefix << texIndex;
const std::string &uniformName = uniformNameStr.str();
GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
ASSERT_NE(-1, location);
glUniform1i(location, texIndex);
RGBA8 contribution = getPixel(texIndex);
expectedSum.R += contribution.R;
expectedSum.G += contribution.G;
}
for (GLint texIndex = 0; texIndex < fragmentTextureCount; ++texIndex)
{
std::stringstream uniformNameStr;
uniformNameStr << fragmentTexturePrefix << texIndex;
const std::string &uniformName = uniformNameStr.str();
GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
ASSERT_NE(-1, location);
glUniform1i(location, texIndex + vertexTextureCount);
RGBA8 contribution = getPixel(texIndex + vertexTextureCount);
expectedSum.R += contribution.R;
expectedSum.G += contribution.G;
}
ASSERT_GE(256u, expectedSum.G);
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(0, 0, expectedSum.R, expectedSum.G, 0, 255);
}
GLuint mProgram;
std::vector<GLuint> mTextures;
GLint mMaxVertexTextures;
GLint mMaxFragmentTextures;
GLint mMaxCombinedTextures;
};
// Test rendering with the maximum vertex texture units.
TEST_P(TextureLimitsTest, MaxVertexTextures)
{
compileProgramWithTextureCounts("tex", mMaxVertexTextures, mMaxVertexTextures, "tex", 0, 0);
ASSERT_NE(0u, mProgram);
ASSERT_GL_NO_ERROR();
testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
}
// Test rendering with the maximum fragment texture units.
TEST_P(TextureLimitsTest, MaxFragmentTextures)
{
compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures, mMaxFragmentTextures);
ASSERT_NE(0u, mProgram);
ASSERT_GL_NO_ERROR();
testWithTextures(mMaxFragmentTextures, "tex", 0, "tex");
}
// Test rendering with maximum combined texture units.
TEST_P(TextureLimitsTest, MaxCombinedTextures)
{
GLint vertexTextures = mMaxVertexTextures;
if (vertexTextures + mMaxFragmentTextures > mMaxCombinedTextures)
{
vertexTextures = mMaxCombinedTextures - mMaxFragmentTextures;
}
compileProgramWithTextureCounts("vtex", vertexTextures, vertexTextures, "ftex",
mMaxFragmentTextures, mMaxFragmentTextures);
ASSERT_NE(0u, mProgram);
ASSERT_GL_NO_ERROR();
testWithTextures(vertexTextures, "vtex", mMaxFragmentTextures, "ftex");
}
// Negative test for exceeding the number of vertex textures
TEST_P(TextureLimitsTest, ExcessiveVertexTextures)
{
compileProgramWithTextureCounts("tex", mMaxVertexTextures + 1, mMaxVertexTextures + 1, "tex", 0,
0);
ASSERT_EQ(0u, mProgram);
}
// Negative test for exceeding the number of fragment textures
TEST_P(TextureLimitsTest, ExcessiveFragmentTextures)
{
compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 1,
mMaxFragmentTextures + 1);
ASSERT_EQ(0u, mProgram);
}
// Test active vertex textures under the limit, but excessive textures specified.
TEST_P(TextureLimitsTest, MaxActiveVertexTextures)
{
compileProgramWithTextureCounts("tex", mMaxVertexTextures + 4, mMaxVertexTextures, "tex", 0, 0);
ASSERT_NE(0u, mProgram);
ASSERT_GL_NO_ERROR();
testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
}
// Test active fragment textures under the limit, but excessive textures specified.
TEST_P(TextureLimitsTest, MaxActiveFragmentTextures)
{
compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 4,
mMaxFragmentTextures);
ASSERT_NE(0u, mProgram);
ASSERT_GL_NO_ERROR();
testWithTextures(0, "tex", mMaxFragmentTextures, "tex");
}
// Negative test for pointing two sampler uniforms of different types to the same texture.
TEST_P(TextureLimitsTest, TextureTypeConflict)
{
const std::string &vertexShader =
"attribute vec2 position;\n"
"varying float color;\n"
"uniform sampler2D tex2D;\n"
"uniform samplerCube texCube;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" vec2 texCoord = (position * 0.5) + 0.5;\n"
" color = texture2D(tex2D, texCoord).x;\n"
" color += textureCube(texCube, vec3(texCoord, 0)).x;\n"
"}";
const std::string &fragmentShader =
"varying mediump float color;\n"
"void main() {\n"
" gl_FragColor = vec4(color, 0, 0, 1);\n"
"}";
mProgram = CompileProgram(vertexShader, fragmentShader);
ASSERT_NE(0u, mProgram);
initTextures(1, 0);
glUseProgram(mProgram);
GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
ASSERT_NE(-1, tex2DLocation);
GLint texCubeLocation = glGetUniformLocation(mProgram, "texCube");
ASSERT_NE(-1, texCubeLocation);
glUniform1i(tex2DLocation, 0);
glUniform1i(texCubeLocation, 0);
ASSERT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Negative test for rendering with texture outside the valid range.
// TODO(jmadill): Research if this is correct.
TEST_P(TextureLimitsTest, DrawWithTexturePastMaximum)
{
const std::string &vertexShader =
"attribute vec2 position;\n"
"varying float color;\n"
"uniform sampler2D tex2D;\n"
"void main() {\n"
" gl_Position = vec4(position, 0, 1);\n"
" vec2 texCoord = (position * 0.5) + 0.5;\n"
" color = texture2D(tex2D, texCoord).x;\n"
"}";
const std::string &fragmentShader =
"varying mediump float color;\n"
"void main() {\n"
" gl_FragColor = vec4(color, 0, 0, 1);\n"
"}";
mProgram = CompileProgram(vertexShader, fragmentShader);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
ASSERT_NE(-1, tex2DLocation);
glUniform1i(tex2DLocation, mMaxCombinedTextures);
ASSERT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(TextureTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3()); // TODO(geofflang): Figure out why this test fails on Intel OpenGL
ANGLE_INSTANTIATE_TEST(TextureTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(TextureLimitsTest, ES2_D3D11(), ES2_OPENGL());
} // namespace
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