mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-07 06:09:57 +03:00
Variable collection is invariably enabled by the front-end as well as other major users of ANGLE such as Firefox. All translator backends except GLSL force-enable variable collection either way. This change removes this compile option and enables variable collection unconditionally. The flag itself remains in ShCompileOptions until references to it are removed from Chromium. Bug: chromium:1447314 Change-Id: I4d3b30c1bfbd345c5ad269abc62c0a6a59de2f56 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4568524 Auto-Submit: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>
661 lines
23 KiB
C++
661 lines
23 KiB
C++
//
|
|
// Copyright 2022 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.
|
|
//
|
|
|
|
#include "test_utils/ANGLETest.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "GLSLANG/ShaderLang.h"
|
|
#include "test_utils/gl_raii.h"
|
|
|
|
using namespace angle;
|
|
|
|
class ShaderBinaryTest : public ANGLETest<>
|
|
{
|
|
protected:
|
|
ShaderBinaryTest()
|
|
{
|
|
setWindowWidth(128);
|
|
setWindowHeight(128);
|
|
setConfigRedBits(8);
|
|
setConfigGreenBits(8);
|
|
setConfigBlueBits(8);
|
|
setConfigAlphaBits(8);
|
|
|
|
// Test flakiness was noticed when reusing displays.
|
|
forceNewDisplay();
|
|
}
|
|
|
|
void testSetUp() override
|
|
{
|
|
ASSERT_EQ(sh::Initialize(), true);
|
|
|
|
mCompileOptions.objectCode = true;
|
|
mCompileOptions.emulateGLDrawID = true;
|
|
mCompileOptions.initializeUninitializedLocals = true;
|
|
|
|
sh::InitBuiltInResources(&mResources);
|
|
|
|
// Generate a shader binary:
|
|
ShShaderSpec spec = SH_GLES2_SPEC;
|
|
ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
|
|
|
|
// Vertex shader:
|
|
const char *source = essl1_shaders::vs::Simple();
|
|
ShHandle vertexCompiler =
|
|
sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
|
|
bool compileResult =
|
|
sh::GetShaderBinary(vertexCompiler, &source, 1, mCompileOptions, &mVertexShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (mVertexShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating vertex shader binary failed.";
|
|
}
|
|
|
|
// Fragment shader:
|
|
source = essl1_shaders::fs::Red();
|
|
ShHandle fragmentCompiler =
|
|
sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
|
|
compileResult = sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions,
|
|
&mFragmentShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (mFragmentShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating fragment shader binary failed.";
|
|
}
|
|
}
|
|
|
|
void testTearDown() override
|
|
{
|
|
sh::Finalize();
|
|
glDeleteBuffers(1, &mBuffer);
|
|
}
|
|
|
|
bool supported() const
|
|
{
|
|
GLint formatCount;
|
|
glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &formatCount);
|
|
if (formatCount == 0)
|
|
{
|
|
std::cout << "Test skipped because no program binary formats are available."
|
|
<< std::endl;
|
|
return false;
|
|
}
|
|
std::vector<GLint> formats(formatCount);
|
|
glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats.data());
|
|
|
|
ASSERT(formats[0] == GL_SHADER_BINARY_ANGLE);
|
|
|
|
return true;
|
|
}
|
|
|
|
ShCompileOptions mCompileOptions = {};
|
|
ShBuiltInResources mResources;
|
|
GLuint mBuffer;
|
|
sh::ShaderBinaryBlob mVertexShaderBinary;
|
|
sh::ShaderBinaryBlob mFragmentShaderBinary;
|
|
};
|
|
|
|
// This tests the ability to successfully create and load a shader binary.
|
|
TEST_P(ShaderBinaryTest, CreateAndLoadBinary)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
|
|
GLint compileResult;
|
|
// Create vertex shader and load binary
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
// Create fragment shader and load binary
|
|
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
|
|
mFragmentShaderBinary.size());
|
|
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
// Create program from the shaders
|
|
GLuint newProgram = glCreateProgram();
|
|
glAttachShader(newProgram, vertShader);
|
|
glAttachShader(newProgram, fragShader);
|
|
glLinkProgram(newProgram);
|
|
newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
|
|
|
|
// Test with a basic draw
|
|
drawQuad(newProgram, "a_position", 0.5f);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
}
|
|
|
|
// Check invalid gl call parameters, such as providing a GL type when a shader handle is expected.
|
|
TEST_P(ShaderBinaryTest, InvalidCallParams)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
|
|
GLuint vertShader[2];
|
|
vertShader[0] = glCreateShader(GL_VERTEX_SHADER);
|
|
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
// Invalid shader
|
|
vertShader[1] = -1;
|
|
glShaderBinary(1, &vertShader[1], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_VALUE);
|
|
|
|
// GL_INVALID_ENUM is generated if binaryFormat is not an accepted value.
|
|
glShaderBinary(1, &vertShader[0], GL_INVALID_ENUM, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_ENUM);
|
|
|
|
// GL_INVALID_VALUE is generated if n or length is negative
|
|
glShaderBinary(-1, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_VALUE);
|
|
glShaderBinary(1, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(), -1);
|
|
EXPECT_GL_ERROR(GL_INVALID_VALUE);
|
|
|
|
// GL_INVALID_OPERATION is generated if any value in shaders is not a shader object.
|
|
GLuint program = glCreateProgram();
|
|
glShaderBinary(1, &program, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
|
|
|
// GL_INVALID_OPERATION is generated if more than one of the handles in shaders refers to the
|
|
// same shader object.
|
|
vertShader[1] = vertShader[0];
|
|
glShaderBinary(2, &vertShader[0], GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
|
|
|
// GL_INVALID_VALUE is generated if the data pointed to by binary does not match the format
|
|
// specified by binaryFormat.
|
|
std::string invalid("Invalid Shader Blob.");
|
|
glShaderBinary(1, &vertShader[0], GL_SHADER_BINARY_ANGLE, invalid.data(), invalid.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_VALUE);
|
|
|
|
// Try loading vertex shader binary into fragment shader
|
|
glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
|
}
|
|
|
|
// Check attempting to get source code from a shader that was loaded with glShaderBinary.
|
|
TEST_P(ShaderBinaryTest, GetSourceFromBinaryShader)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
|
|
GLint compileResult;
|
|
// Create vertex shader and load binary
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
GLsizei length = 0;
|
|
glGetShaderSource(vertShader, 0, &length, nullptr);
|
|
|
|
EXPECT_EQ(length, 0);
|
|
}
|
|
|
|
// Create a program from both shader source code and a binary blob.
|
|
TEST_P(ShaderBinaryTest, CombineSourceAndBinaryShaders)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
|
|
GLint compileResult;
|
|
// Create vertex shader and load binary
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
// Create fragment shader
|
|
GLuint fragShader = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Red());
|
|
|
|
GLuint newProgram = glCreateProgram();
|
|
glAttachShader(newProgram, vertShader);
|
|
glAttachShader(newProgram, fragShader);
|
|
glLinkProgram(newProgram);
|
|
newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
|
|
|
|
// Test with a basic draw
|
|
drawQuad(newProgram, "a_position", 0.5f);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
}
|
|
|
|
// Test that shaders loaded with glShaderBinary do not cause false hits in the program cache.
|
|
TEST_P(ShaderBinaryTest, ProgramCacheWithShaderBinary)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
|
|
|
|
GLint compileResult;
|
|
// Create vertex shader that will be shared between the programs
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
// Create a program with a red vertex shader
|
|
GLuint fragShaderRed = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderBinary(1, &fragShaderRed, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
|
|
mFragmentShaderBinary.size());
|
|
glGetShaderiv(fragShaderRed, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
GLuint programRed = glCreateProgram();
|
|
glAttachShader(programRed, vertShader);
|
|
glAttachShader(programRed, fragShaderRed);
|
|
glLinkProgram(programRed);
|
|
programRed = CheckLinkStatusAndReturnProgram(programRed, true);
|
|
|
|
// Test with a basic draw
|
|
drawQuad(programRed, "a_position", 0.5f);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
|
|
// Create a program with a blue fragment shader, also loaded from a binary
|
|
ShShaderSpec spec = SH_GLES2_SPEC;
|
|
ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
|
|
|
|
const char *source = essl1_shaders::fs::Blue();
|
|
sh::ShaderBinaryBlob fragShaderBlueData;
|
|
ShHandle fragmentCompiler =
|
|
sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
|
|
bool binaryCompileResult =
|
|
sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions, &fragShaderBlueData);
|
|
ASSERT_TRUE(binaryCompileResult);
|
|
if (fragShaderBlueData.size() == 0)
|
|
{
|
|
FAIL() << "Creating fragment shader binary failed.";
|
|
}
|
|
|
|
GLuint fragShaderBlue = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderBinary(1, &fragShaderBlue, GL_SHADER_BINARY_ANGLE, fragShaderBlueData.data(),
|
|
fragShaderBlueData.size());
|
|
glGetShaderiv(fragShaderBlue, GL_COMPILE_STATUS, &compileResult);
|
|
ASSERT_GL_TRUE(compileResult);
|
|
|
|
GLuint programBlue = glCreateProgram();
|
|
glAttachShader(programBlue, vertShader);
|
|
glAttachShader(programBlue, fragShaderBlue);
|
|
glLinkProgram(programBlue);
|
|
programBlue = CheckLinkStatusAndReturnProgram(programBlue, true);
|
|
|
|
// The program cache should miss and create a new program
|
|
drawQuad(programBlue, "a_position", 0.5f);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
|
|
}
|
|
|
|
class ShaderBinaryTestES31 : public ShaderBinaryTest
|
|
{
|
|
protected:
|
|
void testSetUp() override
|
|
{
|
|
ASSERT_EQ(sh::Initialize(), true);
|
|
|
|
mCompileOptions.objectCode = true;
|
|
mCompileOptions.emulateGLDrawID = true;
|
|
mCompileOptions.initializeUninitializedLocals = true;
|
|
|
|
sh::InitBuiltInResources(&mResources);
|
|
mResources.EXT_geometry_shader = 1;
|
|
mResources.EXT_tessellation_shader = 1;
|
|
|
|
// Generate a shader binary:
|
|
ShShaderSpec spec = SH_GLES3_1_SPEC;
|
|
ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
|
|
|
|
// Vertex shader:
|
|
const char *source = essl31_shaders::vs::Simple();
|
|
ShHandle vertexCompiler =
|
|
sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
|
|
bool compileResult =
|
|
sh::GetShaderBinary(vertexCompiler, &source, 1, mCompileOptions, &mVertexShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (mVertexShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating vertex shader binary failed.";
|
|
}
|
|
|
|
// Fragment shader:
|
|
source = essl31_shaders::fs::Red();
|
|
ShHandle fragmentCompiler =
|
|
sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
|
|
compileResult = sh::GetShaderBinary(fragmentCompiler, &source, 1, mCompileOptions,
|
|
&mFragmentShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (mFragmentShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating fragment shader binary failed.";
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test all shader stages
|
|
TEST_P(ShaderBinaryTestES31, AllShaderStages)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
|
|
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
|
|
|
|
const char *kGS = R"(#version 310 es
|
|
#extension GL_EXT_geometry_shader : require
|
|
precision mediump float;
|
|
|
|
layout (triangles) in;
|
|
layout (triangle_strip, max_vertices = 3) out;
|
|
|
|
void main() {
|
|
gl_Position = gl_in[0].gl_Position;
|
|
EmitVertex();
|
|
|
|
gl_Position = gl_in[1].gl_Position;
|
|
EmitVertex();
|
|
|
|
gl_Position = gl_in[2].gl_Position;
|
|
EmitVertex();
|
|
|
|
EndPrimitive();
|
|
}
|
|
)";
|
|
|
|
const char *kTCS = R"(#version 310 es
|
|
#extension GL_EXT_tessellation_shader : require
|
|
precision mediump float;
|
|
|
|
layout (vertices = 1) out;
|
|
|
|
void main()
|
|
{
|
|
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
|
|
gl_TessLevelInner[0] = 1.0;
|
|
gl_TessLevelInner[1] = 1.0;
|
|
gl_TessLevelOuter[0] = 1.0;
|
|
gl_TessLevelOuter[1] = 1.0;
|
|
gl_TessLevelOuter[2] = 1.0;
|
|
gl_TessLevelOuter[3] = 1.0;
|
|
}
|
|
|
|
)";
|
|
|
|
const char *kTES = R"(#version 310 es
|
|
#extension GL_EXT_tessellation_shader : require
|
|
precision mediump float;
|
|
|
|
layout (quads, cw, fractional_odd_spacing) in;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = vec4(gl_TessCoord.xy * 2. - 1., 0, 1);
|
|
}
|
|
)";
|
|
|
|
// Generate a shader binary for geo, tcs, tes:
|
|
ShShaderSpec spec = SH_GLES3_1_SPEC;
|
|
ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
|
|
mResources.EXT_geometry_shader = 1;
|
|
mResources.EXT_tessellation_shader = 1;
|
|
|
|
// Geometry shader:
|
|
sh::ShaderBinaryBlob geometryShaderBinary;
|
|
ShHandle geometryCompiler =
|
|
sh::ConstructCompiler(GL_GEOMETRY_SHADER, spec, output, &mResources);
|
|
bool compileResult =
|
|
sh::GetShaderBinary(geometryCompiler, &kGS, 1, mCompileOptions, &geometryShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
if (geometryShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating geometry shader binary failed.";
|
|
}
|
|
|
|
// tesselation control shader:
|
|
sh::ShaderBinaryBlob tessControlShaderBinary;
|
|
ShHandle tessControlCompiler =
|
|
sh::ConstructCompiler(GL_TESS_CONTROL_SHADER, spec, output, &mResources);
|
|
compileResult = sh::GetShaderBinary(tessControlCompiler, &kTCS, 1, mCompileOptions,
|
|
&tessControlShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
if (tessControlShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating tesselation control shader binary failed.";
|
|
}
|
|
|
|
// tesselation evaluation shader:
|
|
sh::ShaderBinaryBlob tessEvaluationShaderBinary;
|
|
ShHandle tessEvaluationCompiler =
|
|
sh::ConstructCompiler(GL_TESS_EVALUATION_SHADER, spec, output, &mResources);
|
|
compileResult = sh::GetShaderBinary(tessEvaluationCompiler, &kTES, 1, mCompileOptions,
|
|
&tessEvaluationShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
if (tessEvaluationShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating tesselation evaluation shader binary failed.";
|
|
}
|
|
|
|
GLint loadResult;
|
|
// Create vertex shader and load binary
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, mVertexShaderBinary.data(),
|
|
mVertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create geometry shader and load binary
|
|
GLuint geoShader = glCreateShader(GL_GEOMETRY_SHADER);
|
|
glShaderBinary(1, &geoShader, GL_SHADER_BINARY_ANGLE, geometryShaderBinary.data(),
|
|
geometryShaderBinary.size());
|
|
glGetShaderiv(geoShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create tesselation control shader and load binary
|
|
GLuint tcShader = glCreateShader(GL_TESS_CONTROL_SHADER);
|
|
glShaderBinary(1, &tcShader, GL_SHADER_BINARY_ANGLE, tessControlShaderBinary.data(),
|
|
tessControlShaderBinary.size());
|
|
glGetShaderiv(tcShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create tesselation evaluation and load binary
|
|
GLuint teShader = glCreateShader(GL_TESS_EVALUATION_SHADER);
|
|
glShaderBinary(1, &teShader, GL_SHADER_BINARY_ANGLE, tessEvaluationShaderBinary.data(),
|
|
tessEvaluationShaderBinary.size());
|
|
glGetShaderiv(teShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create fragment shader and load binary
|
|
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, mFragmentShaderBinary.data(),
|
|
mFragmentShaderBinary.size());
|
|
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create program from the shaders
|
|
GLuint newProgram = glCreateProgram();
|
|
glAttachShader(newProgram, vertShader);
|
|
glAttachShader(newProgram, geoShader);
|
|
glAttachShader(newProgram, tcShader);
|
|
glAttachShader(newProgram, teShader);
|
|
glAttachShader(newProgram, fragShader);
|
|
glLinkProgram(newProgram);
|
|
newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
|
|
|
|
// Test with a basic draw
|
|
drawPatches(newProgram, "a_position", 0.5f, 1.0f, GL_FALSE);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
}
|
|
|
|
// Test glShaderBinary with complex shaders
|
|
TEST_P(ShaderBinaryTestES31, ComplexShader)
|
|
{
|
|
ANGLE_SKIP_TEST_IF(!supported());
|
|
|
|
const char *kVertexShader = R"(#version 310 es
|
|
uniform vec2 table[4];
|
|
|
|
in vec2 position;
|
|
in vec4 aTest;
|
|
|
|
out vec2 texCoord;
|
|
out vec4 vTest;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = vec4(position + table[gl_InstanceID], 0, 1);
|
|
vTest = aTest;
|
|
texCoord = gl_Position.xy * 0.5 + vec2(0.5);
|
|
})";
|
|
|
|
const char *kFragmentShader = R"(#version 310 es
|
|
precision mediump float;
|
|
|
|
struct S { sampler2D sampler; };
|
|
uniform S uStruct;
|
|
|
|
layout (binding = 0, std430) buffer Input {
|
|
float sampledInput;
|
|
};
|
|
|
|
in vec2 texCoord;
|
|
in vec4 vTest;
|
|
out vec4 my_FragColor;
|
|
|
|
void main()
|
|
{
|
|
if (sampledInput == 1.0)
|
|
{
|
|
my_FragColor = texture(uStruct.sampler, texCoord);
|
|
}
|
|
else
|
|
{
|
|
my_FragColor = vTest;
|
|
}
|
|
})";
|
|
|
|
// Generate shader binaries:
|
|
ShShaderSpec spec = SH_GLES3_1_SPEC;
|
|
ShShaderOutput output = SH_SPIRV_VULKAN_OUTPUT;
|
|
|
|
// Vertex shader:
|
|
sh::ShaderBinaryBlob vertexShaderBinary;
|
|
ShHandle vertexCompiler = sh::ConstructCompiler(GL_VERTEX_SHADER, spec, output, &mResources);
|
|
bool compileResult = sh::GetShaderBinary(vertexCompiler, &kVertexShader, 1, mCompileOptions,
|
|
&vertexShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (vertexShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating vertex shader binary failed.";
|
|
}
|
|
|
|
// Fragment shader:
|
|
sh::ShaderBinaryBlob fragmentShaderBinary;
|
|
ShHandle fragmentCompiler =
|
|
sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &mResources);
|
|
compileResult = sh::GetShaderBinary(fragmentCompiler, &kFragmentShader, 1, mCompileOptions,
|
|
&fragmentShaderBinary);
|
|
ASSERT_TRUE(compileResult);
|
|
|
|
if (fragmentShaderBinary.size() == 0)
|
|
{
|
|
FAIL() << "Creating fragment shader binary failed.";
|
|
}
|
|
|
|
GLint loadResult;
|
|
// Create vertex shader and load binary
|
|
GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderBinary(1, &vertShader, GL_SHADER_BINARY_ANGLE, vertexShaderBinary.data(),
|
|
vertexShaderBinary.size());
|
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create fragment shader and load binary
|
|
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderBinary(1, &fragShader, GL_SHADER_BINARY_ANGLE, fragmentShaderBinary.data(),
|
|
fragmentShaderBinary.size());
|
|
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &loadResult);
|
|
ASSERT_GL_TRUE(loadResult);
|
|
|
|
// Create program from the shaders
|
|
GLuint newProgram = glCreateProgram();
|
|
glAttachShader(newProgram, vertShader);
|
|
glAttachShader(newProgram, fragShader);
|
|
glLinkProgram(newProgram);
|
|
newProgram = CheckLinkStatusAndReturnProgram(newProgram, true);
|
|
glUseProgram(newProgram);
|
|
ASSERT_GL_NO_ERROR();
|
|
|
|
// Setup instance offset table
|
|
constexpr GLfloat table[] = {-1, -1, -1, 1, 1, -1, 1, 1};
|
|
GLint tableMemberLoc = glGetUniformLocation(newProgram, "table");
|
|
ASSERT_NE(-1, tableMemberLoc);
|
|
glUniform2fv(tableMemberLoc, 4, table);
|
|
ASSERT_GL_NO_ERROR();
|
|
|
|
// Setup red testure and sampler uniform
|
|
GLTexture tex;
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
GLubyte texData[] = {255u, 0u, 0u, 255u};
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
|
|
|
|
GLint samplerMemberLoc = glGetUniformLocation(newProgram, "uStruct.sampler");
|
|
ASSERT_NE(-1, samplerMemberLoc);
|
|
glUniform1i(samplerMemberLoc, 0);
|
|
ASSERT_GL_NO_ERROR();
|
|
|
|
// Setup the `aTest` attribute to blue
|
|
std::vector<Vector4> kInputAttribute(6, Vector4(0.0f, 0.0f, 1.0f, 1.0f));
|
|
GLint positionLocation = glGetAttribLocation(newProgram, "aTest");
|
|
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, kInputAttribute.data());
|
|
glEnableVertexAttribArray(positionLocation);
|
|
|
|
// Setup 'sampledInput' storage buffer to 1
|
|
constexpr GLfloat kInputDataOne = 1.0f;
|
|
GLBuffer input;
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, input);
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), &kInputDataOne, GL_STATIC_COPY);
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, input);
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
ASSERT_GL_NO_ERROR();
|
|
|
|
// Test sampling texture with an instanced draw
|
|
drawQuadInstanced(newProgram, "position", 0.5f, 0.5f, GL_FALSE, 4);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
|
|
|
|
// Setup 'sampledInput' storage buffer to 0
|
|
constexpr GLfloat kInputDataZero = 0.0f;
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, input);
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), &kInputDataZero, GL_STATIC_COPY);
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, input);
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
ASSERT_GL_NO_ERROR();
|
|
|
|
// Test color attribute with an instanced draw
|
|
drawQuadInstanced(newProgram, "position", 0.5f, 0.5f, GL_FALSE, 4);
|
|
ASSERT_GL_NO_ERROR();
|
|
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
|
|
}
|
|
|
|
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
|
|
// tests should be run against.
|
|
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31(ShaderBinaryTest);
|
|
|
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShaderBinaryTestES31);
|
|
ANGLE_INSTANTIATE_TEST_ES31(ShaderBinaryTestES31);
|