Skip to content

Commit

Permalink
feat(util): add settings api (lc-soft#192)
Browse files Browse the repository at this point in the history
- Add API for retrieving and modifying global settings
- Utilize this API in the codebase
- Add event for when global settings are changed
- Add event handler for updating the frame rate cap
- Add event handler to notify paint flashing changes

Fixes lc-soft#192
  • Loading branch information
jduo committed Jun 25, 2020
1 parent 17d7d86 commit f6286e5
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 51 deletions.
4 changes: 1 addition & 3 deletions include/LCUI/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,7 @@ LCUI_API size_t LCUIDisplay_Render(void);
/** 呈现渲染后的内容 */
LCUI_API void LCUIDisplay_Present(void);

LCUI_API void LCUIDisplay_EnablePaintFlashing(LCUI_BOOL enable);

/** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */
/** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */
LCUI_API void LCUIDisplay_SetSize(int width, int height);

/** 获取屏幕宽度 */
Expand Down
3 changes: 2 additions & 1 deletion include/LCUI/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ enum LCUI_SysEventType {
LCUI_PAINT,
LCUI_WIDGET,
LCUI_QUIT, /**< 在 LCUI 退出前触发的事件 */
LCUI_SETTINGS_CHANGE,
LCUI_USER = 100 /**< 用户事件,可以把这个当成系统事件与用户事件的分界 */
};

Expand Down Expand Up @@ -203,7 +204,7 @@ LCUI_API void LCUI_RunFrame(void);

LCUI_API void LCUI_RunFrameWithProfile(LCUI_FrameProfile profile);

/* 新建一个主循环 */
/* 新建一个主循环 */
LCUI_API LCUI_MainLoop LCUIMainLoop_New(void);

/* 运行目标循环 */
Expand Down
55 changes: 55 additions & 0 deletions include/LCUI/settings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* settings.h -- Functions for accessing and modifying global settings.
*
* Copyright (c) 2020, James Duong <duong.james@gmail.com> All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of LCUI nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef LCUI_SETTINGS_H
#define LCUI_SETTINGS_H

LCUI_BEGIN_HEADER

typedef struct LCUI_SettingsRec_ {
int frame_rate_cap;
int parallel_rendering_threads;
LCUI_BOOL record_profile;
LCUI_BOOL fps_meter;
LCUI_BOOL paint_flashing;
} LCUI_SettingsRec, *LCUI_Settings;

/* Initialize settings with the current global settings. */
LCUI_API void Settings_Init(LCUI_Settings settings);

/* Update global settings with the given input. */
LCUI_API void LCUI_ApplySettings(LCUI_Settings settings);

/* Reset global settings to their defaults. */
LCUI_API void LCUI_ResetSettings(void);

LCUI_END_HEADER

#endif
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS=foreign
AM_CFLAGS = -I$(abs_top_srcdir)/include $(CODE_COVERAGE_CFLAGS)

LCUI_LDFLAGS = -version-info 2:0:0
LCUI_SOURCES = graph.c ime.c cursor.c worker.c main.c timer.c painter.c display.c keyboard.c
LCUI_SOURCES = graph.c ime.c cursor.c worker.c main.c timer.c painter.c display.c keyboard.c settings.c
LCUI_LIBADD = thread/libthread.la util/libutil.la platform/libplatform.la \
image/libimage.la draw/libdraw.la gui/libgui.la font/libfont.la \
font/in-core/libfont_incore.la $(PACKAGE_LIBS)
Expand Down
46 changes: 23 additions & 23 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <LCUI/thread.h>
#include <LCUI/display.h>
#include <LCUI/platform.h>
#include <LCUI/settings.h>
#include <LCUI/main.h>
#ifdef LCUI_DISPLAY_H
#include LCUI_DISPLAY_H
#endif
Expand All @@ -53,16 +55,6 @@
#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 600

#ifdef USE_OPENMP
/**
* Parallel rendering threads
* We recommend that you set it to half the number of CPU logical cores
*/
#define PARALLEL_RENDERING_THREADS 4
#else
#define PARALLEL_RENDERING_THREADS 1
#endif

typedef struct FlashRectRec_ {
int64_t paint_time;
LCUI_Rect rect;
Expand All @@ -85,11 +77,11 @@ typedef struct SurfaceRecordRec_ {
static struct LCUI_DisplayModule {
unsigned width, height;
LCUI_BOOL active;
LCUI_BOOL enable_paint_flashing;
LCUI_DisplayMode mode;
LinkedList surfaces;
LinkedList rects;
LCUI_DisplayDriver driver;
LCUI_SettingsRec settings;
} display;

/* clang-format on */
Expand All @@ -113,8 +105,13 @@ static void OnDestroySurfaceRecord(void *data)
free(record);
}

static void OnSettingsChangeEvent(LCUI_SysEvent e, void *arg)
{
Settings_Init(&display.settings);
}

static size_t LCUIDisplay_RenderFlashRect(SurfaceRecord record,
FlashRect flash_rect)
FlashRect flash_rect)
{
size_t count;
int64_t period;
Expand Down Expand Up @@ -202,7 +199,8 @@ static void GetRenderingLayerSize(int *width, int *height)

*width = (int)(LCUIDisplay_GetWidth() * scale);
*height = (int)(LCUIDisplay_GetHeight() * scale);
*height = max(200, *height / PARALLEL_RENDERING_THREADS + 1);
*height =
max(200, *height / display.settings.parallel_rendering_threads + 1);
}

static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
Expand All @@ -221,12 +219,14 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
LCUI_Rect rect;
LCUI_Rect *sub_rect;
DirtyLayer layer;
DirtyLayerRec layers[PARALLEL_RENDERING_THREADS];
DirtyLayerRec *layers;
LinkedListNode *node;

GetRenderingLayerSize(&layer_width, &layer_height);
max_dirty = (int)(0.8 * layer_width * layer_height);
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
layers = malloc(sizeof(DirtyLayerRec) *
display.settings.parallel_rendering_threads);
for (i = 0; i < display.settings.parallel_rendering_threads; ++i) {
layer = &layers[i];
layer->diry = 0;
layer->rect.y = i * layer_height;
Expand All @@ -238,7 +238,8 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
sub_rect = malloc(sizeof(LCUI_Rect));
for (LinkedList_Each(node, &record->rects)) {
rect = *(LCUI_Rect *)node->data;
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
for (i = 0; i < display.settings.parallel_rendering_threads;
++i) {
layer = &layers[i];
if (layer->diry >= max_dirty) {
continue;
Expand All @@ -257,7 +258,7 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
}
}
}
for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) {
for (i = 0; i < display.settings.parallel_rendering_threads; ++i) {
layer = &layers[i];
if (layer->diry >= max_dirty) {
RectList_AddEx(rects, &layer->rect, FALSE);
Expand All @@ -268,6 +269,7 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects)
}
RectList_Clear(&record->rects);
free(sub_rect);
free(layers);
}

static size_t LCUIDisplay_RenderSurfaceRect(SurfaceRecord record,
Expand All @@ -288,7 +290,7 @@ static size_t LCUIDisplay_RenderSurfaceRect(SurfaceRecord record,
omp_get_num_threads(), paint->rect.x, paint->rect.y,
paint->rect.width, paint->rect.height);
count = Widget_Render(record->widget, paint);
if (display.enable_paint_flashing) {
if (display.settings.paint_flashing) {
LCUIDisplay_AppendFlashRects(record, &paint->rect);
}
if (display.mode != LCUI_DMODE_SEAMLESS) {
Expand Down Expand Up @@ -622,11 +624,6 @@ int LCUIDisplay_GetMode(void)
return display.mode;
}

void LCUIDisplay_EnablePaintFlashing(LCUI_BOOL enable)
{
display.enable_paint_flashing = enable;
}

/** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */
void LCUIDisplay_SetSize(int width, int height)
{
Expand Down Expand Up @@ -948,6 +945,9 @@ int LCUI_InitDisplay(LCUI_DisplayDriver driver)
display.active = TRUE;
display.width = DEFAULT_WIDTH;
display.height = DEFAULT_HEIGHT;
Settings_Init(&display.settings);
LCUI_BindEvent(LCUI_SETTINGS_CHANGE, OnSettingsChangeEvent, NULL, NULL);

LinkedList_Init(&display.rects);
LinkedList_Init(&display.surfaces);
if (!display.driver) {
Expand Down
53 changes: 30 additions & 23 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <LCUI/ime.h>
#include <LCUI/platform.h>
#include <LCUI/display.h>
#include <LCUI/settings.h>
#ifdef LCUI_EVENTS_H
#include LCUI_EVENTS_H
#endif
Expand Down Expand Up @@ -107,12 +108,12 @@ static struct LCUI_App {
LCUI_Worker main_worker; /**< 主工作线程 */
LCUI_Worker workers[LCUI_WORKER_NUM]; /**< 普通工作线程 */
int worker_next; /**< 下一个工作线程编号 */
LCUI_SettingsRec settings;
LCUI_ProfileRec profile;
LCUI_FrameProfile frame;
} MainApp;

/* clang-format on */

#ifdef DEBUG

static void LCUIProfile_Init(LCUI_Profile profile)
{
memset(profile, 0, sizeof(LCUI_ProfileRec));
Expand Down Expand Up @@ -153,32 +154,37 @@ static void LCUIProfile_Print(LCUI_Profile profile)
}
}

static LCUI_FrameProfile LCUIProfile_BeginFrame(LCUI_Profile profile)
static LCUI_FrameProfile LCUIProfile_BeginFrame(LCUI_Profile profile,
LCUI_Settings settings)
{
LCUI_FrameProfile frame;

frame = &profile->frames[profile->frames_count];
if (profile->frames_count > LCUI_MAX_FRAMES_PER_SEC) {
if (profile->frames_count > settings->frame_rate_cap) {
profile->frames_count = 0;
}
memset(frame, 0, sizeof(LCUI_FrameProfileRec));
return frame;
}

static void LCUIProfile_EndFrame(LCUI_Profile profile)
static void LCUIProfile_EndFrame(LCUI_Profile profile, LCUI_Settings settings)
{
profile->frames_count += 1;
profile->end_time = clock();
if (profile->end_time - profile->start_time >= CLOCKS_PER_SEC) {
if (profile->frames_count < LCUI_MAX_FRAMES_PER_SEC / 4) {
if (profile->frames_count < settings->frame_rate_cap / 4) {
LCUIProfile_Print(profile);
}
profile->frames_count = 0;
profile->start_time = profile->end_time;
}
}

#endif
static void OnSettingsChangeEvent(LCUI_SysEvent e, void *arg)
{
Settings_Init(&MainApp.settings);
StepTimer_SetFrameLimit(MainApp.timer, MainApp.settings.frame_rate_cap);
}

void LCUI_RunFrameWithProfile(LCUI_FrameProfile profile)
{
Expand Down Expand Up @@ -385,10 +391,6 @@ LCUI_MainLoop LCUIMainLoop_New(void)
/** 运行目标主循环 */
int LCUIMainLoop_Run(LCUI_MainLoop loop)
{
#ifdef DEBUG
LCUI_ProfileRec profile;
LCUI_FrameProfile frame;
#endif
LCUI_BOOL at_same_thread = FALSE;
if (loop->state == STATE_RUNNING) {
DEBUG_MSG("error: main-loop already running.\n");
Expand All @@ -409,17 +411,17 @@ int LCUIMainLoop_Run(LCUI_MainLoop loop)
}
DEBUG_MSG("loop: %p, enter\n", loop);
MainApp.loop = loop;
#ifdef DEBUG
LCUIProfile_Init(&profile);
#endif
while (loop->state != STATE_EXITED) {
#ifdef DEBUG
frame = LCUIProfile_BeginFrame(&profile);
LCUI_RunFrameWithProfile(frame);
LCUIProfile_EndFrame(&profile);
#else
LCUI_RunFrame();
#endif
if (MainApp.settings.record_profile) {
MainApp.frame = LCUIProfile_BeginFrame(
&MainApp.profile, &MainApp.settings);
LCUI_RunFrameWithProfile(MainApp.frame);
LCUIProfile_EndFrame(&MainApp.profile,
&MainApp.settings);
} else {
LCUI_RunFrame();
}

StepTimer_Remain(MainApp.timer);
/* 如果当前运行的主循环不是自己 */
while (MainApp.loop != loop) {
Expand Down Expand Up @@ -466,18 +468,22 @@ void LCUI_InitApp(LCUI_AppDriver app)
LCUICond_Init(&MainApp.loop_changed);
LCUIMutex_Init(&MainApp.loop_mutex);
LinkedList_Init(&MainApp.loops);
Settings_Init(&MainApp.settings);
LCUIProfile_Init(&MainApp.profile);
MainApp.main_worker = LCUIWorker_New();
for (i = 0; i < LCUI_WORKER_NUM; ++i) {
MainApp.workers[i] = LCUIWorker_New();
LCUIWorker_RunAsync(MainApp.workers[i]);
}
StepTimer_SetFrameLimit(MainApp.timer, LCUI_MAX_FRAMES_PER_SEC);
StepTimer_SetFrameLimit(MainApp.timer, MainApp.settings.frame_rate_cap);
if (!app) {
app = LCUI_CreateAppDriver();
if (!app) {
return;
}
}
LCUI_BindEvent(LCUI_SETTINGS_CHANGE, OnSettingsChangeEvent, NULL, NULL);

MainApp.active = TRUE;
MainApp.driver = app;
MainApp.driver_ready = TRUE;
Expand Down Expand Up @@ -646,6 +652,7 @@ void LCUI_InitBase(void)

void LCUI_Init(void)
{
LCUI_ResetSettings();
LCUI_InitBase();
LCUI_InitApp(NULL);
LCUI_InitDisplay(NULL);
Expand Down
Loading

0 comments on commit f6286e5

Please sign in to comment.