aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2011-11-28 07:19:15 -0500
committerDave Airlie <airlied@redhat.com>2011-12-19 09:06:05 -0500
commit6abff3c78051e40130a1c653f874fb12b9d40254 (patch)
treeddf2af776bd30d02b7bc0c2f6d83f582ac513901 /drivers/gpu
parentbfc2638dc05f2b27538e40821fdbc8399730b1ea (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.c209
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
35struct 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 */
43void 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
34void vmw_display_unit_cleanup(struct vmw_display_unit *du) 72void 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);
558out_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);
1294out_free_tmp:
1295 kfree(tmp);
1193 1296
1194 return ret; 1297 return ret;
1195} 1298}