the mega audio-memory-profiler-patch TM
[vg.git] / src / vg / vg.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2
3 /*
4 * Memory model:
5 * [global (.data)] [temp-stack] [system-stack] [game-heap]
6 *
7 * 1. Program starts: .data memory is loaded
8 * 2. System initialization:
9 * 2a. the large heap buffer is allocated
10 * 2b. each engine system is initialized in order, using some of the
11 * system stack
12 * 2c. game systems are also put into here
13 */
14
15
16 #ifndef VG_HEADER_H
17 #define VG_HEADER_H
18
19 #include "vg_platform.h"
20 #include "vg_mem.h"
21
22 #ifndef _WIN32
23 #include <execinfo.h>
24 #endif
25
26
27 #if defined(VG_SERVER) || defined(VG_TOOLS)
28 #define VG_NON_CLIENT
29 #endif
30
31 #ifndef VG_SERVER
32 #include "../../dep/glad/glad.h"
33
34 #define GLFW_INCLUDE_GLCOREARB
35
36 #ifdef _WIN32
37 #define GLFW_DLL
38 #endif
39
40 #include "../../dep/glfw/glfw3.h"
41 #endif
42
43 #include "vg_stdint.h"
44
45 void vg_register_exit( void( *funcptr )(void), const char *name );
46
47 #include "vg_m.h"
48 #include "vg_io.h"
49 #include "vg_log.h"
50
51 #ifdef VG_STEAM
52 //#include "vg_steamworks.h"
53 #include "vg_steam.h"
54 #endif
55
56 #ifndef VG_NON_CLIENT
57
58 struct vg
59 {
60 /* Engine sync */
61 GLFWwindow* window;
62
63 vg_mutex mux_context;
64 vg_semaphore sem_allow_exec,
65 sem_exec_finished,
66 sem_loader,
67 sem_fatal;
68 int exec_context;
69
70 vg_mutex mux_engine_status;
71 enum engine_status
72 {
73 k_engine_status_none,
74 k_engine_status_running,
75 k_engine_status_crashed
76 }
77 engine_status;
78 const char *str_const_engine_err;
79 int is_loaded;
80
81 /* Window information */
82 int window_x,
83 window_y,
84 samples;
85 float refresh_rate;
86
87 v2f mouse,
88 mouse_wheel;
89
90 /* Runtime */
91 double time,
92 time_delta,
93 frame_delta,
94 time_real,
95 time_real_last,
96 time_rate,
97 accumulator;
98
99 int fixed_iterations;
100
101 enum engine_stage
102 {
103 k_engine_stage_none,
104 k_engine_stage_update,
105 k_engine_stage_update_fixed,
106 k_engine_stage_rendering,
107 k_engine_stage_ui
108 }
109 engine_stage;
110
111 /* graphics */
112 m4x4f pv;
113
114 /* Gamepad */
115 GLFWgamepadstate gamepad;
116 int gamepad_ready;
117 const char *gamepad_name;
118 int gamepad_id;
119 }
120 VG_STATIC vg = { .time_rate = 1.0 };
121
122 struct vg_thread_info
123 {
124 enum vg_thread_purpose
125 {
126 k_thread_purpose_nothing,
127 k_thread_purpose_main,
128 k_thread_purpose_loader
129 }
130 purpose;
131
132 int gl_context_level;
133 };
134
135 static VG_THREAD_LOCAL struct vg_thread_info vg_thread_info;
136
137
138 //#define VG_SYNC_DEBUG
139
140 #ifdef VG_SYNC_DEBUG
141 #define VG_SYNC_LOG(STR,...) vg_info(STR,vg_thread_info.purpose,##__VA_ARGS__)
142 #else
143 #define VG_SYNC_LOG(...)
144 #endif
145
146 VG_STATIC void vg_fatal_exit_loop( const char *error );
147
148 VG_STATIC void vg_ensure_engine_running(void)
149 {
150 /* Check if the engine is no longer running */
151 vg_mutex_lock( &vg.mux_engine_status );
152 if( vg.engine_status != k_engine_status_running )
153 {
154 VG_SYNC_LOG( "[%d] Engine is no longer running\n");
155 vg_mutex_unlock( &vg.mux_engine_status );
156
157 /* Safe to disregard loader thread from this point on, elswhere */
158 if( vg_thread_info.purpose == k_thread_purpose_loader )
159 {
160 vg_semaphore_post( &vg.sem_loader );
161 }
162
163 VG_SYNC_LOG( "[%d] about to kill\n");
164 vg_thread_exit();
165 }
166 vg_mutex_unlock( &vg.mux_engine_status );
167 }
168
169 /*
170 * Sync execution so that the OpenGL context is switched onto this thread.
171 * Anything after this call will be in a valid context.
172 */
173 VG_STATIC void vg_acquire_thread_sync(void)
174 {
175 /* We dont want to do anything if this is the main thread */
176 if( vg_thread_info.purpose == k_thread_purpose_main )
177 return;
178
179 assert( vg_thread_info.purpose == k_thread_purpose_loader );
180
181 vg_ensure_engine_running();
182
183 /* Check if thread already has the context */
184 if( vg_thread_info.gl_context_level )
185 {
186 vg_thread_info.gl_context_level ++;
187 VG_SYNC_LOG( "[%d] We already have sync here\n" );
188 return;
189 }
190
191 vg_mutex_lock( &vg.mux_context );
192 VG_SYNC_LOG( "[%d] Signal to sync.\n" );
193 vg.exec_context = 1;
194 vg_mutex_unlock( &vg.mux_context );
195
196 /* wait until told we can go */
197 VG_SYNC_LOG( "[%d] Waiting to acuire sync.\n" );
198 vg_semaphore_wait( &vg.sem_allow_exec );
199 glfwMakeContextCurrent( vg.window );
200
201 /* context now valid to work in while we hold up main thread */
202 VG_SYNC_LOG( "[%d] Context acquired.\n" );
203 vg_thread_info.gl_context_level ++;
204 }
205
206 /*
207 * Signify that we are done with the OpenGL context in this thread.
208 * Anything after this call will be in an undefined context.
209 */
210 VG_STATIC void vg_release_thread_sync(void)
211 {
212 if( vg_thread_info.purpose == k_thread_purpose_main )
213 return;
214
215 assert( vg_thread_info.purpose == k_thread_purpose_loader );
216
217 /* signal that we are done */
218 vg_thread_info.gl_context_level --;
219
220 if( !vg_thread_info.gl_context_level )
221 {
222 VG_SYNC_LOG( "[%d] Releasing context.\n" );
223 glfwMakeContextCurrent( NULL );
224 vg_semaphore_post( &vg.sem_exec_finished );
225 }
226 }
227
228 VG_STATIC void vg_run_synced_content(void)
229 {
230 assert( vg_thread_info.purpose == k_thread_purpose_main );
231
232 vg_mutex_lock( &vg.mux_context );
233
234 if( vg.exec_context != 0 )
235 {
236 VG_SYNC_LOG( "[%d] Allowing content (%d).\n", vg.exec_context );
237
238 /* allow operations to go */
239 vg_thread_info.gl_context_level = 0;
240 glfwMakeContextCurrent( NULL );
241 vg_semaphore_post( &vg.sem_allow_exec );
242
243 /* wait for operations to complete */
244 VG_SYNC_LOG( "[%d] Waiting for content (%d).\n", vg.exec_context );
245 vg_semaphore_wait( &vg.sem_exec_finished );
246
247 /* check if we killed the engine */
248 vg_ensure_engine_running();
249
250 /* re-engage main thread */
251 VG_SYNC_LOG( "[%d] Re-engaging.\n" );
252 vg.exec_context = 0;
253 glfwMakeContextCurrent( vg.window );
254 vg_thread_info.gl_context_level = 1;
255 }
256
257 vg_mutex_unlock( &vg.mux_context );
258 }
259
260 VG_STATIC void vg_opengl_sync_init(void)
261 {
262 vg_semaphore_init( &vg.sem_allow_exec, 0 );
263 vg_semaphore_init( &vg.sem_exec_finished, 0 );
264 vg_semaphore_init( &vg.sem_loader, 1 );
265 vg_semaphore_init( &vg.sem_fatal, 1 );
266 vg_mutex_init( &vg.mux_context );
267
268 vg_set_thread_name( "[vg] Main" );
269 vg_thread_info.purpose = k_thread_purpose_main;
270 vg_thread_info.gl_context_level = 1;
271 }
272
273 VG_STATIC void vg_checkgl( const char *src_info );
274 #define VG_STRINGIT( X ) #X
275 #define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) )
276
277 #include "vg_console.h"
278 #include "vg_profiler.h"
279 #include "vg_audio.h"
280 #include "vg_shader.h"
281 #include "vg_tex.h"
282 #include "vg_input.h"
283 #include "vg_ui.h"
284 #include "vg_lines.h"
285 #include "vg_loader.h"
286 #include "vg_opt.h"
287
288 /* Diagnostic */
289 VG_STATIC struct vg_profile vg_prof_update = {.name="update()"},
290 vg_prof_render = {.name="render()"};
291
292 #define VG_GAMELOOP
293 VG_STATIC void vg_register(void) VG_GAMELOOP;
294 VG_STATIC void vg_start(void) VG_GAMELOOP;
295
296 VG_STATIC void vg_update(int loaded) VG_GAMELOOP;
297 VG_STATIC void vg_update_fixed(int loaded) VG_GAMELOOP;
298 VG_STATIC void vg_update_post(int loaded) VG_GAMELOOP;
299
300 VG_STATIC void vg_framebuffer_resize(int w, int h) VG_GAMELOOP;
301 VG_STATIC void vg_render(void) VG_GAMELOOP;
302 VG_STATIC void vg_ui(void) VG_GAMELOOP;
303
304 VG_STATIC void vg_checkgl( const char *src_info )
305 {
306 int fail = 0;
307
308 GLenum err;
309 while( (err = glGetError()) != GL_NO_ERROR )
310 {
311 vg_error( "(%s) OpenGL Error: #%d\n", src_info, err );
312 fail = 1;
313 }
314
315 if( fail )
316 vg_fatal_exit_loop( "OpenGL Error" );
317 }
318
319 void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos )
320 {
321 vg.mouse[0] = xpos;
322 vg.mouse[1] = ypos;
323 }
324
325 void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset )
326 {
327 vg.mouse_wheel[0] += xoffset;
328 vg.mouse_wheel[1] += yoffset;
329 }
330
331 void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
332 {
333 if( !w || !h )
334 {
335 vg_warn( "Got a invalid framebuffer size: %dx%d... ignoring\n", w, h );
336 return;
337 }
338
339 vg.window_x = w;
340 vg.window_y = h;
341
342 vg_framebuffer_resize(w,h);
343 }
344
345 VG_STATIC void vg_bake_shaders(void)
346 {
347 vg_acquire_thread_sync();
348
349 #if 0
350 vg_function_push( (struct vg_cmd)
351 {
352 .name = "shaders",
353 .function = vg_shaders_live_recompile
354 });
355 #endif
356
357 vg_shaders_compile();
358 vg_release_thread_sync();
359 }
360
361 VG_STATIC void vg_preload(void);
362 VG_STATIC void vg_load(void);
363 VG_STATIC void vg_load_full(void)
364 {
365 vg_preload();
366
367 /* internal */
368 vg_loader_highwater( vg_gamepad_init, NULL, NULL );
369 vg_loader_highwater( vg_lines_init, NULL, NULL );
370 vg_loader_highwater( vg_audio_init, vg_audio_free, NULL );
371 vg_loader_highwater( vg_profiler_init, NULL, NULL );
372
373 /* client */
374 vg_load();
375
376 vg_acquire_thread_sync();
377 vg.is_loaded = 1;
378 vg_release_thread_sync();
379 }
380
381 VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name )
382 {
383 char *arg;
384 while( vg_argp( argc, argv ) )
385 {
386 if( (arg = vg_opt_arg( 'w' )) )
387 {
388 vg.window_x = atoi( arg );
389 }
390
391 if( (arg = vg_opt_arg( 'h' )) )
392 {
393 vg.window_y = atoi( arg );
394 }
395
396 if( (arg = vg_long_opt_arg( "samples" )) )
397 {
398 vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
399 }
400
401 if( (arg = vg_long_opt_arg( "use-libc-malloc" )) )
402 {
403 vg_mem.use_libc_malloc = atoi( arg );
404 }
405 }
406
407 vg_alloc_quota();
408 vg_log_init();
409 vg_console_init();
410
411 glfwInit();
412 glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
413 glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
414 glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
415 //glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_FALSE );
416 glfwWindowHint( GLFW_CONTEXT_RELEASE_BEHAVIOR, GLFW_RELEASE_BEHAVIOR_FLUSH );
417
418 glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE );
419 glfwWindowHint( GLFW_DOUBLEBUFFER, GLFW_TRUE );
420
421 glfwWindowHint( GLFW_SAMPLES, vg.samples );
422
423 GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor();
424
425 const GLFWvidmode *mode = glfwGetVideoMode( monitor_primary );
426 glfwWindowHint( GLFW_RED_BITS, mode->redBits );
427 glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits );
428 glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits );
429
430 glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate );
431
432 if( !vg.window_x )
433 vg.window_x = mode->width;
434
435 if( !vg.window_y )
436 vg.window_y = mode->height;
437
438 vg.refresh_rate = mode->refreshRate;
439
440 if( (vg.window = glfwCreateWindow( vg.window_x, vg.window_y,
441 window_name, monitor_primary, NULL)) )
442 {
443 glfwGetFramebufferSize( vg.window, &vg.window_x, &vg.window_y );
444 vg_success( "Window created (%dx%d)\n", vg.window_x, vg.window_y );
445 }
446 else
447 {
448 vg_error( "GLFW Failed to initialize\n" );
449 return;
450 }
451
452 /* We need 3.1.2 for correct VSync on windows */
453 {
454 int vmaj, vmin, vrev;
455 glfwGetVersion( &vmaj, &vmin, &vrev );
456
457 if( vmaj < 3 ||
458 (vmaj == 3 && vmin < 1) ||
459 (vmaj == 3 && vmin == 1 && vrev < 2 ) )
460 {
461 vg_error( "GLFW out of date (%d.%d.%d); (3.1.2 is required)\n",
462 vmaj, vmin, vrev );
463
464 glfwTerminate();
465 return;
466 }
467
468 vg_success( "GLFW Version %d.%d.%d\n", vmaj, vmin, vrev );
469 }
470
471 glfwMakeContextCurrent( vg.window );
472 glfwSwapInterval( 1 );
473
474 glfwSetWindowSizeLimits( vg.window, 800, 600, GLFW_DONT_CARE,GLFW_DONT_CARE);
475 glfwSetFramebufferSizeCallback( vg.window, vg_framebuffer_resize_callback );
476
477 glfwSetCursorPosCallback( vg.window, vg_mouse_callback );
478 glfwSetScrollCallback( vg.window, vg_scroll_callback );
479
480 glfwSetCharCallback( vg.window, console_proc_wchar );
481 glfwSetKeyCallback( vg.window, console_proc_key );
482 glfwSetInputMode( vg.window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN );
483
484 if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) )
485 {
486 vg_error( "Glad Failed to initialize\n" );
487 glfwTerminate();
488 return;
489 }
490
491 const unsigned char* glver = glGetString( GL_VERSION );
492 vg_success( "Load setup complete, OpenGL version: %s\n", glver );
493
494 /* init systems
495 * -----------------------------------------------------------------------*/
496 ui_init_context();
497 vg_loader_init();
498
499 vg_mutex_init( &vg.mux_engine_status );
500 vg.engine_status = k_engine_status_running;
501
502 vg_opengl_sync_init();
503 vg_loader_start();
504
505 vg.accumulator = 0.75f * (1.0f/60.0f);
506
507 int loaded = 0;
508 while(1)
509 {
510 if( glfwWindowShouldClose( vg.window ) )
511 break;
512
513 v2_copy( (v2f){ 0.0f, 0.0f }, vg.mouse_wheel );
514 glfwPollEvents();
515
516 vg.time_real_last = vg.time_real;
517 vg.time_real = glfwGetTime();
518 vg.frame_delta = vg.time_real-vg.time_real_last;
519
520 /* scaled time */
521 vg.time_delta = vg.frame_delta * vg.time_rate;
522 vg.time += vg.time_delta;
523
524 if( vg.is_loaded )
525 {
526 if( !loaded )
527 {
528 vg_start();
529 loaded = 1;
530 }
531 }
532 else
533 {
534 vg_loader_render();
535 }
536
537 /*
538 * Game logic
539 * -------------------------------------------------------
540 */
541 vg_profile_begin( &vg_prof_update );
542 vg_update_inputs();
543
544 vg.engine_stage = k_engine_stage_update;
545 vg_update( loaded );
546
547 /* Fixed update loop */
548 vg.engine_stage = k_engine_stage_update_fixed;
549 vg.accumulator += vg.time_delta;
550
551 vg.fixed_iterations = 0;
552 while( vg.accumulator >= (VG_TIMESTEP_FIXED-0.00125) )
553 {
554 vg_update_fixed( loaded );
555
556 vg.accumulator -= VG_TIMESTEP_FIXED;
557 vg.accumulator = VG_MAX( 0.0, vg.accumulator );
558
559 vg.fixed_iterations ++;
560 if( vg.fixed_iterations == 8 )
561 {
562 break;
563 }
564 }
565
566 /*
567 * Rendering
568 * ---------------------------------------------
569 */
570 vg.engine_stage = k_engine_stage_update;
571 vg_update_post( loaded );
572 vg_profile_end( &vg_prof_update );
573
574 vg_profile_begin( &vg_prof_render );
575
576 if( loaded )
577 {
578 /* render */
579 vg.engine_stage = k_engine_stage_rendering;
580 vg_render();
581
582 /* ui */
583 vg.engine_stage = k_engine_stage_ui;
584 {
585 ui_begin( vg.window_x, vg.window_y );
586 ui_set_mouse( vg.mouse[0], vg.mouse[1],
587 vg_get_button_state( "primary" ) );
588
589 vg_profile_drawn(
590 (struct vg_profile *[]){&vg_prof_update,&vg_prof_render}, 2,
591 (1.0f/(float)vg.refresh_rate)*1000.0f,
592 (ui_rect){ 4, 4, 250, 0 }, 0
593 );
594
595 if( vg_profiler )
596 {
597
598 char perf[128];
599
600 snprintf( perf, 127,
601 "x: %d y: %d\n"
602 "refresh: %.1f (%.1fms)\n"
603 "samples: %d\n"
604 "iterations: %d (acc: %.3fms%%)\n",
605 vg.window_x, vg.window_y,
606 vg.refresh_rate, (1.0f/vg.refresh_rate)*1000.0f,
607 vg.samples,
608 vg.fixed_iterations,
609 (vg.accumulator/VG_TIMESTEP_FIXED)*100.0f );
610
611 ui_text( (ui_rect){258, 4+24+12,0,0},perf, 1,0);
612 }
613
614 audio_debug_ui( vg.pv );
615 vg_ui();
616 vg_console_draw();
617
618 ui_resolve();
619 ui_draw( NULL );
620 }
621 }
622
623 vg_profile_end( &vg_prof_render );
624
625 glfwSwapBuffers( vg.window );
626 vg_run_synced_content();
627 }
628
629 vg_console_write_persistent();
630
631 vg_mutex_lock( &vg.mux_engine_status );
632 vg.engine_status = k_engine_status_none;
633 vg_mutex_unlock( &vg.mux_engine_status );
634
635 vg_loader_free();
636
637 vg_success( "If you see this it means everything went.. \"well\".....\n" );
638 glfwTerminate();
639 }
640
641 /*
642 * Immediately transfer away from calling thread into a safe loop, signal for
643 * others to shutdown, then free everything once the user closes the window.
644 *
645 * FIXME(bug): glfwWindowShouldClose() never returns 1 in windows via wine, ONLY
646 * when calling the program from outside its normal directory.
647 */
648 VG_STATIC void vg_fatal_exit_loop( const char *error )
649 {
650 /*
651 * https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
652 * thanks gnu <3
653 *
654 * TODO: this on windows?
655 */
656
657 #ifndef _WIN32
658
659 void *array[20];
660 char **strings;
661 int size, i;
662
663 size = backtrace( array, 20 );
664 strings = backtrace_symbols( array, size );
665
666 if( strings != NULL )
667 {
668 vg_error( "---------------- gnu backtrace -------------\n" );
669
670 for( int i=0; i<size; i++ )
671 vg_info( "%s\n", strings[i] );
672
673 vg_error( "---------------- gnu backtrace -------------\n" );
674 }
675
676 free( strings );
677
678 #endif
679
680 vg_error( "Fatal error: %s\n", error );
681 assert( vg_semaphore_trywait( &vg.sem_fatal ) );
682
683 vg_mutex_lock( &vg.mux_engine_status );
684
685 if( vg.engine_status == k_engine_status_none )
686 {
687 vg_mutex_unlock( &vg.mux_engine_status );
688
689 /* TODO: Correct shutdown before other systems */
690 exit(0);
691 }
692 else
693 {
694 vg_mutex_unlock( &vg.mux_engine_status );
695
696 /*
697 * if main
698 * if loader running
699 * wait until loader checks in, it will die
700 * else
701 * pass immediately
702 * else
703 * if have context
704 * pass immediately
705 * else
706 * wait for main to get to us, it will never be used again
707 *
708 * undefined behaviour:
709 * fatal_exit_loop is called in both threads, preventing an appropriate
710 * reaction to the crash. This *should* be made
711 * obvious by the assertion
712 */
713 vg_acquire_thread_sync();
714
715 vg_mutex_lock( &vg.mux_engine_status );
716 vg.engine_status = k_engine_status_crashed;
717 vg.str_const_engine_err = error;
718 vg_mutex_unlock( &vg.mux_engine_status );
719
720 /*
721 * Wait for loader to finish what it was doing, if it was running.
722 * Then we can continue in our nice error screen
723 */
724 if( vg_thread_info.purpose == k_thread_purpose_main )
725 {
726 vg_semaphore_wait( &vg.sem_loader );
727 }
728 vg_audio_free(NULL);
729
730 while(1)
731 {
732 if( glfwWindowShouldClose( vg.window ) )
733 break;
734
735 if( glfwGetKey( vg.window, GLFW_KEY_ESCAPE ) )
736 break;
737
738 glfwPollEvents();
739
740 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
741 glEnable(GL_BLEND);
742 glDisable(GL_DEPTH_TEST);
743 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
744 glBlendEquation(GL_FUNC_ADD);
745
746 glClearColor( 0.15f + sinf(glfwGetTime())*0.1f, 0.0f, 0.0f,1.0f );
747 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
748 glViewport( 0,0, vg.window_x, vg.window_y );
749
750 vg_render_log();
751
752 glfwSwapBuffers( vg.window );
753 }
754
755 /* Can now shutdown and EXIT */
756 vg_loader_free();
757 glfwTerminate();
758 exit(0);
759 }
760 }
761
762 #else
763
764 VG_STATIC void vg_fatal_exit_loop( const char *error )
765 {
766 vg_error( "Fatal error: %s\n", error );
767 exit(0);
768 }
769
770 #endif
771
772 /*
773 * Graphic cards will check these to force it to use the GPU
774 */
775 u32 NvOptimusEnablement = 0x00000001;
776 int AmdPowerXpressRequestHighPerformance = 1;
777
778 #endif