summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2025-06-13 19:32:36 -0700
committerVito Caputo <vcaputo@pengaru.com>2025-06-13 19:32:36 -0700
commita7ad112deef0a4dc6e0ab912300e64569e635352 (patch)
tree431065b66111bc5ed3321b63af28d001f124548b
parenteeaa389328bd8e7d4b3a1954e1d18978162fed42 (diff)
WIP DO NOT MERGE
just need to put this somewhere
-rw-r--r--src/charts.c58
-rw-r--r--src/libvmon/vmon.c45
-rw-r--r--src/vcr.c115
-rw-r--r--src/vcr.h19
4 files changed, 183 insertions, 54 deletions
diff --git a/src/charts.c b/src/charts.c
index 1040d45..aeacb18 100644
--- a/src/charts.c
+++ b/src/charts.c
@@ -67,7 +67,7 @@ typedef struct _vwm_charts_t {
float prev_sampling_interval_secs, sampling_interval_secs;
int sampling_paused, contiguous_drops, primed;
unsigned marker_distance;
- float inv_ticks_per_sec, inv_total_delta;
+ double inv_ticks_per_sec, inv_total_delta;
unsigned defer_maintenance:1;
unsigned no_threads:1;
} vwm_charts_t;
@@ -197,7 +197,7 @@ static void sample_callback(vmon_t *vmon, void *arg)
sys_stat->softirq + sys_stat->steal + sys_stat->guest;
charts->total_delta = charts->this_total - charts->last_total;
- charts->inv_total_delta = 1.f / (float)charts->total_delta;
+ charts->inv_total_delta = 1.0 / (double)charts->total_delta;
charts->idle_delta = sys_stat->idle - charts->last_idle;
charts->iowait_delta = sys_stat->iowait - charts->last_iowait;
charts->irq_delta = sys_stat->irq - charts->last_irq;
@@ -287,6 +287,7 @@ static void snowflake_row(vwm_charts_t *charts, vwm_chart_t *chart, int row)
/* stash the graph rows */
vcr_stash_row(chart->vcr, VCR_LAYER_GRAPHA, row);
vcr_stash_row(chart->vcr, VCR_LAYER_GRAPHB, row);
+ vcr_stash_row(chart->vcr, VCR_LAYER_META, row);
/* shift _all_ the layers up by 1 row */
vcr_shift_below_row_up_one(chart->vcr, row);
@@ -294,6 +295,7 @@ static void snowflake_row(vwm_charts_t *charts, vwm_chart_t *chart, int row)
/* unstash the graph rows @ hierarchy end so we have them in the snowflakes */
vcr_unstash_row(chart->vcr, VCR_LAYER_GRAPHA, chart->hierarchy_end);
vcr_unstash_row(chart->vcr, VCR_LAYER_GRAPHB, chart->hierarchy_end);
+ vcr_unstash_row(chart->vcr, VCR_LAYER_META, chart->hierarchy_end);
/* clear the others @ hierarchy end, new argv will get stamped over it */
vcr_clear_row(chart->vcr, VCR_LAYER_TEXT, chart->hierarchy_end, -1, -1);
@@ -319,6 +321,7 @@ static void allocate_row(vwm_charts_t *charts, vwm_chart_t *chart, int row)
vcr_clear_row(chart->vcr, VCR_LAYER_GRAPHB, row, -1, -1);
vcr_clear_row(chart->vcr, VCR_LAYER_TEXT, row, -1, -1);
vcr_clear_row(chart->vcr, VCR_LAYER_SHADOW, row, -1, -1);
+ vcr_clear_row(chart->vcr, VCR_LAYER_META, row, -1, -1);
}
@@ -411,18 +414,35 @@ static int proc_hierarchy_changed(vmon_proc_t *proc)
/* helper for drawing the vertical bars in the graph layers */
-static void draw_bars(vwm_charts_t *charts, vwm_chart_t *chart, int row, float mult, float a_fraction, float inv_a_total, vcr_layer_t a_layer, float b_fraction, float inv_b_total, vcr_layer_t b_layer)
+static void draw_bars(vwm_charts_t *charts, vwm_chart_t *chart, int row, float mult, float a_fraction, double inv_a_total, vcr_layer_t a_layer, float b_fraction, double inv_b_total, vcr_layer_t b_layer)
{
+ int a_height, b_height;
float a_t, b_t;
+//#error "the *ncpus scaling done in floating point seems to often result in enough rounding error to produce 1-pixel overlap of utime and stime bars where they really shouldn't exist"
/* compute the bar %ages for this sample */
a_t = a_fraction * inv_a_total * mult;
+ if (a_t > 1.f)
+ a_t = 1.f;
+
b_t = b_fraction * inv_b_total * mult;
+ if (b_t > 1.f)
+ b_t = 1.f;
+
+ a_height = a_t * (float)(VCR_ROW_HEIGHT - 1);
+ if (a_height == 0 && a_fraction != 0.f)
+ a_height = 1;
+ b_height = b_t * (float)(VCR_ROW_HEIGHT - 1);
+ if (b_height == 0 && b_fraction != 0.f)
+ b_height = 1;
+
+ //fprintf(stderr, "a_t=%f a_h=%i b_t=%f b_h=%i\n",
+ // a_t, a_height, b_t, b_height);
/* ensure at least 1 pixel when the scaled result is a fraction less than 1,
* I want to at least see 1 pixel blips for the slightest cpu utilization */
- vcr_draw_bar(chart->vcr, a_layer, row, a_t, a_fraction != 0 ? 1 : 0 /* min_height */);
- vcr_draw_bar(chart->vcr, b_layer, row, b_t, b_fraction != 0 ? 1 : 0 /* min_height */);
+ vcr_draw_bar(chart->vcr, a_layer, VCR_BAR_BASE_TOP, row, a_height);
+ vcr_draw_bar(chart->vcr, b_layer, VCR_BAR_BASE_BOTTOM, row, b_height);
}
@@ -1116,6 +1136,7 @@ static void draw_chart_rest(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_
if (!proc->is_thread) { /* per-proc RSS row */
allocate_row(charts, chart, (*row) + 1);
+ vcr_set_row_palette(chart->vcr, (*row) + 1, VCR_ROW_PALETTE_1);
chart->hierarchy_end++;
}
@@ -1129,7 +1150,7 @@ static void draw_chart_rest(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_
draw_bars(charts, chart, *row,
(proc->is_thread || !proc->is_threaded) ? charts->vmon.num_cpus : 1.f /* mult */,
- -stime_delta,
+ stime_delta,
charts->inv_total_delta,
VCR_LAYER_GRAPHA,
utime_delta,
@@ -1137,15 +1158,24 @@ static void draw_chart_rest(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_
VCR_LAYER_GRAPHB);
if (!proc->is_thread) {
- if (proc_ctxt->rss != proc_ctxt->prev_rss) {
+ if (proc->is_new) {
+ draw_bars(charts, chart, *row + 1,
+ 1.f /* mult */,
+ 1.f,
+ 1.f,
+ VCR_LAYER_GRAPHB,
+ 1.f,
+ 1.f,
+ VCR_LAYER_GRAPHA);
+ } else if (proc_ctxt->rss != proc_ctxt->prev_rss) {
// fprintf(stderr, "row=%i rss_delta=%i rss=%llu\n", (*row) + 1, proc_ctxt->rss_log2_delta, proc_ctxt->rss);
draw_bars(charts, chart, *row + 1,
1.f /* mult */,
- proc_ctxt->rss_log2_delta < 0.f ? proc_ctxt->rss_log2_delta : 0.f,
- 1.f / (VCR_ROW_HEIGHT - 1),
+ proc_ctxt->rss_log2_delta < 0 ? -proc_ctxt->rss_log2_delta : 0.f,
+ 1.f / VCR_ROW_HEIGHT,
VCR_LAYER_GRAPHB,
- proc_ctxt->rss_log2_delta > 0.f ? proc_ctxt->rss_log2_delta : 0.f,
- 1.f / (VCR_ROW_HEIGHT - 1),
+ proc_ctxt->rss_log2_delta > 0 ? proc_ctxt->rss_log2_delta : 0.f,
+ 1.f / VCR_ROW_HEIGHT,
VCR_LAYER_GRAPHA);
}
}
@@ -1187,7 +1217,7 @@ static void draw_chart(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_t *pr
/* IOWait and Idle % @ row 0 */
draw_bars(charts, chart, row,
1.f /* mult */,
- -charts->iowait_delta,
+ charts->iowait_delta,
charts->inv_total_delta,
VCR_LAYER_GRAPHA,
charts->idle_delta,
@@ -1197,7 +1227,7 @@ static void draw_chart(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_t *pr
/* IRQ and SoftIRQ % @ row 1 */
draw_bars(charts, chart, row + 1,
1.f /* mult */,
- -charts->irq_delta,
+ charts->irq_delta,
charts->inv_total_delta,
VCR_LAYER_GRAPHA,
charts->softirq_delta,
@@ -1207,7 +1237,7 @@ static void draw_chart(vwm_charts_t *charts, vwm_chart_t *chart, vmon_proc_t *pr
/* "Adherence" @ row 2 */
draw_bars(charts, chart, row + 2,
1.f /* mult */,
- charts->this_sample_adherence > 0.f ? -charts->this_sample_adherence : 0.f /* a_fraction */,
+ charts->this_sample_adherence > 0.f ? charts->this_sample_adherence : 0.f /* a_fraction */,
1.f /* inv_a_total */,
VCR_LAYER_GRAPHA,
charts->this_sample_adherence < 0.f ? -charts->this_sample_adherence : 0.f /* b_fraction */,
diff --git a/src/libvmon/vmon.c b/src/libvmon/vmon.c
index b4c008c..b8b9dcf 100644
--- a/src/libvmon/vmon.c
+++ b/src/libvmon/vmon.c
@@ -1637,10 +1637,27 @@ static int sample_siblings_pass2(vmon_t *vmon, list_head_t *siblings)
}
+static void sample_sys_wants(vmon_t *vmon)
+{
+ assert(vmon);
+
+ /* first the sys-wide samplers */
+ vmon->activity = 0;
+ for (int i = 0, cur = 1, wants = vmon->sys_wants; wants; cur <<= 1, i++) {
+ if (wants & cur) {
+ if (vmon->sys_funcs[i](vmon, &vmon->stores[i]) == SAMPLE_CHANGED)
+ vmon->activity |= cur;
+
+ wants &= ~cur;
+ }
+ }
+}
+
+
/* collect information for all monitored processes, this is the interesting part, call it periodically at a regular interval */
int vmon_sample(vmon_t *vmon)
{
- int i, wants, cur, ret = 1;
+ int ret = 1;
assert(vmon);
@@ -1704,21 +1721,6 @@ int vmon_sample(vmon_t *vmon)
/* now for actual sampling */
- /* first the sys-wide samplers */
- wants = vmon->sys_wants; /* the caller-requested sys-wide wants */
- vmon->activity = 0;
- for (i = 0, cur = 1; wants; cur <<= 1, i++) {
- if (wants & cur) {
- if (vmon->sys_funcs[i](vmon, &vmon->stores[i]) == SAMPLE_CHANGED)
- vmon->activity |= cur;
-
- wants &= ~cur;
- }
- }
-
- if (vmon->sample_cb)
- vmon->sample_cb(vmon, vmon->sample_cb_arg);
-
/* then the per-process samplers */
if ((vmon->flags & VMON_FLAG_PROC_ARRAY)) {
int j;
@@ -1730,6 +1732,9 @@ int vmon_sample(vmon_t *vmon)
* mode, only FOLLOW_CHILDREN mode, and it's likely PROC_ARRAY will generally be used together with PROC_ALL, so no hierarchy
* is available to traverse even if we wanted to.
*/
+ sample_sys_wants(vmon);
+ if (vmon->sample_cb)
+ vmon->sample_cb(vmon, vmon->sample_cb_arg);
/* flat process-array ordered sampling, in this mode threads and processes are all placed flatly in the array,
* so this does the sampling for all monitored in no particular order */
@@ -1757,11 +1762,19 @@ int vmon_sample(vmon_t *vmon)
* XXX this is the path vwm utilizes, everything else is for other uses, like implementing top-like programs.
*/
ret = sample_siblings_pass1(vmon, &vmon->processes); /* XXX TODO: errors */
+
+ sample_sys_wants(vmon);
+ if (vmon->sample_cb)
+ vmon->sample_cb(vmon, vmon->sample_cb_arg);
+
ret = sample_siblings_pass2(vmon, &vmon->processes);
} else {
/* recursive hierarchical depth-first processes tree sampling, at each node threads come before children, done in a single pass:
* Pass 1. samplers; callbacks (for every node)
*/
+ sample_sys_wants(vmon);
+ if (vmon->sample_cb)
+ vmon->sample_cb(vmon, vmon->sample_cb_arg);
ret = sample_siblings_unipass(vmon, &vmon->processes);
}
diff --git a/src/vcr.c b/src/vcr.c
index 18cf301..c9a7c6f 100644
--- a/src/vcr.c
+++ b/src/vcr.c
@@ -76,6 +76,10 @@
#define VCR_USECS_PER_SECOND 1000000
+typedef struct vcr_row_meta_t {
+ vcr_row_palette_t palette;
+} vcr_row_meta_t;
+
/* backend is the root vcr object everything else here derives from,
* for an X backend it encompasses the xserver/display connection.
*/
@@ -135,6 +139,9 @@ typedef struct vcr_t {
int *snowflakes_cnt_ptr; /* pointer to count of snowflaked rows (reset to zero to truncate snowflakes display) */
const unsigned *marker_distance_ptr; /* pointer to marker distance to use (0 disables markers, this is kind of silly but I don't want to add setters everywhere so sharing the instance in vwm_charts_t) */
+ vcr_row_meta_t *meta; /* height / VCR_ROW_HEIGHT elements for per-row metadata */
+ vcr_row_meta_t tmp_meta; /* temp storage for a row's meta */
+
union {
#ifdef USE_XLIB
struct {
@@ -149,9 +156,9 @@ typedef struct vcr_t {
} xlib;
#endif /* USE_XLIB */
struct {
- uint8_t *bits; /* .pitch * height bytes are used to represent the coverage status of up to 4 layers (was 8 until nibbles happened) */
- uint8_t *tmp; /* .pitch * VCR_ROW_HEIGHT bytes for a row's worth of temporary storage */
- int pitch; /* "pitch" of mem surface in bytes, which is half the width rounded up to an even number divisible by two. */
+ uint8_t *bits; /* .pitch * height bytes are used to represent the coverage status of up to 4 layers (was 8 until nibbles happened) */
+ uint8_t *tmp; /* .pitch * VCR_ROW_HEIGHT bytes for a row's worth of temporary storage */
+ int pitch; /* "pitch" of mem surface in bytes, which is half the width rounded up to an even number divisible by two. */
} mem;
};
} vcr_t;
@@ -816,6 +823,7 @@ vcr_t * vcr_free(vcr_t *vcr)
assert(0);
}
+ free(vcr->meta);
free(vcr);
}
@@ -854,6 +862,19 @@ int vcr_resize_visible(vcr_t *vcr, int width, int height)
return 1; /* redraw needed */
}
+ { /* the meta layer isn't backend-specific */
+ vcr_row_meta_t *old = vcr->meta;
+
+ vcr->meta = calloc(height / VCR_ROW_HEIGHT, sizeof(vcr_row_meta_t));
+ if (!vcr->meta)
+ return -ENOMEM;
+
+ if (old) {
+ memcpy(vcr->meta, old, (vcr->height / VCR_ROW_HEIGHT) * sizeof(vcr_row_meta_t));
+ free(old);
+ }
+ }
+
/* we're going outside the current allocation dimensions, so we need to involve the backend
* in _really_ resizing.
*/
@@ -1195,35 +1216,32 @@ void vcr_mark_finish_line(vcr_t *vcr, vcr_layer_t layer, int row)
}
-/* draw a bar at the current phase into the specified layer of t % with a minimum of min_height pixels.
+/* draw a bar at the current phase into the specified layer of height pixels
*
* the only layers supported right now are grapha/graphb
*/
-void vcr_draw_bar(vcr_t *vcr, vcr_layer_t layer, int row, float t, int min_height)
+void vcr_draw_bar(vcr_t *vcr, vcr_layer_t layer, vcr_bar_base_t base, int row, int height)
{
- int height, y = row * VCR_ROW_HEIGHT;
+ int y = row * VCR_ROW_HEIGHT;
assert(vcr);
assert(vcr->backend);
assert(row >= 0);
assert(layer == VCR_LAYER_GRAPHA || layer == VCR_LAYER_GRAPHB);
- assert(min_height >= 0 && min_height < (VCR_ROW_HEIGHT - 1));
+ assert(height >= 0 && height < VCR_ROW_HEIGHT);
if ((row + 1) * VCR_ROW_HEIGHT >= vcr->height)
return;
- height = fabsf(t) * (float)(VCR_ROW_HEIGHT - 1);
-
- if (height < min_height)
- height = min_height;
-
- /* clamp the height to not potentially overflow */
- if (height > (VCR_ROW_HEIGHT - 1))
- height = (VCR_ROW_HEIGHT - 1);
-
- /* negative values project down from the top, positive up from bottom */
- if (t > 0.f)
+ switch (base) {
+ case VCR_BAR_BASE_BOTTOM:
y += VCR_ROW_HEIGHT - height - 1;
+ break;
+ case VCR_BAR_BASE_TOP:
+ break;
+ default:
+ assert(0);
+ }
switch (vcr->backend->type) {
#ifdef USE_XLIB
@@ -1296,6 +1314,11 @@ void vcr_clear_row(vcr_t *vcr, vcr_layer_t layer, int row, int x, int width)
if ((row + 1) * VCR_ROW_HEIGHT >= vcr->height)
return;
+ if (layer == VCR_LAYER_META) {
+ vcr->meta[row] = (vcr_row_meta_t){};
+ return;
+ }
+
switch (vcr->backend->type) {
#ifdef USE_XLIB
case VCR_BACKEND_TYPE_XLIB: {
@@ -1351,6 +1374,20 @@ void vcr_clear_row(vcr_t *vcr, vcr_layer_t layer, int row, int x, int width)
}
+void vcr_set_row_palette(vcr_t *vcr, int row, vcr_row_palette_t palette)
+{
+ assert(vcr);
+ assert(vcr->backend);
+ assert(palette < VCR_ROW_PALETTE_CNT);
+ assert(row >= 0);
+
+ if ((row + 1) * VCR_ROW_HEIGHT >= vcr->height)
+ return;
+
+ vcr->meta[row].palette = palette;
+}
+
+
/* copy what's below a given row up by one row across all the layers */
void vcr_shift_below_row_up_one(vcr_t *vcr, int row)
{
@@ -1363,6 +1400,16 @@ void vcr_shift_below_row_up_one(vcr_t *vcr, int row)
assert(*(vcr->hierarchy_end_ptr) >= row);
+ {
+ vcr_row_meta_t *dest = &vcr->meta[row];
+ vcr_row_meta_t *src = &vcr->meta[(1 + row)];
+ size_t len = ((1 + *(vcr->hierarchy_end_ptr)) - (1 + row)) * sizeof(vcr_row_meta_t);
+
+ assert(*(vcr->hierarchy_end_ptr) >= row);
+
+ memmove(dest, src, len);
+ }
+
switch (vcr->backend->type) {
#ifdef USE_XLIB
case VCR_BACKEND_TYPE_XLIB: {
@@ -1432,6 +1479,14 @@ void vcr_shift_below_row_down_one(vcr_t *vcr, int row)
if (dest_y >= vcr->height)
return;
+ {
+ vcr_row_meta_t *dest = &vcr->meta[row + 1];
+ vcr_row_meta_t *src = &vcr->meta[row];
+ size_t len = ((vcr->height / VCR_ROW_HEIGHT) - (row + 1)) * sizeof(vcr_row_meta_t);
+
+ memmove(dest, src, len);
+ }
+
switch (vcr->backend->type) {
#ifdef USE_XLIB
case VCR_BACKEND_TYPE_XLIB: {
@@ -1599,12 +1654,17 @@ void vcr_stash_row(vcr_t *vcr, vcr_layer_t layer, int row)
{
assert(vcr);
assert(vcr->backend);
- assert(layer == VCR_LAYER_GRAPHA || layer == VCR_LAYER_GRAPHB);
+ assert(layer == VCR_LAYER_GRAPHA || layer == VCR_LAYER_GRAPHB || layer == VCR_LAYER_META);
/* for now we only support stashing graphs */
if ((row + 1) * VCR_ROW_HEIGHT >= vcr->height)
return;
+ if (layer == VCR_LAYER_META) {
+ vcr->tmp_meta = vcr->meta[row];
+ return;
+ }
+
switch (vcr->backend->type) {
#ifdef USE_XLIB
case VCR_BACKEND_TYPE_XLIB: {
@@ -1658,11 +1718,16 @@ void vcr_unstash_row(vcr_t *vcr, vcr_layer_t layer, int row)
{
assert(vcr);
assert(vcr->backend);
- assert(layer == VCR_LAYER_GRAPHA || layer == VCR_LAYER_GRAPHB);
+ assert(layer == VCR_LAYER_GRAPHA || layer == VCR_LAYER_GRAPHB || layer == VCR_LAYER_META);
if ((row + 1) * VCR_ROW_HEIGHT >= vcr->height)
return;
+ if (layer == VCR_LAYER_META) {
+ vcr->meta[row] = vcr->tmp_meta;
+ return;
+ }
+
switch (vcr->backend->type) {
#ifdef USE_XLIB
case VCR_BACKEND_TYPE_XLIB: {
@@ -2253,9 +2318,13 @@ static int vcr_present_mem_to_png(vcr_t *vcr, vcr_dest_t *dest)
marker_distance = *(vcr->marker_distance_ptr);
for (int i = 0; i < n_rows; i++) {
- uint8_t *d = row_pixels;
- uint8_t mask = (0x1 << VCR_LAYER_GRAPHA) | (0x1 << VCR_LAYER_GRAPHB);
- uint8_t odd = ((VCR_ODD << 4 | VCR_ODD) * (i & 0x1));
+ uint8_t *d = row_pixels;
+ uint8_t mask = (0x1 << VCR_LAYER_GRAPHA) | (0x1 << VCR_LAYER_GRAPHB);
+ uint8_t odd = ((VCR_ODD << 4 | VCR_ODD) * (i & 0x1));
+ vcr_row_palette_t row_pal = vcr->meta[i].palette;
+
+ lut[VCR_GRAPHA] = lut[VCR_GRAPHA_ODD] = VCR_LUT_ROWSUB0_A + (row_pal << 1);
+ lut[VCR_GRAPHB] = lut[VCR_GRAPHB_ODD] = VCR_LUT_ROWSUB0_B + (row_pal << 1);
/* The graph layers need to be moved to vcr->phase, since the per-sample updates just draw
* individual graph bars without bothering to move the whole graph layer every sample.
diff --git a/src/vcr.h b/src/vcr.h
index 31c7dc6..cdaa6f7 100644
--- a/src/vcr.h
+++ b/src/vcr.h
@@ -35,9 +35,25 @@ typedef enum vcr_layer_t {
VCR_LAYER_SHADOW, /* the shadow layer below the text (XXX: this must be kept after text) */
VCR_LAYER_GRAPHA, /* the graph A layer below the shadow layer */
VCR_LAYER_GRAPHB, /* the graph B layer below the shadow layer */
+ VCR_LAYER_META, /* the meta layer carries metadata about the row (today only the palette exists here), you can't draw to it */
VCR_LAYER_CNT,
} vcr_layer_t;
+typedef enum vcr_bar_base_t {
+ VCR_BAR_BASE_BOTTOM,
+ VCR_BAR_BASE_TOP,
+ VCR_BAR_BASE_CNT
+} vcr_bar_base_t;
+
+typedef enum vcr_row_palette_t {
+ VCR_ROW_PALETTE_0,
+ VCR_ROW_PALETTE_1,
+ VCR_ROW_PALETTE_2,
+ VCR_ROW_PALETTE_3,
+ VCR_ROW_PALETTE_4,
+ VCR_ROW_PALETTE_CNT,
+} vcr_row_palette_t;
+
typedef struct vcr_backend_t vcr_backend_t;
typedef struct vcr_dest_t vcr_dest_t;
typedef struct vcr_t vcr_t;
@@ -69,8 +85,9 @@ int vcr_resize_visible(vcr_t *vcr, int width, int height);
void vcr_draw_text(vcr_t *vcr, vcr_layer_t layer, int x, int row, const vcr_str_t *strs, int n_strs, int *res_width);
void vcr_draw_ortho_line(vcr_t *vcr, vcr_layer_t layer, int x1, int y1, int x2, int y2);
void vcr_mark_finish_line(vcr_t *vcr, vcr_layer_t layer, int row);
-void vcr_draw_bar(vcr_t *vcr, vcr_layer_t layer, int row, float t, int min_height);
+void vcr_draw_bar(vcr_t *vcr, vcr_layer_t layer, vcr_bar_base_t base, int row, int height);
void vcr_clear_row(vcr_t *vcr, vcr_layer_t layer, int row, int x, int width);
+void vcr_set_row_palette(vcr_t *vcr, int row, vcr_row_palette_t palette);
void vcr_shift_below_row_up_one(vcr_t *vcr, int row);
void vcr_shift_below_row_down_one(vcr_t *vcr, int row);
void vcr_shadow_row(vcr_t *vcr, vcr_layer_t layer, int row);
© All Rights Reserved