mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
experimental threaded xray #1607
This commit is contained in:
parent
9a1499bd02
commit
5947f3d4d2
@ -342,6 +342,10 @@ the standard pile. This ought become a reality soon.
|
||||
Sprixels interact poorly with multiple planes, and such usage is discouraged.
|
||||
This situation might improve in the future.
|
||||
|
||||
Multiple threads may not currently call **ncvisual_render** concurrently
|
||||
using the same **ncvisual**, even if targeting distinct **ncplane**s. This
|
||||
will likely change in the future.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**notcurses(3)**,
|
||||
|
187
src/demo/xray.c
187
src/demo/xray.c
@ -1,4 +1,6 @@
|
||||
#include "demo.h"
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
// FIXME turn this into one large plane and move the plane, ratrher than
|
||||
// manually redrawing each time
|
||||
@ -58,6 +60,114 @@ make_slider(struct notcurses* nc, int dimy, int dimx){
|
||||
return n;
|
||||
}
|
||||
|
||||
static atomic_bool cancelled;
|
||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t render_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
// initialized per run
|
||||
static struct marsh {
|
||||
struct notcurses* nc;
|
||||
struct ncvisual* ncv; // video stream
|
||||
// this state is guarded by the lock; always signal after an update.
|
||||
int next_frame; // next frame to render. first thread to get the
|
||||
// lock will be doing even frames, and the other
|
||||
// thread will be doing odd.
|
||||
int last_frame_rendered; // a thread cannot render the standard pile using
|
||||
// its plane N until last_frame_rendered >= N - 1.
|
||||
int last_frame_written; // a thread cannot rasterize and write its frame N
|
||||
// until last_frame_written >= N - 1.
|
||||
struct ncplane* slider; // text plane at top, sliding to the left
|
||||
float dm; // delay multiplier
|
||||
} marsh;
|
||||
|
||||
// returns the index of the next frame, which can immediately begin to be
|
||||
// rendered onto the thread's plane. last_frame ought be -1 the first time
|
||||
// a thread calls this function.
|
||||
static int
|
||||
get_next_frame(struct ncvisual* ncv, struct ncvisual_options* vopts,
|
||||
int last_frame){
|
||||
int ret;
|
||||
pthread_mutex_lock(&lock);
|
||||
if(last_frame < 0){
|
||||
ret = marsh.next_frame++;
|
||||
}else{
|
||||
while(marsh.next_frame != last_frame + 2){
|
||||
pthread_cond_wait(&cond, &lock);
|
||||
}
|
||||
++marsh.next_frame;
|
||||
ret = last_frame + 2;
|
||||
if(ncvisual_decode(ncv)){
|
||||
ret = -1;
|
||||
}else if(ncvisual_render(marsh.nc, ncv, vopts) == NULL){
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
if(ret == last_frame + 2 || ret == -1){
|
||||
pthread_cond_signal(&cond);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void*
|
||||
xray_thread(void *vplane){
|
||||
int frame = -1;
|
||||
struct ncvisual_options vopts = {
|
||||
.x = NCALIGN_CENTER,
|
||||
.y = NCALIGN_CENTER,
|
||||
.scaling = NCSCALE_STRETCH,
|
||||
.n = vplane,
|
||||
.blitter = NCBLIT_PIXEL,
|
||||
.flags = NCVISUAL_OPTION_VERALIGNED | NCVISUAL_OPTION_HORALIGNED
|
||||
| NCVISUAL_OPTION_ADDALPHA,
|
||||
};
|
||||
while(!cancelled){
|
||||
frame = get_next_frame(marsh.ncv, &vopts, frame);
|
||||
if(frame < 0){
|
||||
cancelled = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// only one thread can render the standard pile at a time
|
||||
pthread_mutex_lock(&render_lock);
|
||||
while(marsh.last_frame_rendered + 1 != frame){
|
||||
pthread_cond_wait(&cond, &render_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&render_lock);
|
||||
int x = ncplane_x(marsh.slider);
|
||||
if(ncplane_move_yx(marsh.slider, -1, x - 1)){
|
||||
cancelled = true;
|
||||
return NULL;
|
||||
}
|
||||
// FIXME swap our plane into stdplane, and swap old one out
|
||||
if(ncpile_render(vopts.n)){
|
||||
cancelled = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// and only one thread can write at a time
|
||||
pthread_mutex_lock(&render_lock);
|
||||
marsh.last_frame_rendered = frame;
|
||||
pthread_cond_signal(&cond);
|
||||
while(marsh.last_frame_written + 1 != frame){
|
||||
pthread_cond_wait(&cond, &render_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&render_lock);
|
||||
|
||||
if(ncpile_rasterize(vopts.n)){
|
||||
cancelled = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&render_lock);
|
||||
marsh.last_frame_written = frame;
|
||||
pthread_mutex_unlock(&render_lock);
|
||||
pthread_cond_signal(&cond);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
perframecb(struct ncvisual* ncv, struct ncvisual_options* vopts,
|
||||
const struct timespec* tspec, void* vnewplane){
|
||||
@ -80,6 +190,27 @@ perframecb(struct ncvisual* ncv, struct ncvisual_options* vopts,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make two planes, both the size of the standard plane less one row at the
|
||||
// bottom. the first is in the standard pile, but the second is in its own.
|
||||
static int
|
||||
make_planes(struct notcurses* nc, struct ncplane** t1, struct ncplane** t2){
|
||||
int dimy, dimx;
|
||||
struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
// FIXME want a resizecb
|
||||
struct ncplane_options opts = {
|
||||
.rows = dimy - 1,
|
||||
.cols = dimx,
|
||||
};
|
||||
*t1 = ncplane_create(stdn, &opts);
|
||||
*t2 = ncpile_create(nc, &opts);
|
||||
if(!*t1 || !*t2){
|
||||
ncplane_destroy(*t1);
|
||||
ncplane_destroy(*t2);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xray_demo(struct notcurses* nc){
|
||||
if(!notcurses_canopen_videos(nc)){
|
||||
return 0;
|
||||
@ -93,8 +224,8 @@ int xray_demo(struct notcurses* nc){
|
||||
if(ncv == NULL){
|
||||
return -1;
|
||||
}
|
||||
struct ncplane* newpanel = make_slider(nc, dimy, dimx);
|
||||
if(newpanel == NULL){
|
||||
struct ncplane* slider = make_slider(nc, dimy, dimx);
|
||||
if(slider == NULL){
|
||||
ncvisual_destroy(ncv);
|
||||
return -1;
|
||||
}
|
||||
@ -102,23 +233,45 @@ int xray_demo(struct notcurses* nc){
|
||||
ncchannels_set_fg_alpha(&stdc, CELL_ALPHA_TRANSPARENT);
|
||||
ncchannels_set_bg_alpha(&stdc, CELL_ALPHA_TRANSPARENT);
|
||||
ncplane_set_base(notcurses_stdplane(nc), "", 0, stdc);
|
||||
struct ncvisual_options vopts = {
|
||||
.y = NCALIGN_CENTER,
|
||||
.x = NCALIGN_CENTER,
|
||||
.scaling = NCSCALE_SCALE_HIRES,
|
||||
.blitter = NCBLIT_PIXEL,
|
||||
.flags = NCVISUAL_OPTION_NODEGRADE // to test for NCBLIT_PIXEL
|
||||
| NCVISUAL_OPTION_VERALIGNED | NCVISUAL_OPTION_HORALIGNED
|
||||
| NCVISUAL_OPTION_ADDALPHA,
|
||||
};
|
||||
float dm = 0;
|
||||
// returns non-zero if the selected blitter isn't available
|
||||
if(ncvisual_blitter_geom(nc, ncv, &vopts, NULL, NULL, NULL, NULL, NULL)){
|
||||
vopts.flags &= ~NCVISUAL_OPTION_NODEGRADE;
|
||||
dm = 0.5 * delaymultiplier;
|
||||
if(notcurses_check_pixel_support(nc) < 1){
|
||||
marsh.dm = 0.5 * delaymultiplier;
|
||||
}
|
||||
int ret = ncvisual_stream(nc, ncv, dm, perframecb, &vopts, newpanel);
|
||||
pthread_t tid1, tid2;
|
||||
struct ncplane* t1;
|
||||
struct ncplane* t2;
|
||||
if(make_planes(nc, &t1, &t2)){
|
||||
ncvisual_destroy(ncv);
|
||||
ncplane_destroy(slider);
|
||||
return -1;
|
||||
}
|
||||
marsh.slider = slider;
|
||||
marsh.nc = nc;
|
||||
marsh.ncv = ncv;
|
||||
marsh.next_frame = 0;
|
||||
marsh.last_frame_rendered = -1;
|
||||
marsh.last_frame_written = -1;
|
||||
cancelled = false;
|
||||
if(pthread_create(&tid1, NULL, xray_thread, t1)){
|
||||
ncvisual_destroy(ncv);
|
||||
ncplane_destroy(slider);
|
||||
ncplane_destroy(t1);
|
||||
ncplane_destroy(t2);
|
||||
return -1;
|
||||
}
|
||||
if(pthread_create(&tid2, NULL, xray_thread, t2)){
|
||||
cancelled = 1;
|
||||
pthread_join(tid1, NULL);
|
||||
ncvisual_destroy(ncv);
|
||||
ncplane_destroy(slider);
|
||||
ncplane_destroy(t1);
|
||||
ncplane_destroy(t2);
|
||||
return -1;
|
||||
}
|
||||
int ret = pthread_join(tid1, NULL) | pthread_join(tid2, NULL);
|
||||
ncvisual_destroy(ncv);
|
||||
ncplane_destroy(newpanel);
|
||||
ncplane_destroy(slider);
|
||||
ncplane_destroy(t1);
|
||||
ncplane_destroy(t2);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user