예제 #1
0
static void basic_cache_init(void *vedata)
{
  BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
  BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;

  const DRWContextState *draw_ctx = DRW_context_state_get();
  BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];

  if (!stl->g_data) {
    /* Alloc transient pointers */
    stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
  }

  {
    psl->depth_pass = DRW_pass_create("Depth Pass",
                                      DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
    stl->g_data->depth_shgrp = DRW_shgroup_create(sh_data->depth, psl->depth_pass);
    if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
      DRW_shgroup_state_enable(stl->g_data->depth_shgrp, DRW_STATE_CLIP_PLANES);
    }

    psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull",
                                           DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
                                               DRW_STATE_CULL_BACK);
    stl->g_data->depth_shgrp_cull = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull);
    if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
      DRW_shgroup_state_enable(stl->g_data->depth_shgrp_cull, DRW_STATE_CLIP_PLANES);
    }
  }
}
예제 #2
0
/* Here init all passes and shading groups
 * Assume that all Passes are NULL */
static void EDIT_TEXT_cache_init(void *vedata)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
  EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;

  if (!stl->g_data) {
    /* Alloc transient pointers */
    stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
  }

  {
    /* Text outline (fast drawing!) */
    psl->wire_pass = DRW_pass_create(
        "Font Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
    stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);

    psl->overlay_select_pass = DRW_pass_create("Font Select",
                                               DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
    stl->g_data->overlay_select_shgrp = DRW_shgroup_create(e_data.overlay_select_sh,
                                                           psl->overlay_select_pass);

    psl->overlay_cursor_pass = DRW_pass_create("Font Cursor",
                                               DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
    stl->g_data->overlay_cursor_shgrp = DRW_shgroup_create(e_data.overlay_cursor_sh,
                                                           psl->overlay_cursor_pass);

    psl->text_box_pass = DRW_pass_create("Font Text Boxes",
                                         DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
    stl->g_data->box_shgrp = buffer_dynlines_dashed_uniform_color(
        psl->text_box_pass, G_draw.block.colorWire, draw_ctx->sh_cfg);
    stl->g_data->box_active_shgrp = buffer_dynlines_dashed_uniform_color(
        psl->text_box_pass, G_draw.block.colorActive, draw_ctx->sh_cfg);
  }
}
예제 #3
0
/* Add geometry to shadingGroups. Execute for each objects */
static void EDIT_TEXT_cache_populate(void *vedata, Object *ob)
{
  EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
  EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
  const DRWContextState *draw_ctx = DRW_context_state_get();

  UNUSED_VARS(psl, stl);

  if (ob->type == OB_FONT) {
    if (ob == draw_ctx->object_edit) {
      const Curve *cu = ob->data;
      /* Get geometry cache */
      struct GPUBatch *geom;

      bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
      if ((cu->flag & CU_FAST) || !has_surface) {
        geom = DRW_cache_text_edge_wire_get(ob);
        if (geom) {
          DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob);
        }
      }
      else {
        /* object mode draws */
      }

      edit_text_cache_populate_select(vedata, ob);
      edit_text_cache_populate_cursor(vedata, ob);
      edit_text_cache_populate_boxes(vedata, ob);
    }
  }
}
예제 #4
0
int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
  EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
  EEVEE_FramebufferList *fbl = vedata->fbl;
  EEVEE_StorageList *stl = vedata->stl;
  EEVEE_EffectsInfo *effects = stl->effects;

  const DRWContextState *draw_ctx = DRW_context_state_get();
  const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);

  if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
    const float *viewport_size = DRW_viewport_size_get();
    const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]};

    /* Shaders */
    if (!e_data.gtao_sh) {
      eevee_create_shader_occlusion();
    }

    common_data->ao_dist = scene_eval->eevee.gtao_distance;
    common_data->ao_factor = scene_eval->eevee.gtao_factor;
    common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality;

    common_data->ao_settings = 1.0f; /* USE_AO */
    if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BENT_NORMALS) {
      common_data->ao_settings += 2.0f; /* USE_BENT_NORMAL */
    }
    if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BOUNCE) {
      common_data->ao_settings += 4.0f; /* USE_DENOISE */
    }

    common_data->ao_bounce_fac = (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BOUNCE) ? 1.0f : 0.0f;

    effects->gtao_horizons = DRW_texture_pool_query_2d(
        fs_size[0], fs_size[1], GPU_RGBA8, &draw_engine_eevee_type);
    GPU_framebuffer_ensure_config(
        &fbl->gtao_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons)});

    if (G.debug_value == 6) {
      effects->gtao_horizons_debug = DRW_texture_pool_query_2d(
          fs_size[0], fs_size[1], GPU_RGBA8, &draw_engine_eevee_type);
      GPU_framebuffer_ensure_config(
          &fbl->gtao_debug_fb,
          {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons_debug)});
    }
    else {
      effects->gtao_horizons_debug = NULL;
    }

    return EFFECT_GTAO | EFFECT_NORMAL_BUFFER;
  }

  /* Cleanup */
  effects->gtao_horizons = NULL;
  GPU_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb);
  common_data->ao_settings = 0.0f;

  return 0;
}
예제 #5
0
void DRW_draw_region_info(void)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  ARegion *ar = draw_ctx->ar;

  DRW_draw_cursor();

  view3d_draw_region_info(draw_ctx->evil_C, ar);
}
예제 #6
0
static void basic_engine_init(void *UNUSED(vedata))
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];

  /* Depth prepass */
  if (!sh_data->depth) {
    sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg);
  }
}
예제 #7
0
static void basic_cache_populate(void *vedata, Object *ob)
{
  BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;

  /* TODO(fclem) fix selection of smoke domains. */

  if (!DRW_object_is_renderable(ob) || (ob->dt < OB_SOLID)) {
    return;
  }

  const DRWContextState *draw_ctx = DRW_context_state_get();
  if (ob != draw_ctx->object_edit) {
    for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
      if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
        continue;
      }
      ParticleSettings *part = psys->part;
      const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
      if (draw_as == PART_DRAW_PATH) {
        struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
        DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL);
      }
    }
  }

  /* Make flat object selectable in ortho view if wireframe is enabled. */
  if ((draw_ctx->v3d->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
      (draw_ctx->v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) {
    int flat_axis = 0;
    bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
                                            DRW_object_is_flat(ob, &flat_axis) &&
                                            DRW_object_axis_orthogonal_to_view(ob, flat_axis));

    if (is_flat_object_viewed_from_side) {
      /* Avoid losing flat objects when in ortho views (see T56549) */
      struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob);
      if (geom) {
        DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
      }
      return;
    }
  }

  struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
  if (geom) {
    const bool do_cull = (draw_ctx->v3d &&
                          (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
    /* Depth Prepass */
    DRW_shgroup_call(
        (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob);
  }
}
예제 #8
0
void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
  EEVEE_FramebufferList *fbl = vedata->fbl;
  EEVEE_TextureList *txl = vedata->txl;
  EEVEE_StorageList *stl = vedata->stl;
  EEVEE_PassList *psl = vedata->psl;
  EEVEE_EffectsInfo *effects = stl->effects;

  const DRWContextState *draw_ctx = DRW_context_state_get();
  const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);

  if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
    DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
    float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};

    DRW_texture_ensure_fullscreen_2d(
        &txl->ao_accum, GPU_R32F, 0); /* Should be enough precision for many samples. */

    GPU_framebuffer_ensure_config(&fbl->ao_accum_fb,
                                  {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)});

    /* Clear texture. */
    GPU_framebuffer_bind(fbl->ao_accum_fb);
    GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);

    /* Accumulation pass */
    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE;
    psl->ao_accum_ps = DRW_pass_create("AO Accum", state);
    DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_accum_ps);
    DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
    DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
    DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
    DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
    DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
    DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
    DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
  }
  else {
    /* Cleanup to release memory */
    DRW_TEXTURE_FREE_SAFE(txl->ao_accum);
    GPU_FRAMEBUFFER_FREE_SAFE(fbl->ao_accum_fb);
  }
}
예제 #9
0
/* verify if exist a non instanced version of the object */
static bool gpencil_has_noninstanced_object(Object *ob_instance)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  const ViewLayer *view_layer = draw_ctx->view_layer;
  Object *ob = NULL;
  for (Base *base = view_layer->object_bases.first; base; base = base->next) {
    ob = base->object;
    if (ob->type != OB_GPENCIL) {
      continue;
    }
    /* object must be visible (invisible objects don't create VBO data) */
    if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
      continue;
    }
    /* is not duplicated and the name is equals */
    if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
      if (STREQ(ob->id.name, ob_instance->id.name)) {
        return true;
      }
    }
  }

  return false;
}
예제 #10
0
void DRW_draw_cursor(void)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  ARegion *ar = draw_ctx->ar;
  Scene *scene = draw_ctx->scene;
  ViewLayer *view_layer = draw_ctx->view_layer;

  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  glDepthMask(GL_FALSE);
  glDisable(GL_DEPTH_TEST);

  if (is_cursor_visible(draw_ctx, scene, view_layer)) {
    int co[2];

    /* Get cursor data into quaternion form */
    const View3DCursor *cursor = &scene->cursor;

    if (ED_view3d_project_int_global(
            ar, cursor->location, co, V3D_PROJ_TEST_NOP | V3D_PROJ_TEST_CLIP_NEAR) ==
        V3D_PROJ_RET_OK) {
      RegionView3D *rv3d = ar->regiondata;

      float cursor_quat[4];
      BKE_scene_cursor_rot_to_quat(cursor, cursor_quat);

      /* Draw nice Anti Aliased cursor. */
      GPU_line_width(1.0f);
      GPU_blend(true);
      GPU_line_smooth(true);

      float eps = 1e-5f;
      rv3d->viewquat[0] = -rv3d->viewquat[0];
      bool is_aligned = compare_v4v4(cursor_quat, rv3d->viewquat, eps);
      if (is_aligned == false) {
        float tquat[4];
        rotation_between_quats_to_quat(tquat, rv3d->viewquat, cursor_quat);
        is_aligned = tquat[0] - eps < -1.0f;
      }
      rv3d->viewquat[0] = -rv3d->viewquat[0];

      /* Draw lines */
      if (is_aligned == false) {
        uint pos = GPU_vertformat_attr_add(
            immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
        immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
        immUniformThemeColor3(TH_VIEW_OVERLAY);
        immBegin(GPU_PRIM_LINES, 12);

        const float scale = ED_view3d_pixel_size_no_ui_scale(rv3d, cursor->location) *
                            U.widget_unit;

#define CURSOR_VERT(axis_vec, axis, fac) \
  immVertex3f(pos, \
              cursor->location[0] + axis_vec[0] * (fac), \
              cursor->location[1] + axis_vec[1] * (fac), \
              cursor->location[2] + axis_vec[2] * (fac))

#define CURSOR_EDGE(axis_vec, axis, sign) \
  { \
    CURSOR_VERT(axis_vec, axis, sign 1.0f); \
    CURSOR_VERT(axis_vec, axis, sign 0.25f); \
  } \
  ((void)0)

        for (int axis = 0; axis < 3; axis++) {
          float axis_vec[3] = {0};
          axis_vec[axis] = scale;
          mul_qt_v3(cursor_quat, axis_vec);
          CURSOR_EDGE(axis_vec, axis, +);
          CURSOR_EDGE(axis_vec, axis, -);
        }

#undef CURSOR_VERT
#undef CURSOR_EDGE

        immEnd();
        immUnbindProgram();
      }

      float original_proj[4][4];
      GPU_matrix_projection_get(original_proj);
      GPU_matrix_push();
      ED_region_pixelspace(ar);
      GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f);
      GPU_matrix_scale_2f(U.widget_unit, U.widget_unit);

      GPUBatch *cursor_batch = DRW_cache_cursor_get(is_aligned);
      GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR);
      GPU_batch_program_set(
          cursor_batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader));

      GPU_batch_draw(cursor_batch);

      GPU_blend(false);
      GPU_line_smooth(false);
      GPU_matrix_pop();
      GPU_matrix_projection_set(original_proj);
    }
