Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(draw): add basic vector APIs #4528

Closed
wants to merge 1 commit into from
Closed

Conversation

PeterBee97
Copy link
Contributor

Description of the feature or fix

Vector APIs and basic draw task distribution following #4388 . Some matrix helper functions are provided.

Checkpoints

Be sure the following conventions are followed:

  • Follow the Styling guide
  • Prefer enums instead of macros. If inevitable to use defines export them with LV_EXPORT_CONST_INT(defined_value) right after the define.
  • In function arguments prefer type name[] declaration for array parameters instead of type * name
  • Use typed pointers instead of void * pointers
  • Do not malloc into a static or global variables. Instead declare the variable in lv_global_t structure in lv_global.h and mark the variable with (LV_GLOBAL_DEFAULT()->variable) when it's used. See a detailed description here.
  • Widget constructor must follow the lv_<widget_name>_create(lv_obj_t * parent) pattern.
  • Widget members function must start with lv_<modul_name> and should receive lv_obj_t * as first argument which is a pointer to widget object itself.
  • structs should be used via an API and not modified directly via their elements.
  • struct APIs should follow the widgets' conventions. That is to receive a pointer to the struct as the first argument, and the prefix of the struct name should be used as the prefix of the function name too (e.g. lv_disp_set_default(lv_disp_t * disp))
  • Functions and structs which are not part of the public API must begin with underscore in order to mark them as "private".
  • Arguments must be named in H files too.
  • To register and use callbacks one of the following needs to be followed (see a detailed description here):
    • For both the registration function and the callback pass a pointer to a struct as the first argument. The struct must contain void * user_data field.
    • The last argument of the registration function must be void * user_data and the same user_data needs to be passed as the last argument of the callback.
    • Callback types not following these conventions should end with xcb_t.

Copy link
Member

@kisvegabor kisvegabor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in general! Just a few comments.

src/draw/lv_draw_vector.c Outdated Show resolved Hide resolved
src/draw/lv_draw.h Outdated Show resolved Hide resolved
src/draw/lv_draw_vector.c Outdated Show resolved Hide resolved
@kisvegabor
Copy link
Member

Hey,

Thank you!

Have you already tried it out with ThorVG or VG-Lite (or other GPU)?

src/draw/lv_draw_vector.c Outdated Show resolved Hide resolved
src/draw/lv_draw_vector.c Outdated Show resolved Hide resolved
src/draw/lv_draw_vector.h Show resolved Hide resolved
@kisvegabor
Copy link
Member

As these files uses float please add an #if LV_USE_VECTOR to let the user make LVGL work without float.

@PeterBee97
Copy link
Contributor Author

Hey,

Thank you!

Have you already tried it out with ThorVG or VG-Lite (or other GPU)?

Not yet, this is only the task distribution part and no task handler has been implemented so far.

src/draw/lv_draw_vector.h Outdated Show resolved Hide resolved
@PeterBee97
Copy link
Contributor Author

PeterBee97 commented Sep 13, 2023

Updated:

  1. Changed all API names to lv_vpath_*
  2. Added lv_vpath_submit to daisy chain draw tasks before submitting them. GPU will benefit from batch processing. A lv_vpath_draw_oneshot() is provided for simplified operation.
  3. Enriched matrix helpers with pseudo 3d transformations
  4. Added enum lv_vpath_blend_t for Porter-Duff blend operators

void lv_vpath_set_order(lv_vpath_dsc_t * dsc, bool stroke_first);

/*Draw path commands*/
lv_vpath_task_t * lv_vpath_task_create(void);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lv_vpath_task_t needs to be an private data and should not be created and maintained by the API caller

void lv_vpath_draw(struct _lv_layer_t * layer, lv_vpath_task_t * task, lv_vpath_t * path, lv_vpath_dsc_t * dsc);
void lv_vpath_clear(struct _lv_layer_t * layer, lv_vpath_task_t * task, lv_area_t * rect, lv_color_t color);
void lv_vpath_submit(struct _lv_layer_t * layer, lv_vpath_task_t * task);
void lv_vpath_draw_oneshot(struct _lv_layer_t * layer, lv_vpath_t * path, lv_vpath_dsc_t * dsc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“void lv_vpath_draw_oneshot(struct _lv_layer_t * layer, lv_vpath_t * path, lv_vpath_dsc_t * dsc);”
why need this?

void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y);
void lv_matrix_rotate(lv_matrix_t * matrix, float angle);
/*Pseudo 3D rotation (using affine transformations to simulate 3d rotations cast to xy plane)*/
void lv_matrix_rotate_p3d(lv_matrix_t * matrix, float rx, float ry, float rz);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


void lv_matrix_rotate_p3d(lv_matrix_t * matrix, float rx, float ry, float rz);
void lv_matrix_rotate_quaternion(lv_matrix_t * matrix, float q0, float q1, float q2, float q3);

