[core] Remove binary shader support

The implementation is buggy and not worth maintaining anymore
because performance benefits are not substantial or sometimes
worse. Also, removing it saves about 150 ~ 180 KB in binary size.

Below timings are averages of minimum 5 runs.

```
Device          Init launch     Average relaunch
s10             1129.8 ms       700 ms
s10 - binary    1346.75 ms      694 ms
Pixel           1692 ms         723 ms
Pixel - binary  1883 ms         1039 ms
Kazam           17948 ms        1339 ms
Kazam - binary  19157 ms        1564 ms
Wiko            2060 ms         1278 ms
Wiko - binary   3876 ms         1136 ms
```

Fixes #14294
This commit is contained in:
Thiago Marcos P. Santos
2019-05-17 19:24:54 +03:00
parent f210bbbb6c
commit c2f974f2a5
15 changed files with 0 additions and 480 deletions

View File

@@ -1,19 +0,0 @@
// Protocol Version 1
package mapboxgl.binary_program;
option optimize_for = LITE_RUNTIME;
message binding {
required string name = 1;
required uint32 value = 2;
}
message binary_program {
required uint32 format = 1;
required bytes code = 2;
repeated binding attribute = 3;
repeated binding uniform = 4;
optional string identifier = 5;
repeated binding texture = 6;
}

View File

@@ -18,7 +18,6 @@
"src/mbgl/gfx/attribute.cpp",
"src/mbgl/gfx/renderer_backend.cpp",
"src/mbgl/gl/attribute.cpp",
"src/mbgl/gl/binary_program.cpp",
"src/mbgl/gl/command_encoder.cpp",
"src/mbgl/gl/context.cpp",
"src/mbgl/gl/debugging_extension.cpp",
@@ -533,7 +532,6 @@
"mbgl/gfx/vertex_buffer.hpp": "src/mbgl/gfx/vertex_buffer.hpp",
"mbgl/gfx/vertex_vector.hpp": "src/mbgl/gfx/vertex_vector.hpp",
"mbgl/gl/attribute.hpp": "src/mbgl/gl/attribute.hpp",
"mbgl/gl/binary_program.hpp": "src/mbgl/gl/binary_program.hpp",
"mbgl/gl/command_encoder.hpp": "src/mbgl/gl/command_encoder.hpp",
"mbgl/gl/context.hpp": "src/mbgl/gl/context.hpp",
"mbgl/gl/debugging_extension.hpp": "src/mbgl/gl/debugging_extension.hpp",
@@ -541,13 +539,11 @@
"mbgl/gl/draw_scope_resource.hpp": "src/mbgl/gl/draw_scope_resource.hpp",
"mbgl/gl/enum.hpp": "src/mbgl/gl/enum.hpp",
"mbgl/gl/extension.hpp": "src/mbgl/gl/extension.hpp",
"mbgl/gl/features.hpp": "src/mbgl/gl/features.hpp",
"mbgl/gl/framebuffer.hpp": "src/mbgl/gl/framebuffer.hpp",
"mbgl/gl/index_buffer_resource.hpp": "src/mbgl/gl/index_buffer_resource.hpp",
"mbgl/gl/object.hpp": "src/mbgl/gl/object.hpp",
"mbgl/gl/offscreen_texture.hpp": "src/mbgl/gl/offscreen_texture.hpp",
"mbgl/gl/program.hpp": "src/mbgl/gl/program.hpp",
"mbgl/gl/program_binary_extension.hpp": "src/mbgl/gl/program_binary_extension.hpp",
"mbgl/gl/render_pass.hpp": "src/mbgl/gl/render_pass.hpp",
"mbgl/gl/renderbuffer_resource.hpp": "src/mbgl/gl/renderbuffer_resource.hpp",
"mbgl/gl/state.hpp": "src/mbgl/gl/state.hpp",

View File

