blob: 4fe441d67f5b7f6397ebbe262402431864454e65 [file] [log] [blame]
//
// Copyright 2013 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 "SampleApplication.h"
#include "common/debug.h"
#include "util/EGLWindow.h"
#include "util/gles_loader_autogen.h"
#include "util/random_utils.h"
#include "util/shader_utils.h"
#include "util/test_utils.h"
#include "util/util_gl.h"
#include <string.h>
#include <iostream>
#include <utility>
#if defined(ANGLE_PLATFORM_WINDOWS)
# include "util/windows/WGLWindow.h"
#endif // defined(ANGLE_PLATFORM_WINDOWS)
namespace
{
const char *kUseAngleArg = "--use-angle=";
const char *kUseGlArg = "--use-gl=native";
using DisplayTypeInfo = std::pair<const char *, EGLint>;
const DisplayTypeInfo kDisplayTypes[] = {
{"d3d9", EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE},
{"d3d11", EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE},
{"gl", EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE},
{"gles", EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE},
{"metal", EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE},
{"null", EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE},
{"swiftshader", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
{"vulkan", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
};
EGLint GetDisplayTypeFromArg(const char *displayTypeArg)
{
for (const auto &displayTypeInfo : kDisplayTypes)
{
if (strcmp(displayTypeInfo.first, displayTypeArg) == 0)
{
std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl;
return displayTypeInfo.second;
}
}
std::cout << "Unknown ANGLE back-end API: " << displayTypeArg << std::endl;
return EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
}
EGLint GetDeviceTypeFromArg(const char *displayTypeArg)
{
if (strcmp(displayTypeArg, "swiftshader") == 0)
{
return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
}
else
{
return EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
}
}
ANGLE_MAYBE_UNUSED bool IsGLExtensionEnabled(const std::string &extName)
{
return angle::CheckExtensionExists(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
extName);
}
} // anonymous namespace
SampleApplication::SampleApplication(std::string name,
int argc,
char **argv,
EGLint glesMajorVersion,
EGLint glesMinorVersion,
uint32_t width,
uint32_t height)
: mName(std::move(name)),
mWidth(width),
mHeight(height),
mRunning(false),
mFrameCount(0),
mGLWindow(nullptr),
mEGLWindow(nullptr),
mOSWindow(nullptr),
mDriverType(angle::GLESDriverType::AngleEGL)
{
mPlatformParams.renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
bool useNativeGL = false;
for (int argIndex = 1; argIndex < argc; argIndex++)
{
if (strncmp(argv[argIndex], kUseAngleArg, strlen(kUseAngleArg)) == 0)
{
const char *arg = argv[argIndex] + strlen(kUseAngleArg);
mPlatformParams.renderer = GetDisplayTypeFromArg(arg);
mPlatformParams.deviceType = GetDeviceTypeFromArg(arg);
}
if (strncmp(argv[argIndex], kUseGlArg, strlen(kUseGlArg)) == 0)
{
useNativeGL = true;
}
}
mOSWindow = OSWindow::New();
// Load EGL library so we can initialize the display.
if (useNativeGL)
{
#if defined(ANGLE_PLATFORM_WINDOWS)
mGLWindow = WGLWindow::New(glesMajorVersion, glesMinorVersion);
mEntryPointsLib.reset(angle::OpenSharedLibrary("opengl32", angle::SearchType::SystemDir));
mDriverType = angle::GLESDriverType::SystemWGL;
#else
mGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion);
mEntryPointsLib.reset(angle::OpenSharedLibraryWithExtension(
angle::GetNativeEGLLibraryNameWithExtension(), angle::SearchType::SystemDir));
mDriverType = angle::GLESDriverType::SystemEGL;
#endif // defined(ANGLE_PLATFORM_WINDOWS)
}
else
{
mGLWindow = mEGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion);
mEntryPointsLib.reset(
angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
}
}
SampleApplication::~SampleApplication()
{
GLWindowBase::Delete(&mGLWindow);
OSWindow::Delete(&mOSWindow);
}
bool SampleApplication::initialize()
{
return true;
}
void SampleApplication::destroy() {}
void SampleApplication::step(float dt, double totalTime) {}
void SampleApplication::draw() {}
void SampleApplication::swap()
{
mGLWindow->swap();
}
OSWindow *SampleApplication::getWindow() const
{
return mOSWindow;
}
EGLConfig SampleApplication::getConfig() const
{
ASSERT(mEGLWindow);
return mEGLWindow->getConfig();
}
EGLDisplay SampleApplication::getDisplay() const
{
ASSERT(mEGLWindow);
return mEGLWindow->getDisplay();
}
EGLSurface SampleApplication::getSurface() const
{
ASSERT(mEGLWindow);
return mEGLWindow->getSurface();
}
EGLContext SampleApplication::getContext() const
{
ASSERT(mEGLWindow);
return mEGLWindow->getContext();
}
int SampleApplication::run()
{
if (!mOSWindow->initialize(mName, mWidth, mHeight))
{
return -1;
}
mOSWindow->setVisible(true);
ConfigParameters configParams;
configParams.redBits = 8;
configParams.greenBits = 8;
configParams.blueBits = 8;
configParams.alphaBits = 8;
configParams.depthBits = 24;
configParams.stencilBits = 8;
if (!mGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), mDriverType, mPlatformParams,
configParams))
{
return -1;
}
// Disable vsync
if (!mGLWindow->setSwapInterval(0))
{
return -1;
}
mRunning = true;
int result = 0;
#if defined(ANGLE_ENABLE_ASSERTS)
if (IsGLExtensionEnabled("GL_KHR_debug"))
{
EnableDebugCallback(nullptr, nullptr);
}
#endif
if (!initialize())
{
mRunning = false;
result = -1;
}
mTimer.start();
double prevTime = 0.0;
while (mRunning)
{
double elapsedTime = mTimer.getElapsedTime();
double deltaTime = elapsedTime - prevTime;
step(static_cast<float>(deltaTime), elapsedTime);
// Clear events that the application did not process from this frame
Event event;
while (popEvent(&event))
{
// If the application did not catch a close event, close now
switch (event.Type)
{
case Event::EVENT_CLOSED:
exit();
break;
case Event::EVENT_KEY_RELEASED:
onKeyUp(event.Key);
break;
case Event::EVENT_KEY_PRESSED:
onKeyDown(event.Key);
break;
default:
break;
}
}
if (!mRunning)
{
break;
}
draw();
swap();
mOSWindow->messageLoop();
prevTime = elapsedTime;
mFrameCount++;
if (mFrameCount % 100 == 0)
{
printf("Rate: %0.2lf frames / second\n",
static_cast<double>(mFrameCount) / mTimer.getElapsedTime());
}
}
destroy();
mGLWindow->destroyGL();
mOSWindow->destroy();
return result;
}
void SampleApplication::exit()
{
mRunning = false;
}
bool SampleApplication::popEvent(Event *event)
{
return mOSWindow->popEvent(event);
}
void SampleApplication::onKeyUp(const Event::KeyEvent &keyEvent)
{
// Default no-op.
}
void SampleApplication::onKeyDown(const Event::KeyEvent &keyEvent)
{
// Default no-op.
}