Skip to content

Commit

Permalink
feat(profiling): add fps meter (#192)
Browse files Browse the repository at this point in the history
Signed-off-by: Vasilyy Balyasnyy <v.balyasnyy@gmail.com>
  • Loading branch information
vbalyasnyy committed Feb 9, 2020
1 parent 9d0b5c2 commit f60015f
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 5 deletions.
71 changes: 71 additions & 0 deletions include/LCUI/gui/widget_fpsmeter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* widget_fpsmeter.h -- The widget fps meter operation set.
*
* Copyright (c) 2020, Vasilyy Balyasnyy <v.balyasnyy@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_WIDGET_FPSMETER_H
#define LCUI_WIDGET_FPSMETER_H

LCUI_BEGIN_HEADER

#include <LCUI/LCUI.h>
#include <LCUI/gui/widget.h>
#include <LCUI/gui/widget/textview.h>

typedef struct LCUI_FpsMeterRec_ {
LCUI_Widget widget;

int64_t last_time;
size_t frame_count;

size_t fps;
int render_thread_count;
size_t render_count;
size_t widget_update_count;
} LCUI_FpsMeterRec, *LCUI_FpsMeter;

void LCUI_InitFpsMeter(void);

void LCUI_FreeFpsMeter(void);

void LCUI_FpsMeter_FrameCount(void);

void LCUI_FpsMeter_RenderThreadCount(int count);

void LCUI_FpsMeter_RenderCount(size_t count);

void LCUI_FpsMeter_WidgetUpdateCount(size_t count);

void LCUI_FpsMeter_Enable(void);

void LCUI_FpsMeter_Disable(void);

LCUI_END_HEADER

#endif

2 changes: 1 addition & 1 deletion include/LCUI/gui/widget_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ LCUI_API void Widget_AddTask(LCUI_Widget widget, int task_type);
/** 处理部件中当前积累的任务 */
LCUI_API size_t Widget_Update(LCUI_Widget w);

LCUI_API void Widget_UpdateWithProfile(LCUI_Widget w,
LCUI_API size_t Widget_UpdateWithProfile(LCUI_Widget w,
LCUI_WidgetTasksProfile profile);

/** 根据给定的上下文来处理部件中当前积累的任务 */
Expand Down
7 changes: 7 additions & 0 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <LCUI/thread.h>
#include <LCUI/display.h>
#include <LCUI/platform.h>
#include <LCUI/gui/widget_fpsmeter.h>
#ifdef LCUI_DISPLAY_H
#include LCUI_DISPLAY_H
#endif
Expand Down Expand Up @@ -297,6 +298,9 @@ static size_t LCUIDisplay_RenderSurface(SurfaceRecord record)
LCUI_Rect *rect;
LCUI_PaintContext paint;

#ifdef USE_OPENMP
LCUI_FpsMeter_RenderThreadCount(omp_get_num_threads());
#endif
rect = rect_array[i];
ev.paint.rect = *rect;
LCUI_TriggerEvent(&ev, NULL);
Expand Down Expand Up @@ -353,11 +357,13 @@ size_t LCUIDisplay_Render(void)
LinkedListNode *node;

if (!display.active) {
LCUI_FpsMeter_RenderCount(0);
return 0;
}
for (LinkedList_Each(node, &display.surfaces)) {
count += LCUIDisplay_RenderSurface(node->data);
}
LCUI_FpsMeter_RenderCount(count);
return count;
}

Expand All @@ -378,6 +384,7 @@ void LCUIDisplay_Present(void)
Surface_Present(surface);
}
}
LCUI_FpsMeter_FrameCount();
}

void LCUIDisplay_InvalidateArea(LCUI_Rect *rect)
Expand Down
1 change: 1 addition & 0 deletions src/gui/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ widget_paint.c \
widget_background.c \
widget_border.c \
widget_shadow.c \
widget_fpsmeter.c \
css_parser.c \
css_rule_font_face.c \
css_library.c \
Expand Down
136 changes: 136 additions & 0 deletions src/gui/widget_fpsmeter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* widget_fpsmeter.h -- The widget fps meter operation set.
*
* Copyright (c) 2020, Vasilyy Balyasnyy <v.balyasnyy@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.
*/

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <LCUI_Build.h>
#include <LCUI/LCUI.h>
#include <LCUI/graph.h>
#include <LCUI/font/fontlibrary.h>
#include <LCUI/gui/css_library.h>
#include <LCUI/gui/css_fontstyle.h>
#include <LCUI/font/textlayer.h>
#include <LCUI/gui/widget_fpsmeter.h>

#define FPS_METER_TEXT_SIZE_MAX (256)
#define FPS_METER_UPDATE_TIME_MS (1000)

static LCUI_FpsMeterRec self;

static void LCUI_FpsMeter_Create(void)
{
self.widget = LCUIWidget_New("textview");
TextView_SetColor(self.widget, RGB(255, 255, 255));
Widget_SetFontStyle(self.widget, key_font_size, 16, px);
Widget_SetFontStyle(self.widget, key_text_align, SV_LEFT, style);
Widget_SetStyleString(self.widget, "z-index", "999");
Widget_SetPosition(self.widget, SV_ABSOLUTE);
Widget_SetPadding(self.widget, 20, 20, 20, 20 );
Widget_SetStyle(self.widget, key_background_color, RGB(60, 60, 60), color);
Widget_SetStyle(self.widget, key_opacity, 0.5, scale);
Widget_UpdateStyle(self.widget, TRUE);
}

void LCUI_FpsMeter_Update()
{
char buf[FPS_METER_TEXT_SIZE_MAX];
snprintf(buf, FPS_METER_TEXT_SIZE_MAX,
"FPS: %ld\n"
"Render thread count: %d\n"
"Widget update count: %ld\n"
"Render count: %ld",
self.fps,
self.render_thread_count,
self.widget_update_count,
self.render_count);
TextView_SetText(self.widget, buf);
}

void LCUI_InitFpsMeter(void)
{
self.last_time = LCUI_GetTime();
self.frame_count = 0;
self.fps = 0;
self.render_thread_count = 1;

LCUI_FpsMeter_Create();
LCUI_FpsMeter_Update();
}

void LCUI_FreeFpsMeter(void)
{
Widget_Unlink(self.widget);
}

void LCUI_FpsMeter_FrameCount(void)
{
self.frame_count++;
if (LCUI_GetTimeDelta(self.last_time) >= FPS_METER_UPDATE_TIME_MS) {
self.fps = (self.frame_count * 1000 ) / FPS_METER_UPDATE_TIME_MS;
self.frame_count = 0;
self.last_time = LCUI_GetTime();

LCUI_FpsMeter_Update();
}
}

void LCUI_FpsMeter_RenderThreadCount(int count)
{
if (self.render_thread_count != count) {
self.render_thread_count = count;
}
}

void LCUI_FpsMeter_RenderCount(size_t count)
{
if (self.render_count != count) {
self.render_count = count;
}
}

void LCUI_FpsMeter_WidgetUpdateCount(size_t count)
{
if (self.widget_update_count != count) {
self.widget_update_count = count;
}
}

void LCUI_FpsMeter_Enable()
{
Widget_Append(LCUIWidget_GetRoot(), self.widget);
}

void LCUI_FpsMeter_Disable()
{
Widget_Unlink(self.widget);
}

14 changes: 10 additions & 4 deletions src/gui/widget_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <LCUI_Build.h>
#include <LCUI/LCUI.h>
#include <LCUI/gui/widget.h>
#include <LCUI/gui/widget_fpsmeter.h>

static struct WidgetTaskModule {
DictType style_cache_dict;
Expand Down Expand Up @@ -488,22 +489,26 @@ size_t LCUIWidget_Update(void)
count = Widget_Update(root);
}
LCUIWidget_ClearTrash();
LCUI_FpsMeter_WidgetUpdateCount(count);
return count;
}

void Widget_UpdateWithProfile(LCUI_Widget w, LCUI_WidgetTasksProfile profile)
size_t Widget_UpdateWithProfile(LCUI_Widget w, LCUI_WidgetTasksProfile profile)
{
size_t count;
LCUI_WidgetTaskContext ctx;

ctx = Widget_BeginUpdate(w, NULL);
ctx->profile = profile;
Widget_UpdateWithContext(w, ctx);
count = Widget_UpdateWithContext(w, ctx);
Widget_EndUpdate(ctx);

return count;
}

void LCUIWidget_UpdateWithProfile(LCUI_WidgetTasksProfile profile)
{
size_t i;
size_t i, count = 0;
LCUI_Widget root;

profile->time = clock();
Expand All @@ -515,12 +520,13 @@ void LCUIWidget_UpdateWithProfile(LCUI_WidgetTasksProfile profile)
}
root = LCUIWidget_GetRoot();
for (i = 0; i < self.max_updates_per_frame; ++i) {
Widget_UpdateWithProfile(root, profile);
count += Widget_UpdateWithProfile(root, profile);
}
profile->time = clock() - profile->time;
profile->destroy_time = clock();
profile->destroy_count = LCUIWidget_ClearTrash();
profile->destroy_time = clock() - profile->destroy_time;
LCUI_FpsMeter_WidgetUpdateCount(count);
}

void LCUIWidget_RefreshStyle(void)
Expand Down
3 changes: 3 additions & 0 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/gui/widget_fpsmeter.h>
#ifdef LCUI_EVENTS_H
#include LCUI_EVENTS_H
#endif
Expand Down Expand Up @@ -642,6 +643,7 @@ void LCUI_InitBase(void)
LCUI_InitCursor();
LCUI_InitWidget();
LCUI_InitMetrics();
LCUI_InitFpsMeter();
}

void LCUI_Init(void)
Expand Down Expand Up @@ -688,6 +690,7 @@ int LCUI_Destroy(void)
LCUI_FreeTimer();
LCUI_FreeEvent();
LCUI_FreeMetrics();
LCUI_FreeFpsMeter();
return System.exit_code;
}

Expand Down

0 comments on commit f60015f

Please sign in to comment.