@@ -31,12 +31,6 @@ private:
public:
AttributeLocations() = default;
template <class BinaryProgram>
AttributeLocations(const BinaryProgram& program)
: locations{ program.attributeLocation(
concat_literals<&string_literal<'a', '_'>::value, &As::name>::value())... } {
}
void queryLocations(const ProgramID& id) {
locations = Locations{
queryLocation(id, concat_literals<&string_literal<'a', '_'>::value, &As::name>::value())... };

View File

@@ -1,142 +0,0 @@
#include <mbgl/gl/binary_program.hpp>
#include <protozero/pbf_reader.hpp>
#include <protozero/pbf_writer.hpp>
#include <utility>
#include <stdexcept>
template <class Binding>
static std::pair<const std::string, Binding> parseBinding(protozero::pbf_reader&& pbf) {
bool hasName = false, hasValue = false;
std::pair<std::string, Binding> binding;
while (pbf.next()) {
switch (pbf.tag()) {
case 1: // name
binding.first = pbf.get_string();
hasName = true;
break;
case 2: // value
binding.second = pbf.get_uint32();
hasValue = true;
break;
default:
pbf.skip();
break;
}
}
if (!hasName || !hasValue) {
throw std::runtime_error("BinaryProgram binding is missing required fields");
}
return binding;
}
namespace mbgl {
namespace gl {
BinaryProgram::BinaryProgram(std::string&& data) {
bool hasFormat = false, hasCode = false;
protozero::pbf_reader pbf(data);
while (pbf.next()) {
switch (pbf.tag()) {
case 1: // format
binaryFormat = pbf.get_uint32();
hasFormat = true;
break;
case 2: // code
binaryCode = pbf.get_bytes();
hasCode = true;
break;
case 3: // variable
attributes.emplace_back(parseBinding<gl::AttributeLocation>(pbf.get_message()));
break;
case 4: // uniform
uniforms.emplace_back(parseBinding<gl::UniformLocation>(pbf.get_message()));
break;
case 5: // identifier
binaryIdentifier = pbf.get_string();
break;
case 6: // uniform
textures.emplace_back(parseBinding<gl::UniformLocation>(pbf.get_message()));
break;
default:
pbf.skip();
break;
}
}
if (!hasFormat || !hasCode) {
throw std::runtime_error("BinaryProgram is missing required fields");
}
}
BinaryProgram::BinaryProgram(
gl::BinaryProgramFormat binaryFormat_,
std::string&& binaryCode_,
std::string binaryIdentifier_,
std::vector<std::pair<const std::string, gl::AttributeLocation>>&& attributes_,
std::vector<std::pair<const std::string, gl::UniformLocation>>&& uniforms_,
std::vector<std::pair<const std::string, gl::UniformLocation>>&& textures_)
: binaryFormat(binaryFormat_),
binaryCode(std::move(binaryCode_)),
binaryIdentifier(std::move(binaryIdentifier_)),
attributes(std::move(attributes_)),
uniforms(std::move(uniforms_)),
textures(std::move(textures_)) {
}
std::string BinaryProgram::serialize() const {
std::string data;
data.reserve(32 + binaryCode.size() + uniforms.size() * 32 + attributes.size() * 32);
protozero::pbf_writer pbf(data);
pbf.add_uint32(1 /* format */, binaryFormat);
pbf.add_bytes(2 /* code */, binaryCode.data(), binaryCode.size());
for (const auto& binding : attributes) {
protozero::pbf_writer pbf_binding(pbf, 3 /* attribute */);
pbf_binding.add_string(1 /* name */, binding.first);
pbf_binding.add_uint32(2 /* value */, binding.second);
}
for (const auto& binding : uniforms) {
protozero::pbf_writer pbf_binding(pbf, 4 /* uniform */);
pbf_binding.add_string(1 /* name */, binding.first);
pbf_binding.add_uint32(2 /* value */, binding.second);
}
for (const auto& binding : textures) {
protozero::pbf_writer pbf_binding(pbf, 6 /* texture */);
pbf_binding.add_string(1 /* name */, binding.first);
pbf_binding.add_uint32(2 /* value */, binding.second);
}
if (!binaryIdentifier.empty()) {
pbf.add_string(5 /* identifier */, binaryIdentifier);
}
return data;
}
optional<gl::AttributeLocation> BinaryProgram::attributeLocation(const std::string& name) const {
for (const auto& pair : attributes) {
if (pair.first == name) {
return pair.second;
}
}
return {};
}
gl::UniformLocation BinaryProgram::uniformLocation(const std::string& name) const {
for (const auto& pair : uniforms) {
if (pair.first == name) {
return pair.second;
}
}
return -1;
}
gl::UniformLocation BinaryProgram::textureLocation(const std::string& name) const {
for (const auto& pair : textures) {
if (pair.first == name) {
return pair.second;
}
}
return -1;
}
} // namespace gl
} // namespace mbgl

View File

@@ -1,50 +0,0 @@
#pragma once
#include <mbgl/gl/types.hpp>
#include <mbgl/util/optional.hpp>
#include <string>
#include <vector>
namespace mbgl {
namespace gl {
class BinaryProgram {
public:
// Initialize a BinaryProgram object from a serialized represenation.
BinaryProgram(std::string&& data);
BinaryProgram(gl::BinaryProgramFormat,
std::string&& binaryCode,
std::string binaryIdentifier,
std::vector<std::pair<const std::string, gl::AttributeLocation>>&&,
std::vector<std::pair<const std::string, gl::UniformLocation>>&&,
std::vector<std::pair<const std::string, gl::UniformLocation>>&&);
std::string serialize() const;
gl::BinaryProgramFormat format() const {
return binaryFormat;
}
const std::string& code() const {
return binaryCode;
}
const std::string& identifier() const {
return binaryIdentifier;
}
optional<gl::AttributeLocation> attributeLocation(const std::string& name) const;
gl::UniformLocation uniformLocation(const std::string& name) const;
gl::UniformLocation textureLocation(const std::string& name) const;
private:
gl::BinaryProgramFormat binaryFormat = 0;
std::string binaryCode;
std::string binaryIdentifier;
std::vector<std::pair<const std::string, gl::AttributeLocation>> attributes;
std::vector<std::pair<const std::string, gl::UniformLocation>> uniforms;
std::vector<std::pair<const std::string, gl::UniformLocation>> textures;
};
} // namespace gl
} // namespace mbgl

View File

@@ -9,7 +9,6 @@
#include <mbgl/gl/command_encoder.hpp>
#include <mbgl/gl/debugging_extension.hpp>
#include <mbgl/gl/vertex_array_extension.hpp>
#include <mbgl/gl/program_binary_extension.hpp>
#include <mbgl/util/traits.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/logging.hpp>
@@ -50,8 +49,6 @@ static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "Ope
static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch");
static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch");
static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch");
Context::Context(RendererBackend& backend_)
: gfx::Context(gfx::ContextType::OpenGL, [] {
GLint value;
@@ -107,10 +104,6 @@ void Context::initializeExtensions(const std::function<gl::ProcAddress(const cha
vertexArray = std::make_unique<extension::VertexArray>(fn);
}
#if MBGL_HAS_BINARY_PROGRAMS
programBinary = std::make_unique<extension::ProgramBinary>(fn);
#endif
#if MBGL_USE_GLES2
constexpr const char* halfFloatExtensionName = "OES_texture_half_float";
constexpr const char* halfFloatColorBufferExtensionName = "EXT_color_buffer_half_float";
@@ -186,23 +179,6 @@ UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentSha
return result;
}
#if MBGL_HAS_BINARY_PROGRAMS
UniqueProgram Context::createProgram(BinaryProgramFormat binaryFormat,
const std::string& binaryProgram) {
assert(supportsProgramBinaries());
UniqueProgram result{ MBGL_CHECK_ERROR(glCreateProgram()), { this } };
MBGL_CHECK_ERROR(programBinary->programBinary(result, static_cast<GLenum>(binaryFormat),
binaryProgram.data(),
static_cast<GLint>(binaryProgram.size())));
verifyProgramLinkage(result);
return result;
}
#else
UniqueProgram Context::createProgram(BinaryProgramFormat, const std::string&) {
throw std::runtime_error("binary programs are not supported");
}
#endif
void Context::linkProgram(ProgramID program_) {
MBGL_CHECK_ERROR(glLinkProgram(program_));
verifyProgramLinkage(program_);
@@ -244,51 +220,6 @@ bool Context::supportsVertexArrays() const {
vertexArray->deleteVertexArrays;
}
#if MBGL_HAS_BINARY_PROGRAMS
bool Context::supportsProgramBinaries() const {
if (!programBinary || !programBinary->programBinary || !programBinary->getProgramBinary) {
return false;
}
// Blacklist Adreno 3xx, 4xx, and 5xx GPUs due to known bugs:
// https://bugs.chromium.org/p/chromium/issues/detail?id=510637
// https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316
// Blacklist Vivante GC4000 due to bugs when linking loaded programs:
// https://github.com/mapbox/mapbox-gl-native/issues/10704
const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER)));
if (renderer.find("Adreno (TM) 3") != std::string::npos
|| renderer.find("Adreno (TM) 4") != std::string::npos
|| renderer.find("Adreno (TM) 5") != std::string::npos
|| renderer.find("Vivante GC4000") != std::string::npos) {
return false;
}
return true;
}
optional<std::pair<BinaryProgramFormat, std::string>>
Context::getBinaryProgram(ProgramID program_) const {
if (!supportsProgramBinaries()) {
return {};
}
GLint binaryLength;
MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binaryLength));
std::string binary;
binary.resize(binaryLength);
GLenum binaryFormat;
MBGL_CHECK_ERROR(programBinary->getProgramBinary(
program_, binaryLength, &binaryLength, &binaryFormat, const_cast<char*>(binary.data())));
if (size_t(binaryLength) != binary.size()) {
return {};
}
return { { binaryFormat, std::move(binary) } };
}
#else
optional<std::pair<BinaryProgramFormat, std::string>> Context::getBinaryProgram(ProgramID) const {
return {};
}
#endif
VertexArray Context::createVertexArray() {
if (supportsVertexArrays()) {
VertexArrayID id = 0;

View File

@@ -1,7 +1,6 @@
#pragma once
#include <mbgl/gfx/context.hpp>
#include <mbgl/gl/features.hpp>
#include <mbgl/gl/object.hpp>
#include <mbgl/gl/state.hpp>
#include <mbgl/gl/value.hpp>
@@ -33,7 +32,6 @@ class RendererBackend;
namespace extension {
class VertexArray;
class Debugging;
class ProgramBinary;
} // namespace extension
class Context final : public gfx::Context {
@@ -51,18 +49,10 @@ public:
UniqueShader createShader(ShaderType type, const std::initializer_list<const char*>& sources);
UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader, const char* location0AttribName);
UniqueProgram createProgram(BinaryProgramFormat binaryFormat, const std::string& binaryProgram);
void verifyProgramLinkage(ProgramID);
void linkProgram(ProgramID);
UniqueTexture createUniqueTexture();
#if MBGL_HAS_BINARY_PROGRAMS
bool supportsProgramBinaries() const;
#else
constexpr static bool supportsProgramBinaries() { return false; }
#endif
optional<std::pair<BinaryProgramFormat, std::string>> getBinaryProgram(ProgramID) const;
Framebuffer createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>&,
const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>&);
Framebuffer createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>&);
@@ -140,9 +130,6 @@ private:
std::unique_ptr<extension::Debugging> debugging;
std::unique_ptr<extension::VertexArray> vertexArray;
#if MBGL_HAS_BINARY_PROGRAMS
std::unique_ptr<extension::ProgramBinary> programBinary;
#endif
public:
State<value::ActiveTextureUnit> activeTextureUnit;