예제 #11
0
/* add a gpencil object to cache to defer drawing */
tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array,
                                              Object *ob,
                                              int *gp_cache_size,
                                              int *gp_cache_used)
{
  const DRWContextState *draw_ctx = DRW_context_state_get();
  tGPencilObjectCache *cache_elem = NULL;
  RegionView3D *rv3d = draw_ctx->rv3d;
  View3D *v3d = draw_ctx->v3d;
  tGPencilObjectCache *p = NULL;

  /* By default a cache is created with one block with a predefined number of free slots,
   * if the size is not enough, the cache is reallocated adding a new block of free slots.
   * This is done in order to keep cache small. */
  if (*gp_cache_used + 1 > *gp_cache_size) {
    if ((*gp_cache_size == 0) || (cache_array == NULL)) {
      p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE,
                      "tGPencilObjectCache");
      *gp_cache_size = GP_CACHE_BLOCK_SIZE;
    }
    else {
      *gp_cache_size += GP_CACHE_BLOCK_SIZE;
      p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
    }
    cache_array = p;
  }
  /* zero out all pointers */
  cache_elem = &cache_array[*gp_cache_used];
  memset(cache_elem, 0, sizeof(*cache_elem));

  cache_elem->ob = ob;
  cache_elem->gpd = (bGPdata *)ob->data;
  cache_elem->name = BKE_id_to_unique_string_key(&ob->id);

  copy_v3_v3(cache_elem->loc, ob->obmat[3]);
  copy_m4_m4(cache_elem->obmat, ob->obmat);
  cache_elem->idx = *gp_cache_used;

  /* object is duplicated (particle) */
  if (ob->base_flag & BASE_FROM_DUPLI) {
    /* Check if the original object is not in the viewlayer
     * and cannot be managed as dupli. This is slower, but required to keep
     * the particle drawing FPS and display instanced objects in scene
     * without the original object */
    bool has_original = gpencil_has_noninstanced_object(ob);
    cache_elem->is_dup_ob = (has_original) ? ob->base_flag & BASE_FROM_DUPLI : false;
  }
  else {
    cache_elem->is_dup_ob = false;
  }

  cache_elem->scale = mat4_to_scale(ob->obmat);

  /* save FXs */
  cache_elem->pixfactor = cache_elem->gpd->pixfactor;
  cache_elem->shader_fx = ob->shader_fx;

  /* save wire mode (object mode is always primary option) */
  if (ob->dt == OB_WIRE) {
    cache_elem->shading_type[0] = (int)OB_WIRE;
  }
  else {
    if (v3d) {
      cache_elem->shading_type[0] = (int)v3d->shading.type;
    }
  }

  /* shgrp array */
  cache_elem->tot_layers = 0;
  int totgpl = BLI_listbase_count(&cache_elem->gpd->layers);
  if (totgpl > 0) {
    cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__);
  }

  /* calculate zdepth from point of view */
  float zdepth = 0.0;
  if (rv3d) {
    if (rv3d->is_persp) {
      zdepth = ED_view3d_calc_zfac(rv3d, ob->obmat[3], NULL);
    }
    else {
      zdepth = -dot_v3v3(rv3d->viewinv[2], ob->obmat[3]);
    }
  }
  else {
    /* In render mode, rv3d is not available, so use the distance to camera.
     * The real distance is not important, but the relative distance to the camera plane
     * in order to sort by z_depth of the objects
     */
    float vn[3] = {0.0f, 0.0f, -1.0f}; /* always face down */
    float plane_cam[4];
    struct Object *camera = draw_ctx->scene->camera;
    if (camera) {
      mul_m4_v3(camera->obmat, vn);
      normalize_v3(vn);
      plane_from_point_normal_v3(plane_cam, camera->loc, vn);
      zdepth = dist_squared_to_plane_v3(ob->obmat[3], plane_cam);
    }
  }
  cache_elem->zdepth = zdepth;
  /* increase slots used in cache */
  (*gp_cache_used)++;

  return cache_array;
}
예제 #12
0
int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
  EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
  EEVEE_StorageList *stl = vedata->stl;
  EEVEE_FramebufferList *fbl = vedata->fbl;
  EEVEE_TextureList *txl = vedata->txl;
  EEVEE_EffectsInfo *effects = stl->effects;
  const float *viewport_size = DRW_viewport_size_get();

  const DRWContextState *draw_ctx = DRW_context_state_get();
  const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);

  /* Compute pixel size, (shared with contact shadows) */
  copy_v2_v2(common_data->ssr_pixelsize, viewport_size);
  invert_v2(common_data->ssr_pixelsize);

  if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) {
    const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0;

    if (use_refraction) {
      /* TODO: Opti: Could be shared. */
      DRW_texture_ensure_fullscreen_2d(
          &txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);

      GPU_framebuffer_ensure_config(
          &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)});
    }

    const bool is_persp = DRW_view_is_persp_get(NULL);
    if (effects->ssr_was_persp != is_persp) {
      effects->ssr_was_persp = is_persp;
      DRW_viewport_request_redraw();
      EEVEE_temporal_sampling_reset(vedata);
      stl->g_data->valid_double_buffer = false;
    }

    effects->reflection_trace_full = (scene_eval->eevee.flag & SCE_EEVEE_SSR_HALF_RESOLUTION) == 0;
    common_data->ssr_thickness = scene_eval->eevee.ssr_thickness;
    common_data->ssr_border_fac = scene_eval->eevee.ssr_border_fade;
    common_data->ssr_firefly_fac = scene_eval->eevee.ssr_firefly_fac;
    common_data->ssr_max_roughness = scene_eval->eevee.ssr_max_roughness;
    common_data->ssr_quality = 1.0f - 0.95f * scene_eval->eevee.ssr_quality;
    common_data->ssr_brdf_bias = 0.1f + common_data->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */

    if (common_data->ssr_firefly_fac < 1e-8f) {
      common_data->ssr_firefly_fac = FLT_MAX;
    }

    const int divisor = (effects->reflection_trace_full) ? 1 : 2;
    int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
    int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
    const bool high_qual_input = true; /* TODO dither low quality input */
    const eGPUTextureFormat format = (high_qual_input) ? GPU_RGBA16F : GPU_RGBA8;

    /* MRT for the shading pass in order to output needed data for the SSR pass. */
    effects->ssr_specrough_input = DRW_texture_pool_query_2d(
        size_fs[0], size_fs[1], format, &draw_engine_eevee_type);

    GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0);

    /* Raytracing output */
    effects->ssr_hit_output = DRW_texture_pool_query_2d(
        tracing_res[0], tracing_res[1], GPU_RG16I, &draw_engine_eevee_type);
    effects->ssr_pdf_output = DRW_texture_pool_query_2d(
        tracing_res[0], tracing_res[1], GPU_R16F, &draw_engine_eevee_type);

    GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb,
                                  {GPU_ATTACHMENT_NONE,
                                   GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
                                   GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)});

    /* Enable double buffering to be able to read previous frame color */
    return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER |
           ((use_refraction) ? EFFECT_REFRACT : 0);
  }

  /* Cleanup to release memory */
  GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
  effects->ssr_specrough_input = NULL;
  effects->ssr_hit_output = NULL;
  effects->ssr_pdf_output = NULL;

  return 0;
}