struct etna_bo* etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; if((flags & DRM_ETNA_GEM_TYPE_MASK) == DRM_ETNA_GEM_TYPE_CMD) { mem->bo_type = ETNA_BO_TYPE_CONTIGUOUS; /* Command buffers must be allocated with viv_alloc_contiguous */ if(viv_alloc_contiguous(conn, bytes, &mem->address, &mem->logical, &mem->size)!=0) { ETNA_FREE(mem); return NULL; } } else { enum viv_surf_type type = VIV_SURF_UNKNOWN; enum viv_pool pool = VIV_POOL_DEFAULT; /* Convert GEM bits to surface type */ switch(flags & DRM_ETNA_GEM_TYPE_MASK) { case DRM_ETNA_GEM_TYPE_IDX: type = VIV_SURF_INDEX; break; case DRM_ETNA_GEM_TYPE_VTX: type = VIV_SURF_VERTEX; break; case DRM_ETNA_GEM_TYPE_TEX: type = VIV_SURF_TEXTURE; break; case DRM_ETNA_GEM_TYPE_RT: type = VIV_SURF_RENDER_TARGET; break; case DRM_ETNA_GEM_TYPE_ZS: type = VIV_SURF_DEPTH; break; case DRM_ETNA_GEM_TYPE_HZ: type = VIV_SURF_HIERARCHICAL_DEPTH; break; case DRM_ETNA_GEM_TYPE_BMP: type = VIV_SURF_BITMAP; break; case DRM_ETNA_GEM_TYPE_TS: type = VIV_SURF_TILE_STATUS; break; default: /* Invalid type */ ETNA_FREE(mem); return NULL; break; } mem->bo_type = ETNA_BO_TYPE_VIDMEM; mem->type = type; if(viv_alloc_linear_vidmem(conn, bytes, ETNA_VIDMEM_ALIGNMENT, type, pool, &mem->node, &mem->size)!=0) { #ifdef DEBUG fprintf(stderr, "Error allocating memory\n"); #endif return NULL; } #ifdef DEBUG printf("Allocated: mem=%p node=%08x size=%08x\n", mem, (uint32_t)mem->node, mem->size); #endif int status = etna_bo_lock(conn, mem); if(status != ETNA_OK) { etna_bo_del(conn, mem, NULL); return NULL; } } return mem; }
int etna_queue_create(struct etna_ctx *ctx, struct etna_queue **queue_out) { struct etna_queue *queue = ETNA_CALLOC_STRUCT(etna_queue); if(queue == NULL) { return ETNA_OUT_OF_MEMORY; } queue->ctx = ctx; queue->queue = ETNA_CALLOC_STRUCT_ARRAY(ETNA_QUEUE_CAPACITY, _gcsQUEUE); queue->last = NULL; queue->count = 0; queue->max_count = ETNA_QUEUE_CAPACITY; *queue_out = queue; return ETNA_OK; }
struct etna_bo *etna_bo_from_name(struct viv_conn *conn, uint32_t name) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; mem->bo_type = ETNA_BO_TYPE_VIDMEM_EXTERNAL; mem->node = (viv_node_t)name; /* Lock to this address space */ int status = etna_bo_lock(conn, mem); if(status != ETNA_OK) { free(mem); return NULL; } return mem; }
struct etna_bo *etna_bo_from_usermem(struct viv_conn *conn, void *memory, size_t size) { struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; mem->bo_type = ETNA_BO_TYPE_USERMEM; mem->logical = memory; mem->size = size; if(viv_map_user_memory(conn, memory, size, &mem->usermem_info, &mem->address)!=0) { ETNA_FREE(mem); return NULL; } return mem; }
struct etna_bo *etna_bo_from_fbdev(struct viv_conn *conn, int fd, size_t offset, size_t size) { struct fb_fix_screeninfo finfo; struct etna_bo *mem = ETNA_CALLOC_STRUCT(etna_bo); if(mem == NULL) return NULL; if(ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) goto error; mem->bo_type = ETNA_BO_TYPE_PHYSICAL; if((mem->logical = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == NULL) goto error; mem->address = finfo.smem_start + offset; mem->size = size; return mem; error: ETNA_FREE(mem); return NULL; }
static int gpu_context_initialize(struct etna_ctx *ctx) { gcoCONTEXT vctx = ETNA_CALLOC_STRUCT(_gcoCONTEXT); if(vctx == NULL) { return ETNA_OUT_OF_MEMORY; } vctx->object.type = gcvOBJ_CONTEXT; vctx->id = 0x0; /* Actual ID will be returned here by kernel */ vctx->pipe3DIndex = vctx->pipe2DIndex = /* Any non-zero value will do, as kernel does not use */ vctx->linkIndex = vctx->inUseIndex = 1; /* the actual values, just checks for zero */ vctx->initialPipe = ETNA_PIPE_3D; /* Pipe to be active at beginning of context buffer */ vctx->entryPipe = ETNA_PIPE_3D; /* Pipe at beginning of command buffer (needs to be added to context as well if */ /* pipe at end of context is different from entry pipe) */ vctx->currentPipe = ETNA_PIPE_3D; /* Pipe at end of command buffer */ /* CPU address of buffer */ vctx->logical = 0; /* Number of bytes to read from command buffer by GPU */ vctx->bufferSize = 0; /* Logical address of two NOP words at end of command buffer */ vctx->link = NULL; /* Logical address of inUse flag as returned from kernel (within * consecutive array), must have one word of NOP */ vctx->inUse = NULL; ctx->ctx = VIV_TO_HANDLE(vctx); /* Allocate initial context buffer */ /* XXX DRM_ETNA_GEM_CACHE_xxx */ if((ctx->ctx_bo = etna_bo_new(ctx->conn, COMMAND_BUFFER_SIZE, DRM_ETNA_GEM_TYPE_CMD)) == NULL) { ETNA_FREE(vctx); return ETNA_OUT_OF_MEMORY; } /* Set context to initial sane values */ gpu_context_clear(ctx); return ETNA_OK; }
int etna_create(struct viv_conn *conn, struct etna_ctx **ctx_out) { int rv; if(ctx_out == NULL) return ETNA_INVALID_ADDR; struct etna_ctx *ctx = ETNA_CALLOC_STRUCT(etna_ctx); if(ctx == NULL) return ETNA_OUT_OF_MEMORY; ctx->conn = conn; if(gpu_context_initialize(ctx) != ETNA_OK) { ETNA_FREE(ctx); return ETNA_INTERNAL_ERROR; } /* Create synchronization signal */ if(viv_user_signal_create(conn, 0, &ctx->sig_id) != 0) /* automatic resetting signal */ { #ifdef DEBUG fprintf(stderr, "Cannot create user signal\n"); #endif return ETNA_INTERNAL_ERROR; } #ifdef DEBUG fprintf(stderr, "Created user signal %i\n", ctx->sig_id); #endif /* Allocate command buffers, and create a synchronization signal for each. * Also signal the synchronization signal for the buffers to tell that the buffers are ready for use. */ for(int x=0; x<NUM_COMMAND_BUFFERS; ++x) { ctx->cmdbuf[x] = ETNA_CALLOC_STRUCT(_gcoCMDBUF); if((ctx->cmdbufi[x].bo = etna_bo_new(conn, COMMAND_BUFFER_SIZE, DRM_ETNA_GEM_TYPE_CMD))==NULL) { #ifdef DEBUG fprintf(stderr, "Error allocating host memory for command buffer\n"); #endif return ETNA_OUT_OF_MEMORY; } ctx->cmdbuf[x]->object.type = gcvOBJ_COMMANDBUFFER; #ifdef GCABI_CMDBUF_HAS_PHYSICAL ctx->cmdbuf[x]->physical = PTR_TO_VIV((void*)etna_bo_gpu_address(ctx->cmdbufi[x].bo)); ctx->cmdbuf[x]->bytes = ctx->cmdbufi[x].bytes; #endif ctx->cmdbuf[x]->logical = PTR_TO_VIV((void*)etna_bo_map(ctx->cmdbufi[x].bo)); if(viv_user_signal_create(conn, 0, &ctx->cmdbufi[x].sig_id) != 0 || viv_user_signal_signal(conn, ctx->cmdbufi[x].sig_id, 1) != 0) { #ifdef DEBUG fprintf(stderr, "Cannot create user signal\n"); #endif return ETNA_INTERNAL_ERROR; } #ifdef DEBUG fprintf(stderr, "Allocated buffer %i: phys=%08x log=%08x bytes=%08x [signal %i]\n", x, (uint32_t)buf0_physical, (uint32_t)buf0_logical, buf0_bytes, ctx->cmdbufi[x].sig); #endif } /* Allocate command queue */ if((rv = etna_queue_create(ctx, &ctx->queue)) != ETNA_OK) { #ifdef DEBUG fprintf(stderr, "Error allocating kernel command queue\n"); #endif return rv; } /* Set current buffer to ETNA_NO_BUFFER, to signify that we need to switch to buffer 0 before * queueing of commands can be started. */ ctx->cur_buf = ETNA_NO_BUFFER; *ctx_out = ctx; return ETNA_OK; }