diff options
Diffstat (limited to 'vmwgfx')
-rw-r--r-- | vmwgfx/Makefile.am | 26 | ||||
-rw-r--r-- | vmwgfx/svga3d_reg.h | 1801 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_crtc.c | 455 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_ctrl.c | 523 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_ctrl.h | 48 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_dri2.c | 426 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_driver.c | 1200 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_driver.h | 186 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_drm.h | 792 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_drmi.c | 502 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_drmi.h | 87 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_output.c | 393 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_overlay.c | 893 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa.c | 1514 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa.h | 110 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa_priv.h | 125 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_tex_video.c | 855 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_xa_composite.c | 277 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_xa_surface.c | 368 | ||||
-rw-r--r-- | vmwgfx/wsbm_util.h | 79 |
20 files changed, 10660 insertions, 0 deletions
diff --git a/vmwgfx/Makefile.am b/vmwgfx/Makefile.am new file mode 100644 index 0000000..1ee6582 --- /dev/null +++ b/vmwgfx/Makefile.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES = libvmwgfx.la +libvmwgfx_la_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS) @LIBDRM_CFLAGS@ @XATRACKER_CFLAGS@ -I$(top_srcdir)/src -I$(top_srcdir)/saa +libvmwgfx_la_LIBADD = @LIBDRM_LIBS@ $(top_srcdir)/saa/libsaa.la\ + @XATRACKER_LIBS@ +libvmwgfx_la_DEPENDENCIES = $(top_srcdir)/saa/libsaa.la + +libvmwgfx_la_SOURCES = \ + vmwgfx_driver.c \ + vmwgfx_driver.h \ + vmwgfx_crtc.c \ + vmwgfx_output.c \ + vmwgfx_dri2.c \ + vmwgfx_tex_video.c \ + vmwgfx_saa.c \ + vmwgfx_saa.h \ + vmwgfx_drmi.c \ + vmwgfx_drmi.h \ + vmwgfx_overlay.c \ + vmwgfx_ctrl.c \ + vmwgfx_ctrl.h \ + vmwgfx_xa_composite.c \ + vmwgfx_xa_surface.c \ + wsbm_util.h + + + diff --git a/vmwgfx/svga3d_reg.h b/vmwgfx/svga3d_reg.h new file mode 100644 index 0000000..a527d7d --- /dev/null +++ b/vmwgfx/svga3d_reg.h @@ -0,0 +1,1801 @@ +/********************************************************** + * Copyright 1998-2009 VMware, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + **********************************************************/ + +/* + * svga3d_reg.h -- + * + * SVGA 3D hardware definitions + */ + +#ifndef _SVGA3D_REG_H_ +#define _SVGA3D_REG_H_ + +#include "svga_reg.h" + + +/* + * 3D Hardware Version + * + * The hardware version is stored in the SVGA_FIFO_3D_HWVERSION fifo + * register. Is set by the host and read by the guest. This lets + * us make new guest drivers which are backwards-compatible with old + * SVGA hardware revisions. It does not let us support old guest + * drivers. Good enough for now. + * + */ + +#define SVGA3D_MAKE_HWVERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) +#define SVGA3D_MAJOR_HWVERSION(version) ((version) >> 16) +#define SVGA3D_MINOR_HWVERSION(version) ((version) & 0xFF) + +typedef enum { + SVGA3D_HWVERSION_WS5_RC1 = SVGA3D_MAKE_HWVERSION(0, 1), + SVGA3D_HWVERSION_WS5_RC2 = SVGA3D_MAKE_HWVERSION(0, 2), + SVGA3D_HWVERSION_WS51_RC1 = SVGA3D_MAKE_HWVERSION(0, 3), + SVGA3D_HWVERSION_WS6_B1 = SVGA3D_MAKE_HWVERSION(1, 1), + SVGA3D_HWVERSION_FUSION_11 = SVGA3D_MAKE_HWVERSION(1, 4), + SVGA3D_HWVERSION_WS65_B1 = SVGA3D_MAKE_HWVERSION(2, 0), + SVGA3D_HWVERSION_CURRENT = SVGA3D_HWVERSION_WS65_B1, +} SVGA3dHardwareVersion; + +/* + * Generic Types + */ + +typedef uint32 SVGA3dBool; /* 32-bit Bool definition */ +#define SVGA3D_NUM_CLIPPLANES 6 +#define SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS 8 + + +/* + * Surface formats. + * + * If you modify this list, be sure to keep GLUtil.c in sync. It + * includes the internal format definition of each surface in + * GLUtil_ConvertSurfaceFormat, and it contains a table of + * human-readable names in GLUtil_GetFormatName. + */ + +typedef enum SVGA3dSurfaceFormat { + SVGA3D_FORMAT_INVALID = 0, + + SVGA3D_X8R8G8B8 = 1, + SVGA3D_A8R8G8B8 = 2, + + SVGA3D_R5G6B5 = 3, + SVGA3D_X1R5G5B5 = 4, + SVGA3D_A1R5G5B5 = 5, + SVGA3D_A4R4G4B4 = 6, + + SVGA3D_Z_D32 = 7, + SVGA3D_Z_D16 = 8, + SVGA3D_Z_D24S8 = 9, + SVGA3D_Z_D15S1 = 10, + + SVGA3D_LUMINANCE8 = 11, + SVGA3D_LUMINANCE4_ALPHA4 = 12, + SVGA3D_LUMINANCE16 = 13, + SVGA3D_LUMINANCE8_ALPHA8 = 14, + + SVGA3D_DXT1 = 15, + SVGA3D_DXT2 = 16, + SVGA3D_DXT3 = 17, + SVGA3D_DXT4 = 18, + SVGA3D_DXT5 = 19, + + SVGA3D_BUMPU8V8 = 20, + SVGA3D_BUMPL6V5U5 = 21, + SVGA3D_BUMPX8L8V8U8 = 22, + SVGA3D_BUMPL8V8U8 = 23, + + SVGA3D_ARGB_S10E5 = 24, /* 16-bit floating-point ARGB */ + SVGA3D_ARGB_S23E8 = 25, /* 32-bit floating-point ARGB */ + + SVGA3D_A2R10G10B10 = 26, + + /* signed formats */ + SVGA3D_V8U8 = 27, + SVGA3D_Q8W8V8U8 = 28, + SVGA3D_CxV8U8 = 29, + + /* mixed formats */ + SVGA3D_X8L8V8U8 = 30, + SVGA3D_A2W10V10U10 = 31, + + SVGA3D_ALPHA8 = 32, + + /* Single- and dual-component floating point formats */ + SVGA3D_R_S10E5 = 33, + SVGA3D_R_S23E8 = 34, + SVGA3D_RG_S10E5 = 35, + SVGA3D_RG_S23E8 = 36, + + /* + * Any surface can be used as a buffer object, but SVGA3D_BUFFER is + * the most efficient format to use when creating new surfaces + * expressly for index or vertex data. + */ + SVGA3D_BUFFER = 37, + + SVGA3D_Z_D24X8 = 38, + + SVGA3D_V16U16 = 39, + + SVGA3D_G16R16 = 40, + SVGA3D_A16B16G16R16 = 41, + + /* Packed Video formats */ + SVGA3D_UYVY = 42, + SVGA3D_YUY2 = 43, + + SVGA3D_FORMAT_MAX +} SVGA3dSurfaceFormat; + +typedef uint32 SVGA3dColor; /* a, r, g, b */ + +/* + * These match the D3DFORMAT_OP definitions used by Direct3D. We need + * them so that we can query the host for what the supported surface + * operations are (when we're using the D3D backend, in particular), + * and so we can send those operations to the guest. + */ +typedef enum { + SVGA3DFORMAT_OP_TEXTURE = 0x00000001, + SVGA3DFORMAT_OP_VOLUMETEXTURE = 0x00000002, + SVGA3DFORMAT_OP_CUBETEXTURE = 0x00000004, + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET = 0x00000008, + SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET = 0x00000010, + SVGA3DFORMAT_OP_ZSTENCIL = 0x00000040, + SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH = 0x00000080, + +/* + * This format can be used as a render target if the current display mode + * is the same depth if the alpha channel is ignored. e.g. if the device + * can render to A8R8G8B8 when the display mode is X8R8G8B8, then the + * format op list entry for A8R8G8B8 should have this cap. + */ + SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET = 0x00000100, + +/* + * This format contains DirectDraw support (including Flip). This flag + * should not to be set on alpha formats. + */ + SVGA3DFORMAT_OP_DISPLAYMODE = 0x00000400, + +/* + * The rasterizer can support some level of Direct3D support in this format + * and implies that the driver can create a Context in this mode (for some + * render target format). When this flag is set, the SVGA3DFORMAT_OP_DISPLAYMODE + * flag must also be set. + */ + SVGA3DFORMAT_OP_3DACCELERATION = 0x00000800, + +/* + * This is set for a private format when the driver has put the bpp in + * the structure. + */ + SVGA3DFORMAT_OP_PIXELSIZE = 0x00001000, + +/* + * Indicates that this format can be converted to any RGB format for which + * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified + */ + SVGA3DFORMAT_OP_CONVERT_TO_ARGB = 0x00002000, + +/* + * Indicates that this format can be used to create offscreen plain surfaces. + */ + SVGA3DFORMAT_OP_OFFSCREENPLAIN = 0x00004000, + +/* + * Indicated that this format can be read as an SRGB texture (meaning that the + * sampler will linearize the looked up data) + */ + SVGA3DFORMAT_OP_SRGBREAD = 0x00008000, + +/* + * Indicates that this format can be used in the bumpmap instructions + */ + SVGA3DFORMAT_OP_BUMPMAP = 0x00010000, + +/* + * Indicates that this format can be sampled by the displacement map sampler + */ + SVGA3DFORMAT_OP_DMAP = 0x00020000, + +/* + * Indicates that this format cannot be used with texture filtering + */ + SVGA3DFORMAT_OP_NOFILTER = 0x00040000, + +/* + * Indicates that format conversions are supported to this RGB format if + * SVGA3DFORMAT_OP_CONVERT_TO_ARGB is specified in the source format. + */ + SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB = 0x00080000, + +/* + * Indicated that this format can be written as an SRGB target (meaning that the + * pixel pipe will DE-linearize data on output to format) + */ + SVGA3DFORMAT_OP_SRGBWRITE = 0x00100000, + +/* + * Indicates that this format cannot be used with alpha blending + */ + SVGA3DFORMAT_OP_NOALPHABLEND = 0x00200000, + +/* + * Indicates that the device can auto-generated sublevels for resources + * of this format + */ + SVGA3DFORMAT_OP_AUTOGENMIPMAP = 0x00400000, + +/* + * Indicates that this format can be used by vertex texture sampler + */ + SVGA3DFORMAT_OP_VERTEXTEXTURE = 0x00800000, + +/* + * Indicates that this format supports neither texture coordinate wrap + * modes, nor mipmapping + */ + SVGA3DFORMAT_OP_NOTEXCOORDWRAPNORMIP = 0x01000000 +} SVGA3dFormatOp; + +/* + * This structure is a conversion of SVGA3DFORMAT_OP_*. + * Entries must be located at the same position. + */ +typedef union { + uint32 value; + struct { + uint32 texture : 1; + uint32 volumeTexture : 1; + uint32 cubeTexture : 1; + uint32 offscreenRenderTarget : 1; + uint32 sameFormatRenderTarget : 1; + uint32 unknown1 : 1; + uint32 zStencil : 1; + uint32 zStencilArbitraryDepth : 1; + uint32 sameFormatUpToAlpha : 1; + uint32 unknown2 : 1; + uint32 displayMode : 1; + uint32 acceleration3d : 1; + uint32 pixelSize : 1; + uint32 convertToARGB : 1; + uint32 offscreenPlain : 1; + uint32 sRGBRead : 1; + uint32 bumpMap : 1; + uint32 dmap : 1; + uint32 noFilter : 1; + uint32 memberOfGroupARGB : 1; + uint32 sRGBWrite : 1; + uint32 noAlphaBlend : 1; + uint32 autoGenMipMap : 1; + uint32 vertexTexture : 1; + uint32 noTexCoordWrapNorMip : 1; + }; +} SVGA3dSurfaceFormatCaps; + +/* + * SVGA_3D_CMD_SETRENDERSTATE Types. All value types + * must fit in a uint32. + */ + +typedef enum { + SVGA3D_RS_INVALID = 0, + SVGA3D_RS_ZENABLE = 1, /* SVGA3dBool */ + SVGA3D_RS_ZWRITEENABLE = 2, /* SVGA3dBool */ + SVGA3D_RS_ALPHATESTENABLE = 3, /* SVGA3dBool */ + SVGA3D_RS_DITHERENABLE = 4, /* SVGA3dBool */ + SVGA3D_RS_BLENDENABLE = 5, /* SVGA3dBool */ + SVGA3D_RS_FOGENABLE = 6, /* SVGA3dBool */ + SVGA3D_RS_SPECULARENABLE = 7, /* SVGA3dBool */ + SVGA3D_RS_STENCILENABLE = 8, /* SVGA3dBool */ + SVGA3D_RS_LIGHTINGENABLE = 9, /* SVGA3dBool */ + SVGA3D_RS_NORMALIZENORMALS = 10, /* SVGA3dBool */ + SVGA3D_RS_POINTSPRITEENABLE = 11, /* SVGA3dBool */ + SVGA3D_RS_POINTSCALEENABLE = 12, /* SVGA3dBool */ + SVGA3D_RS_STENCILREF = 13, /* uint32 */ + SVGA3D_RS_STENCILMASK = 14, /* uint32 */ + SVGA3D_RS_STENCILWRITEMASK = 15, /* uint32 */ + SVGA3D_RS_FOGSTART = 16, /* float */ + SVGA3D_RS_FOGEND = 17, /* float */ + SVGA3D_RS_FOGDENSITY = 18, /* float */ + SVGA3D_RS_POINTSIZE = 19, /* float */ + SVGA3D_RS_POINTSIZEMIN = 20, /* float */ + SVGA3D_RS_POINTSIZEMAX = 21, /* float */ + SVGA3D_RS_POINTSCALE_A = 22, /* float */ + SVGA3D_RS_POINTSCALE_B = 23, /* float */ + SVGA3D_RS_POINTSCALE_C = 24, /* float */ + SVGA3D_RS_FOGCOLOR = 25, /* SVGA3dColor */ + SVGA3D_RS_AMBIENT = 26, /* SVGA3dColor */ + SVGA3D_RS_CLIPPLANEENABLE = 27, /* SVGA3dClipPlanes */ + SVGA3D_RS_FOGMODE = 28, /* SVGA3dFogMode */ + SVGA3D_RS_FILLMODE = 29, /* SVGA3dFillMode */ + SVGA3D_RS_SHADEMODE = 30, /* SVGA3dShadeMode */ + SVGA3D_RS_LINEPATTERN = 31, /* SVGA3dLinePattern */ + SVGA3D_RS_SRCBLEND = 32, /* SVGA3dBlendOp */ + SVGA3D_RS_DSTBLEND = 33, /* SVGA3dBlendOp */ + SVGA3D_RS_BLENDEQUATION = 34, /* SVGA3dBlendEquation */ + SVGA3D_RS_CULLMODE = 35, /* SVGA3dFace */ + SVGA3D_RS_ZFUNC = 36, /* SVGA3dCmpFunc */ + SVGA3D_RS_ALPHAFUNC = 37, /* SVGA3dCmpFunc */ + SVGA3D_RS_STENCILFUNC = 38, /* SVGA3dCmpFunc */ + SVGA3D_RS_STENCILFAIL = 39, /* SVGA3dStencilOp */ + SVGA3D_RS_STENCILZFAIL = 40, /* SVGA3dStencilOp */ + SVGA3D_RS_STENCILPASS = 41, /* SVGA3dStencilOp */ + SVGA3D_RS_ALPHAREF = 42, /* float (0.0 .. 1.0) */ + SVGA3D_RS_FRONTWINDING = 43, /* SVGA3dFrontWinding */ + SVGA3D_RS_COORDINATETYPE = 44, /* SVGA3dCoordinateType */ + SVGA3D_RS_ZBIAS = 45, /* float */ + SVGA3D_RS_RANGEFOGENABLE = 46, /* SVGA3dBool */ + SVGA3D_RS_COLORWRITEENABLE = 47, /* SVGA3dColorMask */ + SVGA3D_RS_VERTEXMATERIALENABLE = 48, /* SVGA3dBool */ + SVGA3D_RS_DIFFUSEMATERIALSOURCE = 49, /* SVGA3dVertexMaterial */ + SVGA3D_RS_SPECULARMATERIALSOURCE = 50, /* SVGA3dVertexMaterial */ + SVGA3D_RS_AMBIENTMATERIALSOURCE = 51, /* SVGA3dVertexMaterial */ + SVGA3D_RS_EMISSIVEMATERIALSOURCE = 52, /* SVGA3dVertexMaterial */ + SVGA3D_RS_TEXTUREFACTOR = 53, /* SVGA3dColor */ + SVGA3D_RS_LOCALVIEWER = 54, /* SVGA3dBool */ + SVGA3D_RS_SCISSORTESTENABLE = 55, /* SVGA3dBool */ + SVGA3D_RS_BLENDCOLOR = 56, /* SVGA3dColor */ + SVGA3D_RS_STENCILENABLE2SIDED = 57, /* SVGA3dBool */ + SVGA3D_RS_CCWSTENCILFUNC = 58, /* SVGA3dCmpFunc */ + SVGA3D_RS_CCWSTENCILFAIL = 59, /* SVGA3dStencilOp */ + SVGA3D_RS_CCWSTENCILZFAIL = 60, /* SVGA3dStencilOp */ + SVGA3D_RS_CCWSTENCILPASS = 61, /* SVGA3dStencilOp */ + SVGA3D_RS_VERTEXBLEND = 62, /* SVGA3dVertexBlendFlags */ + SVGA3D_RS_SLOPESCALEDEPTHBIAS = 63, /* float */ + SVGA3D_RS_DEPTHBIAS = 64, /* float */ + + + /* + * Output Gamma Level + * + * Output gamma effects the gamma curve of colors that are output from the + * rendering pipeline. A value of 1.0 specifies a linear color space. If the + * value is <= 0.0, gamma correction is ignored and linear color space is + * used. + */ + + SVGA3D_RS_OUTPUTGAMMA = 65, /* float */ + SVGA3D_RS_ZVISIBLE = 66, /* SVGA3dBool */ + SVGA3D_RS_LASTPIXEL = 67, /* SVGA3dBool */ + SVGA3D_RS_CLIPPING = 68, /* SVGA3dBool */ + SVGA3D_RS_WRAP0 = 69, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP1 = 70, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP2 = 71, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP3 = 72, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP4 = 73, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP5 = 74, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP6 = 75, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP7 = 76, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP8 = 77, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP9 = 78, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP10 = 79, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP11 = 80, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP12 = 81, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP13 = 82, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP14 = 83, /* SVGA3dWrapFlags */ + SVGA3D_RS_WRAP15 = 84, /* SVGA3dWrapFlags */ + SVGA3D_RS_MULTISAMPLEANTIALIAS = 85, /* SVGA3dBool */ + SVGA3D_RS_MULTISAMPLEMASK = 86, /* uint32 */ + SVGA3D_RS_INDEXEDVERTEXBLENDENABLE = 87, /* SVGA3dBool */ + SVGA3D_RS_TWEENFACTOR = 88, /* float */ + SVGA3D_RS_ANTIALIASEDLINEENABLE = 89, /* SVGA3dBool */ + SVGA3D_RS_COLORWRITEENABLE1 = 90, /* SVGA3dColorMask */ + SVGA3D_RS_COLORWRITEENABLE2 = 91, /* SVGA3dColorMask */ + SVGA3D_RS_COLORWRITEENABLE3 = 92, /* SVGA3dColorMask */ + SVGA3D_RS_SEPARATEALPHABLENDENABLE = 93, /* SVGA3dBool */ + SVGA3D_RS_SRCBLENDALPHA = 94, /* SVGA3dBlendOp */ + SVGA3D_RS_DSTBLENDALPHA = 95, /* SVGA3dBlendOp */ + SVGA3D_RS_BLENDEQUATIONALPHA = 96, /* SVGA3dBlendEquation */ + SVGA3D_RS_MAX +} SVGA3dRenderStateName; + +typedef enum { + SVGA3D_VERTEXMATERIAL_NONE = 0, /* Use the value in the current material */ + SVGA3D_VERTEXMATERIAL_DIFFUSE = 1, /* Use the value in the diffuse component */ + SVGA3D_VERTEXMATERIAL_SPECULAR = 2, /* Use the value in the specular component */ +} SVGA3dVertexMaterial; + +typedef enum { + SVGA3D_FILLMODE_INVALID = 0, + SVGA3D_FILLMODE_POINT = 1, + SVGA3D_FILLMODE_LINE = 2, + SVGA3D_FILLMODE_FILL = 3, + SVGA3D_FILLMODE_MAX +} SVGA3dFillModeType; + + +typedef +union { + struct { + uint16 mode; /* SVGA3dFillModeType */ + uint16 face; /* SVGA3dFace */ + }; + uint32 uintValue; +} SVGA3dFillMode; + +typedef enum { + SVGA3D_SHADEMODE_INVALID = 0, + SVGA3D_SHADEMODE_FLAT = 1, + SVGA3D_SHADEMODE_SMOOTH = 2, + SVGA3D_SHADEMODE_PHONG = 3, /* Not supported */ + SVGA3D_SHADEMODE_MAX +} SVGA3dShadeMode; + +typedef +union { + struct { + uint16 repeat; + uint16 pattern; + }; + uint32 uintValue; +} SVGA3dLinePattern; + +typedef enum { + SVGA3D_BLENDOP_INVALID = 0, + SVGA3D_BLENDOP_ZERO = 1, + SVGA3D_BLENDOP_ONE = 2, + SVGA3D_BLENDOP_SRCCOLOR = 3, + SVGA3D_BLENDOP_INVSRCCOLOR = 4, + SVGA3D_BLENDOP_SRCALPHA = 5, + SVGA3D_BLENDOP_INVSRCALPHA = 6, + SVGA3D_BLENDOP_DESTALPHA = 7, + SVGA3D_BLENDOP_INVDESTALPHA = 8, + SVGA3D_BLENDOP_DESTCOLOR = 9, + SVGA3D_BLENDOP_INVDESTCOLOR = 10, + SVGA3D_BLENDOP_SRCALPHASAT = 11, + SVGA3D_BLENDOP_BLENDFACTOR = 12, + SVGA3D_BLENDOP_INVBLENDFACTOR = 13, + SVGA3D_BLENDOP_MAX +} SVGA3dBlendOp; + +typedef enum { + SVGA3D_BLENDEQ_INVALID = 0, + SVGA3D_BLENDEQ_ADD = 1, + SVGA3D_BLENDEQ_SUBTRACT = 2, + SVGA3D_BLENDEQ_REVSUBTRACT = 3, + SVGA3D_BLENDEQ_MINIMUM = 4, + SVGA3D_BLENDEQ_MAXIMUM = 5, + SVGA3D_BLENDEQ_MAX +} SVGA3dBlendEquation; + +typedef enum { + SVGA3D_FRONTWINDING_INVALID = 0, + SVGA3D_FRONTWINDING_CW = 1, + SVGA3D_FRONTWINDING_CCW = 2, + SVGA3D_FRONTWINDING_MAX +} SVGA3dFrontWinding; + +typedef enum { + SVGA3D_FACE_INVALID = 0, + SVGA3D_FACE_NONE = 1, + SVGA3D_FACE_FRONT = 2, + SVGA3D_FACE_BACK = 3, + SVGA3D_FACE_FRONT_BACK = 4, + SVGA3D_FACE_MAX +} SVGA3dFace; + +/* + * The order and the values should not be changed + */ + +typedef enum { + SVGA3D_CMP_INVALID = 0, + SVGA3D_CMP_NEVER = 1, + SVGA3D_CMP_LESS = 2, + SVGA3D_CMP_EQUAL = 3, + SVGA3D_CMP_LESSEQUAL = 4, + SVGA3D_CMP_GREATER = 5, + SVGA3D_CMP_NOTEQUAL = 6, + SVGA3D_CMP_GREATEREQUAL = 7, + SVGA3D_CMP_ALWAYS = 8, + SVGA3D_CMP_MAX +} SVGA3dCmpFunc; + +/* + * SVGA3D_FOGFUNC_* specifies the fog equation, or PER_VERTEX which allows + * the fog factor to be specified in the alpha component of the specular + * (a.k.a. secondary) vertex color. + */ +typedef enum { + SVGA3D_FOGFUNC_INVALID = 0, + SVGA3D_FOGFUNC_EXP = 1, + SVGA3D_FOGFUNC_EXP2 = 2, + SVGA3D_FOGFUNC_LINEAR = 3, + SVGA3D_FOGFUNC_PER_VERTEX = 4 +} SVGA3dFogFunction; + +/* + * SVGA3D_FOGTYPE_* specifies if fog factors are computed on a per-vertex + * or per-pixel basis. + */ +typedef enum { + SVGA3D_FOGTYPE_INVALID = 0, + SVGA3D_FOGTYPE_VERTEX = 1, + SVGA3D_FOGTYPE_PIXEL = 2, + SVGA3D_FOGTYPE_MAX = 3 +} SVGA3dFogType; + +/* + * SVGA3D_FOGBASE_* selects depth or range-based fog. Depth-based fog is + * computed using the eye Z value of each pixel (or vertex), whereas range- + * based fog is computed using the actual distance (range) to the eye. + */ +typedef enum { + SVGA3D_FOGBASE_INVALID = 0, + SVGA3D_FOGBASE_DEPTHBASED = 1, + SVGA3D_FOGBASE_RANGEBASED = 2, + SVGA3D_FOGBASE_MAX = 3 +} SVGA3dFogBase; + +typedef enum { + SVGA3D_STENCILOP_INVALID = 0, + SVGA3D_STENCILOP_KEEP = 1, + SVGA3D_STENCILOP_ZERO = 2, + SVGA3D_STENCILOP_REPLACE = 3, + SVGA3D_STENCILOP_INCRSAT = 4, + SVGA3D_STENCILOP_DECRSAT = 5, + SVGA3D_STENCILOP_INVERT = 6, + SVGA3D_STENCILOP_INCR = 7, + SVGA3D_STENCILOP_DECR = 8, + SVGA3D_STENCILOP_MAX +} SVGA3dStencilOp; + +typedef enum { + SVGA3D_CLIPPLANE_0 = (1 << 0), + SVGA3D_CLIPPLANE_1 = (1 << 1), + SVGA3D_CLIPPLANE_2 = (1 << 2), + SVGA3D_CLIPPLANE_3 = (1 << 3), + SVGA3D_CLIPPLANE_4 = (1 << 4), + SVGA3D_CLIPPLANE_5 = (1 << 5), +} SVGA3dClipPlanes; + +typedef enum { + SVGA3D_CLEAR_COLOR = 0x1, + SVGA3D_CLEAR_DEPTH = 0x2, + SVGA3D_CLEAR_STENCIL = 0x4 +} SVGA3dClearFlag; + +typedef enum { + SVGA3D_RT_DEPTH = 0, + SVGA3D_RT_STENCIL = 1, + SVGA3D_RT_COLOR0 = 2, + SVGA3D_RT_COLOR1 = 3, + SVGA3D_RT_COLOR2 = 4, + SVGA3D_RT_COLOR3 = 5, + SVGA3D_RT_COLOR4 = 6, + SVGA3D_RT_COLOR5 = 7, + SVGA3D_RT_COLOR6 = 8, + SVGA3D_RT_COLOR7 = 9, + SVGA3D_RT_MAX, + SVGA3D_RT_INVALID = ((uint32)-1), +} SVGA3dRenderTargetType; + +#define SVGA3D_MAX_RT_COLOR (SVGA3D_RT_COLOR7 - SVGA3D_RT_COLOR0 + 1) + +typedef +union { + struct { + uint32 red : 1; + uint32 green : 1; + uint32 blue : 1; + uint32 alpha : 1; + }; + uint32 uintValue; +} SVGA3dColorMask; + +typedef enum { + SVGA3D_VBLEND_DISABLE = 0, + SVGA3D_VBLEND_1WEIGHT = 1, + SVGA3D_VBLEND_2WEIGHT = 2, + SVGA3D_VBLEND_3WEIGHT = 3, +} SVGA3dVertexBlendFlags; + +typedef enum { + SVGA3D_WRAPCOORD_0 = 1 << 0, + SVGA3D_WRAPCOORD_1 = 1 << 1, + SVGA3D_WRAPCOORD_2 = 1 << 2, + SVGA3D_WRAPCOORD_3 = 1 << 3, + SVGA3D_WRAPCOORD_ALL = 0xF, +} SVGA3dWrapFlags; + +/* + * SVGA_3D_CMD_TEXTURESTATE Types. All value types + * must fit in a uint32. + */ + +typedef enum { + SVGA3D_TS_INVALID = 0, + SVGA3D_TS_BIND_TEXTURE = 1, /* SVGA3dSurfaceId */ + SVGA3D_TS_COLOROP = 2, /* SVGA3dTextureCombiner */ + SVGA3D_TS_COLORARG1 = 3, /* SVGA3dTextureArgData */ + SVGA3D_TS_COLORARG2 = 4, /* SVGA3dTextureArgData */ + SVGA3D_TS_ALPHAOP = 5, /* SVGA3dTextureCombiner */ + SVGA3D_TS_ALPHAARG1 = 6, /* SVGA3dTextureArgData */ + SVGA3D_TS_ALPHAARG2 = 7, /* SVGA3dTextureArgData */ + SVGA3D_TS_ADDRESSU = 8, /* SVGA3dTextureAddress */ + SVGA3D_TS_ADDRESSV = 9, /* SVGA3dTextureAddress */ + SVGA3D_TS_MIPFILTER = 10, /* SVGA3dTextureFilter */ + SVGA3D_TS_MAGFILTER = 11, /* SVGA3dTextureFilter */ + SVGA3D_TS_MINFILTER = 12, /* SVGA3dTextureFilter */ + SVGA3D_TS_BORDERCOLOR = 13, /* SVGA3dColor */ + SVGA3D_TS_TEXCOORDINDEX = 14, /* uint32 */ + SVGA3D_TS_TEXTURETRANSFORMFLAGS = 15, /* SVGA3dTexTransformFlags */ + SVGA3D_TS_TEXCOORDGEN = 16, /* SVGA3dTextureCoordGen */ + SVGA3D_TS_BUMPENVMAT00 = 17, /* float */ + SVGA3D_TS_BUMPENVMAT01 = 18, /* float */ + SVGA3D_TS_BUMPENVMAT10 = 19, /* float */ + SVGA3D_TS_BUMPENVMAT11 = 20, /* float */ + SVGA3D_TS_TEXTURE_MIPMAP_LEVEL = 21, /* uint32 */ + SVGA3D_TS_TEXTURE_LOD_BIAS = 22, /* float */ + SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL = 23, /* uint32 */ + SVGA3D_TS_ADDRESSW = 24, /* SVGA3dTextureAddress */ + + + /* + * Sampler Gamma Level + * + * Sampler gamma effects the color of samples taken from the sampler. A + * value of 1.0 will produce linear samples. If the value is <= 0.0 the + * gamma value is ignored and a linear space is used. + */ + + SVGA3D_TS_GAMMA = 25, /* float */ + SVGA3D_TS_BUMPENVLSCALE = 26, /* float */ + SVGA3D_TS_BUMPENVLOFFSET = 27, /* float */ + SVGA3D_TS_COLORARG0 = 28, /* SVGA3dTextureArgData */ + SVGA3D_TS_ALPHAARG0 = 29, /* SVGA3dTextureArgData */ + SVGA3D_TS_MAX +} SVGA3dTextureStateName; + +typedef enum { + SVGA3D_TC_INVALID = 0, + SVGA3D_TC_DISABLE = 1, + SVGA3D_TC_SELECTARG1 = 2, + SVGA3D_TC_SELECTARG2 = 3, + SVGA3D_TC_MODULATE = 4, + SVGA3D_TC_ADD = 5, + SVGA3D_TC_ADDSIGNED = 6, + SVGA3D_TC_SUBTRACT = 7, + SVGA3D_TC_BLENDTEXTUREALPHA = 8, + SVGA3D_TC_BLENDDIFFUSEALPHA = 9, + SVGA3D_TC_BLENDCURRENTALPHA = 10, + SVGA3D_TC_BLENDFACTORALPHA = 11, + SVGA3D_TC_MODULATE2X = 12, + SVGA3D_TC_MODULATE4X = 13, + SVGA3D_TC_DSDT = 14, + SVGA3D_TC_DOTPRODUCT3 = 15, + SVGA3D_TC_BLENDTEXTUREALPHAPM = 16, + SVGA3D_TC_ADDSIGNED2X = 17, + SVGA3D_TC_ADDSMOOTH = 18, + SVGA3D_TC_PREMODULATE = 19, + SVGA3D_TC_MODULATEALPHA_ADDCOLOR = 20, + SVGA3D_TC_MODULATECOLOR_ADDALPHA = 21, + SVGA3D_TC_MODULATEINVALPHA_ADDCOLOR = 22, + SVGA3D_TC_MODULATEINVCOLOR_ADDALPHA = 23, + SVGA3D_TC_BUMPENVMAPLUMINANCE = 24, + SVGA3D_TC_MULTIPLYADD = 25, + SVGA3D_TC_LERP = 26, + SVGA3D_TC_MAX +} SVGA3dTextureCombiner; + +#define SVGA3D_TC_CAP_BIT(svga3d_tc_op) (svga3d_tc_op ? (1 << (svga3d_tc_op - 1)) : 0) + +typedef enum { + SVGA3D_TEX_ADDRESS_INVALID = 0, + SVGA3D_TEX_ADDRESS_WRAP = 1, + SVGA3D_TEX_ADDRESS_MIRROR = 2, + SVGA3D_TEX_ADDRESS_CLAMP = 3, + SVGA3D_TEX_ADDRESS_BORDER = 4, + SVGA3D_TEX_ADDRESS_MIRRORONCE = 5, + SVGA3D_TEX_ADDRESS_EDGE = 6, + SVGA3D_TEX_ADDRESS_MAX +} SVGA3dTextureAddress; + +/* + * SVGA3D_TEX_FILTER_NONE as the minification filter means mipmapping is + * disabled, and the rasterizer should use the magnification filter instead. + */ +typedef enum { + SVGA3D_TEX_FILTER_NONE = 0, + SVGA3D_TEX_FILTER_NEAREST = 1, + SVGA3D_TEX_FILTER_LINEAR = 2, + SVGA3D_TEX_FILTER_ANISOTROPIC = 3, + SVGA3D_TEX_FILTER_FLATCUBIC = 4, // Deprecated, not implemented + SVGA3D_TEX_FILTER_GAUSSIANCUBIC = 5, // Deprecated, not implemented + SVGA3D_TEX_FILTER_PYRAMIDALQUAD = 6, // Not currently implemented + SVGA3D_TEX_FILTER_GAUSSIANQUAD = 7, // Not currently implemented + SVGA3D_TEX_FILTER_MAX +} SVGA3dTextureFilter; + +typedef enum { + SVGA3D_TEX_TRANSFORM_OFF = 0, + SVGA3D_TEX_TRANSFORM_S = (1 << 0), + SVGA3D_TEX_TRANSFORM_T = (1 << 1), + SVGA3D_TEX_TRANSFORM_R = (1 << 2), + SVGA3D_TEX_TRANSFORM_Q = (1 << 3), + SVGA3D_TEX_PROJECTED = (1 << 15), +} SVGA3dTexTransformFlags; + +typedef enum { + SVGA3D_TEXCOORD_GEN_OFF = 0, + SVGA3D_TEXCOORD_GEN_EYE_POSITION = 1, + SVGA3D_TEXCOORD_GEN_EYE_NORMAL = 2, + SVGA3D_TEXCOORD_GEN_REFLECTIONVECTOR = 3, + SVGA3D_TEXCOORD_GEN_SPHERE = 4, + SVGA3D_TEXCOORD_GEN_MAX +} SVGA3dTextureCoordGen; + +/* + * Texture argument constants for texture combiner + */ +typedef enum { + SVGA3D_TA_INVALID = 0, + SVGA3D_TA_CONSTANT = 1, + SVGA3D_TA_PREVIOUS = 2, + SVGA3D_TA_DIFFUSE = 3, + SVGA3D_TA_TEXTURE = 4, + SVGA3D_TA_SPECULAR = 5, + SVGA3D_TA_MAX +} SVGA3dTextureArgData; + +#define SVGA3D_TM_MASK_LEN 4 + +/* Modifiers for texture argument constants defined above. */ +typedef enum { + SVGA3D_TM_NONE = 0, + SVGA3D_TM_ALPHA = (1 << SVGA3D_TM_MASK_LEN), + SVGA3D_TM_ONE_MINUS = (2 << SVGA3D_TM_MASK_LEN), +} SVGA3dTextureArgModifier; + +#define SVGA3D_INVALID_ID ((uint32)-1) +#define SVGA3D_MAX_CLIP_PLANES 6 + +/* + * This is the limit to the number of fixed-function texture + * transforms and texture coordinates we can support. It does *not* + * correspond to the number of texture image units (samplers) we + * support! + */ +#define SVGA3D_MAX_TEXTURE_COORDS 8 + +/* + * Vertex declarations + * + * Notes: + * + * SVGA3D_DECLUSAGE_POSITIONT is for pre-transformed vertices. If you + * draw with any POSITIONT vertex arrays, the programmable vertex + * pipeline will be implicitly disabled. Drawing will take place as if + * no vertex shader was bound. + */ + +typedef enum { + SVGA3D_DECLUSAGE_POSITION = 0, + SVGA3D_DECLUSAGE_BLENDWEIGHT, // 1 + SVGA3D_DECLUSAGE_BLENDINDICES, // 2 + SVGA3D_DECLUSAGE_NORMAL, // 3 + SVGA3D_DECLUSAGE_PSIZE, // 4 + SVGA3D_DECLUSAGE_TEXCOORD, // 5 + SVGA3D_DECLUSAGE_TANGENT, // 6 + SVGA3D_DECLUSAGE_BINORMAL, // 7 + SVGA3D_DECLUSAGE_TESSFACTOR, // 8 + SVGA3D_DECLUSAGE_POSITIONT, // 9 + SVGA3D_DECLUSAGE_COLOR, // 10 + SVGA3D_DECLUSAGE_FOG, // 11 + SVGA3D_DECLUSAGE_DEPTH, // 12 + SVGA3D_DECLUSAGE_SAMPLE, // 13 + SVGA3D_DECLUSAGE_MAX +} SVGA3dDeclUsage; + +typedef enum { + SVGA3D_DECLMETHOD_DEFAULT = 0, + SVGA3D_DECLMETHOD_PARTIALU, + SVGA3D_DECLMETHOD_PARTIALV, + SVGA3D_DECLMETHOD_CROSSUV, // Normal + SVGA3D_DECLMETHOD_UV, + SVGA3D_DECLMETHOD_LOOKUP, // Lookup a displacement map + SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map +} SVGA3dDeclMethod; + +typedef enum { + SVGA3D_DECLTYPE_FLOAT1 = 0, + SVGA3D_DECLTYPE_FLOAT2 = 1, + SVGA3D_DECLTYPE_FLOAT3 = 2, + SVGA3D_DECLTYPE_FLOAT4 = 3, + SVGA3D_DECLTYPE_D3DCOLOR = 4, + SVGA3D_DECLTYPE_UBYTE4 = 5, + SVGA3D_DECLTYPE_SHORT2 = 6, + SVGA3D_DECLTYPE_SHORT4 = 7, + SVGA3D_DECLTYPE_UBYTE4N = 8, + SVGA3D_DECLTYPE_SHORT2N = 9, + SVGA3D_DECLTYPE_SHORT4N = 10, + SVGA3D_DECLTYPE_USHORT2N = 11, + SVGA3D_DECLTYPE_USHORT4N = 12, + SVGA3D_DECLTYPE_UDEC3 = 13, + SVGA3D_DECLTYPE_DEC3N = 14, + SVGA3D_DECLTYPE_FLOAT16_2 = 15, + SVGA3D_DECLTYPE_FLOAT16_4 = 16, + SVGA3D_DECLTYPE_MAX, +} SVGA3dDeclType; + +/* + * This structure is used for the divisor for geometry instancing; + * it's a direct translation of the Direct3D equivalent. + */ +typedef union { + struct { + /* + * For index data, this number represents the number of instances to draw. + * For instance data, this number represents the number of + * instances/vertex in this stream + */ + uint32 count : 30; + + /* + * This is 1 if this is supposed to be the data that is repeated for + * every instance. + */ + uint32 indexedData : 1; + + /* + * This is 1 if this is supposed to be the per-instance data. + */ + uint32 instanceData : 1; + }; + + uint32 value; +} SVGA3dVertexDivisor; + +typedef enum { + SVGA3D_PRIMITIVE_INVALID = 0, + SVGA3D_PRIMITIVE_TRIANGLELIST = 1, + SVGA3D_PRIMITIVE_POINTLIST = 2, + SVGA3D_PRIMITIVE_LINELIST = 3, + SVGA3D_PRIMITIVE_LINESTRIP = 4, + SVGA3D_PRIMITIVE_TRIANGLESTRIP = 5, + SVGA3D_PRIMITIVE_TRIANGLEFAN = 6, + SVGA3D_PRIMITIVE_MAX +} SVGA3dPrimitiveType; + +typedef enum { + SVGA3D_COORDINATE_INVALID = 0, + SVGA3D_COORDINATE_LEFTHANDED = 1, + SVGA3D_COORDINATE_RIGHTHANDED = 2, + SVGA3D_COORDINATE_MAX +} SVGA3dCoordinateType; + +typedef enum { + SVGA3D_TRANSFORM_INVALID = 0, + SVGA3D_TRANSFORM_WORLD = 1, + SVGA3D_TRANSFORM_VIEW = 2, + SVGA3D_TRANSFORM_PROJECTION = 3, + SVGA3D_TRANSFORM_TEXTURE0 = 4, + SVGA3D_TRANSFORM_TEXTURE1 = 5, + SVGA3D_TRANSFORM_TEXTURE2 = 6, + SVGA3D_TRANSFORM_TEXTURE3 = 7, + SVGA3D_TRANSFORM_TEXTURE4 = 8, + SVGA3D_TRANSFORM_TEXTURE5 = 9, + SVGA3D_TRANSFORM_TEXTURE6 = 10, + SVGA3D_TRANSFORM_TEXTURE7 = 11, + SVGA3D_TRANSFORM_WORLD1 = 12, + SVGA3D_TRANSFORM_WORLD2 = 13, + SVGA3D_TRANSFORM_WORLD3 = 14, + SVGA3D_TRANSFORM_MAX +} SVGA3dTransformType; + +typedef enum { + SVGA3D_LIGHTTYPE_INVALID = 0, + SVGA3D_LIGHTTYPE_POINT = 1, + SVGA3D_LIGHTTYPE_SPOT1 = 2, /* 1-cone, in degrees */ + SVGA3D_LIGHTTYPE_SPOT2 = 3, /* 2-cone, in radians */ + SVGA3D_LIGHTTYPE_DIRECTIONAL = 4, + SVGA3D_LIGHTTYPE_MAX +} SVGA3dLightType; + +typedef enum { + SVGA3D_CUBEFACE_POSX = 0, + SVGA3D_CUBEFACE_NEGX = 1, + SVGA3D_CUBEFACE_POSY = 2, + SVGA3D_CUBEFACE_NEGY = 3, + SVGA3D_CUBEFACE_POSZ = 4, + SVGA3D_CUBEFACE_NEGZ = 5, +} SVGA3dCubeFace; + +typedef enum { + SVGA3D_SHADERTYPE_COMPILED_DX8 = 0, + SVGA3D_SHADERTYPE_VS = 1, + SVGA3D_SHADERTYPE_PS = 2, + SVGA3D_SHADERTYPE_MAX +} SVGA3dShaderType; + +typedef enum { + SVGA3D_CONST_TYPE_FLOAT = 0, + SVGA3D_CONST_TYPE_INT = 1, + SVGA3D_CONST_TYPE_BOOL = 2, +} SVGA3dShaderConstType; + +#define SVGA3D_MAX_SURFACE_FACES 6 + +typedef enum { + SVGA3D_STRETCH_BLT_POINT = 0, + SVGA3D_STRETCH_BLT_LINEAR = 1, + SVGA3D_STRETCH_BLT_MAX +} SVGA3dStretchBltMode; + +typedef enum { + SVGA3D_QUERYTYPE_OCCLUSION = 0, + SVGA3D_QUERYTYPE_MAX +} SVGA3dQueryType; + +typedef enum { + SVGA3D_QUERYSTATE_PENDING = 0, /* Waiting on the host (set by guest) */ + SVGA3D_QUERYSTATE_SUCCEEDED = 1, /* Completed successfully (set by host) */ + SVGA3D_QUERYSTATE_FAILED = 2, /* Completed unsuccessfully (set by host) */ + SVGA3D_QUERYSTATE_NEW = 3, /* Never submitted (For guest use only) */ +} SVGA3dQueryState; + +typedef enum { + SVGA3D_WRITE_HOST_VRAM = 1, + SVGA3D_READ_HOST_VRAM = 2, +} SVGA3dTransferType; + +/* + * The maximum number of vertex arrays we're guaranteed to support in + * SVGA_3D_CMD_DRAWPRIMITIVES. + */ +#define SVGA3D_MAX_VERTEX_ARRAYS 32 + +/* + * The maximum number of primitive ranges we're guaranteed to support + * in SVGA_3D_CMD_DRAWPRIMITIVES. + */ +#define SVGA3D_MAX_DRAW_PRIMITIVE_RANGES 32 + +/* + * Identifiers for commands in the command FIFO. + * + * IDs between 1000 and 1039 (inclusive) were used by obsolete versions of + * the SVGA3D protocol and remain reserved; they should not be used in the + * future. + * + * IDs between 1040 and 1999 (inclusive) are available for use by the + * current SVGA3D protocol. + * + * FIFO clients other than SVGA3D should stay below 1000, or at 2000 + * and up. + */ + +#define SVGA_3D_CMD_LEGACY_BASE 1000 +#define SVGA_3D_CMD_BASE 1040 + +#define SVGA_3D_CMD_SURFACE_DEFINE SVGA_3D_CMD_BASE + 0 +#define SVGA_3D_CMD_SURFACE_DESTROY SVGA_3D_CMD_BASE + 1 +#define SVGA_3D_CMD_SURFACE_COPY SVGA_3D_CMD_BASE + 2 +#define SVGA_3D_CMD_SURFACE_STRETCHBLT SVGA_3D_CMD_BASE + 3 +#define SVGA_3D_CMD_SURFACE_DMA SVGA_3D_CMD_BASE + 4 +#define SVGA_3D_CMD_CONTEXT_DEFINE SVGA_3D_CMD_BASE + 5 +#define SVGA_3D_CMD_CONTEXT_DESTROY SVGA_3D_CMD_BASE + 6 +#define SVGA_3D_CMD_SETTRANSFORM SVGA_3D_CMD_BASE + 7 +#define SVGA_3D_CMD_SETZRANGE SVGA_3D_CMD_BASE + 8 +#define SVGA_3D_CMD_SETRENDERSTATE SVGA_3D_CMD_BASE + 9 +#define SVGA_3D_CMD_SETRENDERTARGET SVGA_3D_CMD_BASE + 10 +#define SVGA_3D_CMD_SETTEXTURESTATE SVGA_3D_CMD_BASE + 11 +#define SVGA_3D_CMD_SETMATERIAL SVGA_3D_CMD_BASE + 12 +#define SVGA_3D_CMD_SETLIGHTDATA SVGA_3D_CMD_BASE + 13 +#define SVGA_3D_CMD_SETLIGHTENABLED SVGA_3D_CMD_BASE + 14 +#define SVGA_3D_CMD_SETVIEWPORT SVGA_3D_CMD_BASE + 15 +#define SVGA_3D_CMD_SETCLIPPLANE SVGA_3D_CMD_BASE + 16 +#define SVGA_3D_CMD_CLEAR SVGA_3D_CMD_BASE + 17 +#define SVGA_3D_CMD_PRESENT SVGA_3D_CMD_BASE + 18 // Deprecated +#define SVGA_3D_CMD_SHADER_DEFINE SVGA_3D_CMD_BASE + 19 +#define SVGA_3D_CMD_SHADER_DESTROY SVGA_3D_CMD_BASE + 20 +#define SVGA_3D_CMD_SET_SHADER SVGA_3D_CMD_BASE + 21 +#define SVGA_3D_CMD_SET_SHADER_CONST SVGA_3D_CMD_BASE + 22 +#define SVGA_3D_CMD_DRAW_PRIMITIVES SVGA_3D_CMD_BASE + 23 +#define SVGA_3D_CMD_SETSCISSORRECT SVGA_3D_CMD_BASE + 24 +#define SVGA_3D_CMD_BEGIN_QUERY SVGA_3D_CMD_BASE + 25 +#define SVGA_3D_CMD_END_QUERY SVGA_3D_CMD_BASE + 26 +#define SVGA_3D_CMD_WAIT_FOR_QUERY SVGA_3D_CMD_BASE + 27 +#define SVGA_3D_CMD_PRESENT_READBACK SVGA_3D_CMD_BASE + 28 // Deprecated +#define SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN SVGA_3D_CMD_BASE + 29 +#define SVGA_3D_CMD_MAX SVGA_3D_CMD_BASE + 30 + +#define SVGA_3D_CMD_FUTURE_MAX 2000 + +/* + * Common substructures used in multiple FIFO commands: + */ + +typedef struct { + union { + struct { + uint16 function; // SVGA3dFogFunction + uint8 type; // SVGA3dFogType + uint8 base; // SVGA3dFogBase + }; + uint32 uintValue; + }; +} SVGA3dFogMode; + +/* + * Uniquely identify one image (a 1D/2D/3D array) from a surface. This + * is a surface ID as well as face/mipmap indices. + */ + +typedef +struct SVGA3dSurfaceImageId { + uint32 sid; + uint32 face; + uint32 mipmap; +} SVGA3dSurfaceImageId; + +typedef +struct SVGA3dGuestImage { + SVGAGuestPtr ptr; + + /* + * A note on interpretation of pitch: This value of pitch is the + * number of bytes between vertically adjacent image + * blocks. Normally this is the number of bytes between the first + * pixel of two adjacent scanlines. With compressed textures, + * however, this may represent the number of bytes between + * compression blocks rather than between rows of pixels. + * + * XXX: Compressed textures currently must be tightly packed in guest memory. + * + * If the image is 1-dimensional, pitch is ignored. + * + * If 'pitch' is zero, the SVGA3D device calculates a pitch value + * assuming each row of blocks is tightly packed. + */ + uint32 pitch; +} SVGA3dGuestImage; + + +/* + * FIFO command format definitions: + */ + +/* + * The data size header following cmdNum for every 3d command + */ +typedef +struct { + uint32 id; + uint32 size; +} SVGA3dCmdHeader; + +/* + * A surface is a hierarchy of host VRAM surfaces: 1D, 2D, or 3D, with + * optional mipmaps and cube faces. + */ + +typedef +struct { + uint32 width; + uint32 height; + uint32 depth; +} SVGA3dSize; + +typedef enum { + SVGA3D_SURFACE_CUBEMAP = (1 << 0), + SVGA3D_SURFACE_HINT_STATIC = (1 << 1), + SVGA3D_SURFACE_HINT_DYNAMIC = (1 << 2), + SVGA3D_SURFACE_HINT_INDEXBUFFER = (1 << 3), + SVGA3D_SURFACE_HINT_VERTEXBUFFER = (1 << 4), + SVGA3D_SURFACE_HINT_TEXTURE = (1 << 5), + SVGA3D_SURFACE_HINT_RENDERTARGET = (1 << 6), + SVGA3D_SURFACE_HINT_DEPTHSTENCIL = (1 << 7), + SVGA3D_SURFACE_HINT_WRITEONLY = (1 << 8), +} SVGA3dSurfaceFlags; + +typedef +struct { + uint32 numMipLevels; +} SVGA3dSurfaceFace; + +typedef +struct { + uint32 sid; + SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurfaceFormat format; + SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES]; + /* + * Followed by an SVGA3dSize structure for each mip level in each face. + * + * A note on surface sizes: Sizes are always specified in pixels, + * even if the true surface size is not a multiple of the minimum + * block size of the surface's format. For example, a 3x3x1 DXT1 + * compressed texture would actually be stored as a 4x4x1 image in + * memory. + */ +} SVGA3dCmdDefineSurface; /* SVGA_3D_CMD_SURFACE_DEFINE */ + +typedef +struct { + uint32 sid; +} SVGA3dCmdDestroySurface; /* SVGA_3D_CMD_SURFACE_DESTROY */ + +typedef +struct { + uint32 cid; +} SVGA3dCmdDefineContext; /* SVGA_3D_CMD_CONTEXT_DEFINE */ + +typedef +struct { + uint32 cid; +} SVGA3dCmdDestroyContext; /* SVGA_3D_CMD_CONTEXT_DESTROY */ + +typedef +struct { + uint32 cid; + SVGA3dClearFlag clearFlag; + uint32 color; + float depth; + uint32 stencil; + /* Followed by variable number of SVGA3dRect structures */ +} SVGA3dCmdClear; /* SVGA_3D_CMD_CLEAR */ + +typedef +struct SVGA3dCopyRect { + uint32 x; + uint32 y; + uint32 w; + uint32 h; + uint32 srcx; + uint32 srcy; +} SVGA3dCopyRect; + +typedef +struct SVGA3dCopyBox { + uint32 x; + uint32 y; + uint32 z; + uint32 w; + uint32 h; + uint32 d; + uint32 srcx; + uint32 srcy; + uint32 srcz; +} SVGA3dCopyBox; + +typedef +struct { + uint32 x; + uint32 y; + uint32 w; + uint32 h; +} SVGA3dRect; + +typedef +struct { + uint32 x; + uint32 y; + uint32 z; + uint32 w; + uint32 h; + uint32 d; +} SVGA3dBox; + +typedef +struct { + uint32 x; + uint32 y; + uint32 z; +} SVGA3dPoint; + +typedef +struct { + SVGA3dLightType type; + SVGA3dBool inWorldSpace; + float diffuse[4]; + float specular[4]; + float ambient[4]; + float position[4]; + float direction[4]; + float range; + float falloff; + float attenuation0; + float attenuation1; + float attenuation2; + float theta; + float phi; +} SVGA3dLightData; + +typedef +struct { + uint32 sid; + /* Followed by variable number of SVGA3dCopyRect structures */ +} SVGA3dCmdPresent; /* SVGA_3D_CMD_PRESENT */ + +typedef +struct { + SVGA3dRenderStateName state; + union { + uint32 uintValue; + float floatValue; + }; +} SVGA3dRenderState; + +typedef +struct { + uint32 cid; + /* Followed by variable number of SVGA3dRenderState structures */ +} SVGA3dCmdSetRenderState; /* SVGA_3D_CMD_SETRENDERSTATE */ + +typedef +struct { + uint32 cid; + SVGA3dRenderTargetType type; + SVGA3dSurfaceImageId target; +} SVGA3dCmdSetRenderTarget; /* SVGA_3D_CMD_SETRENDERTARGET */ + +typedef +struct { + SVGA3dSurfaceImageId src; + SVGA3dSurfaceImageId dest; + /* Followed by variable number of SVGA3dCopyBox structures */ +} SVGA3dCmdSurfaceCopy; /* SVGA_3D_CMD_SURFACE_COPY */ + +typedef +struct { + SVGA3dSurfaceImageId src; + SVGA3dSurfaceImageId dest; + SVGA3dBox boxSrc; + SVGA3dBox boxDest; + SVGA3dStretchBltMode mode; +} SVGA3dCmdSurfaceStretchBlt; /* SVGA_3D_CMD_SURFACE_STRETCHBLT */ + +typedef +struct { + /* + * If the discard flag is present in a surface DMA operation, the host may + * discard the contents of the current mipmap level and face of the target + * surface before applying the surface DMA contents. + */ + uint32 discard : 1; + + /* + * If the unsynchronized flag is present, the host may perform this upload + * without syncing to pending reads on this surface. + */ + uint32 unsynchronized : 1; + + /* + * Guests *MUST* set the reserved bits to 0 before submitting the command + * suffix as future flags may occupy these bits. + */ + uint32 reserved : 30; +} SVGA3dSurfaceDMAFlags; + +typedef +struct { + SVGA3dGuestImage guest; + SVGA3dSurfaceImageId host; + SVGA3dTransferType transfer; + /* + * Followed by variable number of SVGA3dCopyBox structures. For consistency + * in all clipping logic and coordinate translation, we define the + * "source" in each copyBox as the guest image and the + * "destination" as the host image, regardless of transfer + * direction. + * + * For efficiency, the SVGA3D device is free to copy more data than + * specified. For example, it may round copy boxes outwards such + * that they lie on particular alignment boundaries. + */ +} SVGA3dCmdSurfaceDMA; /* SVGA_3D_CMD_SURFACE_DMA */ + +/* + * SVGA3dCmdSurfaceDMASuffix -- + * + * This is a command suffix that will appear after a SurfaceDMA command in + * the FIFO. It contains some extra information that hosts may use to + * optimize performance or protect the guest. This suffix exists to preserve + * backwards compatibility while also allowing for new functionality to be + * implemented. + */ + +typedef +struct { + uint32 suffixSize; + + /* + * The maximum offset is used to determine the maximum offset from the + * guestPtr base address that will be accessed or written to during this + * surfaceDMA. If the suffix is supported, the host will respect this + * boundary while performing surface DMAs. + * + * Defaults to MAX_UINT32 + */ + uint32 maximumOffset; + + /* + * A set of flags that describes optimizations that the host may perform + * while performing this surface DMA operation. The guest should never rely + * on behaviour that is different when these flags are set for correctness. + * + * Defaults to 0 + */ + SVGA3dSurfaceDMAFlags flags; +} SVGA3dCmdSurfaceDMASuffix; + +/* + * SVGA_3D_CMD_DRAW_PRIMITIVES -- + * + * This command is the SVGA3D device's generic drawing entry point. + * It can draw multiple ranges of primitives, optionally using an + * index buffer, using an arbitrary collection of vertex buffers. + * + * Each SVGA3dVertexDecl defines a distinct vertex array to bind + * during this draw call. The declarations specify which surface + * the vertex data lives in, what that vertex data is used for, + * and how to interpret it. + * + * Each SVGA3dPrimitiveRange defines a collection of primitives + * to render using the same vertex arrays. An index buffer is + * optional. + */ + +typedef +struct { + /* + * A range hint is an optional specification for the range of indices + * in an SVGA3dArray that will be used. If 'last' is zero, it is assumed + * that the entire array will be used. + * + * These are only hints. The SVGA3D device may use them for + * performance optimization if possible, but it's also allowed to + * ignore these values. + */ + uint32 first; + uint32 last; +} SVGA3dArrayRangeHint; + +typedef +struct { + /* + * Define the origin and shape of a vertex or index array. Both + * 'offset' and 'stride' are in bytes. The provided surface will be + * reinterpreted as a flat array of bytes in the same format used + * by surface DMA operations. To avoid unnecessary conversions, the + * surface should be created with the SVGA3D_BUFFER format. + * + * Index 0 in the array starts 'offset' bytes into the surface. + * Index 1 begins at byte 'offset + stride', etc. Array indices may + * not be negative. + */ + uint32 surfaceId; + uint32 offset; + uint32 stride; +} SVGA3dArray; + +typedef +struct { + /* + * Describe a vertex array's data type, and define how it is to be + * used by the fixed function pipeline or the vertex shader. It + * isn't useful to have two VertexDecls with the same + * VertexArrayIdentity in one draw call. + */ + SVGA3dDeclType type; + SVGA3dDeclMethod method; + SVGA3dDeclUsage usage; + uint32 usageIndex; +} SVGA3dVertexArrayIdentity; + +typedef +struct { + SVGA3dVertexArrayIdentity identity; + SVGA3dArray array; + SVGA3dArrayRangeHint rangeHint; +} SVGA3dVertexDecl; + +typedef +struct { + /* + * Define a group of primitives to render, from sequential indices. + * + * The value of 'primitiveType' and 'primitiveCount' imply the + * total number of vertices that will be rendered. + */ + SVGA3dPrimitiveType primType; + uint32 primitiveCount; + + /* + * Optional index buffer. If indexArray.surfaceId is + * SVGA3D_INVALID_ID, we render without an index buffer. Rendering + * without an index buffer is identical to rendering with an index + * buffer containing the sequence [0, 1, 2, 3, ...]. + * + * If an index buffer is in use, indexWidth specifies the width in + * bytes of each index value. It must be less than or equal to + * indexArray.stride. + * + * (Currently, the SVGA3D device requires index buffers to be tightly + * packed. In other words, indexWidth == indexArray.stride) + */ + SVGA3dArray indexArray; + uint32 indexWidth; + + /* + * Optional index bias. This number is added to all indices from + * indexArray before they are used as vertex array indices. This + * can be used in multiple ways: + * + * - When not using an indexArray, this bias can be used to + * specify where in the vertex arrays to begin rendering. + * + * - A positive number here is equivalent to increasing the + * offset in each vertex array. + * + * - A negative number can be used to render using a small + * vertex array and an index buffer that contains large + * values. This may be used by some applications that + * crop a vertex buffer without modifying their index + * buffer. + * + * Note that rendering with a negative bias value may be slower and + * use more memory than rendering with a positive or zero bias. + */ + int32 indexBias; +} SVGA3dPrimitiveRange; + +typedef +struct { + uint32 cid; + uint32 numVertexDecls; + uint32 numRanges; + + /* + * There are two variable size arrays after the + * SVGA3dCmdDrawPrimitives structure. In order, + * they are: + * + * 1. SVGA3dVertexDecl, quantity 'numVertexDecls', but no more than + * SVGA3D_MAX_VERTEX_ARRAYS; + * 2. SVGA3dPrimitiveRange, quantity 'numRanges', but no more than + * SVGA3D_MAX_DRAW_PRIMITIVE_RANGES; + * 3. Optionally, SVGA3dVertexDivisor, quantity 'numVertexDecls' (contains + * the frequency divisor for the corresponding vertex decl). + */ +} SVGA3dCmdDrawPrimitives; /* SVGA_3D_CMD_DRAWPRIMITIVES */ + +typedef +struct { + uint32 stage; + SVGA3dTextureStateName name; + union { + uint32 value; + float floatValue; + }; +} SVGA3dTextureState; + +typedef +struct { + uint32 cid; + /* Followed by variable number of SVGA3dTextureState structures */ +} SVGA3dCmdSetTextureState; /* SVGA_3D_CMD_SETTEXTURESTATE */ + +typedef +struct { + uint32 cid; + SVGA3dTransformType type; + float matrix[16]; +} SVGA3dCmdSetTransform; /* SVGA_3D_CMD_SETTRANSFORM */ + +typedef +struct { + float min; + float max; +} SVGA3dZRange; + +typedef +struct { + uint32 cid; + SVGA3dZRange zRange; +} SVGA3dCmdSetZRange; /* SVGA_3D_CMD_SETZRANGE */ + +typedef +struct { + float diffuse[4]; + float ambient[4]; + float specular[4]; + float emissive[4]; + float shininess; +} SVGA3dMaterial; + +typedef +struct { + uint32 cid; + SVGA3dFace face; + SVGA3dMaterial material; +} SVGA3dCmdSetMaterial; /* SVGA_3D_CMD_SETMATERIAL */ + +typedef +struct { + uint32 cid; + uint32 index; + SVGA3dLightData data; +} SVGA3dCmdSetLightData; /* SVGA_3D_CMD_SETLIGHTDATA */ + +typedef +struct { + uint32 cid; + uint32 index; + uint32 enabled; +} SVGA3dCmdSetLightEnabled; /* SVGA_3D_CMD_SETLIGHTENABLED */ + +typedef +struct { + uint32 cid; + SVGA3dRect rect; +} SVGA3dCmdSetViewport; /* SVGA_3D_CMD_SETVIEWPORT */ + +typedef +struct { + uint32 cid; + SVGA3dRect rect; +} SVGA3dCmdSetScissorRect; /* SVGA_3D_CMD_SETSCISSORRECT */ + +typedef +struct { + uint32 cid; + uint32 index; + float plane[4]; +} SVGA3dCmdSetClipPlane; /* SVGA_3D_CMD_SETCLIPPLANE */ + +typedef +struct { + uint32 cid; + uint32 shid; + SVGA3dShaderType type; + /* Followed by variable number of DWORDs for shader bycode */ +} SVGA3dCmdDefineShader; /* SVGA_3D_CMD_SHADER_DEFINE */ + +typedef +struct { + uint32 cid; + uint32 shid; + SVGA3dShaderType type; +} SVGA3dCmdDestroyShader; /* SVGA_3D_CMD_SHADER_DESTROY */ + +typedef +struct { + uint32 cid; + uint32 reg; /* register number */ + SVGA3dShaderType type; + SVGA3dShaderConstType ctype; + uint32 values[4]; +} SVGA3dCmdSetShaderConst; /* SVGA_3D_CMD_SET_SHADER_CONST */ + +typedef +struct { + uint32 cid; + SVGA3dShaderType type; + uint32 shid; +} SVGA3dCmdSetShader; /* SVGA_3D_CMD_SET_SHADER */ + +typedef +struct { + uint32 cid; + SVGA3dQueryType type; +} SVGA3dCmdBeginQuery; /* SVGA_3D_CMD_BEGIN_QUERY */ + +typedef +struct { + uint32 cid; + SVGA3dQueryType type; + SVGAGuestPtr guestResult; /* Points to an SVGA3dQueryResult structure */ +} SVGA3dCmdEndQuery; /* SVGA_3D_CMD_END_QUERY */ + +typedef +struct { + uint32 cid; /* Same parameters passed to END_QUERY */ + SVGA3dQueryType type; + SVGAGuestPtr guestResult; +} SVGA3dCmdWaitForQuery; /* SVGA_3D_CMD_WAIT_FOR_QUERY */ + +typedef +struct { + uint32 totalSize; /* Set by guest before query is ended. */ + SVGA3dQueryState state; /* Set by host or guest. See SVGA3dQueryState. */ + union { /* Set by host on exit from PENDING state */ + uint32 result32; + }; +} SVGA3dQueryResult; + +/* + * SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN -- + * + * This is a blit from an SVGA3D surface to a Screen Object. Just + * like GMR-to-screen blits, this blit may be directed at a + * specific screen or to the virtual coordinate space. + * + * The blit copies from a rectangular region of an SVGA3D surface + * image to a rectangular region of a screen or screens. + * + * This command takes an optional variable-length list of clipping + * rectangles after the body of the command. If no rectangles are + * specified, there is no clipping region. The entire destRect is + * drawn to. If one or more rectangles are included, they describe + * a clipping region. The clip rectangle coordinates are measured + * relative to the top-left corner of destRect. + * + * This clipping region serves multiple purposes: + * + * - It can be used to perform an irregularly shaped blit more + * efficiently than by issuing many separate blit commands. + * + * - It is equivalent to allowing blits with non-integer + * source coordinates. You could blit just one half-pixel + * of a source, for example, by specifying a larger + * destination rectangle than you need, then removing + * part of it using a clip rectangle. + * + * Availability: + * SVGA_FIFO_CAP_SCREEN_OBJECT + * + * Limitations: + * + * - Currently, no backend supports blits from a mipmap or face + * other than the first one. + */ + +typedef +struct { + SVGA3dSurfaceImageId srcImage; + SVGASignedRect srcRect; + uint32 destScreenId; /* Screen ID or SVGA_ID_INVALID for virt. coords */ + SVGASignedRect destRect; /* Supports scaling if src/rest different size */ + /* Clipping: zero or more SVGASignedRects follow */ +} SVGA3dCmdBlitSurfaceToScreen; /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */ + + +/* + * Capability query index. + * + * Notes: + * + * 1. SVGA3D_DEVCAP_MAX_TEXTURES reflects the maximum number of + * fixed-function texture units available. Each of these units + * work in both FFP and Shader modes, and they support texture + * transforms and texture coordinates. The host may have additional + * texture image units that are only usable with shaders. + * + * 2. The BUFFER_FORMAT capabilities are deprecated, and they always + * return TRUE. Even on physical hardware that does not support + * these formats natively, the SVGA3D device will provide an emulation + * which should be invisible to the guest OS. + * + * In general, the SVGA3D device should support any operation on + * any surface format, it just may perform some of these + * operations in software depending on the capabilities of the + * available physical hardware. + * + * XXX: In the future, we will add capabilities that describe in + * detail what formats are supported in hardware for what kinds + * of operations. + */ + +typedef enum { + SVGA3D_DEVCAP_3D = 0, + SVGA3D_DEVCAP_MAX_LIGHTS = 1, + SVGA3D_DEVCAP_MAX_TEXTURES = 2, /* See note (1) */ + SVGA3D_DEVCAP_MAX_CLIP_PLANES = 3, + SVGA3D_DEVCAP_VERTEX_SHADER_VERSION = 4, + SVGA3D_DEVCAP_VERTEX_SHADER = 5, + SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION = 6, + SVGA3D_DEVCAP_FRAGMENT_SHADER = 7, + SVGA3D_DEVCAP_MAX_RENDER_TARGETS = 8, + SVGA3D_DEVCAP_S23E8_TEXTURES = 9, + SVGA3D_DEVCAP_S10E5_TEXTURES = 10, + SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND = 11, + SVGA3D_DEVCAP_D16_BUFFER_FORMAT = 12, /* See note (2) */ + SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT = 13, /* See note (2) */ + SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT = 14, /* See note (2) */ + SVGA3D_DEVCAP_QUERY_TYPES = 15, + SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING = 16, + SVGA3D_DEVCAP_MAX_POINT_SIZE = 17, + SVGA3D_DEVCAP_MAX_SHADER_TEXTURES = 18, + SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH = 19, + SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT = 20, + SVGA3D_DEVCAP_MAX_VOLUME_EXTENT = 21, + SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT = 22, + SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO = 23, + SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY = 24, + SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT = 25, + SVGA3D_DEVCAP_MAX_VERTEX_INDEX = 26, + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS = 27, + SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS = 28, + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS = 29, + SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS = 30, + SVGA3D_DEVCAP_TEXTURE_OPS = 31, + SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8 = 32, + SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8 = 33, + SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10 = 34, + SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5 = 35, + SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5 = 36, + SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4 = 37, + SVGA3D_DEVCAP_SURFACEFMT_R5G6B5 = 38, + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16 = 39, + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8 = 40, + SVGA3D_DEVCAP_SURFACEFMT_ALPHA8 = 41, + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8 = 42, + SVGA3D_DEVCAP_SURFACEFMT_Z_D16 = 43, + SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8 = 44, + SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8 = 45, + SVGA3D_DEVCAP_SURFACEFMT_DXT1 = 46, + SVGA3D_DEVCAP_SURFACEFMT_DXT2 = 47, + SVGA3D_DEVCAP_SURFACEFMT_DXT3 = 48, + SVGA3D_DEVCAP_SURFACEFMT_DXT4 = 49, + SVGA3D_DEVCAP_SURFACEFMT_DXT5 = 50, + SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8 = 51, + SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10 = 52, + SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8 = 53, + SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8 = 54, + SVGA3D_DEVCAP_SURFACEFMT_CxV8U8 = 55, + SVGA3D_DEVCAP_SURFACEFMT_R_S10E5 = 56, + SVGA3D_DEVCAP_SURFACEFMT_R_S23E8 = 57, + SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5 = 58, + SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8 = 59, + SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5 = 60, + SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8 = 61, + SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES = 63, + + /* + * Note that MAX_SIMULTANEOUS_RENDER_TARGETS is a maximum count of color + * render targets. This does no include the depth or stencil targets. + */ + SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS = 64, + + SVGA3D_DEVCAP_SURFACEFMT_V16U16 = 65, + SVGA3D_DEVCAP_SURFACEFMT_G16R16 = 66, + SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16 = 67, + SVGA3D_DEVCAP_SURFACEFMT_UYVY = 68, + SVGA3D_DEVCAP_SURFACEFMT_YUY2 = 69, + + /* + * Don't add new caps into the previous section; the values in this + * enumeration must not change. You can put new values right before + * SVGA3D_DEVCAP_MAX. + */ + SVGA3D_DEVCAP_MAX /* This must be the last index. */ +} SVGA3dDevCapIndex; + +typedef union { + Bool b; + uint32 u; + int32 i; + float f; +} SVGA3dDevCapResult; + +#endif /* _SVGA3D_REG_H_ */ diff --git a/vmwgfx/vmwgfx_crtc.c b/vmwgfx/vmwgfx_crtc.c new file mode 100644 index 0000000..eaf87b2 --- /dev/null +++ b/vmwgfx/vmwgfx_crtc.c @@ -0,0 +1,455 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <math.h> +#include <stdint.h> + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include <cursorstr.h> +#include "vmwgfx_driver.h" +#include "xf86Modes.h" +#include "vmwgfx_saa.h" + +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +struct crtc_private +{ + drmModeCrtcPtr drm_crtc; + + /* hwcursor */ + struct vmwgfx_dmabuf *cursor_bo; + uint32_t scanout_id; + unsigned cursor_handle; + + /* Scanout info for pixmaps */ + struct vmwgfx_screen_entry entry; +}; + +static void +crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + struct crtc_private *crtcp = crtc->driver_private; + /* ScrnInfoPtr pScrn = crtc->scrn; */ + + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + break; + case DPMSModeOff: + + /* + * The xf86 modesetting code uses DPMS off to turn off + * crtcs that are not enabled. However, the DPMS code does the same. + * We assume, that if we get this call with the crtc not enabled, + * it's a permanent switch off which will only be reversed by a + * major modeset. + * + * If it's a DPMS switch off, (crtc->enabled == TRUE), + * the crtc may be turned on again by + * another dpms call, so don't release the scanout pixmap ref. + */ + if (!crtc->enabled && crtcp->entry.pixmap) { + vmwgfx_scanout_unref(&crtcp->entry); + } + break; + } +} + +/* + * Disable outputs and crtcs and drop the scanout reference from + * scanout pixmaps. This will essentialy free all kms fb allocations. + */ + +void +vmwgfx_disable_scanout(ScrnInfoPtr pScrn) +{ + int i; + Bool save_enabled; + xf86CrtcPtr crtc; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + + xf86DPMSSet(pScrn, DPMSModeOff, 0); + for (i=0; i < config->num_crtc; ++i) { + crtc = config->crtc[i]; + save_enabled = crtc->enabled; + crtc->enabled = FALSE; + crtc_dpms(crtc, DPMSModeOff); + crtc->enabled = save_enabled; + } + xf86RotateFreeShadow(pScrn); +} + +static Bool +crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + modesettingPtr ms = modesettingPTR(crtc->scrn); + ScreenPtr pScreen = crtc->scrn->pScreen; + xf86OutputPtr output = NULL; + struct crtc_private *crtcp = crtc->driver_private; + drmModeCrtcPtr drm_crtc = crtcp->drm_crtc; + drmModeModeInfo drm_mode; + int i, ret; + unsigned int connector_id; + PixmapPtr pixmap; + + for (i = 0; i < config->num_output; output = NULL, i++) { + output = config->output[i]; + + if (output->crtc == crtc) + break; + } + + if (!output) { + LogMessage(X_ERROR, "No output for this crtc.\n"); + return FALSE; + } + + connector_id = xorg_output_get_id(output); + + drm_mode.clock = mode->Clock; + drm_mode.hdisplay = mode->HDisplay; + drm_mode.hsync_start = mode->HSyncStart; + drm_mode.hsync_end = mode->HSyncEnd; + drm_mode.htotal = mode->HTotal; + drm_mode.vdisplay = mode->VDisplay; + drm_mode.vsync_start = mode->VSyncStart; + drm_mode.vsync_end = mode->VSyncEnd; + drm_mode.vtotal = mode->VTotal; + drm_mode.flags = mode->Flags; + drm_mode.hskew = mode->HSkew; + drm_mode.vscan = mode->VScan; + drm_mode.vrefresh = mode->VRefresh; + if (!mode->name) + xf86SetModeDefaultName(mode); + strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1); + drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; + + /* + * Check if we need to scanout from something else than the root + * pixmap. In that case, xf86CrtcRotate will take care of allocating + * new opaque scanout buffer data "crtc->rotatedData". + * However, it will not wrap + * that data into pixmaps until the first rotated damage composite. + * In out case, the buffer data is actually already a pixmap. + */ + + if (!xf86CrtcRotate(crtc)) + return FALSE; + + if (crtc->transform_in_use && crtc->rotatedData) { + x = 0; + y = 0; + pixmap = (PixmapPtr) crtc->rotatedData; + } else + pixmap = pScreen->GetScreenPixmap(pScreen); + + if (crtcp->entry.pixmap != pixmap) { + if (crtcp->entry.pixmap) + vmwgfx_scanout_unref(&crtcp->entry); + + crtcp->entry.pixmap = pixmap; + crtcp->scanout_id = vmwgfx_scanout_ref(&crtcp->entry); + if (crtcp->scanout_id == -1) { + LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n"); + return FALSE; + } + } + ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, crtcp->scanout_id, x, y, + &connector_id, 1, &drm_mode); + if (ret) + return FALSE; + + vmwgfx_scanout_refresh(pixmap); + + /* Only set gamma when needed, to avoid unneeded delays. */ +#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 + if (!crtc->active && crtc->version >= 3) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); + crtc->active = TRUE; +#endif + + return TRUE; +} + +static void +crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue, + int size) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeCrtcSetGamma(ms->fd, crtcp->drm_crtc->crtc_id, size, red, green, blue); +} + +static void * +crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) +{ + ScreenPtr pScreen = crtc->scrn->pScreen; + PixmapPtr rootpix = pScreen->GetScreenPixmap(pScreen); + + /* + * Use the same depth as for the root pixmap. + * The associated kms fb will be created on demand once this pixmap + * is used as scanout by a crtc. + */ + + return pScreen->CreatePixmap(pScreen, width, height, + rootpix->drawable.depth, 0); +} + +static PixmapPtr +crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + return (PixmapPtr) data; +} + +static void +crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + ScreenPtr pScreen = rotate_pixmap->drawable.pScreen; + + pScreen->DestroyPixmap(rotate_pixmap); +} + + +/* + * Cursor functions + */ + +static void +crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) +{ + /* XXX: See if this one is needed, as we only support ARGB cursors */ +} + +static void +crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y); +} + +static void +crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + unsigned char *ptr; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + CursorPtr c = config->cursor; + + if (vmwgfx_cursor_bypass(ms->fd, c->bits->xhot, c->bits->yhot) != 0) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to set VMWare cursor bypass.\n"); + } + + if (!crtcp->cursor_bo) { + size_t size = 64*64*4; + crtcp->cursor_bo = vmwgfx_dmabuf_alloc(ms->fd, size); + if (!crtcp->cursor_bo) + return; + crtcp->cursor_handle = crtcp->cursor_bo->handle; + } + + ptr = vmwgfx_dmabuf_map(crtcp->cursor_bo); + if (ptr) { + memcpy(ptr, image, 64*64*4); + vmwgfx_dmabuf_unmap(crtcp->cursor_bo); + } + + if (crtc->cursor_shown) + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, + crtcp->cursor_handle, 64, 64); + + return; +} + +static void +crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + modesettingPtr ms = modesettingPTR(crtc->scrn); + + /* Older X servers have cursor reference counting bugs leading to use of + * freed memory and consequently random crashes. Should be fixed as of + * xserver 1.8, but this workaround shouldn't hurt anyway. + */ + if (config->cursor) + config->cursor->refcnt++; + + if (ms->cursor) + FreeCursor(ms->cursor, None); + + ms->cursor = config->cursor; + crtc_load_cursor_argb_kms(crtc, image); +} + +static void +crtc_show_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_bo) + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, + crtcp->cursor_handle, 64, 64); +} + +static void +crtc_hide_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0); +} + +/** + * Called at vt leave + */ +void +xorg_crtc_cursor_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_bo) { + vmwgfx_dmabuf_destroy(crtcp->cursor_bo); + crtcp->cursor_bo = NULL; + } +} + +/* + * Misc functions + */ + +static void +crtc_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + if (!WSBMLISTEMPTY(&crtcp->entry.scanout_head)) + vmwgfx_scanout_unref(&crtcp->entry); + + xorg_crtc_cursor_destroy(crtc); + + drmModeFreeCrtc(crtcp->drm_crtc); + + free(crtcp); + crtc->driver_private = NULL; +} + +static const xf86CrtcFuncsRec crtc_funcs = { + .dpms = crtc_dpms, + .set_mode_major = crtc_set_mode_major, + + .set_cursor_colors = crtc_set_cursor_colors, + .set_cursor_position = crtc_set_cursor_position, + .show_cursor = crtc_show_cursor, + .hide_cursor = crtc_hide_cursor, + .load_cursor_argb = crtc_load_cursor_argb, + + .shadow_create = crtc_shadow_create, + .shadow_allocate = crtc_shadow_allocate, + .shadow_destroy = crtc_shadow_destroy, + + .gamma_set = crtc_gamma_set, + .destroy = crtc_destroy, +}; + +void +xorg_crtc_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcPtr crtc; + drmModeResPtr res; + drmModeCrtcPtr drm_crtc = NULL; + struct crtc_private *crtcp; + int c; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + ErrorF("Failed drmModeGetResources %d\n", errno); + return; + } + + for (c = 0; c < res->count_crtcs; c++) { + drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]); + + if (!drm_crtc) + continue; + + crtc = xf86CrtcCreate(pScrn, &crtc_funcs); + if (crtc == NULL) + goto out; + + crtcp = calloc(1, sizeof(struct crtc_private)); + if (!crtcp) { + xf86CrtcDestroy(crtc); + goto out; + } + + crtcp->drm_crtc = drm_crtc; + crtcp->entry.pixmap = NULL; + WSBMINITLISTHEAD(&crtcp->entry.scanout_head); + + crtc->driver_private = crtcp; + } + + out: + drmModeFreeResources(res); +} + +PixmapPtr +crtc_get_scanout(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + return crtcp->entry.pixmap; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/vmwgfx/vmwgfx_ctrl.c b/vmwgfx/vmwgfx_ctrl.c new file mode 100644 index 0000000..3185879 --- /dev/null +++ b/vmwgfx/vmwgfx_ctrl.c @@ -0,0 +1,523 @@ +/* + * Copyright 2006-2011 by VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* + * vmwarectrl.c -- + * + * The implementation of the VMWARE_CTRL protocol extension that + * allows X clients to communicate with the driver. + */ + +#include <xorg-server.h> +#include "dixstruct.h" +#include "extnsionst.h" +#include <X11/X.h> +#include <X11/extensions/panoramiXproto.h> + +#include "vmwarectrlproto.h" +#include "vmwgfx_driver.h" +#include "vmwgfx_drmi.h" + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlQueryVersion -- + * + * Implementation of QueryVersion command handler. Initialises and + * sends a reply. + * + * Results: + * Standard response codes. + * + * Side effects: + * Writes reply to client + * + *---------------------------------------------------------------------------- + */ + +static int +VMwareCtrlQueryVersion(ClientPtr client) +{ + xVMwareCtrlQueryVersionReply rep = { 0, }; + register int n; + + REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION; + rep.minorVersion = VMWARE_CTRL_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep); + + return client->noClientException; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlDoSetRes -- + * + * Set the custom resolution into the mode list. + * + * This is done by alternately updating one of two dynamic modes. It is + * done this way because the server gets upset if you try to switch + * to a new resolution that has the same index as the current one. + * + * Results: + * TRUE on success, FALSE otherwise. + * + * Side effects: + * One dynamic mode will be updated if successful. + * + *---------------------------------------------------------------------------- + */ + +static Bool +VMwareCtrlDoSetRes(ScrnInfoPtr pScrn, + CARD32 x, + CARD32 y) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct drm_vmw_rect rect; + int ret; + + rect.x = 0; + rect.y = 0; + rect.w = x; + rect.h = y; + + ret = vmwgfx_update_gui_layout(ms->fd, 1, &rect); + return (ret == 0); +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlSetRes -- + * + * Implementation of SetRes command handler. Initialises and sends a + * reply. + * + * Results: + * Standard response codes. + * + * Side effects: + * Writes reply to client + * + *---------------------------------------------------------------------------- + */ + +static int +VMwareCtrlSetRes(ClientPtr client) +{ + REQUEST(xVMwareCtrlSetResReq); + xVMwareCtrlSetResReply rep = { 0, }; + ScrnInfoPtr pScrn; + ExtensionEntry *ext; + register int n; + + REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); + + if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { + return BadMatch; + } + + pScrn = ext->extPrivate; + if (pScrn->scrnIndex != stuff->screen) { + return BadMatch; + } + + if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y)) { + return BadValue; + } + + rep.type = X_Reply; + rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2; + rep.sequenceNumber = client->sequence; + rep.screen = stuff->screen; + rep.x = stuff->x; + rep.y = stuff->y; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screen, n); + swapl(&rep.x, n); + swapl(&rep.y, n); + } + WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep); + + return client->noClientException; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlDoSetTopology -- + * + * Set the custom topology and set a dynamic mode to the bounding box + * of the passed topology. If a topology is already pending, then do + * nothing but do not return failure. + * + * Results: + * TRUE on success, FALSE otherwise. + * + * Side effects: + * One dynamic mode and the pending xinerama state will be updated if + * successful. + * + *---------------------------------------------------------------------------- + */ + +static Bool +VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn, + xXineramaScreenInfo *extents, + unsigned long number) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct drm_vmw_rect *rects; + int i; + int ret; + + rects = calloc(number, sizeof(*rects)); + if (!rects) + return FALSE; + + for (i = 0; i < number; i++) { + rects[i].x = extents[i].x_org; + rects[i].y = extents[i].y_org; + rects[i].w = extents[i].width; + rects[i].h = extents[i].height; + } + + ret = vmwgfx_update_gui_layout(ms->fd, number, rects); + + free(rects); + return (ret == 0); +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlSetTopology -- + * + * Implementation of SetTopology command handler. Initialises and sends a + * reply. + * + * Results: + * Standard response codes. + * + * Side effects: + * Writes reply to client + * + *---------------------------------------------------------------------------- + */ + +static int +VMwareCtrlSetTopology(ClientPtr client) +{ + REQUEST(xVMwareCtrlSetTopologyReq); + xVMwareCtrlSetTopologyReply rep = { 0, }; + ScrnInfoPtr pScrn; + ExtensionEntry *ext; + register int n; + xXineramaScreenInfo *extents; + + REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq); + + if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { + return BadMatch; + } + + pScrn = ext->extPrivate; + if (pScrn->scrnIndex != stuff->screen) { + return BadMatch; + } + + extents = (xXineramaScreenInfo *)(stuff + 1); + if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) { + return BadValue; + } + + rep.type = X_Reply; + rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2; + rep.sequenceNumber = client->sequence; + rep.screen = stuff->screen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screen, n); + } + WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep); + + return client->noClientException; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlDispatch -- + * + * Dispatcher for VMWARE_CTRL commands. Calls the correct handler for + * each command type. + * + * Results: + * Standard response codes. + * + * Side effects: + * Side effects of individual command handlers. + * + *---------------------------------------------------------------------------- + */ + +static int +VMwareCtrlDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch(stuff->data) { + case X_VMwareCtrlQueryVersion: + return VMwareCtrlQueryVersion(client); + case X_VMwareCtrlSetRes: + return VMwareCtrlSetRes(client); + case X_VMwareCtrlSetTopology: + return VMwareCtrlSetTopology(client); + } + return BadRequest; +} + + +/* + *---------------------------------------------------------------------------- + * + * SVMwareCtrlQueryVersion -- + * + * Wrapper for QueryVersion handler that handles input from other-endian + * clients. + * + * Results: + * Standard response codes. + * + * Side effects: + * Side effects of unswapped implementation. + * + *---------------------------------------------------------------------------- + */ + +static int +SVMwareCtrlQueryVersion(ClientPtr client) +{ + register int n; + + REQUEST(xVMwareCtrlQueryVersionReq); + REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); + + swaps(&stuff->length, n); + + return VMwareCtrlQueryVersion(client); +} + + +/* + *---------------------------------------------------------------------------- + * + * SVMwareCtrlSetRes -- + * + * Wrapper for SetRes handler that handles input from other-endian + * clients. + * + * Results: + * Standard response codes. + * + * Side effects: + * Side effects of unswapped implementation. + * + *---------------------------------------------------------------------------- + */ + +static int +SVMwareCtrlSetRes(ClientPtr client) +{ + register int n; + + REQUEST(xVMwareCtrlSetResReq); + REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); + + swaps(&stuff->length, n); + swapl(&stuff->screen, n); + swapl(&stuff->x, n); + swapl(&stuff->y, n); + + return VMwareCtrlSetRes(client); +} + + +/* + *---------------------------------------------------------------------------- + * + * SVMwareCtrlSetTopology -- + * + * Wrapper for SetTopology handler that handles input from other-endian + * clients. + * + * Results: + * Standard response codes. + * + * Side effects: + * Side effects of unswapped implementation. + * + *---------------------------------------------------------------------------- + */ + +static int +SVMwareCtrlSetTopology(ClientPtr client) +{ + register int n; + + REQUEST(xVMwareCtrlSetTopologyReq); + REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq); + + swaps(&stuff->length, n); + swapl(&stuff->screen, n); + swapl(&stuff->number, n); + /* Each extent is a struct of shorts. */ + SwapRestS(stuff); + + return VMwareCtrlSetTopology(client); +} + + +/* + *---------------------------------------------------------------------------- + * + * SVMwareCtrlDispatch -- + * + * Wrapper for dispatcher that handles input from other-endian clients. + * + * Results: + * Standard response codes. + * + * Side effects: + * Side effects of individual command handlers. + * + *---------------------------------------------------------------------------- + */ + +static int +SVMwareCtrlDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch(stuff->data) { + case X_VMwareCtrlQueryVersion: + return SVMwareCtrlQueryVersion(client); + case X_VMwareCtrlSetRes: + return SVMwareCtrlSetRes(client); + case X_VMwareCtrlSetTopology: + return SVMwareCtrlSetTopology(client); + } + return BadRequest; +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrlResetProc -- + * + * Cleanup handler called when the extension is removed. + * + * Results: + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static void +VMwareCtrlResetProc(ExtensionEntry* extEntry) +{ + /* Currently, no cleanup is necessary. */ +} + + +/* + *---------------------------------------------------------------------------- + * + * VMwareCtrl_ExitInit -- + * + * Initialiser for the VMWARE_CTRL protocol extension. + * + * Results: + * None. + * + * Side effects: + * Protocol extension will be registered if successful. + * + *---------------------------------------------------------------------------- + */ + +void +vmw_ctrl_ext_init(ScrnInfoPtr pScrn) +{ + ExtensionEntry *myext; + + if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { + if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0, + VMwareCtrlDispatch, + SVMwareCtrlDispatch, + VMwareCtrlResetProc, + StandardMinorOpcode))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to add VMWARE_CTRL extension\n"); + return; + } + + /* + * For now, only support one screen as that's all the virtual + * hardware supports. + */ + myext->extPrivate = pScrn; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Initialized VMWARE_CTRL extension version %d.%d\n", + VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION); + } +} diff --git a/vmwgfx/vmwgfx_ctrl.h b/vmwgfx/vmwgfx_ctrl.h new file mode 100644 index 0000000..8fedbce --- /dev/null +++ b/vmwgfx/vmwgfx_ctrl.h @@ -0,0 +1,48 @@ +/* + * Copyright 2006 by VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* + * vmwgfx_ctrl.h -- + * + * The definitions used by the VMWARE_CTRL protocol extension that + * allows X clients to communicate with the driver. + */ + + +#ifndef _VMWGFX_CTRL_H_ +#define _VMWGFX_CTRL_H_ + +#define VMWARE_CTRL_PROTOCOL_NAME "VMWARE_CTRL" + +#define VMWARE_CTRL_MAJOR_VERSION 0 +#define VMWARE_CTRL_MINOR_VERSION 2 + +#define X_VMwareCtrlQueryVersion 0 +#define X_VMwareCtrlSetRes 1 +#define X_VMwareCtrlSetTopology 2 + +#endif /* _VMW_CTRL_H_ */ diff --git a/vmwgfx/vmwgfx_dri2.c b/vmwgfx/vmwgfx_dri2.c new file mode 100644 index 0000000..1b82ac4 --- /dev/null +++ b/vmwgfx/vmwgfx_dri2.c @@ -0,0 +1,426 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + * + */ + +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "vmwgfx_driver.h" +#include "../saa/saa.h" + +#include "dri2.h" +#include "gcstruct.h" +#include "gc.h" +#include "vmwgfx_saa.h" +#include "wsbm_util.h" +#include <unistd.h> + +#define VMWGFX_FD_PATH_LEN 80 + +typedef struct { + int refcount; + PixmapPtr pPixmap; + struct xa_surface *srf; + unsigned int dri2_depth; +} *BufferPrivatePtr; + + +/* + * Attempt to guess what the dri state tracker is up to. + * Currently it sends only bpp as format. + */ + +static unsigned int +vmwgfx_color_format_to_depth(unsigned int format) +{ + return format; +} + +static unsigned int +vmwgfx_zs_format_to_depth(unsigned int format) +{ + if (format == 24) + return 32; + return format; +} + +static unsigned int +vmwgfx_z_format_to_depth(unsigned int format) +{ + return format; +} + +static Bool +dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int format) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + BufferPrivatePtr private = buffer->driverPrivate; + PixmapPtr pPixmap; + struct vmwgfx_saa_pixmap *vpix; + struct xa_surface *srf = NULL; + unsigned int depth; + + + if (pDraw->type == DRAWABLE_PIXMAP) + pPixmap = (PixmapPtr) pDraw; + else + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); + + vpix = vmwgfx_saa_pixmap(pPixmap); + private->refcount = 0; + + switch (buffer->attachment) { + default: + depth = (format) ? vmwgfx_color_format_to_depth(format) : + pDraw->depth; + + if (buffer->attachment != DRI2BufferFakeFrontLeft || + &pPixmap->drawable != pDraw) { + + pPixmap = (*pScreen->CreatePixmap)(pScreen, + pDraw->width, + pDraw->height, + depth, + 0); + if (pPixmap == NullPixmap) + return FALSE; + + private->pPixmap = pPixmap; + private->dri2_depth = depth; + vpix = vmwgfx_saa_pixmap(pPixmap); + } + break; + case DRI2BufferFrontLeft: + if (&pPixmap->drawable == pDraw) + break; + buffer->name = 0; + buffer->pitch = 0; + buffer->cpp = pDraw->bitsPerPixel / 8; + buffer->driverPrivate = private; + buffer->flags = 0; /* not tiled */ + buffer->format = pDraw->bitsPerPixel; + if (!private->pPixmap) { + private->dri2_depth = 0; + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + return TRUE; + case DRI2BufferStencil: + case DRI2BufferDepthStencil: + + depth = (format) ? vmwgfx_zs_format_to_depth(format) : 32; + + /* + * The SVGA device uses the zs ordering. + */ + + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, xa_type_zs, xa_format_unknown, + XA_FLAG_SHARED ); + if (!srf) + return FALSE; + + private->dri2_depth = depth; + + break; + case DRI2BufferDepth: + depth = (format) ? vmwgfx_z_format_to_depth(format) : + pDraw->bitsPerPixel; + + if (depth == 24) + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, xa_type_zs, xa_format_unknown, + XA_FLAG_SHARED ); + else + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, + xa_type_z, xa_format_unknown, + XA_FLAG_SHARED); + if (!srf) + return FALSE; + + private->dri2_depth = depth; + + break; + } + + if (!private->pPixmap) { + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + + if (!srf) { + depth = (format) ? vmwgfx_color_format_to_depth(format) : + pDraw->depth; + + if (!vmwgfx_hw_dri2_validate(pPixmap, depth)) + return FALSE; + + srf = vpix->hw; + private->refcount++; + private->dri2_depth = depth; + + /* + * Compiz workaround. See vmwgfx_dirty(); + */ + + if (buffer->attachment == DRI2BufferFrontLeft || + buffer->attachment == DRI2BufferFakeFrontLeft) + vpix->hw_is_dri2_fronts++; + } + + private->srf = srf; + if (xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0) + return FALSE; + + buffer->cpp = xa_format_depth(xa_surface_format(srf)) / 8; + buffer->driverPrivate = private; + buffer->flags = 0; /* not tiled */ + buffer->format = format; + private->refcount++; + + return TRUE; +} + +static void +dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer) +{ + BufferPrivatePtr private = buffer->driverPrivate; + struct xa_surface *srf = private->srf; + ScreenPtr pScreen = pDraw->pScreen; + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap); + + if (--private->refcount == 0 && srf) { + xa_surface_destroy(srf); + } + + /* + * Compiz workaround. See vmwgfx_dirty(); + */ + + if ((buffer->attachment == DRI2BufferFrontLeft || + buffer->attachment == DRI2BufferFakeFrontLeft) && + private->refcount == 1 && + --vpix->hw_is_dri2_fronts == 0) + WSBMLISTDELINIT(&vpix->sync_x_head); + + private->srf = NULL; + pScreen->DestroyPixmap(private->pPixmap); +} + + +static DRI2Buffer2Ptr +dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) +{ + DRI2Buffer2Ptr buffer; + BufferPrivatePtr private; + + buffer = calloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + private = calloc(1, sizeof *private); + if (!private) { + goto fail; + } + + buffer->attachment = attachment; + buffer->driverPrivate = private; + + if (dri2_do_create_buffer(pDraw, buffer, format)) + return buffer; + + free(private); +fail: + free(buffer); + return NULL; +} + +static void +dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) +{ + /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ + dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer); + + free(buffer->driverPrivate); + free(buffer); +} + +static void +dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, + DRI2Buffer2Ptr pDestBuffer, DRI2Buffer2Ptr pSrcBuffer) +{ + + + ScreenPtr pScreen = pDraw->pScreen; + BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; + BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; + DrawablePtr src_draw; + DrawablePtr dst_draw; + RegionPtr myClip; + GCPtr gc; + + /* + * In driCreateBuffers we dewrap windows into the + * backing pixmaps in order to get to the texture. + * We need to use the real drawable in CopyArea + * so that cliprects and offsets are correct. + */ + src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : + &src_priv->pPixmap->drawable; + dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : + &dst_priv->pPixmap->drawable; + + /* + * The clients implements glXWaitX with a copy front to fake and then + * waiting on the server to signal its completion of it. While + * glXWaitGL is a client side flush and a copy from fake to front. + * This is how it is done in the DRI2 protocol, how ever depending + * which type of drawables the server does things a bit differently + * then what the protocol says as the fake and front are the same. + * + * for pixmaps glXWaitX is a server flush. + * for pixmaps glXWaitGL is a client flush. + * for windows glXWaitX is a copy from front to fake then a server flush. + * for windows glXWaitGL is a client flush then a copy from fake to front. + * + * XXX in the windows case this code always flushes but that isn't a + * must in the glXWaitGL case but we don't know if this is a glXWaitGL + * or a glFlush/glFinish call. + */ + if (dst_priv->pPixmap == src_priv->pPixmap) { + /* pixmap glXWaitX */ + if (pSrcBuffer->attachment == DRI2BufferFrontLeft && + pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { + + if (!vmwgfx_hw_dri2_validate(dst_priv->pPixmap, + dst_priv->dri2_depth)) + return; + } + /* pixmap glXWaitGL */ + if (pDestBuffer->attachment == DRI2BufferFrontLeft && + pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { + return; + } else { + vmwgfx_flush_dri2(pScreen); + return; + } + } + + gc = GetScratchGC(pDraw->depth, pScreen); + myClip = REGION_CREATE(pScreen, REGION_RECTS(pRegion), + REGION_NUM_RECTS(pRegion)); + (*gc->funcs->ChangeClip) (gc, CT_REGION, myClip, 0); + ValidateGC(dst_draw, gc); + + /* + * Damage the src drawable in order for damageCopyArea to pick up + * that something changed. + */ + DamageRegionAppend(src_draw, pRegion); + if (pSrcBuffer->attachment != DRI2BufferFrontLeft) + saa_drawable_dirty(src_draw, TRUE, pRegion); + DamageRegionProcessPending(src_draw); + + /* + * Call CopyArea. This usually means a call to damageCopyArea that + * is wrapping saa_copy_area. The damageCopyArea function will make + * sure the destination drawable is appropriately damaged. + */ + (*gc->ops->CopyArea)(src_draw, dst_draw, gc, + 0, 0, pDraw->width, pDraw->height, 0, 0); + + /* + * FreeScratchGC will free myClip as well. + */ + myClip = NULL; + FreeScratchGC(gc); +} + +Bool +xorg_dri2_init(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + DRI2InfoRec dri2info; + int major, minor; + char fdPath[VMWGFX_FD_PATH_LEN]; + ssize_t numChar; + + if (xf86LoaderCheckSymbol("DRI2Version")) { + DRI2Version(&major, &minor); + } else { + /* Assume version 1.0 */ + major = 1; + minor = 0; + } + + dri2info.version = min(DRI2INFOREC_VERSION, 3); + dri2info.fd = ms->fd; + dri2info.driverName = "vmwgfx"; + + /* + * This way of obtaining the DRM device name is a bit + * os-specific. It would be better to obtain it from + * drmOpen. Currently this works only for Linux. + */ + memset(fdPath, 0, VMWGFX_FD_PATH_LEN); + snprintf(fdPath, VMWGFX_FD_PATH_LEN - 1, "/proc/self/fd/%d", ms->fd); + numChar = readlink(fdPath, ms->dri2_device_name, VMWGFX_DRI_DEVICE_LEN); + if (numChar <= 0 || numChar >= VMWGFX_DRI_DEVICE_LEN) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not find the drm device name. Disabling dri2.\n"); + return FALSE; + } + ms->dri2_device_name[numChar] = 0; + dri2info.deviceName = ms->dri2_device_name; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Path of drm device is \"%s\".\n", ms->dri2_device_name); + + dri2info.CreateBuffer = dri2_create_buffer; + dri2info.DestroyBuffer = dri2_destroy_buffer; + + dri2info.CopyRegion = dri2_copy_region; + dri2info.Wait = NULL; + + return DRI2ScreenInit(pScreen, &dri2info); +} + +void +xorg_dri2_close(ScreenPtr pScreen) +{ + DRI2CloseScreen(pScreen); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/vmwgfx/vmwgfx_driver.c b/vmwgfx/vmwgfx_driver.c new file mode 100644 index 0000000..dcb6c83 --- /dev/null +++ b/vmwgfx/vmwgfx_driver.c @@ -0,0 +1,1200 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + + +#include <unistd.h> +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "mipointer.h" +#include "micmap.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "edid.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#include "miscstruct.h" +#include "dixstruct.h" +#include "xf86cmap.h" +#include "xf86xv.h" +#include "xorgVersion.h" +#ifndef XSERVER_LIBPCIACCESS +#error "libpciaccess needed" +#endif + +#include <pciaccess.h> + +#include "vmwgfx_driver.h" + +#include <saa.h> +#include "vmwgfx_saa.h" +#include "../src/vmware_bootstrap.h" +#include "../src/vmware_common.h" + +/* + * We can't incude svga_types.h due to conflicting types for Bool. + */ +typedef int64_t int64; +typedef uint64_t uint64; + +typedef int32_t int32; +typedef uint32_t uint32; + +typedef int16_t int16; +typedef uint16_t uint16; + +typedef int8_t int8; +typedef uint8_t uint8; +#include "./src/svga_reg.h" + +#define XA_VERSION_MINOR_REQUIRED 6 +#define DRM_VERSION_MAJOR_REQUIRED 2 +#define DRM_VERSION_MINOR_REQUIRED 3 + +/* + * Some macros to deal with function wrapping. + */ +#define vmwgfx_wrap(priv, real, mem, func) {\ + (priv)->saved_##mem = (real)->mem; \ + (real)->mem = func; \ +} + +#define vmwgfx_unwrap(priv, real, mem) {\ + (real)->mem = (priv)->saved_##mem; \ +} + +#define vmwgfx_swap(priv, real, mem) {\ + void *tmp = (priv)->saved_##mem; \ + (priv)->saved_##mem = (real)->mem; \ + (real)->mem = tmp; \ +} + +/* + * Functions and symbols exported to Xorg via pointers. + */ + +static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags); +static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags); +static void drv_adjust_frame(int scrnIndex, int x, int y, int flags); +static Bool drv_enter_vt(int scrnIndex, int flags); +static void drv_leave_vt(int scrnIndex, int flags); +static void drv_free_screen(int scrnIndex, int flags); +static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, + int flags); + +extern void xorg_tracker_set_functions(ScrnInfoPtr scrn); + +void +vmwgfx_hookup(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = drv_pre_init; + pScrn->ScreenInit = drv_screen_init; + pScrn->SwitchMode = drv_switch_mode; + pScrn->FreeScreen = drv_free_screen; + pScrn->ValidMode = drv_valid_mode; +} + +/* + * Internal function definitions + */ + +static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen); + +/* + * Internal functions + */ + +static Bool +drv_get_rec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec)); + + return TRUE; +} + +static void +drv_free_rec(ScrnInfoPtr pScrn) +{ + if (!pScrn) + return; + + if (!pScrn->driverPrivate) + return; + + free(pScrn->driverPrivate); + + pScrn->driverPrivate = NULL; +} + +static void +drv_probe_ddc(ScrnInfoPtr pScrn, int index) +{ + ConfiguredMonitor = NULL; +} + +static Bool +drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height) +{ + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + int old_width, old_height; + PixmapPtr rootPixmap; + + if (width == pScrn->virtualX && height == pScrn->virtualY) + return TRUE; + + if (ms->check_fb_size) { + size_t size = width*(pScrn->bitsPerPixel / 8) * height + 1024; + + if (size > ms->max_fb_size) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Requested framebuffer size %dx%dx%d will not fit " + "in display memory.\n", + width, height, pScrn->bitsPerPixel); + return FALSE; + } + } + + old_width = pScrn->virtualX; + old_height = pScrn->virtualY; + pScrn->virtualX = width; + pScrn->virtualY = height; + + /* ms->create_front_buffer will remove the old front buffer */ + + rootPixmap = pScreen->GetScreenPixmap(pScreen); + vmwgfx_disable_scanout(pScrn); + if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL)) + goto error_modify; + + pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8); + + xf86SetDesiredModes(pScrn); + return TRUE; + + /* + * FIXME: Try out this error recovery path and fix problems. + + */ + //error_create: + if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL)) + FatalError("failed to resize rootPixmap error path\n"); + + pScrn->displayWidth = rootPixmap->devKind / + (rootPixmap->drawable.bitsPerPixel / 8); + + +error_modify: + pScrn->virtualX = old_width; + pScrn->virtualY = old_height; + + if (xf86SetDesiredModes(pScrn)) + return FALSE; + + FatalError("failed to setup old framebuffer\n"); + return FALSE; +} + +static const xf86CrtcConfigFuncsRec crtc_config_funcs = { + .resize = drv_crtc_resize +}; + +static Bool +drv_init_drm(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + /* deal with server regeneration */ + if (ms->fd < 0) { + char *BusID; + + BusID = malloc(64); + sprintf(BusID, "PCI:%d:%d:%d", + ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), + ms->PciInfo->dev, ms->PciInfo->func + ); + + + ms->fd = drmOpen("vmwgfx", BusID); + ms->isMaster = TRUE; + free(BusID); + + if (ms->fd >= 0) { + drmVersionPtr ver = drmGetVersion(ms->fd); + + if (ver == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not determine DRM version.\n"); + return FALSE; + } + + ms->drm_major = ver->version_major; + ms->drm_minor = ver->version_minor; + ms->drm_patch = ver->version_patchlevel; + + drmFreeVersion(ver); + return TRUE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to open drm.\n"); + + return FALSE; + } + + return TRUE; +} + +/** + * vmwgfx_set_topology - Set the GUI topology according to an option string + * + * @pScrn: Pointer to a ScrnInfo struct. + * @topology: String containing the topology description. + * @info: Info describing the option used to invoke this function. + * + * This function reads a GUI topology according from @topology, and + * calls into the kernel to set that topology. + */ +static Bool +vmwgfx_set_topology(ScrnInfoPtr pScrn, const char *topology, const char *info) +{ + modesettingPtr ms = modesettingPTR(pScrn); + unsigned int num_outputs; + xXineramaScreenInfo *screen_info; + struct drm_vmw_rect *rects; + int ret; + unsigned int i; + + screen_info = VMWAREParseTopologyString(pScrn, topology, &num_outputs, + info); + + if (screen_info == NULL) + return FALSE; + + rects = calloc(num_outputs, sizeof(*rects)); + if (rects == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate topology data.\n"); + goto out_no_rects; + } + + for(i = 0; i < num_outputs; ++i) { + rects[i].x = screen_info[i].x_org; + rects[i].y = screen_info[i].y_org; + rects[i].w = screen_info[i].width; + rects[i].h = screen_info[i].height; + } + + ret = vmwgfx_update_gui_layout(ms->fd, num_outputs, rects); + free(rects); + free(screen_info); + + return (ret == 0); + + out_no_rects: + free(screen_info); + return FALSE; +} + +static Bool +drv_pre_init(ScrnInfoPtr pScrn, int flags) +{ + xf86CrtcConfigPtr xf86_config; + modesettingPtr ms; + rgb defaultWeight = { 0, 0, 0 }; + EntityInfoPtr pEnt; + uint64_t cap; + Bool ret = TRUE; + + if (pScrn->numEntities != 1) + return FALSE; + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { + drv_probe_ddc(pScrn, pEnt->index); + return TRUE; + } + + pScrn->driverPrivate = NULL; + + /* Allocate driverPrivate */ + if (!drv_get_rec(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate driver private.\n"); + } + + ms = modesettingPTR(pScrn); + ms->pEnt = pEnt; + + pScrn->displayWidth = 640; /* default it */ + + if (ms->pEnt->location.type != BUS_PCI) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Incorrect bus for device.\n"); + goto out_err_bus; + } + + ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); + xf86SetPrimInitDone(pScrn->entityList[0]); + + ms->fd = -1; + if (!drv_init_drm(pScrn)) + goto out_err_bus; + + if (ms->drm_major != DRM_VERSION_MAJOR_REQUIRED || + ms->drm_minor < DRM_VERSION_MINOR_REQUIRED) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "DRM driver version is %d.%d.%d\n", + ms->drm_major, ms->drm_minor, ms->drm_patch); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "But KMS- and 3D functionality needs at least " + "%d.%d.0 to work.\n", + DRM_VERSION_MAJOR_REQUIRED, + DRM_VERSION_MINOR_REQUIRED); + goto out_drm_version; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "DRM driver version is %d.%d.%d\n", + ms->drm_major, ms->drm_minor, ms->drm_patch); + } + + ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0); + + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + if (!xf86SetDepthBpp + (pScrn, 0, 0, 0, + PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set depth and bpp.\n"); + goto out_depth; + } + + if (vmwgfx_get_param(ms->fd, DRM_VMW_PARAM_HW_CAPS, &cap) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to detect device " + "screen object capability.\n"); + goto out_depth; + } + + if ((cap & SVGA_CAP_SCREEN_OBJECT_2) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Device is not screen object " + "capable.\n"); + goto out_depth; + } + + switch (pScrn->depth) { + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported with KMS enabled.\n", + pScrn->depth); + goto out_depth; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + goto out_depth; + if (!xf86SetDefaultVisual(pScrn, -1)) + goto out_depth; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(ms->Options = VMWARECopyOptions())) + goto out_depth; + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); + + ms->accelerate_render = TRUE; + ms->from_render = xf86GetOptValBool(ms->Options, OPTION_RENDER_ACCEL, + &ms->accelerate_render) ? + X_CONFIG : X_PROBED; + + ms->rendercheck = FALSE; + ms->from_rendercheck = xf86GetOptValBool(ms->Options, OPTION_RENDERCHECK, + &ms->rendercheck) ? + X_CONFIG : X_DEFAULT; + + ms->enable_dri = ms->accelerate_render; + ms->from_dri = xf86GetOptValBool(ms->Options, OPTION_DRI, + &ms->enable_dri) ? + X_CONFIG : X_PROBED; + + ms->direct_presents = FALSE; + ms->from_dp = xf86GetOptValBool(ms->Options, OPTION_DIRECT_PRESENTS, + &ms->direct_presents) ? + X_CONFIG : X_DEFAULT; + + ms->only_hw_presents = FALSE; + ms->from_hwp = xf86GetOptValBool(ms->Options, OPTION_HW_PRESENTS, + &ms->only_hw_presents) ? + X_CONFIG : X_DEFAULT; + + /* Allocate an xf86CrtcConfig */ + xf86CrtcConfigInit(pScrn, &crtc_config_funcs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + /* get max width and height */ + { + drmModeResPtr res; + int max_width, max_height; + + res = drmModeGetResources(ms->fd); + max_width = res->max_width; + max_height = res->max_height; + + xf86CrtcSetSizeRange(pScrn, res->min_width, + res->min_height, max_width, max_height); + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Min width %d, Max Width %d.\n", + res->min_width, max_width); + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Min height %d, Max Height %d.\n", + res->min_height, max_height); + drmModeFreeResources(res); + } + + + if (!xf86ReturnOptValBool(ms->Options, OPTION_HW_CURSOR, TRUE)) { + ms->SWCursor = TRUE; + } + + if (xf86IsOptionSet(ms->Options, OPTION_GUI_LAYOUT)) { + char *topology = + xf86GetOptValString(ms->Options, OPTION_GUI_LAYOUT); + + ret = FALSE; + if (topology) { + ret = vmwgfx_set_topology(pScrn, topology, "gui"); + free(topology); + } + + } else if (xf86IsOptionSet(ms->Options, OPTION_STATIC_XINERAMA)) { + char *topology = + xf86GetOptValString(ms->Options, OPTION_STATIC_XINERAMA); + + ret = FALSE; + if (topology) { + ret = vmwgfx_set_topology(pScrn, topology, "static Xinerama"); + free(topology); + } + } + + if (!ret) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Falied parsing or setting " + "gui topology from config file.\n"); + + xorg_crtc_init(pScrn); + xorg_output_init(pScrn); + + if (!xf86InitialConfiguration(pScrn, TRUE)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + goto out_modes; + } + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set gamma.\n"); + goto out_modes; + } + } + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No available modes.\n"); + goto out_modes; + } + + pScrn->currentMode = pScrn->modes; + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load fb module.\n"); + goto out_modes; + } + + if (!xf86LoadSubModule(pScrn, "dri2")) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load dri2 module.\n"); + goto out_modes; + } + + return TRUE; + + out_modes: + free(ms->Options); + out_depth: + out_drm_version: + close(ms->fd); + out_err_bus: + drv_free_rec(pScrn); + return FALSE; + +} + +static Bool +vmwgfx_scanout_update(int drm_fd, int fb_id, RegionPtr dirty) +{ + unsigned num_cliprects = REGION_NUM_RECTS(dirty); + drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); + BoxPtr rect = REGION_RECTS(dirty); + int i, ret; + + if (!num_cliprects) + return TRUE; + + for (i = 0; i < num_cliprects; i++, rect++) { + clip[i].x1 = rect->x1; + clip[i].y1 = rect->y1; + clip[i].x2 = rect->x2; + clip[i].y2 = rect->y2; + } + + ret = drmModeDirtyFB(drm_fd, fb_id, clip, num_cliprects); + if (ret) + LogMessage(X_ERROR, "%s: failed to send dirty (%i, %s)\n", + __func__, ret, strerror(-ret)); + return (ret == 0); +} + +static Bool +vmwgfx_scanout_present(ScreenPtr pScreen, int drm_fd, + struct vmwgfx_saa_pixmap *vpix, + RegionPtr dirty) +{ + uint32_t handle; + unsigned int dummy; + + if (!REGION_NOTEMPTY(pScreen, dirty)) + return TRUE; + + if (!vpix->hw) { + LogMessage(X_ERROR, "No surface to present from.\n"); + return FALSE; + } + + if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) { + LogMessage(X_ERROR, "Could not get present surface handle.\n"); + return FALSE; + } + + if (vmwgfx_present(drm_fd, vpix->fb_id, 0, 0, dirty, handle) != 0) { + LogMessage(X_ERROR, "Failed present kernel call.\n"); + return FALSE; + } + + return TRUE; +} + +void xorg_flush(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + PixmapPtr pixmap = NULL; + struct vmwgfx_saa_pixmap *vpix; + int i; + xf86CrtcPtr crtc; + PixmapPtr *pixmaps = calloc(config->num_crtc, sizeof(*pixmaps)); + unsigned int num_scanout = 0; + unsigned int j; + + if (!pixmaps) { + LogMessage(X_ERROR, "Failed memory allocation during screen " + "update.\n"); + return; + } + + /* + * Get an array of pixmaps from which we scan out. + */ + for (i=0; i<config->num_crtc; ++i) { + crtc = config->crtc[i]; + if (crtc->enabled) { + pixmap = crtc_get_scanout(crtc); + if (pixmap) { + unsigned int j; + + /* + * Remove duplicates. + */ + for (j=0; j<num_scanout; ++j) { + if (pixmap == pixmaps[j]) + break; + } + + if (j == num_scanout) + pixmaps[num_scanout++] = pixmap; + } + } + } + + if (!num_scanout) + return; + + for (j=0; j<num_scanout; ++j) { + pixmap = pixmaps[j]; + vpix = vmwgfx_saa_pixmap(pixmap); + + if (vpix->fb_id != -1) { + if (vpix->pending_update) { + if (ms->only_hw_presents && + REGION_NOTEMPTY(pscreen, vpix->pending_update)) { + (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, + 0, NULL); + REGION_UNION(pScreen, vpix->pending_present, + vpix->pending_present, vpix->pending_update); + } else + (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, + vpix->pending_update); + REGION_EMPTY(pScreen, vpix->pending_update); + } + if (vpix->pending_present) { + if (ms->only_hw_presents) + (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, + vpix->pending_present); + else + (void) vmwgfx_scanout_present(pScreen, ms->fd, vpix, + vpix->pending_present); + REGION_EMPTY(pScreen, vpix->pending_present); + } + } + } + free(pixmaps); +} + +static void drv_block_handler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]); + + vmwgfx_swap(ms, pScreen, BlockHandler); + pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); + vmwgfx_swap(ms, pScreen, BlockHandler); + + vmwgfx_flush_dri2(pScreen); + xorg_flush(pScreen); +} + +static Bool +drv_create_screen_resources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + Bool ret; + + vmwgfx_swap(ms, pScreen, CreateScreenResources); + ret = pScreen->CreateScreenResources(pScreen); + vmwgfx_swap(ms, pScreen, CreateScreenResources); + + drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + return drv_enter_vt(pScreen->myNum, 1); +} + +static Bool +drv_set_master(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + + if (!ms->isMaster && drmSetMaster(ms->fd) != 0) { + if (errno == EINVAL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: 2.6.29 or newer kernel required for " + "multi-server DRI\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: %s\n", strerror(errno)); + } + return FALSE; + } + + ms->isMaster = TRUE; + return TRUE; +} + +/** + * vmwgfx_use_hw_cursor_argb - wrapper around hw argb cursor check. + * + * screen: Pointer to the current screen metadata. + * cursor: Pointer to the current cursor metadata. + * + * In addition to the default test, also check whether we might be + * needing more than one hw cursor (which we don't support). + */ +static Bool +vmwgfx_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr pScrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + Bool ret; + + vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); + ret = cursor_info->UseHWCursorARGB(screen, cursor); + vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); + if (!ret) + return FALSE; + + /* + * If there is a chance we might need two cursors, + * revert to sw cursor. + */ + return !vmwgfx_output_explicit_overlap(pScrn); +} + +/** + * vmwgfx_use_hw_cursor - wrapper around hw cursor check. + * + * screen: Pointer to the current screen metadata. + * cursor: Pointer to the current cursor metadata. + * + * In addition to the default test, also check whether we might be + * needing more than one hw cursor (which we don't support). + */ +static Bool +vmwgfx_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr pScrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + Bool ret; + + vmwgfx_swap(ms, cursor_info, UseHWCursor); + ret = cursor_info->UseHWCursor(screen, cursor); + vmwgfx_swap(ms, cursor_info, UseHWCursor); + if (!ret) + return FALSE; + + /* + * If there is a chance we might need two simultaneous cursors, + * revert to sw cursor. + */ + return !vmwgfx_output_explicit_overlap(pScrn); +} + +/** + * vmwgfx_wrap_use_hw_cursor - Wrap functions that check for hw cursor + * support. + * + * pScrn: Pointer to current screen info. + * + * Enables the device-specific hw cursor support check functions. + */ +static void vmwgfx_wrap_use_hw_cursor(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + + vmwgfx_wrap(ms, cursor_info, UseHWCursor, vmwgfx_use_hw_cursor); + vmwgfx_wrap(ms, cursor_info, UseHWCursorARGB, vmwgfx_use_hw_cursor_argb); +} + + +static void drv_load_palette(ScrnInfoPtr pScrn, int numColors, + int *indices, LOCO *colors, VisualPtr pVisual) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + modesettingPtr ms = modesettingPTR(pScrn); + int index, j, i; + int c; + + switch(pScrn->depth) { + case 15: + for (i = 0; i < numColors; i++) { + index = indices[i]; + for (j = 0; j < 8; j++) { + ms->lut_r[index * 8 + j] = colors[index].red << 8; + ms->lut_g[index * 8 + j] = colors[index].green << 8; + ms->lut_b[index * 8 + j] = colors[index].blue << 8; + } + } + break; + case 16: + for (i = 0; i < numColors; i++) { + index = indices[i]; + + if (index < 32) { + for (j = 0; j < 8; j++) { + ms->lut_r[index * 8 + j] = colors[index].red << 8; + ms->lut_b[index * 8 + j] = colors[index].blue << 8; + } + } + + for (j = 0; j < 4; j++) { + ms->lut_g[index * 4 + j] = colors[index].green << 8; + } + } + break; + default: + for (i = 0; i < numColors; i++) { + index = indices[i]; + ms->lut_r[index] = colors[index].red << 8; + ms->lut_g[index] = colors[index].green << 8; + ms->lut_b[index] = colors[index].blue << 8; + } + break; + } + + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + /* Make the change through RandR */ +#ifdef RANDR_12_INTERFACE + if (crtc->randr_crtc) + RRCrtcGammaSet(crtc->randr_crtc, ms->lut_r, ms->lut_g, ms->lut_b); + else +#endif + crtc->funcs->gamma_set(crtc, ms->lut_r, ms->lut_g, ms->lut_b, 256); + } +} + + +static Bool +drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + VisualPtr visual; + + if (!drv_set_master(pScrn)) + return FALSE; + + pScrn->pScreen = pScreen; + + /* HW dependent - FIXME */ + pScrn->displayWidth = pScrn->virtualX; + + miClearVisualTypes(); + + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths()) + return FALSE; + + pScrn->memPhysBase = 0; + pScrn->fbOffset = 0; + + if (!fbScreenInit(pScreen, NULL, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, NULL, 0); + + vmwgfx_wrap(ms, pScreen, BlockHandler, drv_block_handler); + vmwgfx_wrap(ms, pScreen, CreateScreenResources, + drv_create_screen_resources); + + xf86SetBlackWhitePixels(pScreen); + + vmw_ctrl_ext_init(pScrn); + + if (ms->accelerate_render) { + ms->xat = xa_tracker_create(ms->fd); + if (!ms->xat) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to initialize Gallium3D Xa. " + "No render acceleration available.\n"); + ms->from_render = X_PROBED; + } else { + int major, minor, patch; + + xa_tracker_version(&major, &minor, &patch); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Gallium3D XA version: %d.%d.%d.\n", + major, minor, patch); + + if (XA_TRACKER_VERSION_MAJOR == 0) { + if (minor != XA_TRACKER_VERSION_MINOR) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Expecting XA version 0.%d.x.\n", + XA_TRACKER_VERSION_MINOR); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No render acceleration available.\n"); + xa_tracker_destroy(ms->xat); + ms->xat = NULL; + ms->from_render = X_PROBED; + } + } + if (major != XA_TRACKER_VERSION_MAJOR || + minor < XA_VERSION_MINOR_REQUIRED) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Expecting %d.%d.x >= XA version < %d.0.0.\n", + XA_TRACKER_VERSION_MAJOR, + XA_VERSION_MINOR_REQUIRED, + XA_TRACKER_VERSION_MAJOR + 1); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No render acceleration available.\n"); + xa_tracker_destroy(ms->xat); + ms->xat = NULL; + ms->from_render = X_PROBED; + } + } + if (ms->xat == NULL && ms->rendercheck) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Turning off renercheck mode.\n"); + ms->rendercheck = FALSE; + ms->from_rendercheck = X_PROBED; + } + } + + if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, + ms->direct_presents, + ms->only_hw_presents, + ms->rendercheck)) { + FatalError("Failed to initialize SAA.\n"); + } + + ms->dri2_available = FALSE; + if (ms->enable_dri) { + if (ms->xat) { + ms->dri2_available = xorg_dri2_init(pScreen); + if (!ms->dri2_available) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize direct rendering.\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipped initialization of direct rendering due " + "to lack of render acceleration.\n"); + ms->from_dri = X_PROBED; + } + } + + xf86DrvMsg(pScrn->scrnIndex, ms->from_render, "Render acceleration is %s.\n", + (ms->xat != NULL) ? "enabled" : "disabled"); + + xf86DrvMsg(pScrn->scrnIndex, ms->from_rendercheck, + "Rendercheck mode is %s.\n", + (ms->rendercheck) ? "enabled" : "disabled"); + + xf86DrvMsg(pScrn->scrnIndex, ms->from_dri, "Direct rendering (3D) is %s.\n", + (ms->dri2_available) ? "enabled" : "disabled"); + if (ms->xat != NULL) { + xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", + (ms->direct_presents) ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " + "are %s.\n", + (ms->only_hw_presents) ? "enabled" : "disabled"); + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Need to extend HWcursor support to handle mask interleave */ + if (!ms->SWCursor) { + xf86_cursors_init(pScreen, 64, 64, + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + HARDWARE_CURSOR_ARGB | + HARDWARE_CURSOR_UPDATE_UNHIDDEN); + vmwgfx_wrap_use_hw_cursor(pScrn); + } + + /* Must force it before EnterVT, so we are in control of VT and + * later memory should be bound when allocating, e.g rotate_mem */ + pScrn->vtSema = TRUE; + + pScreen->SaveScreen = xf86SaveScreen; + vmwgfx_wrap(ms, pScreen, CloseScreen, drv_close_screen); + + if (!xf86CrtcScreenInit(pScreen)) + return FALSE; + + if (!miCreateDefColormap(pScreen)) + return FALSE; + if (!xf86HandleColormaps(pScreen, 256, 8, drv_load_palette, NULL, + CMAP_PALETTED_TRUECOLOR | + CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + + xf86DPMSInit(pScreen, xf86DPMSSet, 0); + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + + vmwgfx_wrap(ms, pScrn, EnterVT, drv_enter_vt); + vmwgfx_wrap(ms, pScrn, LeaveVT, drv_leave_vt); + vmwgfx_wrap(ms, pScrn, AdjustFrame, drv_adjust_frame); + + /* + * Must be called _after_ function wrapping. + */ + xorg_xv_init(pScreen); + + return TRUE; +} + +static void +drv_adjust_frame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (crtc && crtc->enabled) { + // crtc->funcs->set_mode_major(crtc, pScrn->currentMode, + // RR_Rotate_0, x, y); + crtc->x = output->initial_x + x; + crtc->y = output->initial_y + y; + } +} + +static void +drv_free_screen(int scrnIndex, int flags) +{ + drv_free_rec(xf86Screens[scrnIndex]); +} + +static void +drv_leave_vt(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + + vmwgfx_cursor_bypass(ms->fd, 0, 0); + vmwgfx_disable_scanout(pScrn); + + if (drmDropMaster(ms->fd)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmDropMaster failed: %s\n", strerror(errno)); + + ms->isMaster = FALSE; + pScrn->vtSema = FALSE; +} + +/* + * This gets called when gaining control of the VT, and from ScreenInit(). + */ +static Bool +drv_enter_vt(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + if (!drv_set_master(pScrn)) + return FALSE; + + if (!xf86SetDesiredModes(pScrn)) + return FALSE; + + return TRUE; +} + +static Bool +drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); +} + +static Bool +drv_close_screen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + + if (ms->cursor) { + FreeCursor(ms->cursor, None); + ms->cursor = NULL; + } + + if (ms->dri2_available) + xorg_dri2_close(pScreen); + + if (pScrn->vtSema) + pScrn->LeaveVT(scrnIndex, 0); + + pScrn->vtSema = FALSE; + + vmwgfx_unwrap(ms, pScrn, EnterVT); + vmwgfx_unwrap(ms, pScrn, LeaveVT); + vmwgfx_unwrap(ms, pScrn, AdjustFrame); + vmwgfx_unwrap(ms, pScreen, CloseScreen); + vmwgfx_unwrap(ms, pScreen, BlockHandler); + vmwgfx_unwrap(ms, pScreen, CreateScreenResources); + + if (ms->xat) + xa_tracker_destroy(ms->xat); + + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static ModeStatus +drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + return MODE_OK; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/vmwgfx/vmwgfx_driver.h b/vmwgfx/vmwgfx_driver.h new file mode 100644 index 0000000..3290f0e --- /dev/null +++ b/vmwgfx/vmwgfx_driver.h @@ -0,0 +1,186 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright n<otice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#ifndef _VMWGFX_DRIVER_H_ +#define _VMWGFX_DRIVER_H_ + + +#include <stddef.h> +#include <stdint.h> +#include <errno.h> +#include <drm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <xorg-server.h> +#include <xf86.h> +#include <xf86Crtc.h> +#include <xf86xv.h> +#include <xa_tracker.h> + +#ifdef DRI2 +#include <dri2.h> +#if (!defined(DRI2INFOREC_VERSION) || (DRI2INFOREC_VERSION < 3)) +#undef DRI2 +#endif +#endif + +#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg); +#define debug_printf(...) + +#define VMWGFX_DRI_DEVICE_LEN 80 + +typedef struct +{ + int lastInstance; + int refCount; + ScrnInfoPtr pScrn_1; + ScrnInfoPtr pScrn_2; +} EntRec, *EntPtr; + +#define XORG_NR_FENCES 3 + +enum xorg_throttling_reason { + THROTTLE_RENDER, + THROTTLE_SWAP +}; + +typedef struct _modesettingRec +{ + /* drm */ + int fd; + int drm_major; + int drm_minor; + int drm_patch; + + /* X */ + EntPtr entityPrivate; + + int Chipset; + EntityInfoPtr pEnt; + struct pci_device *PciInfo; + + /* Accel */ + Bool accelerate_render; + MessageType from_render; + Bool rendercheck; + MessageType from_rendercheck; + Bool SWCursor; + CursorPtr cursor; + Bool enable_dri; + MessageType from_dri; + Bool direct_presents; + MessageType from_dp; + Bool only_hw_presents; + MessageType from_hwp; + Bool isMaster; + + + /* Broken-out options. */ + OptionInfoPtr Options; + + ScreenBlockHandlerProcPtr saved_BlockHandler; + CreateScreenResourcesProcPtr saved_CreateScreenResources; + CloseScreenProcPtr saved_CloseScreen; + Bool (*saved_EnterVT)(int, int); + void (*saved_LeaveVT)(int, int); + void (*saved_AdjustFrame)(int, int, int, int); + Bool (*saved_UseHWCursor)(ScreenPtr, CursorPtr); + Bool (*saved_UseHWCursorARGB)(ScreenPtr, CursorPtr); + + uint16_t lut_r[256], lut_g[256], lut_b[256]; + + Bool check_fb_size; + size_t max_fb_size; + + struct xa_tracker *xat; +#ifdef DRI2 + Bool dri2_available; + char dri2_device_name[VMWGFX_DRI_DEVICE_LEN]; +#endif +} modesettingRec, *modesettingPtr; + +#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate)) + +void xorg_flush(ScreenPtr pScreen); +/*********************************************************************** + * xorg_dri2.c + */ +Bool +xorg_dri2_init(ScreenPtr pScreen); + +void +xorg_dri2_close(ScreenPtr pScreen); + + +/*********************************************************************** + * xorg_crtc.c + */ +void +xorg_crtc_init(ScrnInfoPtr pScrn); + +void +xorg_crtc_cursor_destroy(xf86CrtcPtr crtc); + +void +vmwgfx_disable_scanout(ScrnInfoPtr pScrn); + +PixmapPtr +crtc_get_scanout(xf86CrtcPtr crtc); + + +/*********************************************************************** + * xorg_output.c + */ +void +xorg_output_init(ScrnInfoPtr pScrn); + +unsigned +xorg_output_get_id(xf86OutputPtr output); + +Bool +vmwgfx_output_explicit_overlap(ScrnInfoPtr pScrn); + + +/*********************************************************************** + * xorg_xv.c + */ +void +xorg_xv_init(ScreenPtr pScreen); + +XF86VideoAdaptorPtr +vmw_video_init_adaptor(ScrnInfoPtr pScrn); +void +vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports); + +void +vmw_ctrl_ext_init(ScrnInfoPtr pScrn); + +#endif /* _XORG_TRACKER_H_ */ diff --git a/vmwgfx/vmwgfx_drm.h b/vmwgfx/vmwgfx_drm.h new file mode 100644 index 0000000..906a41c --- /dev/null +++ b/vmwgfx/vmwgfx_drm.h @@ -0,0 +1,792 @@ +/************************************************************************** + * + * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef __VMWGFX_DRM_H__ +#define __VMWGFX_DRM_H__ +#include <drm.h> + +#define DRM_VMW_MAX_SURFACE_FACES 6 +#define DRM_VMW_MAX_MIP_LEVELS 24 + + +#define DRM_VMW_GET_PARAM 0 +#define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_UNREF_DMABUF 2 +#define DRM_VMW_CURSOR_BYPASS 3 +/* guarded by DRM_VMW_PARAM_NUM_STREAMS != 0*/ +#define DRM_VMW_CONTROL_STREAM 4 +#define DRM_VMW_CLAIM_STREAM 5 +#define DRM_VMW_UNREF_STREAM 6 +/* guarded by DRM_VMW_PARAM_3D == 1 */ +#define DRM_VMW_CREATE_CONTEXT 7 +#define DRM_VMW_UNREF_CONTEXT 8 +#define DRM_VMW_CREATE_SURFACE 9 +#define DRM_VMW_UNREF_SURFACE 10 +#define DRM_VMW_REF_SURFACE 11 +#define DRM_VMW_EXECBUF 12 +#define DRM_VMW_GET_3D_CAP 13 +#define DRM_VMW_FENCE_WAIT 14 +#define DRM_VMW_FENCE_SIGNALED 15 +#define DRM_VMW_FENCE_UNREF 16 +#define DRM_VMW_FENCE_EVENT 17 +#define DRM_VMW_PRESENT 18 +#define DRM_VMW_PRESENT_READBACK 19 +#define DRM_VMW_UPDATE_LAYOUT 20 + +/*************************************************************************/ +/** + * DRM_VMW_GET_PARAM - get device information. + * + * DRM_VMW_PARAM_FIFO_OFFSET: + * Offset to use to map the first page of the FIFO read-only. + * The fifo is mapped using the mmap() system call on the drm device. + * + * DRM_VMW_PARAM_OVERLAY_IOCTL: + * Does the driver support the overlay ioctl. + */ + +#define DRM_VMW_PARAM_NUM_STREAMS 0 +#define DRM_VMW_PARAM_NUM_FREE_STREAMS 1 +#define DRM_VMW_PARAM_3D 2 +#define DRM_VMW_PARAM_HW_CAPS 3 +#define DRM_VMW_PARAM_FIFO_CAPS 4 +#define DRM_VMW_PARAM_MAX_FB_SIZE 5 +#define DRM_VMW_PARAM_FIFO_HW_VERSION 6 + +/** + * struct drm_vmw_getparam_arg + * + * @value: Returned value. //Out + * @param: Parameter to query. //In. + * + * Argument to the DRM_VMW_GET_PARAM Ioctl. + */ + +struct drm_vmw_getparam_arg { + uint64_t value; + uint32_t param; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_CONTEXT - Create a host context. + * + * Allocates a device unique context id, and queues a create context command + * for the host. Does not wait for host completion. + */ + +/** + * struct drm_vmw_context_arg + * + * @cid: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_context_arg { + int32_t cid; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_CONTEXT - Create a host context. + * + * Frees a global context id, and queues a destroy host command for the host. + * Does not wait for host completion. The context ID can be used directly + * in the command stream and shows up as the same context ID on the host. + */ + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_SURFACE - Create a host suface. + * + * Allocates a device unique surface id, and queues a create surface command + * for the host. Does not wait for host completion. The surface ID can be + * used directly in the command stream and shows up as the same surface + * ID on the host. + */ + +/** + * struct drm_wmv_surface_create_req + * + * @flags: Surface flags as understood by the host. + * @format: Surface format as understood by the host. + * @mip_levels: Number of mip levels for each face. + * An unused face should have 0 encoded. + * @size_addr: Address of a user-space array of sruct drm_vmw_size + * cast to an uint64_t for 32-64 bit compatibility. + * The size of the array should equal the total number of mipmap levels. + * @shareable: Boolean whether other clients (as identified by file descriptors) + * may reference this surface. + * @scanout: Boolean whether the surface is intended to be used as a + * scanout. + * + * Input data to the DRM_VMW_CREATE_SURFACE Ioctl. + * Output data from the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_create_req { + uint32_t flags; + uint32_t format; + uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES]; + uint64_t size_addr; + int32_t shareable; + int32_t scanout; +}; + +/** + * struct drm_wmv_surface_arg + * + * @sid: Surface id of created surface or surface to destroy or reference. + * + * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. + * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. + * Input argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_arg { + int32_t sid; + uint32_t pad64; +}; + +/** + * struct drm_vmw_size ioctl. + * + * @width - mip level width + * @height - mip level height + * @depth - mip level depth + * + * Description of a mip level. + * Input data to the DRM_WMW_CREATE_SURFACE Ioctl. + */ + +struct drm_vmw_size { + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t pad64; +}; + +/** + * union drm_vmw_surface_create_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_CREATE_SURFACE Ioctl. + */ + +union drm_vmw_surface_create_arg { + struct drm_vmw_surface_arg rep; + struct drm_vmw_surface_create_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_REF_SURFACE - Reference a host surface. + * + * Puts a reference on a host surface with a give sid, as previously + * returned by the DRM_VMW_CREATE_SURFACE ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface ID in the command + * stream. + * + * On successful return, the Ioctl returns the surface information given + * in the DRM_VMW_CREATE_SURFACE ioctl. + */ + +/** + * union drm_vmw_surface_reference_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +union drm_vmw_surface_reference_arg { + struct drm_vmw_surface_create_req rep; + struct drm_vmw_surface_arg req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_SURFACE - Unreference a host surface. + * + * Clear a reference previously put on a host surface. + * When all references are gone, including the one implicitly placed + * on creation, + * a destroy surface command will be queued for the host. + * Does not wait for completion. + */ + +/*************************************************************************/ +/** + * DRM_VMW_EXECBUF + * + * Submit a command buffer for execution on the host, and return a + * fence seqno that when signaled, indicates that the command buffer has + * executed. + */ + +/** + * struct drm_vmw_execbuf_arg + * + * @commands: User-space address of a command buffer cast to an uint64_t. + * @command-size: Size in bytes of the command buffer. + * @throttle-us: Sleep until software is less than @throttle_us + * microseconds ahead of hardware. The driver may round this value + * to the nearest kernel tick. + * @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an + * uint64_t. + * @version: Allows expanding the execbuf ioctl parameters without breaking + * backwards compatibility, since user-space will always tell the kernel + * which version it uses. + * @flags: Execbuf flags. None currently. + * + * Argument to the DRM_VMW_EXECBUF Ioctl. + */ + +#define DRM_VMW_EXECBUF_VERSION 1 + +struct drm_vmw_execbuf_arg { + uint64_t commands; + uint32_t command_size; + uint32_t throttle_us; + uint64_t fence_rep; + uint32_t version; + uint32_t flags; +}; + +/** + * struct drm_vmw_fence_rep + * + * @handle: Fence object handle for fence associated with a command submission. + * @mask: Fence flags relevant for this fence object. + * @seqno: Fence sequence number in fifo. A fence object with a lower + * seqno will signal the EXEC flag before a fence object with a higher + * seqno. This can be used by user-space to avoid kernel calls to determine + * whether a fence has signaled the EXEC flag. Note that @seqno will + * wrap at 32-bit. + * @passed_seqno: The highest seqno number processed by the hardware + * so far. This can be used to mark user-space fence objects as signaled, and + * to determine whether a fence seqno might be stale. + * @error: This member should've been set to -EFAULT on submission. + * The following actions should be take on completion: + * error == -EFAULT: Fence communication failed. The host is synchronized. + * Use the last fence id read from the FIFO fence register. + * error != 0 && error != -EFAULT: + * Fence submission failed. The host is synchronized. Use the fence_seq member. + * error == 0: All is OK, The host may not be synchronized. + * Use the fence_seq member. + * + * Input / Output data to the DRM_VMW_EXECBUF Ioctl. + */ + +struct drm_vmw_fence_rep { + uint32_t handle; + uint32_t mask; + uint32_t seqno; + uint32_t passed_seqno; + uint32_t pad64; + int32_t error; +}; + +/*************************************************************************/ +/** + * DRM_VMW_ALLOC_DMABUF + * + * Allocate a DMA buffer that is visible also to the host. + * NOTE: The buffer is + * identified by a handle and an offset, which are private to the guest, but + * useable in the command stream. The guest kernel may translate these + * and patch up the command stream accordingly. In the future, the offset may + * be zero at all times, or it may disappear from the interface before it is + * fixed. + * + * The DMA buffer may stay user-space mapped in the guest at all times, + * and is thus suitable for sub-allocation. + * + * DMA buffers are mapped using the mmap() syscall on the drm device. + */ + +/** + * struct drm_vmw_alloc_dmabuf_req + * + * @size: Required minimum size of the buffer. + * + * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_alloc_dmabuf_req { + uint32_t size; + uint32_t pad64; +}; + +/** + * struct drm_vmw_dmabuf_rep + * + * @map_handle: Offset to use in the mmap() call used to map the buffer. + * @handle: Handle unique to this buffer. Used for unreferencing. + * @cur_gmr_id: GMR id to use in the command stream when this buffer is + * referenced. See not above. + * @cur_gmr_offset: Offset to use in the command stream when this buffer is + * referenced. See note above. + * + * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_dmabuf_rep { + uint64_t map_handle; + uint32_t handle; + uint32_t cur_gmr_id; + uint32_t cur_gmr_offset; + uint32_t pad64; +}; + +/** + * union drm_vmw_dmabuf_arg + * + * @req: Input data as described above. + * @rep: Output data as described above. + * + * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +union drm_vmw_alloc_dmabuf_arg { + struct drm_vmw_alloc_dmabuf_req req; + struct drm_vmw_dmabuf_rep rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. + * + */ + +/** + * struct drm_vmw_unref_dmabuf_arg + * + * @handle: Handle indicating what buffer to free. Obtained from the + * DRM_VMW_ALLOC_DMABUF Ioctl. + * + * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. + */ + +struct drm_vmw_unref_dmabuf_arg { + uint32_t handle; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams. + * + * This IOCTL controls the overlay units of the svga device. + * The SVGA overlay units does not work like regular hardware units in + * that they do not automaticaly read back the contents of the given dma + * buffer. But instead only read back for each call to this ioctl, and + * at any point between this call being made and a following call that + * either changes the buffer or disables the stream. + */ + +/** + * struct drm_vmw_rect + * + * Defines a rectangle. Used in the overlay ioctl to define + * source and destination rectangle. + */ + +struct drm_vmw_rect { + int32_t x; + int32_t y; + uint32_t w; + uint32_t h; +}; + +/** + * struct drm_vmw_control_stream_arg + * + * @stream_id: Stearm to control + * @enabled: If false all following arguments are ignored. + * @handle: Handle to buffer for getting data from. + * @format: Format of the overlay as understood by the host. + * @width: Width of the overlay. + * @height: Height of the overlay. + * @size: Size of the overlay in bytes. + * @pitch: Array of pitches, the two last are only used for YUV12 formats. + * @offset: Offset from start of dma buffer to overlay. + * @src: Source rect, must be within the defined area above. + * @dst: Destination rect, x and y may be negative. + * + * Argument to the DRM_VMW_CONTROL_STREAM Ioctl. + */ + +struct drm_vmw_control_stream_arg { + uint32_t stream_id; + uint32_t enabled; + + uint32_t flags; + uint32_t color_key; + + uint32_t handle; + uint32_t offset; + int32_t format; + uint32_t size; + uint32_t width; + uint32_t height; + uint32_t pitch[3]; + + uint32_t pad64; + struct drm_vmw_rect src; + struct drm_vmw_rect dst; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CURSOR_BYPASS - Give extra information about cursor bypass. + * + */ + +#define DRM_VMW_CURSOR_BYPASS_ALL (1 << 0) +#define DRM_VMW_CURSOR_BYPASS_FLAGS (1) + +/** + * struct drm_vmw_cursor_bypass_arg + * + * @flags: Flags. + * @crtc_id: Crtc id, only used if DMR_CURSOR_BYPASS_ALL isn't passed. + * @xpos: X position of cursor. + * @ypos: Y position of cursor. + * @xhot: X hotspot. + * @yhot: Y hotspot. + * + * Argument to the DRM_VMW_CURSOR_BYPASS Ioctl. + */ + +struct drm_vmw_cursor_bypass_arg { + uint32_t flags; + uint32_t crtc_id; + int32_t xpos; + int32_t ypos; + int32_t xhot; + int32_t yhot; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CLAIM_STREAM - Claim a single stream. + */ + +/** + * struct drm_vmw_context_arg + * + * @stream_id: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_stream_arg { + uint32_t stream_id; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_STREAM - Unclaim a stream. + * + * Return a single stream that was claimed by this process. Also makes + * sure that the stream has been stopped. + */ + +/*************************************************************************/ +/** + * DRM_VMW_GET_3D_CAP + * + * Read 3D capabilities from the FIFO + * + */ + +/** + * struct drm_vmw_get_3d_cap_arg + * + * @buffer: Pointer to a buffer for capability data, cast to an uint64_t + * @size: Max size to copy + * + * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL + * ioctls. + */ + +struct drm_vmw_get_3d_cap_arg { + uint64_t buffer; + uint32_t max_size; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_WAIT + * + * Waits for a fence object to signal. The wait is interruptible, so that + * signals may be delivered during the interrupt. The wait may timeout, + * in which case the calls returns -EBUSY. If the wait is restarted, + * that is restarting without resetting @cookie_valid to zero, + * the timeout is computed from the first call. + * + * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait + * on: + * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command + * stream + * have executed. + * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish + * commands + * in the buffer given to the EXECBUF ioctl returning the fence object handle + * are available to user-space. + * + * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the + * fenc wait ioctl returns 0, the fence object has been unreferenced after + * the wait. + */ + +#define DRM_VMW_FENCE_FLAG_EXEC (1 << 0) +#define DRM_VMW_FENCE_FLAG_QUERY (1 << 1) + +#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0) + +/** + * struct drm_vmw_fence_wait_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @cookie_valid: Must be reset to 0 on first call. Left alone on restart. + * @kernel_cookie: Set to 0 on first call. Left alone on restart. + * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout. + * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick + * before returning. + * @flags: Fence flags to wait on. + * @wait_options: Options that control the behaviour of the wait ioctl. + * + * Input argument to the DRM_VMW_FENCE_WAIT ioctl. + */ + +struct drm_vmw_fence_wait_arg { + uint32_t handle; + int32_t cookie_valid; + uint64_t kernel_cookie; + uint64_t timeout_us; + int32_t lazy; + int32_t flags; + int32_t wait_options; + int32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_SIGNALED + * + * Checks if a fence object is signaled.. + */ + +/** + * struct drm_vmw_fence_signaled_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl + * @signaled: Out: Flags signaled. + * @sequence: Out: Highest sequence passed so far. Can be used to signal the + * EXEC flag of user-space fence objects. + * + * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF + * ioctls. + */ + +struct drm_vmw_fence_signaled_arg { + uint32_t handle; + uint32_t flags; + int32_t signaled; + uint32_t passed_seqno; + uint32_t signaled_flags; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_UNREF + * + * Unreferences a fence object, and causes it to be destroyed if there are no + * other references to it. + * + */ + +/** + * struct drm_vmw_fence_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * + * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl.. + */ + +struct drm_vmw_fence_arg { + uint32_t handle; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_EVENT + * + * Queues an event on a fence to be delivered on the drm character device + * when the fence has signaled the DRM_VMW_FENCE_FLAG_EXEC flag. + * Optionally the approximate time when the fence signaled is + * given by the event. + */ + +/* + * The event type + */ +#define DRM_VMW_EVENT_FENCE_SIGNALED 0x80000000 + +struct drm_vmw_event_fence { + struct drm_event base; + uint64_t user_data; + uint32_t tv_sec; + uint32_t tv_usec; +}; + +/* + * Flags that may be given to the command. + */ +/* Request fence signaled time on the event. */ +#define DRM_VMW_FE_FLAG_REQ_TIME (1 << 0) + +/** + * struct drm_vmw_fence_event_arg + * + * @fence_rep: Pointer to fence_rep structure cast to uint64_t or 0 if + * the fence is not supposed to be referenced by user-space. + * @user_info: Info to be delivered with the event. + * @handle: Attach the event to this fence only. + * @flags: A set of flags as defined above. + */ +struct drm_vmw_fence_event_arg { + uint64_t fence_rep; + uint64_t user_data; + uint32_t handle; + uint32_t flags; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT + * + * Executes an SVGA present on a given fb for a given surface. The surface + * is placed on the framebuffer. Cliprects are given relative to the given + * point (the point disignated by dest_{x|y}). + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: framebuffer id to present / read back from. + * @sid: Surface id to present from. + * @dest_x: X placement coordinate for surface. + * @dest_y: Y placement coordinate for surface. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @num_clips: Number of cliprects given relative to the framebuffer origin, + * in the same coordinate space as the frame buffer. + * @pad64: Unused 64-bit padding. + * + * Input argument to the DRM_VMW_PRESENT ioctl. + */ + +struct drm_vmw_present_arg { + uint32_t fb_id; + uint32_t sid; + int32_t dest_x; + int32_t dest_y; + uint64_t clips_ptr; + uint32_t num_clips; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT_READBACK + * + * Executes an SVGA present readback from a given fb to the dma buffer + * currently bound as the fb. If there is no dma buffer bound to the fb, + * an error will be returned. + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: fb_id to present / read back from. + * @num_clips: Number of cliprects. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t. + * If this member is NULL, then the ioctl should not return a fence. + */ + +struct drm_vmw_present_readback_arg { + uint32_t fb_id; + uint32_t num_clips; + uint64_t clips_ptr; + uint64_t fence_rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UPDATE_LAYOUT - Update layout + * + * Updates the preferred modes and connection status for connectors. The + * command consists of one drm_vmw_update_layout_arg pointing to an array + * of num_outputs drm_vmw_rect's. + */ + +/** + * struct drm_vmw_update_layout_arg + * + * @num_outputs: number of active connectors + * @rects: pointer to array of drm_vmw_rect cast to an uint64_t + * + * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl. + */ +struct drm_vmw_update_layout_arg { + uint32_t num_outputs; + uint32_t pad64; + uint64_t rects; +}; + +#endif diff --git a/vmwgfx/vmwgfx_drmi.c b/vmwgfx/vmwgfx_drmi.c new file mode 100644 index 0000000..e326d31 --- /dev/null +++ b/vmwgfx/vmwgfx_drmi.c @@ -0,0 +1,502 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <errno.h> +#include <sys/mman.h> +#include "vmwgfx_drm.h" +#include <xf86drm.h> +#include "vmwgfx_drmi.h" + +#define uint32 uint32_t +#define int32 int32_t +#define uint16 uint16_t +#define uint8 uint8_t + +#include "svga3d_reg.h" +#include "vmwgfx_driver.h" + +static int +vmwgfx_fence_wait(int drm_fd, uint32_t handle, Bool unref) +{ + struct drm_vmw_fence_wait_arg farg; + memset(&farg, 0, sizeof(farg)); + + farg.handle = handle; + farg.flags = DRM_VMW_FENCE_FLAG_EXEC; + farg.timeout_us = 10*1000000; + farg.cookie_valid = 0; + + if (unref) + farg.wait_options |= DRM_VMW_WAIT_OPTION_UNREF; + + return drmCommandWriteRead(drm_fd, DRM_VMW_FENCE_WAIT, &farg, + sizeof(farg)); +} + +static void +vmwgfx_fence_unref(int drm_fd, uint32_t handle) +{ + struct drm_vmw_fence_arg farg; + memset(&farg, 0, sizeof(farg)); + + farg.handle = handle; + + (void) drmCommandWrite(drm_fd, DRM_VMW_FENCE_UNREF, &farg, + sizeof(farg)); +} + + +int +vmwgfx_present_readback(int drm_fd, uint32_t fb_id, RegionPtr region) +{ + BoxPtr clips = REGION_RECTS(region); + unsigned int num_clips = REGION_NUM_RECTS(region); + struct drm_vmw_fence_rep rep; + struct drm_vmw_present_readback_arg arg; + int ret; + unsigned i; + struct drm_vmw_rect *rects, *r; + + rects = calloc(num_clips, sizeof(*rects)); + if (!rects) { + LogMessage(X_ERROR, "Failed to alloc cliprects for " + "present readback.\n"); + return -1; + } + + memset(&arg, 0, sizeof(arg)); + memset(&rep, 0, sizeof(rep)); + + arg.fb_id = fb_id; + arg.num_clips = num_clips; + arg.clips_ptr = (unsigned long) rects; + arg.fence_rep = (unsigned long) &rep; + rep.error = -EFAULT; + + for (i = 0, r = rects; i < num_clips; ++i, ++r, ++clips) { + r->x = clips->x1; + r->y = clips->y1; + r->w = clips->x2 - clips->x1; + r->h = clips->y2 - clips->y1; + } + + ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT_READBACK, &arg, sizeof(arg)); + if (ret) + LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret)); + free(rects); + + /* + * Sync to avoid racing with Xorg SW rendering. + */ + + if (rep.error == 0) { + ret = vmwgfx_fence_wait(drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "Present readback fence wait error %s.\n", + strerror(-ret)); + vmwgfx_fence_unref(drm_fd, rep.handle); + } + } + + return 0; +} + + +int +vmwgfx_present(int drm_fd, uint32_t fb_id, unsigned int dst_x, + unsigned int dst_y, RegionPtr region, uint32_t handle) +{ + BoxPtr clips = REGION_RECTS(region); + unsigned int num_clips = REGION_NUM_RECTS(region); + struct drm_vmw_present_arg arg; + unsigned int i; + struct drm_vmw_rect *rects, *r; + int ret; + + if (num_clips == 0) + return 0; + + rects = calloc(num_clips, sizeof(*rects)); + if (!rects) { + LogMessage(X_ERROR, "Failed to alloc cliprects for " + "present.\n"); + return -1; + } + + memset(&arg, 0, sizeof(arg)); + arg.fb_id = fb_id; + arg.sid = handle; + arg.dest_x = dst_x; + arg.dest_y = dst_y; + arg.num_clips = num_clips; + arg.clips_ptr = (unsigned long) rects; + + for (i = 0, r = rects; i < num_clips; ++i, ++r, ++clips) { + r->x = clips->x1; + r->y = clips->y1; + r->w = clips->x2 - clips->x1; + r->h = clips->y2 - clips->y1; + } + + ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT, &arg, sizeof(arg)); + if (ret) { + LogMessage(X_ERROR, "Present error %s.\n", strerror(-ret)); + } + + free(rects); + return ((ret != 0) ? -1 : 0); +} + + +struct vmwgfx_int_dmabuf { + struct vmwgfx_dmabuf buf; + uint64_t map_handle; + uint64_t sync_handle; + int sync_valid; + int drm_fd; + uint32_t map_count; + void *addr; +}; + +static inline struct vmwgfx_int_dmabuf * +vmwgfx_int_dmabuf(struct vmwgfx_dmabuf *buf) +{ + return (struct vmwgfx_int_dmabuf *) buf; +} + +struct vmwgfx_dmabuf* +vmwgfx_dmabuf_alloc(int drm_fd, size_t size) +{ + union drm_vmw_alloc_dmabuf_arg arg; + struct vmwgfx_dmabuf *buf; + struct vmwgfx_int_dmabuf *ibuf; + int ret; + + ibuf = calloc(1, sizeof(*ibuf)); + if (!ibuf) + return NULL; + + buf = &ibuf->buf; + memset(&arg, 0, sizeof(arg)); + arg.req.size = size; + + ret = drmCommandWriteRead(drm_fd, DRM_VMW_ALLOC_DMABUF, &arg, + sizeof(arg)); + if (ret) + goto out_kernel_fail; + + ibuf = vmwgfx_int_dmabuf(buf); + ibuf->map_handle = arg.rep.map_handle; + ibuf->drm_fd = drm_fd; + buf->handle = arg.rep.handle; + buf->gmr_id = arg.rep.cur_gmr_id; + buf->gmr_offset = arg.rep.cur_gmr_offset; + buf->size = size; + + return buf; + out_kernel_fail: + free(buf); + return NULL; +} + +void * +vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf) +{ + struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf); + + if (ibuf->addr) + return ibuf->addr; + + ibuf->addr = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED, + ibuf->drm_fd, ibuf->map_handle); + + if (ibuf->addr == MAP_FAILED) { + ibuf->addr = NULL; + return NULL; + } + + ibuf->map_count++; + return ibuf->addr; +} + +void +vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf) +{ + struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf); + + if (--ibuf->map_count) + return; + + /* + * It's a pretty important performance optimzation not to call + * munmap here, although we should watch out for cases where we might fill + * the virtual memory space of the process. + */ +} + +void +vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf) +{ + struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf); + struct drm_vmw_unref_dmabuf_arg arg; + + if (ibuf->addr) { + munmap(ibuf->addr, buf->size); + ibuf->addr = NULL; + } + + memset(&arg, 0, sizeof(arg)); + arg.handle = buf->handle; + + (void) drmCommandWrite(ibuf->drm_fd, DRM_VMW_UNREF_DMABUF, &arg, + sizeof(arg)); + free(buf); +} + +int +vmwgfx_dma(unsigned int host_x, unsigned int host_y, + RegionPtr region, struct vmwgfx_dmabuf *buf, + uint32_t buf_pitch, uint32_t surface_handle, int to_surface) +{ + BoxPtr clips = REGION_RECTS(region); + unsigned int num_clips = REGION_NUM_RECTS(region); + struct drm_vmw_execbuf_arg arg; + struct drm_vmw_fence_rep rep; + int ret; + unsigned int size; + unsigned i; + SVGA3dCopyBox *cb; + SVGA3dCmdSurfaceDMASuffix *suffix; + SVGA3dCmdSurfaceDMA *body; + struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf); + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceDMA body; + SVGA3dCopyBox cb; + } *cmd; + + if (num_clips == 0) + return 0; + + size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cb) + + sizeof(*suffix); + cmd = malloc(size); + if (!cmd) + return -1; + + cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; + cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cb) + + sizeof(*suffix); + cb = &cmd->cb; + + suffix = (SVGA3dCmdSurfaceDMASuffix *) &cb[num_clips]; + suffix->suffixSize = sizeof(*suffix); + suffix->maximumOffset = (uint32_t) -1; + suffix->flags.discard = 0; + suffix->flags.unsynchronized = 0; + suffix->flags.reserved = 0; + + body = &cmd->body; + body->guest.ptr.gmrId = buf->gmr_id; + body->guest.ptr.offset = buf->gmr_offset; + body->guest.pitch = buf_pitch; + body->host.sid = surface_handle; + body->host.face = 0; + body->host.mipmap = 0; + + body->transfer = (to_surface ? SVGA3D_WRITE_HOST_VRAM : + SVGA3D_READ_HOST_VRAM); + + + for (i=0; i < num_clips; i++, cb++, clips++) { + cb->x = (uint16_t) clips->x1 + host_x; + cb->y = (uint16_t) clips->y1 + host_y; + cb->z = 0; + cb->srcx = (uint16_t) clips->x1; + cb->srcy = (uint16_t) clips->y1; + cb->srcz = 0; + cb->w = (uint16_t) (clips->x2 - clips->x1); + cb->h = (uint16_t) (clips->y2 - clips->y1); + cb->d = 1; +#if 0 + LogMessage(X_INFO, "DMA! x: %u y: %u srcx: %u srcy: %u w: %u h: %u %s\n", + cb->x, cb->y, cb->srcx, cb->srcy, cb->w, cb->h, + to_surface ? "to" : "from"); +#endif + + } + + memset(&arg, 0, sizeof(arg)); + memset(&rep, 0, sizeof(rep)); + + rep.error = -EFAULT; + arg.fence_rep = ((to_surface) ? 0UL : (unsigned long)&rep); + arg.commands = (unsigned long)cmd; + arg.command_size = size; + arg.throttle_us = 0; + arg.version = DRM_VMW_EXECBUF_VERSION; + + ret = drmCommandWrite(ibuf->drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg)); + if (ret) { + LogMessage(X_ERROR, "DMA error %s.\n", strerror(-ret)); + } + + free(cmd); + + if (rep.error == 0) { + ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "DMA from host fence wait error %s.\n", + strerror(-ret)); + vmwgfx_fence_unref(ibuf->drm_fd, rep.handle); + } + } + + return 0; +} + +int +vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out) +{ + struct drm_vmw_getparam_arg gp_arg; + int ret; + + memset(&gp_arg, 0, sizeof(gp_arg)); + gp_arg.param = param; + ret = drmCommandWriteRead(drm_fd, DRM_VMW_GET_PARAM, + &gp_arg, sizeof(gp_arg)); + + if (ret == 0) { + *out = gp_arg.value; + } + + return ret; +} + +int +vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree) +{ + uint64_t v1, v2; + int ret; + + ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_STREAMS, &v1); + if (ret) + return ret; + + ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_FREE_STREAMS, &v2); + if (ret) + return ret; + + *ntot = (uint32_t)v1; + *nfree = (uint32_t)v2; + + return 0; +} + +int +vmwgfx_claim_stream(int drm_fd, uint32_t *out) +{ + struct drm_vmw_stream_arg s_arg; + int ret; + + ret = drmCommandRead(drm_fd, DRM_VMW_CLAIM_STREAM, + &s_arg, sizeof(s_arg)); + + if (ret) + return -1; + + *out = s_arg.stream_id; + return 0; +} + +int +vmwgfx_unref_stream(int drm_fd, uint32_t stream_id) +{ + struct drm_vmw_stream_arg s_arg; + int ret; + + memset(&s_arg, 0, sizeof(s_arg)); + s_arg.stream_id = stream_id; + + ret = drmCommandWrite(drm_fd, DRM_VMW_UNREF_STREAM, + &s_arg, sizeof(s_arg)); + + return 0; +} + +int +vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot) +{ + struct drm_vmw_cursor_bypass_arg arg; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.flags = DRM_VMW_CURSOR_BYPASS_ALL; + arg.xhot = xhot; + arg.yhot = yhot; + + ret = drmCommandWrite(drm_fd, DRM_VMW_CURSOR_BYPASS, + &arg, sizeof(arg)); + + return ret; +} + +int +vmwgfx_update_gui_layout(int drm_fd, unsigned int num_rects, + struct drm_vmw_rect *rects) +{ + struct drm_vmw_update_layout_arg arg; + + memset(&arg, 0, sizeof(arg)); + + arg.num_outputs = num_rects; + arg.rects = (unsigned long) rects; + + return drmCommandWrite(drm_fd, DRM_VMW_UPDATE_LAYOUT, &arg, + sizeof(arg)); +} + + +int +vmwgfx_max_fb_size(int drm_fd, size_t *size) +{ + uint64_t tmp_size; + + if (vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_MAX_FB_SIZE, &tmp_size) != 0) + return -1; + + *size = tmp_size; + + return 0; +} diff --git a/vmwgfx/vmwgfx_drmi.h b/vmwgfx/vmwgfx_drmi.h new file mode 100644 index 0000000..2435009 --- /dev/null +++ b/vmwgfx/vmwgfx_drmi.h @@ -0,0 +1,87 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#ifndef _VMWGFX_DRMI_H_ +#define _VMWGFX_DRMI_H_ + +#include <xorg-server.h> +#include <regionstr.h> +#include <stdint.h> +#include "vmwgfx_drm.h" + +struct vmwgfx_dma_ctx; + +extern int +vmwgfx_present_readback(int drm_fd, uint32_t fb_id, RegionPtr region); + +extern int +vmwgfx_present(int drm_fd, uint32_t fb_id, unsigned int dst_x, + unsigned int dst_y, RegionPtr region, uint32_t handle); + +struct vmwgfx_dmabuf { + uint32_t handle; + uint32_t gmr_id; + uint32_t gmr_offset; + size_t size; +}; + +extern struct vmwgfx_dmabuf* +vmwgfx_dmabuf_alloc(int drm_fd, size_t size); +extern void +vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf); +extern void * +vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf); +extern void +vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf); + +extern int +vmwgfx_dma(unsigned int host_x, unsigned int host_y, + RegionPtr region, struct vmwgfx_dmabuf *buf, + uint32_t buf_pitch, uint32_t surface_handle, int to_surface); + +extern int +vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree); + +extern int +vmwgfx_claim_stream(int drm_fd, uint32_t *out); + +extern int +vmwgfx_unref_stream(int drm_fd, uint32_t stream_id); + +int +vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot); + +int +vmwgfx_max_fb_size(int drm_fd, size_t *size); + +int +vmwgfx_update_gui_layout(int drm_fd, unsigned int num_rects, + struct drm_vmw_rect *rects); +int +vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out); +#endif diff --git a/vmwgfx/vmwgfx_output.c b/vmwgfx/vmwgfx_output.c new file mode 100644 index 0000000..4f52f1d --- /dev/null +++ b/vmwgfx/vmwgfx_output.c @@ -0,0 +1,393 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +#include "vmwgfx_driver.h" + +struct output_private +{ + drmModeConnectorPtr drm_connector; + + int c; + + Bool is_implicit; +}; + +static char *output_enum_list[] = { + "Unknown", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "SVIDEO", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "EDP", + "Virtual", +}; + +static void +output_create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE +#endif /* RANDR_12_INTERFACE */ +} + +static void +output_dpms(xf86OutputPtr output, int mode) +{ +} + +static xf86OutputStatus +output_detect(xf86OutputPtr output) +{ + modesettingPtr ms = modesettingPTR(output->scrn); + struct output_private *priv = output->driver_private; + drmModeConnectorPtr drm_connector; + xf86OutputStatus status; + + drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id); + if (drm_connector) { + drmModeFreeConnector(priv->drm_connector); + priv->drm_connector = drm_connector; + } else { + drm_connector = priv->drm_connector; + } + + switch (drm_connector->connection) { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + break; + default: + status = XF86OutputStatusUnknown; + } + + return status; +} + +static DisplayModePtr +output_get_modes(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + drmModeConnectorPtr drm_connector = priv->drm_connector; + drmModeModeInfoPtr drm_mode = NULL; + DisplayModePtr modes = NULL, mode = NULL; + int i; + + for (i = 0; i < drm_connector->count_modes; i++) { + drm_mode = &drm_connector->modes[i]; + if (drm_mode) { + mode = calloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->Clock = drm_mode->clock; + mode->HDisplay = drm_mode->hdisplay; + mode->HSyncStart = drm_mode->hsync_start; + mode->HSyncEnd = drm_mode->hsync_end; + mode->HTotal = drm_mode->htotal; + mode->VDisplay = drm_mode->vdisplay; + mode->VSyncStart = drm_mode->vsync_start; + mode->VSyncEnd = drm_mode->vsync_end; + mode->VTotal = drm_mode->vtotal; + mode->Flags = drm_mode->flags; + mode->HSkew = drm_mode->hskew; + mode->VScan = drm_mode->vscan; + mode->VRefresh = xf86ModeVRefresh(mode); + mode->Private = (void *)drm_mode; + mode->type = 0; + if (drm_mode->type & DRM_MODE_TYPE_PREFERRED) + mode->type |= M_T_PREFERRED; + if (drm_mode->type & DRM_MODE_TYPE_DRIVER) + mode->type |= M_T_DRIVER; + xf86SetModeDefaultName(mode); + modes = xf86ModesAdd(modes, mode); + xf86PrintModeline(0, mode); + } + } + + return modes; +} + +static int +output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + // modesettingPtr ms = modesettingPTR(output->scrn); + // CustomizerPtr cust = ms->cust; + +#if 0 + if (cust && cust->winsys_check_fb_size && + !cust->winsys_check_fb_size(cust, pMode->HDisplay * + output->scrn->bitsPerPixel / 8, + pMode->VDisplay)) + return MODE_BAD; +#endif + return MODE_OK; +} + +#ifdef RANDR_12_INTERFACE +static Bool +output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) +{ + return TRUE; +} +#endif /* RANDR_12_INTERFACE */ + +#ifdef RANDR_13_INTERFACE +static Bool +output_get_property(xf86OutputPtr output, Atom property) +{ + return TRUE; +} +#endif /* RANDR_13_INTERFACE */ + +static void +output_destroy(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + drmModeFreeConnector(priv->drm_connector); + free(priv); + output->driver_private = NULL; +} + +static const xf86OutputFuncsRec output_funcs = { + .create_resources = output_create_resources, +#ifdef RANDR_12_INTERFACE + .set_property = output_set_property, +#endif +#ifdef RANDR_13_INTERFACE + .get_property = output_get_property, +#endif + .dpms = output_dpms, + .detect = output_detect, + + .get_modes = output_get_modes, + .mode_valid = output_mode_valid, + .destroy = output_destroy, +}; + +/** + * vmwgfx_output_explicit_overlap -- Check for explicit output overlaps + * + * This function returns TRUE iff the bounding box in screen space of an + * exlplicit output overlaps the bounding box in screen space of any other + * output. + */ +Bool +vmwgfx_output_explicit_overlap(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + ScreenPtr pScreen = pScrn->pScreen; + RegionRec output_union; + RegionRec cur_output; + RegionRec result; + struct output_private *priv; + xf86CrtcPtr crtc; + Bool overlap = FALSE; + int i; + + (void) pScreen; + REGION_NULL(pScreen, &output_union); + REGION_NULL(pScreen, &cur_output); + REGION_NULL(pScreen, &result); + + /* + * Collect a region of implicit outputs. These may overlap. + */ + for (i = 0; i < config->num_output; i++) { + output = config->output[i]; + priv = output->driver_private; + crtc = output->crtc; + + if (!crtc || !crtc->enabled || !priv->is_implicit) + continue; + + REGION_RESET(pScreen, &cur_output, &crtc->bounds); + REGION_UNION(pScreen, &output_union, &output_union, &cur_output); + } + + /* + * Explicit outputs may not overlap any other output. + */ + for (i = 0; i < config->num_output; i++) { + output = config->output[i]; + priv = output->driver_private; + crtc = output->crtc; + + if (!crtc || !crtc->enabled || priv->is_implicit) + continue; + + REGION_RESET(pScreen, &cur_output, &crtc->bounds); + REGION_NULL(pScreen, &result); + REGION_INTERSECT(pScreen, &result, &output_union, &cur_output); + overlap = REGION_NOTEMPTY(vsaa->pScreen, &result); + if (overlap) + break; + + REGION_UNION(pScreen, &output_union, &output_union, &cur_output); + } + + REGION_UNINIT(pScreen, &output_union); + REGION_UNINIT(pScreen, &cur_output); + REGION_UNINIT(pScreen, &result); + + return overlap; +} + +void +xorg_output_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86OutputPtr output; + drmModeResPtr res; + drmModeConnectorPtr drm_connector = NULL; + drmModeEncoderPtr drm_encoder = NULL; + struct output_private *priv; + char name[32]; + int c, p; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + DRV_ERROR("Failed drmModeGetResources\n"); + return; + } + + for (c = 0; c < res->count_connectors; c++) { + Bool is_implicit = TRUE; + + drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]); + if (!drm_connector) + goto out; + + + for (p = 0; p < drm_connector->count_props; p++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(ms->fd, drm_connector->props[p]); + + if (prop) { + +#if 0 + /* + * Disabled until we sort out what the interface should + * look like. + */ + + if (strcmp(prop->name, "implicit placement") == 0) { + drmModeConnectorSetProperty(ms->fd, + drm_connector->connector_id, + prop->prop_id, + 0); + is_implicit = FALSE; + } +#endif + drmModeFreeProperty(prop); + } + } + + if (drm_connector->connector_type >= + sizeof(output_enum_list) / sizeof(output_enum_list[0])) + drm_connector->connector_type = 0; + + snprintf(name, 32, "%s%d", + output_enum_list[drm_connector->connector_type], + drm_connector->connector_type_id); + + + priv = calloc(sizeof(*priv), 1); + if (!priv) { + continue; + } + + output = xf86OutputCreate(pScrn, &output_funcs, name); + if (!output) { + free(priv); + continue; + } + + priv->is_implicit = is_implicit; + + drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]); + if (drm_encoder) { + output->possible_crtcs = drm_encoder->possible_crtcs; + output->possible_clones = drm_encoder->possible_clones; + } else { + output->possible_crtcs = 0; + output->possible_clones = 0; + } + priv->c = c; + priv->drm_connector = drm_connector; + output->driver_private = priv; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + } + + out: + drmModeFreeResources(res); +} + +unsigned +xorg_output_get_id(xf86OutputPtr output) +{ + struct output_private *priv = output->driver_private; + return priv->drm_connector->connector_id; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/vmwgfx/vmwgfx_overlay.c b/vmwgfx/vmwgfx_overlay.c new file mode 100644 index 0000000..6624a10 --- /dev/null +++ b/vmwgfx/vmwgfx_overlay.c @@ -0,0 +1,893 @@ +/* + * Copyright 2007-2011 by VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + * + */ + +/* + * vmwarevideo.c -- + * + * Xv extension support. + * See http://www.xfree86.org/current/DESIGN16.html + * + */ + + +#include "xf86xv.h" +#include "fourcc.h" +#define debug_printf(...) + +/* + * We can't incude svga_types.h due to conflicting types for Bool. + */ +typedef int64_t int64; +typedef uint64_t uint64; + +typedef int32_t int32; +typedef uint32_t uint32; + +typedef int16_t int16; +typedef uint16_t uint16; + +typedef int8_t int8; +typedef uint8_t uint8; + +#include "../src/svga_reg.h" +#include "../src/svga_escape.h" +#include "../src/svga_overlay.h" + +#include <X11/extensions/Xv.h> + +#include "xf86drm.h" +#include "vmwgfx_drm.h" +#include "vmwgfx_drmi.h" +#include "vmwgfx_driver.h" + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* + * Number of videos that can be played simultaneously + */ +#define VMWARE_VID_NUM_PORTS 1 + +/* + * Using a dark shade as the default colorKey + */ +#define VMWARE_VIDEO_COLORKEY 0x100701 + +/* + * Maximum dimensions + */ +#define VMWARE_VID_MAX_WIDTH 2048 +#define VMWARE_VID_MAX_HEIGHT 2048 + +#define VMWARE_VID_NUM_ENCODINGS 1 +static XF86VideoEncodingRec vmwareVideoEncodings[] = +{ + { + 0, + "XV_IMAGE", + VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT, + {1, 1} + } +}; + +#define VMWARE_VID_NUM_FORMATS 2 +static XF86VideoFormatRec vmwareVideoFormats[] = +{ + { 16, TrueColor}, + { 24, TrueColor} +}; + +#define VMWARE_VID_NUM_IMAGES 3 +static XF86ImageRec vmwareVideoImages[] = +{ + XVIMAGE_YV12, + XVIMAGE_YUY2, + XVIMAGE_UYVY +}; + +#define VMWARE_VID_NUM_ATTRIBUTES 2 +static XF86AttributeRec vmwareVideoAttributes[] = +{ + { + XvGettable | XvSettable, + 0x000000, + 0xffffff, + "XV_COLORKEY" + }, + { + XvGettable | XvSettable, + 0, + 1, + "XV_AUTOPAINT_COLORKEY" + } +}; + +/* + * Video frames are stored in a circular list of buffers. + * Must be power or two, See vmw_video_port_play. + */ +#define VMWARE_VID_NUM_BUFFERS 1 + +/* + * Defines the structure used to hold and pass video data to the host + */ +struct vmw_video_buffer +{ + int size; + void *data; + struct vmwgfx_dmabuf *buf; +}; + + +/** + * Structure representing a single video stream, aka port. + * + * Ports maps one to one to a SVGA stream. Port is just + * what Xv calls a SVGA stream. + */ +struct vmwgfx_overlay_port +{ + /* + * Function prototype same as XvPutImage. + * + * This is either set to vmw_video_port_init or vmw_video_port_play. + * At init this function is set to port_init. In port_init we set it + * to port_play and call it, after initializing the struct. + */ + int (*play)(ScrnInfoPtr, struct vmwgfx_overlay_port *, + short, short, short, short, short, + short, short, short, int, unsigned char*, + short, short, RegionPtr); + + /* values to go into the SVGAOverlayUnit */ + uint32 streamId; + uint32 colorKey; + uint32 flags; + + /* round robin of buffers */ + unsigned currBuf; + struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS]; + + /* properties that applies to all buffers */ + int size; + int pitches[3]; + int offsets[3]; + + /* things for X */ + RegionRec clipBoxes; + Bool isAutoPaintColorkey; + int drm_fd; +}; + +/* + * Callback functions exported to Xv, prefixed with vmw_xv_*. + */ +static int vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y, + short drw_x, short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int image, + unsigned char *buf, short width, short height, + Bool sync, RegionPtr clipBoxes, pointer data, + DrawablePtr dst); +static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup); +static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format, + unsigned short *width, + unsigned short *height, int *pitches, + int *offsets); +static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 value, pointer data); +static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 *value, pointer data); +static void vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion, + short vid_w, short vid_h, short drw_w, + short drw_h, unsigned int *p_w, + unsigned int *p_h, pointer data); + + +/* + * Local functions. + */ +static int vmw_video_port_init(ScrnInfoPtr pScrn, + struct vmwgfx_overlay_port *port, + short src_x, short src_y, short drw_x, + short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int format, + unsigned char *buf, short width, + short height, RegionPtr clipBoxes); +static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port, + short src_x, short src_y, short drw_x, + short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int format, + unsigned char *buf, short width, + short height, RegionPtr clipBoxes); +static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port); + +static int vmw_video_buffer_alloc(int drm_fd, int size, + struct vmw_video_buffer *out); +static int vmw_video_buffer_free(struct vmw_video_buffer *out); + + +static struct vmwgfx_overlay_port * +vmwgfx_overlay_port_create(int drm_fd, ScreenPtr pScreen) +{ + struct vmwgfx_overlay_port *port = calloc(1, sizeof(*port)); + + if (!port) + return NULL; + + port->drm_fd = drm_fd; + port->play = vmw_video_port_init; + port->flags = SVGA_VIDEO_FLAG_COLORKEY; + port->colorKey = VMWARE_VIDEO_COLORKEY; + port->isAutoPaintColorkey = TRUE; + return port; +} + +void +vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports) +{ + if (free_ports) { + int i; + + for(i=0; i<adaptor->nPorts; ++i) { + free(adaptor->pPortPrivates[i].ptr); + } + } + + free(adaptor->pPortPrivates); + xf86XVFreeVideoAdaptorRec(adaptor); +} + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_init_adaptor -- + * + * Initializes a XF86VideoAdaptor structure with the capabilities and + * functions supported by this video driver. + * + * Results: + * On success initialized XF86VideoAdaptor struct or NULL on error + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +XF86VideoAdaptorPtr +vmw_video_init_adaptor(ScrnInfoPtr pScrn) +{ + XF86VideoAdaptorPtr adaptor; + modesettingPtr ms = modesettingPTR(pScrn); + int i; + DevUnion *dev_unions; + uint32_t ntot, nfree; + + if (vmwgfx_num_streams(ms->fd, &ntot, &nfree) != 0) { + debug_printf("No stream ioctl support\n"); + return NULL; + } + if (nfree == 0) { + debug_printf("No free streams\n"); + return NULL; + } + adaptor = xf86XVAllocateVideoAdaptorRec(pScrn); + dev_unions = calloc(VMWARE_VID_NUM_PORTS, sizeof(DevUnion)); + if (adaptor == NULL || dev_unions == NULL) { + xf86XVFreeVideoAdaptorRec(adaptor); + free(dev_unions); + return NULL; + } + + adaptor->type = XvInputMask | XvImageMask | XvWindowMask; + + /** + * Note: CLIP_TO_VIEWPORT was removed from the flags, since with the + * crtc/output based modesetting, the viewport is not updated on + * RandR modeswitches. Hence the video may incorrectly be clipped away. + * The correct approach, (if needed) would be to clip against the + * scanout area union of all active crtcs. Revisit if needed. + */ + + adaptor->flags = VIDEO_OVERLAID_IMAGES; + adaptor->name = "VMware Overlay Video Engine"; + adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS; + adaptor->pEncodings = vmwareVideoEncodings; + adaptor->nFormats = VMWARE_VID_NUM_FORMATS; + adaptor->pFormats = vmwareVideoFormats; + adaptor->nPorts = VMWARE_VID_NUM_PORTS; + adaptor->pPortPrivates = dev_unions; + + for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) { + struct vmwgfx_overlay_port *priv = + vmwgfx_overlay_port_create(ms->fd, pScrn->pScreen); + + adaptor->pPortPrivates[i].ptr = (pointer) priv; + } + + adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES; + adaptor->pAttributes = vmwareVideoAttributes; + adaptor->nImages = VMWARE_VID_NUM_IMAGES; + adaptor->pImages = vmwareVideoImages; + + adaptor->PutVideo = NULL; + adaptor->PutStill = NULL; + adaptor->GetVideo = NULL; + adaptor->GetStill = NULL; + adaptor->StopVideo = vmw_xv_stop_video; + adaptor->SetPortAttribute = vmw_xv_set_port_attribute; + adaptor->GetPortAttribute = vmw_xv_get_port_attribute; + adaptor->QueryBestSize = vmw_xv_query_best_size; + adaptor->PutImage = vmw_xv_put_image; + adaptor->QueryImageAttributes = vmw_xv_query_image_attributes; + + return adaptor; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_port_init -- + * + * Initializes a video stream in response to the first PutImage() on a + * video stream. The process goes as follows: + * - Figure out characteristics according to format + * - Allocate offscreen memory + * - Pass on video to Play() functions + * + * Results: + * Success or XvBadAlloc on failure. + * + * Side effects: + * Video stream is initialized and its first frame sent to the host + * (done by VideoPlay() function called at the end) + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_video_port_init(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port, + short src_x, short src_y, short drw_x, + short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int format, + unsigned char *buf, short width, + short height, RegionPtr clipBoxes) +{ + unsigned short w, h; + int i, ret; + + debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format); + + ret = vmwgfx_claim_stream(port->drm_fd, &port->streamId); + if (ret != 0) + return XvBadAlloc; + + w = width; + h = height; + /* init all the format attributes, used for buffers */ + port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h, + port->pitches, port->offsets); + + if (port->size == -1) { + ret = XvBadAlloc; + goto out_bad_size; + } + + for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) { + ret = vmw_video_buffer_alloc(port->drm_fd, port->size, &port->bufs[i]); + if (ret != Success) + goto out_no_buffer; + } + + port->currBuf = 0; + REGION_NULL(pScrn->pScreen, &port->clipBoxes); + port->play = vmw_video_port_play; + return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h, + drw_w, drw_h, format, buf, width, height, clipBoxes); + + out_no_buffer: + while(i-- != 0) { + vmw_video_buffer_free(&port->bufs[i]); + } + out_bad_size: + (void) vmwgfx_unref_stream(port->drm_fd, port->streamId); + + return ret; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_port_play -- + * + * Sends all the attributes associated with the video frame using the + * FIFO ESCAPE mechanism to the host. + * + * Results: + * Always returns Success. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port, + short src_x, short src_y, short drw_x, + short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int format, + unsigned char *buf, short width, + short height, RegionPtr clipBoxes) +{ + struct drm_vmw_control_stream_arg arg; + unsigned short w, h; + int size; + int ret; + + debug_printf("\t%s: enter\n", __func__); + + w = width; + h = height; + + /* we don't update the ports size */ + size = vmw_xv_query_image_attributes(pScrn, format, &w, &h, + port->pitches, port->offsets); + + if (size != port->size) { + vmw_xv_stop_video(pScrn, port, TRUE); + return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, + src_h, drw_w, drw_h, format, buf, width, height, + clipBoxes); + } + + memcpy(port->bufs[port->currBuf].data, buf, port->size); + + memset(&arg, 0, sizeof(arg)); + + arg.stream_id = port->streamId; + arg.enabled = TRUE; + arg.flags = port->flags; + arg.color_key = port->colorKey; + arg.handle = port->bufs[port->currBuf].buf->handle; + arg.format = format; + arg.size = port->size; + arg.width = w; + arg.height = h; + arg.src.x = src_x; + arg.src.y = src_y; + arg.src.w = src_w; + arg.src.h = src_h; + arg.dst.x = drw_x; + arg.dst.y = drw_y; + arg.dst.w = drw_w; + arg.dst.h = drw_h; + arg.pitch[0] = port->pitches[0]; + arg.pitch[1] = port->pitches[1]; + arg.pitch[2] = port->pitches[2]; + arg.offset = 0; + + /* + * Update the clipList and paint the colorkey, if required. + */ + if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) { + REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes); + if (port->isAutoPaintColorkey) + xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes); + } + + xorg_flush(pScrn->pScreen); + ret = drmCommandWrite(port->drm_fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg)); + if (ret) { + vmw_video_port_cleanup(pScrn, port); + return XvBadAlloc; + } + + if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS) + port->currBuf = 0; + + return Success; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_port_cleanup -- + * + * Frees up all resources (if any) taken by a video stream. + * + * Results: + * None. + * + * Side effects: + * Same as above. + * + *----------------------------------------------------------------------------- + */ + +static void +vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port) +{ + int i; + + debug_printf("\t%s: enter\n", __func__); + + if (port->play == vmw_video_port_init) + return; + + port->play = vmw_video_port_init; + (void) vmwgfx_unref_stream(port->drm_fd, port->streamId); + + for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) { + vmw_video_buffer_free(&port->bufs[i]); + } + + REGION_UNINIT(pScreen->pScreen, &port->clipBoxes); +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_buffer_alloc -- + * + * Allocates and map a kernel buffer to be used as data storage. + * + * Results: + * XvBadAlloc on failure, otherwise Success. + * + * Side effects: + * Calls into the kernel, sets members of out. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_video_buffer_alloc(int drm_fd, int size, + struct vmw_video_buffer *out) +{ + out->buf = vmwgfx_dmabuf_alloc(drm_fd, size); + if (!out->buf) + return XvBadAlloc; + + out->data = vmwgfx_dmabuf_map(out->buf); + if (!out->data) { + vmwgfx_dmabuf_destroy(out->buf); + out->buf = NULL; + return XvBadAlloc; + } + + out->size = size; + debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size); + + return Success; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_video_buffer_free -- + * + * Frees and unmaps an allocated kernel buffer. + * + * Results: + * Success. + * + * Side effects: + * Calls into the kernel, sets members of out to 0. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_video_buffer_free(struct vmw_video_buffer *out) +{ + if (out->size == 0) + return Success; + + vmwgfx_dmabuf_unmap(out->buf); + vmwgfx_dmabuf_destroy(out->buf); + + out->buf = NULL; + out->data = NULL; + out->size = 0; + + debug_printf("\t\t%s: freed buffer %p\n", __func__, out); + + return Success; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_put_image -- + * + * Main video playback function. It copies the passed data which is in + * the specified format (e.g. FOURCC_YV12) into the overlay. + * + * If sync is TRUE the driver should not return from this + * function until it is through reading the data from buf. + * + * Results: + * Success or XvBadAlloc on failure + * + * Side effects: + * Video port will be played(initialized if 1st frame) on success + * or will fail on error. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y, + short drw_x, short drw_y, short src_w, short src_h, + short drw_w, short drw_h, int format, + unsigned char *buf, short width, short height, + Bool sync, RegionPtr clipBoxes, pointer data, + DrawablePtr dst) +{ + struct vmwgfx_overlay_port *port = data; + + debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__, + src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h, + width, height); + + return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h, + drw_w, drw_h, format, buf, width, height, clipBoxes); +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_stop_video -- + * + * Called when we should stop playing video for a particular stream. If + * Cleanup is FALSE, the "stop" operation is only temporary, and thus we + * don't do anything. If Cleanup is TRUE we kill the video port by + * sending a message to the host and freeing up the stream. + * + * Results: + * None. + * + * Side effects: + * See above. + * + *----------------------------------------------------------------------------- + */ + +static void +vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup) +{ + struct vmwgfx_overlay_port *port = data; + + debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE"); + REGION_EMPTY(pScrn->pScreen, &port->clipBoxes); + + if (!cleanup) + return; + + vmw_video_port_cleanup(pScrn, port); +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_query_image_attributes -- + * + * From the spec: This function is called to let the driver specify how data + * for a particular image of size width by height should be stored. + * Sometimes only the size and corrected width and height are needed. In + * that case pitches and offsets are NULL. + * + * Results: + * The size of the memory required for the image, or -1 on error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format, + unsigned short *width, unsigned short *height, + int *pitches, int *offsets) +{ + INT32 size, tmp; + + if (*width > VMWARE_VID_MAX_WIDTH) { + *width = VMWARE_VID_MAX_WIDTH; + } + if (*height > VMWARE_VID_MAX_HEIGHT) { + *height = VMWARE_VID_MAX_HEIGHT; + } + + *width = (*width + 1) & ~1; + if (offsets != NULL) { + offsets[0] = 0; + } + + switch (format) { + case FOURCC_YV12: + *height = (*height + 1) & ~1; + size = (*width + 3) & ~3; + if (pitches) { + pitches[0] = size; + } + size *= *height; + if (offsets) { + offsets[1] = size; + } + tmp = ((*width >> 1) + 3) & ~3; + if (pitches) { + pitches[1] = pitches[2] = tmp; + } + tmp *= (*height >> 1); + size += tmp; + if (offsets) { + offsets[2] = size; + } + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + size = *width * 2; + if (pitches) { + pitches[0] = size; + } + size *= *height; + break; + default: + debug_printf("Query for invalid video format %d\n", format); + return -1; + } + return size; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_set_port_attribute -- + * + * From the spec: A port may have particular attributes such as colorKey, hue, + * saturation, brightness or contrast. Xv clients set these + * attribute values by sending attribute strings (Atoms) to the server. + * + * Results: + * Success if the attribute exists and XvBadAlloc otherwise. + * + * Side effects: + * The respective attribute gets the new value. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 value, pointer data) +{ + struct vmwgfx_overlay_port *port = data; + Atom xvColorKey = MAKE_ATOM("XV_COLORKEY"); + Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); + + if (attribute == xvColorKey) { + debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value); + port->colorKey = value; + } else if (attribute == xvAutoPaint) { + debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE"); + port->isAutoPaintColorkey = value; + } else { + return XvBadAlloc; + } + + return Success; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_get_port_attribute -- + * + * From the spec: A port may have particular attributes such as hue, + * saturation, brightness or contrast. Xv clients get these + * attribute values by sending attribute strings (Atoms) to the server + * + * Results: + * Success if the attribute exists and XvBadAlloc otherwise. + * + * Side effects: + * "value" contains the requested attribute on success. + * + *----------------------------------------------------------------------------- + */ + +static int +vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute, + INT32 *value, pointer data) +{ + struct vmwgfx_overlay_port *port = data; + Atom xvColorKey = MAKE_ATOM("XV_COLORKEY"); + Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); + + if (attribute == xvColorKey) { + *value = port->colorKey; + } else if (attribute == xvAutoPaint) { + *value = port->isAutoPaintColorkey; + } else { + return XvBadAlloc; + } + + return Success; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmw_xv_query_best_size -- + * + * From the spec: QueryBestSize provides the client with a way to query what + * the destination dimensions would end up being if they were to request + * that an area vid_w by vid_h from the video stream be scaled to rectangle + * of drw_w by drw_h on the screen. Since it is not expected that all + * hardware will be able to get the target dimensions exactly, it is + * important that the driver provide this function. + * + * This function seems to never be called, but to be on the safe side + * we apply the same logic that QueryImageAttributes has for width + * and height. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion, + short vid_w, short vid_h, short drw_w, + short drw_h, unsigned int *p_w, + unsigned int *p_h, pointer data) +{ + *p_w = (drw_w + 1) & ~1; + *p_h = drw_h; + + return; +} diff --git a/vmwgfx/vmwgfx_saa.c b/vmwgfx/vmwgfx_saa.c new file mode 100644 index 0000000..0a6b98f --- /dev/null +++ b/vmwgfx/vmwgfx_saa.c @@ -0,0 +1,1514 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#include <xorg-server.h> +#include <mi.h> +#include <fb.h> +#include <xf86drmMode.h> +#include <xa_context.h> +#include "vmwgfx_saa.h" +#include "vmwgfx_drmi.h" +#include "vmwgfx_saa_priv.h" + +/* + * Damage to be added as soon as we attach storage to the pixmap. + */ +static Bool +vmwgfx_pixmap_add_damage(PixmapPtr pixmap) +{ + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + DrawablePtr draw = &pixmap->drawable; + BoxRec box; + + if (spix->damage) + return TRUE; + + if (!saa_add_damage(pixmap)) + return FALSE; + + box.x1 = 0; + box.x2 = draw->width; + box.y1 = 0; + box.y2 = draw->height; + + if (vpix->hw) { + REGION_RESET(draw->pScreen, &spix->dirty_hw, &box); + REGION_EMPTY(draw->pScreen, &spix->dirty_shadow); + } else { + REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box); + REGION_EMPTY(draw->pScreen, &spix->dirty_hw); + } + + return TRUE; +} + +static void +vmwgfx_pixmap_remove_damage(PixmapPtr pixmap) +{ + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc) + return; + + DamageUnregister(&pixmap->drawable, spix->damage); + DamageDestroy(spix->damage); + spix->damage = NULL; +} + +static void +vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix) +{ + if (vpix->dirty_present) + REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present); + if (vpix->present_damage) + REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage); + if (vpix->pending_update) + REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update); + if (vpix->pending_present) + REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present); + vpix->dirty_present = NULL; + vpix->present_damage = NULL; + vpix->pending_update = NULL; + vpix->pending_present = NULL; +} + +static Bool +vmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + ScreenPtr pScreen = pixmap->drawable.pScreen; + (void) pScreen; + + if (present_opt) { + vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0); + if (!vpix->dirty_present) + return FALSE; + vpix->present_damage = REGION_CREATE(pScreen, NULL, 0); + if (!vpix->present_damage) + goto out_no_present_damage; + } + vpix->pending_update = REGION_CREATE(pScreen, NULL, 0); + if (!vpix->pending_update) + goto out_no_pending_update; + vpix->pending_present = REGION_CREATE(pScreen, NULL, 0); + if (!vpix->pending_present) + goto out_no_pending_present; + + return TRUE; + out_no_pending_present: + REGION_DESTROY(pScreen, vpix->pending_update); + out_no_pending_update: + if (vpix->present_damage) + REGION_DESTROY(pScreen, vpix->present_damage); + out_no_present_damage: + if (vpix->dirty_present) + REGION_DESTROY(pScreen, vpix->dirty_present); + return FALSE; +} + +static void +vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix) +{ + if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) { + free(vpix->malloc); + vpix->malloc = NULL; + } + if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) { + xa_surface_destroy(vpix->hw); + vpix->hw = NULL; + } + if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) { + vmwgfx_dmabuf_destroy(vpix->gmr); + vpix->gmr = NULL; + } +} + +static Bool +vmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + size_t size; + struct vmwgfx_dmabuf *gmr; + void *addr; + + if (vpix->gmr) + return TRUE; + + size = pixmap->devKind * pixmap->drawable.height; + gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); + if (!gmr) + return FALSE; + + if (vpix->malloc) { + + addr = vmwgfx_dmabuf_map(gmr); + if (!addr) + goto out_no_transfer; + memcpy(addr, vpix->malloc, size); + vmwgfx_dmabuf_unmap(gmr); + + } else if (!vmwgfx_pixmap_add_damage(pixmap)) + goto out_no_transfer; + + vpix->backing |= VMWGFX_PIX_GMR; + vpix->backing &= ~VMWGFX_PIX_MALLOC; + vpix->gmr = gmr; + + vmwgfx_pixmap_free_storage(vpix); + + return TRUE; + + out_no_transfer: + vmwgfx_dmabuf_destroy(gmr); + return FALSE; +} + +static Bool +vmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR))) + return FALSE; + + if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) { + vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height); + if (!vpix->malloc) + goto out_no_malloc; + if (!vmwgfx_pixmap_add_damage(pixmap)) + goto out_no_damage; + } else if (vpix->backing & VMWGFX_PIX_GMR) + return vmwgfx_pixmap_create_gmr(vsaa, pixmap); + + return TRUE; + + out_no_damage: + free(vpix->malloc); + vpix->malloc = NULL; + out_no_malloc: + return FALSE; +} + + +/** + * + * Makes sure all presented contents covered by @region are read + * back and are present in a valid GMR. + */ + +static Bool +vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap, + RegionPtr region) +{ + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + RegionRec intersection; + + if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) || + !vpix->dirty_present) + return TRUE; + + /* + * Intersect dirty region with region to be read back, if any. + */ + + REGION_NULL(vsaa->pScreen, &intersection); + REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw); + REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, + vpix->dirty_present); + + if (region) + REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region); + + if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection)) + goto out; + + /* + * Make really sure there is a GMR to read back to. + */ + + if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) + goto out_err; + + if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id, + &intersection) != 0) + goto out_err; + + REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, + &spix->dirty_hw, &intersection); + out: + REGION_UNINIT(vsaa->pScreen, &intersection); + return TRUE; + + out_err: + REGION_UNINIT(vsaa->pScreen, &intersection); + return FALSE; +} + +static Bool +vmwgfx_saa_dma(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap, + RegionPtr reg, + Bool to_hw) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (!vpix->hw || (!vpix->gmr && !vpix->malloc)) + return TRUE; + + if (vpix->gmr && vsaa->can_optimize_dma) { + uint32_t handle, dummy; + + if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) + goto out_err; + if (vmwgfx_dma(0, 0, reg, vpix->gmr, pixmap->devKind, handle, + to_hw) != 0) + goto out_err; + } else { + void *data = vpix->malloc; + int ret; + + if (vpix->gmr) { + data = vmwgfx_dmabuf_map(vpix->gmr); + if (!data) + goto out_err; + } + + ret = xa_surface_dma(vsaa->xa_ctx, vpix->hw, data, pixmap->devKind, + (int) to_hw, + (struct xa_box *) REGION_RECTS(reg), + REGION_NUM_RECTS(reg)); + if (vpix->gmr) + vmwgfx_dmabuf_unmap(vpix->gmr); + if (ret) + goto out_err; + } + return TRUE; + out_err: + LogMessage(X_ERROR, "DMA %s surface failed.\n", + to_hw ? "to" : "from"); + return FALSE; +} + + +static Bool +vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap, + RegionPtr readback) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + RegionRec intersection; + + if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback)) + return FALSE; + + if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw)) + return TRUE; + + if (!vpix->hw) + return TRUE; + + REGION_NULL(vsaa->pScreen, &intersection); + REGION_INTERSECT(vsaa->pScreen, &intersection, readback, + &spix->dirty_hw); + readback = &intersection; + + if (!vmwgfx_pixmap_create_sw(vsaa, pixmap)) + goto out_err; + + if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE)) + goto out_err; + REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback); + REGION_UNINIT(vsaa->pScreen, &intersection); + return TRUE; + out_err: + REGION_UNINIT(vsaa->pScreen, &intersection); + return FALSE; +} + + +static Bool +vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap, + RegionPtr upload) +{ + return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE); +} + +static void +vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) +{ + // LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n", + // (unsigned long) pixmap, (unsigned) access); +} + +static void * +vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) +{ + /* + * Errors in this functions will turn up in subsequent map + * calls. + */ + + (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap); + + return NULL; +} + +static void * +vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (vpix->malloc) + return vpix->malloc; + else if (vpix->gmr) + return vmwgfx_dmabuf_map(vpix->gmr); + else + return NULL; +} + +static void +vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (vpix->gmr) + return vmwgfx_dmabuf_unmap(vpix->gmr); + +// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n", + // (unsigned long) pixmap, (unsigned) access); + ; +} + +static Bool +vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix, + int w, int h, int depth, + unsigned int usage_hint, int bpp, int *new_pitch) +{ + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + + WSBMINITLISTHEAD(&vpix->sync_x_head); + WSBMINITLISTHEAD(&vpix->scanout_list); + + return TRUE; +} + +Bool +vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, + struct saa_pixmap *spix) +{ + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + if (!vpix->hw) + return TRUE; + + /* + * Read back any dirty regions from hardware. + */ + + if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, + &spix->dirty_hw)) + return FALSE; + + xa_surface_destroy(vpix->hw); + vpix->hw = NULL; + + /* + * Remove damage tracking if this is not a scanout pixmap. + */ + + if (WSBMLISTEMPTY(&vpix->scanout_list)) + vmwgfx_pixmap_remove_damage(spix->pixmap); + + return TRUE; +} + +void +vmwgfx_flush_dri2(ScreenPtr pScreen) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pScreen)); + struct _WsbmListHead *list, *next; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!pScrn->vtSema) + return; + + WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { + struct vmwgfx_saa_pixmap *vpix = + WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); + struct saa_pixmap *spix = &vpix->base; + PixmapPtr pixmap = spix->pixmap; + + if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { + REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); + WSBMLISTDELINIT(list); + } + } +} + + +static void +vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap) +{ + ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen; + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + (void) pScreen; + + vpix->backing = 0; + vmwgfx_pixmap_free_storage(vpix); + + /* + * Any damage we've registered has already been removed by the server + * at this point. Any attempt to unregister / destroy it will result + * in a double free. + */ + + vmwgfx_pixmap_remove_present(vpix); + WSBMLISTDELINIT(&vpix->sync_x_head); + + if (vpix->hw_is_dri2_fronts) + LogMessage(X_ERROR, "Incorrect dri2 front count.\n"); +} + + + +/** + * + * Makes sure we have a surface with valid contents. + */ + +static void +vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch, + unsigned int src_pitch, unsigned int dst_height, + unsigned int src_height) +{ + unsigned int i; + unsigned int height = (dst_height < src_height) ? dst_height : src_height; + unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch; + + for(i=0; i<height; ++i) { + memcpy(dst, src, pitch); + dst += dst_pitch; + src += src_pitch; + } +} + + +static Bool +vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch, + unsigned int old_height, unsigned int old_width) +{ + ScreenPtr pScreen = pixmap->drawable.pScreen; + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + DrawablePtr draw = &pixmap->drawable; + unsigned int size = pixmap->devKind * draw->height; + BoxRec b_box; + RegionRec b_reg; + + /* + * Ignore copying errors. At worst they will show up as rendering + * artefacts. + */ + + if (vpix->malloc) { + + void *new_malloc = malloc(size); + if (!new_malloc) + return FALSE; + + vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind, + old_pitch, draw->height, + old_height); + free(vpix->malloc); + vpix->malloc = new_malloc; + } + + if (vpix->gmr) { + struct vmwgfx_dmabuf *gmr; + void *new_addr; + void *old_addr; + + gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); + if (!gmr) + return FALSE; + + new_addr = vmwgfx_dmabuf_map(gmr); + old_addr = vmwgfx_dmabuf_map(vpix->gmr); + + if (new_addr && old_addr) + vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind, + old_pitch, draw->height, + old_height); + else + LogMessage(X_ERROR, "Failed pixmap resize copy.\n"); + + if (old_addr) + vmwgfx_dmabuf_unmap(vpix->gmr); + if (new_addr) + vmwgfx_dmabuf_unmap(gmr); + vmwgfx_dmabuf_destroy(vpix->gmr); + vpix->gmr = gmr; + } + + if (vpix->hw) { + if (xa_surface_redefine(vpix->hw, draw->width, draw->height, + draw->depth, xa_type_argb, + xa_format_unknown, vpix->xa_flags, 1) != 0) + return FALSE; + } + + b_box.x1 = 0; + b_box.x2 = draw->width; + b_box.y1 = 0; + b_box.y2 = draw->height; + + REGION_INIT(pScreen, &b_reg, &b_box, 1); + REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, + &b_reg); + REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); + if (vpix->dirty_present) + REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, + &b_reg); + if (vpix->pending_update) + REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, + &b_reg); + if (vpix->pending_present) + REGION_INTERSECT(pScreen, vpix->pending_present, + vpix->pending_present, &b_reg); + if (vpix->present_damage) + REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, + &b_reg); + + REGION_UNINIT(pScreen, &b_reg); + + return TRUE; +} + + +static Bool +vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth, + int bpp, int devkind, void *pixdata) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + unsigned int old_height; + unsigned int old_width; + unsigned int old_pitch; + + if (!vpix) { + LogMessage(X_ERROR, "Not an SAA pixmap.\n"); + return FALSE; + } + + if (pixdata) { + vpix->backing = 0; + vmwgfx_pixmap_free_storage(vpix); + return FALSE; + } + + if (depth <= 0) + depth = pixmap->drawable.depth; + + if (bpp <= 0) + bpp = pixmap->drawable.bitsPerPixel; + + if (w <= 0) + w = pixmap->drawable.width; + + if (h <= 0) + h = pixmap->drawable.height; + + if (w <= 0 || h <= 0 || depth <= 0) + return FALSE; + + old_height = pixmap->drawable.height; + old_width = pixmap->drawable.width; + old_pitch = pixmap->devKind; + + if (!miModifyPixmapHeader(pixmap, w, h, depth, + bpp, devkind, NULL)) + goto out_no_modify; + + if (!vpix->backing) + vpix->backing = VMWGFX_PIX_MALLOC; + + vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width); + vmwgfx_pixmap_free_storage(vpix); + return TRUE; + + out_no_modify: + return FALSE; +} + +static Bool +vmwgfx_present_prepare(struct vmwgfx_saa *vsaa, + struct vmwgfx_saa_pixmap *src_vpix, + struct vmwgfx_saa_pixmap *dst_vpix) +{ + ScreenPtr pScreen = vsaa->pScreen; + unsigned int dummy; + + (void) pScreen; + if (src_vpix == dst_vpix || !src_vpix->hw || + xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0) + return FALSE; + + REGION_NULL(pScreen, &vsaa->present_region); + vsaa->diff_valid = FALSE; + vsaa->dst_vpix = dst_vpix; + vsaa->present_flush(pScreen); + + return TRUE; +} + +/** + * Determine whether we should try present copies on this pixmap. + */ + +static Bool +vmwgfx_is_present_hw(PixmapPtr pixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + return (vpix->dirty_present != NULL); +} + +static void +vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa, + struct vmwgfx_saa_pixmap *vpix, + RegionPtr region, + Bool *has_dirty_hw, + Bool *has_valid_hw) +{ + RegionRec intersection; + + + if (!vpix->hw) { + *has_dirty_hw = FALSE; + *has_valid_hw = FALSE; + return; + } + + if (!region) { + *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, + &vpix->base.dirty_hw); + *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, + &vpix->base.dirty_shadow); + return; + } + + REGION_NULL(vsaa->pScreen, &intersection); + REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw, + region); + *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection); + REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow, + region); + *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection); + REGION_UNINIT(vsaa->pScreen, &intersection); +} + + +Bool +vmwgfx_create_hw(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + struct xa_surface *hw; + uint32_t new_flags; + + if (!vsaa->xat) + return FALSE; + + if (vpix->hw) + return TRUE; + + new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | + vpix->staging_add_flags; + + hw = xa_surface_create(vsaa->xat, + pixmap->drawable.width, + pixmap->drawable.height, + 0, + xa_type_other, + vpix->staging_format, + new_flags); + if (hw == NULL) + return FALSE; + + vpix->xa_flags = new_flags; + + if (!vmwgfx_pixmap_add_damage(pixmap)) + goto out_no_damage; + + /* + * Even if we don't have a GMR yet, indicate that when needed it + * should be created. + */ + + vpix->hw = hw; + vpix->backing |= VMWGFX_PIX_SURFACE; + vmwgfx_pixmap_free_storage(vpix); + + return TRUE; + +out_no_damage: + xa_surface_destroy(hw); + return FALSE; +} + + +Bool +vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + RegionRec intersection; + + if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region)) + return FALSE; + + REGION_NULL(vsaa->pScreen, &intersection); + REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow); + + if (vpix->dirty_present) + REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present, + &spix->dirty_shadow); + + if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) { + RegionPtr upload = &intersection; + + /* + * Check whether we need to upload from GMR. + */ + + if (region) { + REGION_INTERSECT(vsaa->pScreen, &intersection, region, + &intersection); + upload = &intersection; + } + + if (REGION_NOTEMPTY(vsaa->pScreen, upload)) { + Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload); + if (ret) { + REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow, + &spix->dirty_shadow, upload); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, upload); + } else { + REGION_UNINIT(vsaa->pScreen, &intersection); + return FALSE; + } + } + } + REGION_UNINIT(vsaa->pScreen, &intersection); + return TRUE; +} + +static Bool +vmwgfx_copy_prepare(struct saa_driver *driver, + PixmapPtr src_pixmap, + PixmapPtr dst_pixmap, + int dx, + int dy, + int alu, + RegionPtr src_reg, + uint32_t plane_mask) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct vmwgfx_saa_pixmap *src_vpix; + struct vmwgfx_saa_pixmap *dst_vpix; + Bool has_dirty_hw; + Bool has_valid_hw; + + if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) || + alu != GXcopy) + return FALSE; + + src_vpix = vmwgfx_saa_pixmap(src_pixmap); + dst_vpix = vmwgfx_saa_pixmap(dst_pixmap); + + vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg, + &has_dirty_hw, &has_valid_hw); + + if (vmwgfx_is_present_hw(dst_pixmap) && + src_vpix->backing & VMWGFX_PIX_SURFACE) { + + if (!has_dirty_hw && !has_valid_hw) + return FALSE; + + if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) + return FALSE; + if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { + vsaa->present_copy = TRUE; + return TRUE; + } + return FALSE; + } + + vsaa->present_copy = FALSE; + if (src_vpix != dst_vpix) { + + /* + * Use hardware acceleration either if source is partially only + * in hardware, or if source is entirely in hardware and destination + * has a hardware surface. + */ + + if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL))) + return FALSE; + + /* + * Determine surface formats. + */ + + if (src_vpix->base.src_format == 0) { + if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) + return FALSE; + } else { + if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || + !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) + return FALSE; + } + + if (dst_vpix->base.dst_format == 0) { + if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) + return FALSE; + } else { + if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || + !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) + return FALSE; + } + + /* + * Create hardware surfaces. + */ + + if (!vmwgfx_hw_commit(src_pixmap)) + return FALSE; + if (!vmwgfx_hw_commit(dst_pixmap)) + return FALSE; + + /* + * Migrate data. + */ + + if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { + xa_copy_done(vsaa->xa_ctx); + return FALSE; + } + + /* + * Setup copy state. + */ + + if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != + XA_ERR_NONE) + return FALSE; + + return TRUE; + } + + return FALSE; +} + + +static void +vmwgfx_present_done(struct vmwgfx_saa *vsaa) +{ + ScreenPtr pScreen = vsaa->pScreen; + struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix; + + (void) pScreen; + if (!vsaa->diff_valid) + return; + + (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id, + vsaa->xdiff, vsaa->ydiff, + &vsaa->present_region, vsaa->src_handle); + + REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff); + REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage, + &vsaa->present_region); + vsaa->diff_valid = FALSE; + REGION_UNINIT(pScreen, &vsaa->present_region); +} + +static void +vmwgfx_present_copy(struct vmwgfx_saa *vsaa, + int src_x, + int src_y, + int dst_x, + int dst_y, + int w, + int h) +{ + int xdiff = dst_x - src_x; + int ydiff = dst_y - src_y; + BoxRec box; + RegionRec reg; + + if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff))) + (void) vmwgfx_present_done(vsaa); + + if (!vsaa->diff_valid) { + vsaa->xdiff = xdiff; + vsaa->ydiff = ydiff; + vsaa->diff_valid = TRUE; + } + + box.x1 = src_x; + box.x2 = src_x + w; + box.y1 = src_y; + box.y2 = src_y + h; + + REGION_INIT(pScreen, ®, &box, 1); + REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); + REGION_UNINIT(pScreen, ®); +} + +static void +vmwgfx_copy(struct saa_driver *driver, + int src_x, + int src_y, + int dst_x, + int dst_y, + int w, + int h) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + if (vsaa->present_copy) { + vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h); + return; + } + xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h); +} + +static void +vmwgfx_copy_done(struct saa_driver *driver) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + if (vsaa->present_copy) { + vmwgfx_present_done(vsaa); + return; + } + xa_copy_done(vsaa->xa_ctx); +} + +static Bool +vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, + PicturePtr src_pict, PicturePtr mask_pict, + PicturePtr dst_pict, + PixmapPtr src_pix, PixmapPtr mask_pix, + PixmapPtr dst_pix, + RegionPtr src_region, + RegionPtr mask_region, + RegionPtr dst_region) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct vmwgfx_saa_pixmap *src_vpix; + struct vmwgfx_saa_pixmap *dst_vpix; + struct vmwgfx_saa_pixmap *mask_vpix; + Bool tmp_valid_hw; + Bool dirty_hw; + Bool valid_hw; + RegionRec empty; + struct xa_composite *xa_comp; + + REGION_NULL(pScreen, &empty); + + /* + * First we define our migration policy. We accelerate only if there + * are dirty hw regions to be read or if all source data is + * available in hw, and the destination has a hardware surface. + */ + dst_vpix = vmwgfx_saa_pixmap(dst_pix); + valid_hw = (dst_vpix->hw != NULL); + if (saa_op_reads_destination(op)) { + vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } else { + dirty_hw = FALSE; + dst_region = ∅ + } + + if (src_pix && !dirty_hw) { + src_vpix = vmwgfx_saa_pixmap(src_pix); + vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } + + if (mask_pict && mask_pix && !dirty_hw) { + mask_vpix = vmwgfx_saa_pixmap(mask_pix); + vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } + + /* + * In rendercheck mode we try to accelerate all supported + * composite operations. + */ + + if (!valid_hw && !dirty_hw && !vsaa->rendercheck) + goto out_err; + + /* + * Then, setup most of the XA composite state (except hardware surfaces) + * and check whether XA can accelerate. + */ + + xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, + src_pict, mask_pict, dst_pict); + if (!xa_comp) + goto out_err; + + if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) + goto out_err; + + /* + * Check that we can create the needed hardware surfaces. + */ + if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) + goto out_err; + if (mask_pict && mask_pix && + !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) + goto out_err; + if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) + goto out_err; + + /* + * Seems OK. Commit the changes, creating hardware surfaces. + */ + if (src_pix && !vmwgfx_hw_commit(src_pix)) + goto out_err; + if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) + goto out_err; + if (!vmwgfx_hw_commit(dst_pix)) + goto out_err; + + /* + * Update the XA state with our hardware surfaces and + * surface formats + */ + if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) + goto out_err; + + /* + * Migrate data to surfaces. + */ + if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) + goto out_err; + if (mask_pict && mask_pix && mask_region && + !vmwgfx_hw_validate(mask_pix, NULL)) + goto out_err; + if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) + goto out_err; + + + /* + * Bind the XA state. This must be done after data migration, since + * migration may change the hardware surfaces. + */ + if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) + goto out_err; + + REGION_UNINIT(pScreen, &empty); + return TRUE; + + out_err: + REGION_UNINIT(pScreen, &empty); + return FALSE; +} + +static void +vmwgfx_composite(struct saa_driver *driver, + int src_x, int src_y, int mask_x, int mask_y, + int dst_x, int dst_y, + int width, int height) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, + dst_x, dst_y, width, height); +} + +static void +vmwgfx_composite_done(struct saa_driver *driver) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + xa_composite_done(vsaa->xa_ctx); +} + +static void +vmwgfx_takedown(struct saa_driver *driver) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + if (vsaa->vcomp) + vmwgfx_free_composite(vsaa->vcomp); + free(vsaa); +} + +/* + * This function call originates from the damage layer (outside SAA) + * to indicate that an operation is complete, and that damage is being + * processed. + */ +static void +vmwgfx_operation_complete(struct saa_driver *driver, + PixmapPtr pixmap) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + ScrnInfoPtr pScrn = xf86Screens[vsaa->pScreen->myNum]; + + /* + * Make dri2 drawables up to date, or add them to the flush list + * executed at glxWaitX(). Currently glxWaitX() is broken, so + * we flush immediately, unless we're VT-switched away, in which + * case a flush would deadlock in the kernel. + */ + + if (vpix->hw && vpix->hw_is_dri2_fronts) { + if (1 && pScrn->vtSema && + vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { + + REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); + return; + } + + if (WSBMLISTEMPTY(&vpix->sync_x_head)) + WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); + } +} + +/* + * This function is called by SAA to indicate that SAA has + * dirtied a region of a pixmap, either as hw (accelerated) or as + * !hw (not accelerated). + */ +static Bool +vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, + Bool hw, RegionPtr damage) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + /* + * Return if this is not a scanout pixmap. + */ + if (WSBMLISTEMPTY(&vpix->scanout_list)) + return TRUE; + +#if 0 + /* + * This code can be enabled to immediately upload scanout sw + * contents to the hw surface. Otherwise this is done + * just before we call the kms update function for the hw + * surface. + */ + if (vsaa->only_hw_presents) { + if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) + return FALSE; + + REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, + &spix->dirty_shadow, damage); + hw = TRUE; + } +#endif + + /* + * Is the new scanout damage hw or sw? + */ + if (hw) { + /* + * Dump pending present into present tracking region. + */ + if (vpix->dirty_present && + REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) { + REGION_UNION(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, damage); + REGION_EMPTY(vsaa->pScreen, vpix->present_damage); + } else { + if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) { + RegionRec reg; + + REGION_NULL(vsaa->pScreen, ®); + REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, + damage); + if (REGION_NOTEMPTY(vsaa->pScreen, ®)) + vsaa->present_flush(vsaa->pScreen); + REGION_UNINIT(pScreen, ®); + } + REGION_UNION(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, damage); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, damage); + } + } else { + if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { + RegionRec reg; + + REGION_NULL(vsaa->pScreen, ®); + REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, + damage); + if (REGION_NOTEMPTY(vsaa->pScreen, ®)) + vsaa->present_flush(vsaa->pScreen); + REGION_UNINIT(pScreen, ®); + } + REGION_UNION(vsaa->pScreen, vpix->pending_update, + vpix->pending_update, damage); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, damage); + } + + return TRUE; +} + + +static const struct saa_driver vmwgfx_saa_driver = { + .saa_major = SAA_VERSION_MAJOR, + .saa_minor = SAA_VERSION_MINOR, + .pixmap_size = sizeof(struct vmwgfx_saa_pixmap), + .damage = vmwgfx_dirty, + .operation_complete = vmwgfx_operation_complete, + .download_from_hw = vmwgfx_download_from_hw, + .release_from_cpu = vmwgfx_release_from_cpu, + .sync_for_cpu = vmwgfx_sync_for_cpu, + .map = vmwgfx_map, + .unmap = vmwgfx_unmap, + .create_pixmap = vmwgfx_create_pixmap, + .destroy_pixmap = vmwgfx_destroy_pixmap, + .modify_pixmap_header = vmwgfx_modify_pixmap_header, + .copy_prepare = vmwgfx_copy_prepare, + .copy = vmwgfx_copy, + .copy_done = vmwgfx_copy_done, + .composite_prepare = vmwgfx_composite_prepare, + .composite = vmwgfx_composite, + .composite_done = vmwgfx_composite_done, + .takedown = vmwgfx_takedown, +}; + + +Bool +vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, + void (*present_flush)(ScreenPtr pScreen), + Bool direct_presents, + Bool only_hw_presents, + Bool rendercheck) +{ + struct vmwgfx_saa *vsaa; + + vsaa = calloc(1, sizeof(*vsaa)); + if (!vsaa) + return FALSE; + + if (xat == NULL) { + direct_presents = FALSE; + only_hw_presents = FALSE; + } + + vsaa->pScreen = pScreen; + vsaa->xat = xat; + if (xat) + vsaa->xa_ctx = xa_context_default(xat); + vsaa->drm_fd = drm_fd; + vsaa->present_flush = present_flush; + vsaa->can_optimize_dma = FALSE; + vsaa->use_present_opt = direct_presents; + vsaa->only_hw_presents = only_hw_presents; + vsaa->rendercheck = rendercheck; + WSBMINITLISTHEAD(&vsaa->sync_x_list); + + vsaa->driver = vmwgfx_saa_driver; + vsaa->vcomp = vmwgfx_alloc_composite(); + + if (!vsaa->vcomp) + vsaa->driver.composite_prepare = NULL; + + if (!saa_driver_init(pScreen, &vsaa->driver)) + goto out_no_saa; + + return TRUE; + out_no_saa: + free(vsaa); + return FALSE; +} + +/* + * ************************************************************************* + * Scanout functions. + * These do not strictly belong here, but we choose to hide the scanout + * pixmap private data in the saa pixmaps. Might want to revisit this. + */ + +/* + * Make sure we flush / update this scanout on next update run. + */ + +void +vmwgfx_scanout_refresh(PixmapPtr pixmap) +{ + ScreenPtr pScreen = pixmap->drawable.pScreen; + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + BoxRec box; + + (void) pScreen; + box.x1 = 0; + box.y1 = 0; + box.x2 = pixmap->drawable.width; + box.y2 = pixmap->drawable.height; + + REGION_RESET(vsaa->pScreen, vpix->pending_present, &box); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, vpix->dirty_present); + REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, &vpix->base.dirty_shadow); + REGION_COPY(vsaa->pScreen, vpix->pending_update, + &vpix->base.dirty_shadow); +} + +/* + * Take a "scanout reference" on a pixmap. If this is the first scanout + * reference, allocate resources needed for scanout, like proper + * damage tracking and kms fbs. + */ + +uint32_t +vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry) +{ + PixmapPtr pixmap = entry->pixmap; + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (WSBMLISTEMPTY(&vpix->scanout_list)) { + uint32_t handle, dummy; + unsigned int depth; + + if (vsaa->only_hw_presents) { + /* + * The KMS fb will be a HW surface. Create it, add damage + * and get the handle. + */ + if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 0, NULL)) + goto out_err; + if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) + goto out_err; + depth = xa_format_depth(xa_surface_format(vpix->hw)); + + } else { + /* + * The KMS fb will be a Guest Memory Region. Create it, + * add damage and get the handle. + */ + if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) + goto out_err; + + handle = vpix->gmr->handle; + depth = pixmap->drawable.depth; + + } + + if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) + goto out_no_present; + + if (drmModeAddFB(vsaa->drm_fd, + pixmap->drawable.width, + pixmap->drawable.height, + depth, + pixmap->drawable.bitsPerPixel, + pixmap->devKind, + handle, + &vpix->fb_id) != 0) + goto out_no_fb;; + } + pixmap->refcnt += 1; + WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); + return vpix->fb_id; + + out_no_fb: + vmwgfx_pixmap_remove_present(vpix); + out_no_present: + vmwgfx_pixmap_remove_damage(pixmap); + out_err: + vpix->fb_id = -1; + return -1; +} + +/* + * Free a "scanout reference" on a pixmap. If this was the last scanout + * reference, free pixmap resources needed for scanout, like + * damage tracking and kms fbs. + */ +void +vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry) +{ + struct vmwgfx_saa *vsaa; + struct vmwgfx_saa_pixmap *vpix; + PixmapPtr pixmap = entry->pixmap; + + if (!pixmap) + return; + + vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + vpix = vmwgfx_saa_pixmap(pixmap); + WSBMLISTDELINIT(&entry->scanout_head); + + if (WSBMLISTEMPTY(&vpix->scanout_list)) { + REGION_EMPTY(vsaa->pScreen, vpix->pending_update); + drmModeRmFB(vsaa->drm_fd, vpix->fb_id); + vpix->fb_id = -1; + vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL); + vmwgfx_pixmap_remove_present(vpix); + vmwgfx_pixmap_remove_damage(pixmap); + } + + entry->pixmap = NULL; + pixmap->drawable.pScreen->DestroyPixmap(pixmap); +} diff --git a/vmwgfx/vmwgfx_saa.h b/vmwgfx/vmwgfx_saa.h new file mode 100644 index 0000000..bb8ec96 --- /dev/null +++ b/vmwgfx/vmwgfx_saa.h @@ -0,0 +1,110 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#ifndef _VMWGFX_SAA_H_ +#define _VMWGFX_SAA_H_ + +#include "saa.h" +#include <xa_composite.h> +#include "vmwgfx_drmi.h" +#include "wsbm_util.h" + + +#define VMWGFX_FLAG_FORCE_GMR (1 << 0) /* Create with GMR as backing store */ +#define VMWGFX_FLAG_FORCE_SURFACE (1 << 1) /* Create with surface as backing store */ +#define VMWGFX_FLAG_AVOID_HWACCEL (1 << 2) /* Avoid Hardware acceleration on this pixmap */ +#define VMWGFX_FLAG_USE_PRESENT (1 << 3) /* Use presents when copying to this pixmap */ + +struct vmwgfx_saa_pixmap { + struct saa_pixmap base; + RegionPtr dirty_present; + RegionPtr present_damage; + RegionPtr pending_update; + RegionPtr pending_present; + uint32_t usage_flags; + uint32_t backing; + void *malloc; + struct vmwgfx_dmabuf *gmr; + struct xa_surface *hw; + uint32_t fb_id; + int hw_is_dri2_fronts; + struct _WsbmListHead sync_x_head; + struct _WsbmListHead scanout_list; + + uint32_t xa_flags; + uint32_t staging_add_flags; + uint32_t staging_remove_flags; + enum xa_formats staging_format; +}; + +struct vmwgfx_screen_entry { + struct _WsbmListHead scanout_head; + PixmapPtr pixmap; +}; + +static inline struct vmwgfx_saa_pixmap * +to_vmwgfx_saa_pixmap(struct saa_pixmap *spix) +{ + return (struct vmwgfx_saa_pixmap *) spix; +} + +static inline struct vmwgfx_saa_pixmap* +vmwgfx_saa_pixmap(PixmapPtr pix) +{ + return to_vmwgfx_saa_pixmap(saa_get_saa_pixmap(pix)); +} + +extern Bool +vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, + void (*present_flush)(ScreenPtr pScreen), + Bool direct_presents, + Bool only_hw_presents, + Bool rendercheck); + +extern uint32_t +vmwgfx_scanout_ref(struct vmwgfx_screen_entry *box); + +extern void +vmwgfx_scanout_unref(struct vmwgfx_screen_entry *box); + +extern void +vmwgfx_scanout_refresh(PixmapPtr pixmap); + +extern void +vmwgfx_remove_dri2_list(struct vmwgfx_saa_pixmap *vpix); + +extern void +vmwgfx_flush_dri2(ScreenPtr pScreen); + +extern Bool +vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth); + +Bool +vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags, + RegionPtr region); +#endif diff --git a/vmwgfx/vmwgfx_saa_priv.h b/vmwgfx/vmwgfx_saa_priv.h new file mode 100644 index 0000000..5f46dee --- /dev/null +++ b/vmwgfx/vmwgfx_saa_priv.h @@ -0,0 +1,125 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ +#ifndef _VMWGFX_SAA_PRIV_H_ +#define _VMWGFX_SAA_PRIV_H_ + +#define VMWGFX_PIX_MALLOC (1 << 0) +#define VMWGFX_PIX_GMR (1 << 1) +#define VMWGFX_PIX_SURFACE (1 << 2) + +#include <xorg-server.h> +#include <picturestr.h> +#include "vmwgfx_saa.h" + +struct vmwgfx_saa { + struct saa_driver driver; + struct vmwgfx_dma_ctx *ctx; + struct xa_tracker *xat; + struct xa_context *xa_ctx; + ScreenPtr pScreen; + int drm_fd; + struct vmwgfx_saa_pixmap *src_vpix; + struct vmwgfx_saa_pixmap *dst_vpix; + Bool present_copy; + Bool diff_valid; + int xdiff; + int ydiff; + RegionRec present_region; + uint32_t src_handle; + Bool can_optimize_dma; + Bool use_present_opt; + Bool only_hw_presents; + Bool rendercheck; + void (*present_flush) (ScreenPtr pScreen); + struct _WsbmListHead sync_x_list; + struct vmwgfx_composite *vcomp; +}; + +static inline struct vmwgfx_saa * +to_vmwgfx_saa(struct saa_driver *driver) { + return (struct vmwgfx_saa *) driver; +} + +/* + * In vmwgfx_saa.c + */ + +Bool +vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, + struct saa_pixmap *spix); +Bool +vmwgfx_create_hw(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap); + + +/* + * vmwgfx_xa_surface.c + */ + +enum xa_formats +vmwgfx_xa_format(enum _PictFormatShort format); +Bool +vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region); + +Bool +vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags); +Bool +vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format); +Bool +vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format); +Bool +vmwgfx_hw_commit(PixmapPtr pixmap); + +/* + * vmwgfx_xa_composite.c + */ + +struct vmwgfx_composite; + +void +vmwgfx_free_composite(struct vmwgfx_composite *vcomp); +struct vmwgfx_composite * +vmwgfx_alloc_composite(void); + +Bool +vmwgfx_xa_update_comp(struct xa_composite *comp, + PixmapPtr src_pix, + PixmapPtr mask_pix, + PixmapPtr dst_pix); + +struct xa_composite * +vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp, + int op, + PicturePtr src_pict, + PicturePtr mask_pict, + PicturePtr dst_pict); + + +#endif diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c new file mode 100644 index 0000000..cc94c20 --- /dev/null +++ b/vmwgfx/vmwgfx_tex_video.c @@ -0,0 +1,855 @@ +/* + * Copyright 2009-2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + * Author: Zack Rusin <zackr@vmware.com> + */ + +#include "vmwgfx_driver.h" +#include "vmwgfx_drmi.h" +#include "vmwgfx_saa.h" + +#include <xf86xv.h> +#include <X11/extensions/Xv.h> +#include <fourcc.h> +#include <xa_tracker.h> +#include <xa_context.h> +#include <math.h> + +/*XXX get these from pipe's texture limits */ +#define IMAGE_MAX_WIDTH 2048 +#define IMAGE_MAX_HEIGHT 2048 + +#define RES_720P_X 1280 +#define RES_720P_Y 720 + + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* + * ITU-R BT.601, BT.709 transfer matrices. + * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1] + * and [Pb, Pr] components are in the range [-0.5, 0.5]. + * + * The matrices are transposed to fit the xa conversion matrix format. + */ + +static const float bt_601[] = { + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.344136f, 1.772f, 0.f, + 1.402f, -0.714136f, 0.f, 0.f +}; + +static const float bt_709[] = { + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.187324f, 1.8556f, 0.f, + 1.5748f, -0.468124f, 0.f, 0.f +}; + +static Atom xvBrightness, xvContrast, xvSaturation, xvHue; + +#define NUM_TEXTURED_ATTRIBUTES 4 +static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { + {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, + {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, + {XvSettable | XvGettable, -1000, 1000, "XV_HUE"} +}; + +#define NUM_FORMATS 3 +static XF86VideoFormatRec Formats[NUM_FORMATS] = { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +static XF86VideoEncodingRec DummyEncoding[1] = { + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_IMAGES 3 +static XF86ImageRec Images[NUM_IMAGES] = { + XVIMAGE_UYVY, + XVIMAGE_YUY2, + XVIMAGE_YV12, +}; + +struct xorg_xv_port_priv { + struct xa_tracker *xat; + struct xa_context *r; + struct xa_fence *fence; + + RegionRec clip; + + int brightness; + int contrast; + int saturation; + int hue; + + int current_set; + struct vmwgfx_dmabuf *bounce[2][3]; + struct xa_surface *yuv[3]; + + int drm_fd; + + Bool hdtv; + float uv_offset; + float uv_scale; + float y_offset; + float y_scale; + float rgb_offset; + float rgb_scale; + float sinhue; + float coshue; + float cm[16]; +}; + +/* + * vmwgfx_update_conversion_matrix - Compute the effective color conversion + * matrix. + * + * Applies yuv- and resulting rgb scales and offsets to compute the correct + * color conversion matrix. These scales and offsets are properties of the + * video stream and can be adjusted using XV properties as well. + */ +static void +vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv) +{ + int i; + float *cm = priv->cm; + static const float *bt; + + bt = (priv->hdtv) ? bt_709 : bt_601; + + memcpy(cm, bt, sizeof(bt_601)); + + /* + * Apply hue rotation + */ + cm[4] = priv->coshue * bt[4] - priv->sinhue * bt[8]; + cm[8] = priv->sinhue * bt[4] + priv->coshue * bt[8]; + cm[5] = priv->coshue * bt[5] - priv->sinhue * bt[9]; + cm[9] = priv->sinhue * bt[5] + priv->coshue * bt[9]; + cm[6] = priv->coshue * bt[6] - priv->sinhue * bt[10]; + cm[10] = priv->sinhue * bt[6] + priv->coshue * bt[10]; + + /* + * Adjust for yuv scales in input and rgb scale in the converted output. + */ + for(i = 0; i < 3; ++i) { + cm[i] *= (priv->y_scale*priv->rgb_scale); + cm[i+4] *= (priv->uv_scale*priv->rgb_scale); + cm[i+8] *= (priv->uv_scale*priv->rgb_scale); + } + + /* + * Adjust for yuv offsets in input and rgb offset in the converted output. + */ + for (i = 0; i < 3; ++i) + cm[i+12] = -cm[i]*priv->y_offset - (cm[i+4] + cm[i+8])*priv->uv_offset + - priv->rgb_offset*priv->rgb_scale; + + /* + * Alpha is 1, unconditionally. + */ + cm[15] = 1.f; +} + + +static void +stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + int i, j; + + REGION_EMPTY(pScrn->pScreen, &priv->clip); + if (shutdown) { + + /* + * No need to destroy the xa context or xa tracker since + * they are copied from the screen resources. + */ + + xa_fence_destroy(priv->fence); + priv->fence = NULL; + + for (i=0; i<3; ++i) { + if (priv->yuv[i]) { + xa_surface_destroy(priv->yuv[i]); + priv->yuv[i] = NULL; + } + for (j=0; j<2; ++j) { + if (priv->bounce[j][i]) { + vmwgfx_dmabuf_destroy(priv->bounce[j][i]); + priv->bounce[0][i] = NULL; + } + } + } + } +} + +static int +set_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 value, pointer data) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) { + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->brightness = value; + priv->y_offset = -((float) value)/1000.f; + + } else if (attribute == xvContrast) { + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->contrast = value; + priv->rgb_scale = ((float) value + 1000.f)/1000.f; + + } else if (attribute == xvSaturation) { + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->saturation = value; + priv->uv_scale = ((float) value + 1000.f)/1000.f; + + } else if (attribute == xvHue) { + double hue_angle; + + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->hue = value; + hue_angle = (double) value * M_PI / 1000.; + priv->sinhue = sin(hue_angle); + priv->coshue = cos(hue_angle); + + } else + return BadMatch; + + vmwgfx_update_conversion_matrix(priv); + return Success; +} + +static int +get_port_attribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 * value, pointer data) +{ + struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; + + if (attribute == xvBrightness) + *value = priv->brightness; + else if (attribute == xvContrast) + *value = priv->contrast; + else if (attribute == xvSaturation) + *value = priv->saturation; + else if (attribute == xvHue) + *value = priv->hue; + else + return BadMatch; + + return Success; +} + +static void +query_best_size(ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data) +{ + if (vid_w > (drw_w << 1)) + drw_w = vid_w >> 1; + if (vid_h > (drw_h << 1)) + drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + +static int +check_yuv_surfaces(struct xorg_xv_port_priv *priv, int id, + int width, int height) +{ + struct xa_surface **yuv = priv->yuv; + struct vmwgfx_dmabuf **bounce = priv->bounce[priv->current_set]; + int ret = 0; + int i; + size_t size; + + for (i=0; i<3; ++i) { + + /* + * Adjust u,v texture size and DMA buffer to what's required by + * the format. + */ + if (i == 1) { + switch(id) { + case FOURCC_YV12: + height /= 2; + /* Fall through */ + case FOURCC_YUY2: + case FOURCC_UYVY: + width /= 2; + break; + default: + break; + } + } + + if (!yuv[i]) + yuv[i] = xa_surface_create(priv->xat, width, height, 8, + xa_type_yuv_component, + xa_format_unknown, 0); + else + ret = xa_surface_redefine(yuv[i], width, height, 8, + xa_type_yuv_component, + xa_format_unknown, 0, 0); + if (ret || !yuv[i]) + return BadAlloc; + + size = width * height; + + if (bounce[i] && (bounce[i]->size < size || + bounce[i]->size > 2*size)) { + vmwgfx_dmabuf_destroy(bounce[i]); + bounce[i] = NULL; + } + + if (!bounce[i]) { + bounce[i] = vmwgfx_dmabuf_alloc(priv->drm_fd, size); + if (!bounce[i]) + return BadAlloc; + } + } + return Success; +} + +static int +query_image_attributes(ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ + int size, tmp; + + if (*w > IMAGE_MAX_WIDTH) + *w = IMAGE_MAX_WIDTH; + if (*h > IMAGE_MAX_HEIGHT) + *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + case FOURCC_YV12: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if (pitches) { + pitches[0] = size; + } + size *= *h; + if (offsets) { + offsets[1] = size; + } + tmp = ((*w >> 1) + 3) & ~3; + if (pitches) { + pitches[1] = pitches[2] = tmp; + } + tmp *= (*h >> 1); + size += tmp; + if (offsets) { + offsets[2] = size; + } + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static int +copy_packed_data(ScrnInfoPtr pScrn, + struct xorg_xv_port_priv *port, + int id, + unsigned char *buf, + int left, + int top, + unsigned short w, unsigned short h) +{ + int i; + struct vmwgfx_dmabuf **bounce = port->bounce[port->current_set]; + char *ymap, *vmap, *umap; + unsigned char y1, y2, u, v; + int yidx, uidx, vidx; + int y_array_size = w * h; + int ret = BadAlloc; + + /* + * Here, we could use xa_surface_[map|unmap], but given the size of + * the yuv textures, that could stress the xa tracker dma buffer pool, + * particularaly with multiple videos rendering simultaneously. + * + * Instead, cheat and allocate vmwgfx dma buffers directly. + */ + + ymap = (char *)vmwgfx_dmabuf_map(bounce[0]); + if (!ymap) + return BadAlloc; + umap = (char *)vmwgfx_dmabuf_map(bounce[1]); + if (!umap) + goto out_no_umap; + vmap = (char *)vmwgfx_dmabuf_map(bounce[2]); + if (!vmap) + goto out_no_vmap; + + + yidx = uidx = vidx = 0; + + switch (id) { + case FOURCC_YV12: { + int pitches[3], offsets[3]; + unsigned char *y, *u, *v; + query_image_attributes(pScrn, FOURCC_YV12, + &w, &h, pitches, offsets); + + y = buf + offsets[0]; + v = buf + offsets[1]; + u = buf + offsets[2]; + memcpy(ymap, y, w*h); + memcpy(vmap, v, w*h/4); + memcpy(umap, u, w*h/4); + break; + } + case FOURCC_UYVY: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + u = buf[0]; + y1 = buf[1]; + v = buf[2]; + y2 = buf[3]; + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + vmap[vidx++] = v; + } + break; + case FOURCC_YUY2: + for (i = 0; i < y_array_size; i +=2 ) { + /* extracting two pixels */ + y1 = buf[0]; + u = buf[1]; + y2 = buf[2]; + v = buf[3]; + + buf += 4; + + ymap[yidx++] = y1; + ymap[yidx++] = y2; + umap[uidx++] = u; + vmap[vidx++] = v; + } + break; + default: + ret = BadAlloc; + break; + } + + ret = Success; + vmwgfx_dmabuf_unmap(bounce[2]); + out_no_vmap: + vmwgfx_dmabuf_unmap(bounce[1]); + out_no_umap: + vmwgfx_dmabuf_unmap(bounce[0]); + + if (ret == Success) { + struct xa_surface *srf; + struct vmwgfx_dmabuf *buf; + uint32_t handle; + unsigned int stride; + BoxRec box; + RegionRec reg; + + box.x1 = 0; + box.x2 = w; + box.y1 = 0; + box.y2 = h; + + REGION_INIT(pScrn->pScreen, ®, &box, 1); + + for (i=0; i<3; ++i) { + srf = port->yuv[i]; + buf = bounce[i]; + + if (i == 1) { + switch(id) { + case FOURCC_YV12: + h /= 2; + /* Fall through */ + case FOURCC_YUY2: + case FOURCC_UYVY: + w /= 2; + break; + default: + break; + } + + box.x1 = 0; + box.x2 = w; + box.y1 = 0; + box.y2 = h; + + REGION_RESET(pScrn->pScreen, ®, &box); + } + + if (xa_surface_handle(srf, &handle, &stride) != 0) { + ret = BadAlloc; + break; + } + + if (vmwgfx_dma(0, 0, ®, buf, w, handle, 1) != 0) { + ret = BadAlloc; + break; + } + } + REGION_UNINIT(pScrn->pScreen, ®); + } + + return ret; +} + + +static int +display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, + RegionPtr dstRegion, + int src_x, int src_y, int src_w, int src_h, + int dst_x, int dst_y, int dst_w, int dst_h, + PixmapPtr pPixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap); + Bool hdtv; + RegionRec reg; + int ret = BadAlloc; + int blit_ret; + + REGION_NULL(pScreen, ®); + + if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, ®)) + goto out_no_dst; + + hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); + if (hdtv != pPriv->hdtv) { + pPriv->hdtv = hdtv; + vmwgfx_update_conversion_matrix(pPriv); + } + +#ifdef COMPOSITE + + /* + * For redirected windows, we need to fix up the destination coordinates. + */ + + REGION_TRANSLATE(pScreen, dstRegion, -pPixmap->screen_x, + -pPixmap->screen_y); + dst_x -= pPixmap->screen_x; + dst_y -= pPixmap->screen_y; +#endif + + /* + * Throttle on previous blit. + */ + + if (pPriv->fence) { + (void) xa_fence_wait(pPriv->fence, 1000000000ULL); + xa_fence_destroy(pPriv->fence); + pPriv->fence = NULL; + } + + DamageRegionAppend(&pPixmap->drawable, dstRegion); + + blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h, + dst_x, dst_y, dst_w, dst_h, + (struct xa_box *)REGION_RECTS(dstRegion), + REGION_NUM_RECTS(dstRegion), + pPriv->cm, + vpix->hw, pPriv->yuv); + + saa_pixmap_dirty(pPixmap, TRUE, dstRegion); + DamageRegionProcessPending(&pPixmap->drawable); + ret = Success; + + if (!blit_ret) { + ret = Success; + pPriv->fence = xa_fence_get(pPriv->r); + } else + ret = BadAlloc; + + out_no_dst: + REGION_UNINIT(pScreen, ®); + return ret; +} + +static int +put_image(ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char *buf, + short width, short height, + Bool sync, RegionPtr clipBoxes, pointer data, + DrawablePtr pDraw) +{ + struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + PixmapPtr pPixmap; + INT32 x1, x2, y1, y2; + BoxRec dstBox; + int ret; + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, + width, height)) + return Success; + + ret = check_yuv_surfaces(pPriv, id, width, height); + if (ret) + return ret; + + ret = copy_packed_data(pScrn, pPriv, id, buf, + src_x, src_y, width, height); + if (ret) + return ret; + + if (pDraw->type == DRAWABLE_WINDOW) { + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); + } else { + pPixmap = (PixmapPtr)pDraw; + } + + display_video(pScrn->pScreen, pPriv, id, clipBoxes, + src_x, src_y, src_w, src_h, + drw_x, drw_y, + drw_w, drw_h, pPixmap); + + pPriv->current_set = (pPriv->current_set + 1) & 1; + return Success; +} + +static struct xorg_xv_port_priv * +port_priv_create(struct xa_tracker *xat, struct xa_context *r, + int drm_fd) +{ + struct xorg_xv_port_priv *priv = NULL; + + priv = calloc(1, sizeof(struct xorg_xv_port_priv)); + + if (!priv) + return NULL; + + priv->r = r; + priv->xat = xat; + priv->drm_fd = drm_fd; + REGION_NULL(pScreen, &priv->clip); + priv->hdtv = FALSE; + priv->uv_offset = 0.5f; + priv->uv_scale = 1.f; + priv->y_offset = 0.f; + priv->y_scale = 1.f; + priv->rgb_offset = 0.f; + priv->rgb_scale = 1.f; + priv->sinhue = 0.f; + priv->coshue = 1.f; + + vmwgfx_update_conversion_matrix(priv); + + return priv; +} + +static void +vmwgfx_free_textured_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports) +{ + if (free_ports) { + int i; + + for(i=0; i<adaptor->nPorts; ++i) { + free(adaptor->pPortPrivates[i].ptr); + } + } + + free(adaptor->pAttributes); + free(adaptor->pPortPrivates); + xf86XVFreeVideoAdaptorRec(adaptor); +} + +static XF86VideoAdaptorPtr +xorg_setup_textured_adapter(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + XF86VideoAdaptorPtr adapt; + XF86AttributePtr attrs; + DevUnion *dev_unions; + int nports = 16, i; + int nattributes; + struct xa_context *xar; + + /* + * Use the XA default context since we don't expect the X server + * to render from multiple threads. + */ + + xar = xa_context_default(ms->xat); + nattributes = NUM_TEXTURED_ATTRIBUTES; + + adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); + dev_unions = calloc(nports, sizeof(DevUnion)); + attrs = calloc(nattributes, sizeof(XF86AttributeRec)); + if (adapt == NULL || dev_unions == NULL || attrs == NULL) { + free(adapt); + free(dev_unions); + free(attrs); + return NULL; + } + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "XA G3D Textured Video"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 0; + adapt->pPortPrivates = dev_unions; + adapt->nAttributes = nattributes; + adapt->pAttributes = attrs; + memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec)); + adapt->nImages = NUM_IMAGES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = stop_video; + adapt->SetPortAttribute = set_port_attribute; + adapt->GetPortAttribute = get_port_attribute; + adapt->QueryBestSize = query_best_size; + adapt->PutImage = put_image; + adapt->QueryImageAttributes = query_image_attributes; + + + for (i = 0; i < nports; i++) { + struct xorg_xv_port_priv *priv = + port_priv_create(ms->xat, xar, ms->fd); + + adapt->pPortPrivates[i].ptr = (pointer) (priv); + adapt->nPorts++; + } + + return adapt; +} + +void +xorg_xv_init(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL; + XF86VideoAdaptorPtr textured_adapter = NULL, overlay_adaptor = NULL; + int num_adaptors; + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + new_adaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); + if (new_adaptors == NULL) + return; + + memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); + adaptors = new_adaptors; + + /* Add the adaptors supported by our hardware. First, set up the atoms + * that will be used by both output adaptors. + */ + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + xvHue = MAKE_ATOM("XV_HUE"); + + if (ms->xat) { + textured_adapter = xorg_setup_textured_adapter(pScreen); + if (textured_adapter) + adaptors[num_adaptors++] = textured_adapter; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No 3D acceleration. Not setting up textured video.\n"); + } + + overlay_adaptor = vmw_video_init_adaptor(pScrn); + if (overlay_adaptor) + adaptors[num_adaptors++] = overlay_adaptor; + + if (num_adaptors) { + Bool ret; + ret = xf86XVScreenInit(pScreen, adaptors, num_adaptors); + if (textured_adapter) + vmwgfx_free_textured_adaptor(textured_adapter, !ret); + if (overlay_adaptor) + vmw_video_free_adaptor(overlay_adaptor, !ret); + if (!ret) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize Xv.\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling Xv because no adaptors could be initialized.\n"); + } + + + out_err_mem: + free(adaptors); +} diff --git a/vmwgfx/vmwgfx_xa_composite.c b/vmwgfx/vmwgfx_xa_composite.c new file mode 100644 index 0000000..a2e3970 --- /dev/null +++ b/vmwgfx/vmwgfx_xa_composite.c @@ -0,0 +1,277 @@ +/* + * Copyright 2009-2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + * Author: Zack Ruzin <zackr@vmware.com> + * + * The code in this file translates XRender PICT composite stuff + * to fit the libxatracker API. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <picturestr.h> +#include <X11/extensions/Xrender.h> +#include "xa_composite.h" +#include "vmwgfx_saa.h" +#include "vmwgfx_saa_priv.h" + + +struct vmwgfx_composite { + union xa_source_pict *src_spict; + union xa_source_pict *mask_spict; + union xa_source_pict *dst_spict; + struct xa_picture *src_pict; + struct xa_picture *mask_pict; + struct xa_picture *dst_pict; + struct xa_composite *comp; +}; + +static const enum xa_composite_op vmwgfx_op_map[] = { + [PictOpClear] = xa_op_clear, + [PictOpSrc] = xa_op_src, + [PictOpDst] = xa_op_dst, + [PictOpOver] = xa_op_over, + [PictOpOverReverse] = xa_op_over_reverse, + [PictOpIn] = xa_op_in, + [PictOpInReverse] = xa_op_in_reverse, + [PictOpOut] = xa_op_out, + [PictOpOutReverse] = xa_op_out_reverse, + [PictOpAtop] = xa_op_atop, + [PictOpAtopReverse] = xa_op_atop_reverse, + [PictOpXor] = xa_op_xor, + [PictOpAdd] = xa_op_add +}; + +static const unsigned int vmwgfx_op_map_size = + sizeof(vmwgfx_op_map) / sizeof(enum xa_composite_op); + +static Bool +vmwgfx_matrix_from_pict_transform(PictTransform *trans, float *matrix) +{ + if (!trans) + return FALSE; + + matrix[0] = XFixedToDouble(trans->matrix[0][0]); + matrix[3] = XFixedToDouble(trans->matrix[0][1]); + matrix[6] = XFixedToDouble(trans->matrix[0][2]); + + matrix[1] = XFixedToDouble(trans->matrix[1][0]); + matrix[4] = XFixedToDouble(trans->matrix[1][1]); + matrix[7] = XFixedToDouble(trans->matrix[1][2]); + + matrix[2] = XFixedToDouble(trans->matrix[2][0]); + matrix[5] = XFixedToDouble(trans->matrix[2][1]); + matrix[8] = XFixedToDouble(trans->matrix[2][2]); + + return TRUE; +} + +static enum xa_composite_wrap +vmwgfx_xa_setup_wrap(Bool pict_has_repeat, int pict_repeat) +{ + enum xa_composite_wrap wrap = xa_wrap_clamp_to_border; + + if (!pict_has_repeat) + return wrap; + + switch(pict_repeat) { + case RepeatNormal: + wrap = xa_wrap_repeat; + break; + case RepeatReflect: + wrap = xa_wrap_mirror_repeat; + break; + case RepeatPad: + wrap = xa_wrap_clamp_to_edge; + break; + default: + break; + } + return wrap; +} + +static Bool +vmwgfx_render_filter_to_xa(int xrender_filter, + enum xa_composite_filter *out_filter) +{ + switch (xrender_filter) { + case PictFilterConvolution: + case PictFilterNearest: + case PictFilterFast: + *out_filter = xa_filter_nearest; + break; + case PictFilterBest: + case PictFilterGood: + case PictFilterBilinear: + *out_filter = xa_filter_linear; + break; + default: + *out_filter = xa_filter_nearest; + return FALSE; + } + return TRUE; +} + +static Bool +vmwgfx_xa_setup_pict(PicturePtr pict, + struct xa_picture *xa_pict, + union xa_source_pict *src_pict) +{ + if (!pict) + return FALSE; + + memset(xa_pict, 0, sizeof(*xa_pict)); + + xa_pict->pict_format = vmwgfx_xa_format(pict->format); + if (xa_pict->pict_format == xa_format_unknown) + return FALSE; + + /* + * Saa doesn't let drivers accelerate alpha maps. + */ + xa_pict->alpha_map = NULL; + xa_pict->component_alpha = pict->componentAlpha; + + xa_pict->has_transform = + vmwgfx_matrix_from_pict_transform(pict->transform, + xa_pict->transform); + + xa_pict->wrap = vmwgfx_xa_setup_wrap(pict->repeat, + pict->repeatType); + + (void) vmwgfx_render_filter_to_xa(pict->filter, &xa_pict->filter); + + if (pict->pSourcePict) { + if (pict->pSourcePict->type != SourcePictTypeSolidFill) + return FALSE; + + src_pict->type = xa_src_pict_solid_fill; + src_pict->solid_fill.color = pict->pSourcePict->solidFill.color; + xa_pict->src_pict = src_pict; + } + + return TRUE; +} + +struct xa_composite * +vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp, + int op, + PicturePtr src_pict, + PicturePtr mask_pict, + PicturePtr dst_pict) +{ + struct xa_composite *comp = vcomp->comp; + + if (op >= vmwgfx_op_map_size) + return NULL; + + comp->op = vmwgfx_op_map[op]; + if (comp->op == xa_op_clear && op != PictOpClear) + return NULL; + + if (!vmwgfx_xa_setup_pict(dst_pict, vcomp->dst_pict, + vcomp->dst_spict)) + return NULL; + if (!vmwgfx_xa_setup_pict(src_pict, vcomp->src_pict, + vcomp->src_spict)) + return NULL; + if (mask_pict && !vmwgfx_xa_setup_pict(mask_pict, + vcomp->mask_pict, + vcomp->mask_spict)) + return NULL; + + comp->dst = vcomp->dst_pict; + comp->src = vcomp->src_pict; + comp->mask = (mask_pict) ? vcomp->mask_pict : NULL; + + return comp; +} + +Bool +vmwgfx_xa_update_comp(struct xa_composite *comp, + PixmapPtr src_pix, + PixmapPtr mask_pix, + PixmapPtr dst_pix) +{ + comp->dst->srf = vmwgfx_saa_pixmap(dst_pix)->hw; + if (src_pix) + comp->src->srf = vmwgfx_saa_pixmap(src_pix)->hw; + if (mask_pix && comp->mask) + comp->mask->srf = vmwgfx_saa_pixmap(mask_pix)->hw; + return TRUE; +} + + +void +vmwgfx_free_composite(struct vmwgfx_composite *vcomp) +{ + if (!vcomp) + return; + + if (vcomp->src_spict) + free(vcomp->src_spict); + if (vcomp->mask_spict) + free(vcomp->mask_spict); + if (vcomp->dst_spict) + free(vcomp->dst_spict); + if (vcomp->src_pict) + free(vcomp->src_pict); + if (vcomp->mask_pict) + free(vcomp->mask_pict); + if (vcomp->dst_pict) + free(vcomp->dst_pict); + if (vcomp->comp) + free(vcomp->comp); + free(vcomp); +} + +struct vmwgfx_composite * +vmwgfx_alloc_composite(void) +{ + const struct xa_composite_allocation *a = xa_composite_allocation(); + struct vmwgfx_composite *vcomp = calloc(1, sizeof(*vcomp)); + + if (!vcomp) + return NULL; + + vcomp->src_spict = calloc(1, a->xa_source_pict_size); + vcomp->mask_spict = calloc(1, a->xa_source_pict_size); + vcomp->dst_spict = calloc(1, a->xa_source_pict_size); + vcomp->src_pict = calloc(1, a->xa_picture_size); + vcomp->mask_pict = calloc(1, a->xa_picture_size); + vcomp->dst_pict = calloc(1, a->xa_picture_size); + vcomp->comp = calloc(1, a->xa_composite_size); + + if (!vcomp->src_spict || !vcomp->mask_spict || !vcomp->dst_spict || + !vcomp->src_pict || !vcomp->mask_pict || !vcomp->dst_pict || + !vcomp->comp) { + vmwgfx_free_composite(vcomp); + return NULL; + } + + return vcomp; +} diff --git a/vmwgfx/vmwgfx_xa_surface.c b/vmwgfx/vmwgfx_xa_surface.c new file mode 100644 index 0000000..2a18762 --- /dev/null +++ b/vmwgfx/vmwgfx_xa_surface.c @@ -0,0 +1,368 @@ +/* + * Copyright 2011 VMWare, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ +#ifdef _HAVE_CONFIG_H_ +#include "config.h" +#endif + +#include <xorg-server.h> +#include "vmwgfx_saa_priv.h" + + +static const enum xa_surface_type vmwgfx_stype_map[] = { + [PICT_TYPE_OTHER] = xa_type_other, + [PICT_TYPE_A] = xa_type_a, + [PICT_TYPE_ARGB] = xa_type_argb, + [PICT_TYPE_ABGR] = xa_type_abgr, + [PICT_TYPE_BGRA] = xa_type_bgra +}; + +static const unsigned int vmwgfx_stype_map_size = + sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type); + + +/* + * Create an xa format from a PICT format. + */ +enum xa_formats +vmwgfx_xa_format(enum _PictFormatShort format) +{ + uint32_t ptype = PICT_FORMAT_TYPE(format); + + if (ptype >= vmwgfx_stype_map_size || + vmwgfx_stype_map[ptype] == 0 || + vmwgfx_stype_map[ptype] == xa_type_other) + return xa_format_unknown; + + return xa_format(PICT_FORMAT_BPP(format), + vmwgfx_stype_map[ptype], + PICT_FORMAT_A(format), + PICT_FORMAT_R(format), + PICT_FORMAT_G(format), + PICT_FORMAT_B(format)); +} + +/* + * Choose formats and flags for a dri2 surface. + */ +static Bool +vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format; + + if (depth == 0) + depth = pixmap->drawable.depth; + + switch(depth) { + case 32: + format = xa_format_a8r8g8b8; + break; + case 24: + format = xa_format_x8r8g8b8; + break; + case 16: + format = xa_format_r5g6b5; + break; + case 15: + format = xa_format_x1r5g5b5; + break; + default: + return FALSE; + } + + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; + + return TRUE; +} + +/* + * Is composite old format compatible? Only difference is that old format + * has more alpha bits? + */ +static inline Bool +vmwgfx_old_format_compatible(enum xa_formats format, + enum xa_formats old_format) +{ + return (format == old_format || + (xa_format_type(format) == xa_format_type(old_format) && + xa_format_a(format) <= xa_format_a(old_format) && + xa_format_r(format) == xa_format_r(old_format) && + xa_format_g(format) == xa_format_g(old_format) && + xa_format_b(format) == xa_format_b(old_format))); +} + + +/* + * Choose format and flags for a composite dst surface. + */ +Bool +vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = vmwgfx_xa_format(pict_format); + + /* + * Check if we can reuse old hardware format. + */ + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vmwgfx_old_format_compatible(format, old_format)) + format = old_format; + } + + if (xa_format_check_supported(vsaa->xat, format, + vpix->xa_flags | XA_FLAG_RENDER_TARGET) != + XA_ERR_NONE) { + return FALSE; + } + + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = XA_FLAG_RENDER_TARGET; + + return TRUE; +} + +/* + * Choose format and flags for a composite src surface. + */ +Bool +vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = vmwgfx_xa_format(pict_format); + enum xa_formats swizzle_format = xa_format_unknown; + enum xa_surface_type ftype; + + if (format == xa_format_unknown) + return FALSE; + + ftype = xa_format_type(format); + if (ftype == xa_type_abgr) { + + swizzle_format = xa_format(xa_format_bpp(format), + xa_type_argb, + xa_format_a(format), + xa_format_r(format), + xa_format_g(format), + xa_format_b(format)); + } + + /* + * Check if we can reuse old format. + */ + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vmwgfx_old_format_compatible(format, old_format) || + (swizzle_format != xa_format_unknown && + vmwgfx_old_format_compatible(swizzle_format, old_format))) { + format = old_format; + goto have_format; + } + } + + if (swizzle_format != xa_format_unknown && + xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) == + XA_ERR_NONE) { + format = swizzle_format; + goto have_format; + } + + if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) == + XA_ERR_NONE) { + goto have_format; + } + + return FALSE; + have_format: + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = 0; + + return TRUE; +} + +/* + * Choose accel format given depth. + */ +static enum xa_formats +vmwgfx_choose_accel_format(unsigned int depth) +{ + switch(depth) { + case 32: + return xa_format_a8r8g8b8; + case 24: + return xa_format_x8r8g8b8; + case 16: + return xa_format_r5g6b5; + case 15: + return xa_format_x1r5g5b5; + case 8: + return xa_format_a8; + default: + break; + } + return xa_format_unknown; +} + + +/* + * Determine xa format and flags for an ordinary accel surface. + */ +Bool +vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = xa_format_unknown; + + if (depth == 0) + depth = pixmap->drawable.depth; + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + enum xa_surface_type ftype = xa_format_type(old_format); + + if (ftype != xa_type_argb && + ftype != xa_type_a) { + LogMessage(X_ERROR, + "Acceleration fallback due to strange hw format.\n"); + return FALSE; + } + + if (xa_format_depth(old_format) == depth || + (xa_format_depth(old_format) == 32 && + depth == 24)) + format = old_format; + } + + if (format == xa_format_unknown) + format = vmwgfx_choose_accel_format(depth); + + if (format == xa_format_unknown) + return FALSE; + + vpix->staging_add_flags = add_flags; + vpix->staging_remove_flags = remove_flags; + vpix->staging_format = format; + + return TRUE; +} + +/* + * Create a surface with a format and flags determined by one of + * the staging functions. + */ +Bool +vmwgfx_hw_commit(PixmapPtr pixmap) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + enum xa_formats format = vpix->staging_format; + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vpix->staging_format != old_format) { + if (xa_format_type(format) != xa_format_type(old_format) || + xa_format_r(format) != xa_format_r(old_format) || + xa_format_g(format) != xa_format_g(old_format) || + xa_format_b(format) != xa_format_b(old_format)) { + + LogMessage(X_INFO, "Killing old hw surface.\n"); + + if (!vmwgfx_hw_kill(vsaa, spix)) + return FALSE; + } + } + } + + if (vpix->hw) { + uint32_t new_flags; + + new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | + vpix->staging_add_flags; + + if (vpix->staging_format != xa_surface_format(vpix->hw)) + LogMessage(X_INFO, "Changing hardware format.\n"); + + if (xa_surface_redefine(vpix->hw, + pixmap->drawable.width, + pixmap->drawable.height, + 0, + xa_type_other, + vpix->staging_format, + new_flags, 1) != XA_ERR_NONE) + return FALSE; + vpix->xa_flags = new_flags; + } else if (!vmwgfx_create_hw(vsaa, pixmap)) + return FALSE; + + return TRUE; +} + +/* + * Create an accel surface if there is none, and make sure the region + * given by @region is valid. If @region is NULL, the whole surface + * will be valid. This is a utility convenience function only. + */ +Bool +vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags, + RegionPtr region) +{ + return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) && + vmwgfx_hw_commit(pixmap) && + vmwgfx_hw_validate(pixmap, region)); +} + + +/* + * Create a dri2 surface if there is none, + * and make sure the whole surfade is valid. + * This is a utility convenience function only. + */ +Bool +vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth) +{ + return (vmwgfx_hw_dri2_stage(pixmap, depth) && + vmwgfx_hw_commit(pixmap) && + vmwgfx_hw_validate(pixmap, NULL)); +} diff --git a/vmwgfx/wsbm_util.h b/vmwgfx/wsbm_util.h new file mode 100644 index 0000000..2a2613b --- /dev/null +++ b/vmwgfx/wsbm_util.h @@ -0,0 +1,79 @@ +/* + * This file is not copyrighted. + */ + +#ifndef _WSBM_UTIL_H_ +#define _WSBM_UTIL_H_ + +#include <stddef.h> + +#ifndef containerOf +#define containerOf(__item, __type, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) +#endif + +struct _WsbmListHead +{ + struct _WsbmListHead *prev; + struct _WsbmListHead *next; +}; + +#define WSBMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define WSBMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define WSBMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define WSBMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define WSBMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define WSBMLISTFOREACH(__item, __list) \ + for((__item) = (__list)->next; (__item) != (__list); (__item) = (__item)->next) + +#define WSBMLISTFOREACHPREV(__item, __list) \ + for((__item) = (__list)->prev; (__item) != (__list); (__item) = (__item)->prev) + +#define WSBMLISTFOREACHSAFE(__item, __next, __list) \ + for((__item) = (__list)->next, (__next) = (__item)->next; \ + (__item) != (__list); \ + (__item) = (__next), (__next) = (__item)->next) + +#define WSBMLISTFOREACHPREVSAFE(__item, __prev, __list) \ + for((__item) = (__list)->prev, (__prev) = (__item->prev); \ + (__item) != (__list); \ + (__item) = (__prev), (__prev) = (__item)->prev) + +#define WSBMLISTENTRY(__item, __type, __field) \ + containerOf(__item, __type, __field) + +#define WSBMLISTEMPTY(__item) \ + ((__item)->next == (__item)) + +#endif |