diff --git a/driver/fifo.c b/driver/fifo.c index 5cfd95e..4a7cd1a 100644 --- a/driver/fifo.c +++ b/driver/fifo.c @@ -64,10 +64,35 @@ uint32_t fifoAdd(Fifo* f, void* data) return 1; } -void fifoRemove(Fifo* f, void* data) +void* fifoGetLast(Fifo* f) { assert(f); + if(f->last) + { + return f->last->data; + } + + return 0; +} + +void* fifoGetFirst(Fifo* f) +{ + assert(f); + + if(f->first) + { + return f->first->data; + } + + return 0; +} + +uint32_t fifoRemove(Fifo* f, void* data) +{ + assert(f); + assert(data); + if(f->last) { memcpy(data, f->last->data, f->dataSize); @@ -87,7 +112,11 @@ void fifoRemove(Fifo* f, void* data) poolFree(&f->dataBuf, tmp->data); poolFree(&f->fifoElemBuf, tmp); + + return 1; } + + return 0; } void debugPrintFifo(Fifo* f) diff --git a/driver/fifo.h b/driver/fifo.h index 86f249b..701fa88 100644 --- a/driver/fifo.h +++ b/driver/fifo.h @@ -30,7 +30,9 @@ typedef struct Fifo Fifo createFifo(void* dataMem, void* fifoElemMem, uint32_t maxElems, uint32_t dataSize); void destroyFifo(Fifo* f); uint32_t fifoAdd(Fifo* f, void* data); -void fifoRemove(Fifo* f, void* data); +uint32_t fifoRemove(Fifo* f, void* data); +void* fifoGetLast(Fifo* f); +void* fifoGetFirst(Fifo* f); void debugPrintFifo(Fifo* f); #if defined (__cplusplus) diff --git a/driver/modeset.c b/driver/modeset.c index 2e2eee2..367d6ca 100644 --- a/driver/modeset.c +++ b/driver/modeset.c @@ -1,8 +1,22 @@ #include "modeset.h" +#include "fifo.h" + #include atomic_int saved_state_guard = 0; +typedef struct vsyncData +{ + _image* i; + modeset_display_surface* s; + uint32_t pending; +} vsyncData; + +static Fifo flipQueueFifo = {}; +static vsyncData dataMem[5]; +static FifoElem fifoMem[5]; +atomic_int flip_queue_guard = 0; + void modeset_enum_displays(int fd, uint32_t* numDisplays, modeset_display* displays) { drmModeResPtr resPtr = drmModeGetResources(fd); @@ -166,6 +180,16 @@ void modeset_create_surface_for_mode(int fd, uint32_t display, uint32_t mode, mo { // modeset_debug_print(fd); + while(flip_queue_guard); + flip_queue_guard = 1; + + if(!flipQueueFifo.maxElems) + { + flipQueueFifo = createFifo(dataMem, fifoMem, 5, sizeof(vsyncData)); + } + + flip_queue_guard = 0; + surface->savedState = 0; drmModeResPtr resPtr = drmModeGetResources(fd); @@ -253,49 +277,85 @@ void modeset_destroy_fb(int fd, _image* buf) drmModeRmFB(fd, buf->fb); } -typedef struct vsyncData -{ - _image* i; - modeset_display_surface* s; - uint32_t pending; -} vsyncData; - -static vsyncData flipQueue[2] = {}; -atomic_int flip_queue_guard = 0; - static void modeset_page_flip_event(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { if(data) { - vsyncData* d = data; - while(flip_queue_guard); flip_queue_guard = 1; - flipQueue[0].pending = 0; + if(data) + { + vsyncData* d = data; + + d->pending = 0; + } flip_queue_guard = 0; } } -void modeset_acquire_image(int fd, _image* buf, modeset_display_surface* surface) +void modeset_acquire_image(int fd, _image** buf, modeset_display_surface** surface) { + uint32_t pending = 1; + while(flip_queue_guard); flip_queue_guard = 1; - //TODO - //try to find any image that's not pending - //call handle event until that happens - //then find a non-pending image - drmEventContext ev; - memset(&ev, 0, sizeof(ev)); - ev.version = 2; - ev.page_flip_handler = modeset_page_flip_event; - drmHandleEvent(fd, &ev); + vsyncData* last = fifoGetLast(&flipQueueFifo); + + if(last) + { + pending = last->pending; + } + else + { + //fifo empty, just use any image + *buf = 0; + *surface = 0; + + flip_queue_guard = 0; + + return; + } flip_queue_guard = 0; + + while(pending) + { + drmEventContext ev; + memset(&ev, 0, sizeof(ev)); + ev.version = 2; + ev.page_flip_handler = modeset_page_flip_event; + drmHandleEvent(fd, &ev); + + while(flip_queue_guard); + flip_queue_guard = 1; + + vsyncData* d = fifoGetLast(&flipQueueFifo); + + //a frame must be in flight + //so fifo must contain something + assert(d); + + pending = d->pending; + + flip_queue_guard = 0; + } + + vsyncData d; + + while(flip_queue_guard); + flip_queue_guard = 1; + + fifoRemove(&flipQueueFifo, &d); + + flip_queue_guard = 0; + + *buf = d.i; + *surface = d.s; } void modeset_present(int fd, _image *buf, modeset_display_surface* surface) @@ -342,16 +402,29 @@ void modeset_present(int fd, _image *buf, modeset_display_surface* surface) d.s = surface; d.pending = 1; - while(flipQueue[0].pending); + uint32_t added = 0; + + while(!added) + { + while(flip_queue_guard); + flip_queue_guard = 1; + + //try to add request to queue + added = fifoAdd(&flipQueueFifo, &d); + + flip_queue_guard = 0; + } + + void* first = 0; while(flip_queue_guard); flip_queue_guard = 1; - flipQueue[0] = d; - drmModePageFlip(fd, surface->crtc->crtc_id, buf->fb, DRM_MODE_PAGE_FLIP_EVENT, &flipQueue[0]); + first = fifoGetFirst(&flipQueueFifo); flip_queue_guard = 0; + drmModePageFlip(fd, surface->crtc->crtc_id, buf->fb, DRM_MODE_PAGE_FLIP_EVENT, first); } //modeset_debug_print(fd); diff --git a/driver/modeset.h b/driver/modeset.h index d6eaa51..8ede78b 100644 --- a/driver/modeset.h +++ b/driver/modeset.h @@ -62,7 +62,7 @@ void modeset_create_surface_for_mode(int fd, uint32_t display, uint32_t mode, mo void modeset_create_fb_for_surface(int fd, _image* buf, modeset_display_surface* surface); void modeset_destroy_fb(int fd, _image* buf); void modeset_present(int fd, _image* buf, modeset_display_surface* surface); -void modeset_acquire_image(int fd, _image* buf, modeset_display_surface* surface); +void modeset_acquire_image(int fd, _image** buf, modeset_display_surface** surface); void modeset_destroy_surface(int fd, modeset_display_surface* surface); void modeset_debug_print(int fd); diff --git a/driver/wsi.c b/driver/wsi.c index a824d6e..940a61c 100644 --- a/driver/wsi.c +++ b/driver/wsi.c @@ -466,17 +466,38 @@ VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkAcquireNextImageKHR)( assert(semaphore != VK_NULL_HANDLE || fence != VK_NULL_HANDLE); - sem_t* s = semaphore; + sem_t* sem = semaphore; + _swapchain* sc = swapchain; //TODO we need to keep track of currently acquired images? //TODO wait timeout? - *pImageIndex = ((_swapchain*)swapchain)->backbufferIdx; //return back buffer index + _image* i; + modeset_display_surface* surf; + modeset_acquire_image(controlFd, &i, &surf); + + if(i && surf) + { + for(uint32_t c = 0; c < sc->numImages; ++c) + { + if(&sc->images[c] == i && sc->surface == surf) + { + sc->backbufferIdx = c; + break; + } + } + } + else + { + sc->backbufferIdx = 0; + } + + *pImageIndex = sc->backbufferIdx; //return back buffer index //signal semaphore - int semVal; sem_getvalue(s, &semVal); assert(semVal <= 0); //make sure semaphore is unsignalled - sem_post(s); + int semVal; sem_getvalue(sem, &semVal); assert(semVal <= 0); //make sure semaphore is unsignalled + sem_post(sem); _fence* f = fence; if(f) @@ -526,7 +547,6 @@ VKAPI_ATTR VkResult VKAPI_CALL RPIFUNC(vkQueuePresentKHR)( { _swapchain* s = pPresentInfo->pSwapchains[c]; modeset_present(controlFd, &s->images[pPresentInfo->pImageIndices[c]], s->surface); - s->backbufferIdx = (pPresentInfo->pImageIndices[c] + 1) % s->numImages; } PROFILEEND(RPIFUNC(vkQueuePresentKHR));