View File

@@ -1,8 +0,0 @@
#pragma once
#if __APPLE__
#define MBGL_HAS_BINARY_PROGRAMS 0
#else
// https://github.com/mapbox/mapbox-gl-native/issues/14294
#define MBGL_HAS_BINARY_PROGRAMS 0
#endif

View File

@@ -12,8 +12,6 @@
#include <mbgl/gl/attribute.hpp>
#include <mbgl/gl/uniform.hpp>
#include <mbgl/gl/texture.hpp>
#include <mbgl/gl/features.hpp>
#include <mbgl/gl/binary_program.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/logging.hpp>
@@ -57,48 +55,10 @@ public:
textureStates.queryLocations(program);
}
template <class BinaryProgram>
Instance(Context& context, const BinaryProgram& binaryProgram)
: program(context.createProgram(binaryProgram.format(), binaryProgram.code())),
attributeLocations(binaryProgram) {
uniformStates.loadNamedLocations(binaryProgram);
textureStates.loadNamedLocations(binaryProgram);
}
static std::unique_ptr<Instance>
createInstance(gl::Context& context,
const ProgramParameters& programParameters,
const std::string& additionalDefines) {
#if MBGL_HAS_BINARY_PROGRAMS
optional<std::string> cachePath =
programParameters.cachePath(programs::gl::ShaderSource<Name>::name);
std::string programIdentifier;
if (cachePath && context.supportsProgramBinaries()) {
programIdentifier = programs::gl::programIdentifier(
programParameters.getDefines(), additionalDefines, programs::gl::preludeHash,
programs::gl::ShaderSource<Name>::hash);
try {
if (auto cachedBinaryProgram = util::readFile(*cachePath)) {
const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram));
if (binaryProgram.identifier() == programIdentifier) {
return std::make_unique<Instance>(context, binaryProgram);
} else {
Log::Warning(Event::OpenGL,
"Cached program %s changed. Recompilation required.",
programs::gl::ShaderSource<Name>::name);
}
}
} catch (std::runtime_error& error) {
Log::Warning(Event::OpenGL, "Could not load cached program: %s",
error.what());
}
}
#endif
// Compile the shader
const std::initializer_list<const char*> vertexSource = {
programParameters.getDefines().c_str(),
@@ -114,36 +74,9 @@ public:
};
auto result = std::make_unique<Instance>(context, vertexSource, fragmentSource);
#if MBGL_HAS_BINARY_PROGRAMS
if (cachePath && context.supportsProgramBinaries()) {
try {
if (const auto binaryProgram =
result->template get<BinaryProgram>(context, programIdentifier)) {
util::write_file(*cachePath, binaryProgram->serialize());
Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str());
}
} catch (std::runtime_error& error) {
Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what());
}
}
#endif
return std::move(result);
}
template <class BinaryProgram>
optional<BinaryProgram> get(Context& context, const std::string& identifier) const {
if (auto binaryProgram = context.getBinaryProgram(program)) {
return BinaryProgram{ binaryProgram->first,
std::move(binaryProgram->second),
identifier,
attributeLocations.getNamedLocations(),
uniformStates.getNamedLocations(),
textureStates.getNamedLocations() };
}
return {};
}
UniqueProgram program;
gl::AttributeLocations<AttributeList> attributeLocations;
gl::UniformStates<UniformList> uniformStates;

