static void rbug_draw_block_locked(struct rbug_context *rb_pipe, int flag) { if (rb_pipe->draw_blocker & flag) { rb_pipe->draw_blocked |= flag; } else if ((rb_pipe->draw_rule.blocker & flag) && (rb_pipe->draw_blocker & RBUG_BLOCK_RULE)) { unsigned k; boolean block = FALSE; unsigned sh; debug_printf("%s (%p %p) (%p %p) (%p %u) (%p %u)\n", __FUNCTION__, (void *) rb_pipe->draw_rule.shader[PIPE_SHADER_FRAGMENT], (void *) rb_pipe->curr.shader[PIPE_SHADER_FRAGMENT], (void *) rb_pipe->draw_rule.shader[PIPE_SHADER_VERTEX], (void *) rb_pipe->curr.shader[PIPE_SHADER_VERTEX], (void *) rb_pipe->draw_rule.surf, 0, (void *) rb_pipe->draw_rule.texture, 0); for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { if (rb_pipe->draw_rule.shader[sh] && rb_pipe->draw_rule.shader[sh] == rb_pipe->curr.shader[sh]) block = TRUE; } if (rb_pipe->draw_rule.surf && rb_pipe->draw_rule.surf == rb_pipe->curr.zsbuf) block = TRUE; if (rb_pipe->draw_rule.surf) for (k = 0; k < rb_pipe->curr.nr_cbufs; k++) if (rb_pipe->draw_rule.surf == rb_pipe->curr.cbufs[k]) block = TRUE; if (rb_pipe->draw_rule.texture) { for (sh = 0; sh < Elements(rb_pipe->curr.num_views); sh++) { for (k = 0; k < rb_pipe->curr.num_views[sh]; k++) { if (rb_pipe->draw_rule.texture == rb_pipe->curr.texs[sh][k]) { block = TRUE; sh = PIPE_SHADER_TYPES; /* to break out of both loops */ break; } } } } if (block) rb_pipe->draw_blocked |= (flag | RBUG_BLOCK_RULE); } if (rb_pipe->draw_blocked) rbug_notify_draw_blocked(rb_pipe); /* wait for rbug to clear the blocked flag */ while (rb_pipe->draw_blocked & flag) { rb_pipe->draw_blocked |= flag; pipe_condvar_wait(rb_pipe->draw_cond, rb_pipe->draw_mutex); } }
static INLINE void trace_context_draw_block(struct trace_context *tr_ctx, int flag) { int k; pipe_mutex_lock(tr_ctx->draw_mutex); if (tr_ctx->draw_blocker & flag) { tr_ctx->draw_blocked |= flag; } else if ((tr_ctx->draw_rule.blocker & flag) && (tr_ctx->draw_blocker & 4)) { boolean block = FALSE; debug_printf("%s (%p %p) (%p %p) (%p %u) (%p %u)\n", __FUNCTION__, (void *) tr_ctx->draw_rule.fs, (void *) tr_ctx->curr.fs, (void *) tr_ctx->draw_rule.vs, (void *) tr_ctx->curr.vs, (void *) tr_ctx->draw_rule.surf, 0, (void *) tr_ctx->draw_rule.tex, 0); if (tr_ctx->draw_rule.fs && tr_ctx->draw_rule.fs == tr_ctx->curr.fs) block = TRUE; if (tr_ctx->draw_rule.vs && tr_ctx->draw_rule.vs == tr_ctx->curr.vs) block = TRUE; if (tr_ctx->draw_rule.surf && tr_ctx->draw_rule.surf == tr_ctx->curr.zsbuf) block = TRUE; if (tr_ctx->draw_rule.surf) for (k = 0; k < tr_ctx->curr.nr_cbufs; k++) if (tr_ctx->draw_rule.surf == tr_ctx->curr.cbufs[k]) block = TRUE; if (tr_ctx->draw_rule.tex) for (k = 0; k < tr_ctx->curr.num_texs; k++) if (tr_ctx->draw_rule.tex == tr_ctx->curr.tex[k]) block = TRUE; if (block) tr_ctx->draw_blocked |= (flag | 4); } if (tr_ctx->draw_blocked) trace_rbug_notify_draw_blocked(tr_ctx); /* wait for rbug to clear the blocked flag */ while (tr_ctx->draw_blocked & flag) { tr_ctx->draw_blocked |= flag; #ifdef PIPE_THREAD_HAVE_CONDVAR pipe_condvar_wait(tr_ctx->draw_cond, tr_ctx->draw_mutex); #else pipe_mutex_unlock(tr_ctx->draw_mutex); #ifdef PIPE_SUBSYSTEM_WINDOWS_USER Sleep(1); #endif pipe_mutex_lock(tr_ctx->draw_mutex); #endif } pipe_mutex_unlock(tr_ctx->draw_mutex); }
enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring, struct util_packet *packet, unsigned max_dwords, boolean wait ) { const struct util_packet *ring_packet; unsigned i; int ret = PIPE_OK; /* XXX: over-reliance on mutexes, etc: */ pipe_mutex_lock(ring->mutex); /* Get next ring entry: */ if (wait) { while (util_ringbuffer_empty(ring)) pipe_condvar_wait(ring->change, ring->mutex); } else { if (util_ringbuffer_empty(ring)) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto out; } } ring_packet = &ring->buf[ring->tail]; /* Both of these are considered bugs. Raise an assert on debug builds. */ if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) || ring_packet->dwords > max_dwords) { assert(0); ret = PIPE_ERROR_BAD_INPUT; goto out; } /* Copy data from ring: */ for (i = 0; i < ring_packet->dwords; i++) { packet[i] = ring->buf[ring->tail]; ring->tail++; ring->tail &= ring->mask; } out: /* Signal change: */ pipe_condvar_signal(ring->change); pipe_mutex_unlock(ring->mutex); return ret; }
void lp_fence_wait(struct lp_fence *f) { if (LP_DEBUG & DEBUG_FENCE) debug_printf("%s %d\n", __FUNCTION__, f->id); pipe_mutex_lock(f->mutex); assert(f->issued); while (f->count < f->rank) { pipe_condvar_wait(f->signalled, f->mutex); } pipe_mutex_unlock(f->mutex); }
static PIPE_THREAD_ROUTINE( quad_thread, param ) { struct thread_info *info = (struct thread_info *) param; struct quad_job_que *que = &info->setup->que; for (;;) { struct quad_job job; boolean full; /* Wait for an available job. */ pipe_mutex_lock( que->que_mutex ); while (que->last == que->first) pipe_condvar_wait( que->que_notempty_condvar, que->que_mutex ); /* See if the que is full. */ full = (que->last + 1) % NUM_QUAD_JOBS == que->first; /* Take a job and remove it from que. */ job = que->jobs[que->first]; que->first = (que->first + 1) % NUM_QUAD_JOBS; /* Notify the producer if the que is not full. */ if (full) pipe_condvar_signal( que->que_notfull_condvar ); pipe_mutex_unlock( que->que_mutex ); job.routine( info->setup, info->id, &job ); /* Notify the producer if that's the last finished job. */ pipe_mutex_lock( que->que_mutex ); que->jobs_done++; if (que->jobs_added == que->jobs_done) pipe_condvar_signal( que->que_done_condvar ); pipe_mutex_unlock( que->que_mutex ); } return NULL; }
static void add_quad_job( struct quad_job_que *que, struct quad_header *quad, quad_job_routine routine ) { #if INSTANT_NOTEMPTY_NOTIFY boolean empty; #endif /* Wait for empty slot, see if the que is empty. */ pipe_mutex_lock( que->que_mutex ); while ((que->last + 1) % NUM_QUAD_JOBS == que->first) { #if !INSTANT_NOTEMPTY_NOTIFY pipe_condvar_broadcast( que->que_notempty_condvar ); #endif pipe_condvar_wait( que->que_notfull_condvar, que->que_mutex ); } #if INSTANT_NOTEMPTY_NOTIFY empty = que->last == que->first; #endif que->jobs_added++; pipe_mutex_unlock( que->que_mutex ); /* Submit new job. */ que->jobs[que->last].input = quad->input; que->jobs[que->last].inout = quad->inout; que->jobs[que->last].routine = routine; que->last = (que->last + 1) % NUM_QUAD_JOBS; #if INSTANT_NOTEMPTY_NOTIFY /* If the que was empty, notify consumers there's a job to be done. */ if (empty) { pipe_mutex_lock( que->que_mutex ); pipe_condvar_broadcast( que->que_notempty_condvar ); pipe_mutex_unlock( que->que_mutex ); } #endif }
void util_ringbuffer_enqueue( struct util_ringbuffer *ring, const struct util_packet *packet ) { unsigned i; /* XXX: over-reliance on mutexes, etc: */ pipe_mutex_lock(ring->mutex); /* make sure we don't request an impossible amount of space */ assert(packet->dwords <= ring->mask); /* Wait for free space: */ while (util_ringbuffer_space(ring) < packet->dwords) pipe_condvar_wait(ring->change, ring->mutex); /* Copy data to ring: */ for (i = 0; i < packet->dwords; i++) { /* Copy all dwords of the packet. Note we're abusing the * typesystem a little - we're being passed a pointer to * something, but probably not an array of packet structs: */ ring->buf[ring->head] = packet[i]; ring->head++; ring->head &= ring->mask; } /* Signal change: */ pipe_condvar_signal(ring->change); pipe_mutex_unlock(ring->mutex); }
static void radeon_drm_cs_flush(struct radeon_winsys_cs *rcs, unsigned flags, uint32_t cs_trace_id) { struct radeon_drm_cs *cs = radeon_drm_cs(rcs); struct radeon_cs_context *tmp; switch (cs->base.ring_type) { case RING_DMA: /* pad DMA ring to 8 DWs */ if (cs->ws->info.chip_class <= SI) { while (rcs->cdw & 7) OUT_CS(&cs->base, 0xf0000000); /* NOP packet */ } else { while (rcs->cdw & 7) OUT_CS(&cs->base, 0x00000000); /* NOP packet */ } break; case RING_GFX: /* pad DMA ring to 8 DWs to meet CP fetch alignment requirements * r6xx, requires at least 4 dw alignment to avoid a hw bug. */ if (flags & RADEON_FLUSH_COMPUTE) { if (cs->ws->info.chip_class <= SI) { while (rcs->cdw & 7) OUT_CS(&cs->base, 0x80000000); /* type2 nop packet */ } else { while (rcs->cdw & 7) OUT_CS(&cs->base, 0xffff1000); /* type3 nop packet */ } } else { while (rcs->cdw & 7) OUT_CS(&cs->base, 0x80000000); /* type2 nop packet */ } break; } if (rcs->cdw > RADEON_MAX_CMDBUF_DWORDS) { fprintf(stderr, "radeon: command stream overflowed\n"); } radeon_drm_cs_sync_flush(rcs); /* Flip command streams. */ tmp = cs->csc; cs->csc = cs->cst; cs->cst = tmp; cs->cst->cs_trace_id = cs_trace_id; /* If the CS is not empty or overflowed, emit it in a separate thread. */ if (cs->base.cdw && cs->base.cdw <= RADEON_MAX_CMDBUF_DWORDS && !debug_get_option_noop()) { unsigned i, crelocs = cs->cst->crelocs; cs->cst->chunks[0].length_dw = cs->base.cdw; for (i = 0; i < crelocs; i++) { /* Update the number of active asynchronous CS ioctls for the buffer. */ p_atomic_inc(&cs->cst->relocs_bo[i]->num_active_ioctls); } switch (cs->base.ring_type) { case RING_DMA: cs->cst->flags[0] = 0; cs->cst->flags[1] = RADEON_CS_RING_DMA; cs->cst->cs.num_chunks = 3; if (cs->ws->info.r600_virtual_address) { cs->cst->flags[0] |= RADEON_CS_USE_VM; } break; case RING_UVD: cs->cst->flags[0] = 0; cs->cst->flags[1] = RADEON_CS_RING_UVD; cs->cst->cs.num_chunks = 3; break; default: case RING_GFX: cs->cst->flags[0] = 0; cs->cst->flags[1] = RADEON_CS_RING_GFX; cs->cst->cs.num_chunks = 2; if (flags & RADEON_FLUSH_KEEP_TILING_FLAGS) { cs->cst->flags[0] |= RADEON_CS_KEEP_TILING_FLAGS; cs->cst->cs.num_chunks = 3; } if (cs->ws->info.r600_virtual_address) { cs->cst->flags[0] |= RADEON_CS_USE_VM; cs->cst->cs.num_chunks = 3; } if (flags & RADEON_FLUSH_END_OF_FRAME) { cs->cst->flags[0] |= RADEON_CS_END_OF_FRAME; cs->cst->cs.num_chunks = 3; } if (flags & RADEON_FLUSH_COMPUTE) { cs->cst->flags[1] = RADEON_CS_RING_COMPUTE; cs->cst->cs.num_chunks = 3; } break; } if (cs->ws->thread && (flags & RADEON_FLUSH_ASYNC)) { cs->flush_started = 1; radeon_drm_ws_queue_cs(cs->ws, cs); } else { pipe_mutex_lock(cs->ws->cs_stack_lock); if (cs->ws->thread) { while (p_atomic_read(&cs->ws->ncs)) { pipe_condvar_wait(cs->ws->cs_queue_empty, cs->ws->cs_stack_lock); } } pipe_mutex_unlock(cs->ws->cs_stack_lock); radeon_drm_cs_emit_ioctl_oneshot(cs, cs->cst); } } else { radeon_cs_context_cleanup(cs->cst); } /* Prepare a new CS. */ cs->base.buf = cs->csc->buf; cs->base.cdw = 0; }