From: Ville Syrjälä Date: Tue, 25 May 2010 20:31:24 +0000 (+0300) Subject: gpu: pvr: Add support for flip complete events X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=faaeb0a50371f71064caf8270616dc03165f3652;p=sgx.git gpu: pvr: Add support for flip complete events Add framework for flip complete events. The events are supposed to be signalled when a flip has completed. For now signal them immediately to avoid clients blocking indefinitely. Signed-off-by: Ville Syrjälä --- diff --git a/pvr/bridged_sgx_bridge.c b/pvr/bridged_sgx_bridge.c index e10d5cc..dde3ebe 100644 --- a/pvr/bridged_sgx_bridge.c +++ b/pvr/bridged_sgx_bridge.c @@ -1005,6 +1005,7 @@ int SGX2DQueryBlitsCompleteBW(struct file *filp, u32 ui32BridgeID, void *hDevCookieInt; void *pvSyncInfo; struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data; PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SGX_2DQUERYBLTSCOMPLETE); @@ -1016,6 +1017,16 @@ int SGX2DQueryBlitsCompleteBW(struct file *filp, u32 ui32BridgeID, if (psRetOUT->eError != PVRSRV_OK) return 0; + if (ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_FLIP) { + if (pvr_flip_event_req(priv, + (long)ps2DQueryBltsCompleteIN-> + hKernSyncInfo, + ps2DQueryBltsCompleteIN->user_data)) + psRetOUT->eError = PVRSRV_ERROR_OUT_OF_MEMORY; + + return 0; + } + psRetOUT->eError = PVRSRVLookupHandle(psPerProc->psHandleBase, &pvSyncInfo, ps2DQueryBltsCompleteIN->hKernSyncInfo, @@ -1028,8 +1039,6 @@ int SGX2DQueryBlitsCompleteBW(struct file *filp, u32 ui32BridgeID, hDevCookieInt)->pvDevice; if (ps2DQueryBltsCompleteIN->type == _PVR_SYNC_WAIT_EVENT) { - struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data; - if (pvr_sync_event_req(priv, (struct PVRSRV_KERNEL_SYNC_INFO *)pvSyncInfo, ps2DQueryBltsCompleteIN->user_data)) diff --git a/pvr/pvr_events.c b/pvr/pvr_events.c index 3fdca0f..d6449c8 100644 --- a/pvr/pvr_events.c +++ b/pvr/pvr_events.c @@ -11,6 +11,7 @@ static spinlock_t event_lock; static struct list_head sync_wait_list; +static struct list_head flip_wait_list; static inline bool is_render_complete(const struct PVRSRV_SYNC_DATA *sync) { @@ -70,6 +71,55 @@ int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, return 0; } +static void pvr_signal_flip_event(struct pvr_pending_flip_event *e, + const struct timeval *now) +{ + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + + wake_up_interruptible(&e->base.file_priv->event_wait); +} + +int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + unsigned int overlay, u64 user_data) +{ + struct pvr_pending_flip_event *e; + struct timeval now; + unsigned long flags; + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (e == NULL) + return -ENOMEM; + + e->event.base.type = PVR_EVENT_FLIP; + e->event.base.length = sizeof(e->event); + e->base.event = &e->event.base; + e->event.overlay = overlay; + e->event.user_data = user_data; + e->base.file_priv = priv; + e->base.destroy = (void (*)(struct pvr_pending_event *))kfree; + + do_gettimeofday(&now); + spin_lock_irqsave(&event_lock, flags); + + if (priv->event_space < sizeof(e->event)) { + spin_unlock_irqrestore(&event_lock, flags); + kfree(e); + return -ENOMEM; + } + + priv->event_space -= sizeof(e->event); + + list_add_tail(&e->base.link, &flip_wait_list); + pvr_signal_flip_event(e, &now); + + spin_unlock_irqrestore(&event_lock, flags); + + return 0; +} + static bool pvr_dequeue_event(struct PVRSRV_FILE_PRIVATE_DATA *priv, size_t total, size_t max, struct pvr_pending_event **out) { @@ -170,6 +220,8 @@ void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv) struct pvr_pending_event *z; struct pvr_pending_sync_event *e; struct pvr_pending_sync_event *t; + struct pvr_pending_flip_event *e2; + struct pvr_pending_flip_event *t2; unsigned long flags; spin_lock_irqsave(&event_lock, flags); @@ -181,6 +233,12 @@ void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv) e->base.destroy(&e->base); } + list_for_each_entry_safe(e2, t2, &flip_wait_list, base.link) + if (e2->base.file_priv == priv) { + list_del(&e2->base.link); + e2->base.destroy(&e2->base); + } + /* Remove unconsumed events */ list_for_each_entry_safe(w, z, &priv->event_list, link) w->destroy(w); @@ -192,4 +250,5 @@ void pvr_init_events(void) { spin_lock_init(&event_lock); INIT_LIST_HEAD(&sync_wait_list); + INIT_LIST_HEAD(&flip_wait_list); } diff --git a/pvr/pvr_events.h b/pvr/pvr_events.h index 1798a75..b90074d 100644 --- a/pvr/pvr_events.h +++ b/pvr/pvr_events.h @@ -23,6 +23,7 @@ struct pvr_event { }; #define PVR_EVENT_SYNC 0x01 +#define PVR_EVENT_FLIP 0x02 /* * Every buffer used as a render target has a 'PVRSRV_KERNEL_SYNC_INFO' @@ -48,6 +49,14 @@ struct pvr_event_sync { __u32 tv_usec; }; +struct pvr_event_flip { + struct pvr_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 overlay; +}; + /* Event queued up for userspace to read */ struct pvr_pending_event { struct pvr_event *event; @@ -61,11 +70,18 @@ struct pvr_pending_sync_event { struct pvr_event_sync event; }; +struct pvr_pending_flip_event { + struct pvr_pending_event base; + struct pvr_event_flip event; +}; + void pvr_init_events(void); int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, const struct PVRSRV_KERNEL_SYNC_INFO *sync_info, u64 user_data); +int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv, + unsigned int overlay, u64 user_data); ssize_t pvr_read(struct file *filp, char __user *buf, size_t count, loff_t *off); unsigned int pvr_poll(struct file *filp, struct poll_table_struct *wait); diff --git a/pvr/sgx_bridge.h b/pvr/sgx_bridge.h index d40b3b7..8dfdd56 100644 --- a/pvr/sgx_bridge.h +++ b/pvr/sgx_bridge.h @@ -220,6 +220,7 @@ enum pvr_sync_wait_seq_type { _PVR_SYNC_WAIT_BLOCK, _PVR_SYNC_WAIT_NONBLOCK, _PVR_SYNC_WAIT_EVENT, + _PVR_SYNC_WAIT_FLIP, }; struct PVRSRV_BRIDGE_IN_2DQUERYBLTSCOMPLETE {