You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
8.2 KiB
246 lines
8.2 KiB
// Copyright (C) 2018 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "GLSnapshotTesting.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <string>
|
|
|
|
namespace emugl {
|
|
|
|
static const char kTestVertexShaderSource[] = R"(
|
|
attribute vec4 position;
|
|
uniform mat4 projection;
|
|
uniform mat4 transform;
|
|
uniform mat4 screenSpace;
|
|
varying float linear;
|
|
void main(void) {
|
|
vec4 transformedPosition = projection * transform * position;
|
|
gl_Position = transformedPosition;
|
|
linear = (screenSpace * position).x;
|
|
}
|
|
)";
|
|
|
|
static const char kTestFragmentShaderSource[] = R"(
|
|
precision mediump float;
|
|
void main() {
|
|
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}
|
|
)";
|
|
|
|
struct GlShaderState {
|
|
GLenum type;
|
|
GLboolean deleteStatus;
|
|
GLboolean compileStatus;
|
|
GLint infoLogLength;
|
|
std::vector<GLchar> infoLog;
|
|
GLint sourceLength;
|
|
std::string source;
|
|
};
|
|
|
|
// SnapshotGlShaderTest - A helper class for testing snapshot's preservation of
|
|
// a GL shader object's states.
|
|
//
|
|
// It operates like SnapshotPreserveTest, and also holds information about a
|
|
// particular shader object which is manipulated in tests using
|
|
// SnapshotGlShaderTest as a fixture.
|
|
// Helper functions like loadSource first need a created shader identified by
|
|
// |m_shader_name|. This creation happens by default in stateChange. Use them in
|
|
// a lambda, set through setShaderStateChanger, to set up state without
|
|
// overriding doCheckedSnapshot.
|
|
//
|
|
class SnapshotGlShaderTest : public SnapshotPreserveTest {
|
|
public:
|
|
void defaultStateCheck() override {
|
|
EXPECT_EQ(GL_FALSE, gl->glIsShader(m_shader_name));
|
|
}
|
|
|
|
void changedStateCheck() override {
|
|
SCOPED_TRACE("for shader " + std::to_string(m_shader_name));
|
|
|
|
EXPECT_TRUE(compareParameter(GL_SHADER_TYPE, m_shader_state.type));
|
|
EXPECT_TRUE(compareParameter(GL_DELETE_STATUS,
|
|
m_shader_state.deleteStatus));
|
|
EXPECT_TRUE(compareParameter(GL_COMPILE_STATUS,
|
|
m_shader_state.compileStatus));
|
|
EXPECT_TRUE(compareParameter(GL_INFO_LOG_LENGTH,
|
|
m_shader_state.infoLogLength));
|
|
EXPECT_TRUE(compareParameter(GL_SHADER_SOURCE_LENGTH,
|
|
m_shader_state.sourceLength));
|
|
|
|
std::vector<GLchar> srcData = {};
|
|
srcData.resize(m_shader_state.sourceLength);
|
|
gl->glGetShaderSource(m_shader_name, m_shader_state.sourceLength,
|
|
nullptr, srcData.data());
|
|
if (srcData.data() == NULL) {
|
|
EXPECT_EQ(0, m_shader_state.source.length()) << "source is empty";
|
|
} else {
|
|
EXPECT_STREQ(m_shader_state.source.c_str(), srcData.data());
|
|
}
|
|
|
|
std::vector<GLchar> infoLogData = {};
|
|
infoLogData.resize(m_shader_state.infoLogLength);
|
|
gl->glGetShaderInfoLog(m_shader_name, m_shader_state.infoLogLength,
|
|
nullptr, infoLogData.data());
|
|
if (infoLogData.data() == NULL) {
|
|
EXPECT_EQ(0, m_shader_state.infoLogLength) << "info log is empty";
|
|
} else {
|
|
EXPECT_STREQ(m_shader_state.infoLog.data(), infoLogData.data());
|
|
}
|
|
}
|
|
|
|
void stateChange() override {
|
|
m_shader_name = gl->glCreateShader(m_shader_state.type);
|
|
m_shader_state_changer();
|
|
|
|
// Store state of info log
|
|
gl->glGetShaderiv(m_shader_name, GL_INFO_LOG_LENGTH,
|
|
&m_shader_state.infoLogLength);
|
|
m_shader_state.infoLog.resize(m_shader_state.infoLogLength);
|
|
gl->glGetShaderInfoLog(m_shader_name, m_shader_state.infoLogLength,
|
|
nullptr, m_shader_state.infoLog.data());
|
|
}
|
|
|
|
void loadSource(const std::string& sourceString) {
|
|
GLboolean compiler;
|
|
gl->glGetBooleanv(GL_SHADER_COMPILER, &compiler);
|
|
EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
|
|
if (compiler == GL_FALSE) {
|
|
fprintf(stderr, "Shader compiler is not supported.\n");
|
|
return;
|
|
}
|
|
|
|
if (m_shader_name == 0) {
|
|
FAIL() << "Cannot set source without a shader name";
|
|
}
|
|
m_shader_state.source = sourceString;
|
|
GLint len = sourceString.length();
|
|
if (len > 0) {
|
|
m_shader_state.sourceLength =
|
|
len + 1; // Counts the null terminator
|
|
}
|
|
const char* source = sourceString.c_str();
|
|
const char** sources = &source;
|
|
gl->glShaderSource(m_shader_name, 1, sources, &len);
|
|
EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
|
|
}
|
|
|
|
void compile(GLboolean expectCompileStatus = GL_TRUE) {
|
|
GLboolean compiler;
|
|
gl->glGetBooleanv(GL_SHADER_COMPILER, &compiler);
|
|
if (compiler == GL_FALSE) {
|
|
fprintf(stderr, "Shader compiler is not supported.\n");
|
|
return;
|
|
}
|
|
|
|
if (m_shader_name == 0) {
|
|
ADD_FAILURE() << "Cannot compile shader without a shader name";
|
|
}
|
|
if (m_shader_state.source.length() == 0) {
|
|
ADD_FAILURE() << "Shader needs source to compile";
|
|
}
|
|
gl->glCompileShader(m_shader_name);
|
|
m_shader_state.compileStatus = expectCompileStatus;
|
|
}
|
|
|
|
// Supply a lambda as |changer| to perform additional state setup after the
|
|
// shader has been created but before the snapshot is performed.
|
|
void setShaderStateChanger(std::function<void()> changer) {
|
|
m_shader_state_changer = changer;
|
|
}
|
|
|
|
protected:
|
|
testing::AssertionResult compareParameter(GLenum paramName,
|
|
GLenum expected) {
|
|
GLint value;
|
|
gl->glGetShaderiv(m_shader_name, paramName, &value);
|
|
EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
|
|
return compareValue<GLint>(
|
|
expected, value,
|
|
"mismatch on parameter " + describeGlEnum(paramName) +
|
|
" for shader " + std::to_string(m_shader_name));
|
|
}
|
|
|
|
GlShaderState m_shader_state = {};
|
|
GLuint m_shader_name;
|
|
std::function<void()> m_shader_state_changer = [] {};
|
|
};
|
|
|
|
class SnapshotGlVertexShaderTest : public SnapshotGlShaderTest {
|
|
public:
|
|
SnapshotGlVertexShaderTest() { m_shader_state = {GL_VERTEX_SHADER}; }
|
|
};
|
|
|
|
TEST_F(SnapshotGlVertexShaderTest, Create) {
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlVertexShaderTest, SetSource) {
|
|
setShaderStateChanger(
|
|
[this] { loadSource(std::string(kTestVertexShaderSource)); });
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlVertexShaderTest, CompileSuccess) {
|
|
setShaderStateChanger([this] {
|
|
loadSource(std::string(kTestVertexShaderSource));
|
|
compile();
|
|
});
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlVertexShaderTest, CompileFail) {
|
|
std::string failedShader = "vec3 hi my name is compile failed";
|
|
setShaderStateChanger([this, &failedShader] {
|
|
loadSource(failedShader);
|
|
compile(GL_FALSE);
|
|
});
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
class SnapshotGlFragmentShaderTest : public SnapshotGlShaderTest {
|
|
public:
|
|
SnapshotGlFragmentShaderTest() { m_shader_state = {GL_FRAGMENT_SHADER}; }
|
|
};
|
|
|
|
TEST_F(SnapshotGlFragmentShaderTest, Create) {
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlFragmentShaderTest, SetSource) {
|
|
setShaderStateChanger(
|
|
[this] { loadSource(std::string(kTestFragmentShaderSource)); });
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlFragmentShaderTest, CompileSuccess) {
|
|
setShaderStateChanger([this] {
|
|
loadSource(std::string(kTestFragmentShaderSource));
|
|
compile();
|
|
});
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
TEST_F(SnapshotGlFragmentShaderTest, CompileFail) {
|
|
std::string failedShader = "vec3 nice to meet you compile failed";
|
|
setShaderStateChanger([this, &failedShader] {
|
|
loadSource(failedShader);
|
|
compile(GL_FALSE);
|
|
});
|
|
doCheckedSnapshot();
|
|
}
|
|
|
|
} // namespace emugl
|