swr: avoid using exceptions for expected condition handling
[mesa.git] / src / gallium / drivers / swr / swr_state.cpp
index e9ae786164afc8904f36357d8e3d7dfa4f3fda57..b0cbc21964ed33f9307c18c9ddfa421633df6471 100644 (file)
@@ -717,25 +717,46 @@ swr_update_texture_state(struct swr_context *ctx,
    for (unsigned i = 0; i < num_sampler_views; i++) {
       struct pipe_sampler_view *view =
          ctx->sampler_views[shader_type][i];
+      struct swr_jit_texture *jit_tex = &textures[i];
 
+      memset(jit_tex, 0, sizeof(*jit_tex));
       if (view) {
          struct pipe_resource *res = view->texture;
          struct swr_resource *swr_res = swr_resource(res);
-         struct swr_jit_texture *jit_tex = &textures[i];
-         memset(jit_tex, 0, sizeof(*jit_tex));
+         SWR_SURFACE_STATE *swr = &swr_res->swr;
+         size_t *mip_offsets = swr_res->mip_offsets;
+         if (swr_res->has_depth && swr_res->has_stencil &&
+            !util_format_has_depth(util_format_description(view->format))) {
+            swr = &swr_res->secondary;
+            mip_offsets = swr_res->secondary_mip_offsets;
+         }
+
          jit_tex->width = res->width0;
          jit_tex->height = res->height0;
-         jit_tex->depth = res->depth0;
-         jit_tex->first_level = view->u.tex.first_level;
-         jit_tex->last_level = view->u.tex.last_level;
-         jit_tex->base_ptr = swr_res->swr.pBaseAddress;
+         jit_tex->base_ptr = swr->pBaseAddress;
+         if (view->target != PIPE_BUFFER) {
+            jit_tex->first_level = view->u.tex.first_level;
+            jit_tex->last_level = view->u.tex.last_level;
+            if (view->target == PIPE_TEXTURE_3D)
+               jit_tex->depth = res->depth0;
+            else
+               jit_tex->depth =
+                  view->u.tex.last_layer - view->u.tex.first_layer + 1;
+            jit_tex->base_ptr += view->u.tex.first_layer *
+               swr->qpitch * swr->pitch;
+         } else {
+            unsigned view_blocksize = util_format_get_blocksize(view->format);
+            jit_tex->base_ptr += view->u.buf.offset;
+            jit_tex->width = view->u.buf.size / view_blocksize;
+            jit_tex->depth = 1;
+         }
 
          for (unsigned level = jit_tex->first_level;
               level <= jit_tex->last_level;
               level++) {
-            jit_tex->row_stride[level] = swr_res->row_stride[level];
-            jit_tex->img_stride[level] = swr_res->img_stride[level];
-            jit_tex->mip_offsets[level] = swr_res->mip_offsets[level];
+            jit_tex->row_stride[level] = swr->pitch;
+            jit_tex->img_stride[level] = swr->qpitch * swr->pitch;
+            jit_tex->mip_offsets[level] = mip_offsets[level];
          }
       }
    }
@@ -805,6 +826,61 @@ swr_update_constants(struct swr_context *ctx, enum pipe_shader_type shaderType)
    }
 }
 
+static bool
+swr_change_rt(struct swr_context *ctx,
+              unsigned attachment,
+              const struct pipe_surface *sf)
+{
+   swr_draw_context *pDC = &ctx->swrDC;
+   struct SWR_SURFACE_STATE *rt = &pDC->renderTargets[attachment];
+
+   /* Do nothing if the render target hasn't changed */
+   if ((!sf || !sf->texture) && rt->pBaseAddress == nullptr)
+      return false;
+
+   /* Deal with disabling RT up front */
+   if (!sf || !sf->texture) {
+      /* If detaching attachment, mark tiles as RESOLVED so core
+       * won't try to load from non-existent target. */
+      swr_store_render_target(&ctx->pipe, attachment, SWR_TILE_RESOLVED);
+      *rt = {0};
+      return true;
+   }
+
+   const struct swr_resource *swr = swr_resource(sf->texture);
+   const SWR_SURFACE_STATE *swr_surface = &swr->swr;
+   SWR_FORMAT fmt = mesa_to_swr_format(sf->format);
+
+   if (attachment == SWR_ATTACHMENT_STENCIL && swr->secondary.pBaseAddress) {
+      swr_surface = &swr->secondary;
+      fmt = swr_surface->format;
+   }
+
+   if (rt->pBaseAddress == swr_surface->pBaseAddress &&
+       rt->format == fmt &&
+       rt->lod == sf->u.tex.level &&
+       rt->arrayIndex == sf->u.tex.first_layer)
+      return false;
+
+   bool need_fence = false;
+
+   /* StoreTile for changed target */
+   if (rt->pBaseAddress) {
+      /* If changing attachment to a new target, mark tiles as
+       * INVALID so they are reloaded from surface. */
+      swr_store_render_target(&ctx->pipe, attachment, SWR_TILE_INVALID);
+      need_fence = true;
+   }
+
+   /* Make new attachment */
+   *rt = *swr_surface;
+   rt->format = fmt;
+   rt->lod = sf->u.tex.level;
+   rt->arrayIndex = sf->u.tex.first_layer;
+
+   return need_fence;
+}
+
 void
 swr_update_derived(struct pipe_context *pipe,
                    const struct pipe_draw_info *p_draw_info)
