r600g: fix memory/bo leak
[mesa.git] / src / gallium / winsys / r600 / drm / radeon_ctx.c
index bd050c4cf90d96e9326584c4d46bcd9862e491c3..47fca76136825902c0b774b0f0854a7a260acc17 100644 (file)
 #include "radeon_drm.h"
 #include "bof.h"
 
-int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo)
+static int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo)
 {
-       void *ptr;
-
-       ptr = realloc(ctx->bo, sizeof(struct radeon_bo) * (ctx->nbo + 1));
-       if (ptr == NULL) {
-               return -ENOMEM;
-       }
-       ctx->bo = ptr;
+       if (ctx->nbo >= RADEON_CTX_MAX_PM4)
+               return -EBUSY;
        ctx->bo[ctx->nbo] = bo;
        ctx->nbo++;
        return 0;
 }
 
-struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
+static struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
 {
        struct radeon_cs_reloc *greloc;
        unsigned i;
@@ -59,7 +54,7 @@ struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
        return NULL;
 }
 
-void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement)
+static void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement)
 {
        struct radeon_cs_reloc *greloc;
        unsigned i;
@@ -76,50 +71,57 @@ void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *place
        }
 }
 
-struct radeon_ctx *radeon_ctx(struct radeon *radeon)
+void radeon_ctx_clear(struct radeon_ctx *ctx)
 {
-       struct radeon_ctx *ctx;
-
-       if (radeon == NULL)
-               return NULL;
-       ctx = calloc(1, sizeof(*ctx));
-       if (ctx == NULL)
-               return NULL;
-       ctx->radeon = radeon_incref(radeon);
-       return ctx;
+       for (int i = 0; i < ctx->nbo; i++) {
+               ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]);
+       }
+       ctx->ndwords = RADEON_CTX_MAX_PM4;
+       ctx->cdwords = 0;
+       ctx->nreloc = 0;
+       ctx->nbo = 0;
 }
 
-struct radeon_ctx *radeon_ctx_incref(struct radeon_ctx *ctx)
+int radeon_ctx_init(struct radeon_ctx *ctx, struct radeon *radeon)
 {
-       ctx->refcount++;
-       return ctx;
+       if (radeon == NULL)
+               return -EINVAL;
+       memset(ctx, 0, sizeof(struct radeon_ctx));
+       ctx->radeon = radeon_incref(radeon);
+       radeon_ctx_clear(ctx);
+       ctx->pm4 = malloc(RADEON_CTX_MAX_PM4 * 4);
+       if (ctx->pm4 == NULL) {
+               radeon_ctx_fini(ctx);
+               return -ENOMEM;
+       }
+       ctx->reloc = malloc(sizeof(struct radeon_cs_reloc) * RADEON_CTX_MAX_PM4);
+       if (ctx->reloc == NULL) {
+               radeon_ctx_fini(ctx);
+               return -ENOMEM;
+       }
+       ctx->bo = malloc(sizeof(void *) * RADEON_CTX_MAX_PM4);
+       if (ctx->bo == NULL) {
+               radeon_ctx_fini(ctx);
+               return -ENOMEM;
+       }
+       return 0;
 }
 
-struct radeon_ctx *radeon_ctx_decref(struct radeon_ctx *ctx)
+void radeon_ctx_fini(struct radeon_ctx *ctx)
 {
        unsigned i;
 
        if (ctx == NULL)
-               return NULL;
-       if (--ctx->refcount > 0) {
-               return NULL;
-       }
+               return;
 
-       for (i = 0; i < ctx->ndraw; i++) {
-               ctx->draw[i] = radeon_draw_decref(ctx->draw[i]);
-       }
        for (i = 0; i < ctx->nbo; i++) {
                ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]);
        }
        ctx->radeon = radeon_decref(ctx->radeon);
-       free(ctx->state);
-       free(ctx->draw);
        free(ctx->bo);
        free(ctx->pm4);
        free(ctx->reloc);
-       memset(ctx, 0, sizeof(*ctx));
-       free(ctx);
-       return NULL;
+       memset(ctx, 0, sizeof(struct radeon_ctx));
 }
 
 static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state)
@@ -152,17 +154,17 @@ int radeon_ctx_submit(struct radeon_ctx *ctx)
        uint64_t chunk_array[2];
        int r = 0;
 
-       if (!ctx->cpm4)
+       if (!ctx->cdwords)
                return 0;
 #if 0
