Commit 461b09a8 by Lingfeng Yang Committed by Commit Bot

GLES1: Renderer (minimal)

This is the renderer code for GLES1 that delivers basic vertex attributes, matrices, and allows texturing for unit 0 only (more units mean implementing the multitexturing pipeline). + Sample + Update test expectations for GLES1 conformance tests BUG=angleproject:2554 BUG=angleproject:2306 Change-Id: I398edc764f982fbfc4c5e0f9d6bfef1e91aec47c Reviewed-on: https://chromium-review.googlesource.com/1057356Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Lingfeng Yang <lfy@google.com>
parent 5d2ccc53
......@@ -31,6 +31,7 @@ static_library("sample_util") {
"../:angle_common",
"../:angle_util",
"../:libEGL${angle_libs_suffix}",
"../:libGLESv1_CM${angle_libs_suffix}",
"../:libGLESv2${angle_libs_suffix}",
]
public_configs = [ ":sample_util_config" ]
......@@ -172,6 +173,18 @@ angle_sample("window_test") {
]
}
angle_sample("gles1_hello_triangle") {
sources = [
"gles1/HelloTriangle.cpp",
]
}
angle_sample("gles1_simple_texture_2d") {
sources = [
"gles1/SimpleTexture2D.cpp",
]
}
group("all") {
testonly = true
deps = [
......
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Based on Hello_Triangle.c from
// Book: OpenGL(R) ES 2.0 Programming Guide
// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
// ISBN-10: 0321502795
// ISBN-13: 9780321502797
// Publisher: Addison-Wesley Professional
// URLs: http://safari.informit.com/9780321563835
// http://www.opengles-book.com
#include "SampleApplication.h"
#include "shader_utils.h"
#include <GLES/gl.h>
class GLES1HelloTriangleSample : public SampleApplication
{
public:
GLES1HelloTriangleSample(EGLint displayType)
: SampleApplication("GLES1HelloTriangle", 1280, 720, 1, 0, displayType)
{
}
bool initialize() override
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
return true;
}
void destroy() override {}
void draw() override
{
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f,
};
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
glClear(GL_COLOR_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
};
int main(int argc, char **argv)
{
EGLint displayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
if (argc > 1)
{
displayType = GetDisplayTypeFromArg(argv[1]);
}
GLES1HelloTriangleSample app(displayType);
return app.run();
}
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Based on Simple_Texture2D.c from
// Book: OpenGL(R) ES 2.0 Programming Guide
// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
// ISBN-10: 0321502795
// ISBN-13: 9780321502797
// Publisher: Addison-Wesley Professional
// URLs: http://safari.informit.com/9780321563835
// http://www.opengles-book.com
#include "SampleApplication.h"
#include "shader_utils.h"
#include "texture_utils.h"
#include <GLES/gl.h>
class GLES1SimpleTexture2DSample : public SampleApplication
{
public:
GLES1SimpleTexture2DSample(EGLint displayType)
: SampleApplication("GLES1SimpleTexture2D", 1280, 720, 1, 0, displayType)
{
}
bool initialize() override
{
// Load the texture
mTexture = CreateSimpleTexture2D();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_TEXTURE_2D);
return true;
}
void destroy() override { glDeleteTextures(1, &mTexture); }
void draw() override
{
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-0.5f, -0.5f, 0.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
0.5f, -0.5f, 0.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
0.5f, 0.5f, 0.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = {0, 1, 2, 0, 2, 3};
// Set the viewport
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Load the vertex position
glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), vertices);
// Load the texture coordinate
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), vertices + 3);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
private:
// Texture handle
GLuint mTexture = 0;
};
int main(int argc, char **argv)
{
EGLint displayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
if (argc > 1)
{
displayType = GetDisplayTypeFromArg(argv[1]);
}
GLES1SimpleTexture2DSample app(displayType);
return app.run();
}
......@@ -57,7 +57,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources(),
mShaderCompilers({})
{
ASSERT(state.getClientMajorVersion() == 2 || state.getClientMajorVersion() == 3);
ASSERT(state.getClientMajorVersion() == 1 || state.getClientMajorVersion() == 2 ||
state.getClientMajorVersion() == 3);
const gl::Caps &caps = state.getCaps();
const gl::Extensions &extensions = state.getExtensions();
......@@ -74,8 +75,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.OES_standard_derivatives = extensions.standardDerivatives;
mResources.EXT_draw_buffers = extensions.drawBuffers;
mResources.EXT_shader_texture_lod = extensions.shaderTextureLOD;
mResources.OES_EGL_image_external = extensions.eglImageExternal;
mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3;
mResources.OES_EGL_image_external = extensions.eglImageExternal;
mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3;
mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal;
mResources.ARB_texture_rectangle = extensions.textureRectangle;
// TODO: use shader precision caps to determine if high precision is supported?
......@@ -124,7 +125,7 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.MaxCombinedAtomicCounterBuffers = caps.maxCombinedAtomicCounterBuffers;
mResources.MaxAtomicCounterBufferSize = caps.maxAtomicCounterBufferSize;
mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings;
mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings;
mResources.MaxShaderStorageBufferBindings = caps.maxShaderStorageBufferBindings;
// Needed by point size clamping workaround
......@@ -144,11 +145,11 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.MaxGeometryOutputVertices = caps.maxGeometryOutputVertices;
mResources.MaxGeometryTotalOutputComponents = caps.maxGeometryTotalOutputComponents;
mResources.MaxGeometryTextureImageUnits = caps.maxShaderTextureImageUnits[ShaderType::Geometry];
mResources.MaxGeometryAtomicCounterBuffers = caps.maxGeometryAtomicCounterBuffers;
mResources.MaxGeometryAtomicCounters = caps.maxGeometryAtomicCounters;
mResources.MaxGeometryShaderStorageBlocks = caps.maxShaderStorageBlocks[ShaderType::Geometry];
mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations;
mResources.MaxGeometryImageUniforms = caps.maxGeometryImageUniforms;
mResources.MaxGeometryAtomicCounterBuffers = caps.maxGeometryAtomicCounterBuffers;
mResources.MaxGeometryAtomicCounters = caps.maxGeometryAtomicCounters;
mResources.MaxGeometryShaderStorageBlocks = caps.maxShaderStorageBlocks[ShaderType::Geometry];
mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations;
mResources.MaxGeometryImageUniforms = caps.maxGeometryImageUniforms;
}
Compiler::~Compiler()
......
......@@ -24,6 +24,7 @@
#include "libANGLE/Fence.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/GLES1Renderer.h"
#include "libANGLE/Path.h"
#include "libANGLE/Program.h"
#include "libANGLE/ProgramPipeline.h"
......@@ -388,6 +389,12 @@ Context::Context(rx::EGLImplFactory *implFactory,
bindBufferRange(BufferBinding::Uniform, i, 0, 0, -1);
}
// Initialize GLES1 renderer if appropriate.
if (getClientVersion() < Version(2, 0))
{
mGLES1Renderer.reset(new GLES1Renderer());
}
// Initialize dirty bit masks
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_STATE);
mTexImageDirtyBits.set(State::DIRTY_BIT_UNPACK_BUFFER_BINDING);
......@@ -431,6 +438,11 @@ Context::Context(rx::EGLImplFactory *implFactory,
egl::Error Context::onDestroy(const egl::Display *display)
{
if (mGLES1Renderer)
{
mGLES1Renderer->onDestroy(this, &mGLState);
}
// Delete the Surface first to trigger a finish() in Vulkan.
if (mSurfacelessFramebuffer)
{
......@@ -3269,6 +3281,11 @@ void Context::initWorkarounds()
Error Context::prepareForDraw()
{
if (mGLES1Renderer)
{
ANGLE_TRY(mGLES1Renderer->prepareForDraw(this, &mGLState));
}
ANGLE_TRY(syncDirtyObjects());
if (isRobustResourceInitEnabled())
......
......@@ -48,19 +48,20 @@ namespace gl
class Buffer;
class Compiler;
class FenceNV;
class Sync;
class Framebuffer;
class GLES1Renderer;
class MemoryProgramCache;
class Program;
class ProgramPipeline;
class Query;
class Renderbuffer;
class Sampler;
class Shader;
class Sync;
class Texture;
class TransformFeedback;
class VertexArray;
struct VertexAttribute;
class ProgramPipeline;
class Context final : angle::NonCopyable
{
......@@ -1458,6 +1459,8 @@ class Context final : angle::NonCopyable
// GLES1 emulation: Renderer level (for validation)
int vertexArrayIndex(ClientVertexArrayType type) const;
static int TexCoordArrayIndex(unsigned int unit);
AttributesMask getVertexArraysAttributeMask() const;
private:
Error prepareForDraw();
......@@ -1556,6 +1559,9 @@ class Context final : angle::NonCopyable
typedef std::set<GLenum> ErrorSet;
mutable ErrorSet mErrors;
// GLES1 renderer state
std::unique_ptr<GLES1Renderer> mGLES1Renderer;
// Current/lost context flags
bool mHasBeenCurrent;
mutable bool mContextLost;
......
......@@ -11,6 +11,8 @@
#include "common/mathutil.h"
#include "common/utilities.h"
#include "libANGLE/GLES1Renderer.h"
namespace
{
......@@ -607,22 +609,18 @@ void Context::texGenxv(GLenum coord, GLenum pname, const GLint *params)
int Context::vertexArrayIndex(ClientVertexArrayType type) const
{
switch (type)
{
case ClientVertexArrayType::Vertex:
return 0;
case ClientVertexArrayType::Normal:
return 1;
case ClientVertexArrayType::Color:
return 2;
case ClientVertexArrayType::PointSize:
return 3;
case ClientVertexArrayType::TextureCoord:
return 4 + mGLState.gles1().getClientTextureUnit();
default:
UNREACHABLE();
return 0;
}
return mGLES1Renderer->vertexArrayIndex(type, &mGLState);
}
// static
int Context::TexCoordArrayIndex(unsigned int unit)
{
return GLES1Renderer::TexCoordArrayIndex(unit);
}
AttributesMask Context::getVertexArraysAttributeMask() const
{
return mGLES1Renderer->getVertexArraysAttributeMask(&mGLState);
}
// static
......
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GLES1Renderer.cpp: Implements the GLES1Renderer renderer.
#include "libANGLE/GLES1Renderer.h"
#include <string.h>
#include <iterator>
#include <sstream>
#include <vector>
#include "libANGLE/Context.h"
#include "libANGLE/Program.h"
#include "libANGLE/ResourceManager.h"
#include "libANGLE/Shader.h"
#include "libANGLE/State.h"
#include "libANGLE/renderer/ContextImpl.h"
namespace
{
#include "libANGLE/GLES1Shaders.inc"
} // anonymous namespace
namespace gl
{
GLES1Renderer::GLES1Renderer() : mRendererProgramInitialized(false)
{
}
void GLES1Renderer::onDestroy(Context *context, State *state)
{
if (mRendererProgramInitialized)
{
state->setProgram(context, 0);
mShaderPrograms->deleteProgram(context, mProgramState.program);
mShaderPrograms->release(context);
mShaderPrograms = nullptr;
mRendererProgramInitialized = false;
}
}
GLES1Renderer::~GLES1Renderer() = default;
Error GLES1Renderer::prepareForDraw(Context *context, State *glState)
{
ANGLE_TRY(initializeRendererProgram(context, glState));
const GLES1State &gles1State = glState->gles1();
Program *programObject = getProgram(mProgramState.program);
GLES1UniformBuffers &uniformBuffers = mUniformBuffers;
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::Normal))
{
const angle::Vector3 normal = gles1State.getCurrentNormal();
context->vertexAttrib3f(kNormalAttribIndex, normal.x(), normal.y(), normal.z());
}
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::Color))
{
const ColorF color = gles1State.getCurrentColor();
context->vertexAttrib4f(kColorAttribIndex, color.red, color.green, color.blue, color.alpha);
}
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::PointSize))
{
GLfloat pointSize = gles1State.mPointParameters.pointSize;
context->vertexAttrib1f(kPointSizeAttribIndex, pointSize);
}
for (int i = 0; i < kTexUnitCount; i++)
{
if (!gles1State.mTexCoordArrayEnabled[i])
{
const TextureCoordF texcoord = gles1State.getCurrentTextureCoords(i);
context->vertexAttrib4f(kTextureCoordAttribIndexBase + i, texcoord.s, texcoord.t,
texcoord.r, texcoord.q);
}
}
{
angle::Mat4 proj = gles1State.mProjectionMatrices.back();
if (mProgramState.projMatrixLoc != -1)
{
programObject->setUniformMatrix4fv(mProgramState.projMatrixLoc, 1, GL_FALSE,
proj.data());
}
angle::Mat4 modelview = gles1State.mModelviewMatrices.back();
if (mProgramState.modelviewMatrixLoc != -1)
{
programObject->setUniformMatrix4fv(mProgramState.modelviewMatrixLoc, 1, GL_FALSE,
modelview.data());
}
angle::Mat4 modelviewInvTr = modelview.transpose().inverse();
if (mProgramState.modelviewInvTrLoc != -1)
{
programObject->setUniformMatrix4fv(mProgramState.modelviewInvTrLoc, 1, GL_FALSE,
modelviewInvTr.data());
}
Mat4Uniform *textureMatrixBuffer = uniformBuffers.textureMatrices.data();
for (int i = 0; i < kTexUnitCount; i++)
{
angle::Mat4 textureMatrix = gles1State.mTextureMatrices[i].back();
memcpy(textureMatrixBuffer + i, textureMatrix.data(), sizeof(Mat4Uniform));
}
if (mProgramState.textureMatrixLoc != -1)
{
programObject->setUniformMatrix4fv(mProgramState.textureMatrixLoc, 4, GL_FALSE,
(float *)uniformBuffers.textureMatrices.data());
}
}
{
std::array<GLint, kTexUnitCount> &tex2DEnables = uniformBuffers.tex2DEnables;
std::array<GLint, kTexUnitCount> &texCubeEnables = uniformBuffers.texCubeEnables;
for (int i = 0; i < kTexUnitCount; i++)
{
// GL_OES_cube_map allows only one of TEXTURE_2D / TEXTURE_CUBE_MAP
// to be enabled per unit, thankfully. From the extension text:
//
// -- Section 3.8.10 "Texture Application"
//
// Replace the beginning sentences of the first paragraph (page 138)
// with:
//
// "Texturing is enabled or disabled using the generic Enable
// and Disable commands, respectively, with the symbolic constants
// TEXTURE_2D or TEXTURE_CUBE_MAP_OES to enable the two-dimensional or cube
// map texturing respectively. If the cube map texture and the two-
// dimensional texture are enabled, then cube map texturing is used. If
// texturing is disabled, a rasterized fragment is passed on unaltered to the
// next stage of the GL (although its texture coordinates may be discarded).
// Otherwise, a texture value is found according to the parameter values of
// the currently bound texture image of the appropriate dimensionality.
texCubeEnables[i] = gles1State.isTextureTargetEnabled(i, TextureType::CubeMap);
tex2DEnables[i] =
!texCubeEnables[i] && (gles1State.isTextureTargetEnabled(i, TextureType::_2D));
}
if (mProgramState.enableTexture2DLoc != -1)
{
programObject->setUniform1iv(mProgramState.enableTexture2DLoc, kTexUnitCount,
tex2DEnables.data());
}
if (mProgramState.enableTextureCubeMapLoc != -1)
{
programObject->setUniform1iv(mProgramState.enableTextureCubeMapLoc, kTexUnitCount,
texCubeEnables.data());
}
GLint flatShading = gles1State.mShadeModel == ShadingModel::Flat;
if (mProgramState.shadeModelFlatLoc != -1)
{
programObject->setUniform1iv(mProgramState.shadeModelFlatLoc, 1, &flatShading);
}
}
// None of those are changes in sampler, so there is no need to set the GL_PROGRAM dirty.
// Otherwise, put the dirtying here.
return NoError();
}
int GLES1Renderer::vertexArrayIndex(ClientVertexArrayType type, const State *glState) const
{
switch (type)
{
case ClientVertexArrayType::Vertex:
return kVertexAttribIndex;
case ClientVertexArrayType::Normal:
return kNormalAttribIndex;
case ClientVertexArrayType::Color:
return kColorAttribIndex;
case ClientVertexArrayType::PointSize:
return kPointSizeAttribIndex;
case ClientVertexArrayType::TextureCoord:
return kTextureCoordAttribIndexBase + glState->gles1().getClientTextureUnit();
default:
UNREACHABLE();
return 0;
}
}
// static
int GLES1Renderer::TexCoordArrayIndex(unsigned int unit)
{
return kTextureCoordAttribIndexBase + unit;
}
AttributesMask GLES1Renderer::getVertexArraysAttributeMask(const State *glState) const
{
AttributesMask res;
const GLES1State &gles1 = glState->gles1();
ClientVertexArrayType nonTexcoordArrays[] = {
ClientVertexArrayType::Vertex, ClientVertexArrayType::Normal, ClientVertexArrayType::Color,
ClientVertexArrayType::PointSize,
};
for (const ClientVertexArrayType attrib : nonTexcoordArrays)
{
res.set(vertexArrayIndex(attrib, glState), gles1.isClientStateEnabled(attrib));
}
for (unsigned int i = 0; i < kTexUnitCount; i++)
{
res.set(TexCoordArrayIndex(i), gles1.isTexCoordArrayEnabled(i));
}
return res;
}
Shader *GLES1Renderer::getShader(GLuint handle) const
{
return mShaderPrograms->getShader(handle);
}
Program *GLES1Renderer::getProgram(GLuint handle) const
{
return mShaderPrograms->getProgram(handle);
}
Error GLES1Renderer::compileShader(Context *context,
ShaderType shaderType,
const char *src,
GLuint *shaderOut)
{
rx::ContextImpl *implementation = context->getImplementation();
const Limitations &limitations = implementation->getNativeLimitations();
GLuint shader = mShaderPrograms->createShader(implementation, limitations, shaderType);
Shader *shaderObject = getShader(shader);
if (!shaderObject)
return InternalError();
shaderObject->setSource(1, &src, nullptr);
shaderObject->compile(context);
*shaderOut = shader;
if (!shaderObject->isCompiled(context))
{
GLint infoLogLength = shaderObject->getInfoLogLength(context);
std::vector<char> infoLog(infoLogLength, 0);
shaderObject->getInfoLog(context, infoLogLength - 1, nullptr, infoLog.data());
fprintf(stderr, "GLES1Renderer::%s: Info log: %s\n", __func__, infoLog.data());
return InternalError() << "GLES1Renderer shader compile failed. Source: " << src
<< " Info log: " << infoLog.data();
}
return NoError();
}
Error GLES1Renderer::linkProgram(Context *context,
State *glState,
GLuint vertexShader,
GLuint fragmentShader,
const std::unordered_map<GLint, std::string> &attribLocs,
GLuint *programOut)
{
GLuint program = mShaderPrograms->createProgram(context->getImplementation());
Program *programObject = getProgram(program);
if (!programObject)
{
return InternalError();
}
*programOut = program;
programObject->attachShader(getShader(vertexShader));
programObject->attachShader(getShader(fragmentShader));
for (auto it : attribLocs)
{
GLint index = it.first;
const std::string &name = it.second;
programObject->bindAttributeLocation(index, name.c_str());
}
ANGLE_TRY(programObject->link(context));
glState->onProgramExecutableChange(programObject);
if (!programObject->isLinked())
{
GLint infoLogLength = programObject->getInfoLogLength();
std::vector<char> infoLog(infoLogLength, 0);
programObject->getInfoLog(infoLogLength - 1, nullptr, infoLog.data());
return InternalError() << "GLES1Renderer program link failed. Info log: " << infoLog.data();
}
programObject->detachShader(context, getShader(vertexShader));
programObject->detachShader(context, getShader(fragmentShader));
return NoError();
}
Error GLES1Renderer::initializeRendererProgram(Context *context, State *glState)
{
if (mRendererProgramInitialized)
{
return NoError();
}
mShaderPrograms = new ShaderProgramManager();
GLuint vertexShader;
GLuint fragmentShader;
ANGLE_TRY(compileShader(context, ShaderType::Vertex, kGLES1DrawVShader, &vertexShader));
std::stringstream fragmentStream;
fragmentStream << kGLES1DrawFShaderHeader;
fragmentStream << kGLES1DrawFShaderUniformDefs;
fragmentStream << kGLES1DrawFShaderFunctions;
fragmentStream << kGLES1DrawFShaderMain;
ANGLE_TRY(compileShader(context, ShaderType::Fragment, fragmentStream.str().c_str(),
&fragmentShader));
std::unordered_map<GLint, std::string> attribLocs;
attribLocs[(GLint)kVertexAttribIndex] = "pos";
attribLocs[(GLint)kNormalAttribIndex] = "normal";
attribLocs[(GLint)kColorAttribIndex] = "color";
attribLocs[(GLint)kPointSizeAttribIndex] = "pointsize";
for (int i = 0; i < kTexUnitCount; i++)
{
std::stringstream ss;
ss << "texcoord" << i;
attribLocs[kTextureCoordAttribIndexBase + i] = ss.str();
}
ANGLE_TRY(linkProgram(context, glState, vertexShader, fragmentShader, attribLocs,
&mProgramState.program));
mShaderPrograms->deleteShader(context, vertexShader);
mShaderPrograms->deleteShader(context, fragmentShader);
Program *programObject = getProgram(mProgramState.program);
mProgramState.projMatrixLoc = programObject->getUniformLocation("projection");
mProgramState.modelviewMatrixLoc = programObject->getUniformLocation("modelview");
mProgramState.textureMatrixLoc = programObject->getUniformLocation("texture_matrix");
mProgramState.modelviewInvTrLoc = programObject->getUniformLocation("modelview_invtr");
for (int i = 0; i < kTexUnitCount; i++)
{
std::stringstream ss2d;
std::stringstream sscube;
ss2d << "tex_sampler" << i;
sscube << "tex_cube_sampler" << i;
mProgramState.tex2DSamplerLocs[i] = programObject->getUniformLocation(ss2d.str().c_str());
mProgramState.texCubeSamplerLocs[i] =
programObject->getUniformLocation(sscube.str().c_str());
}
mProgramState.shadeModelFlatLoc = programObject->getUniformLocation("shade_model_flat");
mProgramState.enableTexture2DLoc = programObject->getUniformLocation("enable_texture_2d");
mProgramState.enableTextureCubeMapLoc =
programObject->getUniformLocation("enable_texture_cube_map");
glState->setProgram(context, programObject);
for (int i = 0; i < kTexUnitCount; i++)
{
if (mProgramState.tex2DSamplerLocs[i] != -1)
{
GLint val = i;
programObject->setUniform1iv(mProgramState.tex2DSamplerLocs[i], 1, &val);
}
if (mProgramState.texCubeSamplerLocs[i] != -1)
{
GLint val = i + kTexUnitCount;
programObject->setUniform1iv(mProgramState.texCubeSamplerLocs[i], 1, &val);
}
}
glState->setObjectDirty(GL_PROGRAM);
mRendererProgramInitialized = true;
return NoError();
}
} // namespace gl
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GLES1Renderer.h: Defines GLES1 emulation rendering operations on top of a GLES3
// context. Used by Context.h.
#ifndef LIBANGLE_GLES1_RENDERER_H_
#define LIBANGLE_GLES1_RENDERER_H_
#include "angle_gl.h"
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
#include <memory>
#include <string>
#include <unordered_map>
namespace gl
{
class Context;
class Program;
class State;
class Shader;
class ShaderProgramManager;
class GLES1Renderer final : angle::NonCopyable
{
public:
GLES1Renderer();
~GLES1Renderer();
void onDestroy(Context *context, State *state);
Error prepareForDraw(Context *context, State *glState);
int vertexArrayIndex(ClientVertexArrayType type, const State *glState) const;
static int TexCoordArrayIndex(unsigned int unit);
AttributesMask getVertexArraysAttributeMask(const State *glState) const;
private:
using Mat4Uniform = float[16];
Shader *getShader(GLuint handle) const;
Program *getProgram(GLuint handle) const;
Error compileShader(Context *context,
ShaderType shaderType,
const char *src,
GLuint *shaderOut);
Error linkProgram(Context *context,
State *glState,
GLuint vshader,
GLuint fshader,
const std::unordered_map<GLint, std::string> &attribLocs,
GLuint *programOut);
Error initializeRendererProgram(Context *context, State *glState);
static constexpr int kTexUnitCount = 4;
static constexpr int kVertexAttribIndex = 0;
static constexpr int kNormalAttribIndex = 1;
static constexpr int kColorAttribIndex = 2;
static constexpr int kPointSizeAttribIndex = 3;
static constexpr int kTextureCoordAttribIndexBase = 4;
bool mRendererProgramInitialized;
ShaderProgramManager *mShaderPrograms;
struct GLES1ProgramState
{
GLuint program;
GLint projMatrixLoc;
GLint modelviewMatrixLoc;
GLint textureMatrixLoc;
GLint modelviewInvTrLoc;
std::array<GLint, kTexUnitCount> tex2DSamplerLocs;
std::array<GLint, kTexUnitCount> texCubeSamplerLocs;
GLint shadeModelFlatLoc;
GLint enableTexture2DLoc;
GLint enableTextureCubeMapLoc;
};
struct GLES1UniformBuffers
{
std::array<Mat4Uniform, kTexUnitCount> textureMatrices;
std::array<GLint, kTexUnitCount> tex2DEnables;
std::array<GLint, kTexUnitCount> texCubeEnables;
};
GLES1UniformBuffers mUniformBuffers;
GLES1ProgramState mProgramState;
};
} // namespace gl
#endif // LIBANGLE_GLES1_RENDERER_H_
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GLES1Shaders.inc: Defines GLES1 emulation shader.
constexpr char kGLES1DrawVShader[] = R"(#version 300 es
precision highp float;
#define kMaxTexUnits 4
in vec4 pos;
in vec3 normal;
in vec4 color;
in float pointsize;
in vec4 texcoord0;
in vec4 texcoord1;
in vec4 texcoord2;
in vec4 texcoord3;
uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 modelview_invtr;
uniform mat4 texture_matrix[4];
out vec4 pos_varying;
out vec3 normal_varying;
out vec4 color_varying;
flat out vec4 color_varying_flat;
out float pointsize_varying;
out vec4 texcoord0_varying;
out vec4 texcoord1_varying;
out vec4 texcoord2_varying;
out vec4 texcoord3_varying;
void main()
{
pos_varying = modelview * pos;
mat3 mvInvTr3 = mat3(modelview_invtr);
normal_varying = mvInvTr3 * normal;
color_varying = color;
color_varying_flat = color;
pointsize_varying = pointsize;
texcoord0_varying = texture_matrix[0] * texcoord0;
texcoord1_varying = texture_matrix[1] * texcoord1;
texcoord2_varying = texture_matrix[2] * texcoord2;
texcoord3_varying = texture_matrix[3] * texcoord3;
vec4 vertexPos = projection * modelview * pos;
gl_Position = vertexPos;
}
)";
// version, flat,
constexpr char kGLES1DrawFShaderHeader[] = R"(#version 300 es
precision highp float;
// Defines for GL constants
#define kMaxLights 8
#define kMaxTexUnits 4
#define kModulate 0x2100
#define kDecal 0x2101
#define kCombine 0x8570
#define kReplace 0x1E01
#define kBlend 0x0BE2
#define kAdd 0x0104
#define kAddSigned 0x8574
#define kInterpolate 0x8575
#define kSubtract 0x84E7
#define kDot3Rgb 0x86AE
#define kDot3Rgba 0x86AF
#define kAlpha 0x1906
#define kRGB 0x1907
#define kRGBA 0x1908
#define kLuminance 0x1909
#define kLuminanceAlpha 0x190A
#define kTexture 0x1702
#define kConstant 0x8576
#define kPrimaryColor 0x8577
#define kPrevious 0x8578
#define kSrcColor 0x0300
#define kOneMinusSrcColor 0x0301
#define kSrcAlpha 0x0302
#define kOneMinusSrcAlpha 0x0303
#define kLinear 0x2601
#define kExp 0x0800
#define kExp2 0x0801
#define kNever 0x0200
#define kLess 0x0201
#define kEqual 0x0202
#define kLequal 0x0203
#define kGreater 0x0204
#define kNotequal 0x0205
#define kGequal 0x0206
#define kAlways 0x0207
#define kZero 0x0
#define kOne 0x1
#define kClear 0x1500
#define kAnd 0x1501
#define kAnd_reverse 0x1502
#define kCopy 0x1503
#define kAnd_inverted 0x1504
#define kNoop 0x1505
#define kXor 0x1506
#define kOr 0x1507
#define kNor 0x1508
#define kEquiv 0x1509
#define kInvert 0x150A
#define kOr_reverse 0x150B
#define kCopy_inverted 0x150C
#define kOr_inverted 0x150D
#define kNand 0x150E
#define kSet 0x150F)";
constexpr char kGLES1DrawFShaderUniformDefs[] = R"(
// Texture units ///////////////////////////////////////////////////////////////
uniform bool enable_texture_2d[kMaxTexUnits];
uniform bool enable_texture_cube_map[kMaxTexUnits];
// These are not arrays because hw support for arrays
// of samplers is rather lacking.
uniform sampler2D tex_sampler0;
uniform samplerCube tex_cube_sampler0;
uniform sampler2D tex_sampler1;
uniform samplerCube tex_cube_sampler1;
uniform sampler2D tex_sampler2;
uniform samplerCube tex_cube_sampler2;
uniform sampler2D tex_sampler3;
uniform samplerCube tex_cube_sampler3;
// Global enables, alpha func, logic op ////////////////////////////////////////
uniform bool shade_model_flat;
// Vertex attributes////////////////////////////////////////////////////////////
in vec4 pos_varying;
in vec3 normal_varying;
in vec4 color_varying;
flat in vec4 color_varying_flat;
in float pointsize_varying;
in vec4 texcoord0_varying;
in vec4 texcoord1_varying;
in vec4 texcoord2_varying;
in vec4 texcoord3_varying;
// Outgoing fragment////////////////////////////////////////////////////////////
out vec4 frag_color;
)";
constexpr char kGLES1DrawFShaderFunctions[] = R"(
bool isTextureUnitEnabled(int unit)
{
return enable_texture_2d[unit] || enable_texture_cube_map[unit];
}
vec4 getTextureColor(int unit)
{
vec4 res;
switch (unit)
{
case 0:
if (enable_texture_2d[0])
{
res = texture(tex_sampler0, texcoord0_varying.xy);
}
else if (enable_texture_cube_map[0])
{
res = texture(tex_cube_sampler0, texcoord0_varying.xyz);
}
break;
case 1:
if (enable_texture_2d[1])
{
res = texture(tex_sampler1, texcoord1_varying.xy);
}
else if (enable_texture_cube_map[1])
{
res = texture(tex_cube_sampler1, texcoord1_varying.xyz);
}
break;
case 2:
if (enable_texture_2d[2])
{
res = texture(tex_sampler2, texcoord2_varying.xy);
}
else if (enable_texture_cube_map[2])
{
res = texture(tex_cube_sampler2, texcoord2_varying.xyz);
}
break;
case 3:
if (enable_texture_2d[3])
{
res = texture(tex_sampler3, texcoord3_varying.xy);
}
else if (enable_texture_cube_map[3])
{
// TODO: Weird stuff happens
// res = texture(tex_cube_sampler3, texcoord3_varying.xyz);
}
break;
default:
break;
}
return res;
}
vec4 getColor(int unit, vec4 vertexColor)
{
if (!isTextureUnitEnabled(unit))
{
return vertexColor;
}
return getTextureColor(unit);
}
)";
constexpr char kGLES1DrawFShaderMain[] = R"(
void main()
{
vec4 currentFragment;
vec4 vertex_color;
if (shade_model_flat)
{
vertex_color = color_varying_flat;
}
else
{
vertex_color = color_varying;
}
// Unit 0 only for now
currentFragment = getColor(0, vertex_color);
frag_color = currentFragment;
}
)";
......@@ -312,6 +312,12 @@ bool GLES1State::isClientStateEnabled(ClientVertexArrayType clientState) const
}
}
bool GLES1State::isTexCoordArrayEnabled(unsigned int unit) const
{
ASSERT(unit < mTexCoordArrayEnabled.size());
return mTexCoordArrayEnabled[unit];
}
bool GLES1State::isTextureTargetEnabled(unsigned int unit, const TextureType type) const
{
return mTexUnitEnables[unit].test(type);
......
......@@ -115,7 +115,9 @@ struct PointParameters
};
class Context;
class GLES1Renderer;
class State;
class GLES1State final : angle::NonCopyable
{
public:
......@@ -152,10 +154,12 @@ class GLES1State final : angle::NonCopyable
void setClientStateEnabled(ClientVertexArrayType clientState, bool enable);
bool isClientStateEnabled(ClientVertexArrayType clientState) const;
bool isTexCoordArrayEnabled(unsigned int unit) const;
bool isTextureTargetEnabled(unsigned int unit, const TextureType type) const;
private:
friend class State;
friend class GLES1Renderer;
// Back pointer for reading from State.
const State *mGLState;
......
......@@ -117,7 +117,10 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi
const auto &vertexAttribs = vao->getVertexAttributes();
const auto &vertexBindings = vao->getVertexBindings();
const AttributesMask &activeAttribs = (program->getActiveAttribLocationsMask() &
bool isGLES1 = context->getClientVersion() < Version(2, 0);
const AttributesMask &activeAttribs = ((isGLES1 ? context->getVertexArraysAttributeMask()
: program->getActiveAttribLocationsMask()) &
vao->getEnabledAttributesMask() & ~clientAttribs);
for (size_t attributeIndex : activeAttribs)
......@@ -126,7 +129,7 @@ bool ValidateDrawAttribs(Context *context, GLint primcount, GLint maxVertex, GLi
ASSERT(attrib.enabled);
const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
ASSERT(program->isAttribLocationActive(attributeIndex));
ASSERT(isGLES1 || program->isAttribLocationActive(attributeIndex));
GLint maxVertexElement = maxVertex;
GLuint divisor = binding.getDivisor();
......@@ -2675,140 +2678,150 @@ bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count)
return false;
}
gl::Program *program = state.getProgram();
if (!program)
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound);
return false;
}
// In OpenGL ES spec for UseProgram at section 7.3, trying to render without
// vertex shader stage or fragment shader stage is a undefined behaviour.
// But ANGLE should clearly generate an INVALID_OPERATION error instead of
// produce undefined result.
if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
!program->hasLinkedShaderStage(ShaderType::Fragment))
// If we are running GLES1, there is no current program.
if (context->getClientVersion() >= Version(2, 0))
{
context->handleError(InvalidOperation() << "It is a undefined behaviour to render without "
"vertex shader stage or fragment shader stage.");
return false;
}
if (!program->validateSamplers(nullptr, context->getCaps()))
{
context->handleError(InvalidOperation());
return false;
}
if (extensions.multiview)
{
const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
const int framebufferNumViews = framebuffer->getNumViews();
if (framebufferNumViews != programNumViews)
gl::Program *program = state.getProgram();
if (!program)
{
context->handleError(InvalidOperation() << "The number of views in the active program "
"and draw framebuffer does not match.");
ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound);
return false;
}
const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
framebufferNumViews > 1)
// In OpenGL ES spec for UseProgram at section 7.3, trying to render without
// vertex shader stage or fragment shader stage is a undefined behaviour.
// But ANGLE should clearly generate an INVALID_OPERATION error instead of
// produce undefined result.
if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
!program->hasLinkedShaderStage(ShaderType::Fragment))
{
context->handleError(InvalidOperation()
<< "There is an active transform feedback object "
"when the number of views in the active draw "
"framebuffer is greater than 1.");
<< "It is a undefined behaviour to render without "
"vertex shader stage or fragment shader stage.");
return false;
}
if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
state.isQueryActive(QueryType::TimeElapsed))
if (!program->validateSamplers(nullptr, context->getCaps()))
{
context->handleError(InvalidOperation() << "There is an active query for target "
"GL_TIME_ELAPSED_EXT when the number of "
"views in the active draw framebuffer is "
"greater than 1.");
context->handleError(InvalidOperation());
return false;
}
}
// Do geometry shader specific validations
if (program->hasLinkedShaderStage(ShaderType::Geometry))
{
if (!IsCompatibleDrawModeWithGeometryShader(mode,
program->getGeometryShaderInputPrimitiveType()))
if (extensions.multiview)
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(),
IncompatibleDrawModeAgainstGeometryShader);
return false;
}
}
const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
const int framebufferNumViews = framebuffer->getNumViews();
if (framebufferNumViews != programNumViews)
{
context->handleError(InvalidOperation()
<< "The number of views in the active program "
"and draw framebuffer does not match.");
return false;
}
// Uniform buffer validation
for (unsigned int uniformBlockIndex = 0;
uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
const gl::InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
const OffsetBindingPointer<Buffer> &uniformBuffer =
state.getIndexedUniformBuffer(blockBinding);
const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
framebufferNumViews > 1)
{
context->handleError(InvalidOperation()
<< "There is an active transform feedback object "
"when the number of views in the active draw "
"framebuffer is greater than 1.");
return false;
}
if (uniformBuffer.get() == nullptr)
{
// undefined behaviour
context->handleError(
InvalidOperation()
<< "It is undefined behaviour to have a used but unbound uniform buffer.");
return false;
if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
state.isQueryActive(QueryType::TimeElapsed))
{
context->handleError(InvalidOperation()
<< "There is an active query for target "
"GL_TIME_ELAPSED_EXT when the number of "
"views in the active draw framebuffer is "
"greater than 1.");
return false;
}
}
size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
if (uniformBufferSize < uniformBlock.dataSize)
// Do geometry shader specific validations
if (program->hasLinkedShaderStage(ShaderType::Geometry))
{
// undefined behaviour
context->handleError(
InvalidOperation()
<< "It is undefined behaviour to use a uniform buffer that is too small.");
return false;
if (!IsCompatibleDrawModeWithGeometryShader(
mode, program->getGeometryShaderInputPrimitiveType()))
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(),
IncompatibleDrawModeAgainstGeometryShader);
return false;
}
}
if (extensions.webglCompatibility &&
uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
// Uniform buffer validation
for (unsigned int uniformBlockIndex = 0;
uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(),
UniformBufferBoundForTransformFeedback);
return false;
}
}
const gl::InterfaceBlock &uniformBlock =
program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
const OffsetBindingPointer<Buffer> &uniformBuffer =
state.getIndexedUniformBuffer(blockBinding);
// Do some additonal WebGL-specific validation
if (extensions.webglCompatibility)
{
const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
transformFeedbackObject->buffersBoundForOtherUse())
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(), TransformFeedbackBufferDoubleBound);
return false;
}
// Detect rendering feedback loops for WebGL.
if (framebuffer->formsRenderingFeedbackLoopWith(state))
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop);
return false;
}
if (uniformBuffer.get() == nullptr)
{
// undefined behaviour
context->handleError(
InvalidOperation()
<< "It is undefined behaviour to have a used but unbound uniform buffer.");
return false;
}
// Detect that the vertex shader input types match the attribute types
if (!ValidateVertexShaderAttributeTypeMatch(context))
{
return false;
size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
if (uniformBufferSize < uniformBlock.dataSize)
{
// undefined behaviour
context->handleError(
InvalidOperation()
<< "It is undefined behaviour to use a uniform buffer that is too small.");
return false;
}
if (extensions.webglCompatibility &&
uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(),
UniformBufferBoundForTransformFeedback);
return false;
}
}
// Detect that the color buffer types match the fragment shader output types
if (!ValidateFragmentShaderColorBufferTypeMatch(context))
// Do some additonal WebGL-specific validation
if (extensions.webglCompatibility)
{
return false;
const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
if (transformFeedbackObject != nullptr && transformFeedbackObject->isActive() &&
transformFeedbackObject->buffersBoundForOtherUse())
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(),
TransformFeedbackBufferDoubleBound);
return false;
}
// Detect rendering feedback loops for WebGL.
if (framebuffer->formsRenderingFeedbackLoopWith(state))
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(), FeedbackLoop);
return false;
}
// Detect that the vertex shader input types match the attribute types
if (!ValidateVertexShaderAttributeTypeMatch(context))
{
return false;
}
// Detect that the color buffer types match the fragment shader output types
if (!ValidateFragmentShaderColorBufferTypeMatch(context))
{
return false;
}
}
}
......
......@@ -167,6 +167,7 @@
'libANGLE/Framebuffer.h',
'libANGLE/FramebufferAttachment.cpp',
'libANGLE/FramebufferAttachment.h',
'libANGLE/GLES1Renderer.cpp',
'libANGLE/GLES1State.cpp',
'libANGLE/HandleAllocator.cpp',
'libANGLE/HandleAllocator.h',
......
......@@ -48,6 +48,7 @@
'<(angle_path)/src/tests/gl_tests/FramebufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/GeometryShaderTest.cpp',
'<(angle_path)/src/tests/gl_tests/gles1/AlphaFuncTest.cpp',
'<(angle_path)/src/tests/gl_tests/gles1/BasicDrawTest.cpp',
'<(angle_path)/src/tests/gl_tests/gles1/ClientActiveTextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/gles1/ClientStateEnable.cpp',
'<(angle_path)/src/tests/gl_tests/gles1/CurrentColorTest.cpp',
......
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// BasicDrawTest.cpp: Tests basic fullscreen quad draw with and without
// GL_TEXTURE_2D enabled.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include <vector>
using namespace angle;
class BasicDrawTest : public ANGLETest
{
protected:
BasicDrawTest()
{
setWindowWidth(32);
setWindowHeight(32);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
}
std::vector<float> mPositions = {
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
};
void drawRedQuad()
{
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
EXPECT_GL_NO_ERROR();
glEnableClientState(GL_VERTEX_ARRAY);
EXPECT_GL_NO_ERROR();
glVertexPointer(2, GL_FLOAT, 0, mPositions.data());
EXPECT_GL_NO_ERROR();
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
};
// Draws a fullscreen quad with a certain color.
TEST_P(BasicDrawTest, DrawColor)
{
drawRedQuad();
}
// Checks that textures can be enabled or disabled.
TEST_P(BasicDrawTest, EnableDisableTexture)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
// Green
GLubyte texture[] = {
0x00, 0xff, 0x00,
};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
// Texturing is disabled; still red;
drawRedQuad();
// Texturing enabled; is green.
glEnable(GL_TEXTURE_2D);
EXPECT_GL_NO_ERROR();
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
ANGLE_INSTANTIATE_TEST(BasicDrawTest, ES1_D3D11(), ES1_OPENGL(), ES1_OPENGLES());
......@@ -173,25 +173,21 @@ TEST_P(GLES1ConformanceTest, AtnPos)
TEST_P(GLES1ConformanceTest, BClear)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, BClearExec());
}
TEST_P(GLES1ConformanceTest, BColor)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, BColorExec());
}
TEST_P(GLES1ConformanceTest, BCorner)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, BCornerExec());
}
TEST_P(GLES1ConformanceTest, Blend)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, BlendExec());
}
......@@ -203,7 +199,6 @@ TEST_P(GLES1ConformanceTest, Clip)
TEST_P(GLES1ConformanceTest, ColRamp)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ColRampExec());
}
......@@ -239,7 +234,6 @@ TEST_P(GLES1ConformanceTest, DifMatPos)
TEST_P(GLES1ConformanceTest, Dither)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, DitherExec());
}
......@@ -275,13 +269,11 @@ TEST_P(GLES1ConformanceTest, LineAntiAlias)
TEST_P(GLES1ConformanceTest, LineHV)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, LineHVExec());
}
TEST_P(GLES1ConformanceTest, LineRaster)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, LineRasterExec());
}
......@@ -317,13 +309,11 @@ TEST_P(GLES1ConformanceTest, MipSelect)
TEST_P(GLES1ConformanceTest, Mask)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, MaskExec());
}
TEST_P(GLES1ConformanceTest, MatrixStack)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, MatrixStackExec());
}
......@@ -359,13 +349,11 @@ TEST_P(GLES1ConformanceTest, PointRaster)
TEST_P(GLES1ConformanceTest, PolyCull)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, PolyCullExec());
}
TEST_P(GLES1ConformanceTest, ReadFormat)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ReadFormatExec());
}
......@@ -377,19 +365,16 @@ TEST_P(GLES1ConformanceTest, RescaleNormal)
TEST_P(GLES1ConformanceTest, Scissor)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ScissorExec());
}
TEST_P(GLES1ConformanceTest, SPClear)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, SPClearExec());
}
TEST_P(GLES1ConformanceTest, SPCorner)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, SPCornerExec());
}
......@@ -425,13 +410,11 @@ TEST_P(GLES1ConformanceTest, SpecNorm)
TEST_P(GLES1ConformanceTest, SPFunc)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, SPFuncExec());
}
TEST_P(GLES1ConformanceTest, SPOp)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, SPOpExec());
}
......@@ -473,25 +456,21 @@ TEST_P(GLES1ConformanceTest, TextureEdgeClamp)
TEST_P(GLES1ConformanceTest, TriRaster)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, TriRasterExec());
}
TEST_P(GLES1ConformanceTest, TriTile)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, TriTileExec());
}
TEST_P(GLES1ConformanceTest, VertexOrder)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, VertexOrderExec());
}
TEST_P(GLES1ConformanceTest, ViewportClamp)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ViewportClampExec());
}
......@@ -503,7 +482,6 @@ TEST_P(GLES1ConformanceTest, XForm)
TEST_P(GLES1ConformanceTest, XFormMix)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, XFormMixExec());
}
......@@ -527,25 +505,21 @@ TEST_P(GLES1ConformanceTest, XFormHomogenous)
TEST_P(GLES1ConformanceTest, ZBClear)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ZBClearExec());
}
TEST_P(GLES1ConformanceTest, ZBFunc)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, ZBFuncExec());
}
TEST_P(GLES1ConformanceTest, DrawTex)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, DrawTexExec());
}
TEST_P(GLES1ConformanceTest, MatrixQuery)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, MatrixQueryExec());
}
......@@ -575,7 +549,6 @@ TEST_P(GLES1ConformanceTest, UserClip)
TEST_P(GLES1ConformanceTest, MatrixGetTest)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, MatrixGetTestExec());
}
......@@ -593,7 +566,6 @@ TEST_P(GLES1ConformanceTest, TexCombine)
TEST_P(GLES1ConformanceTest, MatrixPalette)
{
ANGLE_SKIP_TEST_IF(true);
ASSERT_NE(CONFORMANCE_TEST_ERROR, MatrixPaletteExec());
}
......
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