1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "SampleApplication.h"
8
9 #include "common/debug.h"
10 #include "util/EGLWindow.h"
11 #include "util/gles_loader_autogen.h"
12 #include "util/random_utils.h"
13 #include "util/shader_utils.h"
14 #include "util/test_utils.h"
15 #include "util/util_gl.h"
16
17 #include <string.h>
18 #include <iostream>
19 #include <utility>
20
21 #if defined(ANGLE_PLATFORM_WINDOWS)
22 # include "util/windows/WGLWindow.h"
23 #endif // defined(ANGLE_PLATFORM_WINDOWS)
24
25 namespace
26 {
27 const char *kUseAngleArg = "--use-angle=";
28 const char *kUseGlArg = "--use-gl=native";
29
30 using DisplayTypeInfo = std::pair<const char *, EGLint>;
31
32 const DisplayTypeInfo kDisplayTypes[] = {
33 {"d3d9", EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE},
34 {"d3d11", EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE},
35 {"gl", EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE},
36 {"gles", EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE},
37 {"metal", EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE},
38 {"null", EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE},
39 {"swiftshader", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
40 {"vulkan", EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE},
41 };
42
GetDisplayTypeFromArg(const char * displayTypeArg)43 EGLint GetDisplayTypeFromArg(const char *displayTypeArg)
44 {
45 for (const auto &displayTypeInfo : kDisplayTypes)
46 {
47 if (strcmp(displayTypeInfo.first, displayTypeArg) == 0)
48 {
49 std::cout << "Using ANGLE back-end API: " << displayTypeInfo.first << std::endl;
50 return displayTypeInfo.second;
51 }
52 }
53
54 std::cout << "Unknown ANGLE back-end API: " << displayTypeArg << std::endl;
55 return EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
56 }
57
GetDeviceTypeFromArg(const char * displayTypeArg)58 EGLint GetDeviceTypeFromArg(const char *displayTypeArg)
59 {
60 if (strcmp(displayTypeArg, "swiftshader") == 0)
61 {
62 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
63 }
64 else
65 {
66 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
67 }
68 }
69 } // anonymous namespace
70
IsGLExtensionEnabled(const std::string & extName)71 bool IsGLExtensionEnabled(const std::string &extName)
72 {
73 return angle::CheckExtensionExists(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
74 extName);
75 }
76
SampleApplication(std::string name,int argc,char ** argv,EGLint glesMajorVersion,EGLint glesMinorVersion,uint32_t width,uint32_t height)77 SampleApplication::SampleApplication(std::string name,
78 int argc,
79 char **argv,
80 EGLint glesMajorVersion,
81 EGLint glesMinorVersion,
82 uint32_t width,
83 uint32_t height)
84 : mName(std::move(name)),
85 mWidth(width),
86 mHeight(height),
87 mRunning(false),
88 mFrameCount(0),
89 mGLWindow(nullptr),
90 mEGLWindow(nullptr),
91 mOSWindow(nullptr),
92 mDriverType(angle::GLESDriverType::AngleEGL)
93 {
94 mPlatformParams.renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
95 bool useNativeGL = false;
96
97 for (int argIndex = 1; argIndex < argc; argIndex++)
98 {
99 if (strncmp(argv[argIndex], kUseAngleArg, strlen(kUseAngleArg)) == 0)
100 {
101 const char *arg = argv[argIndex] + strlen(kUseAngleArg);
102 mPlatformParams.renderer = GetDisplayTypeFromArg(arg);
103 mPlatformParams.deviceType = GetDeviceTypeFromArg(arg);
104 }
105
106 if (strncmp(argv[argIndex], kUseGlArg, strlen(kUseGlArg)) == 0)
107 {
108 useNativeGL = true;
109 }
110 }
111
112 mOSWindow = OSWindow::New();
113
114 // Load EGL library so we can initialize the display.
115 if (useNativeGL)
116 {
117 #if defined(ANGLE_PLATFORM_WINDOWS)
118 mGLWindow = WGLWindow::New(glesMajorVersion, glesMinorVersion);
119 mEntryPointsLib.reset(angle::OpenSharedLibrary("opengl32", angle::SearchType::SystemDir));
120 mDriverType = angle::GLESDriverType::SystemWGL;
121 #else
122 mGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion);
123 mEntryPointsLib.reset(angle::OpenSharedLibraryWithExtension(
124 angle::GetNativeEGLLibraryNameWithExtension(), angle::SearchType::SystemDir));
125 mDriverType = angle::GLESDriverType::SystemEGL;
126 #endif // defined(ANGLE_PLATFORM_WINDOWS)
127 }
128 else
129 {
130 mGLWindow = mEGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion);
131 mEntryPointsLib.reset(
132 angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ModuleDir));
133 }
134 }
135
~SampleApplication()136 SampleApplication::~SampleApplication()
137 {
138 GLWindowBase::Delete(&mGLWindow);
139 OSWindow::Delete(&mOSWindow);
140 }
141
initialize()142 bool SampleApplication::initialize()
143 {
144 return true;
145 }
146
destroy()147 void SampleApplication::destroy() {}
148
step(float dt,double totalTime)149 void SampleApplication::step(float dt, double totalTime) {}
150
draw()151 void SampleApplication::draw() {}
152
swap()153 void SampleApplication::swap()
154 {
155 mGLWindow->swap();
156 }
157
getWindow() const158 OSWindow *SampleApplication::getWindow() const
159 {
160 return mOSWindow;
161 }
162
getConfig() const163 EGLConfig SampleApplication::getConfig() const
164 {
165 ASSERT(mEGLWindow);
166 return mEGLWindow->getConfig();
167 }
168
getDisplay() const169 EGLDisplay SampleApplication::getDisplay() const
170 {
171 ASSERT(mEGLWindow);
172 return mEGLWindow->getDisplay();
173 }
174
getSurface() const175 EGLSurface SampleApplication::getSurface() const
176 {
177 ASSERT(mEGLWindow);
178 return mEGLWindow->getSurface();
179 }
180
getContext() const181 EGLContext SampleApplication::getContext() const
182 {
183 ASSERT(mEGLWindow);
184 return mEGLWindow->getContext();
185 }
186
run()187 int SampleApplication::run()
188 {
189 if (!mOSWindow->initialize(mName, mWidth, mHeight))
190 {
191 return -1;
192 }
193
194 mOSWindow->setVisible(true);
195
196 ConfigParameters configParams;
197 configParams.redBits = 8;
198 configParams.greenBits = 8;
199 configParams.blueBits = 8;
200 configParams.alphaBits = 8;
201 configParams.depthBits = 24;
202 configParams.stencilBits = 8;
203
204 if (!mGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), mDriverType, mPlatformParams,
205 configParams))
206 {
207 return -1;
208 }
209
210 // Disable vsync
211 if (!mGLWindow->setSwapInterval(0))
212 {
213 return -1;
214 }
215
216 mRunning = true;
217 int result = 0;
218
219 #if defined(ANGLE_ENABLE_ASSERTS)
220 if (IsGLExtensionEnabled("GL_KHR_debug"))
221 {
222 EnableDebugCallback(nullptr, nullptr);
223 }
224 #endif
225
226 if (!initialize())
227 {
228 mRunning = false;
229 result = -1;
230 }
231
232 mTimer.start();
233 double prevTime = 0.0;
234
235 while (mRunning)
236 {
237 double elapsedTime = mTimer.getElapsedWallClockTime();
238 double deltaTime = elapsedTime - prevTime;
239
240 step(static_cast<float>(deltaTime), elapsedTime);
241
242 // Clear events that the application did not process from this frame
243 Event event;
244 while (popEvent(&event))
245 {
246 // If the application did not catch a close event, close now
247 switch (event.Type)
248 {
249 case Event::EVENT_CLOSED:
250 exit();
251 break;
252 case Event::EVENT_KEY_RELEASED:
253 onKeyUp(event.Key);
254 break;
255 case Event::EVENT_KEY_PRESSED:
256 onKeyDown(event.Key);
257 break;
258 default:
259 break;
260 }
261 }
262
263 if (!mRunning)
264 {
265 break;
266 }
267
268 draw();
269 swap();
270
271 mOSWindow->messageLoop();
272
273 prevTime = elapsedTime;
274
275 mFrameCount++;
276
277 if (mFrameCount % 100 == 0)
278 {
279 printf("Rate: %0.2lf frames / second\n",
280 static_cast<double>(mFrameCount) / mTimer.getElapsedWallClockTime());
281 }
282 }
283
284 destroy();
285 mGLWindow->destroyGL();
286 mOSWindow->destroy();
287
288 return result;
289 }
290
exit()291 void SampleApplication::exit()
292 {
293 mRunning = false;
294 }
295
popEvent(Event * event)296 bool SampleApplication::popEvent(Event *event)
297 {
298 return mOSWindow->popEvent(event);
299 }
300
onKeyUp(const Event::KeyEvent & keyEvent)301 void SampleApplication::onKeyUp(const Event::KeyEvent &keyEvent)
302 {
303 // Default no-op.
304 }
305
onKeyDown(const Event::KeyEvent & keyEvent)306 void SampleApplication::onKeyDown(const Event::KeyEvent &keyEvent)
307 {
308 // Default no-op.
309 }
310