delete std::mutex, minor cleanup
This commit is contained in:
parent
737062b339
commit
56dec1cf93
@ -1,3 +1,7 @@
|
|||||||
|
// Some notes:
|
||||||
|
// To generate the intermediate to see how many lines are being compiled, in x64 Native Tools Command Prompt for VS2022 or whatever
|
||||||
|
// cl /P /EP exe_main.cpp
|
||||||
|
// tokei exe_main.i
|
||||||
VERSION :: "0.1a";
|
VERSION :: "0.1a";
|
||||||
|
|
||||||
#run,stallable build_cpp_project();
|
#run,stallable build_cpp_project();
|
||||||
|
|||||||
166
imgui_main.cpp
Normal file
166
imgui_main.cpp
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include <d3d11.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include "ImGui_Supplementary.cpp"
|
||||||
|
|
||||||
|
void ImGui_Application () {
|
||||||
|
// Make process DPI aware and obtain main monitor scale
|
||||||
|
ImGui_ImplWin32_EnableDpiAwareness();
|
||||||
|
f32 main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
|
||||||
|
|
||||||
|
// Create application window
|
||||||
|
WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
|
||||||
|
::RegisterClassExW(&wc);
|
||||||
|
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
|
||||||
|
|
||||||
|
// Initialize Direct3D
|
||||||
|
if (!CreateDeviceD3D(hwnd)) {
|
||||||
|
CleanupDeviceD3D();
|
||||||
|
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the window
|
||||||
|
::ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||||||
|
::UpdateWindow(hwnd);
|
||||||
|
|
||||||
|
// Setup Dear ImGui context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
printf("ImGui Version %s \n", ImGui::GetVersion());
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||||
|
|
||||||
|
//io.ConfigViewportsNoAutoMerge = true;
|
||||||
|
//io.ConfigViewportsNoTaskBarIcon = true;
|
||||||
|
//io.ConfigDockingAlwaysTabBar = true;
|
||||||
|
//io.ConfigDockingTransparentPayload = true;
|
||||||
|
|
||||||
|
// Setup Dear ImGui style
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
|
// Setup scaling
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
|
||||||
|
style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose)
|
||||||
|
io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
|
||||||
|
io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
|
||||||
|
|
||||||
|
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
|
{
|
||||||
|
style.WindowRounding = 0.0f;
|
||||||
|
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Platform/Renderer backends
|
||||||
|
ImGui_ImplWin32_Init(hwnd);
|
||||||
|
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
|
||||||
|
|
||||||
|
// #TODO: #ImGUI - Load fonts:
|
||||||
|
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
|
||||||
|
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
|
||||||
|
// - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
|
||||||
|
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
|
||||||
|
// - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author!
|
||||||
|
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
|
||||||
|
//style.FontSizeBase = 20.0f;
|
||||||
|
//io.Fonts->AddFontDefault();
|
||||||
|
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
|
||||||
|
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
|
||||||
|
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
|
||||||
|
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
|
||||||
|
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
|
||||||
|
//IM_ASSERT(font != nullptr);
|
||||||
|
|
||||||
|
bool show_demo_window = true;
|
||||||
|
bool show_another_window = false;
|
||||||
|
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
// Poll and handle messages (inputs, window resize, etc.)
|
||||||
|
// See the WndProc() function below for our to dispatch events to the Win32 backend.
|
||||||
|
MSG msg;
|
||||||
|
while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) {
|
||||||
|
::TranslateMessage(&msg);
|
||||||
|
::DispatchMessage(&msg);
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Handle window being minimized or screen locked
|
||||||
|
if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) {
|
||||||
|
::Sleep(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_SwapChainOccluded = false;
|
||||||
|
|
||||||
|
// Handle window resize (we don't resize directly in the WM_SIZE handler)
|
||||||
|
if (g_ResizeWidth != 0 && g_ResizeHeight != 0) {
|
||||||
|
CleanupRenderTarget();
|
||||||
|
g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0);
|
||||||
|
g_ResizeWidth = g_ResizeHeight = 0;
|
||||||
|
CreateRenderTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the Dear ImGui frame
|
||||||
|
ImGui_ImplDX11_NewFrame();
|
||||||
|
ImGui_ImplWin32_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
// Simple dockspace:
|
||||||
|
ImGui::DockSpaceOverViewport();
|
||||||
|
|
||||||
|
{
|
||||||
|
ImGui::Begin("Hello, world!");
|
||||||
|
|
||||||
|
if (ImGui::Button("Create New Window")) {
|
||||||
|
// I think that create_window should take few parameters, and we have other APIs for
|
||||||
|
// styling, positioning, etc. I just call this and want to get a window.
|
||||||
|
// auto new_window = create_window(window_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Position recently created Window")) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
ImGui::Render();
|
||||||
|
const f32 clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
|
||||||
|
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
|
||||||
|
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
|
||||||
|
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
|
// Update and Render additional Platform Windows
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
|
{
|
||||||
|
ImGui::UpdatePlatformWindows();
|
||||||
|
ImGui::RenderPlatformWindowsDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present
|
||||||
|
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
|
||||||
|
// HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
|
||||||
|
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
|
||||||
|
} // while (!done)
|
||||||
|
|
||||||
|
// Cleanupre
|
||||||
|
ImGui_ImplDX11_Shutdown();
|
||||||
|
ImGui_ImplWin32_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
CleanupDeviceD3D();
|
||||||
|
::DestroyWindow(hwnd);
|
||||||
|
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||||||
|
}
|
||||||
@ -61,9 +61,8 @@ typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count);
|
|||||||
void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
||||||
|
|
||||||
// Interface API for normal use (idk how to explain - see Arena_Table.cpp)
|
// Interface API for normal use (idk how to explain - see Arena_Table.cpp)
|
||||||
#include <mutex> // #TODO: Replace with Mutex (see OS_Win32.cpp)
|
|
||||||
struct Arena_Table {
|
struct Arena_Table {
|
||||||
std::mutex mutex;
|
Mutex mutex;
|
||||||
s32 in_flight_count[6];
|
s32 in_flight_count[6];
|
||||||
Array<Arena*> free_table[6];
|
Array<Arena*> free_table[6];
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ template <typename T, typename U> void table_init (ArenaTable<T, U>* table, s64
|
|||||||
}
|
}
|
||||||
// default hash and compare functions:
|
// default hash and compare functions:
|
||||||
table->hash_function = table_hash_function_fnv1a;
|
table->hash_function = table_hash_function_fnv1a;
|
||||||
table->compare_function = keys_match_u64;
|
table->compare_function = u64_keys_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds given key value pair to the table, returns a pointer to the inserted value.
|
// Adds given key value pair to the table, returns a pointer to the inserted value.
|
||||||
|
|||||||
@ -7,6 +7,7 @@ global Arena_Table* arena_table;
|
|||||||
|
|
||||||
// Only call once from main thread!
|
// Only call once from main thread!
|
||||||
void initialize_arena_table (Allocator allocator) {
|
void initialize_arena_table (Allocator allocator) {
|
||||||
|
mutex_init(&arena_table->mutex);
|
||||||
Assert(arena_table != nullptr);
|
Assert(arena_table != nullptr);
|
||||||
if (arena_table->initialized)
|
if (arena_table->initialized)
|
||||||
return;
|
return;
|
||||||
@ -27,7 +28,7 @@ void initialize_arena_table (Allocator allocator) {
|
|||||||
Arena* next_arena (Arena_Reserve reserve_size) {
|
Arena* next_arena (Arena_Reserve reserve_size) {
|
||||||
Assert(arena_table != nullptr);
|
Assert(arena_table != nullptr);
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
std::lock_guard<std::mutex> lock(arena_table->mutex);
|
lock_guard(&arena_table->mutex);
|
||||||
s64 reserve_index = (s64)reserve_size;
|
s64 reserve_index = (s64)reserve_size;
|
||||||
|
|
||||||
if (!arena_table->free_table[reserve_index].count) {
|
if (!arena_table->free_table[reserve_index].count) {
|
||||||
@ -41,6 +42,8 @@ Arena* next_arena (Arena_Reserve reserve_size) {
|
|||||||
|
|
||||||
arena_table->in_flight_count[reserve_index] += 1;
|
arena_table->in_flight_count[reserve_index] += 1;
|
||||||
|
|
||||||
|
unlock(&arena_table->mutex);
|
||||||
|
|
||||||
Assert(arena != nullptr);
|
Assert(arena != nullptr);
|
||||||
return arena;
|
return arena;
|
||||||
}
|
}
|
||||||
@ -50,7 +53,7 @@ void release_arena (Arena* arena, bool delete_extra_pages) {
|
|||||||
Assert(arena != nullptr);
|
Assert(arena != nullptr);
|
||||||
Assert(arena_is_bootstrapped(arena));
|
Assert(arena_is_bootstrapped(arena));
|
||||||
// Only put into free table if arena is bootstrapped?
|
// Only put into free table if arena is bootstrapped?
|
||||||
std::lock_guard<std::mutex> lock(arena_table->mutex);
|
lock_guard(&arena_table->mutex);
|
||||||
s64 reserve_index = (s64)arena->reserve_size;
|
s64 reserve_index = (s64)arena->reserve_size;
|
||||||
|
|
||||||
#if ARENA_DEBUG
|
#if ARENA_DEBUG
|
||||||
@ -72,4 +75,5 @@ void release_arena (Arena* arena, bool delete_extra_pages) {
|
|||||||
// arenas_to_delete_count -= 1;
|
// arenas_to_delete_count -= 1;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
113
lib/Base/Base.h
113
lib/Base/Base.h
@ -199,35 +199,94 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
|
|||||||
#define context_logger() &thread_context()->logger
|
#define context_logger() &thread_context()->logger
|
||||||
|
|
||||||
// #TODO #constexpr #MATH - make these constexpr
|
// #TODO #constexpr #MATH - make these constexpr
|
||||||
/*
|
// CHECK THAT THESE ARE CORRECT!
|
||||||
TAU :: cast(float32) 6.283185;
|
constexpr f32 TAU = 6.283185f;
|
||||||
TAU64 :: 6.28318530717958648;
|
constexpr f64 TAU_64 = 6.28318530717958648;
|
||||||
|
constexpr f32 PI = 3.1415927f;
|
||||||
|
constexpr f64 PI_64 = 3.141592653589793;
|
||||||
|
|
||||||
PI :: cast(float32) 3.1415927;
|
constexpr f32 FLOAT16_MAX = 65504.0;
|
||||||
PI64 :: 3.141592653589793;
|
|
||||||
|
|
||||||
FLOAT16_MAX : float : 65504.0;
|
constexpr f32 FLOAT32_MIN = (f32)(0x00800000);
|
||||||
|
constexpr f32 FLOAT32_MAX = (f32)(0x7F7FFFFF);
|
||||||
|
constexpr f32 FLOAT32_INFINITY = (f32)(0x7F800000);
|
||||||
|
constexpr f32 FLOAT32_NAN = (f32)(0x7FBFFFFF);
|
||||||
|
|
||||||
FLOAT32_MIN :: 0h00800000;
|
constexpr f64 FLOAT64_MIN = (f64)(0x0010000000000000ULL);
|
||||||
FLOAT32_MAX :: 0h7F7FFFFF;
|
constexpr f64 FLOAT64_MAX = (f64)(0x7FEFFFFFFFFFFFFFULL);
|
||||||
FLOAT32_INFINITY :: 0h7F800000;
|
constexpr f64 FLOAT64_INFINITY = (f64)(0x7FF0000000000000ULL);
|
||||||
FLOAT32_NAN :: 0h7FBFFFFF;
|
constexpr f64 FLOAT64_NAN = (f64)(0x7FF7FFFFFFFFFFFFULL);
|
||||||
|
|
||||||
FLOAT64_MIN :: 0h00100000_00000000;
|
constexpr s8 S8_MIN = -128;
|
||||||
FLOAT64_MAX :: 0h7FEFFFFF_FFFFFFFF;
|
constexpr s8 S8_MAX = 127;
|
||||||
FLOAT64_INFINITY :: 0h7FF00000_00000000;
|
constexpr u8 U8_MAX = 255;
|
||||||
FLOAT64_NAN :: 0h7FF7FFFF_FFFFFFFF;
|
constexpr s16 S16_MIN = -32768;
|
||||||
|
constexpr s16 S16_MAX = 32767;
|
||||||
|
constexpr u16 U16_MAX = 0xffff;
|
||||||
|
constexpr s32 S32_MIN = 0x80000000;
|
||||||
|
constexpr s32 S32_MAX = 0x7fffffff;
|
||||||
|
constexpr u32 U32_MAX = 0xffffffff;
|
||||||
|
constexpr s64 S64_MIN = 0x8000000000000000LL;
|
||||||
|
constexpr s64 S64_MAX = 0x7fffffffffffffffLL;
|
||||||
|
constexpr u64 U64_MAX = 0xffffffffffffffffULL;
|
||||||
|
|
||||||
S8_MIN :s8: -128;
|
// #thread_primitives #move?
|
||||||
S8_MAX :s8: 127;
|
#if OS_WINDOWS
|
||||||
U8_MAX :u8: 255;
|
struct Condition_Variable {
|
||||||
S16_MIN :s16: -32768;
|
CONDITION_VARIABLE condition_variable;
|
||||||
S16_MAX :s16: 32767;
|
};
|
||||||
U16_MAX :u16: 0xffff;
|
struct Semaphore {
|
||||||
S32_MIN :s32: 0x8000_0000;
|
HANDLE event;
|
||||||
S32_MAX :s32: 0x7fff_ffff;
|
};
|
||||||
U32_MAX :u32: 0xffff_ffff;
|
struct Mutex {
|
||||||
S64_MIN :s64: 0x8000_0000_0000_0000;
|
CRITICAL_SECTION csection;
|
||||||
S64_MAX :s64: 0x7fff_ffff_ffff_ffff;
|
};
|
||||||
U64_MAX :u64: 0xffff_ffff_ffff_ffff;
|
struct OS_Thread {
|
||||||
*/
|
HANDLE windows_thread;
|
||||||
|
s32 windows_thread_id;
|
||||||
|
};
|
||||||
|
struct File {
|
||||||
|
HANDLE handle;
|
||||||
|
};
|
||||||
|
internal void mutex_init (Mutex* mutex);
|
||||||
|
internal void mutex_destroy (Mutex* mutex);
|
||||||
|
internal void lock (Mutex* mutex);
|
||||||
|
internal void unlock (Mutex* mutex);
|
||||||
|
#endif
|
||||||
|
#define POSIX_THREADS OS_LINUX || OS_MACOS || OS_IOS || OS_ANDROID
|
||||||
|
#if OS_MACOS
|
||||||
|
struct Semaphore {
|
||||||
|
task_t owner;
|
||||||
|
semaphore_t event = 0;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#if OS_LINUX || OS_ANDROID
|
||||||
|
struct Semaphore {
|
||||||
|
sem_t semaphore;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#if OS_IS_UNIX // #posix threads
|
||||||
|
struct OS_Thread {
|
||||||
|
pthread_t thread_handle;
|
||||||
|
Semaphore is_alive;
|
||||||
|
Semaphore suspended;
|
||||||
|
b32 is_done;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define lock_guard(x) \
|
||||||
|
Mutex_Lock_Guard Concat(_auto_lock_guard_, __LINE__)(x)
|
||||||
|
|
||||||
|
struct Mutex_Lock_Guard {
|
||||||
|
Mutex* mutex;
|
||||||
|
|
||||||
|
Mutex_Lock_Guard (Mutex* mutex) {
|
||||||
|
this->mutex = mutex;
|
||||||
|
lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Mutex_Lock_Guard () {
|
||||||
|
unlock(mutex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
#include <mutex> // #TODO: Replace with Mutex (see OS_Win32.cpp)
|
|
||||||
global General_Allocator gAllocator; // @Shared
|
global General_Allocator gAllocator; // @Shared
|
||||||
global std::mutex allocator_mutex;
|
global Mutex allocator_mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !COMPILER_MSVC
|
#if !COMPILER_MSVC
|
||||||
@ -39,6 +38,7 @@ bool GPAllocator_Tracking_Enabled () {
|
|||||||
|
|
||||||
void GPAllocator_Initialize_Allocation_Tracker () {
|
void GPAllocator_Initialize_Allocation_Tracker () {
|
||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
|
mutex_init(&allocator_mutex);
|
||||||
constexpr s64 alignment = 64;
|
constexpr s64 alignment = 64;
|
||||||
s64 item_count_max = 64 * 4096;
|
s64 item_count_max = 64 * 4096;
|
||||||
s64 total_allocation_size = item_count_max * sizeof(Allocation);
|
s64 total_allocation_size = item_count_max * sizeof(Allocation);
|
||||||
@ -50,7 +50,7 @@ void GPAllocator_Initialize_Allocation_Tracker () {
|
|||||||
|
|
||||||
bool GPAllocator_Is_This_Yours (void* old_memory) {
|
bool GPAllocator_Is_This_Yours (void* old_memory) {
|
||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
std::lock_guard<std::mutex> lock(allocator_mutex);
|
lock_guard(&allocator_mutex);
|
||||||
|
|
||||||
s64 old_size = 0;
|
s64 old_size = 0;
|
||||||
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
||||||
@ -67,7 +67,7 @@ void Add_Allocation(s64 new_size, void* new_memory_address, s32 alignment) {
|
|||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
if (new_memory_address == nullptr) return;
|
if (new_memory_address == nullptr) return;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(allocator_mutex);
|
lock_guard(&allocator_mutex);
|
||||||
Allocation allocation = {new_size, new_memory_address, alignment};
|
Allocation allocation = {new_size, new_memory_address, alignment};
|
||||||
array_add(gAllocator.allocations, allocation);
|
array_add(gAllocator.allocations, allocation);
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ void Add_Allocation(s64 new_size, void* new_memory_address, s32 alignment) {
|
|||||||
|
|
||||||
void Remove_Allocation(void* old_memory) {
|
void Remove_Allocation(void* old_memory) {
|
||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
std::lock_guard<std::mutex> lock(allocator_mutex);
|
lock_guard(&allocator_mutex);
|
||||||
|
|
||||||
s64 old_size = 0;
|
s64 old_size = 0;
|
||||||
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
for (s64 i = 0; i < gAllocator.allocations.count; i += 1) {
|
||||||
|
|||||||
@ -1,21 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
|
#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
|
||||||
#define GP_ALLOCATOR_VERY_DEBUG 0
|
#define GP_ALLOCATOR_VERY_DEBUG BUILD_DEBUG && 0
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
#include <malloc.h> // _aligned_malloc, _aligned_realloc, _aligned_free (MSVC Only!)
|
#include <malloc.h> // _aligned_malloc, _aligned_realloc, _aligned_free (MSVC Only!)
|
||||||
#if GP_ALLOCATOR_VERY_DEBUG
|
#if GP_ALLOCATOR_VERY_DEBUG
|
||||||
|
#include <crtdbg.h> // required for _dbg variants
|
||||||
#define Aligned_Alloc(sz, align) _aligned_malloc_dbg(sz, align, __FILE__, __LINE__)
|
#define Aligned_Alloc(sz, align) _aligned_malloc_dbg(sz, align, __FILE__, __LINE__)
|
||||||
#define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc_dbg(ptr, sz, align, __FILE__, __LINE__)
|
#define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc_dbg(ptr, sz, align, __FILE__, __LINE__)
|
||||||
#define Aligned_Free(ptr) _aligned_free_dbg(ptr)
|
#define Aligned_Free(ptr) _aligned_free_dbg(ptr)
|
||||||
#else
|
#else
|
||||||
#define Aligned_Alloc(sz, align) std::malloc(sz)//_aligned_malloc(sz, align)
|
#define Aligned_Alloc(sz, align) _aligned_malloc(sz, align)
|
||||||
#define Aligned_Realloc(old_sz, ptr, sz, align) std::realloc(ptr, sz)//_aligned_realloc(ptr, sz, align)
|
#define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc(ptr, sz, align)
|
||||||
#define Aligned_Free(ptr) std::free(ptr)//_aligned_free(ptr)
|
#define Aligned_Free(ptr) _aligned_free(ptr)
|
||||||
// #define Aligned_Alloc(sz, align) _aligned_malloc(sz, align)
|
|
||||||
// #define Aligned_Realloc(old_sz, ptr, sz, align) _aligned_realloc(ptr, sz, align)
|
|
||||||
// #define Aligned_Free(ptr) _aligned_free(ptr)
|
|
||||||
#endif
|
#endif
|
||||||
#else // Non-MSVC (POSIX / GCC / Clang)
|
#else // Non-MSVC (POSIX / GCC / Clang)
|
||||||
#include <cstdlib> // std::aligned_alloc
|
#include <cstdlib> // std::aligned_alloc
|
||||||
|
|||||||
@ -51,18 +51,18 @@ u32 table_hash_function_knuth (void* key, s64 size) {
|
|||||||
u32 string_hash_function_fnv1a (void* key, s64 size) {
|
u32 string_hash_function_fnv1a (void* key, s64 size) {
|
||||||
Assert(size == sizeof(string));
|
Assert(size == sizeof(string));
|
||||||
string key_as_string = *((string*)key);
|
string key_as_string = *((string*)key);
|
||||||
|
// #TODO It should be xor folded to the desired range rather than shifted.
|
||||||
return (u32)(fnv1a_hash_any(key_as_string.data, key_as_string.count));
|
return (u32)(fnv1a_hash_any(key_as_string.data, key_as_string.count));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool keys_match_u64 (void* key1, void* key2) {
|
bool u64_keys_match (void* key1, void* key2) {
|
||||||
u64 key1_u64 = *(u64*)key1;
|
u64 key1_u64 = *(u64*)key1;
|
||||||
u64 key2_u64 = *(u64*)key2;
|
u64 key2_u64 = *(u64*)key2;
|
||||||
|
|
||||||
return key1_u64 == key2_u64;
|
return key1_u64 == key2_u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_keys_match_u64 (void* key1, void* key2) {
|
bool string_keys_match (void* key1, void* key2) {
|
||||||
string key1_s = *((string*)key1);
|
string key1_s = *((string*)key1);
|
||||||
string key2_s = *((string*)key2);
|
string key2_s = *((string*)key2);
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,7 @@ template <typename T, typename U> void table_init (Table<T, U>* table, s64 slots
|
|||||||
}
|
}
|
||||||
// default hash and compare functions:
|
// default hash and compare functions:
|
||||||
table->hash_function = table_hash_function_fnv1a;
|
table->hash_function = table_hash_function_fnv1a;
|
||||||
table->compare_function = keys_match_u64;
|
table->compare_function = u64_keys_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds given key value pair to the table, returns a pointer to the inserted value.
|
// Adds given key value pair to the table, returns a pointer to the inserted value.
|
||||||
|
|||||||
@ -1,40 +1,3 @@
|
|||||||
// #thread_primitives
|
|
||||||
#if OS_WINDOWS
|
|
||||||
struct Condition_Variable {
|
|
||||||
CONDITION_VARIABLE condition_variable;
|
|
||||||
};
|
|
||||||
struct Semaphore {
|
|
||||||
HANDLE event;
|
|
||||||
};
|
|
||||||
struct Mutex {
|
|
||||||
CRITICAL_SECTION csection;
|
|
||||||
};
|
|
||||||
struct OS_Thread {
|
|
||||||
HANDLE windows_thread;
|
|
||||||
s32 windows_thread_id;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
#define POSIX_THREADS OS_LINUX || OS_MACOS || OS_IOS || OS_ANDROID
|
|
||||||
#if OS_MACOS
|
|
||||||
struct Semaphore {
|
|
||||||
task_t owner;
|
|
||||||
semaphore_t event = 0;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
#if OS_LINUX || OS_ANDROID
|
|
||||||
struct Semaphore {
|
|
||||||
sem_t semaphore;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
#if OS_IS_UNIX // #posix threads
|
|
||||||
struct OS_Thread {
|
|
||||||
pthread_t thread_handle;
|
|
||||||
Semaphore is_alive;
|
|
||||||
Semaphore suspended;
|
|
||||||
b32 is_done;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// really hacky forward declares.
|
// really hacky forward declares.
|
||||||
struct Work_Entry;
|
struct Work_Entry;
|
||||||
struct Worker_Info;
|
struct Worker_Info;
|
||||||
|
|||||||
@ -1,14 +1,6 @@
|
|||||||
f64 GetUnixTimestamp ();
|
f64 GetUnixTimestamp ();
|
||||||
s64 GetUnixTimestampNanoseconds ();
|
s64 GetUnixTimestampNanoseconds ();
|
||||||
|
|
||||||
struct Condition_Variable;
|
|
||||||
struct Semaphore;
|
|
||||||
struct Mutex;
|
|
||||||
struct OS_Thread;
|
|
||||||
struct File {
|
|
||||||
HANDLE handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
// struct File_Contents {
|
// struct File_Contents {
|
||||||
// File file = {};
|
// File file = {};
|
||||||
// ArrayView<u8> file_data = {};
|
// ArrayView<u8> file_data = {};
|
||||||
@ -21,11 +13,6 @@ enum class Wait_For_Result : s32 {
|
|||||||
ERROR = 2 // can't use ERROR because of Windows.h *sigh*
|
ERROR = 2 // can't use ERROR because of Windows.h *sigh*
|
||||||
};
|
};
|
||||||
|
|
||||||
internal void mutex_init (Mutex* mutex);
|
|
||||||
internal void mutex_destroy (Mutex* mutex);
|
|
||||||
internal void lock (Mutex* mutex);
|
|
||||||
internal void unlock (Mutex* mutex);
|
|
||||||
|
|
||||||
internal void semaphore_init (Semaphore* sem, s32 initial_value = 0);
|
internal void semaphore_init (Semaphore* sem, s32 initial_value = 0);
|
||||||
internal void semaphore_destroy (Semaphore* sem);
|
internal void semaphore_destroy (Semaphore* sem);
|
||||||
internal void signal (Semaphore* sem);
|
internal void signal (Semaphore* sem);
|
||||||
|
|||||||
@ -6,6 +6,10 @@
|
|||||||
// typedefs and procedures that require forward declaration to the top with a metaprogram.
|
// typedefs and procedures that require forward declaration to the top with a metaprogram.
|
||||||
// [ ] Linux / MacOS Ports
|
// [ ] Linux / MacOS Ports
|
||||||
|
|
||||||
|
// Not implemented as distinct types: singly-linked list, doubly-linked list
|
||||||
|
// I'll see where it's used most often and see if I can make macros or templates to make
|
||||||
|
// them easier to use.
|
||||||
|
|
||||||
#include "lib/meta_generated.h"
|
#include "lib/meta_generated.h"
|
||||||
#include "lib/Base/Base.h"
|
#include "lib/Base/Base.h"
|
||||||
#include "lib/Base/Allocator.h"
|
#include "lib/Base/Allocator.h"
|
||||||
|
|||||||
@ -7,179 +7,14 @@ internal void Main_Entry_Point (int argc, WCHAR **argv);
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
#include <cstdlib> // globals __argc, __argv
|
||||||
|
|
||||||
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) {
|
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) {
|
||||||
Main_Entry_Point(__argc, __wargv);
|
Main_Entry_Point(__argc, __wargv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
/*
|
|
||||||
#include <d3d11.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
#include "ImGui_Supplementary.cpp"
|
|
||||||
|
|
||||||
void ImGui_Application () {
|
|
||||||
// Make process DPI aware and obtain main monitor scale
|
|
||||||
ImGui_ImplWin32_EnableDpiAwareness();
|
|
||||||
f32 main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
|
|
||||||
|
|
||||||
// Create application window
|
|
||||||
WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
|
|
||||||
::RegisterClassExW(&wc);
|
|
||||||
HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
|
|
||||||
|
|
||||||
// Initialize Direct3D
|
|
||||||
if (!CreateDeviceD3D(hwnd)) {
|
|
||||||
CleanupDeviceD3D();
|
|
||||||
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the window
|
|
||||||
::ShowWindow(hwnd, SW_SHOWDEFAULT);
|
|
||||||
::UpdateWindow(hwnd);
|
|
||||||
|
|
||||||
// Setup Dear ImGui context
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
printf("ImGui Version %s \n", ImGui::GetVersion());
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
|
||||||
|
|
||||||
//io.ConfigViewportsNoAutoMerge = true;
|
|
||||||
//io.ConfigViewportsNoTaskBarIcon = true;
|
|
||||||
//io.ConfigDockingAlwaysTabBar = true;
|
|
||||||
//io.ConfigDockingTransparentPayload = true;
|
|
||||||
|
|
||||||
// Setup Dear ImGui style
|
|
||||||
ImGui::StyleColorsDark();
|
|
||||||
|
|
||||||
// Setup scaling
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
|
||||||
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
|
|
||||||
style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose)
|
|
||||||
io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
|
|
||||||
io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
|
|
||||||
|
|
||||||
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
|
||||||
{
|
|
||||||
style.WindowRounding = 0.0f;
|
|
||||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup Platform/Renderer backends
|
|
||||||
ImGui_ImplWin32_Init(hwnd);
|
|
||||||
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
|
|
||||||
|
|
||||||
// #TODO: #ImGUI - Load fonts:
|
|
||||||
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
|
|
||||||
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
|
|
||||||
// - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
|
|
||||||
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
|
|
||||||
// - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author!
|
|
||||||
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
|
|
||||||
//style.FontSizeBase = 20.0f;
|
|
||||||
//io.Fonts->AddFontDefault();
|
|
||||||
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
|
|
||||||
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
|
|
||||||
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
|
|
||||||
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
|
|
||||||
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
|
|
||||||
//IM_ASSERT(font != nullptr);
|
|
||||||
|
|
||||||
bool show_demo_window = true;
|
|
||||||
bool show_another_window = false;
|
|
||||||
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
while (!done) {
|
|
||||||
// Poll and handle messages (inputs, window resize, etc.)
|
|
||||||
// See the WndProc() function below for our to dispatch events to the Win32 backend.
|
|
||||||
MSG msg;
|
|
||||||
while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) {
|
|
||||||
::TranslateMessage(&msg);
|
|
||||||
::DispatchMessage(&msg);
|
|
||||||
if (msg.message == WM_QUIT)
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
if (done)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Handle window being minimized or screen locked
|
|
||||||
if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) {
|
|
||||||
::Sleep(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
g_SwapChainOccluded = false;
|
|
||||||
|
|
||||||
// Handle window resize (we don't resize directly in the WM_SIZE handler)
|
|
||||||
if (g_ResizeWidth != 0 && g_ResizeHeight != 0) {
|
|
||||||
CleanupRenderTarget();
|
|
||||||
g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0);
|
|
||||||
g_ResizeWidth = g_ResizeHeight = 0;
|
|
||||||
CreateRenderTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplDX11_NewFrame();
|
|
||||||
ImGui_ImplWin32_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
// Simple dockspace:
|
|
||||||
ImGui::DockSpaceOverViewport();
|
|
||||||
|
|
||||||
{
|
|
||||||
ImGui::Begin("Hello, world!");
|
|
||||||
|
|
||||||
if (ImGui::Button("Create New Window")) {
|
|
||||||
// I think that create_window should take few parameters, and we have other APIs for
|
|
||||||
// styling, positioning, etc. I just call this and want to get a window.
|
|
||||||
// auto new_window = create_window(window_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button("Position recently created Window")) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Rendering
|
|
||||||
ImGui::Render();
|
|
||||||
const f32 clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
|
|
||||||
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
|
|
||||||
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
|
|
||||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
|
|
||||||
// Update and Render additional Platform Windows
|
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
|
||||||
{
|
|
||||||
ImGui::UpdatePlatformWindows();
|
|
||||||
ImGui::RenderPlatformWindowsDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Present
|
|
||||||
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
|
|
||||||
// HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
|
|
||||||
g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
|
|
||||||
} // while (!done)
|
|
||||||
|
|
||||||
// Cleanupre
|
|
||||||
ImGui_ImplDX11_Shutdown();
|
|
||||||
ImGui_ImplWin32_Shutdown();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
|
|
||||||
CleanupDeviceD3D();
|
|
||||||
::DestroyWindow(hwnd);
|
|
||||||
::UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
||||||
set_cpu_base_frequency(3200); // REQUIRED FOR TIMING MODULE! will depend on CPU
|
set_cpu_base_frequency(3200); // REQUIRED FOR TIMING MODULE! will depend on CPU
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user