aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c400
1 files changed, 252 insertions, 148 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 37d40545ed7..f94b33ae221 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)
@@ -82,6 +120,43 @@ int vmw_cursor_update_image(struct vmw_private *dev_priv,
82 return 0; 120 return 0;
83} 121}
84 122
123int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv,
124 struct vmw_dma_buffer *dmabuf,
125 u32 width, u32 height,
126 u32 hotspotX, u32 hotspotY)
127{
128 struct ttm_bo_kmap_obj map;
129 unsigned long kmap_offset;
130 unsigned long kmap_num;
131 void *virtual;
132 bool dummy;
133 int ret;
134
135 kmap_offset = 0;
136 kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT;
137
138 ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0);
139 if (unlikely(ret != 0)) {
140 DRM_ERROR("reserve failed\n");
141 return -EINVAL;
142 }
143
144 ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map);
145 if (unlikely(ret != 0))
146 goto err_unreserve;
147
148 virtual = ttm_kmap_obj_virtual(&map, &dummy);
149 ret = vmw_cursor_update_image(dev_priv, virtual, width, height,
150 hotspotX, hotspotY);
151
152 ttm_bo_kunmap(&map);
153err_unreserve:
154 ttm_bo_unreserve(&dmabuf->base);
155
156 return ret;
157}
158
159
85void vmw_cursor_update_position(struct vmw_private *dev_priv, 160void vmw_cursor_update_position(struct vmw_private *dev_priv,
86 bool show, int x, int y) 161 bool show, int x, int y)
87{ 162{
@@ -110,24 +185,21 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
110 return -EINVAL; 185 return -EINVAL;
111 186
112 if (handle) { 187 if (handle) {
113 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, 188 ret = vmw_user_lookup_handle(dev_priv, tfile,
114 handle, &surface); 189 handle, &surface, &dmabuf);
115 if (!ret) { 190 if (ret) {
116 if (!surface->snooper.image) { 191 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
117 DRM_ERROR("surface not suitable for cursor\n"); 192 return -EINVAL;
118 vmw_surface_unreference(&surface);
119 return -EINVAL;
120 }
121 } else {
122 ret = vmw_user_dmabuf_lookup(tfile,
123 handle, &dmabuf);
124 if (ret) {
125 DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
126 return -EINVAL;
127 }
128 } 193 }
129 } 194 }
130 195
196 /* need to do this before taking down old image */
197 if (surface && !surface->snooper.image) {
198 DRM_ERROR("surface not suitable for cursor\n");
199 vmw_surface_unreference(&surface);
200 return -EINVAL;
201 }
202
131 /* takedown old cursor */ 203 /* takedown old cursor */
132 if (du->cursor_surface) { 204 if (du->cursor_surface) {
133 du->cursor_surface->snooper.crtc = NULL; 205 du->cursor_surface->snooper.crtc = NULL;
@@ -146,36 +218,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
146 vmw_cursor_update_image(dev_priv, surface->snooper.image, 218 vmw_cursor_update_image(dev_priv, surface->snooper.image,
147 64, 64, du->hotspot_x, du->hotspot_y); 219 64, 64, du->hotspot_x, du->hotspot_y);
148 } else if (dmabuf) { 220 } else if (dmabuf) {
149 struct ttm_bo_kmap_obj map;
150 unsigned long kmap_offset;
151 unsigned long kmap_num;
152 void *virtual;
153 bool dummy;
154
155 /* vmw_user_surface_lookup takes one reference */ 221 /* vmw_user_surface_lookup takes one reference */
156 du->cursor_dmabuf = dmabuf; 222 du->cursor_dmabuf = dmabuf;
157 223
158 kmap_offset = 0; 224 ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height,
159 kmap_num = (64*64*4) >> PAGE_SHIFT; 225 du->hotspot_x, du->hotspot_y);
160
161 ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0);
162 if (unlikely(ret != 0)) {
163 DRM_ERROR("reserve failed\n");
164 return -EINVAL;
165 }
166
167 ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map);
168 if (unlikely(ret != 0))
169 goto err_unreserve;
170
171 virtual = ttm_kmap_obj_virtual(&map, &dummy);
172 vmw_cursor_update_image(dev_priv, virtual, 64, 64,
173 du->hotspot_x, du->hotspot_y);
174
175 ttm_bo_kunmap(&map);
176err_unreserve:
177 ttm_bo_unreserve(&dmabuf->base);
178
179 } else { 226 } else {
180 vmw_cursor_update_position(dev_priv, false, 0, 0); 227 vmw_cursor_update_position(dev_priv, false, 0, 0);
181 return 0; 228 return 0;
@@ -377,8 +424,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
377 struct drm_clip_rect *clips, 424 struct drm_clip_rect *clips,
378 unsigned num_clips, int inc) 425 unsigned num_clips, int inc)
379{ 426{
380 struct drm_clip_rect *clips_ptr;
381 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;
382 struct drm_crtc *crtc; 430 struct drm_crtc *crtc;
383 size_t fifo_size; 431 size_t fifo_size;
384 int i, num_units; 432 int i, num_units;
@@ -391,7 +439,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
391 } *cmd; 439 } *cmd;
392 SVGASignedRect *blits; 440 SVGASignedRect *blits;
393 441
394
395 num_units = 0; 442 num_units = 0;
396 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,
397 head) { 444 head) {
@@ -402,13 +449,24 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
402 449
403 BUG_ON(!clips || !num_clips); 450 BUG_ON(!clips || !num_clips);
404 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
405 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; 458 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
406 cmd = kzalloc(fifo_size, GFP_KERNEL); 459 cmd = kzalloc(fifo_size, GFP_KERNEL);
407 if (unlikely(cmd == NULL)) { 460 if (unlikely(cmd == NULL)) {
408 DRM_ERROR("Temporary fifo memory alloc failed.\n"); 461 DRM_ERROR("Temporary fifo memory alloc failed.\n");
409 return -ENOMEM; 462 ret = -ENOMEM;
463 goto out_free_tmp;
410 } 464 }
411 465
466 /* setup blits pointer */
467 blits = (SVGASignedRect *)&cmd[1];
468
469 /* initial clip region */
412 left = clips->x1; 470 left = clips->x1;
413 right = clips->x2; 471 right = clips->x2;
414 top = clips->y1; 472 top = clips->y1;
@@ -434,45 +492,60 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
434 cmd->body.srcRect.bottom = bottom; 492 cmd->body.srcRect.bottom = bottom;
435 493
436 clips_ptr = clips; 494 clips_ptr = clips;
437 blits = (SVGASignedRect *)&cmd[1];
438 for (i = 0; i < num_clips; i++, clips_ptr += inc) { 495 for (i = 0; i < num_clips; i++, clips_ptr += inc) {
439 blits[i].left = clips_ptr->x1 - left; 496 tmp[i].x1 = clips_ptr->x1 - left;
440 blits[i].right = clips_ptr->x2 - left; 497 tmp[i].x2 = clips_ptr->x2 - left;
441 blits[i].top = clips_ptr->y1 - top; 498 tmp[i].y1 = clips_ptr->y1 - top;
442 blits[i].bottom = clips_ptr->y2 - top; 499 tmp[i].y2 = clips_ptr->y2 - top;
443 } 500 }
444 501
445 /* do per unit writing, reuse fifo for each */ 502 /* do per unit writing, reuse fifo for each */
446 for (i = 0; i < num_units; i++) { 503 for (i = 0; i < num_units; i++) {
447 struct vmw_display_unit *unit = units[i]; 504 struct vmw_display_unit *unit = units[i];
448 int clip_x1 = left - unit->crtc.x; 505 struct vmw_clip_rect clip;
449 int clip_y1 = top - unit->crtc.y; 506 int num;
450 int clip_x2 = right - unit->crtc.x; 507
451 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;
452 512
453 /* skip any crtcs that misses the clip region */ 513 /* skip any crtcs that misses the clip region */
454 if (clip_x1 >= unit->crtc.mode.hdisplay || 514 if (clip.x1 >= unit->crtc.mode.hdisplay ||
455 clip_y1 >= unit->crtc.mode.vdisplay || 515 clip.y1 >= unit->crtc.mode.vdisplay ||
456 clip_x2 <= 0 || clip_y2 <= 0) 516 clip.x2 <= 0 || clip.y2 <= 0)
457 continue; 517 continue;
458 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
459 /* need to reset sid as it is changed by execbuf */ 534 /* need to reset sid as it is changed by execbuf */
460 cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); 535 cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
461
462 cmd->body.destScreenId = unit->unit; 536 cmd->body.destScreenId = unit->unit;
463 537
464 /* 538 /* clip and write blits to cmd stream */
465 * The blit command is a lot more resilient then the 539 vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
466 * readback command when it comes to clip rects. So its
467 * okay to go out of bounds.
468 */
469 540
470 cmd->body.destRect.left = clip_x1; 541 /* if no cliprects hit skip this */
471 cmd->body.destRect.right = clip_x2; 542 if (num == 0)
472 cmd->body.destRect.top = clip_y1; 543 continue;
473 cmd->body.destRect.bottom = clip_y2;
474 544
475 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));
476 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, 549 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
477 fifo_size, 0, NULL); 550 fifo_size, 0, NULL);
478 551
@@ -480,7 +553,10 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
480 break; 553 break;
481 } 554 }
482 555
556
483 kfree(cmd); 557 kfree(cmd);
558out_free_tmp:
559 kfree(tmp);
484 560
485 return ret; 561 return ret;
486} 562}
@@ -556,6 +632,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
556 * Sanity checks. 632 * Sanity checks.
557 */ 633 */
558 634
635 /* Surface must be marked as a scanout. */
636 if (unlikely(!surface->scanout))
637 return -EINVAL;
638
559 if (unlikely(surface->mip_levels[0] != 1 || 639 if (unlikely(surface->mip_levels[0] != 1 ||
560 surface->num_sizes != 1 || 640 surface->num_sizes != 1 ||
561 surface->sizes[0].width < mode_cmd->width || 641 surface->sizes[0].width < mode_cmd->width ||
@@ -782,6 +862,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
782 int clip_y1 = clips_ptr->y1 - unit->crtc.y; 862 int clip_y1 = clips_ptr->y1 - unit->crtc.y;
783 int clip_x2 = clips_ptr->x2 - unit->crtc.x; 863 int clip_x2 = clips_ptr->x2 - unit->crtc.x;
784 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;
785 866
786 /* skip any crtcs that misses the clip region */ 867 /* skip any crtcs that misses the clip region */
787 if (clip_x1 >= unit->crtc.mode.hdisplay || 868 if (clip_x1 >= unit->crtc.mode.hdisplay ||
@@ -789,12 +870,21 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
789 clip_x2 <= 0 || clip_y2 <= 0) 870 clip_x2 <= 0 || clip_y2 <= 0)
790 continue; 871 continue;
791 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 */
792 blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 882 blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
793 blits[hit_num].body.destScreenId = unit->unit; 883 blits[hit_num].body.destScreenId = unit->unit;
794 blits[hit_num].body.srcOrigin.x = clips_ptr->x1; 884 blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
795 blits[hit_num].body.srcOrigin.y = clips_ptr->y1; 885 blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
796 blits[hit_num].body.destRect.left = clip_x1; 886 blits[hit_num].body.destRect.left = clip_x1 - move_x;
797 blits[hit_num].body.destRect.top = clip_y1; 887 blits[hit_num].body.destRect.top = clip_y1 - move_y;
798 blits[hit_num].body.destRect.right = clip_x2; 888 blits[hit_num].body.destRect.right = clip_x2;
799 blits[hit_num].body.destRect.bottom = clip_y2; 889 blits[hit_num].body.destRect.bottom = clip_y2;
800 hit_num++; 890 hit_num++;
@@ -1003,7 +1093,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
1003 struct vmw_surface *surface = NULL; 1093 struct vmw_surface *surface = NULL;
1004 struct vmw_dma_buffer *bo = NULL; 1094 struct vmw_dma_buffer *bo = NULL;
1005 struct ttm_base_object *user_obj; 1095 struct ttm_base_object *user_obj;
1006 u64 required_size;
1007 int ret; 1096 int ret;
1008 1097
1009 /** 1098 /**
@@ -1012,8 +1101,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
1012 * requested framebuffer. 1101 * requested framebuffer.
1013 */ 1102 */
1014 1103
1015 required_size = mode_cmd->pitch * mode_cmd->height; 1104 if (!vmw_kms_validate_mode_vram(dev_priv,
1016 if (unlikely(required_size > (u64) dev_priv->vram_size)) { 1105 mode_cmd->pitch,
1106 mode_cmd->height)) {
1017 DRM_ERROR("VRAM size is too small for requested mode.\n"); 1107 DRM_ERROR("VRAM size is too small for requested mode.\n");
1018 return ERR_PTR(-ENOMEM); 1108 return ERR_PTR(-ENOMEM);
1019 } 1109 }
@@ -1033,46 +1123,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
1033 return ERR_PTR(-ENOENT); 1123 return ERR_PTR(-ENOENT);
1034 } 1124 }
1035 1125
1036 /** 1126 /* returns either a dmabuf or surface */
1037 * End conditioned code. 1127 ret = vmw_user_lookup_handle(dev_priv, tfile,
1038 */ 1128 mode_cmd->handle,
1039 1129 &surface, &bo);
1040 ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
1041 mode_cmd->handle, &surface);
1042 if (ret) 1130 if (ret)
1043 goto try_dmabuf; 1131 goto err_out;
1044 1132
1045 if (!surface->scanout) 1133 /* Create the new framebuffer depending one what we got back */
1046 goto err_not_scanout; 1134 if (bo)
1047 1135 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
1048 ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, 1136 mode_cmd);
1049 &vfb, mode_cmd); 1137 else if (surface)
1050 1138 ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv,
1051 /* vmw_user_surface_lookup takes one ref so does new_fb */ 1139 surface, &vfb, mode_cmd);
1052 vmw_surface_unreference(&surface); 1140 else
1053 1141 BUG();
1054 if (ret) {
1055 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
1056 ttm_base_object_unref(&user_obj);
1057 return ERR_PTR(ret);
1058 } else
1059 vfb->user_obj = user_obj;
1060 return &vfb->base;
1061
1062try_dmabuf:
1063 DRM_INFO("%s: trying buffer\n", __func__);
1064
1065 ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo);
1066 if (ret) {
1067 DRM_ERROR("failed to find buffer: %i\n", ret);
1068 return ERR_PTR(-ENOENT);
1069 }
1070
1071 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
1072 mode_cmd);
1073 1142
1074 /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ 1143err_out:
1075 vmw_dmabuf_unreference(&bo); 1144 /* vmw_user_lookup_handle takes one ref so does new_fb */
1145 if (bo)
1146 vmw_dmabuf_unreference(&bo);
1147 if (surface)
1148 vmw_surface_unreference(&surface);
1076 1149
1077 if (ret) { 1150 if (ret) {
1078 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); 1151 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
@@ -1082,14 +1155,6 @@ try_dmabuf:
1082 vfb->user_obj = user_obj; 1155 vfb->user_obj = user_obj;
1083 1156
1084 return &vfb->base; 1157 return &vfb->base;
1085
1086err_not_scanout:
1087 DRM_ERROR("surface not marked as scanout\n");
1088 /* vmw_user_surface_lookup takes one ref */
1089 vmw_surface_unreference(&surface);
1090 ttm_base_object_unref(&user_obj);
1091
1092 return ERR_PTR(-EINVAL);
1093} 1158}
1094 1159
1095static struct drm_mode_config_funcs vmw_kms_funcs = { 1160static struct drm_mode_config_funcs vmw_kms_funcs = {
@@ -1106,10 +1171,12 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1106 uint32_t num_clips) 1171 uint32_t num_clips)
1107{ 1172{
1108 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;
1109 struct drm_crtc *crtc; 1175 struct drm_crtc *crtc;
1110 size_t fifo_size; 1176 size_t fifo_size;
1111 int i, k, num_units; 1177 int i, k, num_units;
1112 int ret = 0; /* silence warning */ 1178 int ret = 0; /* silence warning */
1179 int left, right, top, bottom;
1113 1180
1114 struct { 1181 struct {
1115 SVGA3dCmdHeader header; 1182 SVGA3dCmdHeader header;
@@ -1127,60 +1194,95 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1127 BUG_ON(surface == NULL); 1194 BUG_ON(surface == NULL);
1128 BUG_ON(!clips || !num_clips); 1195 BUG_ON(!clips || !num_clips);
1129 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
1130 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; 1203 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
1131 cmd = kmalloc(fifo_size, GFP_KERNEL); 1204 cmd = kmalloc(fifo_size, GFP_KERNEL);
1132 if (unlikely(cmd == NULL)) { 1205 if (unlikely(cmd == NULL)) {
1133 DRM_ERROR("Failed to allocate temporary fifo memory.\n"); 1206 DRM_ERROR("Failed to allocate temporary fifo memory.\n");
1134 return -ENOMEM; 1207 ret = -ENOMEM;
1208 goto out_free_tmp;
1209 }
1210
1211 left = clips->x;
1212 right = clips->x + clips->w;
1213 top = clips->y;
1214 bottom = clips->y + clips->h;
1215
1216 for (i = 1; i < num_clips; i++) {
1217 left = min_t(int, left, (int)clips[i].x);
1218 right = max_t(int, right, (int)clips[i].x + clips[i].w);
1219 top = min_t(int, top, (int)clips[i].y);
1220 bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h);
1135 } 1221 }
1136 1222
1137 /* only need to do this once */ 1223 /* only need to do this once */
1138 memset(cmd, 0, fifo_size); 1224 memset(cmd, 0, fifo_size);
1139 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);
1140 cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
1141
1142 cmd->body.srcRect.left = 0;
1143 cmd->body.srcRect.right = surface->sizes[0].width;
1144 cmd->body.srcRect.top = 0;
1145 cmd->body.srcRect.bottom = surface->sizes[0].height;
1146 1226
1147 blits = (SVGASignedRect *)&cmd[1]; 1227 blits = (SVGASignedRect *)&cmd[1];
1228
1229 cmd->body.srcRect.left = left;
1230 cmd->body.srcRect.right = right;
1231 cmd->body.srcRect.top = top;
1232 cmd->body.srcRect.bottom = bottom;
1233
1148 for (i = 0; i < num_clips; i++) { 1234 for (i = 0; i < num_clips; i++) {
1149 blits[i].left = clips[i].x; 1235 tmp[i].x1 = clips[i].x - left;
1150 blits[i].right = clips[i].x + clips[i].w; 1236 tmp[i].x2 = clips[i].x + clips[i].w - left;
1151 blits[i].top = clips[i].y; 1237 tmp[i].y1 = clips[i].y - top;
1152 blits[i].bottom = clips[i].y + clips[i].h; 1238 tmp[i].y2 = clips[i].y + clips[i].h - top;
1153 } 1239 }
1154 1240
1155 for (k = 0; k < num_units; k++) { 1241 for (k = 0; k < num_units; k++) {
1156 struct vmw_display_unit *unit = units[k]; 1242 struct vmw_display_unit *unit = units[k];
1157 int clip_x1 = destX - unit->crtc.x; 1243 struct vmw_clip_rect clip;
1158 int clip_y1 = destY - unit->crtc.y; 1244 int num;
1159 int clip_x2 = clip_x1 + surface->sizes[0].width; 1245
1160 int clip_y2 = clip_y1 + surface->sizes[0].height; 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;
1161 1250
1162 /* skip any crtcs that misses the clip region */ 1251 /* skip any crtcs that misses the clip region */
1163 if (clip_x1 >= unit->crtc.mode.hdisplay || 1252 if (clip.x1 >= unit->crtc.mode.hdisplay ||
1164 clip_y1 >= unit->crtc.mode.vdisplay || 1253 clip.y1 >= unit->crtc.mode.vdisplay ||
1165 clip_x2 <= 0 || clip_y2 <= 0) 1254 clip.x2 <= 0 || clip.y2 <= 0)
1166 continue; 1255 continue;
1167 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
1168 /* need to reset sid as it is changed by execbuf */ 1272 /* need to reset sid as it is changed by execbuf */
1169 cmd->body.srcImage.sid = sid; 1273 cmd->body.srcImage.sid = sid;
1170
1171 cmd->body.destScreenId = unit->unit; 1274 cmd->body.destScreenId = unit->unit;
1172 1275
1173 /* 1276 /* clip and write blits to cmd stream */
1174 * The blit command is a lot more resilient then the 1277 vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
1175 * readback command when it comes to clip rects. So its
1176 * okay to go out of bounds.
1177 */
1178 1278
1179 cmd->body.destRect.left = clip_x1; 1279 /* if no cliprects hit skip this */
1180 cmd->body.destRect.right = clip_x2; 1280 if (num == 0)
1181 cmd->body.destRect.top = clip_y1; 1281 continue;
1182 cmd->body.destRect.bottom = clip_y2;
1183 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));
1184 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, 1286 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
1185 fifo_size, 0, NULL); 1287 fifo_size, 0, NULL);
1186 1288
@@ -1189,6 +1291,8 @@ int vmw_kms_present(struct vmw_private *dev_priv,
1189 } 1291 }
1190 1292
1191 kfree(cmd); 1293 kfree(cmd);
1294out_free_tmp:
1295 kfree(tmp);
1192 1296
1193 return ret; 1297 return ret;
1194} 1298}