If you want to implement 3D transformation, you need matrix[4][4], not matrix[3][3]

/*Helper functions*/
void lv_matrix_translate(lv_matrix_t * matrix, float dx, float dy);
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y);
void lv_matrix_rotate(lv_matrix_t * matrix, float angle);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing matrix skew method

void lv_vpath_append_path(lv_vpath_t * path, lv_vpath_t * subpath);

/*Param operations*/
void lv_vpath_dsc_init(lv_vpath_dsc_t * dsc);
Copy link
Contributor

@onecoolx onecoolx Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void lv_vpath_dsc_init(lv_vpath_dsc_t * dsc);
lv_vpath_draw_context_t* lv_vpath_draw_context_create(struct _lv_layer_t * layer);

In order to save the lv_vpath_task_t we can change lv_vpath_dsc_t to lv_vpath_draw_context_t
That we can create and maintain it using methods like:

lv_vpath_draw_context_t*  lv_vpath_draw_context_create(struct _lv_layer_t * layer);
lv_vpath_draw_context_destroy(lv_vpath_draw_context_t* ctx)

The drawing function can be:

void lv_vpath_draw( lv_vpath_draw_context_t * ctx, lv_vpath_t * path);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PeterBee97 Do you think this is better?

lv_vpath_blend_t blend;
lv_area_t scissor_area;
bool stroke_first;
} lv_vpath_dsc_t;
Copy link
Contributor

@onecoolx onecoolx Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} lv_vpath_dsc_t;
} lv_vpath_dsc_t;
typedef struct {
lv_vpath_dsc_t draw_dsc;
lv_vpath_task_t * task;
lv_vpath_task_t * current_task;
} lv_vpath_draw_context_t;

@kisvegabor
Copy link
Member

Please use vector_path instead of vpath. From v9 abbreviations should be avoided for the sake of clarity.

@onecoolx
Copy link
Contributor

onecoolx commented Sep 14, 2023

Please use vector_path instead of vpath. From v9 abbreviations should be avoided for the sake of clarity.

I think "lv_vector_path_" is too long as a prefix, how about “lvg_" ? @kisvegabor

@kisvegabor
Copy link
Member

I looked into the API again I'm a little bit puzzled by

  • lv_vpath_draw
  • lv_vpath_clear
  • lv_vpath_submit
  • lv_vpath_draw_oneshot
  • lv_vpath_task_create

have the same prefix as lv_vpath_quad_to, but they operate on a task list and not a vector path.

What about something like this:

/*Same as `lv_vpath_t`
 *"vector_path" is not prefix but the whole name here*/
lv_vector_path_t * lv_vector_path_create(void);
void lv_vector_path_quad_to(lv_vector_path_t * path, lv_fpoint_t p1, lv_fpoint_t p2);

/*Same as `lv_vpath_dsc_t`
 *lv_vector_draw_dsc_t ) has   `lv_vector_path_t * path`  and  `lv_vector_draw_dsc_t * next` fields*/
void lv_vector_draw_dsc_init(lv_vector_draw_dsc_t * dsc); 
dsc.path = some_path;
dsc.fill_dsc.color = lv_color_hex(0xffaa00);
dsc.next = &another_dsc;

/*Start drawing*/
void lv_vector_draw(struct _lv_layer_t * layer, lv_vector_draw_dsc_t * dsc);

@onecoolx
Copy link
Contributor

onecoolx commented Sep 15, 2023

I looked into the API again I'm a little bit puzzled by

  • lv_vpath_draw
  • lv_vpath_clear
  • lv_vpath_submit
  • lv_vpath_draw_oneshot
  • lv_vpath_task_create

have the same prefix as lv_vpath_quad_to, but they operate on a task list and not a vector path.

What about something like this:

/*Same as `lv_vpath_t`
 *"vector_path" is not prefix but the whole name here*/
lv_vector_path_t * lv_vector_path_create(void);
void lv_vector_path_quad_to(lv_vector_path_t * path, lv_fpoint_t p1, lv_fpoint_t p2);

/*Same as `lv_vpath_dsc_t`
 *lv_vector_draw_dsc_t ) has   `lv_vector_path_t * path`  and  `lv_vector_draw_dsc_t * next` fields*/
void lv_vector_draw_dsc_init(lv_vector_draw_dsc_t * dsc); 
dsc.path = some_path;
dsc.fill_dsc.color = lv_color_hex(0xffaa00);
dsc.next = &another_dsc;

/*Start drawing*/
void lv_vector_draw(struct _lv_layer_t * layer, lv_vector_draw_dsc_t * dsc);

I think this way is not easy to use. The draw_dsc list should be implements under a contxt and should not be maintained by the caller, which is easy cause to errors.
for example:

lv_vpath_draw_context_t* ctx = lv_vpath_draw_context_create(layer);