@@ -823,64 +899,30 @@ swr_update_derived(struct pipe_context *pipe,
    /* Render Targets */
    if (ctx->dirty & SWR_NEW_FRAMEBUFFER) {
       struct pipe_framebuffer_state *fb = &ctx->framebuffer;
-      SWR_SURFACE_STATE *new_attachment[SWR_NUM_ATTACHMENTS] = {0};
-      UINT i;
+      const struct util_format_description *desc = NULL;
+      bool need_fence = false;
 
       /* colorbuffer targets */
-      if (fb->nr_cbufs)
-         for (i = 0; i < fb->nr_cbufs; ++i)
-            if (fb->cbufs[i]) {
-               struct swr_resource *colorBuffer =
-                  swr_resource(fb->cbufs[i]->texture);
-               new_attachment[SWR_ATTACHMENT_COLOR0 + i] = &colorBuffer->swr;
-            }
-
-      /* depth/stencil target */
-      if (fb->zsbuf) {
-         struct swr_resource *depthStencilBuffer =
-            swr_resource(fb->zsbuf->texture);
-         if (depthStencilBuffer->has_depth) {
-            new_attachment[SWR_ATTACHMENT_DEPTH] = &depthStencilBuffer->swr;
-
-            if (depthStencilBuffer->has_stencil)
-               new_attachment[SWR_ATTACHMENT_STENCIL] =
-                  &depthStencilBuffer->secondary;
-
-         } else if (depthStencilBuffer->has_stencil)
-            new_attachment[SWR_ATTACHMENT_STENCIL] = &depthStencilBuffer->swr;
+      if (fb->nr_cbufs) {
+         for (unsigned i = 0; i < fb->nr_cbufs; ++i)
+            need_fence |= swr_change_rt(
+                  ctx, SWR_ATTACHMENT_COLOR0 + i, fb->cbufs[i]);
       }
+      for (unsigned i = fb->nr_cbufs; i < SWR_NUM_RENDERTARGETS; ++i)
+         need_fence |= swr_change_rt(ctx, SWR_ATTACHMENT_COLOR0 + i, NULL);
 
-      /* Make the attachment updates */
-      swr_draw_context *pDC = &ctx->swrDC;
-      SWR_SURFACE_STATE *renderTargets = pDC->renderTargets;
-      unsigned need_fence = FALSE;
-      for (i = 0; i < SWR_NUM_ATTACHMENTS; i++) {
-         void *new_base = nullptr;
-         if (new_attachment[i])
-            new_base = new_attachment[i]->pBaseAddress;
-
-         /* StoreTile for changed target */
-         if (renderTargets[i].pBaseAddress != new_base) {
-            if (renderTargets[i].pBaseAddress) {
-               /* If changing attachment to a new target, mark tiles as
-                * INVALID so they are reloaded from surface.
-                * If detaching attachment, mark tiles as RESOLVED so core
-                * won't try to load from non-existent target. */
-               enum SWR_TILE_STATE post_state = (new_attachment[i]
-                  ? SWR_TILE_INVALID : SWR_TILE_RESOLVED);
-               swr_store_render_target(pipe, i, post_state);
-
-               need_fence |= TRUE;
-            }
+      /* depth/stencil target */
+      if (fb->zsbuf)
+         desc = util_format_description(fb->zsbuf->format);
+      if (fb->zsbuf && util_format_has_depth(desc))
+         need_fence |= swr_change_rt(ctx, SWR_ATTACHMENT_DEPTH, fb->zsbuf);
+      else
+         need_fence |= swr_change_rt(ctx, SWR_ATTACHMENT_DEPTH, NULL);
 
-            /* Make new attachment */
-            if (new_attachment[i])
-               renderTargets[i] = *new_attachment[i];
-            else
-               if (renderTargets[i].pBaseAddress)
-                  renderTargets[i] = {0};
-         }
-      }
+      if (fb->zsbuf && util_format_has_stencil(desc))
+         need_fence |= swr_change_rt(ctx, SWR_ATTACHMENT_STENCIL, fb->zsbuf);
+      else
+         need_fence |= swr_change_rt(ctx, SWR_ATTACHMENT_STENCIL, NULL);
 
       /* This fence ensures any attachment changes are resolved before the
        * next draw */
@@ -976,9 +1018,9 @@ swr_update_derived(struct pipe_context *pipe,
       SWR_VIEWPORT_MATRICES *vpm = &ctx->derived.vpm;
 
       vp->x = state->translate[0] - state->scale[0];
-      vp->width = state->translate[0] + state->scale[0];
+      vp->width = 2 * state->scale[0];
       vp->y = state->translate[1] - fabs(state->scale[1]);
-      vp->height = state->translate[1] + fabs(state->scale[1]);
+      vp->height = 2 * fabs(state->scale[1]);
       util_viewport_zmin_zmax(state, rasterizer->clip_halfz,
                               &vp->minZ, &vp->maxZ);
 
@@ -991,10 +1033,16 @@ swr_update_derived(struct pipe_context *pipe,
 
       /* Now that the matrix is calculated, clip the view coords to screen
        * size.  OpenGL allows for -ve x,y in the viewport. */
-      vp->x = std::max(vp->x, 0.0f);
-      vp->y = std::max(vp->y, 0.0f);
-      vp->width = std::min(vp->width, (float)fb->width);
-      vp->height = std::min(vp->height, (float)fb->height);
+      if (vp->x < 0.0f) {
+         vp->width += vp->x;
+         vp->x = 0.0f;
+      }
+      if (vp->y < 0.0f) {
+         vp->height += vp->y;
+         vp->y = 0.0f;
+      }
+      vp->width = std::min(vp->width, (float)fb->width - vp->x);
+      vp->height = std::min(vp->height, (float)fb->height - vp->y);
 
       SwrSetViewports(ctx->swrContext, 1, vp, vpm);
    }
@@ -1002,14 +1050,39 @@ swr_update_derived(struct pipe_context *pipe,
    /* Set vertex & index buffers */
    /* (using draw info if called by swr_draw_vbo) */
    if (ctx->dirty & SWR_NEW_VERTEX) {
-      uint32_t size, pitch, max_vertex, partial_inbounds;
+      uint32_t size, pitch, max_vertex, partial_inbounds, scratch_total;
       const uint8_t *p_data;
+      uint8_t *scratch = NULL;
 
       /* If being called by swr_draw_vbo, copy draw details */
       struct pipe_draw_info info = {0};
       if (p_draw_info)
          info = *p_draw_info;
 
+      /* We must get all the scratch space in one go */
+      scratch_total = 0;
+      for (UINT i = 0; i < ctx->num_vertex_buffers; i++) {
+         struct pipe_vertex_buffer *vb = &ctx->vertex_buffer[i];
+
+         if (!vb->user_buffer)
+            continue;
+
+         if (vb->stride) {
+            size = (info.max_index - info.min_index + 1) * vb->stride;
+         } else {
+            /* pitch = 0, means constant value
+             * set size to 1 vertex */
+            size = ctx->velems->stream_pitch[i];
+         }
+
+         scratch_total += AlignUp(size, 4);
+      }
+
+      if (scratch_total) {
+         scratch = (uint8_t *)swr_copy_to_scratch_space(
+               ctx, &ctx->scratch->vertex_buffer, NULL, scratch_total);
+      }
+
       /* vertex buffers */
       SWR_VERTEX_BUFFER_STATE swrVertexBuffers[PIPE_MAX_ATTRIBS];
       for (UINT i = 0; i < ctx->num_vertex_buffers; i++) {
@@ -1046,8 +1119,9 @@ swr_update_derived(struct pipe_context *pipe,
             size = AlignUp(size, 4);
             const void *ptr = (const uint8_t *) vb->user_buffer
                + info.min_index * pitch;
-            ptr = swr_copy_to_scratch_space(
-               ctx, &ctx->scratch->vertex_buffer, ptr, size);
+            memcpy(scratch, ptr, size);
+            ptr = scratch;
+            scratch += size;
             p_data = (const uint8_t *)ptr - info.min_index * pitch;
          }