blob: 1abf7e8721d46cf2f9936fce0ea09329a8de6799 [file] [log] [blame]
// Copyright 2013 The Flutter 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 <memory>
#include "GLES3/gl3.h"
#include "fml/logging.h"
#include "impeller/renderer/backend/gles/proc_table_gles.h"
#include "impeller/renderer/backend/gles/test/mock_gles.h"
namespace impeller {
namespace testing {
// OpenGLES is not thread safe.
//
// This mutex is used to ensure that only one test is using the mock at a time.
static std::mutex g_test_lock;
static std::weak_ptr<MockGLES> g_mock_gles;
static std::vector<const unsigned char*> g_extensions;
// Has friend visibility into MockGLES to record calls.
void RecordGLCall(const char* name) {
if (auto mock_gles = g_mock_gles.lock()) {
mock_gles->RecordCall(name);
}
}
template <typename T, typename U>
struct CheckSameSignature : std::false_type {};
template <typename Ret, typename... Args>
struct CheckSameSignature<Ret(Args...), Ret(Args...)> : std::true_type {};
// This is a stub function that does nothing/records nothing.
void doNothing() {}
auto const kMockVendor = (unsigned char*)"MockGLES";
auto const kMockVersion = (unsigned char*)"3.0";
auto const kExtensions = std::vector<const unsigned char*>{
(unsigned char*)"GL_KHR_debug" //
};
const unsigned char* mockGetString(GLenum name) {
switch (name) {
case GL_VENDOR:
return kMockVendor;
case GL_VERSION:
return kMockVersion;
case GL_SHADING_LANGUAGE_VERSION:
return kMockVersion;
default:
return (unsigned char*)"";
}
}
static_assert(CheckSameSignature<decltype(mockGetString), //
decltype(glGetString)>::value);
const unsigned char* mockGetStringi(GLenum name, GLuint index) {
switch (name) {
case GL_EXTENSIONS:
return g_extensions[index];
default:
return (unsigned char*)"";
}
}
static_assert(CheckSameSignature<decltype(mockGetStringi), //
decltype(glGetStringi)>::value);
void mockGetIntegerv(GLenum name, int* value) {
switch (name) {
case GL_NUM_EXTENSIONS: {
*value = g_extensions.size();
} break;
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
*value = 8;
break;
default:
*value = 0;
break;
}
}
static_assert(CheckSameSignature<decltype(mockGetIntegerv), //
decltype(glGetIntegerv)>::value);
GLenum mockGetError() {
return GL_NO_ERROR;
}
static_assert(CheckSameSignature<decltype(mockGetError), //
decltype(glGetError)>::value);
void mockPopDebugGroupKHR() {
RecordGLCall("PopDebugGroupKHR");
}
static_assert(CheckSameSignature<decltype(mockPopDebugGroupKHR), //
decltype(glPopDebugGroupKHR)>::value);
void mockPushDebugGroupKHR(GLenum source,
GLuint id,
GLsizei length,
const GLchar* message) {
RecordGLCall("PushDebugGroupKHR");
}
static_assert(CheckSameSignature<decltype(mockPushDebugGroupKHR), //
decltype(glPushDebugGroupKHR)>::value);
std::shared_ptr<MockGLES> MockGLES::Init(
const std::optional<std::vector<const unsigned char*>>& extensions) {
// If we cannot obtain a lock, MockGLES is already being used elsewhere.
FML_CHECK(g_test_lock.try_lock())
<< "MockGLES is already being used by another test.";
g_extensions = extensions.value_or(kExtensions);
auto mock_gles = std::shared_ptr<MockGLES>(new MockGLES());
g_mock_gles = mock_gles;
return mock_gles;
}
const ProcTableGLES::Resolver kMockResolver = [](const char* name) {
if (strcmp(name, "glPopDebugGroupKHR") == 0) {
return reinterpret_cast<void*>(&mockPopDebugGroupKHR);
} else if (strcmp(name, "glPushDebugGroupKHR") == 0) {
return reinterpret_cast<void*>(&mockPushDebugGroupKHR);
} else if (strcmp(name, "glGetString") == 0) {
return reinterpret_cast<void*>(&mockGetString);
} else if (strcmp(name, "glGetStringi") == 0) {
return reinterpret_cast<void*>(&mockGetStringi);
} else if (strcmp(name, "glGetIntegerv") == 0) {
return reinterpret_cast<void*>(&mockGetIntegerv);
} else if (strcmp(name, "glGetError") == 0) {
return reinterpret_cast<void*>(&mockGetError);
} else {
return reinterpret_cast<void*>(&doNothing);
}
};
MockGLES::MockGLES() : proc_table_(kMockResolver) {}
MockGLES::~MockGLES() {
g_test_lock.unlock();
}
} // namespace testing
} // namespace impeller