/*Start drawing*/
lv_vector_path_set_fill_color(ctx, lv_color_hex(0xffaa00));
lv_vector_draw(ctx,  some_path);

lv_vector_path_set_stroke_color(ctx, lv_color_hex(0xffbbaa));
lv_vector_draw(ctx,  another_path);

lv_vector_commit(ctx); // submit the draw list here

...
lv_vpath_draw_context_destroy(ctx);

In this way, the caller of the API does not need to worry about drawing the list and can focus on the drawing logic.
What do you think of this way? @kisvegabor

@kisvegabor
Copy link
Member

What is the content of lv_vpath_draw_context_t? Is it different from lv_vpath_dsc_t in the PR?

So lv_vector_draw handles the creation of the list, right?

For the sake of consistency with other draw tasks, it'd be great if lv_vector_draw could mean the real drawing (lv_vector_commit in the example) and lv_vector_commit would be lv_vector_add or something like that.

@onecoolx
Copy link
Contributor

onecoolx commented Sep 18, 2023

What is the content of lv_vpath_draw_context_t? Is it different from lv_vpath_dsc_t in the PR?

So lv_vector_draw handles the creation of the list, right?

For the sake of consistency with other draw tasks, it'd be great if lv_vector_draw could mean the real drawing (lv_vector_commit in the example) and lv_vector_commit would be lv_vector_add or something like that.

lv_vpath_draw_context_t is used to save and maintain 'draw_list'. When lv_vector_draw is called, a new draw operation will be added to 'draw_list' , When lv_vector_commit is called, a real lvgl draw task will be created for the drawing task, and the 'draw_list' will be traversed in callback to complete the actual drawing. It is similar as a "Recording / Playback" mechanism.
We think this would reduce interruptions to other lvgl widget's drawing.

Basic draw task distribution via lv_draw_vector()
Providing swift helper functions for matrix calculation

Change-Id: I29e5a3fd8b8010ae172bd9ead053c44eaa4d4188
Signed-off-by: Peter Bee <[email protected]>
@PeterBee97
Copy link
Contributor Author

PeterBee97 commented Sep 19, 2023

Refined API naming and added skew functions. There is one more thing from our internal discussion:
Since the parallel rendering architecture is asynchronous, the path content has to be copied when drawing. As such, zero-copying of path cannot be achieved. So it shouldn't be much pain to add an internal representation of path and convert it to vendor-specific format during rendering. It's O(n) anyway. The code will look cleaner and more consistent with parallel rendering framework, benefiting from less conditionally compiled files.

@kisvegabor
Copy link
Member

You mean lv_vector_path_t, right? If so, I think we can make the vector library to populate a lv_vector_path_t type. IMO it would be quite consistent as functions like lv_vector_path_move_to are implemented by the vector library anyway as well.

@lvgl-bot
Copy link

lvgl-bot commented Oct 5, 2023

We need some feedback on this pull request.

Now we mark this as "stale" because there was no activity here for 14 days.

Remove the "stale" label or comment else this will be closed in 7 days.

@lvgl-bot lvgl-bot added the stale label Oct 5, 2023
@kisvegabor
Copy link
Member

Not stale

@lvgl-bot lvgl-bot removed the stale label Oct 6, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 23, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 23, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 23, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 24, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 25, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 25, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 25, 2023
onecoolx added a commit to onecoolx/lvgl that referenced this pull request Oct 26, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 29, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 29, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 30, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Oct 31, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 1, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 1, 2023
@lvgl-bot
Copy link

lvgl-bot commented Nov 6, 2023

We need some feedback on this pull request.

Now we mark this as "stale" because there was no activity here for 14 days.

Remove the "stale" label or comment else this will be closed in 7 days.

@lvgl-bot lvgl-bot added the stale label Nov 6, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 6, 2023
@kisvegabor
Copy link
Member

Closing in favor of #4691.

@kisvegabor kisvegabor closed this Nov 6, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 7, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 8, 2023
onecoolx pushed a commit to onecoolx/lvgl that referenced this pull request Nov 9, 2023
kisvegabor added a commit that referenced this pull request Nov 9, 2023
Signed-off-by: zhangjipeng <[email protected]>
Co-authored-by: zhangjipeng <[email protected]>
Co-authored-by: Gabor Kiss-Vamosi <[email protected]>
lion2tomato pushed a commit to lion2tomato/lvgl that referenced this pull request Dec 20, 2023
VELAPLATFO-18794

Change-Id: Ibef19691436ac0c03afc6cfe19dc2e6b19423489
Signed-off-by: zhangjipeng <[email protected]>
(cherry picked from commit 4806589a6133a93313c1e19e4bc1824d552eec42)
lion2tomato pushed a commit to lion2tomato/lvgl that referenced this pull request Dec 20, 2023
VELAPLATFO-18794

Change-Id: I8fc1ea228f045804edfa187aca4754f25fb96693
Signed-off-by: zhangjipeng <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants