Skip to content

Commit 4268269

Browse files
en4bzzackr
authored andcommitted
drm/vmwgfx: Filter modes which exceed graphics memory
SVGA requires individual surfaces to fit within graphics memory (max_mob_pages) which means that modes with a final buffer size that would exceed graphics memory must be pruned otherwise creation will fail. Additionally llvmpipe requires its buffer height and width to be a multiple of its tile size which is 64. As a result we have to anticipate that llvmpipe will round up the mode size passed to it by the compositor when it creates buffers and filter modes where this rounding exceeds graphics memory. This fixes an issue where VMs with low graphics memory (< 64MiB) configured with high resolution mode boot to a black screen because surface creation fails. Fixes: d947d1b ("drm/vmwgfx: Add and connect connector helper function") Signed-off-by: Ian Forbes <[email protected]> Signed-off-by: Zack Rusin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 629f2b4 commit 4268269

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,14 @@
4343
#define vmw_connector_to_stdu(x) \
4444
container_of(x, struct vmw_screen_target_display_unit, base.connector)
4545

46-
46+
/*
47+
* Some renderers such as llvmpipe will align the width and height of their
48+
* buffers to match their tile size. We need to keep this in mind when exposing
49+
* modes to userspace so that this possible over-allocation will not exceed
50+
* graphics memory. 64x64 pixels seems to be a reasonable upper bound for the
51+
* tile size of current renderers.
52+
*/
53+
#define GPU_TILE_SIZE 64
4754

4855
enum stdu_content_type {
4956
SAME_AS_DISPLAY = 0,
@@ -829,7 +836,41 @@ static void vmw_stdu_connector_destroy(struct drm_connector *connector)
829836
vmw_stdu_destroy(vmw_connector_to_stdu(connector));
830837
}
831838

839+
static enum drm_mode_status
840+
vmw_stdu_connector_mode_valid(struct drm_connector *connector,
841+
struct drm_display_mode *mode)
842+
{
843+
enum drm_mode_status ret;
844+
struct drm_device *dev = connector->dev;
845+
struct vmw_private *dev_priv = vmw_priv(dev);
846+
u64 assumed_cpp = dev_priv->assume_16bpp ? 2 : 4;
847+
/* Align width and height to account for GPU tile over-alignment */
848+
u64 required_mem = ALIGN(mode->hdisplay, GPU_TILE_SIZE) *
849+
ALIGN(mode->vdisplay, GPU_TILE_SIZE) *
850+
assumed_cpp;
851+
required_mem = ALIGN(required_mem, PAGE_SIZE);
852+
853+
ret = drm_mode_validate_size(mode, dev_priv->stdu_max_width,
854+
dev_priv->stdu_max_height);
855+
if (ret != MODE_OK)
856+
return ret;
832857

858+
ret = drm_mode_validate_size(mode, dev_priv->texture_max_width,
859+
dev_priv->texture_max_height);
860+
if (ret != MODE_OK)
861+
return ret;
862+
863+
if (required_mem > dev_priv->max_primary_mem)
864+
return MODE_MEM;
865+
866+
if (required_mem > dev_priv->max_mob_pages * PAGE_SIZE)
867+
return MODE_MEM;
868+
869+
if (required_mem > dev_priv->max_mob_size)
870+
return MODE_MEM;
871+
872+
return MODE_OK;
873+
}
833874

834875
static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
835876
.dpms = vmw_du_connector_dpms,
@@ -845,7 +886,7 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
845886
static const struct
846887
drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
847888
.get_modes = vmw_connector_get_modes,
848-
.mode_valid = vmw_connector_mode_valid
889+
.mode_valid = vmw_stdu_connector_mode_valid
849890
};
850891

851892

0 commit comments

Comments
 (0)