-       for (r = 0; r < ctx->cpm4; r++) {
+       for (r = 0; r < ctx->cdwords; r++) {
                fprintf(stderr, "0x%08X\n", ctx->pm4[r]);
        }
 #endif
        drmib.num_chunks = 2;
        drmib.chunks = (uint64_t)(uintptr_t)chunk_array;
        chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
-       chunks[0].length_dw = ctx->cpm4;
+       chunks[0].length_dw = ctx->cdwords;
        chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4;
        chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
        chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
@@ -180,7 +182,6 @@ static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
                        unsigned id, unsigned *placement)
 {
        unsigned i;
-       struct radeon_cs_reloc *ptr;
 
        for (i = 0; i < ctx->nreloc; i++) {
                if (ctx->reloc[i].handle == bo->handle) {
@@ -188,14 +189,13 @@ static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
                        return 0;
                }
        }
-       ptr = realloc(ctx->reloc, sizeof(struct radeon_cs_reloc) * (ctx->nreloc + 1));
-       if (ptr == NULL)
-               return -ENOMEM;
-       ctx->reloc = ptr;
-       ptr[ctx->nreloc].handle = bo->handle;
-       ptr[ctx->nreloc].read_domain = placement[0] | placement [1];
-       ptr[ctx->nreloc].write_domain = placement[0] | placement [1];
-       ptr[ctx->nreloc].flags = 0;
+       if (ctx->nreloc >= RADEON_CTX_MAX_PM4) {
+               return -EBUSY;
+       }
+       ctx->reloc[ctx->nreloc].handle = bo->handle;
+       ctx->reloc[ctx->nreloc].read_domain = placement[0] | placement [1];
+       ctx->reloc[ctx->nreloc].write_domain = placement[0] | placement [1];
+       ctx->reloc[ctx->nreloc].flags = 0;
        ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
        ctx->nreloc++;
        return 0;
@@ -208,132 +208,80 @@ static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state
 
        if (state == NULL)
                return 0;
-       memcpy(&ctx->pm4[ctx->id], state->pm4, state->cpm4 * 4);
+       if (state->cpm4 > ctx->ndwords) {
+               return -EBUSY;
+       }
+       memcpy(&ctx->pm4[ctx->cdwords], state->pm4, state->cpm4 * 4);
        for (i = 0; i < state->nreloc; i++) {
                rid = state->reloc_pm4_id[i];
                bid = state->reloc_bo_id[i];
-               cid = ctx->id + rid;
+               cid = ctx->cdwords + rid;
                r = radeon_ctx_reloc(ctx, state->bo[bid], cid,
                                        &state->placement[bid * 2]);
                if (r) {
-                       fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->type);
+                       fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->stype->stype);
                        return r;
                }
        }
