Commit c8261a96 authored by Sinclair Yeh's avatar Sinclair Yeh Committed by Thomas Hellstrom

vmwgfx: Major KMS refactoring / cleanup in preparation of screen targets

Signed-off-by: default avatarSinclair Yeh <syeh@vmware.com>
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
parent 233826a7
/************************************************************************** /**************************************************************************
* *
* Copyright © 2009 VMware, Inc., Palo Alto, CA., USA * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -330,6 +330,17 @@ struct vmw_ctx_binding_state { ...@@ -330,6 +330,17 @@ struct vmw_ctx_binding_state {
struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX]; struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX];
}; };
/*
* enum vmw_display_unit_type - Describes the display unit
*/
enum vmw_display_unit_type {
vmw_du_invalid = 0,
vmw_du_legacy,
vmw_du_screen_object
};
struct vmw_sw_context{ struct vmw_sw_context{
struct drm_open_hash res_ht; struct drm_open_hash res_ht;
bool res_ht_initialized; bool res_ht_initialized;
...@@ -421,6 +432,7 @@ struct vmw_private { ...@@ -421,6 +432,7 @@ struct vmw_private {
*/ */
void *fb_info; void *fb_info;
enum vmw_display_unit_type active_display_unit;
struct vmw_legacy_display *ldu_priv; struct vmw_legacy_display *ldu_priv;
struct vmw_screen_object_display *sou_priv; struct vmw_screen_object_display *sou_priv;
struct vmw_overlay *overlay_priv; struct vmw_overlay *overlay_priv;
...@@ -844,8 +856,8 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -844,8 +856,8 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
extern irqreturn_t vmw_irq_handler(int irq, void *arg); extern irqreturn_t vmw_irq_handler(int irq, void *arg);
extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy, extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy,
uint32_t seqno, bool interruptible, uint32_t seqno, bool interruptible,
unsigned long timeout); unsigned long timeout);
extern void vmw_irq_preinstall(struct drm_device *dev); extern void vmw_irq_preinstall(struct drm_device *dev);
extern int vmw_irq_postinstall(struct drm_device *dev); extern int vmw_irq_postinstall(struct drm_device *dev);
extern void vmw_irq_uninstall(struct drm_device *dev); extern void vmw_irq_uninstall(struct drm_device *dev);
...@@ -876,9 +888,9 @@ extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, ...@@ -876,9 +888,9 @@ extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
extern void vmw_marker_queue_init(struct vmw_marker_queue *queue); extern void vmw_marker_queue_init(struct vmw_marker_queue *queue);
extern void vmw_marker_queue_takedown(struct vmw_marker_queue *queue); extern void vmw_marker_queue_takedown(struct vmw_marker_queue *queue);
extern int vmw_marker_push(struct vmw_marker_queue *queue, extern int vmw_marker_push(struct vmw_marker_queue *queue,
uint32_t seqno); uint32_t seqno);
extern int vmw_marker_pull(struct vmw_marker_queue *queue, extern int vmw_marker_pull(struct vmw_marker_queue *queue,
uint32_t signaled_seqno); uint32_t signaled_seqno);
extern int vmw_wait_lag(struct vmw_private *dev_priv, extern int vmw_wait_lag(struct vmw_private *dev_priv,
struct vmw_marker_queue *queue, uint32_t us); struct vmw_marker_queue *queue, uint32_t us);
......
...@@ -71,8 +71,8 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) ...@@ -71,8 +71,8 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
if (hwversion < SVGA3D_HWVERSION_WS8_B1) if (hwversion < SVGA3D_HWVERSION_WS8_B1)
return false; return false;
/* Non-Screen Object path does not support surfaces */ /* Legacy Display Unit does not support surfaces */
if (!dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_legacy)
return false; return false;
return true; return true;
......
/************************************************************************** /**************************************************************************
* *
* Copyright © 2009 VMware, Inc., Palo Alto, CA., USA * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -32,15 +32,12 @@ ...@@ -32,15 +32,12 @@
#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
struct vmw_clip_rect {
int x1, x2, y1, y2;
};
/** /**
* Clip @num_rects number of @rects against @clip storing the * Clip @num_rects number of @rects against @clip storing the
* results in @out_rects and the number of passed rects in @out_num. * results in @out_rects and the number of passed rects in @out_num.
*/ */
static void vmw_clip_cliprects(struct drm_clip_rect *rects, void vmw_clip_cliprects(struct drm_clip_rect *rects,
int num_rects, int num_rects,
struct vmw_clip_rect clip, struct vmw_clip_rect clip,
SVGASignedRect *out_rects, SVGASignedRect *out_rects,
...@@ -69,7 +66,7 @@ static void vmw_clip_cliprects(struct drm_clip_rect *rects, ...@@ -69,7 +66,7 @@ static void vmw_clip_cliprects(struct drm_clip_rect *rects,
*out_num = k; *out_num = k;
} }
void vmw_display_unit_cleanup(struct vmw_display_unit *du) void vmw_du_cleanup(struct vmw_display_unit *du)
{ {
if (du->cursor_surface) if (du->cursor_surface)
vmw_surface_unreference(&du->cursor_surface); vmw_surface_unreference(&du->cursor_surface);
...@@ -367,15 +364,6 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, ...@@ -367,15 +364,6 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
srf->snooper.age++; srf->snooper.age++;
/* we can't call this function from this function since execbuf has
* reserved fifo space.
*
* if (srf->snooper.crtc)
* vmw_ldu_crtc_cursor_update_image(dev_priv,
* srf->snooper.image, 64, 64,
* du->hotspot_x, du->hotspot_y);
*/
ttm_bo_kunmap(&map); ttm_bo_kunmap(&map);
err_unreserve: err_unreserve:
ttm_bo_unreserve(bo); ttm_bo_unreserve(bo);
...@@ -412,17 +400,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) ...@@ -412,17 +400,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
* Surface framebuffer code * Surface framebuffer code
*/ */
#define vmw_framebuffer_to_vfbs(x) \
container_of(x, struct vmw_framebuffer_surface, base.base)
struct vmw_framebuffer_surface {
struct vmw_framebuffer base;
struct vmw_surface *surface;
struct vmw_dma_buffer *buffer;
struct list_head head;
struct drm_master *master;
};
static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
{ {
struct vmw_framebuffer_surface *vfbs = struct vmw_framebuffer_surface *vfbs =
...@@ -442,153 +419,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) ...@@ -442,153 +419,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
kfree(vfbs); kfree(vfbs);
} }
static int do_surface_dirty_sou(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int inc,
struct vmw_fence_obj **out_fence)
{
struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
struct drm_clip_rect *tmp;
struct drm_crtc *crtc;
size_t fifo_size;
int i, num_units;
int ret = 0; /* silence warning */
int left, right, top, bottom;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdBlitSurfaceToScreen body;
} *cmd;
SVGASignedRect *blits;
num_units = 0;
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
head) {
if (crtc->primary->fb != &framebuffer->base)
continue;
units[num_units++] = vmw_crtc_to_du(crtc);
}
BUG_ON(!clips || !num_clips);
tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
if (unlikely(tmp == NULL)) {
DRM_ERROR("Temporary cliprect memory alloc failed.\n");
return -ENOMEM;
}
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
cmd = kzalloc(fifo_size, GFP_KERNEL);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Temporary fifo memory alloc failed.\n");
ret = -ENOMEM;
goto out_free_tmp;
}
/* setup blits pointer */
blits = (SVGASignedRect *)&cmd[1];
/* initial clip region */
left = clips->x1;
right = clips->x2;
top = clips->y1;
bottom = clips->y2;
/* skip the first clip rect */
for (i = 1, clips_ptr = clips + inc;
i < num_clips; i++, clips_ptr += inc) {
left = min_t(int, left, (int)clips_ptr->x1);
right = max_t(int, right, (int)clips_ptr->x2);
top = min_t(int, top, (int)clips_ptr->y1);
bottom = max_t(int, bottom, (int)clips_ptr->y2);
}
/* only need to do this once */
cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
cmd->body.srcRect.left = left;
cmd->body.srcRect.right = right;
cmd->body.srcRect.top = top;
cmd->body.srcRect.bottom = bottom;
clips_ptr = clips;
for (i = 0; i < num_clips; i++, clips_ptr += inc) {
tmp[i].x1 = clips_ptr->x1 - left;
tmp[i].x2 = clips_ptr->x2 - left;
tmp[i].y1 = clips_ptr->y1 - top;
tmp[i].y2 = clips_ptr->y2 - top;
}
/* do per unit writing, reuse fifo for each */
for (i = 0; i < num_units; i++) {
struct vmw_display_unit *unit = units[i];
struct vmw_clip_rect clip;
int num;
clip.x1 = left - unit->crtc.x;
clip.y1 = top - unit->crtc.y;
clip.x2 = right - unit->crtc.x;
clip.y2 = bottom - unit->crtc.y;
/* skip any crtcs that misses the clip region */
if (clip.x1 >= unit->crtc.mode.hdisplay ||
clip.y1 >= unit->crtc.mode.vdisplay ||
clip.x2 <= 0 || clip.y2 <= 0)
continue;
/*
* In order for the clip rects to be correctly scaled
* the src and dest rects needs to be the same size.
*/
cmd->body.destRect.left = clip.x1;
cmd->body.destRect.right = clip.x2;
cmd->body.destRect.top = clip.y1;
cmd->body.destRect.bottom = clip.y2;
/* create a clip rect of the crtc in dest coords */
clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
clip.x1 = 0 - clip.x1;
clip.y1 = 0 - clip.y1;
/* need to reset sid as it is changed by execbuf */
cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
cmd->body.destScreenId = unit->unit;
/* clip and write blits to cmd stream */
vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
/* if no cliprects hit skip this */
if (num == 0)
continue;
/* only return the last fence */
if (out_fence && *out_fence)
vmw_fence_obj_unreference(out_fence);
/* recalculate package length */
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
}
kfree(cmd);
out_free_tmp:
kfree(tmp);
return ret;
}
static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
struct drm_file *file_priv, struct drm_file *file_priv,
unsigned flags, unsigned color, unsigned flags, unsigned color,
...@@ -604,8 +434,8 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, ...@@ -604,8 +434,8 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
if (unlikely(vfbs->master != file_priv->master)) if (unlikely(vfbs->master != file_priv->master))
return -EINVAL; return -EINVAL;
/* Require ScreenObject support for 3D */ /* Legacy Display Unit does not support 3D */
if (!dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_legacy)
return -EINVAL; return -EINVAL;
drm_modeset_lock_all(dev_priv->dev); drm_modeset_lock_all(dev_priv->dev);
...@@ -627,9 +457,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, ...@@ -627,9 +457,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
inc = 2; /* skip source rects */ inc = 2; /* skip source rects */
} }
ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base, if (dev_priv->active_display_unit == vmw_du_screen_object)
flags, color, ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv,
clips, num_clips, inc, NULL); &vfbs->base,
flags, color,
clips, num_clips,
inc, NULL);
vmw_fifo_flush(dev_priv, false); vmw_fifo_flush(dev_priv, false);
ttm_read_unlock(&dev_priv->reservation_sem); ttm_read_unlock(&dev_priv->reservation_sem);
...@@ -658,8 +491,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ...@@ -658,8 +491,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret; int ret;
/* 3D is only supported on HWv8 hosts which supports screen objects */ /* 3D is only supported on HWv8 and newer hosts */
if (!dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_legacy)
return -ENOSYS; return -ENOSYS;
/* /*
...@@ -693,9 +526,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ...@@ -693,9 +526,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
case 15: case 15:
format = SVGA3D_A1R5G5B5; format = SVGA3D_A1R5G5B5;
break; break;
case 8:
format = SVGA3D_LUMINANCE8;
break;
default: default:
DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth); DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
return -EINVAL; return -EINVAL;
...@@ -753,14 +583,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, ...@@ -753,14 +583,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
* Dmabuf framebuffer code * Dmabuf framebuffer code
*/ */
#define vmw_framebuffer_to_vfbd(x) \
container_of(x, struct vmw_framebuffer_dmabuf, base.base)
struct vmw_framebuffer_dmabuf {
struct vmw_framebuffer base;
struct vmw_dma_buffer *buffer;
};
static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
{ {
struct vmw_framebuffer_dmabuf *vfbd = struct vmw_framebuffer_dmabuf *vfbd =
...@@ -773,180 +595,6 @@ static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) ...@@ -773,180 +595,6 @@ static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
kfree(vfbd); kfree(vfbd);
} }
static int do_dmabuf_dirty_ldu(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int increment)
{
size_t fifo_size;
int i;
struct {
uint32_t header;
SVGAFifoCmdUpdate body;
} *cmd;
fifo_size = sizeof(*cmd) * num_clips;
cmd = vmw_fifo_reserve(dev_priv, fifo_size);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Fifo reserve failed.\n");
return -ENOMEM;
}
memset(cmd, 0, fifo_size);
for (i = 0; i < num_clips; i++, clips += increment) {
cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
cmd[i].body.x = cpu_to_le32(clips->x1);
cmd[i].body.y = cpu_to_le32(clips->y1);
cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1);
cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1);
}
vmw_fifo_commit(dev_priv, fifo_size);
return 0;
}
static int do_dmabuf_define_gmrfb(struct drm_file *file_priv,
struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer)
{
int depth = framebuffer->base.depth;
size_t fifo_size;
int ret;
struct {
uint32_t header;
SVGAFifoCmdDefineGMRFB body;
} *cmd;
/* Emulate RGBA support, contrary to svga_reg.h this is not
* supported by hosts. This is only a problem if we are reading
* this value later and expecting what we uploaded back.
*/
if (depth == 32)
depth = 24;
fifo_size = sizeof(*cmd);
cmd = kmalloc(fifo_size, GFP_KERNEL);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
return -ENOMEM;
}
memset(cmd, 0, fifo_size);
cmd->header = SVGA_CMD_DEFINE_GMRFB;
cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
cmd->body.format.colorDepth = depth;
cmd->body.format.reserved = 0;
cmd->body.bytesPerLine = framebuffer->base.pitches[0];
cmd->body.ptr.gmrId = framebuffer->user_handle;
cmd->body.ptr.offset = 0;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
fifo_size, 0, NULL, NULL);
kfree(cmd);
return ret;
}
static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int increment,
struct vmw_fence_obj **out_fence)
{
struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
int i, k, num_units, ret;
struct drm_crtc *crtc;
size_t fifo_size;
struct {
uint32_t header;
SVGAFifoCmdBlitGMRFBToScreen body;
} *blits;
ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer);
if (unlikely(ret != 0))
return ret; /* define_gmrfb prints warnings */
fifo_size = sizeof(*blits) * num_clips;
blits = kmalloc(fifo_size, GFP_KERNEL);
if (unlikely(blits == NULL)) {
DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
return -ENOMEM;
}
num_units = 0;
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
if (crtc->primary->fb != &framebuffer->base)
continue;
units[num_units++] = vmw_crtc_to_du(crtc);
}
for (k = 0; k < num_units; k++) {
struct vmw_display_unit *unit = units[k];
int hit_num = 0;
clips_ptr = clips;
for (i = 0; i < num_clips; i++, clips_ptr += increment) {
int clip_x1 = clips_ptr->x1 - unit->crtc.x;
int clip_y1 = clips_ptr->y1 - unit->crtc.y;
int clip_x2 = clips_ptr->x2 - unit->crtc.x;
int clip_y2 = clips_ptr->y2 - unit->crtc.y;
int move_x, move_y;
/* skip any crtcs that misses the clip region */
if (clip_x1 >= unit->crtc.mode.hdisplay ||
clip_y1 >= unit->crtc.mode.vdisplay ||
clip_x2 <= 0 || clip_y2 <= 0)
continue;
/* clip size to crtc size */
clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
/* translate both src and dest to bring clip into screen */
move_x = min_t(int, clip_x1, 0);
move_y = min_t(int, clip_y1, 0);
/* actual translate done here */
blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
blits[hit_num].body.destScreenId = unit->unit;
blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
blits[hit_num].body.destRect.left = clip_x1 - move_x;
blits[hit_num].body.destRect.top = clip_y1 - move_y;
blits[hit_num].body.destRect.right = clip_x2;
blits[hit_num].body.destRect.bottom = clip_y2;
hit_num++;
}
/* no clips hit the crtc */
if (hit_num == 0)
continue;
/* only return the last fence */
if (out_fence && *out_fence)
vmw_fence_obj_unreference(out_fence);
fifo_size = sizeof(*blits) * hit_num;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
}
kfree(blits);
return ret;
}
static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
struct drm_file *file_priv, struct drm_file *file_priv,
unsigned flags, unsigned color, unsigned flags, unsigned color,
...@@ -979,13 +627,15 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, ...@@ -979,13 +627,15 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
} }
if (dev_priv->ldu_priv) { if (dev_priv->ldu_priv) {
ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base, ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base,
flags, color, flags, color,
clips, num_clips, increment); clips, num_clips, increment);
} else { } else if (dev_priv->active_display_unit == vmw_du_screen_object) {
ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base, ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv,
flags, color, &vfbd->base,
clips, num_clips, increment, NULL); flags, color,
clips, num_clips, increment,
NULL);
} }
vmw_fifo_flush(dev_priv, false); vmw_fifo_flush(dev_priv, false);
...@@ -1011,8 +661,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) ...@@ -1011,8 +661,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
vmw_framebuffer_to_vfbd(&vfb->base); vmw_framebuffer_to_vfbd(&vfb->base);
int ret; int ret;
/* This code should not be used with screen objects */ /* This code should only be used with Legacy Display Unit */
BUG_ON(dev_priv->sou_priv); BUG_ON(dev_priv->active_display_unit != vmw_du_legacy);
vmw_overlay_pause_all(dev_priv); vmw_overlay_pause_all(dev_priv);
...@@ -1059,7 +709,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, ...@@ -1059,7 +709,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
} }
/* Limited framebuffer color depth support for screen objects */ /* Limited framebuffer color depth support for screen objects */
if (dev_priv->sou_priv) { if (dev_priv->active_display_unit == vmw_du_screen_object) {
switch (mode_cmd->depth) { switch (mode_cmd->depth) {
case 32: case 32:
case 24: case 24:
...@@ -1102,7 +752,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, ...@@ -1102,7 +752,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
vfbd->base.base.depth = mode_cmd->depth; vfbd->base.base.depth = mode_cmd->depth;
vfbd->base.base.width = mode_cmd->width; vfbd->base.base.width = mode_cmd->width;
vfbd->base.base.height = mode_cmd->height; vfbd->base.base.height = mode_cmd->height;
if (!dev_priv->sou_priv) { if (dev_priv->active_display_unit == vmw_du_legacy) {
vfbd->base.pin = vmw_framebuffer_dmabuf_pin; vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
} }
...@@ -1159,7 +809,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, ...@@ -1159,7 +809,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
if (!vmw_kms_validate_mode_vram(dev_priv, if (!vmw_kms_validate_mode_vram(dev_priv,
mode_cmd.pitch, mode_cmd.pitch,
mode_cmd.height)) { mode_cmd.height)) {
DRM_ERROR("VRAM size is too small for requested mode.\n"); DRM_ERROR("Requested mode exceed bounding box limit.\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -1220,7 +870,7 @@ static const struct drm_mode_config_funcs vmw_kms_funcs = { ...@@ -1220,7 +870,7 @@ static const struct drm_mode_config_funcs vmw_kms_funcs = {
.fb_create = vmw_kms_fb_create, .fb_create = vmw_kms_fb_create,
}; };
int vmw_kms_present(struct vmw_private *dev_priv, int vmw_kms_generic_present(struct vmw_private *dev_priv,
struct drm_file *file_priv, struct drm_file *file_priv,
struct vmw_framebuffer *vfb, struct vmw_framebuffer *vfb,
struct vmw_surface *surface, struct vmw_surface *surface,
...@@ -1358,6 +1008,19 @@ int vmw_kms_present(struct vmw_private *dev_priv, ...@@ -1358,6 +1008,19 @@ int vmw_kms_present(struct vmw_private *dev_priv,
return ret; return ret;
} }
int vmw_kms_present(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *vfb,
struct vmw_surface *surface,
uint32_t sid,
int32_t destX, int32_t destY,
struct drm_vmw_rect *clips,
uint32_t num_clips)
{
return vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, sid,
destX, destY, clips, num_clips);
}
int vmw_kms_readback(struct vmw_private *dev_priv, int vmw_kms_readback(struct vmw_private *dev_priv,
struct drm_file *file_priv, struct drm_file *file_priv,
struct vmw_framebuffer *vfb, struct vmw_framebuffer *vfb,
...@@ -1478,26 +1141,29 @@ int vmw_kms_init(struct vmw_private *dev_priv) ...@@ -1478,26 +1141,29 @@ int vmw_kms_init(struct vmw_private *dev_priv)
dev->mode_config.max_width = 8192; dev->mode_config.max_width = 8192;
dev->mode_config.max_height = 8192; dev->mode_config.max_height = 8192;
ret = vmw_kms_init_screen_object_display(dev_priv); ret = vmw_kms_sou_init_display(dev_priv);
if (ret) /* Fallback */ if (ret) /* Fallback */
(void)vmw_kms_init_legacy_display_system(dev_priv); ret = vmw_kms_ldu_init_display(dev_priv);
return 0; return ret;
} }
int vmw_kms_close(struct vmw_private *dev_priv) int vmw_kms_close(struct vmw_private *dev_priv)
{ {
int ret;
/* /*
* Docs says we should take the lock before calling this function * Docs says we should take the lock before calling this function
* but since it destroys encoders and our destructor calls * but since it destroys encoders and our destructor calls
* drm_encoder_cleanup which takes the lock we deadlock. * drm_encoder_cleanup which takes the lock we deadlock.
*/ */
drm_mode_config_cleanup(dev_priv->dev); drm_mode_config_cleanup(dev_priv->dev);
if (dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_screen_object)
vmw_kms_close_screen_object_display(dev_priv); ret = vmw_kms_sou_close_display(dev_priv);
else else
vmw_kms_close_legacy_display_system(dev_priv); ret = vmw_kms_ldu_close_display(dev_priv);
return 0;
return ret;
} }
int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
...@@ -1573,7 +1239,7 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv) ...@@ -1573,7 +1239,7 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); vmw_read(vmw_priv, SVGA_REG_PITCHLOCK);
else if (vmw_fifo_have_pitchlock(vmw_priv)) else if (vmw_fifo_have_pitchlock(vmw_priv))
vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt +
SVGA_FIFO_PITCHLOCK); SVGA_FIFO_PITCHLOCK);
if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
return 0; return 0;
...@@ -1719,75 +1385,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, ...@@ -1719,75 +1385,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
return 0; return 0;
} }
int vmw_du_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
{
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
struct drm_framebuffer *old_fb = crtc->primary->fb;
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
struct drm_file *file_priv ;
struct vmw_fence_obj *fence = NULL;
struct drm_clip_rect clips;
int ret;
if (event == NULL)
return -EINVAL;
/* require ScreenObject support for page flipping */
if (!dev_priv->sou_priv)
return -ENOSYS;
file_priv = event->base.file_priv;
if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
return -EINVAL;
crtc->primary->fb = fb;
/* do a full screen dirty update */
clips.x1 = clips.y1 = 0;
clips.x2 = fb->width;
clips.y2 = fb->height;
if (vfb->dmabuf)
ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb,
0, 0, &clips, 1, 1, &fence);
else
ret = do_surface_dirty_sou(dev_priv, file_priv, vfb,
0, 0, &clips, 1, 1, &fence);
if (ret != 0)
goto out_no_fence;
if (!fence) {
ret = -EINVAL;
goto out_no_fence;
}
ret = vmw_event_fence_action_queue(file_priv, fence,
&event->base,
&event->event.tv_sec,
&event->event.tv_usec,
true);
/*
* No need to hold on to this now. The only cleanup
* we need to do if we fail is unref the fence.
*/
vmw_fence_obj_unreference(&fence);
if (vmw_crtc_to_du(crtc)->is_implicit)
vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc);
return ret;
out_no_fence:
crtc->primary->fb = old_fb;
return ret;
}
void vmw_du_crtc_save(struct drm_crtc *crtc) void vmw_du_crtc_save(struct drm_crtc *crtc)
{ {
} }
...@@ -1958,36 +1555,34 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, ...@@ -1958,36 +1555,34 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
* If using screen objects, then assume 32-bpp because that's what the * If using screen objects, then assume 32-bpp because that's what the
* SVGA device is assuming * SVGA device is assuming
*/ */
if (dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_screen_object)
assumed_bpp = 4; assumed_bpp = 4;
/* Add preferred mode */ /* Add preferred mode */
{ mode = drm_mode_duplicate(dev, &prefmode);
mode = drm_mode_duplicate(dev, &prefmode); if (!mode)
if (!mode) return 0;
return 0; mode->hdisplay = du->pref_width;
mode->hdisplay = du->pref_width; mode->vdisplay = du->pref_height;
mode->vdisplay = du->pref_height; vmw_guess_mode_timing(mode);
vmw_guess_mode_timing(mode);
if (vmw_kms_validate_mode_vram(dev_priv,
mode->hdisplay * assumed_bpp,
mode->vdisplay)) {
drm_mode_probed_add(connector, mode);
} else {
drm_mode_destroy(dev, mode);
mode = NULL;
}
if (du->pref_mode) { if (vmw_kms_validate_mode_vram(dev_priv,
list_del_init(&du->pref_mode->head); mode->hdisplay * assumed_bpp,
drm_mode_destroy(dev, du->pref_mode); mode->vdisplay)) {
} drm_mode_probed_add(connector, mode);
} else {
drm_mode_destroy(dev, mode);
mode = NULL;
}
/* mode might be null here, this is intended */ if (du->pref_mode) {
du->pref_mode = mode; list_del_init(&du->pref_mode->head);
drm_mode_destroy(dev, du->pref_mode);
} }
/* mode might be null here, this is intended */
du->pref_mode = mode;
for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) {
bmode = &vmw_kms_connector_builtin[i]; bmode = &vmw_kms_connector_builtin[i];
if (bmode->hdisplay > max_width || if (bmode->hdisplay > max_width ||
...@@ -2036,6 +1631,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ...@@ -2036,6 +1631,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
int ret; int ret;
int i; int i;
struct drm_mode_config *mode_config = &dev->mode_config; struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_vmw_rect bounding_box = {0};
if (!arg->num_outputs) { if (!arg->num_outputs) {
struct drm_vmw_rect def_rect = {0, 0, 800, 600}; struct drm_vmw_rect def_rect = {0, 0, 800, 600};
...@@ -2066,6 +1662,16 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ...@@ -2066,6 +1662,16 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
ret = -EINVAL; ret = -EINVAL;
goto out_free; goto out_free;
} }
/*
* bounding_box.w and bunding_box.h are used as
* lower-right coordinates
*/
if (rects[i].x + rects[i].w > bounding_box.w)
bounding_box.w = rects[i].x + rects[i].w;
if (rects[i].y + rects[i].h > bounding_box.h)
bounding_box.h = rects[i].y + rects[i].h;
} }
vmw_du_update_layout(dev_priv, arg->num_outputs, rects); vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
......
/************************************************************************** /**************************************************************************
* *
* Copyright © 2009 VMware, Inc., Palo Alto, CA., USA * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -32,11 +32,17 @@ ...@@ -32,11 +32,17 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include "vmwgfx_drv.h" #include "vmwgfx_drv.h"
#define VMWGFX_NUM_DISPLAY_UNITS 8 #define VMWGFX_NUM_DISPLAY_UNITS 8
#define vmw_framebuffer_to_vfb(x) \ #define vmw_framebuffer_to_vfb(x) \
container_of(x, struct vmw_framebuffer, base) container_of(x, struct vmw_framebuffer, base)
#define vmw_framebuffer_to_vfbs(x) \
container_of(x, struct vmw_framebuffer_surface, base.base)
#define vmw_framebuffer_to_vfbd(x) \
container_of(x, struct vmw_framebuffer_dmabuf, base.base)
/** /**
* Base class for framebuffers * Base class for framebuffers
...@@ -53,9 +59,36 @@ struct vmw_framebuffer { ...@@ -53,9 +59,36 @@ struct vmw_framebuffer {
uint32_t user_handle; uint32_t user_handle;
}; };
/*
* Clip rectangle
*/
struct vmw_clip_rect {
int x1, x2, y1, y2;
};
struct vmw_framebuffer_surface {
struct vmw_framebuffer base;
struct vmw_surface *surface;
struct vmw_dma_buffer *buffer;
struct list_head head;
struct drm_master *master;
};
#define vmw_crtc_to_du(x) \
container_of(x, struct vmw_display_unit, crtc) struct vmw_framebuffer_dmabuf {
struct vmw_framebuffer base;
struct vmw_dma_buffer *buffer;
};
/*
* Basic clip rect manipulation
*/
void vmw_clip_cliprects(struct drm_clip_rect *rects,
int num_rects,
struct vmw_clip_rect clip,
SVGASignedRect *out_rects,
int *out_num);
/* /*
* Basic cursor manipulation * Basic cursor manipulation
...@@ -120,11 +153,7 @@ struct vmw_display_unit { ...@@ -120,11 +153,7 @@ struct vmw_display_unit {
/* /*
* Shared display unit functions - vmwgfx_kms.c * Shared display unit functions - vmwgfx_kms.c
*/ */
void vmw_display_unit_cleanup(struct vmw_display_unit *du); void vmw_du_cleanup(struct vmw_display_unit *du);
int vmw_du_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags);
void vmw_du_crtc_save(struct drm_crtc *crtc); void vmw_du_crtc_save(struct drm_crtc *crtc);
void vmw_du_crtc_restore(struct drm_crtc *crtc); void vmw_du_crtc_restore(struct drm_crtc *crtc);
void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
...@@ -148,20 +177,31 @@ int vmw_du_connector_set_property(struct drm_connector *connector, ...@@ -148,20 +177,31 @@ int vmw_du_connector_set_property(struct drm_connector *connector,
/* /*
* Legacy display unit functions - vmwgfx_ldu.c * Legacy display unit functions - vmwgfx_ldu.c
*/ */
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); int vmw_kms_ldu_init_display(struct vmw_private *dev_priv);
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); int vmw_kms_ldu_close_display(struct vmw_private *dev_priv);
int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int increment);
/* /*
* Screen Objects display functions - vmwgfx_scrn.c * Screen Objects display functions - vmwgfx_scrn.c
*/ */
int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv); int vmw_kms_sou_init_display(struct vmw_private *dev_priv);
int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv); int vmw_kms_sou_close_display(struct vmw_private *dev_priv);
int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num, int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
struct drm_vmw_rect *rects); struct drm_file *file_priv,
bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer,
struct drm_crtc *crtc); unsigned flags, unsigned color,
void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, struct drm_clip_rect *clips,
struct drm_crtc *crtc); unsigned num_clips, int inc,
struct vmw_fence_obj **out_fence);
int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv,
struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int increment,
struct vmw_fence_obj **out_fence);
#endif #endif
...@@ -57,7 +57,7 @@ struct vmw_legacy_display_unit { ...@@ -57,7 +57,7 @@ struct vmw_legacy_display_unit {
static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
{ {
list_del_init(&ldu->active); list_del_init(&ldu->active);
vmw_display_unit_cleanup(&ldu->base); vmw_du_cleanup(&ldu->base);
kfree(ldu); kfree(ldu);
} }
...@@ -386,7 +386,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) ...@@ -386,7 +386,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
return 0; return 0;
} }
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
{ {
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
int i, ret; int i, ret;
...@@ -423,6 +423,10 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) ...@@ -423,6 +423,10 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
else else
vmw_ldu_init(dev_priv, 0); vmw_ldu_init(dev_priv, 0);
dev_priv->active_display_unit = vmw_du_legacy;
DRM_INFO("Legacy Display Unit initialized\n");
return 0; return 0;
err_vblank_cleanup: err_vblank_cleanup:
...@@ -433,7 +437,7 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) ...@@ -433,7 +437,7 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
return ret; return ret;
} }
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) int vmw_kms_ldu_close_display(struct vmw_private *dev_priv)
{ {
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
...@@ -448,3 +452,38 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) ...@@ -448,3 +452,38 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
return 0; return 0;
} }
int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int increment)
{
size_t fifo_size;
int i;
struct {
uint32_t header;
SVGAFifoCmdUpdate body;
} *cmd;
fifo_size = sizeof(*cmd) * num_clips;
cmd = vmw_fifo_reserve(dev_priv, fifo_size);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Fifo reserve failed.\n");
return -ENOMEM;
}
memset(cmd, 0, fifo_size);
for (i = 0; i < num_clips; i++, clips += increment) {
cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE);
cmd[i].body.x = cpu_to_le32(clips->x1);
cmd[i].body.y = cpu_to_le32(clips->y1);
cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1);
cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1);
}
vmw_fifo_commit(dev_priv, fifo_size);
return 0;
}
...@@ -100,7 +100,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv, ...@@ -100,7 +100,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv,
{ {
struct vmw_escape_video_flush *flush; struct vmw_escape_video_flush *flush;
size_t fifo_size; size_t fifo_size;
bool have_so = dev_priv->sou_priv ? true : false; bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object);
int i, num_items; int i, num_items;
SVGAGuestPtr ptr; SVGAGuestPtr ptr;
...@@ -231,7 +231,7 @@ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, ...@@ -231,7 +231,7 @@ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv,
if (!pin) if (!pin)
return vmw_dmabuf_unpin(dev_priv, buf, inter); return vmw_dmabuf_unpin(dev_priv, buf, inter);
if (!dev_priv->sou_priv) if (dev_priv->active_display_unit == vmw_du_legacy)
return vmw_dmabuf_to_vram(dev_priv, buf, true, inter); return vmw_dmabuf_to_vram(dev_priv, buf, true, inter);
return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter); return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter);
...@@ -453,7 +453,7 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv) ...@@ -453,7 +453,7 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv)
static bool vmw_overlay_available(const struct vmw_private *dev_priv) static bool vmw_overlay_available(const struct vmw_private *dev_priv)
{ {
return (dev_priv->overlay_priv != NULL && return (dev_priv->overlay_priv != NULL &&
((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) == ((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) ==
VMW_OVERLAY_CAP_MASK)); VMW_OVERLAY_CAP_MASK));
} }
......
/************************************************************************** /**************************************************************************
* *
* Copyright © 2011 VMware, Inc., Palo Alto, CA., USA * Copyright © 2011-2014 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -57,7 +57,7 @@ struct vmw_screen_object_unit { ...@@ -57,7 +57,7 @@ struct vmw_screen_object_unit {
static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
{ {
vmw_display_unit_cleanup(&sou->base); vmw_du_cleanup(&sou->base);
kfree(sou); kfree(sou);
} }
...@@ -72,7 +72,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) ...@@ -72,7 +72,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
} }
static void vmw_sou_del_active(struct vmw_private *vmw_priv, static void vmw_sou_del_active(struct vmw_private *vmw_priv,
struct vmw_screen_object_unit *sou) struct vmw_screen_object_unit *sou)
{ {
struct vmw_screen_object_display *ld = vmw_priv->sou_priv; struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
...@@ -84,8 +84,8 @@ static void vmw_sou_del_active(struct vmw_private *vmw_priv, ...@@ -84,8 +84,8 @@ static void vmw_sou_del_active(struct vmw_private *vmw_priv,
} }
static void vmw_sou_add_active(struct vmw_private *vmw_priv, static void vmw_sou_add_active(struct vmw_private *vmw_priv,
struct vmw_screen_object_unit *sou, struct vmw_screen_object_unit *sou,
struct vmw_framebuffer *vfb) struct vmw_framebuffer *vfb)
{ {
struct vmw_screen_object_display *ld = vmw_priv->sou_priv; struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
...@@ -274,13 +274,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) ...@@ -274,13 +274,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
dev_priv = vmw_priv(crtc->dev); dev_priv = vmw_priv(crtc->dev);
if (set->num_connectors > 1) { if (set->num_connectors > 1) {
DRM_ERROR("to many connectors\n"); DRM_ERROR("Too many connectors\n");
return -EINVAL; return -EINVAL;
} }
if (set->num_connectors == 1 && if (set->num_connectors == 1 &&
set->connectors[0] != &sou->base.connector) { set->connectors[0] != &sou->base.connector) {
DRM_ERROR("connector doesn't match %p %p\n", DRM_ERROR("Connector doesn't match %p %p\n",
set->connectors[0], &sou->base.connector); set->connectors[0], &sou->base.connector);
return -EINVAL; return -EINVAL;
} }
...@@ -391,6 +391,250 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) ...@@ -391,6 +391,250 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
return 0; return 0;
} }
/**
* Returns if this unit can be page flipped.
* Must be called with the mode_config mutex held.
*/
static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv,
struct drm_crtc *crtc)
{
struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
if (!sou->base.is_implicit)
return true;
if (dev_priv->sou_priv->num_implicit != 1)
return false;
return true;
}
/**
* Update the implicit fb to the current fb of this crtc.
* Must be called with the mode_config mutex held.
*/
void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv,
struct drm_crtc *crtc)
{
struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
BUG_ON(!sou->base.is_implicit);
dev_priv->sou_priv->implicit_fb =
vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
}
static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t flags)
{
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
struct drm_framebuffer *old_fb = crtc->primary->fb;
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
struct drm_file *file_priv = event->base.file_priv;
struct vmw_fence_obj *fence = NULL;
struct drm_clip_rect clips;
int ret;
/* require ScreenObject support for page flipping */
if (!dev_priv->sou_priv)
return -ENOSYS;
if (!vmw_sou_screen_object_flippable(dev_priv, crtc))
return -EINVAL;
crtc->primary->fb = fb;
/* do a full screen dirty update */
clips.x1 = clips.y1 = 0;
clips.x2 = fb->width;
clips.y2 = fb->height;
if (vfb->dmabuf)
ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, vfb,
0, 0, &clips, 1, 1, &fence);
else
ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, vfb,
0, 0, &clips, 1, 1, &fence);
if (ret != 0)
goto out_no_fence;
if (!fence) {
ret = -EINVAL;
goto out_no_fence;
}
ret = vmw_event_fence_action_queue(file_priv, fence,
&event->base,
&event->event.tv_sec,
&event->event.tv_usec,
true);
/*
* No need to hold on to this now. The only cleanup
* we need to do if we fail is unref the fence.
*/
vmw_fence_obj_unreference(&fence);
if (vmw_crtc_to_du(crtc)->is_implicit)
vmw_sou_update_implicit_fb(dev_priv, crtc);
return ret;
out_no_fence:
crtc->primary->fb = old_fb;
return ret;
}
int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *framebuffer,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips, int inc,
struct vmw_fence_obj **out_fence)
{
struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
struct drm_clip_rect *tmp;
struct drm_crtc *crtc;
size_t fifo_size;
int i, num_units;
int ret = 0; /* silence warning */
int left, right, top, bottom;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdBlitSurfaceToScreen body;
} *cmd;
SVGASignedRect *blits;
num_units = 0;
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
head) {
if (crtc->primary->fb != &framebuffer->base)
continue;
units[num_units++] = vmw_crtc_to_du(crtc);
}
BUG_ON(!clips || !num_clips);
tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL);
if (unlikely(tmp == NULL)) {
DRM_ERROR("Temporary cliprect memory alloc failed.\n");
return -ENOMEM;
}
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips;
cmd = kzalloc(fifo_size, GFP_KERNEL);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Temporary fifo memory alloc failed.\n");
ret = -ENOMEM;
goto out_free_tmp;
}
/* setup blits pointer */
blits = (SVGASignedRect *)&cmd[1];
/* initial clip region */
left = clips->x1;
right = clips->x2;
top = clips->y1;
bottom = clips->y2;
/* skip the first clip rect */
for (i = 1, clips_ptr = clips + inc;
i < num_clips; i++, clips_ptr += inc) {
left = min_t(int, left, (int)clips_ptr->x1);
right = max_t(int, right, (int)clips_ptr->x2);
top = min_t(int, top, (int)clips_ptr->y1);
bottom = max_t(int, bottom, (int)clips_ptr->y2);
}
/* only need to do this once */
cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN);
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
cmd->body.srcRect.left = left;
cmd->body.srcRect.right = right;
cmd->body.srcRect.top = top;
cmd->body.srcRect.bottom = bottom;
clips_ptr = clips;
for (i = 0; i < num_clips; i++, clips_ptr += inc) {
tmp[i].x1 = clips_ptr->x1 - left;
tmp[i].x2 = clips_ptr->x2 - left;
tmp[i].y1 = clips_ptr->y1 - top;
tmp[i].y2 = clips_ptr->y2 - top;
}
/* do per unit writing, reuse fifo for each */
for (i = 0; i < num_units; i++) {
struct vmw_display_unit *unit = units[i];
struct vmw_clip_rect clip;
int num;
clip.x1 = left - unit->crtc.x;
clip.y1 = top - unit->crtc.y;
clip.x2 = right - unit->crtc.x;
clip.y2 = bottom - unit->crtc.y;
/* skip any crtcs that misses the clip region */
if (clip.x1 >= unit->crtc.mode.hdisplay ||
clip.y1 >= unit->crtc.mode.vdisplay ||
clip.x2 <= 0 || clip.y2 <= 0)
continue;
/*
* In order for the clip rects to be correctly scaled
* the src and dest rects needs to be the same size.
*/
cmd->body.destRect.left = clip.x1;
cmd->body.destRect.right = clip.x2;
cmd->body.destRect.top = clip.y1;
cmd->body.destRect.bottom = clip.y2;
/* create a clip rect of the crtc in dest coords */
clip.x2 = unit->crtc.mode.hdisplay - clip.x1;
clip.y2 = unit->crtc.mode.vdisplay - clip.y1;
clip.x1 = 0 - clip.x1;
clip.y1 = 0 - clip.y1;
/* need to reset sid as it is changed by execbuf */
cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle);
cmd->body.destScreenId = unit->unit;
/* clip and write blits to cmd stream */
vmw_clip_cliprects(tmp, num_clips, clip, blits, &num);
/* if no cliprects hit skip this */
if (num == 0)
continue;
/* only return the last fence */
if (out_fence && *out_fence)
vmw_fence_obj_unreference(out_fence);
/* recalculate package length */
fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num;
cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header));
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
}
kfree(cmd);
out_free_tmp:
kfree(tmp);
return ret;
}
static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.save = vmw_du_crtc_save, .save = vmw_du_crtc_save,
.restore = vmw_du_crtc_restore, .restore = vmw_du_crtc_restore,
...@@ -399,7 +643,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { ...@@ -399,7 +643,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.gamma_set = vmw_du_crtc_gamma_set, .gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_sou_crtc_destroy, .destroy = vmw_sou_crtc_destroy,
.set_config = vmw_sou_crtc_set_config, .set_config = vmw_sou_crtc_set_config,
.page_flip = vmw_du_page_flip, .page_flip = vmw_sou_crtc_page_flip,
}; };
/* /*
...@@ -424,7 +668,7 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector) ...@@ -424,7 +668,7 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector)
vmw_sou_destroy(vmw_connector_to_sou(connector)); vmw_sou_destroy(vmw_connector_to_sou(connector));
} }
static struct drm_connector_funcs vmw_legacy_connector_funcs = { static struct drm_connector_funcs vmw_sou_connector_funcs = {
.dpms = vmw_du_connector_dpms, .dpms = vmw_du_connector_dpms,
.save = vmw_du_connector_save, .save = vmw_du_connector_save,
.restore = vmw_du_connector_restore, .restore = vmw_du_connector_restore,
...@@ -459,7 +703,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) ...@@ -459,7 +703,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
sou->base.pref_mode = NULL; sou->base.pref_mode = NULL;
sou->base.is_implicit = true; sou->base.is_implicit = true;
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL); DRM_MODE_CONNECTOR_VIRTUAL);
connector->status = vmw_du_connector_detect(connector, true); connector->status = vmw_du_connector_detect(connector, true);
...@@ -482,7 +726,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) ...@@ -482,7 +726,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
return 0; return 0;
} }
int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
{ {
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
int i, ret; int i, ret;
...@@ -517,7 +761,9 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) ...@@ -517,7 +761,9 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
vmw_sou_init(dev_priv, i); vmw_sou_init(dev_priv, i);
DRM_INFO("Screen objects system initialized\n"); dev_priv->active_display_unit = vmw_du_screen_object;
DRM_INFO("Screen Objects Display Unit initialized\n");
return 0; return 0;
...@@ -530,7 +776,7 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) ...@@ -530,7 +776,7 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
return ret; return ret;
} }
int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) int vmw_kms_sou_close_display(struct vmw_private *dev_priv)
{ {
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
...@@ -544,35 +790,143 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) ...@@ -544,35 +790,143 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
return 0; return 0;
} }
/** static int do_dmabuf_define_gmrfb(struct drm_file *file_priv,
* Returns if this unit can be page flipped. struct vmw_private *dev_priv,
* Must be called with the mode_config mutex held. struct vmw_framebuffer *framebuffer)
*/
bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv,
struct drm_crtc *crtc)
{ {
struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); int depth = framebuffer->base.depth;
size_t fifo_size;
int ret;
if (!sou->base.is_implicit) struct {
return true; uint32_t header;
SVGAFifoCmdDefineGMRFB body;
} *cmd;
if (dev_priv->sou_priv->num_implicit != 1) /* Emulate RGBA support, contrary to svga_reg.h this is not
return false; * supported by hosts. This is only a problem if we are reading
* this value later and expecting what we uploaded back.
*/
if (depth == 32)
depth = 24;
return true; fifo_size = sizeof(*cmd);
cmd = kmalloc(fifo_size, GFP_KERNEL);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
return -ENOMEM;
}
memset(cmd, 0, fifo_size);
cmd->header = SVGA_CMD_DEFINE_GMRFB;
cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
cmd->body.format.colorDepth = depth;
cmd->body.format.reserved = 0;
cmd->body.bytesPerLine = framebuffer->base.pitches[0];
cmd->body.ptr.gmrId = framebuffer->user_handle;
cmd->body.ptr.offset = 0;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd,
fifo_size, 0, NULL, NULL);
kfree(cmd);
return ret;
} }
/** int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv,
* Update the implicit fb to the current fb of this crtc. struct vmw_private *dev_priv,
* Must be called with the mode_config mutex held. struct vmw_framebuffer *framebuffer,
*/ unsigned flags, unsigned color,
void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, struct drm_clip_rect *clips,
struct drm_crtc *crtc) unsigned num_clips, int increment,
struct vmw_fence_obj **out_fence)
{ {
struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS];
struct drm_clip_rect *clips_ptr;
int i, k, num_units, ret;
struct drm_crtc *crtc;
size_t fifo_size;
BUG_ON(!sou->base.is_implicit); struct {
uint32_t header;
SVGAFifoCmdBlitGMRFBToScreen body;
} *blits;
dev_priv->sou_priv->implicit_fb = ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer);
vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); if (unlikely(ret != 0))
return ret; /* define_gmrfb prints warnings */
fifo_size = sizeof(*blits) * num_clips;
blits = kmalloc(fifo_size, GFP_KERNEL);
if (unlikely(blits == NULL)) {
DRM_ERROR("Failed to allocate temporary cmd buffer.\n");
return -ENOMEM;
}
num_units = 0;
list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
if (crtc->primary->fb != &framebuffer->base)
continue;
units[num_units++] = vmw_crtc_to_du(crtc);
}
for (k = 0; k < num_units; k++) {
struct vmw_display_unit *unit = units[k];
int hit_num = 0;
clips_ptr = clips;
for (i = 0; i < num_clips; i++, clips_ptr += increment) {
int clip_x1 = clips_ptr->x1 - unit->crtc.x;
int clip_y1 = clips_ptr->y1 - unit->crtc.y;
int clip_x2 = clips_ptr->x2 - unit->crtc.x;
int clip_y2 = clips_ptr->y2 - unit->crtc.y;
int move_x, move_y;
/* skip any crtcs that misses the clip region */
if (clip_x1 >= unit->crtc.mode.hdisplay ||
clip_y1 >= unit->crtc.mode.vdisplay ||
clip_x2 <= 0 || clip_y2 <= 0)
continue;
/* clip size to crtc size */
clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay);
clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay);
/* translate both src and dest to bring clip into screen */
move_x = min_t(int, clip_x1, 0);
move_y = min_t(int, clip_y1, 0);
/* actual translate done here */
blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
blits[hit_num].body.destScreenId = unit->unit;
blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x;
blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y;
blits[hit_num].body.destRect.left = clip_x1 - move_x;
blits[hit_num].body.destRect.top = clip_y1 - move_y;
blits[hit_num].body.destRect.right = clip_x2;
blits[hit_num].body.destRect.bottom = clip_y2;
hit_num++;
}
/* no clips hit the crtc */
if (hit_num == 0)
continue;
/* only return the last fence */
if (out_fence && *out_fence)
vmw_fence_obj_unreference(out_fence);
fifo_size = sizeof(*blits) * hit_num;
ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits,
fifo_size, 0, NULL, out_fence);
if (unlikely(ret != 0))
break;
}
kfree(blits);
return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment