17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2017 Intel Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice shall be included
127ec681f3Smrg * in all copies or substantial portions of the Software.
137ec681f3Smrg *
147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
157ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
187ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
197ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
207ec681f3Smrg * DEALINGS IN THE SOFTWARE.
217ec681f3Smrg */
227ec681f3Smrg
237ec681f3Smrg/**
247ec681f3Smrg * @file crocus_resolve.c
257ec681f3Smrg *
267ec681f3Smrg * This file handles resolve tracking for main and auxiliary surfaces.
277ec681f3Smrg *
287ec681f3Smrg * It also handles our cache tracking.  We have sets for the render cache,
297ec681f3Smrg * depth cache, and so on.  If a BO is in a cache's set, then it may have
307ec681f3Smrg * data in that cache.  The helpers take care of emitting flushes for
317ec681f3Smrg * render-to-texture, format reinterpretation issues, and other situations.
327ec681f3Smrg */
337ec681f3Smrg
347ec681f3Smrg#include "util/hash_table.h"
357ec681f3Smrg#include "util/set.h"
367ec681f3Smrg#include "crocus_context.h"
377ec681f3Smrg#include "compiler/nir/nir.h"
387ec681f3Smrg
397ec681f3Smrg#define FILE_DEBUG_FLAG DEBUG_BLORP
407ec681f3Smrg
417ec681f3Smrgstatic void
427ec681f3Smrgcrocus_update_stencil_shadow(struct crocus_context *ice,
437ec681f3Smrg                             struct crocus_resource *res);
447ec681f3Smrg/**
457ec681f3Smrg * Disable auxiliary buffers if a renderbuffer is also bound as a texture
467ec681f3Smrg * or shader image.  This causes a self-dependency, where both rendering
477ec681f3Smrg * and sampling may concurrently read or write the CCS buffer, causing
487ec681f3Smrg * incorrect pixels.
497ec681f3Smrg */
507ec681f3Smrgstatic bool
517ec681f3Smrgdisable_rb_aux_buffer(struct crocus_context *ice,
527ec681f3Smrg                      bool *draw_aux_buffer_disabled,
537ec681f3Smrg                      struct crocus_resource *tex_res,
547ec681f3Smrg                      unsigned min_level, unsigned num_levels,
557ec681f3Smrg                      const char *usage)
567ec681f3Smrg{
577ec681f3Smrg   struct pipe_framebuffer_state *cso_fb = &ice->state.framebuffer;
587ec681f3Smrg   bool found = false;
597ec681f3Smrg
607ec681f3Smrg   /* We only need to worry about fast clears. */
617ec681f3Smrg   if (tex_res->aux.usage != ISL_AUX_USAGE_CCS_D)
627ec681f3Smrg      return false;
637ec681f3Smrg
647ec681f3Smrg   for (unsigned i = 0; i < cso_fb->nr_cbufs; i++) {
657ec681f3Smrg      struct crocus_surface *surf = (void *) cso_fb->cbufs[i];
667ec681f3Smrg      if (!surf)
677ec681f3Smrg         continue;
687ec681f3Smrg
697ec681f3Smrg      struct crocus_resource *rb_res = (void *) surf->base.texture;
707ec681f3Smrg
717ec681f3Smrg      if (rb_res->bo == tex_res->bo &&
727ec681f3Smrg          surf->base.u.tex.level >= min_level &&
737ec681f3Smrg          surf->base.u.tex.level < min_level + num_levels) {
747ec681f3Smrg         found = draw_aux_buffer_disabled[i] = true;
757ec681f3Smrg      }
767ec681f3Smrg   }
777ec681f3Smrg
787ec681f3Smrg   if (found) {
797ec681f3Smrg      perf_debug(&ice->dbg,
807ec681f3Smrg                 "Disabling CCS because a renderbuffer is also bound %s.\n",
817ec681f3Smrg                 usage);
827ec681f3Smrg   }
837ec681f3Smrg
847ec681f3Smrg   return found;
857ec681f3Smrg}
867ec681f3Smrg
877ec681f3Smrgstatic void
887ec681f3Smrgresolve_sampler_views(struct crocus_context *ice,
897ec681f3Smrg                      struct crocus_batch *batch,
907ec681f3Smrg                      struct crocus_shader_state *shs,
917ec681f3Smrg                      const struct shader_info *info,
927ec681f3Smrg                      bool *draw_aux_buffer_disabled,
937ec681f3Smrg                      bool consider_framebuffer)
947ec681f3Smrg{
957ec681f3Smrg   uint32_t views = info ? (shs->bound_sampler_views & info->textures_used[0]) : 0;
967ec681f3Smrg
977ec681f3Smrg   while (views) {
987ec681f3Smrg      const int i = u_bit_scan(&views);
997ec681f3Smrg      struct crocus_sampler_view *isv = shs->textures[i];
1007ec681f3Smrg
1017ec681f3Smrg      if (isv->res->base.b.target != PIPE_BUFFER) {
1027ec681f3Smrg         if (consider_framebuffer) {
1037ec681f3Smrg            disable_rb_aux_buffer(ice, draw_aux_buffer_disabled, isv->res,
1047ec681f3Smrg                                  isv->view.base_level, isv->view.levels,
1057ec681f3Smrg                                  "for sampling");
1067ec681f3Smrg         }
1077ec681f3Smrg
1087ec681f3Smrg         crocus_resource_prepare_texture(ice, isv->res, isv->view.format,
1097ec681f3Smrg                                         isv->view.base_level, isv->view.levels,
1107ec681f3Smrg                                         isv->view.base_array_layer,
1117ec681f3Smrg                                         isv->view.array_len);
1127ec681f3Smrg      }
1137ec681f3Smrg
1147ec681f3Smrg      crocus_cache_flush_for_read(batch, isv->res->bo);
1157ec681f3Smrg
1167ec681f3Smrg      if (batch->screen->devinfo.ver == 7 &&
1177ec681f3Smrg          (isv->base.format == PIPE_FORMAT_X24S8_UINT ||
1187ec681f3Smrg           isv->base.format == PIPE_FORMAT_X32_S8X24_UINT ||
1197ec681f3Smrg           isv->base.format == PIPE_FORMAT_S8_UINT)) {
1207ec681f3Smrg         struct crocus_resource *zres, *sres;
1217ec681f3Smrg         crocus_get_depth_stencil_resources(&batch->screen->devinfo, isv->base.texture, &zres, &sres);
1227ec681f3Smrg         crocus_update_stencil_shadow(ice, sres);
1237ec681f3Smrg         crocus_cache_flush_for_read(batch, sres->shadow->bo);
1247ec681f3Smrg      }
1257ec681f3Smrg   }
1267ec681f3Smrg}
1277ec681f3Smrg
1287ec681f3Smrgstatic void
1297ec681f3Smrgresolve_image_views(struct crocus_context *ice,
1307ec681f3Smrg                    struct crocus_batch *batch,
1317ec681f3Smrg                    struct crocus_shader_state *shs,
1327ec681f3Smrg                    bool *draw_aux_buffer_disabled,
1337ec681f3Smrg                    bool consider_framebuffer)
1347ec681f3Smrg{
1357ec681f3Smrg   /* TODO: Consider images used by program */
1367ec681f3Smrg   uint32_t views = shs->bound_image_views;
1377ec681f3Smrg
1387ec681f3Smrg   while (views) {
1397ec681f3Smrg      const int i = u_bit_scan(&views);
1407ec681f3Smrg      struct pipe_image_view *pview = &shs->image[i].base;
1417ec681f3Smrg      struct crocus_resource *res = (void *) pview->resource;
1427ec681f3Smrg
1437ec681f3Smrg      if (res->base.b.target != PIPE_BUFFER) {
1447ec681f3Smrg         if (consider_framebuffer) {
1457ec681f3Smrg            disable_rb_aux_buffer(ice, draw_aux_buffer_disabled,
1467ec681f3Smrg                                  res, pview->u.tex.level, 1,
1477ec681f3Smrg                                  "as a shader image");
1487ec681f3Smrg         }
1497ec681f3Smrg
1507ec681f3Smrg         unsigned num_layers =
1517ec681f3Smrg            pview->u.tex.last_layer - pview->u.tex.first_layer + 1;
1527ec681f3Smrg
1537ec681f3Smrg         /* The data port doesn't understand any compression */
1547ec681f3Smrg         crocus_resource_prepare_access(ice, res,
1557ec681f3Smrg                                        pview->u.tex.level, 1,
1567ec681f3Smrg                                        pview->u.tex.first_layer, num_layers,
1577ec681f3Smrg                                        ISL_AUX_USAGE_NONE, false);
1587ec681f3Smrg      }
1597ec681f3Smrg
1607ec681f3Smrg      crocus_cache_flush_for_read(batch, res->bo);
1617ec681f3Smrg   }
1627ec681f3Smrg}
1637ec681f3Smrg
1647ec681f3Smrgstatic void
1657ec681f3Smrgcrocus_update_align_res(struct crocus_batch *batch,
1667ec681f3Smrg                        struct crocus_surface *surf,
1677ec681f3Smrg                        bool copy_to_wa)
1687ec681f3Smrg{
1697ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen *)batch->screen;
1707ec681f3Smrg   struct pipe_blit_info info = { 0 };
1717ec681f3Smrg
1727ec681f3Smrg   info.src.resource = copy_to_wa ? surf->base.texture : surf->align_res;
1737ec681f3Smrg   info.src.level = copy_to_wa ? surf->base.u.tex.level : 0;
1747ec681f3Smrg   u_box_2d_zslice(0, 0, copy_to_wa ? surf->base.u.tex.first_layer : 0,
1757ec681f3Smrg                   u_minify(surf->base.texture->width0, surf->base.u.tex.level),
1767ec681f3Smrg                   u_minify(surf->base.texture->height0, surf->base.u.tex.level), &info.src.box);
1777ec681f3Smrg   info.src.format = surf->base.texture->format;
1787ec681f3Smrg   info.dst.resource = copy_to_wa ? surf->align_res : surf->base.texture;
1797ec681f3Smrg   info.dst.level = copy_to_wa ? 0 : surf->base.u.tex.level;
1807ec681f3Smrg   info.dst.box = info.src.box;
1817ec681f3Smrg   info.dst.box.z = copy_to_wa ? 0 : surf->base.u.tex.first_layer;
1827ec681f3Smrg   info.dst.format = surf->base.texture->format;
1837ec681f3Smrg   info.mask = util_format_is_depth_or_stencil(surf->base.texture->format) ? PIPE_MASK_ZS : PIPE_MASK_RGBA;
1847ec681f3Smrg   info.filter = 0;
1857ec681f3Smrg   if (!screen->vtbl.blit_blt(batch, &info)) {
1867ec681f3Smrg      assert(0);
1877ec681f3Smrg   }
1887ec681f3Smrg}
1897ec681f3Smrg
1907ec681f3Smrg/**
1917ec681f3Smrg * \brief Resolve buffers before drawing.
1927ec681f3Smrg *
1937ec681f3Smrg * Resolve the depth buffer's HiZ buffer, resolve the depth buffer of each
1947ec681f3Smrg * enabled depth texture, and flush the render cache for any dirty textures.
1957ec681f3Smrg */
1967ec681f3Smrgvoid
1977ec681f3Smrgcrocus_predraw_resolve_inputs(struct crocus_context *ice,
1987ec681f3Smrg                              struct crocus_batch *batch,
1997ec681f3Smrg                              bool *draw_aux_buffer_disabled,
2007ec681f3Smrg                              gl_shader_stage stage,
2017ec681f3Smrg                              bool consider_framebuffer)
2027ec681f3Smrg{
2037ec681f3Smrg   struct crocus_shader_state *shs = &ice->state.shaders[stage];
2047ec681f3Smrg   const struct shader_info *info = crocus_get_shader_info(ice, stage);
2057ec681f3Smrg
2067ec681f3Smrg   uint64_t stage_dirty = (CROCUS_STAGE_DIRTY_BINDINGS_VS << stage) |
2077ec681f3Smrg      (consider_framebuffer ? CROCUS_STAGE_DIRTY_BINDINGS_FS : 0);
2087ec681f3Smrg
2097ec681f3Smrg   if (ice->state.stage_dirty & stage_dirty) {
2107ec681f3Smrg      resolve_sampler_views(ice, batch, shs, info, draw_aux_buffer_disabled,
2117ec681f3Smrg                            consider_framebuffer);
2127ec681f3Smrg      resolve_image_views(ice, batch, shs, draw_aux_buffer_disabled,
2137ec681f3Smrg                          consider_framebuffer);
2147ec681f3Smrg   }
2157ec681f3Smrg}
2167ec681f3Smrg
2177ec681f3Smrgvoid
2187ec681f3Smrgcrocus_predraw_resolve_framebuffer(struct crocus_context *ice,
2197ec681f3Smrg                                   struct crocus_batch *batch,
2207ec681f3Smrg                                   bool *draw_aux_buffer_disabled)
2217ec681f3Smrg{
2227ec681f3Smrg   struct pipe_framebuffer_state *cso_fb = &ice->state.framebuffer;
2237ec681f3Smrg   struct crocus_screen *screen = (void *) ice->ctx.screen;
2247ec681f3Smrg   struct intel_device_info *devinfo = &screen->devinfo;
2257ec681f3Smrg   struct crocus_uncompiled_shader *ish =
2267ec681f3Smrg      ice->shaders.uncompiled[MESA_SHADER_FRAGMENT];
2277ec681f3Smrg   const nir_shader *nir = ish->nir;
2287ec681f3Smrg
2297ec681f3Smrg   if (ice->state.dirty & CROCUS_DIRTY_DEPTH_BUFFER) {
2307ec681f3Smrg      struct pipe_surface *zs_surf = cso_fb->zsbuf;
2317ec681f3Smrg
2327ec681f3Smrg      if (zs_surf) {
2337ec681f3Smrg         struct crocus_resource *z_res, *s_res;
2347ec681f3Smrg         crocus_get_depth_stencil_resources(devinfo, zs_surf->texture, &z_res, &s_res);
2357ec681f3Smrg         unsigned num_layers =
2367ec681f3Smrg            zs_surf->u.tex.last_layer - zs_surf->u.tex.first_layer + 1;
2377ec681f3Smrg
2387ec681f3Smrg         if (z_res) {
2397ec681f3Smrg            crocus_resource_prepare_render(ice, z_res,
2407ec681f3Smrg                                           zs_surf->u.tex.level,
2417ec681f3Smrg                                           zs_surf->u.tex.first_layer,
2427ec681f3Smrg                                           num_layers, ice->state.hiz_usage);
2437ec681f3Smrg            crocus_cache_flush_for_depth(batch, z_res->bo);
2447ec681f3Smrg
2457ec681f3Smrg            if (((struct crocus_surface *)zs_surf)->align_res) {
2467ec681f3Smrg               crocus_update_align_res(batch, (struct crocus_surface *)zs_surf, true);
2477ec681f3Smrg            }
2487ec681f3Smrg         }
2497ec681f3Smrg
2507ec681f3Smrg         if (s_res) {
2517ec681f3Smrg            crocus_cache_flush_for_depth(batch, s_res->bo);
2527ec681f3Smrg         }
2537ec681f3Smrg      }
2547ec681f3Smrg   }
2557ec681f3Smrg
2567ec681f3Smrg   if (nir->info.outputs_read != 0) {
2577ec681f3Smrg      for (unsigned i = 0; i < cso_fb->nr_cbufs; i++) {
2587ec681f3Smrg         if (cso_fb->cbufs[i]) {
2597ec681f3Smrg            struct crocus_surface *surf = (void *) cso_fb->cbufs[i];
2607ec681f3Smrg            struct crocus_resource *res = (void *) cso_fb->cbufs[i]->texture;
2617ec681f3Smrg
2627ec681f3Smrg            crocus_resource_prepare_texture(ice, res, surf->view.format,
2637ec681f3Smrg                                            surf->view.base_level, 1,
2647ec681f3Smrg                                            surf->view.base_array_layer,
2657ec681f3Smrg                                            surf->view.array_len);
2667ec681f3Smrg         }
2677ec681f3Smrg      }
2687ec681f3Smrg   }
2697ec681f3Smrg
2707ec681f3Smrg   if (ice->state.stage_dirty & CROCUS_STAGE_DIRTY_BINDINGS_FS) {
2717ec681f3Smrg      for (unsigned i = 0; i < cso_fb->nr_cbufs; i++) {
2727ec681f3Smrg         struct crocus_surface *surf = (void *) cso_fb->cbufs[i];
2737ec681f3Smrg         if (!surf)
2747ec681f3Smrg            continue;
2757ec681f3Smrg
2767ec681f3Smrg         struct crocus_resource *res = (void *) surf->base.texture;
2777ec681f3Smrg
2787ec681f3Smrg         if (surf->align_res)
2797ec681f3Smrg            crocus_update_align_res(batch, surf, true);
2807ec681f3Smrg
2817ec681f3Smrg         enum isl_aux_usage aux_usage =
2827ec681f3Smrg            crocus_resource_render_aux_usage(ice, res, surf->view.base_level,
2837ec681f3Smrg                                             surf->view.format,
2847ec681f3Smrg                                             draw_aux_buffer_disabled[i]);
2857ec681f3Smrg
2867ec681f3Smrg         if (ice->state.draw_aux_usage[i] != aux_usage) {
2877ec681f3Smrg            ice->state.draw_aux_usage[i] = aux_usage;
2887ec681f3Smrg            /* XXX: Need to track which bindings to make dirty */
2897ec681f3Smrg            ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_BINDINGS;
2907ec681f3Smrg         }
2917ec681f3Smrg
2927ec681f3Smrg         crocus_resource_prepare_render(ice, res, surf->view.base_level,
2937ec681f3Smrg                                        surf->view.base_array_layer,
2947ec681f3Smrg                                        surf->view.array_len,
2957ec681f3Smrg                                        aux_usage);
2967ec681f3Smrg
2977ec681f3Smrg         crocus_cache_flush_for_render(batch, res->bo, surf->view.format,
2987ec681f3Smrg                                       aux_usage);
2997ec681f3Smrg      }
3007ec681f3Smrg   }
3017ec681f3Smrg}
3027ec681f3Smrg
3037ec681f3Smrg/**
3047ec681f3Smrg * \brief Call this after drawing to mark which buffers need resolving
3057ec681f3Smrg *
3067ec681f3Smrg * If the depth buffer was written to and if it has an accompanying HiZ
3077ec681f3Smrg * buffer, then mark that it needs a depth resolve.
3087ec681f3Smrg *
3097ec681f3Smrg * If the color buffer is a multisample window system buffer, then
3107ec681f3Smrg * mark that it needs a downsample.
3117ec681f3Smrg *
3127ec681f3Smrg * Also mark any render targets which will be textured as needing a render
3137ec681f3Smrg * cache flush.
3147ec681f3Smrg */
3157ec681f3Smrgvoid
3167ec681f3Smrgcrocus_postdraw_update_resolve_tracking(struct crocus_context *ice,
3177ec681f3Smrg                                        struct crocus_batch *batch)
3187ec681f3Smrg{
3197ec681f3Smrg   struct pipe_framebuffer_state *cso_fb = &ice->state.framebuffer;
3207ec681f3Smrg   struct crocus_screen *screen = (void *) ice->ctx.screen;
3217ec681f3Smrg   struct intel_device_info *devinfo = &screen->devinfo;
3227ec681f3Smrg   // XXX: front buffer drawing?
3237ec681f3Smrg
3247ec681f3Smrg   bool may_have_resolved_depth =
3257ec681f3Smrg      ice->state.dirty & (CROCUS_DIRTY_DEPTH_BUFFER |
3267ec681f3Smrg                          CROCUS_DIRTY_GEN6_WM_DEPTH_STENCIL);
3277ec681f3Smrg
3287ec681f3Smrg   struct pipe_surface *zs_surf = cso_fb->zsbuf;
3297ec681f3Smrg   if (zs_surf) {
3307ec681f3Smrg      struct crocus_resource *z_res, *s_res;
3317ec681f3Smrg      crocus_get_depth_stencil_resources(devinfo, zs_surf->texture, &z_res, &s_res);
3327ec681f3Smrg      unsigned num_layers =
3337ec681f3Smrg         zs_surf->u.tex.last_layer - zs_surf->u.tex.first_layer + 1;
3347ec681f3Smrg
3357ec681f3Smrg      if (z_res) {
3367ec681f3Smrg         if (may_have_resolved_depth && ice->state.depth_writes_enabled) {
3377ec681f3Smrg            crocus_resource_finish_render(ice, z_res, zs_surf->u.tex.level,
3387ec681f3Smrg                                          zs_surf->u.tex.first_layer, num_layers,
3397ec681f3Smrg                                          ice->state.hiz_usage);
3407ec681f3Smrg         }
3417ec681f3Smrg
3427ec681f3Smrg         if (ice->state.depth_writes_enabled)
3437ec681f3Smrg            crocus_depth_cache_add_bo(batch, z_res->bo);
3447ec681f3Smrg
3457ec681f3Smrg         if (((struct crocus_surface *)zs_surf)->align_res) {
3467ec681f3Smrg            crocus_update_align_res(batch, (struct crocus_surface *)zs_surf, false);
3477ec681f3Smrg         }
3487ec681f3Smrg      }
3497ec681f3Smrg
3507ec681f3Smrg      if (s_res) {
3517ec681f3Smrg         if (may_have_resolved_depth && ice->state.stencil_writes_enabled) {
3527ec681f3Smrg            crocus_resource_finish_write(ice, s_res, zs_surf->u.tex.level,
3537ec681f3Smrg                                         zs_surf->u.tex.first_layer, num_layers,
3547ec681f3Smrg                                         s_res->aux.usage);
3557ec681f3Smrg         }
3567ec681f3Smrg
3577ec681f3Smrg         if (ice->state.stencil_writes_enabled)
3587ec681f3Smrg            crocus_depth_cache_add_bo(batch, s_res->bo);
3597ec681f3Smrg      }
3607ec681f3Smrg   }
3617ec681f3Smrg
3627ec681f3Smrg   bool may_have_resolved_color =
3637ec681f3Smrg      ice->state.stage_dirty & CROCUS_STAGE_DIRTY_BINDINGS_FS;
3647ec681f3Smrg
3657ec681f3Smrg   for (unsigned i = 0; i < cso_fb->nr_cbufs; i++) {
3667ec681f3Smrg      struct crocus_surface *surf = (void *) cso_fb->cbufs[i];
3677ec681f3Smrg      if (!surf)
3687ec681f3Smrg         continue;
3697ec681f3Smrg
3707ec681f3Smrg      if (surf->align_res)
3717ec681f3Smrg         crocus_update_align_res(batch, surf, false);
3727ec681f3Smrg      struct crocus_resource *res = (void *) surf->base.texture;
3737ec681f3Smrg      enum isl_aux_usage aux_usage = ice->state.draw_aux_usage[i];
3747ec681f3Smrg
3757ec681f3Smrg      crocus_render_cache_add_bo(batch, res->bo, surf->view.format,
3767ec681f3Smrg                                 aux_usage);
3777ec681f3Smrg
3787ec681f3Smrg      if (may_have_resolved_color) {
3797ec681f3Smrg         union pipe_surface_desc *desc = &surf->base.u;
3807ec681f3Smrg         unsigned num_layers =
3817ec681f3Smrg            desc->tex.last_layer - desc->tex.first_layer + 1;
3827ec681f3Smrg         crocus_resource_finish_render(ice, res, desc->tex.level,
3837ec681f3Smrg                                       desc->tex.first_layer, num_layers,
3847ec681f3Smrg                                       aux_usage);
3857ec681f3Smrg      }
3867ec681f3Smrg   }
3877ec681f3Smrg}
3887ec681f3Smrg
3897ec681f3Smrg/**
3907ec681f3Smrg * Clear the cache-tracking sets.
3917ec681f3Smrg */
3927ec681f3Smrgvoid
3937ec681f3Smrgcrocus_cache_sets_clear(struct crocus_batch *batch)
3947ec681f3Smrg{
3957ec681f3Smrg   hash_table_foreach(batch->cache.render, render_entry)
3967ec681f3Smrg      _mesa_hash_table_remove(batch->cache.render, render_entry);
3977ec681f3Smrg
3987ec681f3Smrg   set_foreach(batch->cache.depth, depth_entry)
3997ec681f3Smrg      _mesa_set_remove(batch->cache.depth, depth_entry);
4007ec681f3Smrg}
4017ec681f3Smrg
4027ec681f3Smrg/**
4037ec681f3Smrg * Emits an appropriate flush for a BO if it has been rendered to within the
4047ec681f3Smrg * same batchbuffer as a read that's about to be emitted.
4057ec681f3Smrg *
4067ec681f3Smrg * The GPU has separate, incoherent caches for the render cache and the
4077ec681f3Smrg * sampler cache, along with other caches.  Usually data in the different
4087ec681f3Smrg * caches don't interact (e.g. we don't render to our driver-generated
4097ec681f3Smrg * immediate constant data), but for render-to-texture in FBOs we definitely
4107ec681f3Smrg * do.  When a batchbuffer is flushed, the kernel will ensure that everything
4117ec681f3Smrg * necessary is flushed before another use of that BO, but for reuse from
4127ec681f3Smrg * different caches within a batchbuffer, it's all our responsibility.
4137ec681f3Smrg */
4147ec681f3Smrgvoid
4157ec681f3Smrgcrocus_flush_depth_and_render_caches(struct crocus_batch *batch)
4167ec681f3Smrg{
4177ec681f3Smrg   const struct intel_device_info *devinfo = &batch->screen->devinfo;
4187ec681f3Smrg   if (devinfo->ver >= 6) {
4197ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
4207ec681f3Smrg                                     "cache tracker: render-to-texture",
4217ec681f3Smrg                                     PIPE_CONTROL_DEPTH_CACHE_FLUSH |
4227ec681f3Smrg                                     PIPE_CONTROL_RENDER_TARGET_FLUSH |
4237ec681f3Smrg                                     PIPE_CONTROL_CS_STALL);
4247ec681f3Smrg
4257ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
4267ec681f3Smrg                                     "cache tracker: render-to-texture",
4277ec681f3Smrg                                     PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
4287ec681f3Smrg                                     PIPE_CONTROL_CONST_CACHE_INVALIDATE);
4297ec681f3Smrg   } else {
4307ec681f3Smrg      crocus_emit_mi_flush(batch);
4317ec681f3Smrg   }
4327ec681f3Smrg
4337ec681f3Smrg   crocus_cache_sets_clear(batch);
4347ec681f3Smrg}
4357ec681f3Smrg
4367ec681f3Smrgvoid
4377ec681f3Smrgcrocus_cache_flush_for_read(struct crocus_batch *batch,
4387ec681f3Smrg                            struct crocus_bo *bo)
4397ec681f3Smrg{
4407ec681f3Smrg   if (_mesa_hash_table_search_pre_hashed(batch->cache.render, bo->hash, bo) ||
4417ec681f3Smrg       _mesa_set_search_pre_hashed(batch->cache.depth, bo->hash, bo))
4427ec681f3Smrg      crocus_flush_depth_and_render_caches(batch);
4437ec681f3Smrg}
4447ec681f3Smrg
4457ec681f3Smrgstatic void *
4467ec681f3Smrgformat_aux_tuple(enum isl_format format, enum isl_aux_usage aux_usage)
4477ec681f3Smrg{
4487ec681f3Smrg   return (void *)(uintptr_t)((uint32_t)format << 8 | aux_usage);
4497ec681f3Smrg}
4507ec681f3Smrg
4517ec681f3Smrgvoid
4527ec681f3Smrgcrocus_cache_flush_for_render(struct crocus_batch *batch,
4537ec681f3Smrg                              struct crocus_bo *bo,
4547ec681f3Smrg                              enum isl_format format,
4557ec681f3Smrg                              enum isl_aux_usage aux_usage)
4567ec681f3Smrg{
4577ec681f3Smrg   if (_mesa_set_search_pre_hashed(batch->cache.depth, bo->hash, bo))
4587ec681f3Smrg      crocus_flush_depth_and_render_caches(batch);
4597ec681f3Smrg
4607ec681f3Smrg   /* Check to see if this bo has been used by a previous rendering operation
4617ec681f3Smrg    * but with a different format or aux usage.  If it has, flush the render
4627ec681f3Smrg    * cache so we ensure that it's only in there with one format or aux usage
4637ec681f3Smrg    * at a time.
4647ec681f3Smrg    *
4657ec681f3Smrg    * Even though it's not obvious, this can easily happen in practice.
4667ec681f3Smrg    * Suppose a client is blending on a surface with sRGB encode enabled on
4677ec681f3Smrg    * gen9.  This implies that you get AUX_USAGE_CCS_D at best.  If the client
4687ec681f3Smrg    * then disables sRGB decode and continues blending we will flip on
4697ec681f3Smrg    * AUX_USAGE_CCS_E without doing any sort of resolve in-between (this is
4707ec681f3Smrg    * perfectly valid since CCS_E is a subset of CCS_D).  However, this means
4717ec681f3Smrg    * that we have fragments in-flight which are rendering with UNORM+CCS_E
4727ec681f3Smrg    * and other fragments in-flight with SRGB+CCS_D on the same surface at the
4737ec681f3Smrg    * same time and the pixel scoreboard and color blender are trying to sort
4747ec681f3Smrg    * it all out.  This ends badly (i.e. GPU hangs).
4757ec681f3Smrg    *
4767ec681f3Smrg    * To date, we have never observed GPU hangs or even corruption to be
4777ec681f3Smrg    * associated with switching the format, only the aux usage.  However,
4787ec681f3Smrg    * there are comments in various docs which indicate that the render cache
4797ec681f3Smrg    * isn't 100% resilient to format changes.  We may as well be conservative
4807ec681f3Smrg    * and flush on format changes too.  We can always relax this later if we
4817ec681f3Smrg    * find it to be a performance problem.
4827ec681f3Smrg    */
4837ec681f3Smrg   struct hash_entry *entry =
4847ec681f3Smrg      _mesa_hash_table_search_pre_hashed(batch->cache.render, bo->hash, bo);
4857ec681f3Smrg   if (entry && entry->data != format_aux_tuple(format, aux_usage))
4867ec681f3Smrg      crocus_flush_depth_and_render_caches(batch);
4877ec681f3Smrg}
4887ec681f3Smrg
4897ec681f3Smrgvoid
4907ec681f3Smrgcrocus_render_cache_add_bo(struct crocus_batch *batch,
4917ec681f3Smrg                           struct crocus_bo *bo,
4927ec681f3Smrg                           enum isl_format format,
4937ec681f3Smrg                           enum isl_aux_usage aux_usage)
4947ec681f3Smrg{
4957ec681f3Smrg#ifndef NDEBUG
4967ec681f3Smrg   struct hash_entry *entry =
4977ec681f3Smrg      _mesa_hash_table_search_pre_hashed(batch->cache.render, bo->hash, bo);
4987ec681f3Smrg   if (entry) {
4997ec681f3Smrg      /* Otherwise, someone didn't do a flush_for_render and that would be
5007ec681f3Smrg       * very bad indeed.
5017ec681f3Smrg       */
5027ec681f3Smrg      assert(entry->data == format_aux_tuple(format, aux_usage));
5037ec681f3Smrg   }
5047ec681f3Smrg#endif
5057ec681f3Smrg
5067ec681f3Smrg   _mesa_hash_table_insert_pre_hashed(batch->cache.render, bo->hash, bo,
5077ec681f3Smrg                                      format_aux_tuple(format, aux_usage));
5087ec681f3Smrg}
5097ec681f3Smrg
5107ec681f3Smrgvoid
5117ec681f3Smrgcrocus_cache_flush_for_depth(struct crocus_batch *batch,
5127ec681f3Smrg                             struct crocus_bo *bo)
5137ec681f3Smrg{
5147ec681f3Smrg   if (_mesa_hash_table_search_pre_hashed(batch->cache.render, bo->hash, bo))
5157ec681f3Smrg      crocus_flush_depth_and_render_caches(batch);
5167ec681f3Smrg}
5177ec681f3Smrg
5187ec681f3Smrgvoid
5197ec681f3Smrgcrocus_depth_cache_add_bo(struct crocus_batch *batch, struct crocus_bo *bo)
5207ec681f3Smrg{
5217ec681f3Smrg   _mesa_set_add_pre_hashed(batch->cache.depth, bo->hash, bo);
5227ec681f3Smrg}
5237ec681f3Smrg
5247ec681f3Smrgstatic void
5257ec681f3Smrgcrocus_resolve_color(struct crocus_context *ice,
5267ec681f3Smrg                     struct crocus_batch *batch,
5277ec681f3Smrg                     struct crocus_resource *res,
5287ec681f3Smrg                     unsigned level, unsigned layer,
5297ec681f3Smrg                     enum isl_aux_op resolve_op)
5307ec681f3Smrg{
5317ec681f3Smrg   struct crocus_screen *screen = batch->screen;
5327ec681f3Smrg   DBG("%s to res %p level %u layer %u\n", __func__, res, level, layer);
5337ec681f3Smrg
5347ec681f3Smrg   struct blorp_surf surf;
5357ec681f3Smrg   crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev, &surf,
5367ec681f3Smrg                                  &res->base.b, res->aux.usage, level, true);
5377ec681f3Smrg
5387ec681f3Smrg   crocus_batch_maybe_flush(batch, 1500);
5397ec681f3Smrg
5407ec681f3Smrg   /* Ivybridge PRM Vol 2, Part 1, "11.7 MCS Buffer for Render Target(s)":
5417ec681f3Smrg    *
5427ec681f3Smrg    *    "Any transition from any value in {Clear, Render, Resolve} to a
5437ec681f3Smrg    *     different value in {Clear, Render, Resolve} requires end of pipe
5447ec681f3Smrg    *     synchronization."
5457ec681f3Smrg    *
5467ec681f3Smrg    * In other words, fast clear ops are not properly synchronized with
5477ec681f3Smrg    * other drawing.  We need to use a PIPE_CONTROL to ensure that the
5487ec681f3Smrg    * contents of the previous draw hit the render target before we resolve
5497ec681f3Smrg    * and again afterwards to ensure that the resolve is complete before we
5507ec681f3Smrg    * do any more regular drawing.
5517ec681f3Smrg    */
5527ec681f3Smrg   crocus_emit_end_of_pipe_sync(batch, "color resolve: pre-flush",
5537ec681f3Smrg                                PIPE_CONTROL_RENDER_TARGET_FLUSH);
5547ec681f3Smrg
5557ec681f3Smrg   struct blorp_batch blorp_batch;
5567ec681f3Smrg   blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
5577ec681f3Smrg   blorp_ccs_resolve(&blorp_batch, &surf, level, layer, 1,
5587ec681f3Smrg                     isl_format_srgb_to_linear(res->surf.format),
5597ec681f3Smrg                     resolve_op);
5607ec681f3Smrg   blorp_batch_finish(&blorp_batch);
5617ec681f3Smrg
5627ec681f3Smrg   /* See comment above */
5637ec681f3Smrg   crocus_emit_end_of_pipe_sync(batch, "color resolve: post-flush",
5647ec681f3Smrg                                PIPE_CONTROL_RENDER_TARGET_FLUSH);
5657ec681f3Smrg}
5667ec681f3Smrg
5677ec681f3Smrgstatic void
5687ec681f3Smrgcrocus_mcs_partial_resolve(struct crocus_context *ice,
5697ec681f3Smrg                           struct crocus_batch *batch,
5707ec681f3Smrg                           struct crocus_resource *res,
5717ec681f3Smrg                           uint32_t start_layer,
5727ec681f3Smrg                           uint32_t num_layers)
5737ec681f3Smrg{
5747ec681f3Smrg   struct crocus_screen *screen = batch->screen;
5757ec681f3Smrg
5767ec681f3Smrg   DBG("%s to res %p layers %u-%u\n", __func__, res,
5777ec681f3Smrg       start_layer, start_layer + num_layers - 1);
5787ec681f3Smrg
5797ec681f3Smrg   assert(isl_aux_usage_has_mcs(res->aux.usage));
5807ec681f3Smrg
5817ec681f3Smrg   struct blorp_surf surf;
5827ec681f3Smrg   crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev, &surf,
5837ec681f3Smrg                                  &res->base.b, res->aux.usage, 0, true);
5847ec681f3Smrg
5857ec681f3Smrg   struct blorp_batch blorp_batch;
5867ec681f3Smrg   blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
5877ec681f3Smrg   blorp_mcs_partial_resolve(&blorp_batch, &surf,
5887ec681f3Smrg                             isl_format_srgb_to_linear(res->surf.format),
5897ec681f3Smrg                             start_layer, num_layers);
5907ec681f3Smrg   blorp_batch_finish(&blorp_batch);
5917ec681f3Smrg}
5927ec681f3Smrg
5937ec681f3Smrg/**
5947ec681f3Smrg * Perform a HiZ or depth resolve operation.
5957ec681f3Smrg *
5967ec681f3Smrg * For an overview of HiZ ops, see the following sections of the Sandy Bridge
5977ec681f3Smrg * PRM, Volume 1, Part 2:
5987ec681f3Smrg *   - 7.5.3.1 Depth Buffer Clear
5997ec681f3Smrg *   - 7.5.3.2 Depth Buffer Resolve
6007ec681f3Smrg *   - 7.5.3.3 Hierarchical Depth Buffer Resolve
6017ec681f3Smrg */
6027ec681f3Smrgvoid
6037ec681f3Smrgcrocus_hiz_exec(struct crocus_context *ice,
6047ec681f3Smrg                struct crocus_batch *batch,
6057ec681f3Smrg                struct crocus_resource *res,
6067ec681f3Smrg                unsigned int level, unsigned int start_layer,
6077ec681f3Smrg                unsigned int num_layers, enum isl_aux_op op,
6087ec681f3Smrg                bool update_clear_depth)
6097ec681f3Smrg{
6107ec681f3Smrg   struct crocus_screen *screen = batch->screen;
6117ec681f3Smrg   const struct intel_device_info *devinfo = &batch->screen->devinfo;
6127ec681f3Smrg   assert(crocus_resource_level_has_hiz(res, level));
6137ec681f3Smrg   assert(op != ISL_AUX_OP_NONE);
6147ec681f3Smrg   UNUSED const char *name = NULL;
6157ec681f3Smrg
6167ec681f3Smrg   switch (op) {
6177ec681f3Smrg   case ISL_AUX_OP_FULL_RESOLVE:
6187ec681f3Smrg      name = "depth resolve";
6197ec681f3Smrg      break;
6207ec681f3Smrg   case ISL_AUX_OP_AMBIGUATE:
6217ec681f3Smrg      name = "hiz ambiguate";
6227ec681f3Smrg      break;
6237ec681f3Smrg   case ISL_AUX_OP_FAST_CLEAR:
6247ec681f3Smrg      name = "depth clear";
6257ec681f3Smrg      break;
6267ec681f3Smrg   case ISL_AUX_OP_PARTIAL_RESOLVE:
6277ec681f3Smrg   case ISL_AUX_OP_NONE:
6287ec681f3Smrg      unreachable("Invalid HiZ op");
6297ec681f3Smrg   }
6307ec681f3Smrg
6317ec681f3Smrg   DBG("%s %s to res %p level %d layers %d-%d\n",
6327ec681f3Smrg       __func__, name, res, level, start_layer, start_layer + num_layers - 1);
6337ec681f3Smrg
6347ec681f3Smrg   /* The following stalls and flushes are only documented to be required
6357ec681f3Smrg    * for HiZ clear operations.  However, they also seem to be required for
6367ec681f3Smrg    * resolve operations.
6377ec681f3Smrg    *
6387ec681f3Smrg    * From the Ivybridge PRM, volume 2, "Depth Buffer Clear":
6397ec681f3Smrg    *
6407ec681f3Smrg    *   "If other rendering operations have preceded this clear, a
6417ec681f3Smrg    *    PIPE_CONTROL with depth cache flush enabled, Depth Stall bit
6427ec681f3Smrg    *    enabled must be issued before the rectangle primitive used for
6437ec681f3Smrg    *    the depth buffer clear operation."
6447ec681f3Smrg    *
6457ec681f3Smrg    * Same applies for Gen8 and Gen9.
6467ec681f3Smrg    *
6477ec681f3Smrg    * In addition, from the Ivybridge PRM, volume 2, 1.10.4.1
6487ec681f3Smrg    * PIPE_CONTROL, Depth Cache Flush Enable:
6497ec681f3Smrg    *
6507ec681f3Smrg    *   "This bit must not be set when Depth Stall Enable bit is set in
6517ec681f3Smrg    *    this packet."
6527ec681f3Smrg    *
6537ec681f3Smrg    * This is confirmed to hold for real, Haswell gets immediate gpu hangs.
6547ec681f3Smrg    *
6557ec681f3Smrg    * Therefore issue two pipe control flushes, one for cache flush and
6567ec681f3Smrg    * another for depth stall.
6577ec681f3Smrg    */
6587ec681f3Smrg   if (devinfo->ver == 6) {
6597ec681f3Smrg      /* From the Sandy Bridge PRM, volume 2 part 1, page 313:
6607ec681f3Smrg       *
6617ec681f3Smrg       *   "If other rendering operations have preceded this clear, a
6627ec681f3Smrg       *   PIPE_CONTROL with write cache flush enabled and Z-inhibit
6637ec681f3Smrg       *   disabled must be issued before the rectangle primitive used for
6647ec681f3Smrg       *   the depth buffer clear operation.
6657ec681f3Smrg       */
6667ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
6677ec681f3Smrg                                     "hiz op: pre-flushes (1)",
6687ec681f3Smrg                                     PIPE_CONTROL_RENDER_TARGET_FLUSH |
6697ec681f3Smrg                                     PIPE_CONTROL_DEPTH_CACHE_FLUSH |
6707ec681f3Smrg                                     PIPE_CONTROL_CS_STALL);
6717ec681f3Smrg   } else if (devinfo->ver >= 7) {
6727ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
6737ec681f3Smrg                                     "hiz op: pre-flushes (1/2)",
6747ec681f3Smrg                                     PIPE_CONTROL_DEPTH_CACHE_FLUSH |
6757ec681f3Smrg                                     PIPE_CONTROL_CS_STALL);
6767ec681f3Smrg      crocus_emit_pipe_control_flush(batch, "hiz op: pre-flushes (2/2)",
6777ec681f3Smrg                                     PIPE_CONTROL_DEPTH_STALL);
6787ec681f3Smrg   }
6797ec681f3Smrg
6807ec681f3Smrg   assert(isl_aux_usage_has_hiz(res->aux.usage) && res->aux.bo);
6817ec681f3Smrg
6827ec681f3Smrg   crocus_batch_maybe_flush(batch, 1500);
6837ec681f3Smrg
6847ec681f3Smrg   struct blorp_surf surf;
6857ec681f3Smrg   crocus_blorp_surf_for_resource(&screen->vtbl, &batch->screen->isl_dev, &surf,
6867ec681f3Smrg                                  &res->base.b, res->aux.usage, level, true);
6877ec681f3Smrg
6887ec681f3Smrg   struct blorp_batch blorp_batch;
6897ec681f3Smrg   enum blorp_batch_flags flags = 0;
6907ec681f3Smrg   flags |= update_clear_depth ? 0 : BLORP_BATCH_NO_UPDATE_CLEAR_COLOR;
6917ec681f3Smrg   blorp_batch_init(&ice->blorp, &blorp_batch, batch, flags);
6927ec681f3Smrg   blorp_hiz_op(&blorp_batch, &surf, level, start_layer, num_layers, op);
6937ec681f3Smrg   blorp_batch_finish(&blorp_batch);
6947ec681f3Smrg
6957ec681f3Smrg   /* The following stalls and flushes are only documented to be required
6967ec681f3Smrg    * for HiZ clear operations.  However, they also seem to be required for
6977ec681f3Smrg    * resolve operations.
6987ec681f3Smrg    *
6997ec681f3Smrg    * From the Broadwell PRM, volume 7, "Depth Buffer Clear":
7007ec681f3Smrg    *
7017ec681f3Smrg    *    "Depth buffer clear pass using any of the methods (WM_STATE,
7027ec681f3Smrg    *     3DSTATE_WM or 3DSTATE_WM_HZ_OP) must be followed by a
7037ec681f3Smrg    *     PIPE_CONTROL command with DEPTH_STALL bit and Depth FLUSH bits
7047ec681f3Smrg    *     "set" before starting to render.  DepthStall and DepthFlush are
7057ec681f3Smrg    *     not needed between consecutive depth clear passes nor is it
7067ec681f3Smrg    *     required if the depth clear pass was done with
7077ec681f3Smrg    *     'full_surf_clear' bit set in the 3DSTATE_WM_HZ_OP."
7087ec681f3Smrg    *
7097ec681f3Smrg    * TODO: Such as the spec says, this could be conditional.
7107ec681f3Smrg    */
7117ec681f3Smrg   if (devinfo->ver == 6) {
7127ec681f3Smrg      /* From the Sandy Bridge PRM, volume 2 part 1, page 314:
7137ec681f3Smrg       *
7147ec681f3Smrg       *     "DevSNB, DevSNB-B{W/A}]: Depth buffer clear pass must be
7157ec681f3Smrg       *     followed by a PIPE_CONTROL command with DEPTH_STALL bit set
7167ec681f3Smrg       *     and Then followed by Depth FLUSH'
7177ec681f3Smrg       */
7187ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
7197ec681f3Smrg                                     "hiz op: post-flushes (1/2)",
7207ec681f3Smrg                                     PIPE_CONTROL_DEPTH_STALL);
7217ec681f3Smrg
7227ec681f3Smrg      crocus_emit_pipe_control_flush(batch,
7237ec681f3Smrg                                     "hiz op: post-flushes (2/2)",
7247ec681f3Smrg                                     PIPE_CONTROL_DEPTH_CACHE_FLUSH |
7257ec681f3Smrg                                     PIPE_CONTROL_CS_STALL);
7267ec681f3Smrg   }
7277ec681f3Smrg}
7287ec681f3Smrg
7297ec681f3Smrg/**
7307ec681f3Smrg * Does the resource's slice have hiz enabled?
7317ec681f3Smrg */
7327ec681f3Smrgbool
7337ec681f3Smrgcrocus_resource_level_has_hiz(const struct crocus_resource *res, uint32_t level)
7347ec681f3Smrg{
7357ec681f3Smrg   crocus_resource_check_level_layer(res, level, 0);
7367ec681f3Smrg   return res->aux.has_hiz & 1 << level;
7377ec681f3Smrg}
7387ec681f3Smrg
7397ec681f3Smrgstatic bool
7407ec681f3Smrgcrocus_resource_level_has_aux(const struct crocus_resource *res, uint32_t level)
7417ec681f3Smrg{
7427ec681f3Smrg   if (isl_aux_usage_has_hiz(res->aux.usage))
7437ec681f3Smrg      return crocus_resource_level_has_hiz(res, level);
7447ec681f3Smrg   else
7457ec681f3Smrg      return level < res->aux.surf.levels;
7467ec681f3Smrg}
7477ec681f3Smrg
7487ec681f3Smrg/** \brief Assert that the level and layer are valid for the resource. */
7497ec681f3Smrgvoid
7507ec681f3Smrgcrocus_resource_check_level_layer(UNUSED const struct crocus_resource *res,
7517ec681f3Smrg                                  UNUSED uint32_t level, UNUSED uint32_t layer)
7527ec681f3Smrg{
7537ec681f3Smrg   assert(level < res->surf.levels);
7547ec681f3Smrg   assert(layer < util_num_layers(&res->base.b, level));
7557ec681f3Smrg}
7567ec681f3Smrg
7577ec681f3Smrgstatic inline uint32_t
7587ec681f3Smrgmiptree_level_range_length(const struct crocus_resource *res,
7597ec681f3Smrg                           uint32_t start_level, uint32_t num_levels)
7607ec681f3Smrg{
7617ec681f3Smrg   assert(start_level < res->surf.levels);
7627ec681f3Smrg
7637ec681f3Smrg   if (num_levels == INTEL_REMAINING_LAYERS)
7647ec681f3Smrg      num_levels = res->surf.levels;
7657ec681f3Smrg
7667ec681f3Smrg   /* Check for overflow */
7677ec681f3Smrg   assert(start_level + num_levels >= start_level);
7687ec681f3Smrg   assert(start_level + num_levels <= res->surf.levels);
7697ec681f3Smrg
7707ec681f3Smrg   return num_levels;
7717ec681f3Smrg}
7727ec681f3Smrg
7737ec681f3Smrgstatic inline uint32_t
7747ec681f3Smrgmiptree_layer_range_length(const struct crocus_resource *res, uint32_t level,
7757ec681f3Smrg                           uint32_t start_layer, uint32_t num_layers)
7767ec681f3Smrg{
7777ec681f3Smrg   assert(level <= res->base.b.last_level);
7787ec681f3Smrg
7797ec681f3Smrg   const uint32_t total_num_layers = crocus_get_num_logical_layers(res, level);
7807ec681f3Smrg   assert(start_layer < total_num_layers);
7817ec681f3Smrg   if (num_layers == INTEL_REMAINING_LAYERS)
7827ec681f3Smrg      num_layers = total_num_layers - start_layer;
7837ec681f3Smrg   /* Check for overflow */
7847ec681f3Smrg   assert(start_layer + num_layers >= start_layer);
7857ec681f3Smrg   assert(start_layer + num_layers <= total_num_layers);
7867ec681f3Smrg
7877ec681f3Smrg   return num_layers;
7887ec681f3Smrg}
7897ec681f3Smrg
7907ec681f3Smrgbool
7917ec681f3Smrgcrocus_has_invalid_primary(const struct crocus_resource *res,
7927ec681f3Smrg                           unsigned start_level, unsigned num_levels,
7937ec681f3Smrg                           unsigned start_layer, unsigned num_layers)
7947ec681f3Smrg{
7957ec681f3Smrg   if (!res->aux.bo)
7967ec681f3Smrg      return false;
7977ec681f3Smrg
7987ec681f3Smrg   /* Clamp the level range to fit the resource */
7997ec681f3Smrg   num_levels = miptree_level_range_length(res, start_level, num_levels);
8007ec681f3Smrg
8017ec681f3Smrg   for (uint32_t l = 0; l < num_levels; l++) {
8027ec681f3Smrg      const uint32_t level = start_level + l;
8037ec681f3Smrg      if (!crocus_resource_level_has_aux(res, level))
8047ec681f3Smrg         continue;
8057ec681f3Smrg
8067ec681f3Smrg      const uint32_t level_layers =
8077ec681f3Smrg         miptree_layer_range_length(res, level, start_layer, num_layers);
8087ec681f3Smrg      for (unsigned a = 0; a < level_layers; a++) {
8097ec681f3Smrg         enum isl_aux_state aux_state =
8107ec681f3Smrg            crocus_resource_get_aux_state(res, level, start_layer + a);
8117ec681f3Smrg         if (!isl_aux_state_has_valid_primary(aux_state))
8127ec681f3Smrg            return true;
8137ec681f3Smrg      }
8147ec681f3Smrg   }
8157ec681f3Smrg
8167ec681f3Smrg   return false;
8177ec681f3Smrg}
8187ec681f3Smrg
8197ec681f3Smrgvoid
8207ec681f3Smrgcrocus_resource_prepare_access(struct crocus_context *ice,
8217ec681f3Smrg                               struct crocus_resource *res,
8227ec681f3Smrg                               uint32_t start_level, uint32_t num_levels,
8237ec681f3Smrg                               uint32_t start_layer, uint32_t num_layers,
8247ec681f3Smrg                               enum isl_aux_usage aux_usage,
8257ec681f3Smrg                               bool fast_clear_supported)
8267ec681f3Smrg{
8277ec681f3Smrg   if (!res->aux.bo)
8287ec681f3Smrg      return;
8297ec681f3Smrg
8307ec681f3Smrg   /* We can't do resolves on the compute engine, so awkwardly, we have to
8317ec681f3Smrg    * do them on the render batch...
8327ec681f3Smrg    */
8337ec681f3Smrg   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
8347ec681f3Smrg
8357ec681f3Smrg   const uint32_t clamped_levels =
8367ec681f3Smrg      miptree_level_range_length(res, start_level, num_levels);
8377ec681f3Smrg   for (uint32_t l = 0; l < clamped_levels; l++) {
8387ec681f3Smrg      const uint32_t level = start_level + l;
8397ec681f3Smrg      if (!crocus_resource_level_has_aux(res, level))
8407ec681f3Smrg         continue;
8417ec681f3Smrg
8427ec681f3Smrg      const uint32_t level_layers =
8437ec681f3Smrg         miptree_layer_range_length(res, level, start_layer, num_layers);
8447ec681f3Smrg      for (uint32_t a = 0; a < level_layers; a++) {
8457ec681f3Smrg         const uint32_t layer = start_layer + a;
8467ec681f3Smrg         const enum isl_aux_state aux_state =
8477ec681f3Smrg            crocus_resource_get_aux_state(res, level, layer);
8487ec681f3Smrg         const enum isl_aux_op aux_op =
8497ec681f3Smrg            isl_aux_prepare_access(aux_state, aux_usage, fast_clear_supported);
8507ec681f3Smrg
8517ec681f3Smrg         /* Prepare the aux buffer for a conditional or unconditional access.
8527ec681f3Smrg          * A conditional access is handled by assuming that the access will
8537ec681f3Smrg          * not evaluate to a no-op. If the access does in fact occur, the aux
8547ec681f3Smrg          * will be in the required state. If it does not, no data is lost
8557ec681f3Smrg          * because the aux_op performed is lossless.
8567ec681f3Smrg          */
8577ec681f3Smrg         if (aux_op == ISL_AUX_OP_NONE) {
8587ec681f3Smrg            /* Nothing to do here. */
8597ec681f3Smrg         } else if (isl_aux_usage_has_mcs(res->aux.usage)) {
8607ec681f3Smrg            assert(aux_op == ISL_AUX_OP_PARTIAL_RESOLVE);
8617ec681f3Smrg            crocus_mcs_partial_resolve(ice, batch, res, layer, 1);
8627ec681f3Smrg         } else if (isl_aux_usage_has_hiz(res->aux.usage)) {
8637ec681f3Smrg            crocus_hiz_exec(ice, batch, res, level, layer, 1, aux_op, false);
8647ec681f3Smrg         } else if (res->aux.usage == ISL_AUX_USAGE_STC_CCS) {
8657ec681f3Smrg            unreachable("crocus doesn't resolve STC_CCS resources");
8667ec681f3Smrg         } else {
8677ec681f3Smrg            assert(isl_aux_usage_has_ccs(res->aux.usage));
8687ec681f3Smrg            crocus_resolve_color(ice, batch, res, level, layer, aux_op);
8697ec681f3Smrg         }
8707ec681f3Smrg
8717ec681f3Smrg         const enum isl_aux_state new_state =
8727ec681f3Smrg            isl_aux_state_transition_aux_op(aux_state, res->aux.usage, aux_op);
8737ec681f3Smrg         crocus_resource_set_aux_state(ice, res, level, layer, 1, new_state);
8747ec681f3Smrg      }
8757ec681f3Smrg   }
8767ec681f3Smrg}
8777ec681f3Smrg
8787ec681f3Smrgvoid
8797ec681f3Smrgcrocus_resource_finish_write(struct crocus_context *ice,
8807ec681f3Smrg                             struct crocus_resource *res, uint32_t level,
8817ec681f3Smrg                             uint32_t start_layer, uint32_t num_layers,
8827ec681f3Smrg                             enum isl_aux_usage aux_usage)
8837ec681f3Smrg{
8847ec681f3Smrg   if (res->base.b.format == PIPE_FORMAT_S8_UINT)
8857ec681f3Smrg      res->shadow_needs_update = true;
8867ec681f3Smrg
8877ec681f3Smrg   if (!crocus_resource_level_has_aux(res, level))
8887ec681f3Smrg      return;
8897ec681f3Smrg
8907ec681f3Smrg   const uint32_t level_layers =
8917ec681f3Smrg      miptree_layer_range_length(res, level, start_layer, num_layers);
8927ec681f3Smrg
8937ec681f3Smrg   for (uint32_t a = 0; a < level_layers; a++) {
8947ec681f3Smrg      const uint32_t layer = start_layer + a;
8957ec681f3Smrg      const enum isl_aux_state aux_state =
8967ec681f3Smrg         crocus_resource_get_aux_state(res, level, layer);
8977ec681f3Smrg
8987ec681f3Smrg      /* Transition the aux state for a conditional or unconditional write. A
8997ec681f3Smrg       * conditional write is handled by assuming that the write applies to
9007ec681f3Smrg       * only part of the render target. This prevents the new state from
9017ec681f3Smrg       * losing the types of compression that might exist in the current state
9027ec681f3Smrg       * (e.g. CLEAR). If the write evaluates to a no-op, the state will still
9037ec681f3Smrg       * be able to communicate when resolves are necessary (but it may
9047ec681f3Smrg       * falsely communicate this as well).
9057ec681f3Smrg       */
9067ec681f3Smrg      const enum isl_aux_state new_aux_state =
9077ec681f3Smrg         isl_aux_state_transition_write(aux_state, aux_usage, false);
9087ec681f3Smrg
9097ec681f3Smrg      crocus_resource_set_aux_state(ice, res, level, layer, 1, new_aux_state);
9107ec681f3Smrg   }
9117ec681f3Smrg}
9127ec681f3Smrg
9137ec681f3Smrgenum isl_aux_state
9147ec681f3Smrgcrocus_resource_get_aux_state(const struct crocus_resource *res,
9157ec681f3Smrg                              uint32_t level, uint32_t layer)
9167ec681f3Smrg{
9177ec681f3Smrg   crocus_resource_check_level_layer(res, level, layer);
9187ec681f3Smrg   assert(crocus_resource_level_has_aux(res, level));
9197ec681f3Smrg
9207ec681f3Smrg   return res->aux.state[level][layer];
9217ec681f3Smrg}
9227ec681f3Smrg
9237ec681f3Smrgvoid
9247ec681f3Smrgcrocus_resource_set_aux_state(struct crocus_context *ice,
9257ec681f3Smrg                              struct crocus_resource *res, uint32_t level,
9267ec681f3Smrg                              uint32_t start_layer, uint32_t num_layers,
9277ec681f3Smrg                              enum isl_aux_state aux_state)
9287ec681f3Smrg{
9297ec681f3Smrg   assert(crocus_resource_level_has_aux(res, level));
9307ec681f3Smrg
9317ec681f3Smrg   num_layers = miptree_layer_range_length(res, level, start_layer, num_layers);
9327ec681f3Smrg   for (unsigned a = 0; a < num_layers; a++) {
9337ec681f3Smrg      if (res->aux.state[level][start_layer + a] != aux_state) {
9347ec681f3Smrg         res->aux.state[level][start_layer + a] = aux_state;
9357ec681f3Smrg         ice->state.dirty |= CROCUS_DIRTY_RENDER_RESOLVES_AND_FLUSHES |
9367ec681f3Smrg                             CROCUS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES;
9377ec681f3Smrg         /* XXX: Need to track which bindings to make dirty */
9387ec681f3Smrg         ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_BINDINGS;
9397ec681f3Smrg      }
9407ec681f3Smrg   }
9417ec681f3Smrg}
9427ec681f3Smrg
9437ec681f3Smrgstatic bool
9447ec681f3Smrgisl_formats_are_fast_clear_compatible(enum isl_format a, enum isl_format b)
9457ec681f3Smrg{
9467ec681f3Smrg   /* On gen8 and earlier, the hardware was only capable of handling 0/1 clear
9477ec681f3Smrg    * values so sRGB curve application was a no-op for all fast-clearable
9487ec681f3Smrg    * formats.
9497ec681f3Smrg    *
9507ec681f3Smrg    * On gen9+, the hardware supports arbitrary clear values.  For sRGB clear
9517ec681f3Smrg    * values, the hardware interprets the floats, not as what would be
9527ec681f3Smrg    * returned from the sampler (or written by the shader), but as being
9537ec681f3Smrg    * between format conversion and sRGB curve application.  This means that
9547ec681f3Smrg    * we can switch between sRGB and UNORM without having to whack the clear
9557ec681f3Smrg    * color.
9567ec681f3Smrg    */
9577ec681f3Smrg   return isl_format_srgb_to_linear(a) == isl_format_srgb_to_linear(b);
9587ec681f3Smrg}
9597ec681f3Smrg
9607ec681f3Smrgvoid
9617ec681f3Smrgcrocus_resource_prepare_texture(struct crocus_context *ice,
9627ec681f3Smrg                                struct crocus_resource *res,
9637ec681f3Smrg                                enum isl_format view_format,
9647ec681f3Smrg                                uint32_t start_level, uint32_t num_levels,
9657ec681f3Smrg                                uint32_t start_layer, uint32_t num_layers)
9667ec681f3Smrg{
9677ec681f3Smrg   enum isl_aux_usage aux_usage =
9687ec681f3Smrg      crocus_resource_texture_aux_usage(res);
9697ec681f3Smrg
9707ec681f3Smrg   bool clear_supported = aux_usage != ISL_AUX_USAGE_NONE;
9717ec681f3Smrg
9727ec681f3Smrg   /* Clear color is specified as ints or floats and the conversion is done by
9737ec681f3Smrg    * the sampler.  If we have a texture view, we would have to perform the
9747ec681f3Smrg    * clear color conversion manually.  Just disable clear color.
9757ec681f3Smrg    */
9767ec681f3Smrg   if (!isl_formats_are_fast_clear_compatible(res->surf.format, view_format))
9777ec681f3Smrg      clear_supported = false;
9787ec681f3Smrg
9797ec681f3Smrg   crocus_resource_prepare_access(ice, res, start_level, num_levels,
9807ec681f3Smrg                                  start_layer, num_layers,
9817ec681f3Smrg                                  aux_usage, clear_supported);
9827ec681f3Smrg}
9837ec681f3Smrg
9847ec681f3Smrgenum isl_aux_usage
9857ec681f3Smrgcrocus_resource_render_aux_usage(struct crocus_context *ice,
9867ec681f3Smrg                                 struct crocus_resource *res,
9877ec681f3Smrg                                 uint32_t level,
9887ec681f3Smrg                                 enum isl_format render_format,
9897ec681f3Smrg                                 bool draw_aux_disabled)
9907ec681f3Smrg{
9917ec681f3Smrg   struct crocus_screen *screen = (void *) ice->ctx.screen;
9927ec681f3Smrg   struct intel_device_info *devinfo = &screen->devinfo;
9937ec681f3Smrg
9947ec681f3Smrg   if (draw_aux_disabled)
9957ec681f3Smrg      return ISL_AUX_USAGE_NONE;
9967ec681f3Smrg
9977ec681f3Smrg   switch (res->aux.usage) {
9987ec681f3Smrg   case ISL_AUX_USAGE_MCS:
9997ec681f3Smrg      return res->aux.usage;
10007ec681f3Smrg
10017ec681f3Smrg   case ISL_AUX_USAGE_CCS_D:
10027ec681f3Smrg      /* Otherwise, we try to fall back to CCS_D */
10037ec681f3Smrg      if (isl_format_supports_ccs_d(devinfo, render_format))
10047ec681f3Smrg         return ISL_AUX_USAGE_CCS_D;
10057ec681f3Smrg
10067ec681f3Smrg      return ISL_AUX_USAGE_NONE;
10077ec681f3Smrg
10087ec681f3Smrg   case ISL_AUX_USAGE_HIZ:
10097ec681f3Smrg      assert(render_format == res->surf.format);
10107ec681f3Smrg      return crocus_resource_level_has_hiz(res, level) ?
10117ec681f3Smrg         res->aux.usage : ISL_AUX_USAGE_NONE;
10127ec681f3Smrg
10137ec681f3Smrg   default:
10147ec681f3Smrg      return ISL_AUX_USAGE_NONE;
10157ec681f3Smrg   }
10167ec681f3Smrg}
10177ec681f3Smrg
10187ec681f3Smrgvoid
10197ec681f3Smrgcrocus_resource_prepare_render(struct crocus_context *ice,
10207ec681f3Smrg                               struct crocus_resource *res, uint32_t level,
10217ec681f3Smrg                               uint32_t start_layer, uint32_t layer_count,
10227ec681f3Smrg                               enum isl_aux_usage aux_usage)
10237ec681f3Smrg{
10247ec681f3Smrg   crocus_resource_prepare_access(ice, res, level, 1, start_layer,
10257ec681f3Smrg                                  layer_count, aux_usage,
10267ec681f3Smrg                                  aux_usage != ISL_AUX_USAGE_NONE);
10277ec681f3Smrg}
10287ec681f3Smrg
10297ec681f3Smrgvoid
10307ec681f3Smrgcrocus_resource_finish_render(struct crocus_context *ice,
10317ec681f3Smrg                              struct crocus_resource *res, uint32_t level,
10327ec681f3Smrg                              uint32_t start_layer, uint32_t layer_count,
10337ec681f3Smrg                              enum isl_aux_usage aux_usage)
10347ec681f3Smrg{
10357ec681f3Smrg   crocus_resource_finish_write(ice, res, level, start_layer, layer_count,
10367ec681f3Smrg                                aux_usage);
10377ec681f3Smrg}
10387ec681f3Smrg
10397ec681f3Smrgstatic void
10407ec681f3Smrgcrocus_update_stencil_shadow(struct crocus_context *ice,
10417ec681f3Smrg                             struct crocus_resource *res)
10427ec681f3Smrg{
10437ec681f3Smrg   struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
10447ec681f3Smrg   UNUSED const struct intel_device_info *devinfo = &screen->devinfo;
10457ec681f3Smrg   assert(devinfo->ver == 7);
10467ec681f3Smrg
10477ec681f3Smrg   if (!res->shadow_needs_update)
10487ec681f3Smrg      return;
10497ec681f3Smrg
10507ec681f3Smrg   struct pipe_box box;
10517ec681f3Smrg   for (unsigned level = 0; level <= res->base.b.last_level; level++) {
10527ec681f3Smrg      u_box_2d(0, 0,
10537ec681f3Smrg               u_minify(res->base.b.width0, level),
10547ec681f3Smrg               u_minify(res->base.b.height0, level), &box);
10557ec681f3Smrg      const unsigned depth = res->base.b.target == PIPE_TEXTURE_3D ?
10567ec681f3Smrg         u_minify(res->base.b.depth0, level) : res->base.b.array_size;
10577ec681f3Smrg
10587ec681f3Smrg      for (unsigned layer = 0; layer < depth; layer++) {
10597ec681f3Smrg         box.z = layer;
10607ec681f3Smrg         ice->ctx.resource_copy_region(&ice->ctx,
10617ec681f3Smrg                                       &res->shadow->base.b, level, 0, 0, layer,
10627ec681f3Smrg                                       &res->base.b, level, &box);
10637ec681f3Smrg      }
10647ec681f3Smrg   }
10657ec681f3Smrg   res->shadow_needs_update = false;
10667ec681f3Smrg}
1067