0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <drm/drm_atomic.h>
0034 #include <drm/drm_damage_helper.h>
0035 #include <drm/drm_device.h>
0036 #include <drm/drm_framebuffer.h>
0037
0038 static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
0039 struct drm_mode_rect *dest,
0040 uint32_t num_clips, uint32_t src_inc)
0041 {
0042 while (num_clips > 0) {
0043 dest->x1 = src->x1;
0044 dest->y1 = src->y1;
0045 dest->x2 = src->x2;
0046 dest->y2 = src->y2;
0047 src += src_inc;
0048 dest++;
0049 num_clips--;
0050 }
0051 }
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
0068 struct drm_plane_state *plane_state)
0069 {
0070 struct drm_crtc_state *crtc_state;
0071
0072 if (plane_state->crtc) {
0073 crtc_state = drm_atomic_get_new_crtc_state(state,
0074 plane_state->crtc);
0075
0076 if (WARN_ON(!crtc_state))
0077 return;
0078
0079 if (drm_atomic_crtc_needs_modeset(crtc_state)) {
0080 drm_property_blob_put(plane_state->fb_damage_clips);
0081 plane_state->fb_damage_clips = NULL;
0082 }
0083 }
0084 }
0085 EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
0108 struct drm_file *file_priv, unsigned int flags,
0109 unsigned int color, struct drm_clip_rect *clips,
0110 unsigned int num_clips)
0111 {
0112 struct drm_modeset_acquire_ctx ctx;
0113 struct drm_property_blob *damage = NULL;
0114 struct drm_mode_rect *rects = NULL;
0115 struct drm_atomic_state *state;
0116 struct drm_plane *plane;
0117 int ret = 0;
0118
0119
0120
0121
0122
0123 drm_modeset_acquire_init(&ctx,
0124 file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
0125
0126 state = drm_atomic_state_alloc(fb->dev);
0127 if (!state) {
0128 ret = -ENOMEM;
0129 goto out_drop_locks;
0130 }
0131 state->acquire_ctx = &ctx;
0132
0133 if (clips) {
0134 uint32_t inc = 1;
0135
0136 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
0137 inc = 2;
0138 num_clips /= 2;
0139 }
0140
0141 rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
0142 if (!rects) {
0143 ret = -ENOMEM;
0144 goto out;
0145 }
0146
0147 convert_clip_rect_to_rect(clips, rects, num_clips, inc);
0148 damage = drm_property_create_blob(fb->dev,
0149 num_clips * sizeof(*rects),
0150 rects);
0151 if (IS_ERR(damage)) {
0152 ret = PTR_ERR(damage);
0153 damage = NULL;
0154 goto out;
0155 }
0156 }
0157
0158 retry:
0159 drm_for_each_plane(plane, fb->dev) {
0160 struct drm_plane_state *plane_state;
0161
0162 ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
0163 if (ret)
0164 goto out;
0165
0166 if (plane->state->fb != fb) {
0167 drm_modeset_unlock(&plane->mutex);
0168 continue;
0169 }
0170
0171 plane_state = drm_atomic_get_plane_state(state, plane);
0172 if (IS_ERR(plane_state)) {
0173 ret = PTR_ERR(plane_state);
0174 goto out;
0175 }
0176
0177 drm_property_replace_blob(&plane_state->fb_damage_clips,
0178 damage);
0179 }
0180
0181 ret = drm_atomic_commit(state);
0182
0183 out:
0184 if (ret == -EDEADLK) {
0185 drm_atomic_state_clear(state);
0186 ret = drm_modeset_backoff(&ctx);
0187 if (!ret)
0188 goto retry;
0189 }
0190
0191 drm_property_blob_put(damage);
0192 kfree(rects);
0193 drm_atomic_state_put(state);
0194
0195 out_drop_locks:
0196 drm_modeset_drop_locks(&ctx);
0197 drm_modeset_acquire_fini(&ctx);
0198
0199 return ret;
0200
0201 }
0202 EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 void
0223 drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
0224 const struct drm_plane_state *old_state,
0225 const struct drm_plane_state *state)
0226 {
0227 memset(iter, 0, sizeof(*iter));
0228
0229 if (!state || !state->crtc || !state->fb || !state->visible)
0230 return;
0231
0232 iter->clips = (struct drm_rect *)drm_plane_get_damage_clips(state);
0233 iter->num_clips = drm_plane_get_damage_clips_count(state);
0234
0235
0236 iter->plane_src.x1 = state->src.x1 >> 16;
0237 iter->plane_src.y1 = state->src.y1 >> 16;
0238 iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
0239 iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
0240
0241 if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
0242 iter->clips = NULL;
0243 iter->num_clips = 0;
0244 iter->full_update = true;
0245 }
0246 }
0247 EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 bool
0266 drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
0267 struct drm_rect *rect)
0268 {
0269 bool ret = false;
0270
0271 if (iter->full_update) {
0272 *rect = iter->plane_src;
0273 iter->full_update = false;
0274 return true;
0275 }
0276
0277 while (iter->curr_clip < iter->num_clips) {
0278 *rect = iter->clips[iter->curr_clip];
0279 iter->curr_clip++;
0280
0281 if (drm_rect_intersect(rect, &iter->plane_src)) {
0282 ret = true;
0283 break;
0284 }
0285 }
0286
0287 return ret;
0288 }
0289 EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state,
0307 struct drm_plane_state *state,
0308 struct drm_rect *rect)
0309 {
0310 struct drm_atomic_helper_damage_iter iter;
0311 struct drm_rect clip;
0312 bool valid = false;
0313
0314 rect->x1 = INT_MAX;
0315 rect->y1 = INT_MAX;
0316 rect->x2 = 0;
0317 rect->y2 = 0;
0318
0319 drm_atomic_helper_damage_iter_init(&iter, old_state, state);
0320 drm_atomic_for_each_plane_damage(&iter, &clip) {
0321 rect->x1 = min(rect->x1, clip.x1);
0322 rect->y1 = min(rect->y1, clip.y1);
0323 rect->x2 = max(rect->x2, clip.x2);
0324 rect->y2 = max(rect->y2, clip.y2);
0325 valid = true;
0326 }
0327
0328 return valid;
0329 }
0330 EXPORT_SYMBOL(drm_atomic_helper_damage_merged);