Commit d4cfa57d by Jamie Madill

Move more draw call validation to the API.

The GL expects us to reject invalid draw calls before we start doing any work, so we can prevent internal unnecessary state changes. Also update the program binary's cached sampler data when we validate. The previous patch was breaking draw calls in Google Earth WebGL. BUG=angle:571 BUG=390412 Change-Id: I1c4e204ae2467afc36b76af975a3a49e26349639 Reviewed-on: https://chromium-review.googlesource.com/206482Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent f6d38b05
...@@ -1336,6 +1336,11 @@ void Context::setProgramBinary(GLuint program, const void *binary, GLint length) ...@@ -1336,6 +1336,11 @@ void Context::setProgramBinary(GLuint program, const void *binary, GLint length)
} }
GLuint Context::getCurrentProgram() const
{
return mState.currentProgram;
}
void Context::bindTransformFeedback(GLuint transformFeedback) void Context::bindTransformFeedback(GLuint transformFeedback)
{ {
TransformFeedback *transformFeedbackObject = getTransformFeedback(transformFeedback); TransformFeedback *transformFeedbackObject = getTransformFeedback(transformFeedback);
...@@ -1479,7 +1484,7 @@ Buffer *Context::getElementArrayBuffer() const ...@@ -1479,7 +1484,7 @@ Buffer *Context::getElementArrayBuffer() const
return getCurrentVertexArray()->getElementArrayBuffer(); return getCurrentVertexArray()->getElementArrayBuffer();
} }
ProgramBinary *Context::getCurrentProgramBinary() ProgramBinary *Context::getCurrentProgramBinary() const
{ {
return mCurrentProgramBinary.get(); return mCurrentProgramBinary.get();
} }
...@@ -2829,13 +2834,10 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, ...@@ -2829,13 +2834,10 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
{ {
if (!mState.currentProgram) ASSERT(mState.currentProgram);
{
return gl::error(GL_INVALID_OPERATION);
}
ProgramBinary *programBinary = getCurrentProgramBinary(); ProgramBinary *programBinary = getCurrentProgramBinary();
programBinary->applyUniforms(); programBinary->updateSamplerMapping();
Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
...@@ -2883,11 +2885,6 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan ...@@ -2883,11 +2885,6 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
return; return;
} }
if (!programBinary->validateSamplers(NULL))
{
return gl::error(GL_INVALID_OPERATION);
}
if (!skipDraw(mode)) if (!skipDraw(mode))
{ {
mRenderer->drawArrays(mode, count, instances, transformFeedbackActive); mRenderer->drawArrays(mode, count, instances, transformFeedbackActive);
...@@ -2901,19 +2898,10 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan ...@@ -2901,19 +2898,10 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances)
{ {
if (!mState.currentProgram) ASSERT(mState.currentProgram);
{
return gl::error(GL_INVALID_OPERATION);
}
VertexArray *vao = getCurrentVertexArray();
if (!indices && !vao->getElementArrayBuffer())
{
return gl::error(GL_INVALID_OPERATION);
}
ProgramBinary *programBinary = getCurrentProgramBinary(); ProgramBinary *programBinary = getCurrentProgramBinary();
programBinary->applyUniforms(); programBinary->updateSamplerMapping();
Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; Texture *vsTextures[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS]; TextureType vsTextureTypes[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
...@@ -2940,6 +2928,7 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid ...@@ -2940,6 +2928,7 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid
applyState(mode); applyState(mode);
VertexArray *vao = getCurrentVertexArray();
rx::TranslatedIndexData indexInfo; rx::TranslatedIndexData indexInfo;
GLenum err = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); GLenum err = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
if (err != GL_NO_ERROR) if (err != GL_NO_ERROR)
...@@ -2972,11 +2961,6 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid ...@@ -2972,11 +2961,6 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid
return; return;
} }
if (!programBinary->validateSamplers(NULL))
{
return gl::error(GL_INVALID_OPERATION);
}
if (!skipDraw(mode)) if (!skipDraw(mode))
{ {
mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances);
......
...@@ -306,6 +306,7 @@ class Context ...@@ -306,6 +306,7 @@ class Context
void useProgram(GLuint program); void useProgram(GLuint program);
void linkProgram(GLuint program); void linkProgram(GLuint program);
void setProgramBinary(GLuint program, const void *binary, GLint length); void setProgramBinary(GLuint program, const void *binary, GLint length);
GLuint getCurrentProgram() const;
void bindTransformFeedback(GLuint transformFeedback); void bindTransformFeedback(GLuint transformFeedback);
void beginQuery(GLenum target, GLuint query); void beginQuery(GLenum target, GLuint query);
...@@ -341,7 +342,7 @@ class Context ...@@ -341,7 +342,7 @@ class Context
Buffer *getTargetBuffer(GLenum target) const; Buffer *getTargetBuffer(GLenum target) const;
Buffer *getArrayBuffer(); Buffer *getArrayBuffer();
Buffer *getElementArrayBuffer() const; Buffer *getElementArrayBuffer() const;
ProgramBinary *getCurrentProgramBinary(); ProgramBinary *getCurrentProgramBinary() const;
Texture *getTargetTexture(GLenum target) const; Texture *getTargetTexture(GLenum target) const;
Texture2D *getTexture2D() const; Texture2D *getTexture2D() const;
......
...@@ -150,6 +150,7 @@ ProgramBinary::ProgramBinary(rx::Renderer *renderer) ...@@ -150,6 +150,7 @@ ProgramBinary::ProgramBinary(rx::Renderer *renderer)
mUsedPixelSamplerRange(0), mUsedPixelSamplerRange(0),
mUsesPointSize(false), mUsesPointSize(false),
mShaderVersion(100), mShaderVersion(100),
mDirtySamplerMapping(true),
mVertexUniformStorage(NULL), mVertexUniformStorage(NULL),
mFragmentUniformStorage(NULL), mFragmentUniformStorage(NULL),
mValidated(false), mValidated(false),
...@@ -765,6 +766,13 @@ void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) ...@@ -765,6 +766,13 @@ void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
} }
} }
else UNREACHABLE(); else UNREACHABLE();
// Set a special flag if we change a sampler uniform
if (IsSampler(targetUniform->type) &&
(memcmp(targetUniform->data, v, sizeof(GLint)) != 0))
{
mDirtySamplerMapping = true;
}
} }
void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
...@@ -909,9 +917,15 @@ void ProgramBinary::dirtyAllUniforms() ...@@ -909,9 +917,15 @@ void ProgramBinary::dirtyAllUniforms()
} }
} }
// Applies all the uniforms set for this program object to the renderer void ProgramBinary::updateSamplerMapping()
void ProgramBinary::applyUniforms()
{ {
if (!mDirtySamplerMapping)
{
return;
}
mDirtySamplerMapping = false;
// Retrieve sampler uniform values // Retrieve sampler uniform values
for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
{ {
...@@ -922,7 +936,7 @@ void ProgramBinary::applyUniforms() ...@@ -922,7 +936,7 @@ void ProgramBinary::applyUniforms()
if (IsSampler(targetUniform->type)) if (IsSampler(targetUniform->type))
{ {
int count = targetUniform->elementCount(); int count = targetUniform->elementCount();
GLint (*v)[4] = (GLint(*)[4])targetUniform->data; GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
if (targetUniform->isReferencedByFragmentShader()) if (targetUniform->isReferencedByFragmentShader())
{ {
...@@ -958,6 +972,12 @@ void ProgramBinary::applyUniforms() ...@@ -958,6 +972,12 @@ void ProgramBinary::applyUniforms()
} }
} }
} }
}
// Applies all the uniforms set for this program object to the renderer
void ProgramBinary::applyUniforms()
{
updateSamplerMapping();
mRenderer->applyUniforms(*this); mRenderer->applyUniforms(*this);
...@@ -2615,6 +2635,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog) ...@@ -2615,6 +2635,7 @@ bool ProgramBinary::validateSamplers(InfoLog *infoLog)
// if any two active samplers in a program are of different types, but refer to the same // 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 // texture image unit, and this is the current program, then ValidateProgram will fail, and
// DrawArrays and DrawElements will issue the INVALID_OPERATION error. // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
updateSamplerMapping();
const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits(); const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS]; TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
...@@ -2800,6 +2821,7 @@ void ProgramBinary::reset() ...@@ -2800,6 +2821,7 @@ void ProgramBinary::reset()
mUsedPixelSamplerRange = 0; mUsedPixelSamplerRange = 0;
mUsesPointSize = false; mUsesPointSize = false;
mShaderVersion = 0; mShaderVersion = 0;
mDirtySamplerMapping = true;
SafeDeleteContainer(mUniforms); SafeDeleteContainer(mUniforms);
SafeDeleteContainer(mUniformBlocks); SafeDeleteContainer(mUniformBlocks);
......
...@@ -162,6 +162,7 @@ class ProgramBinary : public RefCountObject ...@@ -162,6 +162,7 @@ class ProgramBinary : public RefCountObject
void validate(InfoLog &infoLog); void validate(InfoLog &infoLog);
bool validateSamplers(InfoLog *infoLog); bool validateSamplers(InfoLog *infoLog);
bool isValidated() const; bool isValidated() const;
void updateSamplerMapping();
unsigned int getSerial() const; unsigned int getSerial() const;
int getShaderVersion() const; int getShaderVersion() const;
...@@ -290,6 +291,7 @@ class ProgramBinary : public RefCountObject ...@@ -290,6 +291,7 @@ class ProgramBinary : public RefCountObject
GLuint mUsedPixelSamplerRange; GLuint mUsedPixelSamplerRange;
bool mUsesPointSize; bool mUsesPointSize;
int mShaderVersion; int mShaderVersion;
bool mDirtySamplerMapping;
std::vector<LinkedUniform*> mUniforms; std::vector<LinkedUniform*> mUniforms;
std::vector<UniformBlock*> mUniformBlocks; std::vector<UniformBlock*> mUniformBlocks;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "libGLESv2/Query.h" #include "libGLESv2/Query.h"
#include "libGLESv2/ProgramBinary.h" #include "libGLESv2/ProgramBinary.h"
#include "libGLESv2/TransformFeedback.h" #include "libGLESv2/TransformFeedback.h"
#include "libGLESv2/VertexArray.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -1346,6 +1347,17 @@ static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei co ...@@ -1346,6 +1347,17 @@ static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei co
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false); return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
} }
if (!context->getCurrentProgram())
{
return gl::error(GL_INVALID_OPERATION, false);
}
gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
if (!programBinary->validateSamplers(NULL))
{
return gl::error(GL_INVALID_OPERATION, false);
}
// No-op if zero count // No-op if zero count
return (count > 0); return (count > 0);
} }
...@@ -1422,6 +1434,12 @@ bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count ...@@ -1422,6 +1434,12 @@ bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
gl::VertexArray *vao = context->getCurrentVertexArray();
if (!indices && !vao->getElementArrayBuffer())
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (!ValidateDrawBase(context, mode, count)) if (!ValidateDrawBase(context, mode, count))
{ {
return false; return false;
......
...@@ -16,12 +16,17 @@ protected: ...@@ -16,12 +16,17 @@ protected:
virtual void SetUp() virtual void SetUp()
{ {
ANGLETest::SetUp(); ANGLETest::SetUp();
glGenTextures(1, &mTexture); glGenTextures(1, &mTexture2D);
glGenTextures(1, &mTextureCube);
glBindTexture(GL_TEXTURE_2D, mTexture); glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
glTexStorage2DEXT(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, 1, 1);
EXPECT_GL_NO_ERROR();
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
const std::string vertexShaderSource = SHADER_SOURCE const std::string vertexShaderSource = SHADER_SOURCE
...@@ -37,7 +42,7 @@ protected: ...@@ -37,7 +42,7 @@ protected:
} }
); );
const std::string fragmentShaderSource = SHADER_SOURCE const std::string fragmentShaderSource2D = SHADER_SOURCE
( (
precision highp float; precision highp float;
uniform sampler2D tex; uniform sampler2D tex;
...@@ -49,32 +54,51 @@ protected: ...@@ -49,32 +54,51 @@ protected:
} }
); );
mProgram = compileProgram(vertexShaderSource, fragmentShaderSource); const std::string fragmentShaderSourceCube = SHADER_SOURCE
if (mProgram == 0) (
precision highp float;
uniform sampler2D tex2D;
uniform samplerCube texCube;
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(tex2D, texcoord);
gl_FragColor += textureCube(texCube, vec3(texcoord, 0));
}
);
m2DProgram = compileProgram(vertexShaderSource, fragmentShaderSource2D);
mCubeProgram = compileProgram(vertexShaderSource, fragmentShaderSourceCube);
if (m2DProgram == 0 || mCubeProgram == 0)
{ {
FAIL() << "shader compilation failed."; FAIL() << "shader compilation failed.";
} }
mTextureUniformLocation = glGetUniformLocation(mProgram, "tex"); mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
} }
virtual void TearDown() virtual void TearDown()
{ {
glDeleteTextures(1, &mTexture); glDeleteTextures(1, &mTexture2D);
glDeleteProgram(mProgram); glDeleteTextures(1, &mTextureCube);
glDeleteProgram(m2DProgram);
glDeleteProgram(mCubeProgram);
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
GLuint mTexture; GLuint mTexture2D;
GLuint mTextureCube;
GLuint mProgram; GLuint m2DProgram;
GLint mTextureUniformLocation; GLuint mCubeProgram;
GLint mTexture2DUniformLocation;
}; };
TEST_F(TextureTest, negative_api_subimage) TEST_F(TextureTest, negative_api_subimage)
{ {
glBindTexture(GL_TEXTURE_2D, mTexture); glBindTexture(GL_TEXTURE_2D, mTexture2D);
EXPECT_GL_ERROR(GL_NO_ERROR); EXPECT_GL_ERROR(GL_NO_ERROR);
const GLubyte *pixels[20] = { 0 }; const GLubyte *pixels[20] = { 0 };
...@@ -84,13 +108,13 @@ TEST_F(TextureTest, negative_api_subimage) ...@@ -84,13 +108,13 @@ TEST_F(TextureTest, negative_api_subimage)
TEST_F(TextureTest, zero_sized_uploads) TEST_F(TextureTest, zero_sized_uploads)
{ {
glBindTexture(GL_TEXTURE_2D, mTexture); glBindTexture(GL_TEXTURE_2D, mTexture2D);
EXPECT_GL_ERROR(GL_NO_ERROR); EXPECT_GL_ERROR(GL_NO_ERROR);
// Use the texture first to make sure it's in video memory // Use the texture first to make sure it's in video memory
glUseProgram(mProgram); glUseProgram(m2DProgram);
glUniform1i(mTextureUniformLocation, 0); glUniform1i(mTexture2DUniformLocation, 0);
drawQuad(mProgram, "position", 0.5f); drawQuad(m2DProgram, "position", 0.5f);
const GLubyte *pixel[4] = { 0 }; const GLubyte *pixel[4] = { 0 };
...@@ -103,3 +127,23 @@ TEST_F(TextureTest, zero_sized_uploads) ...@@ -103,3 +127,23 @@ TEST_F(TextureTest, zero_sized_uploads)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Test drawing with two texture types, to trigger an ANGLE bug in validation
TEST_F(TextureTest, cube_map_bug)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
EXPECT_GL_ERROR(GL_NO_ERROR);
glUseProgram(mCubeProgram);
GLint tex2DUniformLocation = glGetUniformLocation(mCubeProgram, "tex2D");
GLint texCubeUniformLocation = glGetUniformLocation(mCubeProgram, "texCube");
EXPECT_NE(-1, tex2DUniformLocation);
EXPECT_NE(-1, texCubeUniformLocation);
glUniform1i(tex2DUniformLocation, 0);
glUniform1i(texCubeUniformLocation, 1);
drawQuad(mCubeProgram, "position", 0.5f);
EXPECT_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