mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-04 06:12:04 +00:00
[client] add ImPlot and rework latency graphs
This commit is contained in:
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -5,7 +5,7 @@
|
|||||||
path = repos/PureSpice
|
path = repos/PureSpice
|
||||||
url = https://github.com/gnif/PureSpice
|
url = https://github.com/gnif/PureSpice
|
||||||
[submodule "repos/cimgui"]
|
[submodule "repos/cimgui"]
|
||||||
path = repos/cimgui
|
path = repos/gui/cimgui
|
||||||
url = https://github.com/cimgui/cimgui.git
|
url = https://github.com/cimgui/cimgui.git
|
||||||
[submodule "repos/wayland-protocols"]
|
[submodule "repos/wayland-protocols"]
|
||||||
path = repos/wayland-protocols
|
path = repos/wayland-protocols
|
||||||
@@ -13,3 +13,6 @@
|
|||||||
[submodule "repos/nanosvg"]
|
[submodule "repos/nanosvg"]
|
||||||
path = repos/nanosvg
|
path = repos/nanosvg
|
||||||
url = https://github.com/memononen/nanosvg.git
|
url = https://github.com/memononen/nanosvg.git
|
||||||
|
[submodule "repos/cimplot"]
|
||||||
|
path = repos/gui/cimplot
|
||||||
|
url = https://github.com/cimgui/cimplot.git
|
||||||
|
|||||||
@@ -181,18 +181,11 @@ if(ENABLE_AUDIO)
|
|||||||
list(APPEND SOURCES src/audio.c)
|
list(APPEND SOURCES src/audio.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Force cimgui to build as a static library.
|
|
||||||
set(IMGUI_STATIC "yes" CACHE STRING "Build as a static library")
|
|
||||||
# Support Unicode codepoints outside the basic multilingual plane.
|
|
||||||
set(IMGUI_WCHAR32 "yes")
|
|
||||||
add_definitions("-DCIMGUI_USE_OPENGL2=1")
|
|
||||||
add_definitions("-DCIMGUI_USE_OPENGL3=1")
|
|
||||||
|
|
||||||
add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources")
|
add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources")
|
||||||
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )
|
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )
|
||||||
add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" )
|
add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" )
|
||||||
add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice")
|
add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice")
|
||||||
add_subdirectory("${PROJECT_TOP}/repos/cimgui" "${CMAKE_BINARY_DIR}/cimgui" EXCLUDE_FROM_ALL)
|
add_subdirectory("${PROJECT_TOP}/repos/gui" "${CMAKE_BINARY_DIR}/gui" EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
add_subdirectory(displayservers)
|
add_subdirectory(displayservers)
|
||||||
add_subdirectory(renderers)
|
add_subdirectory(renderers)
|
||||||
@@ -235,7 +228,7 @@ target_link_libraries(looking-glass-client
|
|||||||
renderers
|
renderers
|
||||||
transports
|
transports
|
||||||
audiodevs
|
audiodevs
|
||||||
cimgui
|
lg_gui
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_TESTS)
|
if(ENABLE_TESTS)
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ bool waylandPresentationInit(void)
|
|||||||
wlWm.photonTimings = ringbuffer_new(256, sizeof(float));
|
wlWm.photonTimings = ringbuffer_new(256, sizeof(float));
|
||||||
wlWm.photonGraph = app_registerGraph("PHOTON", wlWm.photonTimings,
|
wlWm.photonGraph = app_registerGraph("PHOTON", wlWm.photonTimings,
|
||||||
0.0f, 30.0f, NULL);
|
0.0f, 30.0f, NULL);
|
||||||
|
app_setGraphCompact(wlWm.photonGraph, true);
|
||||||
wp_presentation_add_listener(wlWm.presentation, &presentationListener, NULL);
|
wp_presentation_add_listener(wlWm.presentation, &presentationListener, NULL);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -145,6 +145,8 @@ GraphHandle app_registerGraph(const char * name, RingBuffer buffer,
|
|||||||
float min, float max, GraphFormatFn formatFn);
|
float min, float max, GraphFormatFn formatFn);
|
||||||
void app_unregisterGraph(GraphHandle handle);
|
void app_unregisterGraph(GraphHandle handle);
|
||||||
void app_invalidateGraph(GraphHandle handle);
|
void app_invalidateGraph(GraphHandle handle);
|
||||||
|
void app_setGraphCompact(GraphHandle handle, bool compact);
|
||||||
|
void app_setFrameImportTime(uint64_t time);
|
||||||
|
|
||||||
void app_overlayConfigRegister(const char * title,
|
void app_overlayConfigRegister(const char * title,
|
||||||
void (*callback)(void * udata, int * id), void * udata);
|
void (*callback)(void * udata, int * id), void * udata);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
typedef struct ImVec2 ImVec2;
|
typedef struct ImVec2_c ImVec2;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ add_library(renderer_EGL STATIC
|
|||||||
filter_downscale.c
|
filter_downscale.c
|
||||||
${EGL_SHADER_OBJS}
|
${EGL_SHADER_OBJS}
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
"${CMAKE_CURRENT_BINARY_DIR}/shader/desktop_rgb.def.h"
|
||||||
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl3.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(renderer_EGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 IMGUI_IMPL_OPENGL_ES3)
|
target_compile_definitions(renderer_EGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 IMGUI_IMPL_OPENGL_ES3)
|
||||||
@@ -113,7 +112,7 @@ target_link_libraries(renderer_EGL
|
|||||||
PkgConfig::RENDERER_EGL
|
PkgConfig::RENDERER_EGL
|
||||||
lg_common
|
lg_common
|
||||||
|
|
||||||
cimgui
|
lg_gui
|
||||||
)
|
)
|
||||||
if(RENDERER_EGL_OPT_FOUND)
|
if(RENDERER_EGL_OPT_FOUND)
|
||||||
target_link_libraries(renderer_EGL
|
target_link_libraries(renderer_EGL
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include <GLES3/gl32.h>
|
#include <GLES3/gl32.h>
|
||||||
|
|
||||||
#include "cimgui.h"
|
#include "cimgui.h"
|
||||||
#include "generator/output/cimgui_impl.h"
|
#include "cimgui_impl.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -124,9 +124,6 @@ struct Inst
|
|||||||
int overlayHistoryCount[DESKTOP_DAMAGE_COUNT];
|
int overlayHistoryCount[DESKTOP_DAMAGE_COUNT];
|
||||||
unsigned int overlayHistoryIdx;
|
unsigned int overlayHistoryIdx;
|
||||||
|
|
||||||
RingBuffer importTimings;
|
|
||||||
GraphHandle importGraph;
|
|
||||||
|
|
||||||
bool showSpice;
|
bool showSpice;
|
||||||
int spiceWidth, spiceHeight;
|
int spiceWidth, spiceHeight;
|
||||||
|
|
||||||
@@ -292,10 +289,6 @@ static bool egl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
|||||||
LG_LOCK_INIT(this->desktopDamageLock);
|
LG_LOCK_INIT(this->desktopDamageLock);
|
||||||
this->desktopDamage[0].count = -1;
|
this->desktopDamage[0].count = -1;
|
||||||
|
|
||||||
this->importTimings = ringbuffer_new(256, sizeof(float));
|
|
||||||
this->importGraph = app_registerGraph("IMPORT", this->importTimings,
|
|
||||||
0.0f, 5.0f, NULL);
|
|
||||||
|
|
||||||
*needsOpenGL = false;
|
*needsOpenGL = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -317,8 +310,6 @@ static void egl_deinitialize(LG_Renderer * renderer)
|
|||||||
egl_stateInvalidate();
|
egl_stateInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ringbuffer_free(&this->importTimings);
|
|
||||||
|
|
||||||
egl_desktopFree(&this->desktop);
|
egl_desktopFree(&this->desktop);
|
||||||
egl_cursorFree (&this->cursor);
|
egl_cursorFree (&this->cursor);
|
||||||
egl_damageFree (&this->damage);
|
egl_damageFree (&this->damage);
|
||||||
@@ -592,10 +583,8 @@ static void egl_onResize(LG_Renderer * renderer, const int width, const int heig
|
|||||||
|
|
||||||
static bool egl_onFontUpdate(LG_Renderer * renderer)
|
static bool egl_onFontUpdate(LG_Renderer * renderer)
|
||||||
{
|
{
|
||||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
|
||||||
const bool result = ImGui_ImplOpenGL3_CreateFontsTexture();
|
|
||||||
egl_stateInvalidate();
|
egl_stateInvalidate();
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool egl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
static bool egl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
||||||
@@ -759,14 +748,14 @@ static bool egl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int d
|
|||||||
struct Inst * this = UPCAST(struct Inst, renderer);
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
||||||
egl_stateCheckShared();
|
egl_stateCheckShared();
|
||||||
|
|
||||||
uint64_t start = nanotime();
|
const uint64_t start = nanotime();
|
||||||
if (unlikely(!egl_desktopUpdate(
|
if (unlikely(!egl_desktopUpdate(
|
||||||
this->desktop, frame, dmaFd, damageRects, damageRectsCount)))
|
this->desktop, frame, dmaFd, damageRects, damageRectsCount)))
|
||||||
{
|
{
|
||||||
DEBUG_INFO("Failed to to update the desktop");
|
DEBUG_INFO("Failed to to update the desktop");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ringbuffer_push(this->importTimings, &(float){ (nanotime() - start) * 1e-6f });
|
app_setFrameImportTime(nanotime() - start);
|
||||||
|
|
||||||
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
||||||
struct DesktopDamage * damage = this->desktopDamage + this->desktopDamageIdx;
|
struct DesktopDamage * damage = this->desktopDamage + this->desktopDamageIdx;
|
||||||
|
|||||||
@@ -496,10 +496,6 @@ static void configUI(void * opaque, int * id)
|
|||||||
|
|
||||||
bool doMove = false;
|
bool doMove = false;
|
||||||
|
|
||||||
ImVec2 window, pos;
|
|
||||||
igGetWindowPos(&window);
|
|
||||||
igGetMousePos(&pos);
|
|
||||||
|
|
||||||
EGL_Filter ** filters = vector_data(&this->filters);
|
EGL_Filter ** filters = vector_data(&this->filters);
|
||||||
size_t count = vector_size(&this->filters);
|
size_t count = vector_size(&this->filters);
|
||||||
for (size_t i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ pkg_check_modules(RENDERER_OPENGL REQUIRED IMPORTED_TARGET
|
|||||||
|
|
||||||
add_library(renderer_OpenGL STATIC
|
add_library(renderer_OpenGL STATIC
|
||||||
opengl.c
|
opengl.c
|
||||||
${PROJECT_TOP}/repos/cimgui/imgui/backends/imgui_impl_opengl2.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(renderer_OpenGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1)
|
target_compile_definitions(renderer_OpenGL PRIVATE CIMGUI_DEFINE_ENUMS_AND_STRUCTS=1)
|
||||||
@@ -17,7 +16,7 @@ target_link_libraries(renderer_OpenGL
|
|||||||
PkgConfig::RENDERER_OPENGL
|
PkgConfig::RENDERER_OPENGL
|
||||||
lg_common
|
lg_common
|
||||||
|
|
||||||
cimgui
|
lg_gui
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(renderer_OpenGL
|
target_include_directories(renderer_OpenGL
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
#include "cimgui.h"
|
#include "cimgui.h"
|
||||||
#include "generator/output/cimgui_impl.h"
|
#include "cimgui_impl.h"
|
||||||
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
@@ -318,8 +318,7 @@ void opengl_onResize(LG_Renderer * renderer, const int width, const int height,
|
|||||||
|
|
||||||
static bool opengl_onFontUpdate(LG_Renderer * renderer)
|
static bool opengl_onFontUpdate(LG_Renderer * renderer)
|
||||||
{
|
{
|
||||||
ImGui_ImplOpenGL2_DestroyFontsTexture();
|
return true;
|
||||||
return ImGui_ImplOpenGL2_CreateFontsTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool opengl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
bool opengl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
||||||
|
|||||||
@@ -917,6 +917,16 @@ void app_invalidateGraph(GraphHandle handle)
|
|||||||
overlayGraph_invalidate(handle);
|
overlayGraph_invalidate(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void app_setGraphCompact(GraphHandle handle, bool compact)
|
||||||
|
{
|
||||||
|
overlayGraph_setCompact(handle, compact);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_setFrameImportTime(uint64_t time)
|
||||||
|
{
|
||||||
|
g_state.frameImportTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
void app_registerOverlay(const struct LG_OverlayOps * ops, const void * params)
|
void app_registerOverlay(const struct LG_OverlayOps * ops, const void * params)
|
||||||
{
|
{
|
||||||
ASSERT_LG_OVERLAY_VALID(ops);
|
ASSERT_LG_OVERLAY_VALID(ops);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#define STBTT_STATIC
|
#define STBTT_STATIC
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
#include "repos/cimgui/imgui/imstb_truetype.h"
|
#include "repos/gui/cimgui/imgui/imstb_truetype.h"
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -202,18 +202,73 @@ static bool tickTimerFn(void * unused)
|
|||||||
struct RenderTiming
|
struct RenderTiming
|
||||||
{
|
{
|
||||||
uint64_t renderStart;
|
uint64_t renderStart;
|
||||||
uint64_t producerTime;
|
uint64_t captureTime;
|
||||||
|
uint64_t postProcessTime;
|
||||||
|
uint64_t copyTime;
|
||||||
|
uint64_t importTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct RenderTiming frameTimingLoad(void)
|
||||||
|
{
|
||||||
|
struct RenderTiming timing = {};
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const unsigned sequence = atomic_load_explicit(
|
||||||
|
&g_state.frameTimingSequence, memory_order_seq_cst);
|
||||||
|
if (sequence & 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
timing.captureTime = atomic_load_explicit(
|
||||||
|
&g_state.producerCaptureTime, memory_order_seq_cst);
|
||||||
|
timing.postProcessTime = atomic_load_explicit(
|
||||||
|
&g_state.producerPostProcessTime, memory_order_seq_cst);
|
||||||
|
timing.copyTime = atomic_load_explicit(
|
||||||
|
&g_state.producerCopyTime, memory_order_seq_cst);
|
||||||
|
timing.importTime = atomic_load_explicit(
|
||||||
|
&g_state.clientImportTime, memory_order_seq_cst);
|
||||||
|
|
||||||
|
if (sequence == atomic_load_explicit(
|
||||||
|
&g_state.frameTimingSequence, memory_order_seq_cst))
|
||||||
|
return timing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frameTimingStore(const LG_TransportFrameTiming * timing,
|
||||||
|
uint64_t importTime)
|
||||||
|
{
|
||||||
|
atomic_fetch_add_explicit(
|
||||||
|
&g_state.frameTimingSequence, 1, memory_order_seq_cst);
|
||||||
|
atomic_store_explicit(&g_state.producerCaptureTime,
|
||||||
|
timing->captureTime, memory_order_seq_cst);
|
||||||
|
atomic_store_explicit(&g_state.producerPostProcessTime,
|
||||||
|
timing->postProcessTime, memory_order_seq_cst);
|
||||||
|
atomic_store_explicit(&g_state.producerCopyTime,
|
||||||
|
timing->copyTime, memory_order_seq_cst);
|
||||||
|
atomic_store_explicit(&g_state.clientImportTime,
|
||||||
|
importTime, memory_order_seq_cst);
|
||||||
|
atomic_fetch_add_explicit(
|
||||||
|
&g_state.frameTimingSequence, 1, memory_order_seq_cst);
|
||||||
|
}
|
||||||
|
|
||||||
static void preSwapCallback(void * udata)
|
static void preSwapCallback(void * udata)
|
||||||
{
|
{
|
||||||
const struct RenderTiming * timing = (const struct RenderTiming *)udata;
|
const struct RenderTiming * timing = (const struct RenderTiming *)udata;
|
||||||
const uint64_t renderTime = nanotime() - timing->renderStart;
|
const uint64_t timestamp = nanotime();
|
||||||
ringbuffer_push(g_state.renderDuration, &(float) {renderTime * 1e-6f});
|
const uint64_t renderTime = timestamp - timing->renderStart;
|
||||||
|
if (timing->captureTime || timing->postProcessTime || timing->copyTime ||
|
||||||
if (timing->producerTime)
|
timing->importTime)
|
||||||
ringbuffer_push(g_state.endToEndDuration,
|
{
|
||||||
&(float) {(timing->producerTime + renderTime) * 1e-6f});
|
const OverlayFrameTiming frameTiming = {
|
||||||
|
.timestamp = timestamp,
|
||||||
|
.capture = timing->captureTime * 1e-6f,
|
||||||
|
.postProcess = timing->postProcessTime * 1e-6f,
|
||||||
|
.copy = timing->copyTime * 1e-6f,
|
||||||
|
.import = timing->importTime * 1e-6f,
|
||||||
|
.render = renderTime * 1e-6f,
|
||||||
|
};
|
||||||
|
ringbuffer_push(g_state.frameLatency, &frameTiming);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_TESTS
|
#ifdef ENABLE_TESTS
|
||||||
if (!l_testCapture.enabled || l_testCapture.complete)
|
if (!l_testCapture.enabled || l_testCapture.complete)
|
||||||
@@ -375,7 +430,7 @@ static int renderThread(void * unused)
|
|||||||
.x = g_state.windowScale,
|
.x = g_state.windowScale,
|
||||||
.y = g_state.windowScale,
|
.y = g_state.windowScale,
|
||||||
};
|
};
|
||||||
g_state.io->FontGlobalScale = 1.0f / g_state.windowScale;
|
igGetStyle()->FontScaleMain = 1.0f / g_state.windowScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
||||||
@@ -407,11 +462,9 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
const bool invalidate = atomic_exchange(&g_state.invalidateWindow, false);
|
const bool invalidate = atomic_exchange(&g_state.invalidateWindow, false);
|
||||||
|
|
||||||
const struct RenderTiming renderTiming = {
|
struct RenderTiming renderTiming =
|
||||||
.renderStart = nanotime(),
|
newFrame ? frameTimingLoad() : (struct RenderTiming) {};
|
||||||
.producerTime = newFrame ? atomic_load_explicit(
|
renderTiming.renderStart = nanotime();
|
||||||
&g_state.producerFrameTime, memory_order_acquire) : 0,
|
|
||||||
};
|
|
||||||
LG_LOCK(g_state.lgrLock);
|
LG_LOCK(g_state.lgrLock);
|
||||||
|
|
||||||
renderQueue_process();
|
renderQueue_process();
|
||||||
@@ -783,6 +836,7 @@ int main_frameThread(void * unused)
|
|||||||
damageCount = 0;
|
damageCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_state.frameImportTime = 0;
|
||||||
if (!RENDERER(onFrame, frame.framebuffer, frame.dmaFD,
|
if (!RENDERER(onFrame, frame.framebuffer, frame.dmaFD,
|
||||||
frame.damageRects, damageCount))
|
frame.damageRects, damageCount))
|
||||||
{
|
{
|
||||||
@@ -797,15 +851,7 @@ int main_frameThread(void * unused)
|
|||||||
g_state.transportOps->getFrameTiming(
|
g_state.transportOps->getFrameTiming(
|
||||||
g_state.transport, &frame, &timing);
|
g_state.transport, &frame, &timing);
|
||||||
|
|
||||||
ringbuffer_push(g_state.captureDuration,
|
frameTimingStore(&timing, g_state.frameImportTime);
|
||||||
&(float) {timing.captureTime * 1e-6f});
|
|
||||||
ringbuffer_push(g_state.postProcessDuration,
|
|
||||||
&(float) {timing.postProcessTime * 1e-6f});
|
|
||||||
ringbuffer_push(g_state.copyDuration,
|
|
||||||
&(float) {timing.copyTime * 1e-6f});
|
|
||||||
atomic_store_explicit(&g_state.producerFrameTime,
|
|
||||||
timing.captureTime + timing.postProcessTime + timing.copyTime,
|
|
||||||
memory_order_release);
|
|
||||||
|
|
||||||
overlaySplash_show(false);
|
overlaySplash_show(false);
|
||||||
if ((frame.flags & LG_TRANSPORT_FRAME_REQUEST_ACTIVATION) &&
|
if ((frame.flags & LG_TRANSPORT_FRAME_REQUEST_ACTIVATION) &&
|
||||||
@@ -824,13 +870,6 @@ int main_frameThread(void * unused)
|
|||||||
g_state.autoIdleInhibitState = blockScreensaver;
|
g_state.autoIdleInhibitState = blockScreensaver;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t now = nanotime();
|
|
||||||
const uint64_t delta = now - g_state.lastFrameTime;
|
|
||||||
g_state.lastFrameTime = now;
|
|
||||||
if (g_state.lastFrameTimeValid)
|
|
||||||
ringbuffer_push(g_state.uploadTimings, &(float) { delta * 1e-6f });
|
|
||||||
g_state.lastFrameTimeValid = true;
|
|
||||||
|
|
||||||
atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed);
|
atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed);
|
||||||
#ifdef ENABLE_TESTS
|
#ifdef ENABLE_TESTS
|
||||||
atomic_store_explicit(&l_testFrameSerial, frame.serial,
|
atomic_store_explicit(&l_testFrameSerial, frame.serial,
|
||||||
@@ -1309,7 +1348,7 @@ static int lg_run(void)
|
|||||||
|
|
||||||
/* setup imgui */
|
/* setup imgui */
|
||||||
igCreateContext(NULL);
|
igCreateContext(NULL);
|
||||||
g_state.io = igGetIO();
|
g_state.io = igGetIO_Nil();
|
||||||
g_state.style = igGetStyle();
|
g_state.style = igGetStyle();
|
||||||
|
|
||||||
g_state.style->Colors[ImGuiCol_ModalWindowDimBg] = (ImVec4) { 0.0f, 0.0f, 0.0f, 0.4f };
|
g_state.style->Colors[ImGuiCol_ModalWindowDimBg] = (ImVec4) { 0.0f, 0.0f, 0.0f, 0.4f };
|
||||||
@@ -1335,19 +1374,10 @@ static int lg_run(void)
|
|||||||
|
|
||||||
// initialize metrics ringbuffers
|
// initialize metrics ringbuffers
|
||||||
g_state.renderTimings = ringbuffer_new(256, sizeof(float));
|
g_state.renderTimings = ringbuffer_new(256, sizeof(float));
|
||||||
g_state.uploadTimings = ringbuffer_new(256, sizeof(float));
|
g_state.frameLatency = ringbuffer_new(4096, sizeof(OverlayFrameTiming));
|
||||||
g_state.renderDuration = ringbuffer_new(256, sizeof(float));
|
overlayGraph_setCompact(overlayGraph_register(
|
||||||
g_state.captureDuration = ringbuffer_new(256, sizeof(float));
|
"FRAME", g_state.renderTimings, 0.0f, 50.0f, NULL), true);
|
||||||
g_state.postProcessDuration = ringbuffer_new(256, sizeof(float));
|
overlayGraph_registerFrameTiming("FRAME LATENCY", g_state.frameLatency);
|
||||||
g_state.copyDuration = ringbuffer_new(256, sizeof(float));
|
|
||||||
g_state.endToEndDuration = ringbuffer_new(256, sizeof(float));
|
|
||||||
overlayGraph_register("FRAME" , g_state.renderTimings , 0.0f, 50.0f, NULL);
|
|
||||||
overlayGraph_register("UPLOAD" , g_state.uploadTimings , 0.0f, 50.0f, NULL);
|
|
||||||
overlayGraph_register("RENDER" , g_state.renderDuration , 0.0f, 10.0f, NULL);
|
|
||||||
overlayGraph_register("CAPTURE" , g_state.captureDuration , 0.0f, 20.0f, NULL);
|
|
||||||
overlayGraph_register("POST PROCESS", g_state.postProcessDuration, 0.0f, 20.0f, NULL);
|
|
||||||
overlayGraph_register("COPY" , g_state.copyDuration , 0.0f, 20.0f, NULL);
|
|
||||||
overlayGraph_register("END TO END" , g_state.endToEndDuration , 0.0f, 50.0f, NULL);
|
|
||||||
|
|
||||||
// unknown guest OS at this time
|
// unknown guest OS at this time
|
||||||
g_state.guestOS = LG_TRANSPORT_OS_OTHER;
|
g_state.guestOS = LG_TRANSPORT_OS_OTHER;
|
||||||
@@ -1830,12 +1860,7 @@ static void lg_shutdown(void)
|
|||||||
|
|
||||||
// free metrics ringbuffers
|
// free metrics ringbuffers
|
||||||
ringbuffer_free(&g_state.renderTimings);
|
ringbuffer_free(&g_state.renderTimings);
|
||||||
ringbuffer_free(&g_state.uploadTimings);
|
ringbuffer_free(&g_state.frameLatency);
|
||||||
ringbuffer_free(&g_state.renderDuration);
|
|
||||||
ringbuffer_free(&g_state.captureDuration);
|
|
||||||
ringbuffer_free(&g_state.postProcessDuration);
|
|
||||||
ringbuffer_free(&g_state.copyDuration);
|
|
||||||
ringbuffer_free(&g_state.endToEndDuration);
|
|
||||||
|
|
||||||
free(g_state.fontName);
|
free(g_state.fontName);
|
||||||
igDestroyContext(NULL);
|
igDestroyContext(NULL);
|
||||||
|
|||||||
@@ -143,20 +143,18 @@ struct AppState
|
|||||||
bool formatValid;
|
bool formatValid;
|
||||||
uint64_t frameTime;
|
uint64_t frameTime;
|
||||||
uint64_t overlayFrameTime;
|
uint64_t overlayFrameTime;
|
||||||
uint64_t lastFrameTime;
|
|
||||||
bool lastFrameTimeValid;
|
|
||||||
uint64_t lastRenderTime;
|
uint64_t lastRenderTime;
|
||||||
bool lastRenderTimeValid;
|
bool lastRenderTimeValid;
|
||||||
RingBuffer renderTimings;
|
RingBuffer renderTimings;
|
||||||
RingBuffer renderDuration;
|
RingBuffer frameLatency;
|
||||||
RingBuffer uploadTimings;
|
uint64_t frameImportTime;
|
||||||
RingBuffer captureDuration;
|
|
||||||
RingBuffer postProcessDuration;
|
|
||||||
RingBuffer copyDuration;
|
|
||||||
RingBuffer endToEndDuration;
|
|
||||||
|
|
||||||
atomic_uint_least64_t pendingCount;
|
atomic_uint_least64_t pendingCount;
|
||||||
atomic_uint_least64_t producerFrameTime;
|
atomic_uint frameTimingSequence;
|
||||||
|
atomic_uint_least64_t producerCaptureTime;
|
||||||
|
atomic_uint_least64_t producerPostProcessTime;
|
||||||
|
atomic_uint_least64_t producerCopyTime;
|
||||||
|
atomic_uint_least64_t clientImportTime;
|
||||||
atomic_uint_least64_t renderCount, frameCount;
|
atomic_uint_least64_t renderCount, frameCount;
|
||||||
_Atomic(float) fps, ups;
|
_Atomic(float) fps, ups;
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ static int alert_render(void * udata, bool interactive, struct Rect * windowRect
|
|||||||
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar
|
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar
|
||||||
);
|
);
|
||||||
|
|
||||||
igPushFont(g_state.fontLarge);
|
igPushFont(g_state.fontLarge, 0.0f);
|
||||||
igText("%s", l_alert.message);
|
igText("%s", l_alert.message);
|
||||||
igPopFont();
|
igPopFont();
|
||||||
|
|
||||||
|
|||||||
@@ -20,28 +20,47 @@
|
|||||||
|
|
||||||
#include "interface/overlay.h"
|
#include "interface/overlay.h"
|
||||||
#include "cimgui.h"
|
#include "cimgui.h"
|
||||||
|
#include "cimplot.h"
|
||||||
|
|
||||||
#include "../main.h"
|
#include "../main.h"
|
||||||
|
#include "../overlays.h"
|
||||||
|
|
||||||
|
#include "common/array.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/stringutils.h"
|
#include "common/stringutils.h"
|
||||||
|
#include "common/time.h"
|
||||||
#include "overlay_utils.h"
|
#include "overlay_utils.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
struct GraphState
|
struct GraphState
|
||||||
{
|
{
|
||||||
bool show;
|
bool show;
|
||||||
struct ll * graphs;
|
struct ll * graphs;
|
||||||
|
ImPlotContext * plotContext;
|
||||||
|
ImPlotSpec * plotSpec;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct GraphState gs = {0};
|
static struct GraphState gs = {0};
|
||||||
|
|
||||||
|
enum OverlayGraphType
|
||||||
|
{
|
||||||
|
OVERLAY_GRAPH_LINE,
|
||||||
|
OVERLAY_GRAPH_FRAME_TIMING,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TIMING_STATISTIC_COUNT 3
|
||||||
|
|
||||||
struct OverlayGraph
|
struct OverlayGraph
|
||||||
{
|
{
|
||||||
char * name;
|
char * name;
|
||||||
RingBuffer buffer;
|
RingBuffer buffer;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
bool compact;
|
||||||
|
enum OverlayGraphType type;
|
||||||
float min;
|
float min;
|
||||||
float max;
|
float max;
|
||||||
|
float yScale[TIMING_STATISTIC_COUNT];
|
||||||
GraphFormatFn formatFn;
|
GraphFormatFn formatFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,6 +100,23 @@ static void graphs_earlyInit(void)
|
|||||||
|
|
||||||
static bool graphs_init(void ** udata, const void * params)
|
static bool graphs_init(void ** udata, const void * params)
|
||||||
{
|
{
|
||||||
|
gs.plotContext = ImPlot_CreateContext();
|
||||||
|
if (!gs.plotContext)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to create ImPlot context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot_SetImGuiContext(igGetCurrentContext());
|
||||||
|
gs.plotSpec = ImPlotSpec_ImPlotSpec();
|
||||||
|
if (!gs.plotSpec)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to create ImPlot specification");
|
||||||
|
ImPlot_DestroyContext(gs.plotContext);
|
||||||
|
gs.plotContext = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
app_overlayConfigRegister("Performance Metrics", configCallback, NULL);
|
app_overlayConfigRegister("Performance Metrics", configCallback, NULL);
|
||||||
app_registerKeybind(KEY_T, showTimingKeybind, NULL,
|
app_registerKeybind(KEY_T, showTimingKeybind, NULL,
|
||||||
"Show frame timing information");
|
"Show frame timing information");
|
||||||
@@ -97,6 +133,11 @@ static void graphs_free(void * udata)
|
|||||||
}
|
}
|
||||||
ll_free(gs.graphs);
|
ll_free(gs.graphs);
|
||||||
gs.graphs = NULL;
|
gs.graphs = NULL;
|
||||||
|
|
||||||
|
ImPlotSpec_destroy(gs.plotSpec);
|
||||||
|
gs.plotSpec = NULL;
|
||||||
|
ImPlot_DestroyContext(gs.plotContext);
|
||||||
|
gs.plotContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BufferMetrics
|
struct BufferMetrics
|
||||||
@@ -119,6 +160,7 @@ static bool rbCalcMetrics(int index, void * value_, void * udata_)
|
|||||||
udata->min = *value;
|
udata->min = *value;
|
||||||
udata->max = *value;
|
udata->max = *value;
|
||||||
udata->sum = *value;
|
udata->sum = *value;
|
||||||
|
udata->last = *value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +175,248 @@ static bool rbCalcMetrics(int index, void * value_, void * udata_)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TIMING_PLOT_BUCKETS 100
|
||||||
|
#define TIMING_PLOT_WINDOW_NS 20000000000ULL
|
||||||
|
#define TIMING_PLOT_BUCKET_NS \
|
||||||
|
(TIMING_PLOT_WINDOW_NS / TIMING_PLOT_BUCKETS)
|
||||||
|
#define TIMING_STAGE_COUNT 5
|
||||||
|
|
||||||
|
struct TimingPlotData
|
||||||
|
{
|
||||||
|
uint64_t windowStart;
|
||||||
|
uint64_t windowEnd;
|
||||||
|
float stageMin[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS];
|
||||||
|
float stageMax[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS];
|
||||||
|
float stageSum[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS];
|
||||||
|
unsigned count[TIMING_PLOT_BUCKETS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static float roundTimingScale(float value)
|
||||||
|
{
|
||||||
|
value = max(value, 1.0f);
|
||||||
|
const float magnitude = powf(10.0f, floorf(log10f(value)));
|
||||||
|
const float normalized = value / magnitude;
|
||||||
|
const float rounded = normalized <= 1.0f ? 1.0f :
|
||||||
|
normalized <= 1.5f ? 1.5f :
|
||||||
|
normalized <= 2.0f ? 2.0f :
|
||||||
|
normalized <= 3.0f ? 3.0f :
|
||||||
|
normalized <= 5.0f ? 5.0f :
|
||||||
|
normalized <= 7.5f ? 7.5f : 10.0f;
|
||||||
|
return rounded * magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float graphScale(struct OverlayGraph * graph, int scaleId,
|
||||||
|
float peak)
|
||||||
|
{
|
||||||
|
float scale = graph->yScale[scaleId];
|
||||||
|
if (scale == 0.0f || peak > scale * 0.95f || peak < scale * 0.45f)
|
||||||
|
scale = roundTimingScale(peak * 1.2f);
|
||||||
|
|
||||||
|
graph->yScale[scaleId] = scale;
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float graphRowWeight(const struct OverlayGraph * graph)
|
||||||
|
{
|
||||||
|
if (graph->type == OVERLAY_GRAPH_FRAME_TIMING)
|
||||||
|
return 3.0f;
|
||||||
|
return graph->compact ? 0.5f : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool accumulateTimingSample(int index, void * value_, void * udata_)
|
||||||
|
{
|
||||||
|
struct TimingPlotData * data = udata_;
|
||||||
|
const OverlayFrameTiming * timing = value_;
|
||||||
|
if (timing->timestamp < data->windowStart)
|
||||||
|
return true;
|
||||||
|
if (timing->timestamp >= data->windowEnd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const uint64_t offset = timing->timestamp - data->windowStart;
|
||||||
|
const int bucket = min(offset / TIMING_PLOT_BUCKET_NS,
|
||||||
|
TIMING_PLOT_BUCKETS - 1);
|
||||||
|
const float values[TIMING_STAGE_COUNT] = {
|
||||||
|
timing->capture,
|
||||||
|
timing->postProcess,
|
||||||
|
timing->copy,
|
||||||
|
timing->import,
|
||||||
|
timing->render,
|
||||||
|
};
|
||||||
|
for (int i = 0; i < TIMING_STAGE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if (!data->count[bucket])
|
||||||
|
data->stageMin[i][bucket] = data->stageMax[i][bucket] = values[i];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data->stageMin[i][bucket] = min(data->stageMin[i][bucket], values[i]);
|
||||||
|
data->stageMax[i][bucket] = max(data->stageMax[i][bucket], values[i]);
|
||||||
|
}
|
||||||
|
data->stageSum[i][bucket] += values[i];
|
||||||
|
}
|
||||||
|
++data->count[bucket];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImPlotFlags graphFlags(bool interactive, bool legend)
|
||||||
|
{
|
||||||
|
ImPlotFlags flags = legend ? ImPlotFlags_None : ImPlotFlags_NoLegend;
|
||||||
|
if (!interactive)
|
||||||
|
flags |= ImPlotFlags_NoInputs | ImPlotFlags_NoMenus |
|
||||||
|
ImPlotFlags_NoBoxSelect;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderLineGraph(struct OverlayGraph * graph, bool interactive,
|
||||||
|
ImVec2 size)
|
||||||
|
{
|
||||||
|
struct BufferMetrics metrics = {};
|
||||||
|
ringbuffer_forEach(graph->buffer, rbCalcMetrics, &metrics, false);
|
||||||
|
|
||||||
|
const int count = ringbuffer_getCount(graph->buffer);
|
||||||
|
if (metrics.sum > 0.0f && count > 0)
|
||||||
|
{
|
||||||
|
metrics.avg = metrics.sum / count;
|
||||||
|
metrics.freq = 1000.0f / metrics.avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * description;
|
||||||
|
if (graph->formatFn)
|
||||||
|
description = graph->formatFn(graph->name,
|
||||||
|
metrics.min, metrics.max, metrics.avg, metrics.freq, metrics.last);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static char text[128];
|
||||||
|
snprintf(text, sizeof(text),
|
||||||
|
"%s: min %.2f, max %.2f, avg %.2f ms / %.2f Hz",
|
||||||
|
graph->name, metrics.min, metrics.max, metrics.avg, metrics.freq);
|
||||||
|
description = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
char title[256];
|
||||||
|
snprintf(title, sizeof(title), "%s###graph_%p", description, (void *)graph);
|
||||||
|
if (!ImPlot_BeginPlot(title, size, graphFlags(interactive, false)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImPlot_SetupAxes(NULL, "ms",
|
||||||
|
ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_None);
|
||||||
|
const float valueMax = graphScale(graph, 0,
|
||||||
|
count > 0 ? metrics.max : graph->max);
|
||||||
|
ImPlot_SetupAxesLimits(0.0, max(1, count - 1), graph->min, valueMax,
|
||||||
|
ImPlotCond_Always);
|
||||||
|
|
||||||
|
gs.plotSpec->Offset = ringbuffer_getStart(graph->buffer);
|
||||||
|
gs.plotSpec->Stride = sizeof(float);
|
||||||
|
gs.plotSpec->Flags = ImPlotLineFlags_None;
|
||||||
|
ImPlot_PlotLine_FloatPtrInt(graph->name,
|
||||||
|
ringbuffer_getValues(graph->buffer), count, 1.0, 0.0, *gs.plotSpec);
|
||||||
|
ImPlot_EndPlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderTimingStatistic(struct OverlayGraph * graph,
|
||||||
|
const char * statistic, int statisticId,
|
||||||
|
const float values[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS],
|
||||||
|
bool interactive, ImVec2 size)
|
||||||
|
{
|
||||||
|
float cumulative[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS] = {};
|
||||||
|
float zero[TIMING_PLOT_BUCKETS] = {};
|
||||||
|
float xValues[TIMING_PLOT_BUCKETS];
|
||||||
|
float peak = 0.0f;
|
||||||
|
for (int bucket = 0; bucket < TIMING_PLOT_BUCKETS; ++bucket)
|
||||||
|
{
|
||||||
|
xValues[bucket] = bucket;
|
||||||
|
for (int stage = 0; stage < TIMING_STAGE_COUNT; ++stage)
|
||||||
|
cumulative[stage][bucket] = values[stage][bucket] +
|
||||||
|
(stage ? cumulative[stage - 1][bucket] : 0.0f);
|
||||||
|
peak = max(peak, cumulative[TIMING_STAGE_COUNT - 1][bucket]);
|
||||||
|
}
|
||||||
|
const float valueMax = graphScale(graph, statisticId, peak);
|
||||||
|
|
||||||
|
char title[160];
|
||||||
|
snprintf(title, sizeof(title), "%s %s###graph_%p_%d",
|
||||||
|
graph->name, statistic, (void *)graph, statisticId);
|
||||||
|
if (!ImPlot_BeginPlot(title, size, graphFlags(interactive, true)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImPlot_SetupAxes(NULL, "ms",
|
||||||
|
ImPlotAxisFlags_NoDecorations,
|
||||||
|
ImPlotAxisFlags_None);
|
||||||
|
ImPlot_SetupAxesLimits(-0.5, TIMING_PLOT_BUCKETS - 0.5, 0.0, valueMax,
|
||||||
|
ImPlotCond_Always);
|
||||||
|
ImPlot_SetupLegend(ImPlotLocation_South,
|
||||||
|
ImPlotLegendFlags_Outside | ImPlotLegendFlags_Horizontal);
|
||||||
|
|
||||||
|
const char * labels[TIMING_STAGE_COUNT] = {
|
||||||
|
"Capture",
|
||||||
|
"Post",
|
||||||
|
"Copy",
|
||||||
|
"Import",
|
||||||
|
"Render",
|
||||||
|
};
|
||||||
|
|
||||||
|
gs.plotSpec->Offset = 0;
|
||||||
|
gs.plotSpec->Stride = sizeof(float);
|
||||||
|
for (int stage = 0; stage < TIMING_STAGE_COUNT; ++stage)
|
||||||
|
{
|
||||||
|
const ImVec4 color =
|
||||||
|
ImPlot_GetColormapColor(stage, ImPlotColormap_Deep);
|
||||||
|
gs.plotSpec->FillColor = color;
|
||||||
|
gs.plotSpec->FillAlpha = 0.35f;
|
||||||
|
gs.plotSpec->LineWeight = 1.0f;
|
||||||
|
gs.plotSpec->Flags = ImPlotShadedFlags_None;
|
||||||
|
ImPlot_PlotShaded_FloatPtrFloatPtrFloatPtr(labels[stage], xValues,
|
||||||
|
stage ? cumulative[stage - 1] : zero, cumulative[stage],
|
||||||
|
TIMING_PLOT_BUCKETS, *gs.plotSpec);
|
||||||
|
|
||||||
|
gs.plotSpec->LineColor = color;
|
||||||
|
gs.plotSpec->LineWeight = 1.0f;
|
||||||
|
gs.plotSpec->FillAlpha = 1.0f;
|
||||||
|
gs.plotSpec->Flags = ImPlotLineFlags_None;
|
||||||
|
ImPlot_PlotLine_FloatPtrInt(labels[stage], cumulative[stage],
|
||||||
|
TIMING_PLOT_BUCKETS, 1.0, 0.0, *gs.plotSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
gs.plotSpec->LineColor = (ImVec4) {0.0f, 0.0f, 0.0f, -1.0f};
|
||||||
|
gs.plotSpec->FillColor = (ImVec4) {0.0f, 0.0f, 0.0f, -1.0f};
|
||||||
|
gs.plotSpec->LineWeight = 1.0f;
|
||||||
|
ImPlot_EndPlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderTimingGraph(struct OverlayGraph * graph, bool interactive,
|
||||||
|
ImVec2 size)
|
||||||
|
{
|
||||||
|
struct TimingPlotData data = {};
|
||||||
|
data.windowEnd = nanotime() / TIMING_PLOT_BUCKET_NS * TIMING_PLOT_BUCKET_NS;
|
||||||
|
data.windowStart = data.windowEnd > TIMING_PLOT_WINDOW_NS ?
|
||||||
|
data.windowEnd - TIMING_PLOT_WINDOW_NS : 0;
|
||||||
|
ringbuffer_forEach(graph->buffer, accumulateTimingSample, &data, false);
|
||||||
|
|
||||||
|
float minimum[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS] = {};
|
||||||
|
float maximum[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS] = {};
|
||||||
|
float average[TIMING_STAGE_COUNT][TIMING_PLOT_BUCKETS] = {};
|
||||||
|
for (int bucket = 0; bucket < TIMING_PLOT_BUCKETS; ++bucket)
|
||||||
|
{
|
||||||
|
if (!data.count[bucket])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int stage = 0; stage < TIMING_STAGE_COUNT; ++stage)
|
||||||
|
{
|
||||||
|
minimum[stage][bucket] = data.stageMin[stage][bucket];
|
||||||
|
maximum[stage][bucket] = data.stageMax[stage][bucket];
|
||||||
|
average[stage][bucket] =
|
||||||
|
data.stageSum[stage][bucket] / data.count[bucket];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float spacing = igGetStyle()->ItemSpacing.y;
|
||||||
|
const float height = (size.y - spacing * 2.0f) / 3.0f;
|
||||||
|
renderTimingStatistic(graph, "MINIMUM", 0, minimum,
|
||||||
|
interactive, (ImVec2) {size.x, height});
|
||||||
|
renderTimingStatistic(graph, "MAXIMUM", 1, maximum,
|
||||||
|
interactive, (ImVec2) {size.x, height});
|
||||||
|
renderTimingStatistic(graph, "AVERAGE", 2, average,
|
||||||
|
interactive, (ImVec2) {size.x, height});
|
||||||
|
}
|
||||||
|
|
||||||
static int graphs_render(void * udata, bool interactive,
|
static int graphs_render(void * udata, bool interactive,
|
||||||
struct Rect * windowRects, int maxRects)
|
struct Rect * windowRects, int maxRects)
|
||||||
{
|
{
|
||||||
@@ -143,11 +427,15 @@ static int graphs_render(void * udata, bool interactive,
|
|||||||
|
|
||||||
GraphHandle graph;
|
GraphHandle graph;
|
||||||
int graphCount = 0;
|
int graphCount = 0;
|
||||||
|
float graphRows = 0.0f;
|
||||||
ll_lock(gs.graphs);
|
ll_lock(gs.graphs);
|
||||||
ll_forEachNL(gs.graphs, item, graph)
|
ll_forEachNL(gs.graphs, item, graph)
|
||||||
{
|
{
|
||||||
if (graph->enabled)
|
if (graph->enabled)
|
||||||
|
{
|
||||||
++graphCount;
|
++graphCount;
|
||||||
|
graphRows += graphRowWeight(graph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!graphCount)
|
if (!graphCount)
|
||||||
@@ -162,7 +450,7 @@ static int graphs_render(void * udata, bool interactive,
|
|||||||
igSetNextWindowSize(
|
igSetNextWindowSize(
|
||||||
(ImVec2){
|
(ImVec2){
|
||||||
28.0f * fontSize,
|
28.0f * fontSize,
|
||||||
7.0f * fontSize * graphCount
|
7.0f * fontSize * graphRows
|
||||||
},
|
},
|
||||||
ImGuiCond_FirstUseEver);
|
ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
@@ -172,51 +460,27 @@ static int graphs_render(void * udata, bool interactive,
|
|||||||
|
|
||||||
igBegin("Performance Metrics", NULL, flags);
|
igBegin("Performance Metrics", NULL, flags);
|
||||||
|
|
||||||
ImVec2 winSize;
|
ImVec2 winSize = igGetContentRegionAvail();
|
||||||
igGetContentRegionAvail(&winSize);
|
const float spacing = igGetStyle()->ItemSpacing.y;
|
||||||
const float height = (winSize.y / graphCount)
|
const float rowHeight =
|
||||||
- igGetStyle()->ItemSpacing.y;
|
(winSize.y - spacing * (graphCount - 1)) / graphRows;
|
||||||
|
|
||||||
|
for (int pass = 0; pass < 2; ++pass)
|
||||||
|
{
|
||||||
ll_forEachNL(gs.graphs, item, graph)
|
ll_forEachNL(gs.graphs, item, graph)
|
||||||
{
|
{
|
||||||
if (!graph->enabled)
|
if (!graph->enabled || graph->compact != (pass == 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
struct BufferMetrics metrics = {};
|
|
||||||
ringbuffer_forEach(graph->buffer, rbCalcMetrics, &metrics, false);
|
|
||||||
|
|
||||||
if (metrics.sum > 0.0f)
|
|
||||||
{
|
|
||||||
metrics.avg = metrics.sum / ringbuffer_getCount(graph->buffer);
|
|
||||||
metrics.freq = 1000.0f / metrics.avg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * title;
|
|
||||||
if (graph->formatFn)
|
|
||||||
title = graph->formatFn(graph->name,
|
|
||||||
metrics.min, metrics.max, metrics.avg, metrics.freq, metrics.last);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static char _title[64];
|
|
||||||
snprintf(_title, sizeof(_title),
|
|
||||||
"%s: min:%4.2f max:%4.2f avg:%4.2f/%4.2fHz",
|
|
||||||
graph->name, metrics.min, metrics.max, metrics.avg, metrics.freq);
|
|
||||||
title = _title;
|
|
||||||
}
|
|
||||||
|
|
||||||
igPushID_Ptr(graph);
|
igPushID_Ptr(graph);
|
||||||
igPlotLines_FloatPtr(
|
const float height = rowHeight * graphRowWeight(graph);
|
||||||
"##graph",
|
if (graph->type == OVERLAY_GRAPH_FRAME_TIMING)
|
||||||
(float *)ringbuffer_getValues(graph->buffer),
|
renderTimingGraph(graph, interactive, (ImVec2) {winSize.x, height});
|
||||||
ringbuffer_getLength(graph->buffer),
|
else
|
||||||
ringbuffer_getStart (graph->buffer),
|
renderLineGraph(graph, interactive, (ImVec2) {winSize.x, height});
|
||||||
title,
|
|
||||||
graph->min,
|
|
||||||
graph->max,
|
|
||||||
(ImVec2){ winSize.x, height },
|
|
||||||
sizeof(float));
|
|
||||||
igPopID();
|
igPopID();
|
||||||
};
|
}
|
||||||
|
}
|
||||||
ll_unlock(gs.graphs);
|
ll_unlock(gs.graphs);
|
||||||
|
|
||||||
overlayGetImGuiRect(windowRects);
|
overlayGetImGuiRect(windowRects);
|
||||||
@@ -259,13 +523,26 @@ GraphHandle overlayGraph_register(const char * name, RingBuffer buffer,
|
|||||||
|
|
||||||
graph->buffer = buffer;
|
graph->buffer = buffer;
|
||||||
graph->enabled = true;
|
graph->enabled = true;
|
||||||
|
graph->compact = false;
|
||||||
|
graph->type = OVERLAY_GRAPH_LINE;
|
||||||
graph->min = min;
|
graph->min = min;
|
||||||
graph->max = max;
|
graph->max = max;
|
||||||
|
for (int i = 0; i < TIMING_STATISTIC_COUNT; ++i)
|
||||||
|
graph->yScale[i] = 0.0f;
|
||||||
graph->formatFn = formatFn;
|
graph->formatFn = formatFn;
|
||||||
ll_push(gs.graphs, graph);
|
ll_push(gs.graphs, graph);
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphHandle overlayGraph_registerFrameTiming(const char * name,
|
||||||
|
RingBuffer buffer)
|
||||||
|
{
|
||||||
|
GraphHandle graph = overlayGraph_register(name, buffer, 0.0f, 0.0f, NULL);
|
||||||
|
if (graph)
|
||||||
|
graph->type = OVERLAY_GRAPH_FRAME_TIMING;
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
void overlayGraph_unregister(GraphHandle handle)
|
void overlayGraph_unregister(GraphHandle handle)
|
||||||
{
|
{
|
||||||
if (!gs.graphs || !handle)
|
if (!gs.graphs || !handle)
|
||||||
@@ -279,6 +556,12 @@ void overlayGraph_unregister(GraphHandle handle)
|
|||||||
app_invalidateWindow(false);
|
app_invalidateWindow(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void overlayGraph_setCompact(GraphHandle handle, bool compact)
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
handle->compact = compact;
|
||||||
|
}
|
||||||
|
|
||||||
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
|
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
|
||||||
bool * enabled, void * udata), void * udata)
|
bool * enabled, void * udata), void * udata)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ static int msg_render(void * udata, bool interactive, struct Rect * windowRects,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
igCalcTextSize(&textSize, line, NULL, false, 0.0);
|
textSize = igCalcTextSize(line, NULL, false, 0.0);
|
||||||
igSetCursorPosX((igGetWindowWidth() * 0.5f) - (textSize.x * 0.5f));
|
igSetCursorPosX((igGetWindowWidth() * 0.5f) - (textSize.x * 0.5f));
|
||||||
igText("%s", stringlist_at(msg->lines, i));
|
igText("%s", stringlist_at(msg->lines, i));
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ static int msg_render(void * udata, bool interactive, struct Rect * windowRects,
|
|||||||
bool destroy = false;
|
bool destroy = false;
|
||||||
if (msg->confirm)
|
if (msg->confirm)
|
||||||
{
|
{
|
||||||
igCalcTextSize(&textSize, "Yes", NULL, false, 0.0);
|
textSize = igCalcTextSize("Yes", NULL, false, 0.0);
|
||||||
ImGuiStyle * style = igGetStyle();
|
ImGuiStyle * style = igGetStyle();
|
||||||
textSize.x += (style->FramePadding.x * 2.0f) * 8.0f;
|
textSize.x += (style->FramePadding.x * 2.0f) * 8.0f;
|
||||||
textSize.y += (style->FramePadding.y * 2.0f) * 1.5f;
|
textSize.y += (style->FramePadding.y * 2.0f) * 1.5f;
|
||||||
@@ -156,7 +156,7 @@ static int msg_render(void * udata, bool interactive, struct Rect * windowRects,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
igCalcTextSize(&textSize, "OK", NULL, false, 0.0);
|
textSize = igCalcTextSize("OK", NULL, false, 0.0);
|
||||||
ImGuiStyle * style = igGetStyle();
|
ImGuiStyle * style = igGetStyle();
|
||||||
textSize.x += (style->FramePadding.x * 2.0f) * 8.0f;
|
textSize.x += (style->FramePadding.x * 2.0f) * 8.0f;
|
||||||
textSize.y += (style->FramePadding.y * 2.0f) * 1.5f;
|
textSize.y += (style->FramePadding.y * 2.0f) * 1.5f;
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ static void renderText(ImDrawList * list, int x, int y, ImU32 color,
|
|||||||
if (textHeight == 0.0f)
|
if (textHeight == 0.0f)
|
||||||
{
|
{
|
||||||
const char * tmp = "W";
|
const char * tmp = "W";
|
||||||
igCalcTextSize(&size, tmp, tmp + 1, false, 0.0f);
|
size = igCalcTextSize(tmp, tmp + 1, false, 0.0f);
|
||||||
textHeight = size.y;
|
textHeight = size.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ static void renderText(ImDrawList * list, int x, int y, ImU32 color,
|
|||||||
const char * text = stringlist_at(lines, topAlign ? i : count - i - 1);
|
const char * text = stringlist_at(lines, topAlign ? i : count - i - 1);
|
||||||
const int len = strlen(text);
|
const int len = strlen(text);
|
||||||
|
|
||||||
igCalcTextSize(&size, text, text + len, false, 0.0f);
|
size = igCalcTextSize(text, text + len, false, 0.0f);
|
||||||
ImDrawList_AddText_Vec2(
|
ImDrawList_AddText_Vec2(
|
||||||
list,
|
list,
|
||||||
(ImVec2){
|
(ImVec2){
|
||||||
@@ -195,7 +195,7 @@ static int splash_render(void * udata, bool interactive, struct Rect * windowRec
|
|||||||
|
|
||||||
ImDrawList_AddImage(
|
ImDrawList_AddImage(
|
||||||
list,
|
list,
|
||||||
(ImTextureID)l_logo.tex,
|
(ImTextureRef) { ._TexID = (ImTextureID)(uintptr_t)l_logo.tex },
|
||||||
(ImVec2){
|
(ImVec2){
|
||||||
logoRect.x,
|
logoRect.x,
|
||||||
logoRect.y
|
logoRect.y
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ static int status_render(void * udata, bool interactive, struct Rect * windowRec
|
|||||||
|
|
||||||
ImDrawList_AddImage(
|
ImDrawList_AddImage(
|
||||||
igGetBackgroundDrawList_Nil(),
|
igGetBackgroundDrawList_Nil(),
|
||||||
(ImTextureID)img->tex,
|
(ImTextureRef) { ._TexID = (ImTextureID)(uintptr_t)img->tex },
|
||||||
(ImVec2){
|
(ImVec2){
|
||||||
xPos,
|
xPos,
|
||||||
marginY
|
marginY
|
||||||
|
|||||||
@@ -41,11 +41,8 @@
|
|||||||
|
|
||||||
void overlayGetImGuiRect(struct Rect * rect)
|
void overlayGetImGuiRect(struct Rect * rect)
|
||||||
{
|
{
|
||||||
ImVec2 size;
|
ImVec2 pos = igGetWindowPos();
|
||||||
ImVec2 pos;
|
ImVec2 size = igGetWindowSize();
|
||||||
|
|
||||||
igGetWindowPos(&pos);
|
|
||||||
igGetWindowSize(&size);
|
|
||||||
|
|
||||||
rect->x = pos.x;
|
rect->x = pos.x;
|
||||||
rect->y = pos.y;
|
rect->y = pos.y;
|
||||||
@@ -60,9 +57,8 @@ ImVec2 * overlayGetScreenSize(void)
|
|||||||
|
|
||||||
static void overlayAddUnderline(ImU32 color)
|
static void overlayAddUnderline(ImU32 color)
|
||||||
{
|
{
|
||||||
ImVec2 min, max;
|
ImVec2 min = igGetItemRectMin();
|
||||||
igGetItemRectMin(&min);
|
ImVec2 max = igGetItemRectMax();
|
||||||
igGetItemRectMax(&max);
|
|
||||||
min.y = max.y;
|
min.y = max.y;
|
||||||
ImDrawList_AddLine(igGetWindowDrawList(), min, max, color, 1.0f);
|
ImDrawList_AddLine(igGetWindowDrawList(), min, max, color, 1.0f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,23 @@ extern struct LG_OverlayOps LGOverlayStatus;
|
|||||||
|
|
||||||
void overlayAlert_show(LG_MsgAlert type, const char * fmt, va_list args);
|
void overlayAlert_show(LG_MsgAlert type, const char * fmt, va_list args);
|
||||||
|
|
||||||
|
typedef struct OverlayFrameTiming
|
||||||
|
{
|
||||||
|
uint64_t timestamp;
|
||||||
|
float capture;
|
||||||
|
float postProcess;
|
||||||
|
float copy;
|
||||||
|
float import;
|
||||||
|
float render;
|
||||||
|
}
|
||||||
|
OverlayFrameTiming;
|
||||||
|
|
||||||
GraphHandle overlayGraph_register(const char * name, RingBuffer buffer,
|
GraphHandle overlayGraph_register(const char * name, RingBuffer buffer,
|
||||||
float min, float max, GraphFormatFn formatFn);
|
float min, float max, GraphFormatFn formatFn);
|
||||||
|
GraphHandle overlayGraph_registerFrameTiming(const char * name,
|
||||||
|
RingBuffer buffer);
|
||||||
void overlayGraph_unregister(GraphHandle handle);
|
void overlayGraph_unregister(GraphHandle handle);
|
||||||
|
void overlayGraph_setCompact(GraphHandle handle, bool compact);
|
||||||
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
|
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
|
||||||
bool * enabled, void * udata), void * udata);
|
bool * enabled, void * udata), void * udata);
|
||||||
void overlayGraph_invalidate(GraphHandle handle);
|
void overlayGraph_invalidate(GraphHandle handle);
|
||||||
|
|||||||
@@ -610,7 +610,7 @@ bool util_buildUIFontAtlas(
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ImFontAtlas_Build(atlas);
|
result = true;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
LG_UNLOCK(UIFontLock);
|
LG_UNLOCK(UIFontLock);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ add_executable(font-tests
|
|||||||
../src/font.c
|
../src/font.c
|
||||||
)
|
)
|
||||||
target_compile_definitions(font-tests PRIVATE
|
target_compile_definitions(font-tests PRIVATE
|
||||||
FONT_TEST_FILE="${PROJECT_TOP}/repos/cimgui/imgui/misc/fonts/DroidSans.ttf"
|
FONT_TEST_FILE="${PROJECT_TOP}/repos/gui/cimgui/imgui/misc/fonts/DroidSans.ttf"
|
||||||
)
|
)
|
||||||
target_include_directories(font-tests PRIVATE
|
target_include_directories(font-tests PRIVATE
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
if (EXISTS "${PROJECT_TOP}/.git" AND (
|
if (EXISTS "${PROJECT_TOP}/.git" AND (
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/cimgui/.git") OR
|
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimgui/.git") OR
|
||||||
|
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimplot/.git") OR
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/LGMP/.git") OR
|
(NOT EXISTS "${PROJECT_TOP}/repos/LGMP/.git") OR
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/PureSpice/.git") OR
|
(NOT EXISTS "${PROJECT_TOP}/repos/PureSpice/.git") OR
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/cimgui/imgui/.git") OR
|
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimgui/imgui/.git") OR
|
||||||
|
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimplot/implot/.git") OR
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/wayland-protocols/.git") OR
|
(NOT EXISTS "${PROJECT_TOP}/repos/wayland-protocols/.git") OR
|
||||||
(NOT EXISTS "${PROJECT_TOP}/repos/nanosvg/.git")
|
(NOT EXISTS "${PROJECT_TOP}/repos/nanosvg/.git")
|
||||||
))
|
))
|
||||||
|
|||||||
Submodule repos/cimgui deleted from d6b4ecda71
57
repos/gui/CMakeLists.txt
Normal file
57
repos/gui/CMakeLists.txt
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(lg_gui LANGUAGES CXX)
|
||||||
|
|
||||||
|
add_library(lg_gui STATIC
|
||||||
|
cimgui/cimgui.cpp
|
||||||
|
cimgui/imgui/imgui.cpp
|
||||||
|
cimgui/imgui/imgui_draw.cpp
|
||||||
|
cimgui/imgui/imgui_tables.cpp
|
||||||
|
cimgui/imgui/imgui_widgets.cpp
|
||||||
|
cimplot/cimplot.cpp
|
||||||
|
cimplot/implot/implot.cpp
|
||||||
|
cimplot/implot/implot_items.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(lg_gui PUBLIC
|
||||||
|
IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1
|
||||||
|
IMGUI_USE_WCHAR32
|
||||||
|
IMGUI_USER_CONFIG="../cimconfig.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ENABLE_OPENGL)
|
||||||
|
target_sources(lg_gui PRIVATE
|
||||||
|
cimgui/imgui/backends/imgui_impl_opengl2.cpp
|
||||||
|
)
|
||||||
|
target_compile_definitions(lg_gui PUBLIC CIMGUI_USE_OPENGL2=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_EGL)
|
||||||
|
set(IMGUI_OPENGL3_BACKEND
|
||||||
|
cimgui/imgui/backends/imgui_impl_opengl3.cpp
|
||||||
|
)
|
||||||
|
target_sources(lg_gui PRIVATE ${IMGUI_OPENGL3_BACKEND})
|
||||||
|
set_source_files_properties(${IMGUI_OPENGL3_BACKEND} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS IMGUI_IMPL_OPENGL_ES3
|
||||||
|
)
|
||||||
|
target_compile_definitions(lg_gui PUBLIC CIMGUI_USE_OPENGL3=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_compile_definitions(lg_gui PUBLIC
|
||||||
|
IMGUI_IMPL_API=extern\t"C"\t__declspec\(dllexport\)
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(lg_gui PUBLIC IMGUI_IMPL_API=extern\t"C"\t)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(lg_gui PUBLIC
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cimgui"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cimgui/imgui"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cimplot"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cimplot/implot"
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(lg_gui PROPERTIES
|
||||||
|
CXX_STANDARD 11
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
)
|
||||||
1
repos/gui/cimgui
Submodule
1
repos/gui/cimgui
Submodule
Submodule repos/gui/cimgui added at 4e8fcc1367
1
repos/gui/cimplot
Submodule
1
repos/gui/cimplot
Submodule
Submodule repos/gui/cimplot added at 8213880419
Reference in New Issue
Block a user