View File

@@ -1,44 +0,0 @@
#pragma once
#include <mbgl/gl/features.hpp>
#include <mbgl/gl/extension.hpp>
#include <mbgl/gl/defines.hpp>
#if MBGL_HAS_BINARY_PROGRAMS
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#define GL_PROGRAM_BINARY_FORMATS 0x87FF
namespace mbgl {
namespace gl {
namespace extension {
class ProgramBinary {
public:
template <typename Fn>
ProgramBinary(const Fn& loadExtension)
: getProgramBinary(loadExtension({
{ "GL_OES_get_program_binary", "glGetProgramBinaryOES" },
{ "GL_ARB_get_program_binary", "glGetProgramBinary" },
})),
programBinary(loadExtension({
{ "GL_OES_get_program_binary", "glProgramBinaryOES" },
{ "GL_ARB_get_program_binary", "glProgramBinary" },
})) {
}
const ExtensionFunction<void(
GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)>
getProgramBinary;
const ExtensionFunction<void(
GLuint program, GLenum binaryFormat, const GLvoid* binary, GLint length)>
programBinary;
};
} // namespace extension
} // namespace gl
} // namespace mbgl
#endif

View File

@@ -32,12 +32,6 @@ public:
concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value())... };
}
template <class BinaryProgram>
void loadNamedLocations(const BinaryProgram& program) {
state = State{ program.textureLocation(
concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value())... };
}
NamedUniformLocations getNamedLocations() const {
return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value(),
state.template get<Ts>().location }... };