-       ctx->id += state->cpm4;
+       ctx->cdwords += state->cpm4;
+       ctx->ndwords -= state->cpm4;
        return 0;
 }
 
 int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state)
 {
-       void *tmp;
        int r = 0;
 
        /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
-       if (state->type != R600_QUERY_BEGIN_TYPE && state->type != R600_QUERY_END_TYPE) {
-               return -EINVAL;
-       }
        r = radeon_state_pm4(state);
        if (r)
                return r;
-       if ((ctx->draw_cpm4 + state->cpm4) > RADEON_CTX_MAX_PM4) {
-               /* need to flush */
-               return -EBUSY;
-       }
-       if (state->cpm4 >= RADEON_CTX_MAX_PM4) {
-               fprintf(stderr, "%s single state too big %d, max %d\n",
-                       __func__, state->cpm4, RADEON_CTX_MAX_PM4);
-               return -EINVAL;
-       }
-       tmp = realloc(ctx->state, (ctx->nstate + 1) * sizeof(void*));
-       if (tmp == NULL)
-               return -ENOMEM;
-       ctx->state = tmp;
-       ctx->state[ctx->nstate++] = radeon_state_incref(state);
        /* BEGIN/END query are balanced in the same cs so account for END
         * END query when scheduling BEGIN query
         */
-       if (state->type == R600_QUERY_BEGIN_TYPE) {
-               ctx->draw_cpm4 += state->cpm4 * 2;
+       switch (state->stype->stype) {
+       case R600_STATE_QUERY_BEGIN:
+               /* is there enough place for begin & end */
+               if ((state->cpm4 * 2) > ctx->ndwords)
+                       return -EBUSY;
+               ctx->ndwords -= state->cpm4;
+               break;
+       case R600_STATE_QUERY_END:
+               ctx->ndwords += state->cpm4;
+               break;
+       default:
+               return -EINVAL;
        }
-       return 0;
+       return radeon_ctx_state_schedule(ctx, state);
 }
 
-int radeon_ctx_set_draw_new(struct radeon_ctx *ctx, struct radeon_draw *draw)
+int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
 {
-       struct radeon_draw *pdraw = NULL;
-       struct radeon_draw **ndraw;
-       struct radeon_state *nstate, *ostate;
-       unsigned cpm4, i, cstate;
-       void *tmp;
+       unsigned previous_cdwords;
        int r = 0;
 
-       ndraw = realloc(ctx->draw, sizeof(void*) * (ctx->ndraw + 1));
-       if (ndraw == NULL)
-               return -ENOMEM;
-       ctx->draw = ndraw;
-       for (i = 0; i < draw->nstate; i++) {
+       for (int i = 0; i < (ctx->radeon->nstate_per_shader * R600_SHADER_MAX); i++) {
                r = radeon_ctx_state_bo(ctx, draw->state[i]);
                if (r)
                        return r;
        }
-       r = radeon_draw_check(draw);
-       if (r)
-               return r;
-       if (draw->cpm4 >= RADEON_CTX_MAX_PM4) {
-               fprintf(stderr, "%s single draw too big %d, max %d\n",
-                       __func__, draw->cpm4, RADEON_CTX_MAX_PM4);
-               return -EINVAL;
-       }
-       tmp = realloc(ctx->state, (ctx->nstate + draw->nstate) * sizeof(void*));
-       if (tmp == NULL)
-               return -ENOMEM;
-       ctx->state = tmp;
-       pdraw = ctx->cdraw;
-       for (i = 0, cpm4 = 0, cstate = ctx->nstate; i < draw->nstate - 1; i++) {
-               nstate = draw->state[i];
-               if (nstate) {
-                       if (pdraw && pdraw->state[i]) {
-                               ostate = pdraw->state[i];
-                               if (ostate->pm4_crc != nstate->pm4_crc) {
-                                       ctx->state[cstate++] = nstate;
-                                       cpm4 += nstate->cpm4;
+       previous_cdwords = ctx->cdwords;
+       for (int i = 0, id = 0; i < ctx->radeon->nstate_per_shader; i++) {
+               for (int j = 0; j < R600_SHADER_MAX; j++) {
+                       id = j * ctx->radeon->nstate_per_shader + i;
+                       if (draw->state[id]) {
+                               r = radeon_ctx_state_schedule(ctx, draw->state[id]);
+                               if (r) {
+                                       ctx->cdwords = previous_cdwords;
+                                       return r;
                                }
-                       } else {
-                               ctx->state[cstate++] = nstate;
-                               cpm4 += nstate->cpm4;
                        }
                }
        }
-       /* The last state is the draw state always add it */
-       if (draw->state[i] == NULL) {
-               fprintf(stderr, "%s no draw command\n", __func__);
-               return -EINVAL;
-       }
-       ctx->state[cstate++] = draw->state[i];
-       cpm4 += draw->state[i]->cpm4;
-       if ((ctx->draw_cpm4 + cpm4) > RADEON_CTX_MAX_PM4) {
-               /* need to flush */
-               return -EBUSY;
-       }
-       ctx->draw_cpm4 += cpm4;
-       ctx->nstate = cstate;
-       ctx->draw[ctx->ndraw++] = draw;
-       ctx->cdraw = draw;
        return 0;
 }
 
-int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
-{
-       int r;
-
-       radeon_draw_incref(draw);
-       r = radeon_ctx_set_draw_new(ctx, draw);
-       if (r)
-               radeon_draw_decref(draw);
-       return r;
-}
-
+#if 0
 int radeon_ctx_pm4(struct radeon_ctx *ctx)
 {
        unsigned i;
@@ -345,9 +293,6 @@ int radeon_ctx_pm4(struct radeon_ctx *ctx)
        if (ctx->pm4 == NULL)
                return -EINVAL;
        for (i = 0, ctx->id = 0; i < ctx->nstate; i++) {
-               r = radeon_ctx_state_schedule(ctx, ctx->state[i]);
-               if (r)
-                       return r;
        }
        if (ctx->id != ctx->draw_cpm4) {
                fprintf(stderr, "%s miss predicted pm4 size %d for %d\n",
@@ -357,6 +302,7 @@ int radeon_ctx_pm4(struct radeon_ctx *ctx)
        ctx->cpm4 = ctx->draw_cpm4;
        return 0;
 }
+#endif
 
 void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file)
 {
@@ -384,8 +330,8 @@ printf("%d relocs\n", ctx->nreloc);
        bof_decref(blob);
        blob = NULL;
        /* dump cs */
-printf("%d pm4\n", ctx->cpm4);
-       blob = bof_blob(ctx->cpm4 * 4, ctx->pm4);
+printf("%d pm4\n", ctx->cdwords);
+       blob = bof_blob(ctx->cdwords * 4, ctx->pm4);
        if (blob == NULL)
                goto out_err;
        if (bof_object_set(root, "pm4", blob))