etnaviv: fix memory leak when BO allocation fails
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_resource.c
index a8858c5a49e19ac1926598427a2bf0142c06d7a7..97e0a15597fa4b8a43ba185c6ec234dcb17190cc 100644 (file)
@@ -52,7 +52,8 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
 
    /* TS only for level 0 -- XXX is this formula correct? */
    pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format);
-   ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, 0x100);
+   ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80,
+                           0x100 * screen->specs.pixel_pipes);
    rt_ts_size = ts_layer_stride * rsc->base.array_size;
    if (rt_ts_size == 0)
       return true;
@@ -179,7 +180,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
                         &paddingY, &halign);
    assert(paddingX && paddingY);
 
-   if (templat->bind != PIPE_BUFFER) {
+   if (templat->target != PIPE_BUFFER) {
       unsigned min_paddingY = 4 * screen->specs.pixel_pipes;
       if (paddingY < min_paddingY)
          paddingY = min_paddingY;
@@ -201,10 +202,13 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
 
    size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
 
-   struct etna_bo *bo = etna_bo_new(screen->dev, size, DRM_ETNA_GEM_CACHE_WC);
+   uint32_t flags = DRM_ETNA_GEM_CACHE_WC;
+   if (templat->bind & PIPE_BIND_VERTEX_BUFFER)
+      flags |= DRM_ETNA_GEM_FORCE_MMU;
+   struct etna_bo *bo = etna_bo_new(screen->dev, size, flags);
    if (unlikely(bo == NULL)) {
       BUG("Problem allocating video memory for resource");
-      return NULL;
+      goto free_rsc;
    }
 
    rsc->bo = bo;
@@ -219,6 +223,10 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    }
 
    return &rsc->base;
+
+free_rsc:
+   FREE(rsc);
+   return NULL;
 }
 
 static struct pipe_resource *
@@ -227,12 +235,9 @@ etna_resource_create(struct pipe_screen *pscreen,
 {
    struct etna_screen *screen = etna_screen(pscreen);
 
-   /* Figure out what tiling to use -- for now, assume that textures cannot be
-    * supertiled, and cannot be linear.
-    * There is a feature flag SUPERTILED_TEXTURE (not supported on any known hw)
-    * that may allow this, as well
-    * as LINEAR_TEXTURE_SUPPORT (supported on gc880 and gc2000 at least), but
-    * not sure how it works.
+   /* Figure out what tiling to use -- for now, assume that texture cannot be linear.
+    * there is a capability LINEAR_TEXTURE_SUPPORT (supported on gc880 and
+    * gc2000 at least), but not sure how it works.
     * Buffers always have LINEAR layout.
     */
    unsigned layout = ETNA_LAYOUT_LINEAR;
@@ -245,8 +250,14 @@ etna_resource_create(struct pipe_screen *pscreen,
       if (util_format_is_compressed(templat->format))
          layout = ETNA_LAYOUT_LINEAR;
    } else if (templat->target != PIPE_BUFFER) {
-      bool want_multitiled = screen->specs.pixel_pipes > 1;
-      bool want_supertiled = screen->specs.can_supertile && !DBG_ENABLED(ETNA_DBG_NO_SUPERTILE);
+      bool want_multitiled = false;
+      bool want_supertiled = screen->specs.can_supertile;
+
+      /* When this GPU supports single-buffer rendering, don't ever enable
+       * multi-tiling. This replicates the blob behavior on GC3000.
+       */
+      if (!screen->specs.single_buffer)
+         want_multitiled = screen->specs.pixel_pipes > 1;
 
       /* Keep single byte blocksized resources as tiled, since we
        * are unable to use the RS blit to de-tile them. However,
@@ -274,6 +285,14 @@ etna_resource_create(struct pipe_screen *pscreen,
    return etna_resource_alloc(pscreen, layout, templat);
 }
 
+static void
+etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
+{
+   struct etna_resource *res = etna_resource(prsc);
+
+   res->seqno++;
+}
+
 static void
 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
 {
@@ -286,7 +305,7 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
       etna_bo_del(rsc->ts_bo);
 
    if (rsc->scanout)
-      renderonly_scanout_destroy(rsc->scanout);
+      renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
 
    list_delinit(&rsc->list);
 
@@ -337,6 +356,8 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
 
    level->padded_width = align(level->width, paddingX);
    level->padded_height = align(level->height, paddingY);
+   level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format,
+                                                                  level->padded_height);
 
    /* The DDX must give us a BO which conforms to our padding size.
     * The stride of the BO must be greater or equal to our padded
@@ -386,7 +407,8 @@ etna_resource_get_handle(struct pipe_screen *pscreen,
 {
    struct etna_resource *rsc = etna_resource(prsc);
 
-   if (renderonly_get_handle(rsc->scanout, handle))
+   if (handle->type == DRM_API_HANDLE_TYPE_KMS &&
+       renderonly_get_handle(rsc->scanout, handle))
       return TRUE;
 
    return etna_screen_bo_get_handle(pscreen, rsc->bo, rsc->levels[0].stride,
@@ -413,22 +435,6 @@ etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
    rsc->pending_ctx = ctx;
 }
 
-void
-etna_resource_wait(struct pipe_context *pctx, struct etna_resource *rsc)
-{
-   if (rsc->status & ETNA_PENDING_WRITE) {
-      struct pipe_fence_handle *fence;
-      struct pipe_screen *pscreen = pctx->screen;
-
-      pctx->flush(pctx, &fence, 0);
-
-      if (!pscreen->fence_finish(pscreen, pctx, fence, 5000000000ULL))
-         BUG("fence timed out (hung GPU?)");
-
-      pscreen->fence_reference(pscreen, &fence, NULL);
-   }
-}
-
 void
 etna_resource_screen_init(struct pipe_screen *pscreen)
 {
@@ -436,5 +442,6 @@ etna_resource_screen_init(struct pipe_screen *pscreen)
    pscreen->resource_create = etna_resource_create;
    pscreen->resource_from_handle = etna_resource_from_handle;
    pscreen->resource_get_handle = etna_resource_get_handle;
+   pscreen->resource_changed = etna_resource_changed;
    pscreen->resource_destroy = etna_resource_destroy;
 }