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; }
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; }