Ejemplo n.º 1
0
int etna_flush(etna_ctx *ctx)
{
    if(ctx == NULL)
        return ETNA_INVALID_ADDR;
    if(ctx->cur_buf == -1)
        return ETNA_OK; /* Nothing to do */
    gcoCMDBUF cur_buf = &ctx->cmdbuf[ctx->cur_buf];
    ETNA_ALIGN(ctx); /* make sure end of submitted command buffer end is aligned */
#ifdef DEBUG
    printf("Committing command buffer %i startOffset=%x offset=%x\n", ctx->cur_buf,
            cur_buf->startOffset, ctx->offset*4);
#endif
    if(ctx->offset*4 <= (cur_buf->startOffset + BEGIN_COMMIT_CLEARANCE))
        return ETNA_OK; /* Nothing to do */
    cur_buf->offset = ctx->offset*4; /* Copy over current ending offset into CMDBUF, for kernel */
#ifdef DEBUG
    printf("    {");
    for(size_t i=cur_buf->startOffset; i<cur_buf->offset; i+=4)
    {
        printf("0x%08x,", *((uint32_t*)(((size_t)cur_buf->logical)+i)));
    }
    printf("}\n");
#endif
    int status = viv_commit(cur_buf, &ctx->ctx);
    if(status != 0)
    {
#ifdef DEBUG
        fprintf(stderr, "Error committing command buffer\n");
#endif
        return status;
    }
    if(*ctx->ctx.inUse)
    {
        printf("    Warning: context buffer used, full context handling not yet supported. Rendering may be corrupted.\n");
        *ctx->ctx.inUse = 0;
    }
    /* TODO: analyze command buffer to update context */
    /* set context entryPipe to currentPipe (next commit will start with current pipe) */
    ctx->ctx.entryPipe = ctx->ctx.currentPipe;
    /* TODO: update context, NOP out final pipe2D if entryPipe is 2D, else put in the 2D pipe switch */
    /* TODO: if context was used, queue it to be freed later, and initialize new context buffer */
    cur_buf->startOffset = cur_buf->offset + END_COMMIT_CLEARANCE;
    cur_buf->offset = cur_buf->startOffset + BEGIN_COMMIT_CLEARANCE;
    ctx->offset = cur_buf->offset / 4;
#ifdef DEBUG
    printf("  New start offset: %x New offset: %x Contextbuffer used: %i\n", cur_buf->startOffset, cur_buf->offset, *ctx->ctx.inUse);
#endif
    return ETNA_OK;
}
Ejemplo n.º 2
0
int etna_flush(struct etna_ctx *ctx)
{
    int status;
    if(ctx == NULL)
        return ETNA_INVALID_ADDR;
    if(ctx->cur_buf == ETNA_CTX_BUFFER)
        /* Can never flush while building context buffer */
        return ETNA_INTERNAL_ERROR;
    struct _gcsQUEUE *queue_first = etna_queue_first(ctx->queue);
    if(ctx->cur_buf == ETNA_NO_BUFFER)
        goto nothing_to_do;
    gcoCMDBUF cur_buf = ctx->cmdbuf[ctx->cur_buf];

    ETNA_ALIGN(ctx); /* make sure end of submitted command buffer end is aligned */
#ifdef DEBUG
    printf("Committing command buffer %i startOffset=%x offset=%x\n", ctx->cur_buf,
            cur_buf->startOffset, ctx->offset*4);
#endif
    if(ctx->offset*4 <= (cur_buf->startOffset + BEGIN_COMMIT_CLEARANCE))
        goto nothing_to_do;
    cur_buf->offset = ctx->offset*4; /* Copy over current ending offset into CMDBUF, for kernel */
#ifdef DEBUG_CMDBUF
    etna_dump_cmd_buffer(ctx);
#endif
#ifdef GCABI_HAS_CONTEXT
    gpu_context_finish_up(ctx);
#endif
    if(!queue_first)
        ctx->flushes += 1;
    else
        ctx->flushes = 0;
    if((status = viv_commit(ctx->conn, cur_buf, ctx->ctx, queue_first)) != 0)
    {
#ifdef DEBUG
        fprintf(stderr, "Error committing command buffer\n");
#endif
        return status;
    }
    if((status = etna_queue_clear(ctx->queue)) != ETNA_OK)
        return status;
#ifdef GCABI_HAS_CONTEXT
    /* set context entryPipe to currentPipe (next commit will start with current pipe) */
    GCCTX(ctx)->entryPipe = GCCTX(ctx)->currentPipe;
    gpu_context_clear(ctx);
    if(ctx->ctx_cb)
    {
        enum etna_pipe initial_pipe, final_pipe;
        /* Start building GPU context */
        if((status = gpu_context_build_start(ctx)) != ETNA_OK)
        {
            printf("%s: gpu_context_build_start failed with status %i\n", __func__, status);
            return status;
        }
        if((status = ctx->ctx_cb(ctx->ctx_cb_data, ctx, &initial_pipe, &final_pipe)) != ETNA_OK)
        {
            printf("%s: Context callback failed with status %i\n", __func__, status);
            return status;
        }
        /* Set initial pipe in context */
        GCCTX(ctx)->initialPipe = initial_pipe;
        /* Finish building GPU context */
        if((status = gpu_context_build_end(ctx, final_pipe)) != ETNA_OK)
        {
            printf("%s: gpu_context_build_end failed with status %i\n", __func__, status);
            return status;
        }
    }
#endif
    cur_buf->startOffset = cur_buf->offset + END_COMMIT_CLEARANCE;
    cur_buf->offset = cur_buf->startOffset + BEGIN_COMMIT_CLEARANCE;

    if((cur_buf->offset + END_COMMIT_CLEARANCE) >= COMMAND_BUFFER_SIZE ||
       ctx->flushes > ETNA_MAX_UNSIGNALED_FLUSHES)
    {
        /* nothing more fits in buffer, prevent warning about buffer overflow
           on next etna_reserve.
         */
        cur_buf->startOffset = cur_buf->offset = COMMAND_BUFFER_SIZE - END_COMMIT_CLEARANCE;
    }

    /* Set writing offset for next etna_reserve. For convenience this is
       stored as an index instead of a byte offset.  */
    ctx->offset = cur_buf->offset / 4;
#ifdef DEBUG
#ifdef GCABI_HAS_CONTEXT
    printf("  New start offset: %x New offset: %x Contextbuffer used: %i\n", cur_buf->startOffset, cur_buf->offset, *(GCCTX(ctx)->inUse));
#else
    printf("  New start offset: %x New offset: %x\n", cur_buf->startOffset, cur_buf->offset);
#endif
#endif
    return ETNA_OK;
nothing_to_do:
    /* Nothing in command buffer; but there may be kernel commands to submit. Do this seperately. */
    if(queue_first != NULL)
    {
        ctx->flushes = 0;
        if((status = viv_event_commit(ctx->conn, queue_first)) != 0)
        {
#ifdef DEBUG
            fprintf(stderr, "Error committing kernel commands\n");
#endif
            return status;
        }
        if((status = etna_queue_clear(ctx->queue)) != ETNA_OK)
            return status;
    }
    return ETNA_OK;
}