View File

@@ -38,8 +38,6 @@ constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b)
return a.alignment != b.alignment;
}
using BinaryProgramFormat = uint32_t;
enum class UniformDataType : uint32_t {
Float = 0x1406,
FloatVec2 = 0x8B50,

View File

@@ -82,11 +82,6 @@ public:
state = State{ gl::uniformLocation(id, concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())... };
}
template <class BinaryProgram>
void loadNamedLocations(const BinaryProgram& program) {
state = State{ UniformState<typename Us::Value>(program.uniformLocation(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value()))... };
}
NamedUniformLocations getNamedLocations() const {
return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value(), state.template get<Us>().location }... };
}

View File

@@ -1,44 +0,0 @@
#include <mbgl/test/util.hpp>
#include <mbgl/gl/binary_program.hpp>
using namespace mbgl;
TEST(BinaryProgram, ObtainValues) {
const gl::BinaryProgram binaryProgram{ 42,
"binary code",
"identifier",
{ { "a_pos", 1 }, { "a_data", 4 } },
{ { "u_world", 1 }, { "u_ratio", 3 } },
{ { "u_image", 0 } } };
EXPECT_EQ(42u, binaryProgram.format());
EXPECT_EQ("binary code", binaryProgram.code());
EXPECT_EQ("identifier", binaryProgram.identifier());
EXPECT_EQ(1u, binaryProgram.attributeLocation("a_pos"));
EXPECT_FALSE(binaryProgram.attributeLocation("u_world"));
EXPECT_EQ(4u, binaryProgram.attributeLocation("a_data"));
EXPECT_EQ(1, binaryProgram.uniformLocation("u_world"));
EXPECT_EQ(3, binaryProgram.uniformLocation("u_ratio"));
EXPECT_EQ(-1, binaryProgram.uniformLocation("a_data"));
EXPECT_EQ(0, binaryProgram.textureLocation("u_image"));
EXPECT_EQ(-1, binaryProgram.textureLocation("u_image2"));
auto serialized = binaryProgram.serialize();
const gl::BinaryProgram binaryProgram2(std::move(serialized));
EXPECT_EQ(42u, binaryProgram2.format());
EXPECT_EQ("binary code", binaryProgram2.code());
EXPECT_EQ("identifier", binaryProgram2.identifier());
EXPECT_EQ(1u, binaryProgram2.attributeLocation("a_pos"));
EXPECT_FALSE(binaryProgram2.attributeLocation("u_world"));
EXPECT_EQ(4u, binaryProgram2.attributeLocation("a_data"));
EXPECT_EQ(1, binaryProgram2.uniformLocation("u_world"));
EXPECT_EQ(3, binaryProgram2.uniformLocation("u_ratio"));
EXPECT_EQ(-1, binaryProgram2.uniformLocation("a_data"));
EXPECT_EQ(0, binaryProgram.textureLocation("u_image"));
EXPECT_EQ(-1, binaryProgram.textureLocation("u_image2"));
EXPECT_THROW(gl::BinaryProgram(""), std::runtime_error);
}

View File

@@ -23,7 +23,6 @@
"test/math/clamp.test.cpp",
"test/math/minmax.test.cpp",
"test/math/wrap.test.cpp",
"test/programs/binary_program.test.cpp",
"test/programs/symbol_program.test.cpp",
"test/renderer/backend_scope.test.cpp",
"test/renderer/image_manager.test.cpp",