| .. | .. |
|---|
| 25 | 25 | * |
|---|
| 26 | 26 | ******************************************************************************/ |
|---|
| 27 | 27 | |
|---|
| 28 | | -#include "vmwgfx_kms.h" |
|---|
| 29 | | -#include "device_include/svga3d_surfacedefs.h" |
|---|
| 30 | | -#include <drm/drm_plane_helper.h> |
|---|
| 31 | 28 | #include <drm/drm_atomic.h> |
|---|
| 32 | 29 | #include <drm/drm_atomic_helper.h> |
|---|
| 30 | +#include <drm/drm_damage_helper.h> |
|---|
| 31 | +#include <drm/drm_fourcc.h> |
|---|
| 32 | +#include <drm/drm_plane_helper.h> |
|---|
| 33 | +#include <drm/drm_vblank.h> |
|---|
| 33 | 34 | |
|---|
| 35 | +#include "vmwgfx_kms.h" |
|---|
| 36 | +#include "device_include/svga3d_surfacedefs.h" |
|---|
| 34 | 37 | |
|---|
| 35 | 38 | #define vmw_crtc_to_stdu(x) \ |
|---|
| 36 | 39 | container_of(x, struct vmw_screen_target_display_unit, base.crtc) |
|---|
| .. | .. |
|---|
| 92 | 95 | SVGA3dCmdSurfaceCopy body; |
|---|
| 93 | 96 | }; |
|---|
| 94 | 97 | |
|---|
| 98 | +struct vmw_stdu_update_gb_image { |
|---|
| 99 | + SVGA3dCmdHeader header; |
|---|
| 100 | + SVGA3dCmdUpdateGBImage body; |
|---|
| 101 | +}; |
|---|
| 95 | 102 | |
|---|
| 96 | 103 | /** |
|---|
| 97 | 104 | * struct vmw_screen_target_display_unit |
|---|
| .. | .. |
|---|
| 107 | 114 | */ |
|---|
| 108 | 115 | struct vmw_screen_target_display_unit { |
|---|
| 109 | 116 | struct vmw_display_unit base; |
|---|
| 110 | | - const struct vmw_surface *display_srf; |
|---|
| 117 | + struct vmw_surface *display_srf; |
|---|
| 111 | 118 | enum stdu_content_type content_fb_type; |
|---|
| 112 | 119 | s32 display_width, display_height; |
|---|
| 113 | 120 | |
|---|
| .. | .. |
|---|
| 163 | 170 | SVGA3dCmdDefineGBScreenTarget body; |
|---|
| 164 | 171 | } *cmd; |
|---|
| 165 | 172 | |
|---|
| 166 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
|---|
| 167 | | - |
|---|
| 168 | | - if (unlikely(cmd == NULL)) { |
|---|
| 169 | | - DRM_ERROR("Out of FIFO space defining Screen Target\n"); |
|---|
| 173 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); |
|---|
| 174 | + if (unlikely(cmd == NULL)) |
|---|
| 170 | 175 | return -ENOMEM; |
|---|
| 171 | | - } |
|---|
| 172 | 176 | |
|---|
| 173 | 177 | cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET; |
|---|
| 174 | 178 | cmd->header.size = sizeof(cmd->body); |
|---|
| .. | .. |
|---|
| 225 | 229 | memset(&image, 0, sizeof(image)); |
|---|
| 226 | 230 | image.sid = res ? res->id : SVGA3D_INVALID_ID; |
|---|
| 227 | 231 | |
|---|
| 228 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
|---|
| 229 | | - |
|---|
| 230 | | - if (unlikely(cmd == NULL)) { |
|---|
| 231 | | - DRM_ERROR("Out of FIFO space binding a screen target\n"); |
|---|
| 232 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); |
|---|
| 233 | + if (unlikely(cmd == NULL)) |
|---|
| 232 | 234 | return -ENOMEM; |
|---|
| 233 | | - } |
|---|
| 234 | 235 | |
|---|
| 235 | 236 | cmd->header.id = SVGA_3D_CMD_BIND_GB_SCREENTARGET; |
|---|
| 236 | 237 | cmd->header.size = sizeof(cmd->body); |
|---|
| .. | .. |
|---|
| 292 | 293 | return -EINVAL; |
|---|
| 293 | 294 | } |
|---|
| 294 | 295 | |
|---|
| 295 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
|---|
| 296 | | - |
|---|
| 297 | | - if (unlikely(cmd == NULL)) { |
|---|
| 298 | | - DRM_ERROR("Out of FIFO space updating a Screen Target\n"); |
|---|
| 296 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); |
|---|
| 297 | + if (unlikely(cmd == NULL)) |
|---|
| 299 | 298 | return -ENOMEM; |
|---|
| 300 | | - } |
|---|
| 301 | 299 | |
|---|
| 302 | 300 | vmw_stdu_populate_update(cmd, stdu->base.unit, |
|---|
| 303 | 301 | 0, stdu->display_width, |
|---|
| .. | .. |
|---|
| 331 | 329 | if (unlikely(!stdu->defined)) |
|---|
| 332 | 330 | return 0; |
|---|
| 333 | 331 | |
|---|
| 334 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
|---|
| 335 | | - |
|---|
| 336 | | - if (unlikely(cmd == NULL)) { |
|---|
| 337 | | - DRM_ERROR("Out of FIFO space, screen target not destroyed\n"); |
|---|
| 332 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); |
|---|
| 333 | + if (unlikely(cmd == NULL)) |
|---|
| 338 | 334 | return -ENOMEM; |
|---|
| 339 | | - } |
|---|
| 340 | 335 | |
|---|
| 341 | 336 | cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET; |
|---|
| 342 | 337 | cmd->header.size = sizeof(cmd->body); |
|---|
| .. | .. |
|---|
| 396 | 391 | if (!crtc->state->enable) |
|---|
| 397 | 392 | return; |
|---|
| 398 | 393 | |
|---|
| 399 | | - if (stdu->base.is_implicit) { |
|---|
| 400 | | - x = crtc->x; |
|---|
| 401 | | - y = crtc->y; |
|---|
| 402 | | - } else { |
|---|
| 403 | | - x = vmw_conn_state->gui_x; |
|---|
| 404 | | - y = vmw_conn_state->gui_y; |
|---|
| 405 | | - } |
|---|
| 394 | + x = vmw_conn_state->gui_x; |
|---|
| 395 | + y = vmw_conn_state->gui_y; |
|---|
| 406 | 396 | |
|---|
| 407 | 397 | vmw_svga_enable(dev_priv); |
|---|
| 408 | 398 | ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); |
|---|
| .. | .. |
|---|
| 417 | 407 | { |
|---|
| 418 | 408 | } |
|---|
| 419 | 409 | |
|---|
| 420 | | - |
|---|
| 421 | 410 | static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, |
|---|
| 422 | 411 | struct drm_crtc_state *old_state) |
|---|
| 423 | 412 | { |
|---|
| 424 | | - struct drm_plane_state *plane_state = crtc->primary->state; |
|---|
| 425 | | - struct vmw_private *dev_priv; |
|---|
| 426 | | - struct vmw_screen_target_display_unit *stdu; |
|---|
| 427 | | - struct vmw_framebuffer *vfb; |
|---|
| 428 | | - struct drm_framebuffer *fb; |
|---|
| 429 | | - |
|---|
| 430 | | - |
|---|
| 431 | | - stdu = vmw_crtc_to_stdu(crtc); |
|---|
| 432 | | - dev_priv = vmw_priv(crtc->dev); |
|---|
| 433 | | - fb = plane_state->fb; |
|---|
| 434 | | - |
|---|
| 435 | | - vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; |
|---|
| 436 | | - |
|---|
| 437 | | - if (vfb) |
|---|
| 438 | | - vmw_kms_add_active(dev_priv, &stdu->base, vfb); |
|---|
| 439 | | - else |
|---|
| 440 | | - vmw_kms_del_active(dev_priv, &stdu->base); |
|---|
| 441 | 413 | } |
|---|
| 442 | 414 | |
|---|
| 443 | 415 | static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, |
|---|
| .. | .. |
|---|
| 470 | 442 | stdu->content_fb_type = SAME_AS_DISPLAY; |
|---|
| 471 | 443 | } |
|---|
| 472 | 444 | } |
|---|
| 473 | | - |
|---|
| 474 | | -/** |
|---|
| 475 | | - * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target |
|---|
| 476 | | - * |
|---|
| 477 | | - * @crtc: CRTC to attach FB to |
|---|
| 478 | | - * @fb: FB to attach |
|---|
| 479 | | - * @event: Event to be posted. This event should've been alloced |
|---|
| 480 | | - * using k[mz]alloc, and should've been completely initialized. |
|---|
| 481 | | - * @page_flip_flags: Input flags. |
|---|
| 482 | | - * |
|---|
| 483 | | - * If the STDU uses the same display and content buffers, i.e. a true flip, |
|---|
| 484 | | - * this function will replace the existing display buffer with the new content |
|---|
| 485 | | - * buffer. |
|---|
| 486 | | - * |
|---|
| 487 | | - * If the STDU uses different display and content buffers, i.e. a blit, then |
|---|
| 488 | | - * only the content buffer will be updated. |
|---|
| 489 | | - * |
|---|
| 490 | | - * RETURNS: |
|---|
| 491 | | - * 0 on success, error code on failure |
|---|
| 492 | | - */ |
|---|
| 493 | | -static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, |
|---|
| 494 | | - struct drm_framebuffer *new_fb, |
|---|
| 495 | | - struct drm_pending_vblank_event *event, |
|---|
| 496 | | - uint32_t flags, |
|---|
| 497 | | - struct drm_modeset_acquire_ctx *ctx) |
|---|
| 498 | | - |
|---|
| 499 | | -{ |
|---|
| 500 | | - struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
|---|
| 501 | | - struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); |
|---|
| 502 | | - int ret; |
|---|
| 503 | | - |
|---|
| 504 | | - if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) |
|---|
| 505 | | - return -EINVAL; |
|---|
| 506 | | - |
|---|
| 507 | | - ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); |
|---|
| 508 | | - if (ret) { |
|---|
| 509 | | - DRM_ERROR("Page flip error %d.\n", ret); |
|---|
| 510 | | - return ret; |
|---|
| 511 | | - } |
|---|
| 512 | | - |
|---|
| 513 | | - return 0; |
|---|
| 514 | | -} |
|---|
| 515 | | - |
|---|
| 516 | 445 | |
|---|
| 517 | 446 | /** |
|---|
| 518 | 447 | * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect |
|---|
| .. | .. |
|---|
| 595 | 524 | |
|---|
| 596 | 525 | vmw_fifo_commit(dirty->dev_priv, sizeof(*cmd) + blit_size); |
|---|
| 597 | 526 | |
|---|
| 527 | + stdu->display_srf->res.res_dirty = true; |
|---|
| 598 | 528 | ddirty->left = ddirty->top = S32_MAX; |
|---|
| 599 | 529 | ddirty->right = ddirty->bottom = S32_MIN; |
|---|
| 600 | 530 | } |
|---|
| .. | .. |
|---|
| 660 | 590 | return; |
|---|
| 661 | 591 | |
|---|
| 662 | 592 | /* Assume we are blitting from Guest (bo) to Host (display_srf) */ |
|---|
| 663 | | - dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; |
|---|
| 593 | + dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; |
|---|
| 664 | 594 | dst_bo = &stdu->display_srf->res.backup->base; |
|---|
| 665 | 595 | dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; |
|---|
| 666 | 596 | |
|---|
| .. | .. |
|---|
| 691 | 621 | region.x2 = diff.rect.x2; |
|---|
| 692 | 622 | region.y1 = diff.rect.y1; |
|---|
| 693 | 623 | region.y2 = diff.rect.y2; |
|---|
| 694 | | - ret = vmw_kms_update_proxy( |
|---|
| 695 | | - (struct vmw_resource *) &stdu->display_srf->res, |
|---|
| 696 | | - (const struct drm_clip_rect *) ®ion, 1, 1); |
|---|
| 624 | + ret = vmw_kms_update_proxy(&stdu->display_srf->res, ®ion, |
|---|
| 625 | + 1, 1); |
|---|
| 697 | 626 | if (ret) |
|---|
| 698 | 627 | goto out_cleanup; |
|---|
| 699 | 628 | |
|---|
| 700 | 629 | |
|---|
| 701 | 630 | dev_priv = vmw_priv(stdu->base.crtc.dev); |
|---|
| 702 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); |
|---|
| 703 | | - |
|---|
| 704 | | - if (!cmd) { |
|---|
| 705 | | - DRM_ERROR("Cannot reserve FIFO space to update STDU"); |
|---|
| 631 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); |
|---|
| 632 | + if (!cmd) |
|---|
| 706 | 633 | goto out_cleanup; |
|---|
| 707 | | - } |
|---|
| 708 | 634 | |
|---|
| 709 | 635 | vmw_stdu_populate_update(cmd, stdu->base.unit, |
|---|
| 710 | 636 | region.x1, region.x2, |
|---|
| .. | .. |
|---|
| 759 | 685 | struct vmw_stdu_dirty ddirty; |
|---|
| 760 | 686 | int ret; |
|---|
| 761 | 687 | bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); |
|---|
| 688 | + DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); |
|---|
| 762 | 689 | |
|---|
| 763 | 690 | /* |
|---|
| 764 | 691 | * VMs without 3D support don't have the surface DMA command and |
|---|
| 765 | 692 | * we'll be using a CPU blit, and the framebuffer should be moved out |
|---|
| 766 | 693 | * of VRAM. |
|---|
| 767 | 694 | */ |
|---|
| 768 | | - ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, |
|---|
| 769 | | - false, cpu_blit); |
|---|
| 695 | + ret = vmw_validation_add_bo(&val_ctx, buf, false, cpu_blit); |
|---|
| 770 | 696 | if (ret) |
|---|
| 771 | 697 | return ret; |
|---|
| 698 | + |
|---|
| 699 | + ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); |
|---|
| 700 | + if (ret) |
|---|
| 701 | + goto out_unref; |
|---|
| 772 | 702 | |
|---|
| 773 | 703 | ddirty.transfer = (to_surface) ? SVGA3D_WRITE_HOST_VRAM : |
|---|
| 774 | 704 | SVGA3D_READ_HOST_VRAM; |
|---|
| .. | .. |
|---|
| 796 | 726 | |
|---|
| 797 | 727 | ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, |
|---|
| 798 | 728 | 0, 0, num_clips, increment, &ddirty.base); |
|---|
| 799 | | - vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, |
|---|
| 800 | | - user_fence_rep); |
|---|
| 801 | 729 | |
|---|
| 730 | + vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL, |
|---|
| 731 | + user_fence_rep); |
|---|
| 732 | + return ret; |
|---|
| 733 | + |
|---|
| 734 | +out_unref: |
|---|
| 735 | + vmw_validation_unref_lists(&val_ctx); |
|---|
| 802 | 736 | return ret; |
|---|
| 803 | 737 | } |
|---|
| 804 | 738 | |
|---|
| .. | .. |
|---|
| 874 | 808 | cmd->body.dest.sid = stdu->display_srf->res.id; |
|---|
| 875 | 809 | update = (struct vmw_stdu_update *) &blit[dirty->num_hits]; |
|---|
| 876 | 810 | commit_size = sizeof(*cmd) + blit_size + sizeof(*update); |
|---|
| 811 | + stdu->display_srf->res.res_dirty = true; |
|---|
| 877 | 812 | } else { |
|---|
| 878 | 813 | update = dirty->cmd; |
|---|
| 879 | 814 | commit_size = sizeof(*update); |
|---|
| .. | .. |
|---|
| 924 | 859 | struct vmw_framebuffer_surface *vfbs = |
|---|
| 925 | 860 | container_of(framebuffer, typeof(*vfbs), base); |
|---|
| 926 | 861 | struct vmw_stdu_dirty sdirty; |
|---|
| 927 | | - struct vmw_validation_ctx ctx; |
|---|
| 862 | + DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); |
|---|
| 928 | 863 | int ret; |
|---|
| 929 | 864 | |
|---|
| 930 | 865 | if (!srf) |
|---|
| 931 | 866 | srf = &vfbs->surface->res; |
|---|
| 932 | 867 | |
|---|
| 933 | | - ret = vmw_kms_helper_resource_prepare(srf, true, &ctx); |
|---|
| 868 | + ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, |
|---|
| 869 | + NULL, NULL); |
|---|
| 934 | 870 | if (ret) |
|---|
| 935 | 871 | return ret; |
|---|
| 872 | + |
|---|
| 873 | + ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); |
|---|
| 874 | + if (ret) |
|---|
| 875 | + goto out_unref; |
|---|
| 936 | 876 | |
|---|
| 937 | 877 | if (vfbs->is_bo_proxy) { |
|---|
| 938 | 878 | ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); |
|---|
| .. | .. |
|---|
| 954 | 894 | dest_x, dest_y, num_clips, inc, |
|---|
| 955 | 895 | &sdirty.base); |
|---|
| 956 | 896 | out_finish: |
|---|
| 957 | | - vmw_kms_helper_resource_finish(&ctx, out_fence); |
|---|
| 897 | + vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, |
|---|
| 898 | + NULL); |
|---|
| 958 | 899 | |
|---|
| 900 | + return ret; |
|---|
| 901 | + |
|---|
| 902 | +out_unref: |
|---|
| 903 | + vmw_validation_unref_lists(&val_ctx); |
|---|
| 959 | 904 | return ret; |
|---|
| 960 | 905 | } |
|---|
| 961 | 906 | |
|---|
| .. | .. |
|---|
| 969 | 914 | .reset = vmw_du_crtc_reset, |
|---|
| 970 | 915 | .atomic_duplicate_state = vmw_du_crtc_duplicate_state, |
|---|
| 971 | 916 | .atomic_destroy_state = vmw_du_crtc_destroy_state, |
|---|
| 972 | | - .set_config = vmw_kms_set_config, |
|---|
| 973 | | - .page_flip = vmw_stdu_crtc_page_flip, |
|---|
| 917 | + .set_config = drm_atomic_helper_set_config, |
|---|
| 918 | + .page_flip = drm_atomic_helper_page_flip, |
|---|
| 919 | + .get_vblank_counter = vmw_get_vblank_counter, |
|---|
| 920 | + .enable_vblank = vmw_enable_vblank, |
|---|
| 921 | + .disable_vblank = vmw_disable_vblank, |
|---|
| 974 | 922 | }; |
|---|
| 975 | 923 | |
|---|
| 976 | 924 | |
|---|
| .. | .. |
|---|
| 1025 | 973 | .dpms = vmw_du_connector_dpms, |
|---|
| 1026 | 974 | .detect = vmw_du_connector_detect, |
|---|
| 1027 | 975 | .fill_modes = vmw_du_connector_fill_modes, |
|---|
| 1028 | | - .set_property = vmw_du_connector_set_property, |
|---|
| 1029 | 976 | .destroy = vmw_stdu_connector_destroy, |
|---|
| 1030 | 977 | .reset = vmw_du_connector_reset, |
|---|
| 1031 | 978 | .atomic_duplicate_state = vmw_du_connector_duplicate_state, |
|---|
| 1032 | 979 | .atomic_destroy_state = vmw_du_connector_destroy_state, |
|---|
| 1033 | | - .atomic_set_property = vmw_du_connector_atomic_set_property, |
|---|
| 1034 | | - .atomic_get_property = vmw_du_connector_atomic_get_property, |
|---|
| 1035 | 980 | }; |
|---|
| 1036 | 981 | |
|---|
| 1037 | 982 | |
|---|
| 1038 | 983 | static const struct |
|---|
| 1039 | 984 | drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { |
|---|
| 1040 | | - .best_encoder = drm_atomic_helper_best_encoder, |
|---|
| 1041 | 985 | }; |
|---|
| 1042 | 986 | |
|---|
| 1043 | 987 | |
|---|
| .. | .. |
|---|
| 1097 | 1041 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); |
|---|
| 1098 | 1042 | enum stdu_content_type new_content_type; |
|---|
| 1099 | 1043 | struct vmw_framebuffer_surface *new_vfbs; |
|---|
| 1100 | | - struct drm_crtc *crtc = new_state->crtc; |
|---|
| 1101 | 1044 | uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h; |
|---|
| 1102 | 1045 | int ret; |
|---|
| 1103 | 1046 | |
|---|
| .. | .. |
|---|
| 1114 | 1057 | vfb = vmw_framebuffer_to_vfb(new_fb); |
|---|
| 1115 | 1058 | new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); |
|---|
| 1116 | 1059 | |
|---|
| 1117 | | - if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay && |
|---|
| 1118 | | - new_vfbs->surface->base_size.height == vdisplay) |
|---|
| 1060 | + if (new_vfbs && |
|---|
| 1061 | + new_vfbs->surface->metadata.base_size.width == hdisplay && |
|---|
| 1062 | + new_vfbs->surface->metadata.base_size.height == vdisplay) |
|---|
| 1119 | 1063 | new_content_type = SAME_AS_DISPLAY; |
|---|
| 1120 | 1064 | else if (vfb->bo) |
|---|
| 1121 | 1065 | new_content_type = SEPARATE_BO; |
|---|
| .. | .. |
|---|
| 1123 | 1067 | new_content_type = SEPARATE_SURFACE; |
|---|
| 1124 | 1068 | |
|---|
| 1125 | 1069 | if (new_content_type != SAME_AS_DISPLAY) { |
|---|
| 1126 | | - struct vmw_surface content_srf; |
|---|
| 1127 | | - struct drm_vmw_size display_base_size = {0}; |
|---|
| 1128 | | - |
|---|
| 1129 | | - display_base_size.width = hdisplay; |
|---|
| 1130 | | - display_base_size.height = vdisplay; |
|---|
| 1131 | | - display_base_size.depth = 1; |
|---|
| 1070 | + struct vmw_surface_metadata metadata = {0}; |
|---|
| 1132 | 1071 | |
|---|
| 1133 | 1072 | /* |
|---|
| 1134 | 1073 | * If content buffer is a buffer object, then we have to |
|---|
| .. | .. |
|---|
| 1138 | 1077 | |
|---|
| 1139 | 1078 | switch (new_fb->format->cpp[0]*8) { |
|---|
| 1140 | 1079 | case 32: |
|---|
| 1141 | | - content_srf.format = SVGA3D_X8R8G8B8; |
|---|
| 1080 | + metadata.format = SVGA3D_X8R8G8B8; |
|---|
| 1142 | 1081 | break; |
|---|
| 1143 | 1082 | |
|---|
| 1144 | 1083 | case 16: |
|---|
| 1145 | | - content_srf.format = SVGA3D_R5G6B5; |
|---|
| 1084 | + metadata.format = SVGA3D_R5G6B5; |
|---|
| 1146 | 1085 | break; |
|---|
| 1147 | 1086 | |
|---|
| 1148 | 1087 | case 8: |
|---|
| 1149 | | - content_srf.format = SVGA3D_P8; |
|---|
| 1088 | + metadata.format = SVGA3D_P8; |
|---|
| 1150 | 1089 | break; |
|---|
| 1151 | 1090 | |
|---|
| 1152 | 1091 | default: |
|---|
| .. | .. |
|---|
| 1154 | 1093 | return -EINVAL; |
|---|
| 1155 | 1094 | } |
|---|
| 1156 | 1095 | |
|---|
| 1157 | | - content_srf.flags = 0; |
|---|
| 1158 | | - content_srf.mip_levels[0] = 1; |
|---|
| 1159 | | - content_srf.multisample_count = 0; |
|---|
| 1160 | | - content_srf.multisample_pattern = |
|---|
| 1161 | | - SVGA3D_MS_PATTERN_NONE; |
|---|
| 1162 | | - content_srf.quality_level = SVGA3D_MS_QUALITY_NONE; |
|---|
| 1096 | + metadata.mip_levels[0] = 1; |
|---|
| 1097 | + metadata.num_sizes = 1; |
|---|
| 1098 | + metadata.scanout = true; |
|---|
| 1163 | 1099 | } else { |
|---|
| 1164 | | - content_srf = *new_vfbs->surface; |
|---|
| 1100 | + metadata = new_vfbs->surface->metadata; |
|---|
| 1165 | 1101 | } |
|---|
| 1166 | 1102 | |
|---|
| 1167 | | - if (vps->surf) { |
|---|
| 1168 | | - struct drm_vmw_size cur_base_size = vps->surf->base_size; |
|---|
| 1103 | + metadata.base_size.width = hdisplay; |
|---|
| 1104 | + metadata.base_size.height = vdisplay; |
|---|
| 1105 | + metadata.base_size.depth = 1; |
|---|
| 1169 | 1106 | |
|---|
| 1170 | | - if (cur_base_size.width != display_base_size.width || |
|---|
| 1171 | | - cur_base_size.height != display_base_size.height || |
|---|
| 1172 | | - vps->surf->format != content_srf.format) { |
|---|
| 1107 | + if (vps->surf) { |
|---|
| 1108 | + struct drm_vmw_size cur_base_size = |
|---|
| 1109 | + vps->surf->metadata.base_size; |
|---|
| 1110 | + |
|---|
| 1111 | + if (cur_base_size.width != metadata.base_size.width || |
|---|
| 1112 | + cur_base_size.height != metadata.base_size.height || |
|---|
| 1113 | + vps->surf->metadata.format != metadata.format) { |
|---|
| 1173 | 1114 | WARN_ON(vps->pinned != 0); |
|---|
| 1174 | 1115 | vmw_surface_unreference(&vps->surf); |
|---|
| 1175 | 1116 | } |
|---|
| .. | .. |
|---|
| 1177 | 1118 | } |
|---|
| 1178 | 1119 | |
|---|
| 1179 | 1120 | if (!vps->surf) { |
|---|
| 1180 | | - ret = vmw_surface_gb_priv_define |
|---|
| 1181 | | - (crtc->dev, |
|---|
| 1182 | | - /* Kernel visible only */ |
|---|
| 1183 | | - 0, |
|---|
| 1184 | | - content_srf.flags, |
|---|
| 1185 | | - content_srf.format, |
|---|
| 1186 | | - true, /* a scanout buffer */ |
|---|
| 1187 | | - content_srf.mip_levels[0], |
|---|
| 1188 | | - content_srf.multisample_count, |
|---|
| 1189 | | - 0, |
|---|
| 1190 | | - display_base_size, |
|---|
| 1191 | | - content_srf.multisample_pattern, |
|---|
| 1192 | | - content_srf.quality_level, |
|---|
| 1193 | | - &vps->surf); |
|---|
| 1121 | + ret = vmw_gb_surface_define(dev_priv, 0, &metadata, |
|---|
| 1122 | + &vps->surf); |
|---|
| 1194 | 1123 | if (ret != 0) { |
|---|
| 1195 | 1124 | DRM_ERROR("Couldn't allocate STDU surface.\n"); |
|---|
| 1196 | 1125 | return ret; |
|---|
| .. | .. |
|---|
| 1240 | 1169 | return ret; |
|---|
| 1241 | 1170 | } |
|---|
| 1242 | 1171 | |
|---|
| 1172 | +static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update, |
|---|
| 1173 | + uint32_t num_hits) |
|---|
| 1174 | +{ |
|---|
| 1175 | + return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits + |
|---|
| 1176 | + sizeof(SVGA3dCmdSurfaceDMASuffix) + |
|---|
| 1177 | + sizeof(struct vmw_stdu_update); |
|---|
| 1178 | +} |
|---|
| 1243 | 1179 | |
|---|
| 1180 | +static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, |
|---|
| 1181 | + uint32_t num_hits) |
|---|
| 1182 | +{ |
|---|
| 1183 | + return sizeof(struct vmw_stdu_update_gb_image) + |
|---|
| 1184 | + sizeof(struct vmw_stdu_update); |
|---|
| 1185 | +} |
|---|
| 1186 | + |
|---|
| 1187 | +static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update, |
|---|
| 1188 | + void *cmd, uint32_t num_hits) |
|---|
| 1189 | +{ |
|---|
| 1190 | + struct vmw_screen_target_display_unit *stdu; |
|---|
| 1191 | + struct vmw_framebuffer_bo *vfbbo; |
|---|
| 1192 | + struct vmw_stdu_dma *cmd_dma = cmd; |
|---|
| 1193 | + |
|---|
| 1194 | + stdu = container_of(update->du, typeof(*stdu), base); |
|---|
| 1195 | + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); |
|---|
| 1196 | + |
|---|
| 1197 | + cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA; |
|---|
| 1198 | + cmd_dma->header.size = sizeof(cmd_dma->body) + |
|---|
| 1199 | + sizeof(struct SVGA3dCopyBox) * num_hits + |
|---|
| 1200 | + sizeof(SVGA3dCmdSurfaceDMASuffix); |
|---|
| 1201 | + vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr); |
|---|
| 1202 | + cmd_dma->body.guest.pitch = update->vfb->base.pitches[0]; |
|---|
| 1203 | + cmd_dma->body.host.sid = stdu->display_srf->res.id; |
|---|
| 1204 | + cmd_dma->body.host.face = 0; |
|---|
| 1205 | + cmd_dma->body.host.mipmap = 0; |
|---|
| 1206 | + cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM; |
|---|
| 1207 | + |
|---|
| 1208 | + return sizeof(*cmd_dma); |
|---|
| 1209 | +} |
|---|
| 1210 | + |
|---|
| 1211 | +static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update, |
|---|
| 1212 | + void *cmd, struct drm_rect *clip, |
|---|
| 1213 | + uint32_t fb_x, uint32_t fb_y) |
|---|
| 1214 | +{ |
|---|
| 1215 | + struct SVGA3dCopyBox *box = cmd; |
|---|
| 1216 | + |
|---|
| 1217 | + box->srcx = fb_x; |
|---|
| 1218 | + box->srcy = fb_y; |
|---|
| 1219 | + box->srcz = 0; |
|---|
| 1220 | + box->x = clip->x1; |
|---|
| 1221 | + box->y = clip->y1; |
|---|
| 1222 | + box->z = 0; |
|---|
| 1223 | + box->w = drm_rect_width(clip); |
|---|
| 1224 | + box->h = drm_rect_height(clip); |
|---|
| 1225 | + box->d = 1; |
|---|
| 1226 | + |
|---|
| 1227 | + return sizeof(*box); |
|---|
| 1228 | +} |
|---|
| 1229 | + |
|---|
| 1230 | +static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update, |
|---|
| 1231 | + void *cmd, struct drm_rect *bb) |
|---|
| 1232 | +{ |
|---|
| 1233 | + struct vmw_screen_target_display_unit *stdu; |
|---|
| 1234 | + struct vmw_framebuffer_bo *vfbbo; |
|---|
| 1235 | + SVGA3dCmdSurfaceDMASuffix *suffix = cmd; |
|---|
| 1236 | + |
|---|
| 1237 | + stdu = container_of(update->du, typeof(*stdu), base); |
|---|
| 1238 | + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); |
|---|
| 1239 | + |
|---|
| 1240 | + suffix->suffixSize = sizeof(*suffix); |
|---|
| 1241 | + suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE; |
|---|
| 1242 | + |
|---|
| 1243 | + vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2, |
|---|
| 1244 | + bb->y1, bb->y2); |
|---|
| 1245 | + |
|---|
| 1246 | + return sizeof(*suffix) + sizeof(struct vmw_stdu_update); |
|---|
| 1247 | +} |
|---|
| 1248 | + |
|---|
| 1249 | +static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update, |
|---|
| 1250 | + void *cmd, uint32_t num_hits) |
|---|
| 1251 | +{ |
|---|
| 1252 | + struct vmw_du_update_plane_buffer *bo_update = |
|---|
| 1253 | + container_of(update, typeof(*bo_update), base); |
|---|
| 1254 | + |
|---|
| 1255 | + bo_update->fb_left = INT_MAX; |
|---|
| 1256 | + bo_update->fb_top = INT_MAX; |
|---|
| 1257 | + |
|---|
| 1258 | + return 0; |
|---|
| 1259 | +} |
|---|
| 1260 | + |
|---|
| 1261 | +static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update, |
|---|
| 1262 | + void *cmd, struct drm_rect *clip, |
|---|
| 1263 | + uint32_t fb_x, uint32_t fb_y) |
|---|
| 1264 | +{ |
|---|
| 1265 | + struct vmw_du_update_plane_buffer *bo_update = |
|---|
| 1266 | + container_of(update, typeof(*bo_update), base); |
|---|
| 1267 | + |
|---|
| 1268 | + bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x); |
|---|
| 1269 | + bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y); |
|---|
| 1270 | + |
|---|
| 1271 | + return 0; |
|---|
| 1272 | +} |
|---|
| 1273 | + |
|---|
| 1274 | +static uint32_t |
|---|
| 1275 | +vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, |
|---|
| 1276 | + struct drm_rect *bb) |
|---|
| 1277 | +{ |
|---|
| 1278 | + struct vmw_du_update_plane_buffer *bo_update; |
|---|
| 1279 | + struct vmw_screen_target_display_unit *stdu; |
|---|
| 1280 | + struct vmw_framebuffer_bo *vfbbo; |
|---|
| 1281 | + struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0); |
|---|
| 1282 | + struct vmw_stdu_update_gb_image *cmd_img = cmd; |
|---|
| 1283 | + struct vmw_stdu_update *cmd_update; |
|---|
| 1284 | + struct ttm_buffer_object *src_bo, *dst_bo; |
|---|
| 1285 | + u32 src_offset, dst_offset; |
|---|
| 1286 | + s32 src_pitch, dst_pitch; |
|---|
| 1287 | + s32 width, height; |
|---|
| 1288 | + |
|---|
| 1289 | + bo_update = container_of(update, typeof(*bo_update), base); |
|---|
| 1290 | + stdu = container_of(update->du, typeof(*stdu), base); |
|---|
| 1291 | + vfbbo = container_of(update->vfb, typeof(*vfbbo), base); |
|---|
| 1292 | + |
|---|
| 1293 | + width = bb->x2 - bb->x1; |
|---|
| 1294 | + height = bb->y2 - bb->y1; |
|---|
| 1295 | + |
|---|
| 1296 | + diff.cpp = stdu->cpp; |
|---|
| 1297 | + |
|---|
| 1298 | + dst_bo = &stdu->display_srf->res.backup->base; |
|---|
| 1299 | + dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; |
|---|
| 1300 | + dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; |
|---|
| 1301 | + |
|---|
| 1302 | + src_bo = &vfbbo->buffer->base; |
|---|
| 1303 | + src_pitch = update->vfb->base.pitches[0]; |
|---|
| 1304 | + src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * |
|---|
| 1305 | + stdu->cpp; |
|---|
| 1306 | + |
|---|
| 1307 | + (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo, |
|---|
| 1308 | + src_offset, src_pitch, width * stdu->cpp, height, |
|---|
| 1309 | + &diff); |
|---|
| 1310 | + |
|---|
| 1311 | + if (drm_rect_visible(&diff.rect)) { |
|---|
| 1312 | + SVGA3dBox *box = &cmd_img->body.box; |
|---|
| 1313 | + |
|---|
| 1314 | + cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; |
|---|
| 1315 | + cmd_img->header.size = sizeof(cmd_img->body); |
|---|
| 1316 | + cmd_img->body.image.sid = stdu->display_srf->res.id; |
|---|
| 1317 | + cmd_img->body.image.face = 0; |
|---|
| 1318 | + cmd_img->body.image.mipmap = 0; |
|---|
| 1319 | + |
|---|
| 1320 | + box->x = diff.rect.x1; |
|---|
| 1321 | + box->y = diff.rect.y1; |
|---|
| 1322 | + box->z = 0; |
|---|
| 1323 | + box->w = drm_rect_width(&diff.rect); |
|---|
| 1324 | + box->h = drm_rect_height(&diff.rect); |
|---|
| 1325 | + box->d = 1; |
|---|
| 1326 | + |
|---|
| 1327 | + cmd_update = (struct vmw_stdu_update *)&cmd_img[1]; |
|---|
| 1328 | + vmw_stdu_populate_update(cmd_update, stdu->base.unit, |
|---|
| 1329 | + diff.rect.x1, diff.rect.x2, |
|---|
| 1330 | + diff.rect.y1, diff.rect.y2); |
|---|
| 1331 | + |
|---|
| 1332 | + return sizeof(*cmd_img) + sizeof(*cmd_update); |
|---|
| 1333 | + } |
|---|
| 1334 | + |
|---|
| 1335 | + return 0; |
|---|
| 1336 | +} |
|---|
| 1337 | + |
|---|
| 1338 | +/** |
|---|
| 1339 | + * vmw_stdu_plane_update_bo - Update display unit for bo backed fb. |
|---|
| 1340 | + * @dev_priv: device private. |
|---|
| 1341 | + * @plane: plane state. |
|---|
| 1342 | + * @old_state: old plane state. |
|---|
| 1343 | + * @vfb: framebuffer which is blitted to display unit. |
|---|
| 1344 | + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. |
|---|
| 1345 | + * The returned fence pointer may be NULL in which case the device |
|---|
| 1346 | + * has already synchronized. |
|---|
| 1347 | + * |
|---|
| 1348 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 1349 | + */ |
|---|
| 1350 | +static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, |
|---|
| 1351 | + struct drm_plane *plane, |
|---|
| 1352 | + struct drm_plane_state *old_state, |
|---|
| 1353 | + struct vmw_framebuffer *vfb, |
|---|
| 1354 | + struct vmw_fence_obj **out_fence) |
|---|
| 1355 | +{ |
|---|
| 1356 | + struct vmw_du_update_plane_buffer bo_update; |
|---|
| 1357 | + |
|---|
| 1358 | + memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); |
|---|
| 1359 | + bo_update.base.plane = plane; |
|---|
| 1360 | + bo_update.base.old_state = old_state; |
|---|
| 1361 | + bo_update.base.dev_priv = dev_priv; |
|---|
| 1362 | + bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); |
|---|
| 1363 | + bo_update.base.vfb = vfb; |
|---|
| 1364 | + bo_update.base.out_fence = out_fence; |
|---|
| 1365 | + bo_update.base.mutex = NULL; |
|---|
| 1366 | + bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); |
|---|
| 1367 | + bo_update.base.intr = false; |
|---|
| 1368 | + |
|---|
| 1369 | + /* |
|---|
| 1370 | + * VM without 3D support don't have surface DMA command and framebuffer |
|---|
| 1371 | + * should be moved out of VRAM. |
|---|
| 1372 | + */ |
|---|
| 1373 | + if (bo_update.base.cpu_blit) { |
|---|
| 1374 | + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu; |
|---|
| 1375 | + bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu; |
|---|
| 1376 | + bo_update.base.clip = vmw_stdu_bo_clip_cpu; |
|---|
| 1377 | + bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu; |
|---|
| 1378 | + } else { |
|---|
| 1379 | + bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size; |
|---|
| 1380 | + bo_update.base.pre_clip = vmw_stdu_bo_populate_dma; |
|---|
| 1381 | + bo_update.base.clip = vmw_stdu_bo_populate_clip; |
|---|
| 1382 | + bo_update.base.post_clip = vmw_stdu_bo_populate_update; |
|---|
| 1383 | + } |
|---|
| 1384 | + |
|---|
| 1385 | + return vmw_du_helper_plane_update(&bo_update.base); |
|---|
| 1386 | +} |
|---|
| 1387 | + |
|---|
| 1388 | +static uint32_t |
|---|
| 1389 | +vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, |
|---|
| 1390 | + uint32_t num_hits) |
|---|
| 1391 | +{ |
|---|
| 1392 | + struct vmw_framebuffer_surface *vfbs; |
|---|
| 1393 | + uint32_t size = 0; |
|---|
| 1394 | + |
|---|
| 1395 | + vfbs = container_of(update->vfb, typeof(*vfbs), base); |
|---|
| 1396 | + |
|---|
| 1397 | + if (vfbs->is_bo_proxy) |
|---|
| 1398 | + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; |
|---|
| 1399 | + |
|---|
| 1400 | + size += sizeof(struct vmw_stdu_update); |
|---|
| 1401 | + |
|---|
| 1402 | + return size; |
|---|
| 1403 | +} |
|---|
| 1404 | + |
|---|
| 1405 | +static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, |
|---|
| 1406 | + uint32_t num_hits) |
|---|
| 1407 | +{ |
|---|
| 1408 | + struct vmw_framebuffer_surface *vfbs; |
|---|
| 1409 | + uint32_t size = 0; |
|---|
| 1410 | + |
|---|
| 1411 | + vfbs = container_of(update->vfb, typeof(*vfbs), base); |
|---|
| 1412 | + |
|---|
| 1413 | + if (vfbs->is_bo_proxy) |
|---|
| 1414 | + size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; |
|---|
| 1415 | + |
|---|
| 1416 | + size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * |
|---|
| 1417 | + num_hits + sizeof(struct vmw_stdu_update); |
|---|
| 1418 | + |
|---|
| 1419 | + return size; |
|---|
| 1420 | +} |
|---|
| 1421 | + |
|---|
| 1422 | +static uint32_t |
|---|
| 1423 | +vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) |
|---|
| 1424 | +{ |
|---|
| 1425 | + struct vmw_framebuffer_surface *vfbs; |
|---|
| 1426 | + struct drm_plane_state *state = update->plane->state; |
|---|
| 1427 | + struct drm_plane_state *old_state = update->old_state; |
|---|
| 1428 | + struct vmw_stdu_update_gb_image *cmd_update = cmd; |
|---|
| 1429 | + struct drm_atomic_helper_damage_iter iter; |
|---|
| 1430 | + struct drm_rect clip; |
|---|
| 1431 | + uint32_t copy_size = 0; |
|---|
| 1432 | + |
|---|
| 1433 | + vfbs = container_of(update->vfb, typeof(*vfbs), base); |
|---|
| 1434 | + |
|---|
| 1435 | + /* |
|---|
| 1436 | + * proxy surface is special where a buffer object type fb is wrapped |
|---|
| 1437 | + * in a surface and need an update gb image command to sync with device. |
|---|
| 1438 | + */ |
|---|
| 1439 | + drm_atomic_helper_damage_iter_init(&iter, old_state, state); |
|---|
| 1440 | + drm_atomic_for_each_plane_damage(&iter, &clip) { |
|---|
| 1441 | + SVGA3dBox *box = &cmd_update->body.box; |
|---|
| 1442 | + |
|---|
| 1443 | + cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; |
|---|
| 1444 | + cmd_update->header.size = sizeof(cmd_update->body); |
|---|
| 1445 | + cmd_update->body.image.sid = vfbs->surface->res.id; |
|---|
| 1446 | + cmd_update->body.image.face = 0; |
|---|
| 1447 | + cmd_update->body.image.mipmap = 0; |
|---|
| 1448 | + |
|---|
| 1449 | + box->x = clip.x1; |
|---|
| 1450 | + box->y = clip.y1; |
|---|
| 1451 | + box->z = 0; |
|---|
| 1452 | + box->w = drm_rect_width(&clip); |
|---|
| 1453 | + box->h = drm_rect_height(&clip); |
|---|
| 1454 | + box->d = 1; |
|---|
| 1455 | + |
|---|
| 1456 | + copy_size += sizeof(*cmd_update); |
|---|
| 1457 | + cmd_update++; |
|---|
| 1458 | + } |
|---|
| 1459 | + |
|---|
| 1460 | + return copy_size; |
|---|
| 1461 | +} |
|---|
| 1462 | + |
|---|
| 1463 | +static uint32_t |
|---|
| 1464 | +vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, |
|---|
| 1465 | + uint32_t num_hits) |
|---|
| 1466 | +{ |
|---|
| 1467 | + struct vmw_screen_target_display_unit *stdu; |
|---|
| 1468 | + struct vmw_framebuffer_surface *vfbs; |
|---|
| 1469 | + struct vmw_stdu_surface_copy *cmd_copy = cmd; |
|---|
| 1470 | + |
|---|
| 1471 | + stdu = container_of(update->du, typeof(*stdu), base); |
|---|
| 1472 | + vfbs = container_of(update->vfb, typeof(*vfbs), base); |
|---|
| 1473 | + |
|---|
| 1474 | + cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; |
|---|
| 1475 | + cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * |
|---|
| 1476 | + num_hits; |
|---|
| 1477 | + cmd_copy->body.src.sid = vfbs->surface->res.id; |
|---|
| 1478 | + cmd_copy->body.dest.sid = stdu->display_srf->res.id; |
|---|
| 1479 | + |
|---|
| 1480 | + return sizeof(*cmd_copy); |
|---|
| 1481 | +} |
|---|
| 1482 | + |
|---|
| 1483 | +static uint32_t |
|---|
| 1484 | +vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd, |
|---|
| 1485 | + struct drm_rect *clip, uint32_t fb_x, |
|---|
| 1486 | + uint32_t fb_y) |
|---|
| 1487 | +{ |
|---|
| 1488 | + struct SVGA3dCopyBox *box = cmd; |
|---|
| 1489 | + |
|---|
| 1490 | + box->srcx = fb_x; |
|---|
| 1491 | + box->srcy = fb_y; |
|---|
| 1492 | + box->srcz = 0; |
|---|
| 1493 | + box->x = clip->x1; |
|---|
| 1494 | + box->y = clip->y1; |
|---|
| 1495 | + box->z = 0; |
|---|
| 1496 | + box->w = drm_rect_width(clip); |
|---|
| 1497 | + box->h = drm_rect_height(clip); |
|---|
| 1498 | + box->d = 1; |
|---|
| 1499 | + |
|---|
| 1500 | + return sizeof(*box); |
|---|
| 1501 | +} |
|---|
| 1502 | + |
|---|
| 1503 | +static uint32_t |
|---|
| 1504 | +vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd, |
|---|
| 1505 | + struct drm_rect *bb) |
|---|
| 1506 | +{ |
|---|
| 1507 | + vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1, |
|---|
| 1508 | + bb->y2); |
|---|
| 1509 | + |
|---|
| 1510 | + return sizeof(struct vmw_stdu_update); |
|---|
| 1511 | +} |
|---|
| 1512 | + |
|---|
| 1513 | +/** |
|---|
| 1514 | + * vmw_stdu_plane_update_surface - Update display unit for surface backed fb |
|---|
| 1515 | + * @dev_priv: Device private |
|---|
| 1516 | + * @plane: Plane state |
|---|
| 1517 | + * @old_state: Old plane state |
|---|
| 1518 | + * @vfb: Framebuffer which is blitted to display unit |
|---|
| 1519 | + * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. |
|---|
| 1520 | + * The returned fence pointer may be NULL in which case the device |
|---|
| 1521 | + * has already synchronized. |
|---|
| 1522 | + * |
|---|
| 1523 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 1524 | + */ |
|---|
| 1525 | +static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, |
|---|
| 1526 | + struct drm_plane *plane, |
|---|
| 1527 | + struct drm_plane_state *old_state, |
|---|
| 1528 | + struct vmw_framebuffer *vfb, |
|---|
| 1529 | + struct vmw_fence_obj **out_fence) |
|---|
| 1530 | +{ |
|---|
| 1531 | + struct vmw_du_update_plane srf_update; |
|---|
| 1532 | + struct vmw_screen_target_display_unit *stdu; |
|---|
| 1533 | + struct vmw_framebuffer_surface *vfbs; |
|---|
| 1534 | + |
|---|
| 1535 | + stdu = vmw_crtc_to_stdu(plane->state->crtc); |
|---|
| 1536 | + vfbs = container_of(vfb, typeof(*vfbs), base); |
|---|
| 1537 | + |
|---|
| 1538 | + memset(&srf_update, 0, sizeof(struct vmw_du_update_plane)); |
|---|
| 1539 | + srf_update.plane = plane; |
|---|
| 1540 | + srf_update.old_state = old_state; |
|---|
| 1541 | + srf_update.dev_priv = dev_priv; |
|---|
| 1542 | + srf_update.du = vmw_crtc_to_du(plane->state->crtc); |
|---|
| 1543 | + srf_update.vfb = vfb; |
|---|
| 1544 | + srf_update.out_fence = out_fence; |
|---|
| 1545 | + srf_update.mutex = &dev_priv->cmdbuf_mutex; |
|---|
| 1546 | + srf_update.cpu_blit = false; |
|---|
| 1547 | + srf_update.intr = true; |
|---|
| 1548 | + |
|---|
| 1549 | + if (vfbs->is_bo_proxy) |
|---|
| 1550 | + srf_update.post_prepare = vmw_stdu_surface_update_proxy; |
|---|
| 1551 | + |
|---|
| 1552 | + if (vfbs->surface->res.id != stdu->display_srf->res.id) { |
|---|
| 1553 | + srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; |
|---|
| 1554 | + srf_update.pre_clip = vmw_stdu_surface_populate_copy; |
|---|
| 1555 | + srf_update.clip = vmw_stdu_surface_populate_clip; |
|---|
| 1556 | + } else { |
|---|
| 1557 | + srf_update.calc_fifo_size = |
|---|
| 1558 | + vmw_stdu_surface_fifo_size_same_display; |
|---|
| 1559 | + } |
|---|
| 1560 | + |
|---|
| 1561 | + srf_update.post_clip = vmw_stdu_surface_populate_update; |
|---|
| 1562 | + |
|---|
| 1563 | + return vmw_du_helper_plane_update(&srf_update); |
|---|
| 1564 | +} |
|---|
| 1244 | 1565 | |
|---|
| 1245 | 1566 | /** |
|---|
| 1246 | 1567 | * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane |
|---|
| 1247 | | - * |
|---|
| 1248 | 1568 | * @plane: display plane |
|---|
| 1249 | 1569 | * @old_state: Only used to get crtc info |
|---|
| 1250 | 1570 | * |
|---|
| .. | .. |
|---|
| 1261 | 1581 | struct drm_crtc *crtc = plane->state->crtc; |
|---|
| 1262 | 1582 | struct vmw_screen_target_display_unit *stdu; |
|---|
| 1263 | 1583 | struct drm_pending_vblank_event *event; |
|---|
| 1584 | + struct vmw_fence_obj *fence = NULL; |
|---|
| 1264 | 1585 | struct vmw_private *dev_priv; |
|---|
| 1265 | 1586 | int ret; |
|---|
| 1266 | 1587 | |
|---|
| 1267 | | - /* |
|---|
| 1268 | | - * We cannot really fail this function, so if we do, then output an |
|---|
| 1269 | | - * error and maintain consistent atomic state. |
|---|
| 1270 | | - */ |
|---|
| 1588 | + /* If case of device error, maintain consistent atomic state */ |
|---|
| 1271 | 1589 | if (crtc && plane->state->fb) { |
|---|
| 1272 | 1590 | struct vmw_framebuffer *vfb = |
|---|
| 1273 | 1591 | vmw_framebuffer_to_vfb(plane->state->fb); |
|---|
| 1274 | | - struct drm_vmw_rect vclips; |
|---|
| 1275 | 1592 | stdu = vmw_crtc_to_stdu(crtc); |
|---|
| 1276 | 1593 | dev_priv = vmw_priv(crtc->dev); |
|---|
| 1277 | 1594 | |
|---|
| .. | .. |
|---|
| 1279 | 1596 | stdu->content_fb_type = vps->content_fb_type; |
|---|
| 1280 | 1597 | stdu->cpp = vps->cpp; |
|---|
| 1281 | 1598 | |
|---|
| 1282 | | - vclips.x = crtc->x; |
|---|
| 1283 | | - vclips.y = crtc->y; |
|---|
| 1284 | | - vclips.w = crtc->mode.hdisplay; |
|---|
| 1285 | | - vclips.h = crtc->mode.vdisplay; |
|---|
| 1286 | | - |
|---|
| 1287 | 1599 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); |
|---|
| 1288 | 1600 | if (ret) |
|---|
| 1289 | 1601 | DRM_ERROR("Failed to bind surface to STDU.\n"); |
|---|
| 1290 | 1602 | |
|---|
| 1291 | 1603 | if (vfb->bo) |
|---|
| 1292 | | - ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, |
|---|
| 1293 | | - &vclips, 1, 1, true, false, |
|---|
| 1294 | | - crtc); |
|---|
| 1604 | + ret = vmw_stdu_plane_update_bo(dev_priv, plane, |
|---|
| 1605 | + old_state, vfb, &fence); |
|---|
| 1295 | 1606 | else |
|---|
| 1296 | | - ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, |
|---|
| 1297 | | - &vclips, NULL, 0, 0, |
|---|
| 1298 | | - 1, 1, NULL, crtc); |
|---|
| 1607 | + ret = vmw_stdu_plane_update_surface(dev_priv, plane, |
|---|
| 1608 | + old_state, vfb, |
|---|
| 1609 | + &fence); |
|---|
| 1299 | 1610 | if (ret) |
|---|
| 1300 | 1611 | DRM_ERROR("Failed to update STDU.\n"); |
|---|
| 1301 | 1612 | } else { |
|---|
| .. | .. |
|---|
| 1303 | 1614 | stdu = vmw_crtc_to_stdu(crtc); |
|---|
| 1304 | 1615 | dev_priv = vmw_priv(crtc->dev); |
|---|
| 1305 | 1616 | |
|---|
| 1306 | | - /* |
|---|
| 1307 | | - * When disabling a plane, CRTC and FB should always be NULL |
|---|
| 1308 | | - * together, otherwise it's an error. |
|---|
| 1309 | | - * Here primary plane is being disable so blank the screen |
|---|
| 1310 | | - * target display unit, if not already done. |
|---|
| 1311 | | - */ |
|---|
| 1617 | + /* Blank STDU when fb and crtc are NULL */ |
|---|
| 1312 | 1618 | if (!stdu->defined) |
|---|
| 1313 | 1619 | return; |
|---|
| 1314 | 1620 | |
|---|
| .. | .. |
|---|
| 1323 | 1629 | return; |
|---|
| 1324 | 1630 | } |
|---|
| 1325 | 1631 | |
|---|
| 1632 | + /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ |
|---|
| 1326 | 1633 | event = crtc->state->event; |
|---|
| 1327 | | - /* |
|---|
| 1328 | | - * In case of failure and other cases, vblank event will be sent in |
|---|
| 1329 | | - * vmw_du_crtc_atomic_flush. |
|---|
| 1330 | | - */ |
|---|
| 1331 | | - if (event && (ret == 0)) { |
|---|
| 1332 | | - struct vmw_fence_obj *fence = NULL; |
|---|
| 1634 | + if (event && fence) { |
|---|
| 1333 | 1635 | struct drm_file *file_priv = event->base.file_priv; |
|---|
| 1334 | 1636 | |
|---|
| 1335 | | - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); |
|---|
| 1336 | | - |
|---|
| 1337 | | - /* |
|---|
| 1338 | | - * If fence is NULL, then already sync. |
|---|
| 1339 | | - */ |
|---|
| 1340 | | - if (fence) { |
|---|
| 1341 | | - ret = vmw_event_fence_action_queue( |
|---|
| 1342 | | - file_priv, fence, &event->base, |
|---|
| 1343 | | - &event->event.vbl.tv_sec, |
|---|
| 1344 | | - &event->event.vbl.tv_usec, |
|---|
| 1345 | | - true); |
|---|
| 1346 | | - if (ret) |
|---|
| 1347 | | - DRM_ERROR("Failed to queue event on fence.\n"); |
|---|
| 1348 | | - else |
|---|
| 1349 | | - crtc->state->event = NULL; |
|---|
| 1350 | | - |
|---|
| 1351 | | - vmw_fence_obj_unreference(&fence); |
|---|
| 1352 | | - } |
|---|
| 1353 | | - } else { |
|---|
| 1354 | | - (void) vmw_fifo_flush(dev_priv, false); |
|---|
| 1637 | + ret = vmw_event_fence_action_queue(file_priv, |
|---|
| 1638 | + fence, |
|---|
| 1639 | + &event->base, |
|---|
| 1640 | + &event->event.vbl.tv_sec, |
|---|
| 1641 | + &event->event.vbl.tv_usec, |
|---|
| 1642 | + true); |
|---|
| 1643 | + if (ret) |
|---|
| 1644 | + DRM_ERROR("Failed to queue event on fence.\n"); |
|---|
| 1645 | + else |
|---|
| 1646 | + crtc->state->event = NULL; |
|---|
| 1355 | 1647 | } |
|---|
| 1648 | + |
|---|
| 1649 | + if (fence) |
|---|
| 1650 | + vmw_fence_obj_unreference(&fence); |
|---|
| 1356 | 1651 | } |
|---|
| 1357 | 1652 | |
|---|
| 1358 | 1653 | |
|---|
| .. | .. |
|---|
| 1440 | 1735 | stdu->base.pref_active = (unit == 0); |
|---|
| 1441 | 1736 | stdu->base.pref_width = dev_priv->initial_width; |
|---|
| 1442 | 1737 | stdu->base.pref_height = dev_priv->initial_height; |
|---|
| 1443 | | - |
|---|
| 1444 | | - /* |
|---|
| 1445 | | - * Remove this after enabling atomic because property values can |
|---|
| 1446 | | - * only exist in a state object |
|---|
| 1447 | | - */ |
|---|
| 1448 | 1738 | stdu->base.is_implicit = false; |
|---|
| 1449 | 1739 | |
|---|
| 1450 | 1740 | /* Initialize primary plane */ |
|---|
| 1451 | | - vmw_du_plane_reset(primary); |
|---|
| 1452 | | - |
|---|
| 1453 | 1741 | ret = drm_universal_plane_init(dev, primary, |
|---|
| 1454 | 1742 | 0, &vmw_stdu_plane_funcs, |
|---|
| 1455 | 1743 | vmw_primary_plane_formats, |
|---|
| .. | .. |
|---|
| 1461 | 1749 | } |
|---|
| 1462 | 1750 | |
|---|
| 1463 | 1751 | drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); |
|---|
| 1752 | + drm_plane_enable_fb_damage_clips(primary); |
|---|
| 1464 | 1753 | |
|---|
| 1465 | 1754 | /* Initialize cursor plane */ |
|---|
| 1466 | | - vmw_du_plane_reset(cursor); |
|---|
| 1467 | | - |
|---|
| 1468 | 1755 | ret = drm_universal_plane_init(dev, cursor, |
|---|
| 1469 | 1756 | 0, &vmw_stdu_cursor_funcs, |
|---|
| 1470 | 1757 | vmw_cursor_plane_formats, |
|---|
| .. | .. |
|---|
| 1478 | 1765 | |
|---|
| 1479 | 1766 | drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs); |
|---|
| 1480 | 1767 | |
|---|
| 1481 | | - vmw_du_connector_reset(connector); |
|---|
| 1482 | | - |
|---|
| 1483 | 1768 | ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, |
|---|
| 1484 | 1769 | DRM_MODE_CONNECTOR_VIRTUAL); |
|---|
| 1485 | 1770 | if (ret) { |
|---|
| .. | .. |
|---|
| 1489 | 1774 | |
|---|
| 1490 | 1775 | drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); |
|---|
| 1491 | 1776 | connector->status = vmw_du_connector_detect(connector, false); |
|---|
| 1492 | | - vmw_connector_state_to_vcs(connector->state)->is_implicit = false; |
|---|
| 1493 | 1777 | |
|---|
| 1494 | 1778 | ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, |
|---|
| 1495 | 1779 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
|---|
| .. | .. |
|---|
| 1508 | 1792 | goto err_free_encoder; |
|---|
| 1509 | 1793 | } |
|---|
| 1510 | 1794 | |
|---|
| 1511 | | - vmw_du_crtc_reset(crtc); |
|---|
| 1512 | 1795 | ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary, |
|---|
| 1513 | 1796 | &stdu->base.cursor, |
|---|
| 1514 | 1797 | &vmw_stdu_crtc_funcs, NULL); |
|---|
| .. | .. |
|---|
| 1527 | 1810 | dev->mode_config.suggested_x_property, 0); |
|---|
| 1528 | 1811 | drm_object_attach_property(&connector->base, |
|---|
| 1529 | 1812 | dev->mode_config.suggested_y_property, 0); |
|---|
| 1530 | | - if (dev_priv->implicit_placement_property) |
|---|
| 1531 | | - drm_object_attach_property |
|---|
| 1532 | | - (&connector->base, |
|---|
| 1533 | | - dev_priv->implicit_placement_property, |
|---|
| 1534 | | - stdu->base.is_implicit); |
|---|
| 1535 | 1813 | return 0; |
|---|
| 1536 | 1814 | |
|---|
| 1537 | 1815 | err_free_unregister: |
|---|
| .. | .. |
|---|
| 1588 | 1866 | |
|---|
| 1589 | 1867 | |
|---|
| 1590 | 1868 | /* Do nothing if Screen Target support is turned off */ |
|---|
| 1591 | | - if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) |
|---|
| 1869 | + if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE || !dev_priv->has_mob) |
|---|
| 1592 | 1870 | return -ENOSYS; |
|---|
| 1593 | 1871 | |
|---|
| 1594 | 1872 | if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) |
|---|
| .. | .. |
|---|
| 1600 | 1878 | |
|---|
| 1601 | 1879 | dev_priv->active_display_unit = vmw_du_screen_target; |
|---|
| 1602 | 1880 | |
|---|
| 1603 | | - vmw_kms_create_implicit_placement_property(dev_priv, false); |
|---|
| 1604 | | - |
|---|
| 1605 | 1881 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { |
|---|
| 1606 | 1882 | ret = vmw_stdu_init(dev_priv, i); |
|---|
| 1607 | 1883 | |
|---|
| .. | .. |
|---|
| 1611 | 1887 | } |
|---|
| 1612 | 1888 | } |
|---|
| 1613 | 1889 | |
|---|
| 1890 | + drm_mode_config_reset(dev); |
|---|
| 1891 | + |
|---|
| 1614 | 1892 | DRM_INFO("Screen Target Display device initialized\n"); |
|---|
| 1615 | 1893 | |
|---|
| 1616 | 1894 | return 0; |
|---|