summaryrefslogtreecommitdiff
path: root/vmwgfx
diff options
context:
space:
mode:
Diffstat (limited to 'vmwgfx')
-rw-r--r--vmwgfx/Makefile.am26
-rw-r--r--vmwgfx/svga3d_reg.h1801
-rw-r--r--vmwgfx/vmwgfx_crtc.c455
-rw-r--r--vmwgfx/vmwgfx_ctrl.c523
-rw-r--r--vmwgfx/vmwgfx_ctrl.h48
-rw-r--r--vmwgfx/vmwgfx_dri2.c426
-rw-r--r--vmwgfx/vmwgfx_driver.c1200
-rw-r--r--vmwgfx/vmwgfx_driver.h186
-rw-r--r--vmwgfx/vmwgfx_drm.h792
-rw-r--r--vmwgfx/vmwgfx_drmi.c502
-rw-r--r--vmwgfx/vmwgfx_drmi.h87
-rw-r--r--vmwgfx/vmwgfx_output.c393
-rw-r--r--vmwgfx/vmwgfx_overlay.c893
-rw-r--r--vmwgfx/vmwgfx_saa.c1514
-rw-r--r--vmwgfx/vmwgfx_saa.h110
-rw-r--r--vmwgfx/vmwgfx_saa_priv.h125
-rw-r--r--vmwgfx/vmwgfx_tex_video.c855
-rw-r--r--vmwgfx/vmwgfx_xa_composite.c277
-rw-r--r--vmwgfx/vmwgfx_xa_surface.c368
-rw-r--r--vmwgfx/wsbm_util.h79
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, &reg, &box, 1);
+ REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, &reg);
+ REGION_UNINIT(pScreen, &reg);
+}
+
+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 = &empty;
+ }
+
+ 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, &reg);
+ REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_update,
+ damage);
+ if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
+ vsaa->present_flush(vsaa->pScreen);
+ REGION_UNINIT(pScreen, &reg);
+ }
+ 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, &reg);
+ REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_present,
+ damage);
+ if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
+ vsaa->present_flush(vsaa->pScreen);
+ REGION_UNINIT(pScreen, &reg);
+ }
+ 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, &reg, &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, &reg, &box);
+ }
+
+ if (xa_surface_handle(srf, &handle, &stride) != 0) {
+ ret = BadAlloc;
+ break;
+ }
+
+ if (vmwgfx_dma(0, 0, &reg, buf, w, handle, 1) != 0) {
+ ret = BadAlloc;
+ break;
+ }
+ }
+ REGION_UNINIT(pScrn->pScreen, &reg);
+ }
+
+ 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, &reg);
+
+ if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, &reg))
+ 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, &reg);
+ 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