aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2011-10-04 14:13:26 -0400
committerDave Airlie <airlied@redhat.com>2011-10-05 05:17:17 -0400
commit2fcd5a73bfd5341876f9ea6b5adcc1dd814226d4 (patch)
tree88aa55c24bc1fe620a0753ab1598fe2727b19352 /drivers/gpu/drm
parent44031d25ccface0ae647d664347ae3d3a8016f5f (diff)
vmwgfx: Add present and readback ioctls
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c13
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h19
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c172
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c170
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h3
5 files changed, 377 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 73757c3db8eb..ace4402214c6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -94,6 +94,12 @@
94#define DRM_IOCTL_VMW_FENCE_UNREF \ 94#define DRM_IOCTL_VMW_FENCE_UNREF \
95 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \ 95 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \
96 struct drm_vmw_fence_arg) 96 struct drm_vmw_fence_arg)
97#define DRM_IOCTL_VMW_PRESENT \
98 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT, \
99 struct drm_vmw_present_arg)
100#define DRM_IOCTL_VMW_PRESENT_READBACK \
101 DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \
102 struct drm_vmw_present_readback_arg)
97 103
98/** 104/**
99 * The core DRM version of this macro doesn't account for 105 * The core DRM version of this macro doesn't account for
@@ -146,6 +152,13 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
146 DRM_AUTH | DRM_UNLOCKED), 152 DRM_AUTH | DRM_UNLOCKED),
147 VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, 153 VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
148 DRM_AUTH | DRM_UNLOCKED), 154 DRM_AUTH | DRM_UNLOCKED),
155
156 /* these allow direct access to the framebuffers mark as master only */
157 VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl,
158 DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
159 VMW_IOCTL_DEF(VMW_PRESENT_READBACK,
160 vmw_present_readback_ioctl,
161 DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
149}; 162};
150 163
151static struct pci_device_id vmw_pci_id_list[] = { 164static struct pci_device_id vmw_pci_id_list[] = {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 2124fbc919aa..fc0e3bc63ec0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -97,6 +97,8 @@ struct vmw_cursor_snooper {
97 uint32_t *image; 97 uint32_t *image;
98}; 98};
99 99
100struct vmw_framebuffer;
101
100struct vmw_surface { 102struct vmw_surface {
101 struct vmw_resource res; 103 struct vmw_resource res;
102 uint32_t flags; 104 uint32_t flags;
@@ -430,6 +432,10 @@ extern int vmw_getparam_ioctl(struct drm_device *dev, void *data,
430 struct drm_file *file_priv); 432 struct drm_file *file_priv);
431extern int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, 433extern int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
432 struct drm_file *file_priv); 434 struct drm_file *file_priv);
435extern int vmw_present_ioctl(struct drm_device *dev, void *data,
436 struct drm_file *file_priv);
437extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
438 struct drm_file *file_priv);
433 439
434/** 440/**
435 * Fifo utilities - vmwgfx_fifo.c 441 * Fifo utilities - vmwgfx_fifo.c
@@ -554,6 +560,19 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
554 uint32_t pitch, 560 uint32_t pitch,
555 uint32_t height); 561 uint32_t height);
556u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc); 562u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
563int vmw_kms_present(struct vmw_private *dev_priv,
564 struct drm_file *file_priv,
565 struct vmw_framebuffer *vfb,
566 struct vmw_surface *surface,
567 uint32_t sid, int32_t destX, int32_t destY,
568 struct drm_vmw_rect *clips,
569 uint32_t num_clips);
570int vmw_kms_readback(struct vmw_private *dev_priv,
571 struct drm_file *file_priv,
572 struct vmw_framebuffer *vfb,
573 struct drm_vmw_fence_rep __user *user_fence_rep,
574 struct drm_vmw_rect *clips,
575 uint32_t num_clips);
557 576
558/** 577/**
559 * Overlay control - vmwgfx_overlay.c 578 * Overlay control - vmwgfx_overlay.c
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 5ecf96660644..c0284a4784c9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -27,6 +27,7 @@
27 27
28#include "vmwgfx_drv.h" 28#include "vmwgfx_drv.h"
29#include "vmwgfx_drm.h" 29#include "vmwgfx_drm.h"
30#include "vmwgfx_kms.h"
30 31
31int vmw_getparam_ioctl(struct drm_device *dev, void *data, 32int vmw_getparam_ioctl(struct drm_device *dev, void *data,
32 struct drm_file *file_priv) 33 struct drm_file *file_priv)
@@ -110,3 +111,174 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
110 111
111 return ret; 112 return ret;
112} 113}
114
115int vmw_present_ioctl(struct drm_device *dev, void *data,
116 struct drm_file *file_priv)
117{
118 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
119 struct vmw_private *dev_priv = vmw_priv(dev);
120 struct drm_vmw_present_arg *arg =
121 (struct drm_vmw_present_arg *)data;
122 struct vmw_surface *surface;
123 struct vmw_master *vmaster = vmw_master(file_priv->master);
124 struct drm_vmw_rect __user *clips_ptr;
125 struct drm_vmw_rect *clips = NULL;
126 struct drm_mode_object *obj;
127 struct vmw_framebuffer *vfb;
128 uint32_t num_clips;
129 int ret;
130
131 num_clips = arg->num_clips;
132 clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
133
134 if (unlikely(num_clips == 0))
135 return 0;
136
137 if (clips_ptr == NULL) {
138 DRM_ERROR("Variable clips_ptr must be specified.\n");
139 ret = -EINVAL;
140 goto out_clips;
141 }
142
143 clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
144 if (clips == NULL) {
145 DRM_ERROR("Failed to allocate clip rect list.\n");
146 ret = -ENOMEM;
147 goto out_clips;
148 }
149
150 ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
151 if (ret) {
152 DRM_ERROR("Failed to copy clip rects from userspace.\n");
153 goto out_no_copy;
154 }
155
156 ret = mutex_lock_interruptible(&dev->mode_config.mutex);
157 if (unlikely(ret != 0)) {
158 ret = -ERESTARTSYS;
159 goto out_no_mode_mutex;
160 }
161
162 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
163 if (!obj) {
164 DRM_ERROR("Invalid framebuffer id.\n");
165 ret = -EINVAL;
166 goto out_no_fb;
167 }
168
169 vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
170 if (!vfb->dmabuf) {
171 DRM_ERROR("Framebuffer not dmabuf backed.\n");
172 ret = -EINVAL;
173 goto out_no_fb;
174 }
175
176 ret = ttm_read_lock(&vmaster->lock, true);
177 if (unlikely(ret != 0))
178 goto out_no_ttm_lock;
179
180 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid,
181 &surface);
182 if (ret)
183 goto out_no_surface;
184
185 ret = vmw_kms_present(dev_priv, file_priv,
186 vfb, surface, arg->sid,
187 arg->dest_x, arg->dest_y,
188 clips, num_clips);
189
190 /* vmw_user_surface_lookup takes one ref so does new_fb */
191 vmw_surface_unreference(&surface);
192
193out_no_surface:
194 ttm_read_unlock(&vmaster->lock);
195out_no_ttm_lock:
196out_no_fb:
197 mutex_unlock(&dev->mode_config.mutex);
198out_no_mode_mutex:
199out_no_copy:
200 kfree(clips);
201out_clips:
202 return ret;
203}
204
205int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
206 struct drm_file *file_priv)
207{
208 struct vmw_private *dev_priv = vmw_priv(dev);
209 struct drm_vmw_present_readback_arg *arg =
210 (struct drm_vmw_present_readback_arg *)data;
211 struct drm_vmw_fence_rep __user *user_fence_rep =
212 (struct drm_vmw_fence_rep __user *)
213 (unsigned long)arg->fence_rep;
214 struct vmw_master *vmaster = vmw_master(file_priv->master);
215 struct drm_vmw_rect __user *clips_ptr;
216 struct drm_vmw_rect *clips = NULL;
217 struct drm_mode_object *obj;
218 struct vmw_framebuffer *vfb;
219 uint32_t num_clips;
220 int ret;
221
222 num_clips = arg->num_clips;
223 clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
224
225 if (unlikely(num_clips == 0))
226 return 0;
227
228 if (clips_ptr == NULL) {
229 DRM_ERROR("Argument clips_ptr must be specified.\n");
230 ret = -EINVAL;
231 goto out_clips;
232 }
233
234 clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
235 if (clips == NULL) {
236 DRM_ERROR("Failed to allocate clip rect list.\n");
237 ret = -ENOMEM;
238 goto out_clips;
239 }
240
241 ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
242 if (ret) {
243 DRM_ERROR("Failed to copy clip rects from userspace.\n");
244 goto out_no_copy;
245 }
246
247 ret = mutex_lock_interruptible(&dev->mode_config.mutex);
248 if (unlikely(ret != 0)) {
249 ret = -ERESTARTSYS;
250 goto out_no_mode_mutex;
251 }
252
253 obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
254 if (!obj) {
255 DRM_ERROR("Invalid framebuffer id.\n");
256 ret = -EINVAL;
257 goto out_no_fb;
258 }
259
260 vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
261 if (!vfb->dmabuf) {
262 DRM_ERROR("Framebuffer not dmabuf backed.\n");
263 ret = -EINVAL;
264 goto out_no_fb;
265 }
266
267 ret = ttm_read_lock(&vmaster->lock, true);
268 if (unlikely(ret != 0))
269 goto out_no_ttm_lock;
270
271 ret = vmw_kms_readback(dev_priv, file_priv,
272 vfb, user_fence_rep,
273 clips, num_clips);
274
275 ttm_read_unlock(&vmaster->lock);
276out_no_ttm_lock:
277out_no_fb:
278 mutex_unlock(&dev->mode_config.mutex);
279out_no_mode_mutex:
280out_no_copy:
281 kfree(clips);
282out_clips:
283 return ret;
284}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8628bc7cc0d6..41916b58a3fb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -800,6 +800,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
800 vfbd->base.pin = vmw_framebuffer_dmabuf_pin; 800 vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
801 vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; 801 vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
802 } 802 }
803 vfbd->base.dmabuf = true;
803 vfbd->buffer = dmabuf; 804 vfbd->buffer = dmabuf;
804 vfbd->handle = mode_cmd->handle; 805 vfbd->handle = mode_cmd->handle;
805 *out = &vfbd->base; 806 *out = &vfbd->base;
@@ -900,6 +901,175 @@ static struct drm_mode_config_funcs vmw_kms_funcs = {
900 .fb_create = vmw_kms_fb_create, 901 .fb_create = vmw_kms_fb_create,
901}; 902};
902 903
904int vmw_kms_present(struct vmw_private *dev_priv,
905 struct drm_file *file_priv,
906 struct vmw_framebuffer *vfb,
907 struct vmw_surface *surface,
908 uint32_t sid,
909 int32_t destX, int32_t destY,
910 struct drm_vmw_rect *clips,
911 uint32_t num_clips)
912{
913 size_t fifo_size;
914 int i, ret;
915
916 struct {
917 SVGA3dCmdHeader header;
918 SVGA3dCmdBlitSurfaceToScreen body;
919 } *cmd;
920 SVGASignedRect *blits;
921
922 BUG_ON(surface == NULL);
923 BUG_ON(!clips || !num_clips);
924
925 fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
926 cmd = kmalloc(fifo_size, GFP_KERNEL);
927 if (unlikely(cmd == NULL)) {
928 DRM_ERROR("Failed to allocate temporary fifo memory.\n");
929 return -ENOMEM;
930 }
931
932 memset(cmd, 0, fifo_size);
933
934 cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
935 cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
936
937 cmd->body.srcImage.sid = sid;
938 cmd->body.destScreenId = SVGA_ID_INVALID; /* virtual coords */
939
940 cmd->body.srcRect.left = 0;
941 cmd->body.srcRect.right = surface->sizes[0].width;
942 cmd->body.srcRect.top = 0;
943 cmd->body.srcRect.bottom = surface->sizes[0].height;
944
945 cmd->body.destRect.left = destX;
946 cmd->body.destRect.right = destX + surface->sizes[0].width;
947 cmd->body.destRect.top = destY;
948 cmd->body.destRect.bottom = destY + surface->sizes[0].height;
949
950 blits = (SVGASignedRect *)&cmd[1];
951 for (i = 0; i < num_clips; i++) {
952 blits[i].left = clips[i].x;
953 blits[i].right = clips[i].x + clips[i].w;
954 blits[i].top = clips[i].y;
955 blits[i].bottom = clips[i].y + clips[i].h;
956 }
957
958 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
959 fifo_size, 0, NULL);
960
961 kfree(cmd);
962
963 return ret;
964}
965
966int vmw_kms_readback(struct vmw_private *dev_priv,
967 struct drm_file *file_priv,
968 struct vmw_framebuffer *vfb,
969 struct drm_vmw_fence_rep __user *user_fence_rep,
970 struct drm_vmw_rect *clips,
971 uint32_t num_clips)
972{
973 struct vmw_framebuffer_dmabuf *vfbd =
974 vmw_framebuffer_to_vfbd(&vfb->base);
975 struct vmw_dma_buffer *dmabuf = vfbd->buffer;
976 struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
977 struct drm_crtc *crtc;
978 size_t fifo_size;
979 int i, k, ret, num_units, blits_pos;
980
981 struct {
982 uint32_t header;
983 SVGAFifoCmdDefineGMRFB body;
984 } *cmd;
985 struct {
986 uint32_t header;
987 SVGAFifoCmdBlitScreenToGMRFB body;
988 } *blits;
989
990 num_units = 0;
991 list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
992 if (crtc->fb != &vfb->base)
993 continue;
994 units[num_units++] = vmw_crtc_to_du(crtc);
995 }
996
997 BUG_ON(dmabuf == NULL);
998 BUG_ON(!clips || !num_clips);
999
1000 /* take a safe guess at fifo size */
1001 fifo_size = sizeof(*cmd) + sizeof(*blits) * num_clips * num_units;
1002 cmd = kmalloc(fifo_size, GFP_KERNEL);
1003 if (unlikely(cmd == NULL)) {
1004 DRM_ERROR("Failed to allocate temporary fifo memory.\n");
1005 return -ENOMEM;
1006 }
1007
1008 memset(cmd, 0, fifo_size);
1009 cmd->header = SVGA_CMD_DEFINE_GMRFB;
1010 cmd->body.format.bitsPerPixel = vfb->base.bits_per_pixel;
1011 cmd->body.format.colorDepth = vfb->base.depth;
1012 cmd->body.format.reserved = 0;
1013 cmd->body.bytesPerLine = vfb->base.pitch;
1014 cmd->body.ptr.gmrId = vfbd->handle;
1015 cmd->body.ptr.offset = 0;
1016
1017 blits = (void *)&cmd[1];
1018 blits_pos = 0;
1019 for (i = 0; i < num_units; i++) {
1020 struct drm_vmw_rect *c = clips;
1021 for (k = 0; k < num_clips; k++, c++) {
1022 /* transform clip coords to crtc origin based coords */
1023 int clip_x1 = c->x - units[i]->crtc.x;
1024 int clip_x2 = c->x - units[i]->crtc.x + c->w;
1025 int clip_y1 = c->y - units[i]->crtc.y;
1026 int clip_y2 = c->y - units[i]->crtc.y + c->h;
1027 int dest_x = c->x;
1028 int dest_y = c->y;
1029
1030 /* compensate for clipping, we negate
1031 * a negative number and add that.
1032 */
1033 if (clip_x1 < 0)
1034 dest_x += -clip_x1;
1035 if (clip_y1 < 0)
1036 dest_y += -clip_y1;
1037
1038 /* clip */
1039 clip_x1 = max(clip_x1, 0);
1040 clip_y1 = max(clip_y1, 0);
1041 clip_x2 = min(clip_x2, units[i]->crtc.mode.hdisplay);
1042 clip_y2 = min(clip_y2, units[i]->crtc.mode.vdisplay);
1043
1044 /* and cull any rects that misses the crtc */
1045 if (clip_x1 >= units[i]->crtc.mode.hdisplay ||
1046 clip_y1 >= units[i]->crtc.mode.vdisplay ||
1047 clip_x2 <= 0 || clip_y2 <= 0)
1048 continue;
1049
1050 blits[blits_pos].header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB;
1051 blits[blits_pos].body.srcScreenId = units[i]->unit;
1052 blits[blits_pos].body.destOrigin.x = dest_x;
1053 blits[blits_pos].body.destOrigin.y = dest_y;
1054
1055 blits[blits_pos].body.srcRect.left = clip_x1;
1056 blits[blits_pos].body.srcRect.top = clip_y1;
1057 blits[blits_pos].body.srcRect.right = clip_x2;
1058 blits[blits_pos].body.srcRect.bottom = clip_y2;
1059 blits_pos++;
1060 }
1061 }
1062 /* reset size here and use calculated exact size from loops */
1063 fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos;
1064
1065 ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size,
1066 0, user_fence_rep);
1067
1068 kfree(cmd);
1069
1070 return ret;
1071}
1072
903int vmw_kms_init(struct vmw_private *dev_priv) 1073int vmw_kms_init(struct vmw_private *dev_priv)
904{ 1074{
905 struct drm_device *dev = dev_priv->dev; 1075 struct drm_device *dev = dev_priv->dev;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index ee16a06e4ca1..08d2630ac3a7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -47,6 +47,7 @@ struct vmw_framebuffer {
47 struct drm_framebuffer base; 47 struct drm_framebuffer base;
48 int (*pin)(struct vmw_framebuffer *fb); 48 int (*pin)(struct vmw_framebuffer *fb);
49 int (*unpin)(struct vmw_framebuffer *fb); 49 int (*unpin)(struct vmw_framebuffer *fb);
50 bool dmabuf;
50}; 51};
51 52
52 53
@@ -95,6 +96,8 @@ struct vmw_display_unit {
95 struct drm_display_mode *pref_mode; 96 struct drm_display_mode *pref_mode;
96}; 97};
97 98
99#define vmw_crtc_to_du(x) \
100 container_of(x, struct vmw_display_unit, crtc)
98#define vmw_connector_to_du(x) \ 101#define vmw_connector_to_du(x) \
99 container_of(x, struct vmw_display_unit, connector) 102 container_of(x, struct vmw_display_unit, connector)
100 103