diff options
author | Jakob Bornecrantz <jakob@vmware.com> | 2011-11-28 07:19:15 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-12-19 09:06:05 -0500 |
commit | 6abff3c78051e40130a1c653f874fb12b9d40254 (patch) | |
tree | ddf2af776bd30d02b7bc0c2f6d83f582ac513901 /drivers/gpu | |
parent | bfc2638dc05f2b27538e40821fdbc8399730b1ea (diff) |
vmwgfx: Clip cliprects against screen boundaries in present and dirty
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 209 |
1 files changed, 156 insertions, 53 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index d31ae338cfc1..8aa1dbb45c67 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -31,6 +31,44 @@ | |||
31 | /* Might need a hrtimer here? */ | 31 | /* Might need a hrtimer here? */ |
32 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) | 32 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
33 | 33 | ||
34 | |||
35 | struct vmw_clip_rect { | ||
36 | int x1, x2, y1, y2; | ||
37 | }; | ||
38 | |||
39 | /** | ||
40 | * Clip @num_rects number of @rects against @clip storing the | ||
41 | * results in @out_rects and the number of passed rects in @out_num. | ||
42 | */ | ||
43 | void vmw_clip_cliprects(struct drm_clip_rect *rects, | ||
44 | int num_rects, | ||
45 | struct vmw_clip_rect clip, | ||
46 | SVGASignedRect *out_rects, | ||
47 | int *out_num) | ||
48 | { | ||
49 | int i, k; | ||
50 | |||
51 | for (i = 0, k = 0; i < num_rects; i++) { | ||
52 | int x1 = max_t(int, clip.x1, rects[i].x1); | ||
53 | int y1 = max_t(int, clip.y1, rects[i].y1); | ||
54 | int x2 = min_t(int, clip.x2, rects[i].x2); | ||
55 | int y2 = min_t(int, clip.y2, rects[i].y2); | ||
56 | |||
57 | if (x1 >= x2) | ||
58 | continue; | ||
59 | if (y1 >= y2) | ||
60 | continue; | ||
61 | |||
62 | out_rects[k].left = x1; | ||
63 | out_rects[k].top = y1; | ||
64 | out_rects[k].right = x2; | ||
65 | out_rects[k].bottom = y2; | ||
66 | k++; | ||
67 | } | ||
68 | |||
69 | *out_num = k; | ||
70 | } | ||
71 | |||
34 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) | 72 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) |
35 | { | 73 | { |
36 | if (du->cursor_surface) | 74 | if (du->cursor_surface) |
@@ -386,8 +424,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, | |||
386 | struct drm_clip_rect *clips, | 424 | struct drm_clip_rect *clips, |
387 | unsigned num_clips, int inc) | 425 | unsigned num_clips, int inc) |
388 | { | 426 | { |
389 | struct drm_clip_rect *clips_ptr; | ||
390 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; | 427 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
428 | struct drm_clip_rect *clips_ptr; | ||
429 | struct drm_clip_rect *tmp; | ||
391 | struct drm_crtc *crtc; | 430 | struct drm_crtc *crtc; |
392 | size_t fifo_size; | 431 | size_t fifo_size; |
393 | int i, num_units; | 432 | int i, num_units; |
@@ -400,7 +439,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, | |||
400 | } *cmd; | 439 | } *cmd; |
401 | SVGASignedRect *blits; | 440 | SVGASignedRect *blits; |
402 | 441 | ||
403 | |||
404 | num_units = 0; | 442 | num_units = 0; |
405 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, | 443 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, |
406 | head) { | 444 | head) { |
@@ -411,13 +449,24 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, | |||
411 | 449 | ||
412 | BUG_ON(!clips || !num_clips); | 450 | BUG_ON(!clips || !num_clips); |
413 | 451 | ||
452 | tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); | ||
453 | if (unlikely(tmp == NULL)) { | ||
454 | DRM_ERROR("Temporary cliprect memory alloc failed.\n"); | ||
455 | return -ENOMEM; | ||
456 | } | ||
457 | |||
414 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; | 458 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; |
415 | cmd = kzalloc(fifo_size, GFP_KERNEL); | 459 | cmd = kzalloc(fifo_size, GFP_KERNEL); |
416 | if (unlikely(cmd == NULL)) { | 460 | if (unlikely(cmd == NULL)) { |
417 | DRM_ERROR("Temporary fifo memory alloc failed.\n"); | 461 | DRM_ERROR("Temporary fifo memory alloc failed.\n"); |
418 | return -ENOMEM; | 462 | ret = -ENOMEM; |
463 | goto out_free_tmp; | ||
419 | } | 464 | } |
420 | 465 | ||
466 | /* setup blits pointer */ | ||
467 | blits = (SVGASignedRect *)&cmd[1]; | ||
468 | |||
469 | /* initial clip region */ | ||
421 | left = clips->x1; | 470 | left = clips->x1; |
422 | right = clips->x2; | 471 | right = clips->x2; |
423 | top = clips->y1; | 472 | top = clips->y1; |
@@ -443,45 +492,60 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, | |||
443 | cmd->body.srcRect.bottom = bottom; | 492 | cmd->body.srcRect.bottom = bottom; |
444 | 493 | ||
445 | clips_ptr = clips; | 494 | clips_ptr = clips; |
446 | blits = (SVGASignedRect *)&cmd[1]; | ||
447 | for (i = 0; i < num_clips; i++, clips_ptr += inc) { | 495 | for (i = 0; i < num_clips; i++, clips_ptr += inc) { |
448 | blits[i].left = clips_ptr->x1 - left; | 496 | tmp[i].x1 = clips_ptr->x1 - left; |
449 | blits[i].right = clips_ptr->x2 - left; | 497 | tmp[i].x2 = clips_ptr->x2 - left; |
450 | blits[i].top = clips_ptr->y1 - top; | 498 | tmp[i].y1 = clips_ptr->y1 - top; |
451 | blits[i].bottom = clips_ptr->y2 - top; | 499 | tmp[i].y2 = clips_ptr->y2 - top; |
452 | } | 500 | } |
453 | 501 | ||
454 | /* do per unit writing, reuse fifo for each */ | 502 | /* do per unit writing, reuse fifo for each */ |
455 | for (i = 0; i < num_units; i++) { | 503 | for (i = 0; i < num_units; i++) { |
456 | struct vmw_display_unit *unit = units[i]; | 504 | struct vmw_display_unit *unit = units[i]; |
457 | int clip_x1 = left - unit->crtc.x; | 505 | struct vmw_clip_rect clip; |
458 | int clip_y1 = top - unit->crtc.y; | 506 | int num; |
459 | int clip_x2 = right - unit->crtc.x; | 507 | |
460 | int clip_y2 = bottom - unit->crtc.y; | 508 | clip.x1 = left - unit->crtc.x; |
509 | clip.y1 = top - unit->crtc.y; | ||
510 | clip.x2 = right - unit->crtc.x; | ||
511 | clip.y2 = bottom - unit->crtc.y; | ||
461 | 512 | ||
462 | /* skip any crtcs that misses the clip region */ | 513 | /* skip any crtcs that misses the clip region */ |
463 | if (clip_x1 >= unit->crtc.mode.hdisplay || | 514 | if (clip.x1 >= unit->crtc.mode.hdisplay || |
464 | clip_y1 >= unit->crtc.mode.vdisplay || | 515 | clip.y1 >= unit->crtc.mode.vdisplay || |
465 | clip_x2 <= 0 || clip_y2 <= 0) | 516 | clip.x2 <= 0 || clip.y2 <= 0) |
466 | continue; | 517 | continue; |
467 | 518 | ||
519 | /* | ||
520 | * In order for the clip rects to be correctly scaled | ||
521 | * the src and dest rects needs to be the same size. | ||
522 | */ | ||
523 | cmd->body.destRect.left = clip.x1; | ||
524 | cmd->body.destRect.right = clip.x2; | ||
525 | cmd->body.destRect.top = clip.y1; | ||
526 | cmd->body.destRect.bottom = clip.y2; | ||
527 | |||
528 | /* create a clip rect of the crtc in dest coords */ | ||
529 | clip.x2 = unit->crtc.mode.hdisplay - clip.x1; | ||
530 | clip.y2 = unit->crtc.mode.vdisplay - clip.y1; | ||
531 | clip.x1 = 0 - clip.x1; | ||
532 | clip.y1 = 0 - clip.y1; | ||
533 | |||
468 | /* need to reset sid as it is changed by execbuf */ | 534 | /* need to reset sid as it is changed by execbuf */ |
469 | cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); | 535 | cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); |
470 | |||
471 | cmd->body.destScreenId = unit->unit; | 536 | cmd->body.destScreenId = unit->unit; |
472 | 537 | ||
473 | /* | 538 | /* clip and write blits to cmd stream */ |
474 | * The blit command is a lot more resilient then the | 539 | vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); |
475 | * readback command when it comes to clip rects. So its | ||
476 | * okay to go out of bounds. | ||
477 | */ | ||
478 | 540 | ||
479 | cmd->body.destRect.left = clip_x1; | 541 | /* if no cliprects hit skip this */ |
480 | cmd->body.destRect.right = clip_x2; | 542 | if (num == 0) |
481 | cmd->body.destRect.top = clip_y1; | 543 | continue; |
482 | cmd->body.destRect.bottom = clip_y2; | ||
483 | 544 | ||
484 | 545 | ||
546 | /* recalculate package length */ | ||
547 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; | ||
548 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); | ||
485 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, | 549 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
486 | fifo_size, 0, NULL); | 550 | fifo_size, 0, NULL); |
487 | 551 | ||
@@ -489,7 +553,10 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, | |||
489 | break; | 553 | break; |
490 | } | 554 | } |
491 | 555 | ||
556 | |||
492 | kfree(cmd); | 557 | kfree(cmd); |
558 | out_free_tmp: | ||
559 | kfree(tmp); | ||
493 | 560 | ||
494 | return ret; | 561 | return ret; |
495 | } | 562 | } |
@@ -795,6 +862,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, | |||
795 | int clip_y1 = clips_ptr->y1 - unit->crtc.y; | 862 | int clip_y1 = clips_ptr->y1 - unit->crtc.y; |
796 | int clip_x2 = clips_ptr->x2 - unit->crtc.x; | 863 | int clip_x2 = clips_ptr->x2 - unit->crtc.x; |
797 | int clip_y2 = clips_ptr->y2 - unit->crtc.y; | 864 | int clip_y2 = clips_ptr->y2 - unit->crtc.y; |
865 | int move_x, move_y; | ||
798 | 866 | ||
799 | /* skip any crtcs that misses the clip region */ | 867 | /* skip any crtcs that misses the clip region */ |
800 | if (clip_x1 >= unit->crtc.mode.hdisplay || | 868 | if (clip_x1 >= unit->crtc.mode.hdisplay || |
@@ -802,12 +870,21 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, | |||
802 | clip_x2 <= 0 || clip_y2 <= 0) | 870 | clip_x2 <= 0 || clip_y2 <= 0) |
803 | continue; | 871 | continue; |
804 | 872 | ||
873 | /* clip size to crtc size */ | ||
874 | clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); | ||
875 | clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); | ||
876 | |||
877 | /* translate both src and dest to bring clip into screen */ | ||
878 | move_x = min_t(int, clip_x1, 0); | ||
879 | move_y = min_t(int, clip_y1, 0); | ||
880 | |||
881 | /* actual translate done here */ | ||
805 | blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; | 882 | blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; |
806 | blits[hit_num].body.destScreenId = unit->unit; | 883 | blits[hit_num].body.destScreenId = unit->unit; |
807 | blits[hit_num].body.srcOrigin.x = clips_ptr->x1; | 884 | blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; |
808 | blits[hit_num].body.srcOrigin.y = clips_ptr->y1; | 885 | blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; |
809 | blits[hit_num].body.destRect.left = clip_x1; | 886 | blits[hit_num].body.destRect.left = clip_x1 - move_x; |
810 | blits[hit_num].body.destRect.top = clip_y1; | 887 | blits[hit_num].body.destRect.top = clip_y1 - move_y; |
811 | blits[hit_num].body.destRect.right = clip_x2; | 888 | blits[hit_num].body.destRect.right = clip_x2; |
812 | blits[hit_num].body.destRect.bottom = clip_y2; | 889 | blits[hit_num].body.destRect.bottom = clip_y2; |
813 | hit_num++; | 890 | hit_num++; |
@@ -1094,6 +1171,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1094 | uint32_t num_clips) | 1171 | uint32_t num_clips) |
1095 | { | 1172 | { |
1096 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; | 1173 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
1174 | struct drm_clip_rect *tmp; | ||
1097 | struct drm_crtc *crtc; | 1175 | struct drm_crtc *crtc; |
1098 | size_t fifo_size; | 1176 | size_t fifo_size; |
1099 | int i, k, num_units; | 1177 | int i, k, num_units; |
@@ -1116,11 +1194,18 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1116 | BUG_ON(surface == NULL); | 1194 | BUG_ON(surface == NULL); |
1117 | BUG_ON(!clips || !num_clips); | 1195 | BUG_ON(!clips || !num_clips); |
1118 | 1196 | ||
1197 | tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); | ||
1198 | if (unlikely(tmp == NULL)) { | ||
1199 | DRM_ERROR("Temporary cliprect memory alloc failed.\n"); | ||
1200 | return -ENOMEM; | ||
1201 | } | ||
1202 | |||
1119 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; | 1203 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; |
1120 | cmd = kmalloc(fifo_size, GFP_KERNEL); | 1204 | cmd = kmalloc(fifo_size, GFP_KERNEL); |
1121 | if (unlikely(cmd == NULL)) { | 1205 | if (unlikely(cmd == NULL)) { |
1122 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); | 1206 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); |
1123 | return -ENOMEM; | 1207 | ret = -ENOMEM; |
1208 | goto out_free_tmp; | ||
1124 | } | 1209 | } |
1125 | 1210 | ||
1126 | left = clips->x; | 1211 | left = clips->x; |
@@ -1138,50 +1223,66 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1138 | /* only need to do this once */ | 1223 | /* only need to do this once */ |
1139 | memset(cmd, 0, fifo_size); | 1224 | memset(cmd, 0, fifo_size); |
1140 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); | 1225 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); |
1141 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); | 1226 | |
1227 | blits = (SVGASignedRect *)&cmd[1]; | ||
1142 | 1228 | ||
1143 | cmd->body.srcRect.left = left; | 1229 | cmd->body.srcRect.left = left; |
1144 | cmd->body.srcRect.right = right; | 1230 | cmd->body.srcRect.right = right; |
1145 | cmd->body.srcRect.top = top; | 1231 | cmd->body.srcRect.top = top; |
1146 | cmd->body.srcRect.bottom = bottom; | 1232 | cmd->body.srcRect.bottom = bottom; |
1147 | 1233 | ||
1148 | blits = (SVGASignedRect *)&cmd[1]; | ||
1149 | for (i = 0; i < num_clips; i++) { | 1234 | for (i = 0; i < num_clips; i++) { |
1150 | blits[i].left = clips[i].x - left; | 1235 | tmp[i].x1 = clips[i].x - left; |
1151 | blits[i].right = clips[i].x + clips[i].w - left; | 1236 | tmp[i].x2 = clips[i].x + clips[i].w - left; |
1152 | blits[i].top = clips[i].y - top; | 1237 | tmp[i].y1 = clips[i].y - top; |
1153 | blits[i].bottom = clips[i].y + clips[i].h - top; | 1238 | tmp[i].y2 = clips[i].y + clips[i].h - top; |
1154 | } | 1239 | } |
1155 | 1240 | ||
1156 | for (k = 0; k < num_units; k++) { | 1241 | for (k = 0; k < num_units; k++) { |
1157 | struct vmw_display_unit *unit = units[k]; | 1242 | struct vmw_display_unit *unit = units[k]; |
1158 | int clip_x1 = left + destX - unit->crtc.x; | 1243 | struct vmw_clip_rect clip; |
1159 | int clip_y1 = top + destY - unit->crtc.y; | 1244 | int num; |
1160 | int clip_x2 = right + destX - unit->crtc.x; | 1245 | |
1161 | int clip_y2 = bottom + destY - unit->crtc.y; | 1246 | clip.x1 = left + destX - unit->crtc.x; |
1247 | clip.y1 = top + destY - unit->crtc.y; | ||
1248 | clip.x2 = right + destX - unit->crtc.x; | ||
1249 | clip.y2 = bottom + destY - unit->crtc.y; | ||
1162 | 1250 | ||
1163 | /* skip any crtcs that misses the clip region */ | 1251 | /* skip any crtcs that misses the clip region */ |
1164 | if (clip_x1 >= unit->crtc.mode.hdisplay || | 1252 | if (clip.x1 >= unit->crtc.mode.hdisplay || |
1165 | clip_y1 >= unit->crtc.mode.vdisplay || | 1253 | clip.y1 >= unit->crtc.mode.vdisplay || |
1166 | clip_x2 <= 0 || clip_y2 <= 0) | 1254 | clip.x2 <= 0 || clip.y2 <= 0) |
1167 | continue; | 1255 | continue; |
1168 | 1256 | ||
1257 | /* | ||
1258 | * In order for the clip rects to be correctly scaled | ||
1259 | * the src and dest rects needs to be the same size. | ||
1260 | */ | ||
1261 | cmd->body.destRect.left = clip.x1; | ||
1262 | cmd->body.destRect.right = clip.x2; | ||
1263 | cmd->body.destRect.top = clip.y1; | ||
1264 | cmd->body.destRect.bottom = clip.y2; | ||
1265 | |||
1266 | /* create a clip rect of the crtc in dest coords */ | ||
1267 | clip.x2 = unit->crtc.mode.hdisplay - clip.x1; | ||
1268 | clip.y2 = unit->crtc.mode.vdisplay - clip.y1; | ||
1269 | clip.x1 = 0 - clip.x1; | ||
1270 | clip.y1 = 0 - clip.y1; | ||
1271 | |||
1169 | /* need to reset sid as it is changed by execbuf */ | 1272 | /* need to reset sid as it is changed by execbuf */ |
1170 | cmd->body.srcImage.sid = sid; | 1273 | cmd->body.srcImage.sid = sid; |
1171 | |||
1172 | cmd->body.destScreenId = unit->unit; | 1274 | cmd->body.destScreenId = unit->unit; |
1173 | 1275 | ||
1174 | /* | 1276 | /* clip and write blits to cmd stream */ |
1175 | * The blit command is a lot more resilient then the | 1277 | vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); |
1176 | * readback command when it comes to clip rects. So its | ||
1177 | * okay to go out of bounds. | ||
1178 | */ | ||
1179 | 1278 | ||
1180 | cmd->body.destRect.left = clip_x1; | 1279 | /* if no cliprects hit skip this */ |
1181 | cmd->body.destRect.right = clip_x2; | 1280 | if (num == 0) |
1182 | cmd->body.destRect.top = clip_y1; | 1281 | continue; |
1183 | cmd->body.destRect.bottom = clip_y2; | ||
1184 | 1282 | ||
1283 | /* recalculate package length */ | ||
1284 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; | ||
1285 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); | ||
1185 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, | 1286 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
1186 | fifo_size, 0, NULL); | 1287 | fifo_size, 0, NULL); |
1187 | 1288 | ||
@@ -1190,6 +1291,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1190 | } | 1291 | } |
1191 | 1292 | ||
1192 | kfree(cmd); | 1293 | kfree(cmd); |
1294 | out_free_tmp: | ||
1295 | kfree(tmp); | ||
1193 | 1296 | ||
1194 | return ret; | 1297 | return ret; |
1195 | } | 1298 | } |