* write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
* we wrote to PIPESRC.
*/
-static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
+static void intel_fbc_get_plane_source_size(struct intel_fbc_state_cache *cache,
int *width, int *height)
{
- struct intel_plane_state *plane_state =
- to_intel_plane_state(crtc->base.primary->state);
int w, h;
- if (intel_rotation_90_or_270(plane_state->base.rotation)) {
- w = drm_rect_height(&plane_state->src) >> 16;
- h = drm_rect_width(&plane_state->src) >> 16;
+ if (intel_rotation_90_or_270(cache->plane.rotation)) {
+ w = cache->plane.src_h;
+ h = cache->plane.src_w;
} else {
- w = drm_rect_width(&plane_state->src) >> 16;
- h = drm_rect_height(&plane_state->src) >> 16;
+ w = cache->plane.src_w;
+ h = cache->plane.src_h;
}
if (width)
*height = h;
}
-static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc,
- struct drm_framebuffer *fb)
+static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv,
+ struct intel_fbc_state_cache *cache)
{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
int lines;
- intel_fbc_get_plane_source_size(crtc, NULL, &lines);
+ intel_fbc_get_plane_source_size(cache, NULL, &lines);
if (INTEL_INFO(dev_priv)->gen >= 7)
lines = min(lines, 2048);
/* Hardware needs the full buffer stride, not just the active area. */
- return lines * fb->pitches[0];
+ return lines * cache->fb.stride;
}
static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct intel_fbc *fbc = &dev_priv->fbc;
- struct drm_framebuffer *fb = crtc->base.primary->state->fb;
struct drm_mm_node *uninitialized_var(compressed_llb);
int size, fb_cpp, ret;
WARN_ON(drm_mm_node_allocated(&fbc->compressed_fb));
- size = intel_fbc_calculate_cfb_size(crtc, fb);
- fb_cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+ size = intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache);
+ fb_cpp = drm_format_plane_cpp(fbc->state_cache.fb.pixel_format, 0);
ret = find_compression_threshold(dev_priv, &fbc->compressed_fb,
size, fb_cpp);
return true;
}
-static bool pixel_format_is_valid(struct drm_framebuffer *fb)
+static bool pixel_format_is_valid(struct drm_i915_private *dev_priv,
+ uint32_t pixel_format)
{
- struct drm_device *dev = fb->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- switch (fb->pixel_format) {
+ switch (pixel_format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
return true;
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_RGB565:
/* 16bpp not supported on gen2 */
- if (IS_GEN2(dev))
+ if (IS_GEN2(dev_priv))
return false;
/* WaFbcOnly1to1Ratio:ctg */
if (IS_G4X(dev_priv))
static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_fbc *fbc = &dev_priv->fbc;
unsigned int effective_w, effective_h, max_w, max_h;
if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) {
max_h = 1536;
}
- intel_fbc_get_plane_source_size(crtc, &effective_w, &effective_h);
+ intel_fbc_get_plane_source_size(&fbc->state_cache, &effective_w,
+ &effective_h);
effective_w += crtc->adjusted_x;
effective_h += crtc->adjusted_y;
return effective_w <= max_w && effective_h <= max_h;
}
-static bool intel_fbc_can_activate(struct intel_crtc *crtc)
+static void intel_fbc_update_state_cache(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct intel_fbc *fbc = &dev_priv->fbc;
- struct drm_plane *primary;
- struct drm_framebuffer *fb;
- struct intel_plane_state *plane_state;
+ struct intel_fbc_state_cache *cache = &fbc->state_cache;
+ struct intel_crtc_state *crtc_state = crtc->config;
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(crtc->base.primary->state);
+ struct drm_framebuffer *fb = plane_state->base.fb;
struct drm_i915_gem_object *obj;
- const struct drm_display_mode *adjusted_mode;
- if (!intel_crtc_active(&crtc->base)) {
- set_no_fbc_reason(dev_priv, "CRTC not active");
- return false;
- }
+ cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
+ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+ cache->crtc.hsw_bdw_pixel_rate =
+ ilk_pipe_pixel_rate(crtc_state);
+
+ cache->plane.rotation = plane_state->base.rotation;
+ cache->plane.src_w = drm_rect_width(&plane_state->src) >> 16;
+ cache->plane.src_h = drm_rect_height(&plane_state->src) >> 16;
+ cache->plane.visible = plane_state->visible;
+
+ if (!cache->plane.visible)
+ return;
- primary = crtc->base.primary;
- fb = primary->fb;
obj = intel_fb_obj(fb);
- adjusted_mode = &crtc->config->base.adjusted_mode;
- plane_state = to_intel_plane_state(primary->state);
- if (!plane_state->visible) {
+ /* FIXME: We lack the proper locking here, so only run this on the
+ * platforms that need. */
+ if (dev_priv->fbc.activate == ilk_fbc_activate)
+ cache->fb.ilk_ggtt_offset = i915_gem_obj_ggtt_offset(obj);
+ cache->fb.id = fb->base.id;
+ cache->fb.pixel_format = fb->pixel_format;
+ cache->fb.stride = fb->pitches[0];
+ cache->fb.fence_reg = obj->fence_reg;
+ cache->fb.tiling_mode = obj->tiling_mode;
+}
+
+static bool intel_fbc_can_activate(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_fbc *fbc = &dev_priv->fbc;
+ struct intel_fbc_state_cache *cache = &fbc->state_cache;
+
+ if (!cache->plane.visible) {
set_no_fbc_reason(dev_priv, "primary plane not visible");
return false;
}
- if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
- (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+ if ((cache->crtc.mode_flags & DRM_MODE_FLAG_INTERLACE) ||
+ (cache->crtc.mode_flags & DRM_MODE_FLAG_DBLSCAN)) {
set_no_fbc_reason(dev_priv, "incompatible mode");
return false;
}
/* The use of a CPU fence is mandatory in order to detect writes
* by the CPU to the scanout and trigger updates to the FBC.
*/
- if (obj->tiling_mode != I915_TILING_X ||
- obj->fence_reg == I915_FENCE_REG_NONE) {
+ if (cache->fb.tiling_mode != I915_TILING_X ||
+ cache->fb.fence_reg == I915_FENCE_REG_NONE) {
set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced");
return false;
}
if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) &&
- plane_state->base.rotation != BIT(DRM_ROTATE_0)) {
+ cache->plane.rotation != BIT(DRM_ROTATE_0)) {
set_no_fbc_reason(dev_priv, "rotation unsupported");
return false;
}
- if (!stride_is_valid(dev_priv, fb->pitches[0])) {
+ if (!stride_is_valid(dev_priv, cache->fb.stride)) {
set_no_fbc_reason(dev_priv, "framebuffer stride not supported");
return false;
}
- if (!pixel_format_is_valid(fb)) {
+ if (!pixel_format_is_valid(dev_priv, cache->fb.pixel_format)) {
set_no_fbc_reason(dev_priv, "pixel format is invalid");
return false;
}
/* WaFbcExceedCdClockThreshold:hsw,bdw */
if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
- ilk_pipe_pixel_rate(crtc->config) >=
- dev_priv->cdclk_freq * 95 / 100) {
+ cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk_freq * 95 / 100) {
set_no_fbc_reason(dev_priv, "pixel rate is too big");
return false;
}
* we didn't get any invalidate/deactivate calls, but this would require
* a lot of tracking just for a specific case. If we conclude it's an
* important case, we can implement it later. */
- if (intel_fbc_calculate_cfb_size(crtc, fb) >
+ if (intel_fbc_calculate_cfb_size(dev_priv, &fbc->state_cache) >
fbc->compressed_fb.size * fbc->threshold) {
set_no_fbc_reason(dev_priv, "CFB requirements changed");
return false;
struct intel_fbc_reg_params *params)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- struct drm_framebuffer *fb = crtc->base.primary->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_fbc *fbc = &dev_priv->fbc;
+ struct intel_fbc_state_cache *cache = &fbc->state_cache;
/* Since all our fields are integer types, use memset here so the
* comparison function can rely on memcmp because the padding will be
params->crtc.plane = crtc->plane;
params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc);
- params->fb.id = fb->base.id;
- params->fb.pixel_format = fb->pixel_format;
- params->fb.stride = fb->pitches[0];
- params->fb.fence_reg = obj->fence_reg;
+ params->fb.id = cache->fb.id;
+ params->fb.pixel_format = cache->fb.pixel_format;
+ params->fb.stride = cache->fb.stride;
+ params->fb.fence_reg = cache->fb.fence_reg;
- params->cfb_size = intel_fbc_calculate_cfb_size(crtc, fb);
+ params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
- /* FIXME: We lack the proper locking here, so only run this on the
- * platforms that need. */
- if (dev_priv->fbc.activate == ilk_fbc_activate)
- params->fb.ggtt_offset = i915_gem_obj_ggtt_offset(obj);
+ params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset;
}
static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
if (!fbc->enabled || fbc->crtc != crtc)
return;
+ intel_fbc_update_state_cache(crtc);
+
if (!intel_fbc_can_activate(crtc))
goto out_disable;
if (!intel_fbc_can_enable(crtc))
goto out;
+ intel_fbc_update_state_cache(crtc);
if (intel_fbc_alloc_cfb(crtc)) {
set_no_fbc_reason(dev_priv, "not enough stolen memory");
goto out;