summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/svga
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/svga')
-rw-r--r--src/gallium/drivers/svga/Makefile60
-rw-r--r--src/gallium/drivers/svga/SConscript72
-rw-r--r--src/gallium/drivers/svga/include/README3
-rw-r--r--src/gallium/drivers/svga/include/svga3d_caps.h139
-rw-r--r--src/gallium/drivers/svga/include/svga3d_reg.h1793
-rw-r--r--src/gallium/drivers/svga/include/svga3d_shaderdefs.h519
-rw-r--r--src/gallium/drivers/svga/include/svga_reg.h1346
-rw-r--r--src/gallium/drivers/svga/include/svga_types.h46
-rw-r--r--src/gallium/drivers/svga/svga_cmd.c1427
-rw-r--r--src/gallium/drivers/svga/svga_cmd.h235
-rw-r--r--src/gallium/drivers/svga/svga_context.c271
-rw-r--r--src/gallium/drivers/svga/svga_context.h448
-rw-r--r--src/gallium/drivers/svga/svga_debug.h75
-rw-r--r--src/gallium/drivers/svga/svga_draw.c377
-rw-r--r--src/gallium/drivers/svga/svga_draw.h83
-rw-r--r--src/gallium/drivers/svga/svga_draw_arrays.c297
-rw-r--r--src/gallium/drivers/svga/svga_draw_elements.c255
-rw-r--r--src/gallium/drivers/svga/svga_draw_private.h158
-rw-r--r--src/gallium/drivers/svga/svga_hw_reg.h42
-rw-r--r--src/gallium/drivers/svga/svga_pipe_blend.c246
-rw-r--r--src/gallium/drivers/svga/svga_pipe_blit.c92
-rw-r--r--src/gallium/drivers/svga/svga_pipe_clear.c125
-rw-r--r--src/gallium/drivers/svga/svga_pipe_constants.c74
-rw-r--r--src/gallium/drivers/svga/svga_pipe_depthstencil.c153
-rw-r--r--src/gallium/drivers/svga/svga_pipe_draw.c261
-rw-r--r--src/gallium/drivers/svga/svga_pipe_flush.c71
-rw-r--r--src/gallium/drivers/svga/svga_pipe_fs.c124
-rw-r--r--src/gallium/drivers/svga/svga_pipe_misc.c187
-rw-r--r--src/gallium/drivers/svga/svga_pipe_query.c267
-rw-r--r--src/gallium/drivers/svga/svga_pipe_rasterizer.c250
-rw-r--r--src/gallium/drivers/svga/svga_pipe_sampler.c243
-rw-r--r--src/gallium/drivers/svga/svga_pipe_vertex.c115
-rw-r--r--src/gallium/drivers/svga/svga_pipe_vs.c189
-rw-r--r--src/gallium/drivers/svga/svga_screen.c440
-rw-r--r--src/gallium/drivers/svga/svga_screen.h95
-rw-r--r--src/gallium/drivers/svga/svga_screen_buffer.c824
-rw-r--r--src/gallium/drivers/svga/svga_screen_buffer.h190
-rw-r--r--src/gallium/drivers/svga/svga_screen_cache.c338
-rw-r--r--src/gallium/drivers/svga/svga_screen_cache.h144
-rw-r--r--src/gallium/drivers/svga/svga_screen_texture.c1089
-rw-r--r--src/gallium/drivers/svga/svga_screen_texture.h187
-rw-r--r--src/gallium/drivers/svga/svga_state.c278
-rw-r--r--src/gallium/drivers/svga/svga_state.h95
-rw-r--r--src/gallium/drivers/svga/svga_state_constants.c239
-rw-r--r--src/gallium/drivers/svga/svga_state_framebuffer.c458
-rw-r--r--src/gallium/drivers/svga/svga_state_fs.c282
-rw-r--r--src/gallium/drivers/svga/svga_state_need_swtnl.c200
-rw-r--r--src/gallium/drivers/svga/svga_state_rss.c268
-rw-r--r--src/gallium/drivers/svga/svga_state_tss.c279
-rw-r--r--src/gallium/drivers/svga/svga_state_vdecl.c182
-rw-r--r--src/gallium/drivers/svga/svga_state_vs.c239
-rw-r--r--src/gallium/drivers/svga/svga_swtnl.h52
-rw-r--r--src/gallium/drivers/svga/svga_swtnl_backend.c349
-rw-r--r--src/gallium/drivers/svga/svga_swtnl_draw.c170
-rw-r--r--src/gallium/drivers/svga/svga_swtnl_private.h93
-rw-r--r--src/gallium/drivers/svga/svga_swtnl_state.c242
-rw-r--r--src/gallium/drivers/svga/svga_tgsi.c280
-rw-r--r--src/gallium/drivers/svga/svga_tgsi.h139
-rw-r--r--src/gallium/drivers/svga/svga_tgsi_decl_sm20.c280
-rw-r--r--src/gallium/drivers/svga/svga_tgsi_decl_sm30.c385
-rw-r--r--src/gallium/drivers/svga/svga_tgsi_emit.h345
-rw-r--r--src/gallium/drivers/svga/svga_tgsi_insn.c2716
-rw-r--r--src/gallium/drivers/svga/svga_winsys.h299
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_dump.c1736
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_dump.h34
-rwxr-xr-xsrc/gallium/drivers/svga/svgadump/svga_dump.py329
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_shader.h220
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_shader_dump.c654
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_shader_dump.h42
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_shader_op.c168
-rw-r--r--src/gallium/drivers/svga/svgadump/svga_shader_op.h46
71 files changed, 24449 insertions, 0 deletions
diff --git a/src/gallium/drivers/svga/Makefile b/src/gallium/drivers/svga/Makefile
new file mode 100644
index 0000000000..f361908187
--- /dev/null
+++ b/src/gallium/drivers/svga/Makefile
@@ -0,0 +1,60 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = svga
+
+C_SOURCES = \
+ svgadump/svga_shader_dump.c \
+ svgadump/svga_shader_op.c \
+ svgadump/svga_dump.c \
+ svga_cmd.c \
+ svga_context.c \
+ svga_draw.c \
+ svga_draw_arrays.c \
+ svga_draw_elements.c \
+ svga_pipe_blend.c \
+ svga_pipe_blit.c \
+ svga_pipe_clear.c \
+ svga_pipe_constants.c \
+ svga_pipe_depthstencil.c \
+ svga_pipe_draw.c \
+ svga_pipe_flush.c \
+ svga_pipe_fs.c \
+ svga_pipe_misc.c \
+ svga_pipe_query.c \
+ svga_pipe_rasterizer.c \
+ svga_pipe_sampler.c \
+ svga_pipe_vertex.c \
+ svga_pipe_vs.c \
+ svga_screen.c \
+ svga_screen_buffer.c \
+ svga_screen_texture.c \
+ svga_screen_cache.c \
+ svga_state.c \
+ svga_state_need_swtnl.c \
+ svga_state_constants.c \
+ svga_state_framebuffer.c \
+ svga_state_rss.c \
+ svga_state_tss.c \
+ svga_state_vdecl.c \
+ svga_state_fs.c \
+ svga_state_vs.c \
+ svga_swtnl_backend.c \
+ svga_swtnl_draw.c \
+ svga_swtnl_state.c \
+ svga_tgsi.c \
+ svga_tgsi_decl_sm20.c \
+ svga_tgsi_decl_sm30.c \
+ svga_tgsi_insn.c
+
+LIBRARY_INCLUDES = \
+ -I$(TOP)/src/gallium/drivers/svga/include
+
+# With linux-debug we get a lots of warnings, filter out the bad flags.
+CFLAGS := $(filter-out -pedantic, $(filter-out -ansi, $(CFLAGS)))
+
+LIBRARY_DEFINES = \
+ -std=gnu99 -fvisibility=hidden \
+ -DHAVE_STDINT_H -DHAVE_SYS_TYPES_H
+
+include ../../Makefile.template
diff --git a/src/gallium/drivers/svga/SConscript b/src/gallium/drivers/svga/SConscript
new file mode 100644
index 0000000000..737b791ceb
--- /dev/null
+++ b/src/gallium/drivers/svga/SConscript
@@ -0,0 +1,72 @@
+Import('*')
+
+env = env.Clone()
+
+if env['platform'] in ['linux']:
+ env.Append(CCFLAGS = ['-fvisibility=hidden'])
+
+if env['gcc']:
+ env.Append(CPPDEFINES = [
+ 'HAVE_STDINT_H',
+ 'HAVE_SYS_TYPES_H',
+ ])
+
+env.Prepend(CPPPATH = [
+ 'include',
+])
+
+env.Append(CPPDEFINES = [
+])
+
+sources = [
+ 'svga_cmd.c',
+ 'svga_context.c',
+ 'svga_draw.c',
+ 'svga_draw_arrays.c',
+ 'svga_draw_elements.c',
+ 'svga_pipe_blend.c',
+ 'svga_pipe_blit.c',
+ 'svga_pipe_clear.c',
+ 'svga_pipe_constants.c',
+ 'svga_pipe_depthstencil.c',
+ 'svga_pipe_draw.c',
+ 'svga_pipe_flush.c',
+ 'svga_pipe_fs.c',
+ 'svga_pipe_misc.c',
+ 'svga_pipe_query.c',
+ 'svga_pipe_rasterizer.c',
+ 'svga_pipe_sampler.c',
+ 'svga_pipe_vertex.c',
+ 'svga_pipe_vs.c',
+ 'svga_screen.c',
+ 'svga_screen_buffer.c',
+ 'svga_screen_cache.c',
+ 'svga_screen_texture.c',
+ 'svga_state.c',
+ 'svga_state_constants.c',
+ 'svga_state_framebuffer.c',
+ 'svga_state_need_swtnl.c',
+ 'svga_state_rss.c',
+ 'svga_state_tss.c',
+ 'svga_state_vdecl.c',
+ 'svga_state_fs.c',
+ 'svga_state_vs.c',
+ 'svga_swtnl_backend.c',
+ 'svga_swtnl_draw.c',
+ 'svga_swtnl_state.c',
+ 'svga_tgsi.c',
+ 'svga_tgsi_decl_sm20.c',
+ 'svga_tgsi_decl_sm30.c',
+ 'svga_tgsi_insn.c',
+
+ 'svgadump/svga_dump.c',
+ 'svgadump/svga_shader_dump.c',
+ 'svgadump/svga_shader_op.c',
+]
+
+svga = env.ConvenienceLibrary(
+ target = 'svga',
+ source = sources,
+)
+
+Export('svga')
diff --git a/src/gallium/drivers/svga/include/README b/src/gallium/drivers/svga/include/README
new file mode 100644
index 0000000000..a0b8916104
--- /dev/null
+++ b/src/gallium/drivers/svga/include/README
@@ -0,0 +1,3 @@
+This directory contains the headers from the VMware SVGA Device Developer Kit:
+
+ https://vmware-svga.svn.sourceforge.net/svnroot/vmware-svga/trunk/lib/vmware/
diff --git a/src/gallium/drivers/svga/include/svga3d_caps.h b/src/gallium/drivers/svga/include/svga3d_caps.h
new file mode 100644
index 0000000000..714ce9f45f
--- /dev/null
+++ b/src/gallium/drivers/svga/include/svga3d_caps.h
@@ -0,0 +1,139 @@
+/**********************************************************
+ * Copyright 2007-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_caps.h --
+ *
+ * Definitions for SVGA3D hardware capabilities. Capabilities
+ * are used to query for optional rendering features during
+ * driver initialization. The capability data is stored as very
+ * basic key/value dictionary within the "FIFO register" memory
+ * area at the beginning of BAR2.
+ *
+ * Note that these definitions are only for 3D capabilities.
+ * The SVGA device also has "device capabilities" and "FIFO
+ * capabilities", which are non-3D-specific and are stored as
+ * bitfields rather than key/value pairs.
+ */
+
+#ifndef _SVGA3D_CAPS_H_
+#define _SVGA3D_CAPS_H_
+
+#define SVGA_FIFO_3D_CAPS_SIZE (SVGA_FIFO_3D_CAPS_LAST - \
+ SVGA_FIFO_3D_CAPS + 1)
+
+
+/*
+ * SVGA3dCapsRecordType
+ *
+ * Record types that can be found in the caps block.
+ * Related record types are grouped together numerically so that
+ * SVGA3dCaps_FindRecord() can be applied on a range of record
+ * types.
+ */
+
+typedef enum {
+ SVGA3DCAPS_RECORD_UNKNOWN = 0,
+ SVGA3DCAPS_RECORD_DEVCAPS_MIN = 0x100,
+ SVGA3DCAPS_RECORD_DEVCAPS = 0x100,
+ SVGA3DCAPS_RECORD_DEVCAPS_MAX = 0x1ff,
+} SVGA3dCapsRecordType;
+
+
+/*
+ * SVGA3dCapsRecordHeader
+ *
+ * Header field leading each caps block record. Contains the offset (in
+ * register words, NOT bytes) to the next caps block record (or the end
+ * of caps block records which will be a zero word) and the record type
+ * as defined above.
+ */
+
+typedef
+struct SVGA3dCapsRecordHeader {
+ uint32 length;
+ SVGA3dCapsRecordType type;
+}
+SVGA3dCapsRecordHeader;
+
+
+/*
+ * SVGA3dCapsRecord
+ *
+ * Caps block record; "data" is a placeholder for the actual data structure
+ * contained within the record; for example a record containing a FOOBAR
+ * structure would be of size "sizeof(SVGA3dCapsRecordHeader) +
+ * sizeof(FOOBAR)".
+ */
+
+typedef
+struct SVGA3dCapsRecord {
+ SVGA3dCapsRecordHeader header;
+ uint32 data[1];
+}
+SVGA3dCapsRecord;
+
+
+typedef uint32 SVGA3dCapPair[2];
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3dCaps_FindRecord
+ *
+ * Finds the record with the highest-valued type within the given range
+ * in the caps block.
+ *
+ * Result: pointer to found record, or NULL if not found.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE SVGA3dCapsRecord *
+SVGA3dCaps_FindRecord(const uint32 *capsBlock,
+ SVGA3dCapsRecordType recordTypeMin,
+ SVGA3dCapsRecordType recordTypeMax)
+{
+ SVGA3dCapsRecord *record, *found = NULL;
+ uint32 offset;
+
+ /*
+ * Search linearly through the caps block records for the specified type.
+ */
+ for (offset = 0; capsBlock[offset] != 0; offset += capsBlock[offset]) {
+ record = (SVGA3dCapsRecord *) (capsBlock + offset);
+ if ((record->header.type >= recordTypeMin) &&
+ (record->header.type <= recordTypeMax) &&
+ (!found || (record->header.type > found->header.type))) {
+ found = record;
+ }
+ }
+
+ return found;
+}
+
+
+#endif // _SVGA3D_CAPS_H_
diff --git a/src/gallium/drivers/svga/include/svga3d_reg.h b/src/gallium/drivers/svga/include/svga3d_reg.h
new file mode 100644
index 0000000000..77cb453310
--- /dev/null
+++ b/src/gallium/drivers/svga/include/svga3d_reg.h
@@ -0,0 +1,1793 @@
+/**********************************************************
+ * 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 vertex arrays we're guaranteed to support in
+ * SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_VERTEX_ARRAYS 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'
+ * 2. SVGA3dPrimitiveRange, quantity 'numRanges'
+ * 3. Optionally, SVGA3dVertexDivisor, quantity 'numVertexDecls' (contains
+ * the frequency divisor for this 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/src/gallium/drivers/svga/include/svga3d_shaderdefs.h b/src/gallium/drivers/svga/include/svga3d_shaderdefs.h
new file mode 100644
index 0000000000..2078c4a8a4
--- /dev/null
+++ b/src/gallium/drivers/svga/include/svga3d_shaderdefs.h
@@ -0,0 +1,519 @@
+/**********************************************************
+ * Copyright 2007-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_shaderdefs.h --
+ *
+ * SVGA3D byte code format and limit definitions.
+ *
+ * The format of the byte code directly corresponds to that defined
+ * by Microsoft DirectX SDK 9.0c (file d3d9types.h). The format can
+ * also be extended so that different shader formats can be supported
+ * for example GLSL, ARB vp/fp, NV/ATI shader formats, etc.
+ *
+ */
+
+#ifndef __SVGA3D_SHADER_DEFS__
+#define __SVGA3D_SHADER_DEFS__
+
+/* SVGA3D shader hardware limits. */
+
+#define SVGA3D_INPUTREG_MAX 16
+#define SVGA3D_OUTPUTREG_MAX 12
+#define SVGA3D_VERTEX_SAMPLERREG_MAX 4
+#define SVGA3D_PIXEL_SAMPLERREG_MAX 16
+#define SVGA3D_SAMPLERREG_MAX (SVGA3D_PIXEL_SAMPLERREG_MAX+\
+ SVGA3D_VERTEX_SAMPLERREG_MAX)
+#define SVGA3D_TEMPREG_MAX 32
+#define SVGA3D_CONSTREG_MAX 256
+#define SVGA3D_CONSTINTREG_MAX 16
+#define SVGA3D_CONSTBOOLREG_MAX 16
+#define SVGA3D_ADDRREG_MAX 1
+#define SVGA3D_PREDREG_MAX 1
+
+/* SVGA3D byte code specific limits */
+
+#define SVGA3D_MAX_SRC_REGS 4
+#define SVGA3D_MAX_NESTING_LEVEL 32
+
+/* SVGA3D version information. */
+
+#define SVGA3D_VS_TYPE 0xFFFE
+#define SVGA3D_PS_TYPE 0xFFFF
+
+typedef struct {
+ union {
+ struct {
+ uint32 minor : 8;
+ uint32 major : 8;
+ uint32 type : 16;
+ };
+
+ uint32 value;
+ };
+} SVGA3dShaderVersion;
+
+#define SVGA3D_VS_10 ((SVGA3D_VS_TYPE << 16) | 1 << 8)
+#define SVGA3D_VS_11 (SVGA3D_VS_10 | 1)
+#define SVGA3D_VS_20 ((SVGA3D_VS_TYPE << 16) | 2 << 8)
+#define SVGA3D_VS_30 ((SVGA3D_VS_TYPE << 16) | 3 << 8)
+
+#define SVGA3D_PS_10 ((SVGA3D_PS_TYPE << 16) | 1 << 8)
+#define SVGA3D_PS_11 (SVGA3D_PS_10 | 1)
+#define SVGA3D_PS_12 (SVGA3D_PS_10 | 2)
+#define SVGA3D_PS_13 (SVGA3D_PS_10 | 3)
+#define SVGA3D_PS_14 (SVGA3D_PS_10 | 4)
+#define SVGA3D_PS_20 ((SVGA3D_PS_TYPE << 16) | 2 << 8)
+#define SVGA3D_PS_30 ((SVGA3D_PS_TYPE << 16) | 3 << 8)
+
+/* The *_ENABLED are for backwards compatibility with old drivers */
+typedef enum {
+ SVGA3DPSVERSION_NONE = 0,
+ SVGA3DPSVERSION_ENABLED = 1,
+ SVGA3DPSVERSION_11 = 3,
+ SVGA3DPSVERSION_12 = 5,
+ SVGA3DPSVERSION_13 = 7,
+ SVGA3DPSVERSION_14 = 9,
+ SVGA3DPSVERSION_20 = 11,
+ SVGA3DPSVERSION_30 = 13,
+ SVGA3DPSVERSION_40 = 15,
+ SVGA3DPSVERSION_MAX
+} SVGA3dPixelShaderVersion;
+
+typedef enum {
+ SVGA3DVSVERSION_NONE = 0,
+ SVGA3DVSVERSION_ENABLED = 1,
+ SVGA3DVSVERSION_11 = 3,
+ SVGA3DVSVERSION_20 = 5,
+ SVGA3DVSVERSION_30 = 7,
+ SVGA3DVSVERSION_40 = 9,
+ SVGA3DVSVERSION_MAX
+} SVGA3dVertexShaderVersion;
+
+/* SVGA3D instruction op codes. */
+
+typedef enum {
+ SVGA3DOP_NOP = 0,
+ SVGA3DOP_MOV,
+ SVGA3DOP_ADD,
+ SVGA3DOP_SUB,
+ SVGA3DOP_MAD,
+ SVGA3DOP_MUL,
+ SVGA3DOP_RCP,
+ SVGA3DOP_RSQ,
+ SVGA3DOP_DP3,
+ SVGA3DOP_DP4,
+ SVGA3DOP_MIN,
+ SVGA3DOP_MAX,
+ SVGA3DOP_SLT,
+ SVGA3DOP_SGE,
+ SVGA3DOP_EXP,
+ SVGA3DOP_LOG,
+ SVGA3DOP_LIT,
+ SVGA3DOP_DST,
+ SVGA3DOP_LRP,
+ SVGA3DOP_FRC,
+ SVGA3DOP_M4x4,
+ SVGA3DOP_M4x3,
+ SVGA3DOP_M3x4,
+ SVGA3DOP_M3x3,
+ SVGA3DOP_M3x2,
+ SVGA3DOP_CALL,
+ SVGA3DOP_CALLNZ,
+ SVGA3DOP_LOOP,
+ SVGA3DOP_RET,
+ SVGA3DOP_ENDLOOP,
+ SVGA3DOP_LABEL,
+ SVGA3DOP_DCL,
+ SVGA3DOP_POW,
+ SVGA3DOP_CRS,
+ SVGA3DOP_SGN,
+ SVGA3DOP_ABS,
+ SVGA3DOP_NRM,
+ SVGA3DOP_SINCOS,
+ SVGA3DOP_REP,
+ SVGA3DOP_ENDREP,
+ SVGA3DOP_IF,
+ SVGA3DOP_IFC,
+ SVGA3DOP_ELSE,
+ SVGA3DOP_ENDIF,
+ SVGA3DOP_BREAK,
+ SVGA3DOP_BREAKC,
+ SVGA3DOP_MOVA,
+ SVGA3DOP_DEFB,
+ SVGA3DOP_DEFI,
+ SVGA3DOP_TEXCOORD = 64,
+ SVGA3DOP_TEXKILL,
+ SVGA3DOP_TEX,
+ SVGA3DOP_TEXBEM,
+ SVGA3DOP_TEXBEML,
+ SVGA3DOP_TEXREG2AR,
+ SVGA3DOP_TEXREG2GB = 70,
+ SVGA3DOP_TEXM3x2PAD,
+ SVGA3DOP_TEXM3x2TEX,
+ SVGA3DOP_TEXM3x3PAD,
+ SVGA3DOP_TEXM3x3TEX,
+ SVGA3DOP_RESERVED0,
+ SVGA3DOP_TEXM3x3SPEC,
+ SVGA3DOP_TEXM3x3VSPEC,
+ SVGA3DOP_EXPP,
+ SVGA3DOP_LOGP,
+ SVGA3DOP_CND = 80,
+ SVGA3DOP_DEF,
+ SVGA3DOP_TEXREG2RGB,
+ SVGA3DOP_TEXDP3TEX,
+ SVGA3DOP_TEXM3x2DEPTH,
+ SVGA3DOP_TEXDP3,
+ SVGA3DOP_TEXM3x3,
+ SVGA3DOP_TEXDEPTH,
+ SVGA3DOP_CMP,
+ SVGA3DOP_BEM,
+ SVGA3DOP_DP2ADD = 90,
+ SVGA3DOP_DSX,
+ SVGA3DOP_DSY,
+ SVGA3DOP_TEXLDD,
+ SVGA3DOP_SETP,
+ SVGA3DOP_TEXLDL,
+ SVGA3DOP_BREAKP = 96,
+ SVGA3DOP_LAST_INST,
+ SVGA3DOP_PHASE = 0xFFFD,
+ SVGA3DOP_COMMENT = 0xFFFE,
+ SVGA3DOP_END = 0xFFFF,
+} SVGA3dShaderOpCodeType;
+
+/* SVGA3D operation control/comparison function types */
+
+typedef enum {
+ SVGA3DOPCONT_NONE,
+ SVGA3DOPCONT_PROJECT, /* Projective texturing */
+ SVGA3DOPCONT_BIAS, /* Texturing with a LOD bias */
+} SVGA3dShaderOpCodeControlFnType;
+
+typedef enum {
+ SVGA3DOPCOMP_RESERVED0 = 0,
+ SVGA3DOPCOMP_GT,
+ SVGA3DOPCOMP_EQ,
+ SVGA3DOPCOMP_GE,
+ SVGA3DOPCOMP_LT,
+ SVGA3DOPCOMPC_NE,
+ SVGA3DOPCOMP_LE,
+ SVGA3DOPCOMP_RESERVED1
+} SVGA3dShaderOpCodeCompFnType;
+
+/* SVGA3D register types */
+
+typedef enum {
+ SVGA3DREG_TEMP = 0, /* Temporary register file */
+ SVGA3DREG_INPUT, /* Input register file */
+ SVGA3DREG_CONST, /* Constant register file */
+ SVGA3DREG_ADDR, /* Address register for VS */
+ SVGA3DREG_TEXTURE = 3, /* Texture register file for PS */
+ SVGA3DREG_RASTOUT, /* Rasterizer register file */
+ SVGA3DREG_ATTROUT, /* Attribute output register file */
+ SVGA3DREG_TEXCRDOUT, /* Texture coordinate output register file */
+ SVGA3DREG_OUTPUT = 6, /* Output register file for VS 3.0+ */
+ SVGA3DREG_CONSTINT, /* Constant integer vector register file */
+ SVGA3DREG_COLOROUT, /* Color output register file */
+ SVGA3DREG_DEPTHOUT, /* Depth output register file */
+ SVGA3DREG_SAMPLER, /* Sampler state register file */
+ SVGA3DREG_CONST2, /* Constant register file 2048 - 4095 */
+ SVGA3DREG_CONST3, /* Constant register file 4096 - 6143 */
+ SVGA3DREG_CONST4, /* Constant register file 6144 - 8191 */
+ SVGA3DREG_CONSTBOOL, /* Constant boolean register file */
+ SVGA3DREG_LOOP, /* Loop counter register file */
+ SVGA3DREG_TEMPFLOAT16, /* 16-bit float temp register file */
+ SVGA3DREG_MISCTYPE, /* Miscellaneous (single) registers */
+ SVGA3DREG_LABEL, /* Label */
+ SVGA3DREG_PREDICATE, /* Predicate register */
+} SVGA3dShaderRegType;
+
+/* SVGA3D rasterizer output register types */
+
+typedef enum {
+ SVGA3DRASTOUT_POSITION = 0,
+ SVGA3DRASTOUT_FOG,
+ SVGA3DRASTOUT_PSIZE
+} SVGA3dShaderRastOutRegType;
+
+/* SVGA3D miscellaneous register types */
+
+typedef enum {
+ SVGA3DMISCREG_POSITION = 0, /* Input position x,y,z,rhw (PS) */
+ SVGA3DMISCREG_FACE /* Floating point primitive area (PS) */
+} SVGA3DShaderMiscRegType;
+
+/* SVGA3D sampler types */
+
+typedef enum {
+ SVGA3DSAMP_UNKNOWN = 0, /* Uninitialized value */
+ SVGA3DSAMP_2D = 2, /* dcl_2d s# (for declaring a 2-D texture) */
+ SVGA3DSAMP_CUBE, /* dcl_cube s# (for declaring a cube texture) */
+ SVGA3DSAMP_VOLUME, /* dcl_volume s# (for declaring a volume texture) */
+} SVGA3dShaderSamplerType;
+
+/* SVGA3D sampler format classes */
+
+typedef enum {
+ SVGA3DSAMPFORMAT_ARGB, /* ARGB formats */
+ SVGA3DSAMPFORMAT_V8U8, /* Sign and normalize (SNORM) V & U */
+ SVGA3DSAMPFORMAT_Q8W8V8U8, /* SNORM all */
+ SVGA3DSAMPFORMAT_CxV8U8, /* SNORM V & U, C=SQRT(1-U^2-V^2) */
+ SVGA3DSAMPFORMAT_X8L8V8U8, /* SNORM V & U */
+ SVGA3DSAMPFORMAT_A2W10V10U10, /* SNORM W, V & U */
+ SVGA3DSAMPFORMAT_DXT_PMA, /* DXT pre-multiplied alpha */
+ SVGA3DSAMPFORMAT_YUV, /* YUV video format */
+ SVGA3DSAMPFORMAT_UYVY, /* UYVY video format */
+ SVGA3DSAMPFORMAT_Rx, /* R16F/32F */
+ SVGA3DSAMPFORMAT_RxGx, /* R16FG16F, R32FG32F */
+ SVGA3DSAMPFORMAT_V16U16, /* SNORM all */
+} SVGA3DShaderSamplerFormatClass;
+
+/* SVGA3D write mask */
+
+#define SVGA3DWRITEMASK_0 1 /* Component 0 (X;Red) */
+#define SVGA3DWRITEMASK_1 2 /* Component 1 (Y;Green) */
+#define SVGA3DWRITEMASK_2 4 /* Component 2 (Z;Blue) */
+#define SVGA3DWRITEMASK_3 8 /* Component 3 (W;Alpha) */
+#define SVGA3DWRITEMASK_ALL 15 /* All components */
+
+/* SVGA3D destination modifiers */
+
+#define SVGA3DDSTMOD_NONE 0 /* nop */
+#define SVGA3DDSTMOD_SATURATE 1 /* clamp to [0, 1] */
+#define SVGA3DDSTMOD_PARTIALPRECISION 2 /* Partial precision hint */
+
+/*
+ * Relevant to multisampling only:
+ * When the pixel center is not covered, sample
+ * attribute or compute gradients/LOD
+ * using multisample "centroid" location.
+ * "Centroid" is some location within the covered
+ * region of the pixel.
+ */
+
+#define SVGA3DDSTMOD_MSAMPCENTROID 4
+
+/* SVGA3D source swizzle */
+
+#define SVGA3DSWIZZLE_REPLICATEX 0x00
+#define SVGA3DSWIZZLE_REPLICATEY 0x55
+#define SVGA3DSWIZZLE_REPLICATEZ 0xAA
+#define SVGA3DSWIZZLE_REPLICATEW 0xFF
+#define SVGA3DSWIZZLE_NONE 0xE4
+#define SVGA3DSWIZZLE_YZXW 0xC9
+#define SVGA3DSWIZZLE_ZXYW 0xD2
+#define SVGA3DSWIZZLE_WXYZ 0x1B
+
+/* SVGA3D source modifiers */
+
+typedef enum {
+ SVGA3DSRCMOD_NONE = 0, /* nop */
+ SVGA3DSRCMOD_NEG, /* negate */
+ SVGA3DSRCMOD_BIAS, /* bias */
+ SVGA3DSRCMOD_BIASNEG, /* bias and negate */
+ SVGA3DSRCMOD_SIGN, /* sign */
+ SVGA3DSRCMOD_SIGNNEG, /* sign and negate */
+ SVGA3DSRCMOD_COMP, /* complement */
+ SVGA3DSRCMOD_X2, /* x2 */
+ SVGA3DSRCMOD_X2NEG, /* x2 and negate */
+ SVGA3DSRCMOD_DZ, /* divide through by z component */
+ SVGA3DSRCMOD_DW, /* divide through by w component */
+ SVGA3DSRCMOD_ABS, /* abs() */
+ SVGA3DSRCMOD_ABSNEG, /* -abs() */
+ SVGA3DSRCMOD_NOT, /* ! (for predicate register) */
+} SVGA3dShaderSrcModType;
+
+/* SVGA3D instruction token */
+
+typedef struct {
+ union {
+ struct {
+ uint32 comment_op : 16;
+ uint32 comment_size : 16;
+ };
+
+ struct {
+ uint32 op : 16;
+ uint32 control : 3;
+ uint32 reserved2 : 5;
+ uint32 size : 4;
+ uint32 predicated : 1;
+ uint32 reserved1 : 1;
+ uint32 coissue : 1;
+ uint32 reserved0 : 1;
+ };
+
+ uint32 value;
+ };
+} SVGA3dShaderInstToken;
+
+/* SVGA3D destination parameter token */
+
+typedef struct {
+ union {
+ struct {
+ uint32 num : 11;
+ uint32 type_upper : 2;
+ uint32 relAddr : 1;
+ uint32 reserved1 : 2;
+ uint32 mask : 4;
+ uint32 dstMod : 4;
+ uint32 shfScale : 4;
+ uint32 type_lower : 3;
+ uint32 reserved0 : 1;
+ };
+
+ uint32 value;
+ };
+} SVGA3dShaderDestToken;
+
+/* SVGA3D source parameter token */
+
+typedef struct {
+ union {
+ struct {
+ uint32 num : 11;
+ uint32 type_upper : 2;
+ uint32 relAddr : 1;
+ uint32 reserved1 : 2;
+ uint32 swizzle : 8;
+ uint32 srcMod : 4;
+ uint32 type_lower : 3;
+ uint32 reserved0 : 1;
+ };
+
+ uint32 value;
+ };
+} SVGA3dShaderSrcToken;
+
+/* SVGA3DOP_DCL parameter tokens */
+
+typedef struct {
+ union {
+ struct {
+ union {
+ struct {
+ uint32 usage : 5;
+ uint32 reserved1 : 11;
+ uint32 index : 4;
+ uint32 reserved0 : 12;
+ }; /* input / output declaration */
+
+ struct {
+ uint32 reserved3 : 27;
+ uint32 type : 4;
+ uint32 reserved2 : 1;
+ }; /* sampler declaration */
+ };
+
+ SVGA3dShaderDestToken dst;
+ };
+
+ uint32 values[2];
+ };
+} SVGA3DOpDclArgs;
+
+/* SVGA3DOP_DEF parameter tokens */
+
+typedef struct {
+ union {
+ struct {
+ SVGA3dShaderDestToken dst;
+
+ union {
+ float constValues[4];
+ int constIValues[4];
+ Bool constBValue;
+ };
+ };
+
+ uint32 values[5];
+ };
+} SVGA3DOpDefArgs;
+
+/* SVGA3D shader token */
+
+typedef union {
+ uint32 value;
+ SVGA3dShaderInstToken inst;
+ SVGA3dShaderDestToken dest;
+ SVGA3dShaderSrcToken src;
+} SVGA3dShaderToken;
+
+/* SVGA3D shader program */
+
+typedef struct {
+ SVGA3dShaderVersion version;
+ /* SVGA3dShaderToken stream */
+} SVGA3dShaderProgram;
+
+/* SVGA3D version specific register assignments */
+
+static const uint32 SVGA3D_INPUT_REG_POSITION_VS11 = 0;
+static const uint32 SVGA3D_INPUT_REG_PSIZE_VS11 = 1;
+static const uint32 SVGA3D_INPUT_REG_FOG_VS11 = 3;
+static const uint32 SVGA3D_INPUT_REG_FOG_MASK_VS11 = SVGA3DWRITEMASK_3;
+static const uint32 SVGA3D_INPUT_REG_COLOR_BASE_VS11 = 2;
+static const uint32 SVGA3D_INPUT_REG_TEXCOORD_BASE_VS11 = 4;
+
+static const uint32 SVGA3D_INPUT_REG_COLOR_BASE_PS11 = 0;
+static const uint32 SVGA3D_INPUT_REG_TEXCOORD_BASE_PS11 = 2;
+static const uint32 SVGA3D_OUTPUT_REG_DEPTH_PS11 = 0;
+static const uint32 SVGA3D_OUTPUT_REG_COLOR_PS11 = 1;
+
+static const uint32 SVGA3D_INPUT_REG_COLOR_BASE_PS20 = 0;
+static const uint32 SVGA3D_INPUT_REG_COLOR_NUM_PS20 = 2;
+static const uint32 SVGA3D_INPUT_REG_TEXCOORD_BASE_PS20 = 2;
+static const uint32 SVGA3D_INPUT_REG_TEXCOORD_NUM_PS20 = 8;
+static const uint32 SVGA3D_OUTPUT_REG_COLOR_BASE_PS20 = 1;
+static const uint32 SVGA3D_OUTPUT_REG_COLOR_NUM_PS20 = 4;
+static const uint32 SVGA3D_OUTPUT_REG_DEPTH_BASE_PS20 = 0;
+static const uint32 SVGA3D_OUTPUT_REG_DEPTH_NUM_PS20 = 1;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3dShaderGetRegType --
+ *
+ * As the register type is split into two non sequential fields,
+ * this function provides an useful way of accessing the actual
+ * register type without having to manually concatenate the
+ * type_upper and type_lower fields.
+ *
+ * Results:
+ * Returns the register type.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE SVGA3dShaderRegType
+SVGA3dShaderGetRegType(uint32 token)
+{
+ SVGA3dShaderSrcToken src;
+ src.value = token;
+ return (SVGA3dShaderRegType)(src.type_upper << 3 | src.type_lower);
+}
+
+#endif /* __SVGA3D_SHADER_DEFS__ */
diff --git a/src/gallium/drivers/svga/include/svga_reg.h b/src/gallium/drivers/svga/include/svga_reg.h
new file mode 100644
index 0000000000..1b96c2ec07
--- /dev/null
+++ b/src/gallium/drivers/svga/include/svga_reg.h
@@ -0,0 +1,1346 @@
+/**********************************************************
+ * 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.
+ *
+ **********************************************************/
+
+/*
+ * svga_reg.h --
+ *
+ * Virtual hardware definitions for the VMware SVGA II device.
+ */
+
+#ifndef _SVGA_REG_H_
+#define _SVGA_REG_H_
+
+/*
+ * PCI device IDs.
+ */
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+
+/*
+ * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
+ * cursor bypass mode. This is still supported, but no new guest
+ * drivers should use it.
+ */
+#define SVGA_CURSOR_ON_HIDE 0x0 /* Must be 0 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_SHOW 0x1 /* Must be 1 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 /* Remove the cursor from the framebuffer because we need to see what's under it */
+#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* Put the cursor back in the framebuffer so the user can see it */
+
+/*
+ * The maximum framebuffer size that can traced for e.g. guests in VESA mode.
+ * The changeMap in the monitor is proportional to this number. Therefore, we'd
+ * like to keep it as small as possible to reduce monitor overhead (using
+ * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area by over
+ * 4k!).
+ *
+ * NB: For compatibility reasons, this value must be greater than 0xff0000.
+ * See bug 335072.
+ */
+#define SVGA_FB_MAX_TRACEABLE_SIZE 0x1000000
+
+#define SVGA_MAX_PSEUDOCOLOR_DEPTH 8
+#define SVGA_MAX_PSEUDOCOLORS (1 << SVGA_MAX_PSEUDOCOLOR_DEPTH)
+#define SVGA_NUM_PALETTE_REGS (3 * SVGA_MAX_PSEUDOCOLORS)
+
+#define SVGA_MAGIC 0x900000UL
+#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver))
+
+/* Version 2 let the address of the frame buffer be unsigned on Win32 */
+#define SVGA_VERSION_2 2
+#define SVGA_ID_2 SVGA_MAKE_ID(SVGA_VERSION_2)
+
+/* Version 1 has new registers starting with SVGA_REG_CAPABILITIES so
+ PALETTE_BASE has moved */
+#define SVGA_VERSION_1 1
+#define SVGA_ID_1 SVGA_MAKE_ID(SVGA_VERSION_1)
+
+/* Version 0 is the initial version */
+#define SVGA_VERSION_0 0
+#define SVGA_ID_0 SVGA_MAKE_ID(SVGA_VERSION_0)
+
+/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */
+#define SVGA_ID_INVALID 0xFFFFFFFF
+
+/* Port offsets, relative to BAR0 */
+#define SVGA_INDEX_PORT 0x0
+#define SVGA_VALUE_PORT 0x1
+#define SVGA_BIOS_PORT 0x2
+#define SVGA_IRQSTATUS_PORT 0x8
+
+/*
+ * Interrupt source flags for IRQSTATUS_PORT and IRQMASK.
+ *
+ * Interrupts are only supported when the
+ * SVGA_CAP_IRQMASK capability is present.
+ */
+#define SVGA_IRQFLAG_ANY_FENCE 0x1 /* Any fence was passed */
+#define SVGA_IRQFLAG_FIFO_PROGRESS 0x2 /* Made forward progress in the FIFO */
+#define SVGA_IRQFLAG_FENCE_GOAL 0x4 /* SVGA_FIFO_FENCE_GOAL reached */
+
+/*
+ * Registers
+ */
+
+enum {
+ SVGA_REG_ID = 0,
+ SVGA_REG_ENABLE = 1,
+ SVGA_REG_WIDTH = 2,
+ SVGA_REG_HEIGHT = 3,
+ SVGA_REG_MAX_WIDTH = 4,
+ SVGA_REG_MAX_HEIGHT = 5,
+ SVGA_REG_DEPTH = 6,
+ SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */
+ SVGA_REG_PSEUDOCOLOR = 8,
+ SVGA_REG_RED_MASK = 9,
+ SVGA_REG_GREEN_MASK = 10,
+ SVGA_REG_BLUE_MASK = 11,
+ SVGA_REG_BYTES_PER_LINE = 12,
+ SVGA_REG_FB_START = 13, /* (Deprecated) */
+ SVGA_REG_FB_OFFSET = 14,
+ SVGA_REG_VRAM_SIZE = 15,
+ SVGA_REG_FB_SIZE = 16,
+
+ /* ID 0 implementation only had the above registers, then the palette */
+
+ SVGA_REG_CAPABILITIES = 17,
+ SVGA_REG_MEM_START = 18, /* (Deprecated) */
+ SVGA_REG_MEM_SIZE = 19,
+ SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */
+ SVGA_REG_SYNC = 21, /* See "FIFO Synchronization Registers" */
+ SVGA_REG_BUSY = 22, /* See "FIFO Synchronization Registers" */
+ SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */
+ SVGA_REG_CURSOR_ID = 24, /* (Deprecated) */
+ SVGA_REG_CURSOR_X = 25, /* (Deprecated) */
+ SVGA_REG_CURSOR_Y = 26, /* (Deprecated) */
+ SVGA_REG_CURSOR_ON = 27, /* (Deprecated) */
+ SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* (Deprecated) */
+ SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */
+ SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */
+ SVGA_REG_NUM_DISPLAYS = 31, /* (Deprecated) */
+ SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */
+ SVGA_REG_IRQMASK = 33, /* Interrupt mask */
+
+ /* Legacy multi-monitor support */
+ SVGA_REG_NUM_GUEST_DISPLAYS = 34,/* Number of guest displays in X/Y direction */
+ SVGA_REG_DISPLAY_ID = 35, /* Display ID for the following display attributes */
+ SVGA_REG_DISPLAY_IS_PRIMARY = 36,/* Whether this is a primary display */
+ SVGA_REG_DISPLAY_POSITION_X = 37,/* The display position x */
+ SVGA_REG_DISPLAY_POSITION_Y = 38,/* The display position y */
+ SVGA_REG_DISPLAY_WIDTH = 39, /* The display's width */
+ SVGA_REG_DISPLAY_HEIGHT = 40, /* The display's height */
+
+ /* See "Guest memory regions" below. */
+ SVGA_REG_GMR_ID = 41,
+ SVGA_REG_GMR_DESCRIPTOR = 42,
+ SVGA_REG_GMR_MAX_IDS = 43,
+ SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
+
+ SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
+ SVGA_REG_TOP = 46, /* Must be 1 more than the last register */
+
+ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
+ /* Next 768 (== 256*3) registers exist for colormap */
+
+ SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + SVGA_NUM_PALETTE_REGS
+ /* Base of scratch registers */
+ /* Next reg[SVGA_REG_SCRATCH_SIZE] registers exist for scratch usage:
+ First 4 are reserved for VESA BIOS Extension; any remaining are for
+ the use of the current SVGA driver. */
+};
+
+
+/*
+ * Guest memory regions (GMRs):
+ *
+ * This is a new memory mapping feature available in SVGA devices
+ * which have the SVGA_CAP_GMR bit set. Previously, there were two
+ * fixed memory regions available with which to share data between the
+ * device and the driver: the FIFO ('MEM') and the framebuffer. GMRs
+ * are our name for an extensible way of providing arbitrary DMA
+ * buffers for use between the driver and the SVGA device. They are a
+ * new alternative to framebuffer memory, usable for both 2D and 3D
+ * graphics operations.
+ *
+ * Since GMR mapping must be done synchronously with guest CPU
+ * execution, we use a new pair of SVGA registers:
+ *
+ * SVGA_REG_GMR_ID --
+ *
+ * Read/write.
+ * This register holds the 32-bit ID (a small positive integer)
+ * of a GMR to create, delete, or redefine. Writing this register
+ * has no side-effects.
+ *
+ * SVGA_REG_GMR_DESCRIPTOR --
+ *
+ * Write-only.
+ * Writing this register will create, delete, or redefine the GMR
+ * specified by the above ID register. If this register is zero,
+ * the GMR is deleted. Any pointers into this GMR (including those
+ * currently being processed by FIFO commands) will be
+ * synchronously invalidated.
+ *
+ * If this register is nonzero, it must be the physical page
+ * number (PPN) of a data structure which describes the physical
+ * layout of the memory region this GMR should describe. The
+ * descriptor structure will be read synchronously by the SVGA
+ * device when this register is written. The descriptor need not
+ * remain allocated for the lifetime of the GMR.
+ *
+ * The guest driver should write SVGA_REG_GMR_ID first, then
+ * SVGA_REG_GMR_DESCRIPTOR.
+ *
+ * SVGA_REG_GMR_MAX_IDS --
+ *
+ * Read-only.
+ * The SVGA device may choose to support a maximum number of
+ * user-defined GMR IDs. This register holds the number of supported
+ * IDs. (The maximum supported ID plus 1)
+ *
+ * SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH --
+ *
+ * Read-only.
+ * The SVGA device may choose to put a limit on the total number
+ * of SVGAGuestMemDescriptor structures it will read when defining
+ * a single GMR.
+ *
+ * The descriptor structure is an array of SVGAGuestMemDescriptor
+ * structures. Each structure may do one of three things:
+ *
+ * - Terminate the GMR descriptor list.
+ * (ppn==0, numPages==0)
+ *
+ * - Add a PPN or range of PPNs to the GMR's virtual address space.
+ * (ppn != 0, numPages != 0)
+ *
+ * - Provide the PPN of the next SVGAGuestMemDescriptor, in order to
+ * support multi-page GMR descriptor tables without forcing the
+ * driver to allocate physically contiguous memory.
+ * (ppn != 0, numPages == 0)
+ *
+ * Note that each physical page of SVGAGuestMemDescriptor structures
+ * can describe at least 2MB of guest memory. If the driver needs to
+ * use more than one page of descriptor structures, it must use one of
+ * its SVGAGuestMemDescriptors to point to an additional page. The
+ * device will never automatically cross a page boundary.
+ *
+ * Once the driver has described a GMR, it is immediately available
+ * for use via any FIFO command that uses an SVGAGuestPtr structure.
+ * These pointers include a GMR identifier plus an offset into that
+ * GMR.
+ *
+ * The driver must check the SVGA_CAP_GMR bit before using the GMR
+ * registers.
+ */
+
+/*
+ * Special GMR IDs, allowing SVGAGuestPtrs to point to framebuffer
+ * memory as well. In the future, these IDs could even be used to
+ * allow legacy memory regions to be redefined by the guest as GMRs.
+ *
+ * Using the guest framebuffer (GFB) at BAR1 for general purpose DMA
+ * is being phased out. Please try to use user-defined GMRs whenever
+ * possible.
+ */
+#define SVGA_GMR_NULL ((uint32) -1)
+#define SVGA_GMR_FRAMEBUFFER ((uint32) -2) // Guest Framebuffer (GFB)
+
+typedef
+struct SVGAGuestMemDescriptor {
+ uint32 ppn;
+ uint32 numPages;
+} SVGAGuestMemDescriptor;
+
+typedef
+struct SVGAGuestPtr {
+ uint32 gmrId;
+ uint32 offset;
+} SVGAGuestPtr;
+
+
+/*
+ * SVGAGMRImageFormat --
+ *
+ * This is a packed representation of the source 2D image format
+ * for a GMR-to-screen blit. Currently it is defined as an encoding
+ * of the screen's color depth and bits-per-pixel, however, 16 bits
+ * are reserved for future use to identify other encodings (such as
+ * RGBA or higher-precision images).
+ *
+ * Currently supported formats:
+ *
+ * bpp depth Format Name
+ * --- ----- -----------
+ * 32 24 32-bit BGRX
+ * 24 24 24-bit BGR
+ * 16 16 RGB 5-6-5
+ * 16 15 RGB 5-5-5
+ *
+ */
+
+typedef
+struct SVGAGMRImageFormat {
+ union {
+ struct {
+ uint32 bitsPerPixel : 8;
+ uint32 colorDepth : 8;
+ uint32 reserved : 16; // Must be zero
+ };
+
+ uint32 value;
+ };
+} SVGAGMRImageFormat;
+
+/*
+ * SVGAColorBGRX --
+ *
+ * A 24-bit color format (BGRX), which does not depend on the
+ * format of the legacy guest framebuffer (GFB) or the current
+ * GMRFB state.
+ */
+
+typedef
+struct SVGAColorBGRX {
+ union {
+ struct {
+ uint32 b : 8;
+ uint32 g : 8;
+ uint32 r : 8;
+ uint32 x : 8; // Unused
+ };
+
+ uint32 value;
+ };
+} SVGAColorBGRX;
+
+
+/*
+ * SVGASignedRect --
+ * SVGASignedPoint --
+ *
+ * Signed rectangle and point primitives. These are used by the new
+ * 2D primitives for drawing to Screen Objects, which can occupy a
+ * signed virtual coordinate space.
+ *
+ * SVGASignedRect specifies a half-open interval: the (left, top)
+ * pixel is part of the rectangle, but the (right, bottom) pixel is
+ * not.
+ */
+
+typedef
+struct SVGASignedRect {
+ int32 left;
+ int32 top;
+ int32 right;
+ int32 bottom;
+} SVGASignedRect;
+
+typedef
+struct SVGASignedPoint {
+ int32 x;
+ int32 y;
+} SVGASignedPoint;
+
+
+/*
+ * Capabilities
+ *
+ * Note the holes in the bitfield. Missing bits have been deprecated,
+ * and must not be reused. Those capabilities will never be reported
+ * by new versions of the SVGA device.
+ */
+
+#define SVGA_CAP_NONE 0x00000000
+#define SVGA_CAP_RECT_COPY 0x00000002
+#define SVGA_CAP_CURSOR 0x00000020
+#define SVGA_CAP_CURSOR_BYPASS 0x00000040 // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_CURSOR_BYPASS_2 0x00000080 // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_8BIT_EMULATION 0x00000100
+#define SVGA_CAP_ALPHA_CURSOR 0x00000200
+#define SVGA_CAP_3D 0x00004000
+#define SVGA_CAP_EXTENDED_FIFO 0x00008000
+#define SVGA_CAP_MULTIMON 0x00010000 // Legacy multi-monitor support
+#define SVGA_CAP_PITCHLOCK 0x00020000
+#define SVGA_CAP_IRQMASK 0x00040000
+#define SVGA_CAP_DISPLAY_TOPOLOGY 0x00080000 // Legacy multi-monitor support
+#define SVGA_CAP_GMR 0x00100000
+#define SVGA_CAP_TRACES 0x00200000
+
+
+/*
+ * FIFO register indices.
+ *
+ * The FIFO is a chunk of device memory mapped into guest physmem. It
+ * is always treated as 32-bit words.
+ *
+ * The guest driver gets to decide how to partition it between
+ * - FIFO registers (there are always at least 4, specifying where the
+ * following data area is and how much data it contains; there may be
+ * more registers following these, depending on the FIFO protocol
+ * version in use)
+ * - FIFO data, written by the guest and slurped out by the VMX.
+ * These indices are 32-bit word offsets into the FIFO.
+ */
+
+enum {
+ /*
+ * Block 1 (basic registers): The originally defined FIFO registers.
+ * These exist and are valid for all versions of the FIFO protocol.
+ */
+
+ SVGA_FIFO_MIN = 0,
+ SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */
+ SVGA_FIFO_NEXT_CMD,
+ SVGA_FIFO_STOP,
+
+ /*
+ * Block 2 (extended registers): Mandatory registers for the extended
+ * FIFO. These exist if the SVGA caps register includes
+ * SVGA_CAP_EXTENDED_FIFO; some of them are valid only if their
+ * associated capability bit is enabled.
+ *
+ * Note that when originally defined, SVGA_CAP_EXTENDED_FIFO implied
+ * support only for (FIFO registers) CAPABILITIES, FLAGS, and FENCE.
+ * This means that the guest has to test individually (in most cases
+ * using FIFO caps) for the presence of registers after this; the VMX
+ * can define "extended FIFO" to mean whatever it wants, and currently
+ * won't enable it unless there's room for that set and much more.
+ */
+
+ SVGA_FIFO_CAPABILITIES = 4,
+ SVGA_FIFO_FLAGS,
+ // Valid with SVGA_FIFO_CAP_FENCE:
+ SVGA_FIFO_FENCE,
+
+ /*
+ * Block 3a (optional extended registers): Additional registers for the
+ * extended FIFO, whose presence isn't actually implied by
+ * SVGA_CAP_EXTENDED_FIFO; these exist if SVGA_FIFO_MIN is high enough to
+ * leave room for them.
+ *
+ * These in block 3a, the VMX currently considers mandatory for the
+ * extended FIFO.
+ */
+
+ // Valid if exists (i.e. if extended FIFO enabled):
+ SVGA_FIFO_3D_HWVERSION, /* See SVGA3dHardwareVersion in svga3d_reg.h */
+ // Valid with SVGA_FIFO_CAP_PITCHLOCK:
+ SVGA_FIFO_PITCHLOCK,
+
+ // Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3:
+ SVGA_FIFO_CURSOR_ON, /* Cursor bypass 3 show/hide register */
+ SVGA_FIFO_CURSOR_X, /* Cursor bypass 3 x register */
+ SVGA_FIFO_CURSOR_Y, /* Cursor bypass 3 y register */
+ SVGA_FIFO_CURSOR_COUNT, /* Incremented when any of the other 3 change */
+ SVGA_FIFO_CURSOR_LAST_UPDATED,/* Last time the host updated the cursor */
+
+ // Valid with SVGA_FIFO_CAP_RESERVE:
+ SVGA_FIFO_RESERVED, /* Bytes past NEXT_CMD with real contents */
+
+ /*
+ * Valid with SVGA_FIFO_CAP_SCREEN_OBJECT:
+ *
+ * By default this is SVGA_ID_INVALID, to indicate that the cursor
+ * coordinates are specified relative to the virtual root. If this
+ * is set to a specific screen ID, cursor position is reinterpreted
+ * as a signed offset relative to that screen's origin. This is the
+ * only way to place the cursor on a non-rooted screen.
+ */
+ SVGA_FIFO_CURSOR_SCREEN_ID,
+
+ /*
+ * XXX: The gap here, up until SVGA_FIFO_3D_CAPS, can be used for new
+ * registers, but this must be done carefully and with judicious use of
+ * capability bits, since comparisons based on SVGA_FIFO_MIN aren't
+ * enough to tell you whether the register exists: we've shipped drivers
+ * and products that used SVGA_FIFO_3D_CAPS but didn't know about some of
+ * the earlier ones. The actual order of introduction was:
+ * - PITCHLOCK
+ * - 3D_CAPS
+ * - CURSOR_* (cursor bypass 3)
+ * - RESERVED
+ * So, code that wants to know whether it can use any of the
+ * aforementioned registers, or anything else added after PITCHLOCK and
+ * before 3D_CAPS, needs to reason about something other than
+ * SVGA_FIFO_MIN.
+ */
+
+ /*
+ * 3D caps block space; valid with 3D hardware version >=
+ * SVGA3D_HWVERSION_WS6_B1.
+ */
+ SVGA_FIFO_3D_CAPS = 32,
+ SVGA_FIFO_3D_CAPS_LAST = 32 + 255,
+
+ /*
+ * End of VMX's current definition of "extended-FIFO registers".
+ * Registers before here are always enabled/disabled as a block; either
+ * the extended FIFO is enabled and includes all preceding registers, or
+ * it's disabled entirely.
+ *
+ * Block 3b (truly optional extended registers): Additional registers for
+ * the extended FIFO, which the VMX already knows how to enable and
+ * disable with correct granularity.
+ *
+ * Registers after here exist if and only if the guest SVGA driver
+ * sets SVGA_FIFO_MIN high enough to leave room for them.
+ */
+
+ // Valid if register exists:
+ SVGA_FIFO_GUEST_3D_HWVERSION, /* Guest driver's 3D version */
+ SVGA_FIFO_FENCE_GOAL, /* Matching target for SVGA_IRQFLAG_FENCE_GOAL */
+ SVGA_FIFO_BUSY, /* See "FIFO Synchronization Registers" */
+
+ /*
+ * Always keep this last. This defines the maximum number of
+ * registers we know about. At power-on, this value is placed in
+ * the SVGA_REG_MEM_REGS register, and we expect the guest driver
+ * to allocate this much space in FIFO memory for registers.
+ */
+ SVGA_FIFO_NUM_REGS
+};
+
+
+/*
+ * Definition of registers included in extended FIFO support.
+ *
+ * The guest SVGA driver gets to allocate the FIFO between registers
+ * and data. It must always allocate at least 4 registers, but old
+ * drivers stopped there.
+ *
+ * The VMX will enable extended FIFO support if and only if the guest
+ * left enough room for all registers defined as part of the mandatory
+ * set for the extended FIFO.
+ *
+ * Note that the guest drivers typically allocate the FIFO only at
+ * initialization time, not at mode switches, so it's likely that the
+ * number of FIFO registers won't change without a reboot.
+ *
+ * All registers less than this value are guaranteed to be present if
+ * svgaUser->fifo.extended is set. Any later registers must be tested
+ * individually for compatibility at each use (in the VMX).
+ *
+ * This value is used only by the VMX, so it can change without
+ * affecting driver compatibility; keep it that way?
+ */
+#define SVGA_FIFO_EXTENDED_MANDATORY_REGS (SVGA_FIFO_3D_CAPS_LAST + 1)
+
+
+/*
+ * FIFO Synchronization Registers
+ *
+ * This explains the relationship between the various FIFO
+ * sync-related registers in IOSpace and in FIFO space.
+ *
+ * SVGA_REG_SYNC --
+ *
+ * The SYNC register can be used in two different ways by the guest:
+ *
+ * 1. If the guest wishes to fully sync (drain) the FIFO,
+ * it will write once to SYNC then poll on the BUSY
+ * register. The FIFO is sync'ed once BUSY is zero.
+ *
+ * 2. If the guest wants to asynchronously wake up the host,
+ * it will write once to SYNC without polling on BUSY.
+ * Ideally it will do this after some new commands have
+ * been placed in the FIFO, and after reading a zero
+ * from SVGA_FIFO_BUSY.
+ *
+ * (1) is the original behaviour that SYNC was designed to
+ * support. Originally, a write to SYNC would implicitly
+ * trigger a read from BUSY. This causes us to synchronously
+ * process the FIFO.
+ *
+ * This behaviour has since been changed so that writing SYNC
+ * will *not* implicitly cause a read from BUSY. Instead, it
+ * makes a channel call which asynchronously wakes up the MKS
+ * thread.
+ *
+ * New guests can use this new behaviour to implement (2)
+ * efficiently. This lets guests get the host's attention
+ * without waiting for the MKS to poll, which gives us much
+ * better CPU utilization on SMP hosts and on UP hosts while
+ * we're blocked on the host GPU.
+ *
+ * Old guests shouldn't notice the behaviour change. SYNC was
+ * never guaranteed to process the entire FIFO, since it was
+ * bounded to a particular number of CPU cycles. Old guests will
+ * still loop on the BUSY register until the FIFO is empty.
+ *
+ * Writing to SYNC currently has the following side-effects:
+ *
+ * - Sets SVGA_REG_BUSY to TRUE (in the monitor)
+ * - Asynchronously wakes up the MKS thread for FIFO processing
+ * - The value written to SYNC is recorded as a "reason", for
+ * stats purposes.
+ *
+ * If SVGA_FIFO_BUSY is available, drivers are advised to only
+ * write to SYNC if SVGA_FIFO_BUSY is FALSE. Drivers should set
+ * SVGA_FIFO_BUSY to TRUE after writing to SYNC. The MKS will
+ * eventually set SVGA_FIFO_BUSY on its own, but this approach
+ * lets the driver avoid sending multiple asynchronous wakeup
+ * messages to the MKS thread.
+ *
+ * SVGA_REG_BUSY --
+ *
+ * This register is set to TRUE when SVGA_REG_SYNC is written,
+ * and it reads as FALSE when the FIFO has been completely
+ * drained.
+ *
+ * Every read from this register causes us to synchronously
+ * process FIFO commands. There is no guarantee as to how many
+ * commands each read will process.
+ *
+ * CPU time spent processing FIFO commands will be billed to
+ * the guest.
+ *
+ * New drivers should avoid using this register unless they
+ * need to guarantee that the FIFO is completely drained. It
+ * is overkill for performing a sync-to-fence. Older drivers
+ * will use this register for any type of synchronization.
+ *
+ * SVGA_FIFO_BUSY --
+ *
+ * This register is a fast way for the guest driver to check
+ * whether the FIFO is already being processed. It reads and
+ * writes at normal RAM speeds, with no monitor intervention.
+ *
+ * If this register reads as TRUE, the host is guaranteeing that
+ * any new commands written into the FIFO will be noticed before
+ * the MKS goes back to sleep.
+ *
+ * If this register reads as FALSE, no such guarantee can be
+ * made.
+ *
+ * The guest should use this register to quickly determine
+ * whether or not it needs to wake up the host. If the guest
+ * just wrote a command or group of commands that it would like
+ * the host to begin processing, it should:
+ *
+ * 1. Read SVGA_FIFO_BUSY. If it reads as TRUE, no further
+ * action is necessary.
+ *
+ * 2. Write TRUE to SVGA_FIFO_BUSY. This informs future guest
+ * code that we've already sent a SYNC to the host and we
+ * don't need to send a duplicate.
+ *
+ * 3. Write a reason to SVGA_REG_SYNC. This will send an
+ * asynchronous wakeup to the MKS thread.
+ */
+
+
+/*
+ * FIFO Capabilities
+ *
+ * Fence -- Fence register and command are supported
+ * Accel Front -- Front buffer only commands are supported
+ * Pitch Lock -- Pitch lock register is supported
+ * Video -- SVGA Video overlay units are supported
+ * Escape -- Escape command is supported
+ *
+ * XXX: Add longer descriptions for each capability, including a list
+ * of the new features that each capability provides.
+ *
+ * SVGA_FIFO_CAP_SCREEN_OBJECT --
+ *
+ * Provides dynamic multi-screen rendering, for improved Unity and
+ * multi-monitor modes. With Screen Object, the guest can
+ * dynamically create and destroy 'screens', which can represent
+ * Unity windows or virtual monitors. Screen Object also provides
+ * strong guarantees that DMA operations happen only when
+ * guest-initiated. Screen Object deprecates the BAR1 guest
+ * framebuffer (GFB) and all commands that work only with the GFB.
+ *
+ * New registers:
+ * FIFO_CURSOR_SCREEN_ID, VIDEO_DATA_GMRID, VIDEO_DST_SCREEN_ID
+ *
+ * New 2D commands:
+ * DEFINE_SCREEN, DESTROY_SCREEN, DEFINE_GMRFB, BLIT_GMRFB_TO_SCREEN,
+ * BLIT_SCREEN_TO_GMRFB, ANNOTATION_FILL, ANNOTATION_COPY
+ *
+ * New 3D commands:
+ * BLIT_SURFACE_TO_SCREEN
+ *
+ * New guarantees:
+ *
+ * - The host will not read or write guest memory, including the GFB,
+ * except when explicitly initiated by a DMA command.
+ *
+ * - All DMA, including legacy DMA like UPDATE and PRESENT_READBACK,
+ * is guaranteed to complete before any subsequent FENCEs.
+ *
+ * - All legacy commands which affect a Screen (UPDATE, PRESENT,
+ * PRESENT_READBACK) as well as new Screen blit commands will
+ * all behave consistently as blits, and memory will be read
+ * or written in FIFO order.
+ *
+ * For example, if you PRESENT from one SVGA3D surface to multiple
+ * places on the screen, the data copied will always be from the
+ * SVGA3D surface at the time the PRESENT was issued in the FIFO.
+ * This was not necessarily true on devices without Screen Object.
+ *
+ * This means that on devices that support Screen Object, the
+ * PRESENT_READBACK command should not be necessary unless you
+ * actually want to read back the results of 3D rendering into
+ * system memory. (And for that, the BLIT_SCREEN_TO_GMRFB
+ * command provides a strict superset of functionality.)
+ *
+ * - When a screen is resized, either using Screen Object commands or
+ * legacy multimon registers, its contents are preserved.
+ */
+
+#define SVGA_FIFO_CAP_NONE 0
+#define SVGA_FIFO_CAP_FENCE (1<<0)
+#define SVGA_FIFO_CAP_ACCELFRONT (1<<1)
+#define SVGA_FIFO_CAP_PITCHLOCK (1<<2)
+#define SVGA_FIFO_CAP_VIDEO (1<<3)
+#define SVGA_FIFO_CAP_CURSOR_BYPASS_3 (1<<4)
+#define SVGA_FIFO_CAP_ESCAPE (1<<5)
+#define SVGA_FIFO_CAP_RESERVE (1<<6)
+#define SVGA_FIFO_CAP_SCREEN_OBJECT (1<<7)
+
+
+/*
+ * FIFO Flags
+ *
+ * Accel Front -- Driver should use front buffer only commands
+ */
+
+#define SVGA_FIFO_FLAG_NONE 0
+#define SVGA_FIFO_FLAG_ACCELFRONT (1<<0)
+#define SVGA_FIFO_FLAG_RESERVED (1<<31) // Internal use only
+
+/*
+ * FIFO reservation sentinel value
+ */
+
+#define SVGA_FIFO_RESERVED_UNKNOWN 0xffffffff
+
+
+/*
+ * Video overlay support
+ */
+
+#define SVGA_NUM_OVERLAY_UNITS 32
+
+
+/*
+ * Video capabilities that the guest is currently using
+ */
+
+#define SVGA_VIDEO_FLAG_COLORKEY 0x0001
+
+
+/*
+ * Offsets for the video overlay registers
+ */
+
+enum {
+ SVGA_VIDEO_ENABLED = 0,
+ SVGA_VIDEO_FLAGS,
+ SVGA_VIDEO_DATA_OFFSET,
+ SVGA_VIDEO_FORMAT,
+ SVGA_VIDEO_COLORKEY,
+ SVGA_VIDEO_SIZE, // Deprecated
+ SVGA_VIDEO_WIDTH,
+ SVGA_VIDEO_HEIGHT,
+ SVGA_VIDEO_SRC_X,
+ SVGA_VIDEO_SRC_Y,
+ SVGA_VIDEO_SRC_WIDTH,
+ SVGA_VIDEO_SRC_HEIGHT,
+ SVGA_VIDEO_DST_X, // Signed int32
+ SVGA_VIDEO_DST_Y, // Signed int32
+ SVGA_VIDEO_DST_WIDTH,
+ SVGA_VIDEO_DST_HEIGHT,
+ SVGA_VIDEO_PITCH_1,
+ SVGA_VIDEO_PITCH_2,
+ SVGA_VIDEO_PITCH_3,
+ SVGA_VIDEO_DATA_GMRID, // Optional, defaults to SVGA_GMR_FRAMEBUFFER
+ SVGA_VIDEO_DST_SCREEN_ID, // Optional, defaults to virtual coords (SVGA_ID_INVALID)
+ SVGA_VIDEO_NUM_REGS
+};
+
+
+/*
+ * SVGA Overlay Units
+ *
+ * width and height relate to the entire source video frame.
+ * srcX, srcY, srcWidth and srcHeight represent subset of the source
+ * video frame to be displayed.
+ */
+
+typedef struct SVGAOverlayUnit {
+ uint32 enabled;
+ uint32 flags;
+ uint32 dataOffset;
+ uint32 format;
+ uint32 colorKey;
+ uint32 size;
+ uint32 width;
+ uint32 height;
+ uint32 srcX;
+ uint32 srcY;
+ uint32 srcWidth;
+ uint32 srcHeight;
+ int32 dstX;
+ int32 dstY;
+ uint32 dstWidth;
+ uint32 dstHeight;
+ uint32 pitches[3];
+ uint32 dataGMRId;
+ uint32 dstScreenId;
+} SVGAOverlayUnit;
+
+
+/*
+ * SVGAScreenObject --
+ *
+ * This is a new way to represent a guest's multi-monitor screen or
+ * Unity window. Screen objects are only supported if the
+ * SVGA_FIFO_CAP_SCREEN_OBJECT capability bit is set.
+ *
+ * If Screen Objects are supported, they can be used to fully
+ * replace the functionality provided by the framebuffer registers
+ * (SVGA_REG_WIDTH, HEIGHT, etc.) and by SVGA_CAP_DISPLAY_TOPOLOGY.
+ *
+ * The screen object is a struct with guaranteed binary
+ * compatibility. New flags can be added, and the struct may grow,
+ * but existing fields must retain their meaning.
+ *
+ */
+
+#define SVGA_SCREEN_HAS_ROOT (1 << 0) // Screen is present in the virtual coord space
+#define SVGA_SCREEN_IS_PRIMARY (1 << 1) // Guest considers this screen to be 'primary'
+#define SVGA_SCREEN_FULLSCREEN_HINT (1 << 2) // Guest is running a fullscreen app here
+
+typedef
+struct SVGAScreenObject {
+ uint32 structSize; // sizeof(SVGAScreenObject)
+ uint32 id;
+ uint32 flags;
+ struct {
+ uint32 width;
+ uint32 height;
+ } size;
+ struct {
+ int32 x;
+ int32 y;
+ } root; // Only used if SVGA_SCREEN_HAS_ROOT is set.
+} SVGAScreenObject;
+
+
+/*
+ * Commands in the command FIFO:
+ *
+ * Command IDs defined below are used for the traditional 2D FIFO
+ * communication (not all commands are available for all versions of the
+ * SVGA FIFO protocol).
+ *
+ * Note the holes in the command ID numbers: These commands have been
+ * deprecated, and the old IDs must not be reused.
+ *
+ * Command IDs from 1000 to 1999 are reserved for use by the SVGA3D
+ * protocol.
+ *
+ * Each command's parameters are described by the comments and
+ * structs below.
+ */
+
+typedef enum {
+ SVGA_CMD_INVALID_CMD = 0,
+ SVGA_CMD_UPDATE = 1,
+ SVGA_CMD_RECT_COPY = 3,
+ SVGA_CMD_DEFINE_CURSOR = 19,
+ SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+ SVGA_CMD_UPDATE_VERBOSE = 25,
+ SVGA_CMD_FRONT_ROP_FILL = 29,
+ SVGA_CMD_FENCE = 30,
+ SVGA_CMD_ESCAPE = 33,
+ SVGA_CMD_DEFINE_SCREEN = 34,
+ SVGA_CMD_DESTROY_SCREEN = 35,
+ SVGA_CMD_DEFINE_GMRFB = 36,
+ SVGA_CMD_BLIT_GMRFB_TO_SCREEN = 37,
+ SVGA_CMD_BLIT_SCREEN_TO_GMRFB = 38,
+ SVGA_CMD_ANNOTATION_FILL = 39,
+ SVGA_CMD_ANNOTATION_COPY = 40,
+ SVGA_CMD_MAX
+} SVGAFifoCmdId;
+
+#define SVGA_CMD_MAX_ARGS 64
+
+
+/*
+ * SVGA_CMD_UPDATE --
+ *
+ * This is a DMA transfer which copies from the Guest Framebuffer
+ * (GFB) at BAR1 + SVGA_REG_FB_OFFSET to any screens which
+ * intersect with the provided virtual rectangle.
+ *
+ * This command does not support using arbitrary guest memory as a
+ * data source- it only works with the pre-defined GFB memory.
+ * This command also does not support signed virtual coordinates.
+ * If you have defined screens (using SVGA_CMD_DEFINE_SCREEN) with
+ * negative root x/y coordinates, the negative portion of those
+ * screens will not be reachable by this command.
+ *
+ * This command is not necessary when using framebuffer
+ * traces. Traces are automatically enabled if the SVGA FIFO is
+ * disabled, and you may explicitly enable/disable traces using
+ * SVGA_REG_TRACES. With traces enabled, any write to the GFB will
+ * automatically act as if a subsequent SVGA_CMD_UPDATE was issued.
+ *
+ * Traces and SVGA_CMD_UPDATE are the only supported ways to render
+ * pseudocolor screen updates. The newer Screen Object commands
+ * only support true color formats.
+ *
+ * Availability:
+ * Always available.
+ */
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+} SVGAFifoCmdUpdate;
+
+
+/*
+ * SVGA_CMD_RECT_COPY --
+ *
+ * Perform a rectangular DMA transfer from one area of the GFB to
+ * another, and copy the result to any screens which intersect it.
+ *
+ * Availability:
+ * SVGA_CAP_RECT_COPY
+ */
+
+typedef
+struct {
+ uint32 srcX;
+ uint32 srcY;
+ uint32 destX;
+ uint32 destY;
+ uint32 width;
+ uint32 height;
+} SVGAFifoCmdRectCopy;
+
+
+/*
+ * SVGA_CMD_DEFINE_CURSOR --
+ *
+ * Provide a new cursor image, as an AND/XOR mask.
+ *
+ * The recommended way to position the cursor overlay is by using
+ * the SVGA_FIFO_CURSOR_* registers, supported by the
+ * SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ * SVGA_CAP_CURSOR
+ */
+
+typedef
+struct {
+ uint32 id; // Reserved, must be zero.
+ uint32 hotspotX;
+ uint32 hotspotY;
+ uint32 width;
+ uint32 height;
+ uint32 andMaskDepth; // Value must be 1 or equal to BITS_PER_PIXEL
+ uint32 xorMaskDepth; // Value must be 1 or equal to BITS_PER_PIXEL
+ /*
+ * Followed by scanline data for AND mask, then XOR mask.
+ * Each scanline is padded to a 32-bit boundary.
+ */
+} SVGAFifoCmdDefineCursor;
+
+
+/*
+ * SVGA_CMD_DEFINE_ALPHA_CURSOR --
+ *
+ * Provide a new cursor image, in 32-bit BGRA format.
+ *
+ * The recommended way to position the cursor overlay is by using
+ * the SVGA_FIFO_CURSOR_* registers, supported by the
+ * SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ * SVGA_CAP_ALPHA_CURSOR
+ */
+
+typedef
+struct {
+ uint32 id; // Reserved, must be zero.
+ uint32 hotspotX;
+ uint32 hotspotY;
+ uint32 width;
+ uint32 height;
+ /* Followed by scanline data */
+} SVGAFifoCmdDefineAlphaCursor;
+
+
+/*
+ * SVGA_CMD_UPDATE_VERBOSE --
+ *
+ * Just like SVGA_CMD_UPDATE, but also provide a per-rectangle
+ * 'reason' value, an opaque cookie which is used by internal
+ * debugging tools. Third party drivers should not use this
+ * command.
+ *
+ * Availability:
+ * SVGA_CAP_EXTENDED_FIFO
+ */
+
+typedef
+struct {
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ uint32 reason;
+} SVGAFifoCmdUpdateVerbose;
+
+
+/*
+ * SVGA_CMD_FRONT_ROP_FILL --
+ *
+ * This is a hint which tells the SVGA device that the driver has
+ * just filled a rectangular region of the GFB with a solid
+ * color. Instead of reading these pixels from the GFB, the device
+ * can assume that they all equal 'color'. This is primarily used
+ * for remote desktop protocols.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_ACCELFRONT
+ */
+
+#define SVGA_ROP_COPY 0x03
+
+typedef
+struct {
+ uint32 color; // In the same format as the GFB
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ uint32 rop; // Must be SVGA_ROP_COPY
+} SVGAFifoCmdFrontRopFill;
+
+
+/*
+ * SVGA_CMD_FENCE --
+ *
+ * Insert a synchronization fence. When the SVGA device reaches
+ * this command, it will copy the 'fence' value into the
+ * SVGA_FIFO_FENCE register. It will also compare the fence against
+ * SVGA_FIFO_FENCE_GOAL. If the fence matches the goal and the
+ * SVGA_IRQFLAG_FENCE_GOAL interrupt is enabled, the device will
+ * raise this interrupt.
+ *
+ * Availability:
+ * SVGA_FIFO_FENCE for this command,
+ * SVGA_CAP_IRQMASK for SVGA_FIFO_FENCE_GOAL.
+ */
+
+typedef
+struct {
+ uint32 fence;
+} SVGAFifoCmdFence;
+
+
+/*
+ * SVGA_CMD_ESCAPE --
+ *
+ * Send an extended or vendor-specific variable length command.
+ * This is used for video overlay, third party plugins, and
+ * internal debugging tools. See svga_escape.h
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_ESCAPE
+ */
+
+typedef
+struct {
+ uint32 nsid;
+ uint32 size;
+ /* followed by 'size' bytes of data */
+} SVGAFifoCmdEscape;
+
+
+/*
+ * SVGA_CMD_DEFINE_SCREEN --
+ *
+ * Define or redefine an SVGAScreenObject. See the description of
+ * SVGAScreenObject above. The video driver is responsible for
+ * generating new screen IDs. They should be small positive
+ * integers. The virtual device will have an implementation
+ * specific upper limit on the number of screen IDs
+ * supported. Drivers are responsible for recycling IDs. The first
+ * valid ID is zero.
+ *
+ * - Interaction with other registers:
+ *
+ * For backwards compatibility, when the GFB mode registers (WIDTH,
+ * HEIGHT, PITCHLOCK, BITS_PER_PIXEL) are modified, the SVGA device
+ * deletes all screens other than screen #0, and redefines screen
+ * #0 according to the specified mode. Drivers that use
+ * SVGA_CMD_DEFINE_SCREEN should destroy or redefine screen #0.
+ *
+ * If you use screen objects, do not use the legacy multi-mon
+ * registers (SVGA_REG_NUM_GUEST_DISPLAYS, SVGA_REG_DISPLAY_*).
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGAScreenObject screen; // Variable-length according to version
+} SVGAFifoCmdDefineScreen;
+
+
+/*
+ * SVGA_CMD_DESTROY_SCREEN --
+ *
+ * Destroy an SVGAScreenObject. Its ID is immediately available for
+ * re-use.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ uint32 screenId;
+} SVGAFifoCmdDestroyScreen;
+
+
+/*
+ * SVGA_CMD_DEFINE_GMRFB --
+ *
+ * This command sets a piece of SVGA device state called the
+ * Guest Memory Region Framebuffer, or GMRFB. The GMRFB is a
+ * piece of light-weight state which identifies the location and
+ * format of an image in guest memory or in BAR1. The GMRFB has
+ * an arbitrary size, and it doesn't need to match the geometry
+ * of the GFB or any screen object.
+ *
+ * The GMRFB can be redefined as often as you like. You could
+ * always use the same GMRFB, you could redefine it before
+ * rendering from a different guest screen, or you could even
+ * redefine it before every blit.
+ *
+ * There are multiple ways to use this command. The simplest way is
+ * to use it to move the framebuffer either to elsewhere in the GFB
+ * (BAR1) memory region, or to a user-defined GMR. This lets a
+ * driver use a framebuffer allocated entirely out of normal system
+ * memory, which we encourage.
+ *
+ * Another way to use this command is to set up a ring buffer of
+ * updates in GFB memory. If a driver wants to ensure that no
+ * frames are skipped by the SVGA device, it is important that the
+ * driver not modify the source data for a blit until the device is
+ * done processing the command. One efficient way to accomplish
+ * this is to use a ring of small DMA buffers. Each buffer is used
+ * for one blit, then we move on to the next buffer in the
+ * ring. The FENCE mechanism is used to protect each buffer from
+ * re-use until the device is finished with that buffer's
+ * corresponding blit.
+ *
+ * This command does not affect the meaning of SVGA_CMD_UPDATE.
+ * UPDATEs always occur from the legacy GFB memory area. This
+ * command has no support for pseudocolor GMRFBs. Currently only
+ * true-color 15, 16, and 24-bit depths are supported. Future
+ * devices may expose capabilities for additional framebuffer
+ * formats.
+ *
+ * The default GMRFB value is undefined. Drivers must always send
+ * this command at least once before performing any blit from the
+ * GMRFB.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGAGuestPtr ptr;
+ uint32 bytesPerLine;
+ SVGAGMRImageFormat format;
+} SVGAFifoCmdDefineGMRFB;
+
+
+/*
+ * SVGA_CMD_BLIT_GMRFB_TO_SCREEN --
+ *
+ * This is a guest-to-host blit. It performs a DMA operation to
+ * copy a rectangular region of pixels from the current GMRFB to
+ * one or more Screen Objects.
+ *
+ * The destination coordinate may be specified relative to a
+ * screen's origin (if a screen ID is specified) or relative to the
+ * virtual coordinate system's origin (if the screen ID is
+ * SVGA_ID_INVALID). The actual destination may span zero or more
+ * screens, in the case of a virtual destination rect or a rect
+ * which extends off the edge of the specified screen.
+ *
+ * This command writes to the screen's "base layer": the underlying
+ * framebuffer which exists below any cursor or video overlays. No
+ * action is necessary to explicitly hide or update any overlays
+ * which exist on top of the updated region.
+ *
+ * The SVGA device is guaranteed to finish reading from the GMRFB
+ * by the time any subsequent FENCE commands are reached.
+ *
+ * This command consumes an annotation. See the
+ * SVGA_CMD_ANNOTATION_* commands for details.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGASignedPoint srcOrigin;
+ SVGASignedRect destRect;
+ uint32 destScreenId;
+} SVGAFifoCmdBlitGMRFBToScreen;
+
+
+/*
+ * SVGA_CMD_BLIT_SCREEN_TO_GMRFB --
+ *
+ * This is a host-to-guest blit. It performs a DMA operation to
+ * copy a rectangular region of pixels from a single Screen Object
+ * back to the current GMRFB.
+ *
+ * Usage note: This command should be used rarely. It will
+ * typically be inefficient, but it is necessary for some types of
+ * synchronization between 3D (GPU) and 2D (CPU) rendering into
+ * overlapping areas of a screen.
+ *
+ * The source coordinate is specified relative to a screen's
+ * origin. The provided screen ID must be valid. If any parameters
+ * are invalid, the resulting pixel values are undefined.
+ *
+ * This command reads the screen's "base layer". Overlays like
+ * video and cursor are not included, but any data which was sent
+ * using a blit-to-screen primitive will be available, no matter
+ * whether the data's original source was the GMRFB or the 3D
+ * acceleration hardware.
+ *
+ * Note that our guest-to-host blits and host-to-guest blits aren't
+ * symmetric in their current implementation. While the parameters
+ * are identical, host-to-guest blits are a lot less featureful.
+ * They do not support clipping: If the source parameters don't
+ * fully fit within a screen, the blit fails. They must originate
+ * from exactly one screen. Virtual coordinates are not directly
+ * supported.
+ *
+ * Host-to-guest blits do support the same set of GMRFB formats
+ * offered by guest-to-host blits.
+ *
+ * The SVGA device is guaranteed to finish writing to the GMRFB by
+ * the time any subsequent FENCE commands are reached.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGASignedPoint destOrigin;
+ SVGASignedRect srcRect;
+ uint32 srcScreenId;
+} SVGAFifoCmdBlitScreenToGMRFB;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_FILL --
+ *
+ * This is a blit annotation. This command stores a small piece of
+ * device state which is consumed by the next blit-to-screen
+ * command. The state is only cleared by commands which are
+ * specifically documented as consuming an annotation. Other
+ * commands (such as ESCAPEs for debugging) may intervene between
+ * the annotation and its associated blit.
+ *
+ * This annotation is a promise about the contents of the next
+ * blit: The video driver is guaranteeing that all pixels in that
+ * blit will have the same value, specified here as a color in
+ * SVGAColorBGRX format.
+ *
+ * The SVGA device can still render the blit correctly even if it
+ * ignores this annotation, but the annotation may allow it to
+ * perform the blit more efficiently, for example by ignoring the
+ * source data and performing a fill in hardware.
+ *
+ * This annotation is most important for performance when the
+ * user's display is being remoted over a network connection.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGAColorBGRX color;
+} SVGAFifoCmdAnnotationFill;
+
+
+/*
+ * SVGA_CMD_ANNOTATION_COPY --
+ *
+ * This is a blit annotation. See SVGA_CMD_ANNOTATION_FILL for more
+ * information about annotations.
+ *
+ * This annotation is a promise about the contents of the next
+ * blit: The video driver is guaranteeing that all pixels in that
+ * blit will have the same value as those which already exist at an
+ * identically-sized region on the same or a different screen.
+ *
+ * Note that the source pixels for the COPY in this annotation are
+ * sampled before applying the anqnotation's associated blit. They
+ * are allowed to overlap with the blit's destination pixels.
+ *
+ * The copy source rectangle is specified the same way as the blit
+ * destination: it can be a rectangle which spans zero or more
+ * screens, specified relative to either a screen or to the virtual
+ * coordinate system's origin. If the source rectangle includes
+ * pixels which are not from exactly one screen, the results are
+ * undefined.
+ *
+ * Availability:
+ * SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+ SVGASignedPoint srcOrigin;
+ uint32 srcScreenId;
+} SVGAFifoCmdAnnotationCopy;
+
+#endif
diff --git a/src/gallium/drivers/svga/include/svga_types.h b/src/gallium/drivers/svga/include/svga_types.h
new file mode 100644
index 0000000000..7fd9bab03a
--- /dev/null
+++ b/src/gallium/drivers/svga/include/svga_types.h
@@ -0,0 +1,46 @@
+/**********************************************************
+ * 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.
+ *
+ **********************************************************/
+
+#ifndef _SVGA_TYPES_H_
+#define _SVGA_TYPES_H_
+
+#include "pipe/p_compiler.h"
+
+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;
+
+typedef uint8_t Bool;
+
+#endif /* _SVGA_TYPES_H_ */
+
diff --git a/src/gallium/drivers/svga/svga_cmd.c b/src/gallium/drivers/svga/svga_cmd.c
new file mode 100644
index 0000000000..a0da7d7e5d
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_cmd.c
@@ -0,0 +1,1427 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * svga_cmd.c --
+ *
+ * Command construction utility for the SVGA3D protocol used by
+ * the VMware SVGA device, based on the svgautil library.
+ */
+
+#include "svga_winsys.h"
+#include "svga_screen_buffer.h"
+#include "svga_screen_texture.h"
+#include "svga_cmd.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * surface_to_surfaceid --
+ *
+ * Utility function for surface ids.
+ * Can handle null surface. Does a surface_reallocation so you need
+ * to have allocated the fifo space before converting.
+ *
+ * Results:
+ * id is filld out.
+ *
+ * Side effects:
+ * One surface relocation is preformed for texture handle.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE
+void surface_to_surfaceid(struct svga_winsys_context *swc, // IN
+ struct pipe_surface *surface, // IN
+ SVGA3dSurfaceImageId *id, // OUT
+ unsigned flags) // IN
+{
+ if(surface) {
+ struct svga_surface *s = svga_surface(surface);
+ swc->surface_relocation(swc, &id->sid, s->handle, flags);
+ id->face = s->real_face; /* faces have the same order */
+ id->mipmap = s->real_level;
+ }
+ else {
+ id->sid = SVGA3D_INVALID_ID;
+ id->face = 0;
+ id->mipmap = 0;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_FIFOReserve --
+ *
+ * Reserve space for an SVGA3D FIFO command.
+ *
+ * The 2D SVGA commands have been around for a while, so they
+ * have a rather asymmetric structure. The SVGA3D protocol is
+ * more uniform: each command begins with a header containing the
+ * command number and the full size.
+ *
+ * This is a convenience wrapper around SVGA_FIFOReserve. We
+ * reserve space for the whole command, and write the header.
+ *
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Results:
+ * Returns a pointer to the space reserved for command-specific
+ * data. It must be 'cmdSize' bytes long.
+ *
+ * Side effects:
+ * Begins a FIFO reservation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void *
+SVGA3D_FIFOReserve(struct svga_winsys_context *swc,
+ uint32 cmd, // IN
+ uint32 cmdSize, // IN
+ uint32 nr_relocs) // IN
+{
+ SVGA3dCmdHeader *header;
+
+ header = swc->reserve(swc, sizeof *header + cmdSize, nr_relocs);
+ if(!header)
+ return NULL;
+
+ header->id = cmd;
+ header->size = cmdSize;
+
+ return &header[1];
+}
+
+
+void
+SVGA_FIFOCommitAll(struct svga_winsys_context *swc)
+{
+ swc->commit(swc);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DefineContext --
+ *
+ * Create a new context, to be referred to with the provided ID.
+ *
+ * Context objects encapsulate all render state, and shader
+ * objects are per-context.
+ *
+ * Surfaces are not per-context. The same surface can be shared
+ * between multiple contexts, and surface operations can occur
+ * without a context.
+ *
+ * If the provided context ID already existed, it is redefined.
+ *
+ * Context IDs are arbitrary small non-negative integers,
+ * global to the entire SVGA device.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DefineContext(struct svga_winsys_context *swc) // IN
+{
+ SVGA3dCmdDefineContext *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_CONTEXT_DEFINE, sizeof *cmd, 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroyContext --
+ *
+ * Delete a context created with SVGA3D_DefineContext.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DestroyContext(struct svga_winsys_context *swc) // IN
+{
+ SVGA3dCmdDestroyContext *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_CONTEXT_DESTROY, sizeof *cmd, 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginDefineSurface --
+ *
+ * Begin a SURFACE_DEFINE command. This reserves space for it in
+ * the FIFO, and returns pointers to the command's faces and
+ * mipsizes arrays.
+ *
+ * This function must be paired with SVGA_FIFOCommitAll().
+ * The faces and mipSizes arrays are initialized to zero.
+ *
+ * This creates a "surface" object in the SVGA3D device,
+ * with the provided surface ID (sid). Surfaces are generic
+ * containers for host VRAM objects like textures, vertex
+ * buffers, and depth/stencil buffers.
+ *
+ * Surfaces are hierarchial:
+ *
+ * - Surface may have multiple faces (for cube maps)
+ *
+ * - Each face has a list of mipmap levels
+ *
+ * - Each mipmap image may have multiple volume
+ * slices, if the image is three dimensional.
+ *
+ * - Each slice is a 2D array of 'blocks'
+ *
+ * - Each block may be one or more pixels.
+ * (Usually 1, more for DXT or YUV formats.)
+ *
+ * Surfaces are generic host VRAM objects. The SVGA3D device
+ * may optimize surfaces according to the format they were
+ * created with, but this format does not limit the ways in
+ * which the surface may be used. For example, a depth surface
+ * can be used as a texture, or a floating point image may
+ * be used as a vertex buffer. Some surface usages may be
+ * lower performance, due to software emulation, but any
+ * usage should work with any surface.
+ *
+ * If 'sid' is already defined, the old surface is deleted
+ * and this new surface replaces it.
+ *
+ * Surface IDs are arbitrary small non-negative integers,
+ * global to the entire SVGA device.
+ *
+ * Results:
+ * Returns pointers to arrays allocated in the FIFO for 'faces'
+ * and 'mipSizes'.
+ *
+ * Side effects:
+ * Begins a FIFO reservation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginDefineSurface(struct svga_winsys_context *swc,
+ struct svga_winsys_surface *sid, // IN
+ SVGA3dSurfaceFlags flags, // IN
+ SVGA3dSurfaceFormat format, // IN
+ SVGA3dSurfaceFace **faces, // OUT
+ SVGA3dSize **mipSizes, // OUT
+ uint32 numMipSizes) // IN
+{
+ SVGA3dCmdDefineSurface *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_DEFINE, sizeof *cmd +
+ sizeof **mipSizes * numMipSizes, 1);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ swc->surface_relocation(swc, &cmd->sid, sid, PIPE_BUFFER_USAGE_GPU_WRITE);
+ cmd->surfaceFlags = flags;
+ cmd->format = format;
+
+ *faces = &cmd->face[0];
+ *mipSizes = (SVGA3dSize*) &cmd[1];
+
+ memset(*faces, 0, sizeof **faces * SVGA3D_MAX_SURFACE_FACES);
+ memset(*mipSizes, 0, sizeof **mipSizes * numMipSizes);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DefineSurface2D --
+ *
+ * This is a simplified version of SVGA3D_BeginDefineSurface(),
+ * which does not support cube maps, mipmaps, or volume textures.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DefineSurface2D(struct svga_winsys_context *swc, // IN
+ struct svga_winsys_surface *sid, // IN
+ uint32 width, // IN
+ uint32 height, // IN
+ SVGA3dSurfaceFormat format) // IN
+{
+ SVGA3dSize *mipSizes;
+ SVGA3dSurfaceFace *faces;
+ enum pipe_error ret;
+
+ ret = SVGA3D_BeginDefineSurface(swc,
+ sid, 0, format, &faces, &mipSizes, 1);
+ if(ret != PIPE_OK)
+ return ret;
+
+ faces[0].numMipLevels = 1;
+
+ mipSizes[0].width = width;
+ mipSizes[0].height = height;
+ mipSizes[0].depth = 1;
+
+ swc->commit(swc);;
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroySurface --
+ *
+ * Release the host VRAM encapsulated by a particular surface ID.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DestroySurface(struct svga_winsys_context *swc,
+ struct svga_winsys_surface *sid) // IN
+{
+ SVGA3dCmdDestroySurface *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_DESTROY, sizeof *cmd, 1);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ swc->surface_relocation(swc, &cmd->sid, sid, PIPE_BUFFER_USAGE_GPU_READ);
+ swc->commit(swc);;
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSurfaceDMA--
+ *
+ * Begin a SURFACE_DMA command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's box array.
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * When the SVGA3D device asynchronously processes this FIFO
+ * command, a DMA operation is performed between host VRAM and
+ * a generic SVGAGuestPtr. The guest pointer may refer to guest
+ * VRAM (provided by the SVGA PCI device) or to guest system
+ * memory that has been set up as a Guest Memory Region (GMR)
+ * by the SVGA device.
+ *
+ * The guest's DMA buffer must remain valid (not freed, paged out,
+ * or overwritten) until the host has finished processing this
+ * command. The guest can determine that the host has finished
+ * by using the SVGA device's FIFO Fence mechanism.
+ *
+ * The guest's image buffer can be an arbitrary size and shape.
+ * Guest image data is interpreted according to the SVGA3D surface
+ * format specified when the surface was defined.
+ *
+ * The caller may optionally define the guest image's pitch.
+ * guestImage->pitch can either be zero (assume image is tightly
+ * packed) or it must be the number of bytes between vertically
+ * adjacent image blocks.
+ *
+ * The provided copybox list specifies which regions of the source
+ * image are to be copied, and where they appear on the destination.
+ *
+ * NOTE: srcx/srcy are always on the guest image and x/y are
+ * always on the host image, regardless of the actual 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.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SurfaceDMA(struct svga_winsys_context *swc,
+ struct svga_transfer *st, // IN
+ SVGA3dTransferType transfer, // IN
+ const SVGA3dCopyBox *boxes, // IN
+ uint32 numBoxes) // IN
+{
+ struct svga_texture *texture = svga_texture(st->base.texture);
+ SVGA3dCmdSurfaceDMA *cmd;
+ SVGA3dCmdSurfaceDMASuffix *pSuffix;
+ uint32 boxesSize = sizeof *boxes * numBoxes;
+ unsigned region_flags;
+ unsigned surface_flags;
+
+ if(transfer == SVGA3D_WRITE_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ }
+ else if(transfer == SVGA3D_READ_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ }
+ else {
+ assert(0);
+ return PIPE_ERROR_BAD_INPUT;
+ }
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_DMA,
+ sizeof *cmd + boxesSize + sizeof *pSuffix,
+ 2);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ swc->region_relocation(swc, &cmd->guest.ptr, st->hwbuf, 0, region_flags);
+ cmd->guest.pitch = st->base.stride;
+
+ swc->surface_relocation(swc, &cmd->host.sid, texture->handle, surface_flags);
+ cmd->host.face = st->base.face; /* PIPE_TEX_FACE_* and SVGA3D_CUBEFACE_* match */
+ cmd->host.mipmap = st->base.level;
+
+ cmd->transfer = transfer;
+
+ memcpy(&cmd[1], boxes, boxesSize);
+
+ pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + boxesSize);
+ pSuffix->suffixSize = sizeof *pSuffix;
+ pSuffix->maximumOffset = st->hw_nblocksy*st->base.stride;
+ memset(&pSuffix->flags, 0, sizeof pSuffix->flags);
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+enum pipe_error
+SVGA3D_BufferDMA(struct svga_winsys_context *swc,
+ struct svga_winsys_buffer *guest,
+ struct svga_winsys_surface *host,
+ SVGA3dTransferType transfer, // IN
+ uint32 size, // IN
+ uint32 offset, // IN
+ SVGA3dSurfaceDMAFlags flags) // IN
+{
+ SVGA3dCmdSurfaceDMA *cmd;
+ SVGA3dCopyBox *box;
+ SVGA3dCmdSurfaceDMASuffix *pSuffix;
+ unsigned region_flags;
+ unsigned surface_flags;
+
+ if(transfer == SVGA3D_WRITE_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ }
+ else if(transfer == SVGA3D_READ_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ }
+ else {
+ assert(0);
+ return PIPE_ERROR_BAD_INPUT;
+ }
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_DMA,
+ sizeof *cmd + sizeof *box + sizeof *pSuffix,
+ 2);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ swc->region_relocation(swc, &cmd->guest.ptr, guest, 0, region_flags);
+ cmd->guest.pitch = 0;
+
+ swc->surface_relocation(swc, &cmd->host.sid, host, surface_flags);
+ cmd->host.face = 0;
+ cmd->host.mipmap = 0;
+
+ cmd->transfer = transfer;
+
+ box = (SVGA3dCopyBox *)&cmd[1];
+ box->x = offset;
+ box->y = 0;
+ box->z = 0;
+ box->w = size;
+ box->h = 1;
+ box->d = 1;
+ box->srcx = offset;
+ box->srcy = 0;
+ box->srcz = 0;
+
+ pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + sizeof *box);
+ pSuffix->suffixSize = sizeof *pSuffix;
+ pSuffix->maximumOffset = offset + size;
+ pSuffix->flags = flags;
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetRenderTarget --
+ *
+ * Bind a surface object to a particular render target attachment
+ * point on the current context. Render target attachment points
+ * exist for color buffers, a depth buffer, and a stencil buffer.
+ *
+ * The SVGA3D device is quite lenient about the types of surfaces
+ * that may be used as render targets. The color buffers must
+ * all be the same size, but the depth and stencil buffers do not
+ * have to be the same size as the color buffer. All attachments
+ * are optional.
+ *
+ * Some combinations of render target formats may require software
+ * emulation, depending on the capabilities of the host graphics
+ * API and graphics hardware.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetRenderTarget(struct svga_winsys_context *swc,
+ SVGA3dRenderTargetType type, // IN
+ struct pipe_surface *surface) // IN
+{
+ SVGA3dCmdSetRenderTarget *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETRENDERTARGET, sizeof *cmd, 1);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+
+ cmd->cid = swc->cid;
+
+ cmd->type = type;
+
+ surface_to_surfaceid(swc, surface, &cmd->target, PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DefineShader --
+ *
+ * Upload the bytecode for a new shader. The bytecode is "SVGA3D
+ * format", which is theoretically a binary-compatible superset
+ * of Microsoft's DirectX shader bytecode. In practice, the
+ * SVGA3D bytecode doesn't yet have any extensions to DirectX's
+ * bytecode format.
+ *
+ * The SVGA3D device supports shader models 1.1 through 2.0.
+ *
+ * The caller chooses a shader ID (small positive integer) by
+ * which this shader will be identified in future commands. This
+ * ID is in a namespace which is per-context and per-shader-type.
+ *
+ * 'bytecodeLen' is specified in bytes. It must be a multiple of 4.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DefineShader(struct svga_winsys_context *swc,
+ uint32 shid, // IN
+ SVGA3dShaderType type, // IN
+ const uint32 *bytecode, // IN
+ uint32 bytecodeLen) // IN
+{
+ SVGA3dCmdDefineShader *cmd;
+
+ assert(bytecodeLen % 4 == 0);
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SHADER_DEFINE, sizeof *cmd + bytecodeLen,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->shid = shid;
+ cmd->type = type;
+ memcpy(&cmd[1], bytecode, bytecodeLen);
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_DestroyShader --
+ *
+ * Delete a shader that was created by SVGA3D_DefineShader. If
+ * the shader was the current vertex or pixel shader for its
+ * context, rendering results are undefined until a new shader is
+ * bound.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_DestroyShader(struct svga_winsys_context *swc,
+ uint32 shid, // IN
+ SVGA3dShaderType type) // IN
+{
+ SVGA3dCmdDestroyShader *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SHADER_DESTROY, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->shid = shid;
+ cmd->type = type;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetShaderConst --
+ *
+ * Set the value of a shader constant.
+ *
+ * Shader constants are analogous to uniform variables in GLSL,
+ * except that they belong to the render context rather than to
+ * an individual shader.
+ *
+ * Constants may have one of three types: A 4-vector of floats,
+ * a 4-vector of integers, or a single boolean flag.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetShaderConst(struct svga_winsys_context *swc,
+ uint32 reg, // IN
+ SVGA3dShaderType type, // IN
+ SVGA3dShaderConstType ctype, // IN
+ const void *value) // IN
+{
+ SVGA3dCmdSetShaderConst *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SET_SHADER_CONST, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->reg = reg;
+ cmd->type = type;
+ cmd->ctype = ctype;
+
+ switch (ctype) {
+
+ case SVGA3D_CONST_TYPE_FLOAT:
+ case SVGA3D_CONST_TYPE_INT:
+ memcpy(&cmd->values, value, sizeof cmd->values);
+ break;
+
+ case SVGA3D_CONST_TYPE_BOOL:
+ memset(&cmd->values, 0, sizeof cmd->values);
+ cmd->values[0] = *(uint32*)value;
+ break;
+
+ default:
+ assert(0);
+ break;
+
+ }
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetShader --
+ *
+ * Switch active shaders. This binds a new vertex or pixel shader
+ * to the specified context.
+ *
+ * A shader ID of SVGA3D_INVALID_ID unbinds any shader, switching
+ * back to the fixed function vertex or pixel pipeline.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetShader(struct svga_winsys_context *swc,
+ SVGA3dShaderType type, // IN
+ uint32 shid) // IN
+{
+ SVGA3dCmdSetShader *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SET_SHADER, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->type = type;
+ cmd->shid = shid;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginClear --
+ *
+ * Begin a CLEAR command. This reserves space for it in the FIFO,
+ * and returns a pointer to the command's rectangle array. This
+ * function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Clear is a rendering operation which fills a list of
+ * rectangles with constant values on all render target types
+ * indicated by 'flags'.
+ *
+ * Clear is not affected by clipping, depth test, or other
+ * render state which affects the fragment pipeline.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May write to attached render target surfaces.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginClear(struct svga_winsys_context *swc,
+ SVGA3dClearFlag flags, // IN
+ uint32 color, // IN
+ float depth, // IN
+ uint32 stencil, // IN
+ SVGA3dRect **rects, // OUT
+ uint32 numRects) // IN
+{
+ SVGA3dCmdClear *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_CLEAR,
+ sizeof *cmd + sizeof **rects * numRects,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->clearFlag = flags;
+ cmd->color = color;
+ cmd->depth = depth;
+ cmd->stencil = stencil;
+ *rects = (SVGA3dRect*) &cmd[1];
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_ClearRect --
+ *
+ * This is a simplified version of SVGA3D_BeginClear().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_ClearRect(struct svga_winsys_context *swc,
+ SVGA3dClearFlag flags, // IN
+ uint32 color, // IN
+ float depth, // IN
+ uint32 stencil, // IN
+ uint32 x, // IN
+ uint32 y, // IN
+ uint32 w, // IN
+ uint32 h) // IN
+{
+ SVGA3dRect *rect;
+ enum pipe_error ret;
+
+ ret = SVGA3D_BeginClear(swc, flags, color, depth, stencil, &rect, 1);
+ if(ret != PIPE_OK)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ memset(rect, 0, sizeof *rect);
+ rect->x = x;
+ rect->y = y;
+ rect->w = w;
+ rect->h = h;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginDrawPrimitives --
+ *
+ * Begin a DRAW_PRIMITIVES command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's arrays.
+ * This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * Drawing commands consist of two variable-length arrays:
+ * SVGA3dVertexDecl elements declare a set of vertex buffers to
+ * use while rendering, and SVGA3dPrimitiveRange elements specify
+ * groups of primitives each with an optional index buffer.
+ *
+ * The decls and ranges arrays are initialized to zero.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May write to attached render target surfaces.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginDrawPrimitives(struct svga_winsys_context *swc,
+ SVGA3dVertexDecl **decls, // OUT
+ uint32 numVertexDecls, // IN
+ SVGA3dPrimitiveRange **ranges, // OUT
+ uint32 numRanges) // IN
+{
+ SVGA3dCmdDrawPrimitives *cmd;
+ SVGA3dVertexDecl *declArray;
+ SVGA3dPrimitiveRange *rangeArray;
+ uint32 declSize = sizeof **decls * numVertexDecls;
+ uint32 rangeSize = sizeof **ranges * numRanges;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_DRAW_PRIMITIVES,
+ sizeof *cmd + declSize + rangeSize,
+ numVertexDecls + numRanges);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->numVertexDecls = numVertexDecls;
+ cmd->numRanges = numRanges;
+
+ declArray = (SVGA3dVertexDecl*) &cmd[1];
+ rangeArray = (SVGA3dPrimitiveRange*) &declArray[numVertexDecls];
+
+ memset(declArray, 0, declSize);
+ memset(rangeArray, 0, rangeSize);
+
+ *decls = declArray;
+ *ranges = rangeArray;
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSurfaceCopy --
+ *
+ * Begin a SURFACE_COPY command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's arrays. This
+ * function must be paired with SVGA_FIFOCommitAll().
+ *
+ * The box array is initialized with zeroes.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Asynchronously copies a list of boxes from surface to surface.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginSurfaceCopy(struct svga_winsys_context *swc,
+ struct pipe_surface *src, // IN
+ struct pipe_surface *dest, // IN
+ SVGA3dCopyBox **boxes, // OUT
+ uint32 numBoxes) // IN
+{
+ SVGA3dCmdSurfaceCopy *cmd;
+ uint32 boxesSize = sizeof **boxes * numBoxes;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_COPY, sizeof *cmd + boxesSize,
+ 2);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ surface_to_surfaceid(swc, src, &cmd->src, PIPE_BUFFER_USAGE_GPU_READ);
+ surface_to_surfaceid(swc, dest, &cmd->dest, PIPE_BUFFER_USAGE_GPU_WRITE);
+ *boxes = (SVGA3dCopyBox*) &cmd[1];
+
+ memset(*boxes, 0, boxesSize);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SurfaceStretchBlt --
+ *
+ * Issue a SURFACE_STRETCHBLT command: an asynchronous
+ * surface-to-surface blit, with scaling.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Asynchronously copies one box from surface to surface.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SurfaceStretchBlt(struct svga_winsys_context *swc,
+ struct pipe_surface *src, // IN
+ struct pipe_surface *dest, // IN
+ SVGA3dBox *boxSrc, // IN
+ SVGA3dBox *boxDest, // IN
+ SVGA3dStretchBltMode mode) // IN
+{
+ SVGA3dCmdSurfaceStretchBlt *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_STRETCHBLT, sizeof *cmd,
+ 2);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ surface_to_surfaceid(swc, src, &cmd->src, PIPE_BUFFER_USAGE_GPU_READ);
+ surface_to_surfaceid(swc, dest, &cmd->dest, PIPE_BUFFER_USAGE_GPU_WRITE);
+ cmd->boxSrc = *boxSrc;
+ cmd->boxDest = *boxDest;
+ cmd->mode = mode;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetViewport --
+ *
+ * Set the current context's viewport rectangle. The viewport
+ * is clipped to the dimensions of the current render target,
+ * then all rendering is clipped to the viewport.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetViewport(struct svga_winsys_context *swc,
+ SVGA3dRect *rect) // IN
+{
+ SVGA3dCmdSetViewport *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETVIEWPORT, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->rect = *rect;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetScissorRect --
+ *
+ * Set the current context's scissor rectangle. If scissor
+ * is enabled then all rendering is clipped to the scissor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetScissorRect(struct svga_winsys_context *swc,
+ SVGA3dRect *rect) // IN
+{
+ SVGA3dCmdSetScissorRect *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETSCISSORRECT, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->rect = *rect;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetClipPlane --
+ *
+ * Set one of the current context's clip planes. If the clip
+ * plane is enabled then all 3d rendering is clipped to against
+ * the plane.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error SVGA3D_SetClipPlane(struct svga_winsys_context *swc,
+ uint32 index, const float *plane)
+{
+ SVGA3dCmdSetClipPlane *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETCLIPPLANE, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->index = index;
+ cmd->plane[0] = plane[0];
+ cmd->plane[1] = plane[1];
+ cmd->plane[2] = plane[2];
+ cmd->plane[3] = plane[3];
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_SetZRange --
+ *
+ * Set the range of the depth buffer to use. 'min' and 'max'
+ * are values between 0.0 and 1.0.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_SetZRange(struct svga_winsys_context *swc,
+ float zMin, // IN
+ float zMax) // IN
+{
+ SVGA3dCmdSetZRange *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETZRANGE, sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->zRange.min = zMin;
+ cmd->zRange.max = zMax;
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSetTextureState --
+ *
+ * Begin a SETTEXTURESTATE command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's texture state
+ * array. This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * This command sets rendering state which is per-texture-unit.
+ *
+ * XXX: Individual texture states need documentation. However,
+ * they are very similar to the texture states defined by
+ * Direct3D. The D3D documentation is a good starting point
+ * for understanding SVGA3D texture states.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginSetTextureState(struct svga_winsys_context *swc,
+ SVGA3dTextureState **states, // OUT
+ uint32 numStates) // IN
+{
+ SVGA3dCmdSetTextureState *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETTEXTURESTATE,
+ sizeof *cmd + sizeof **states * numStates,
+ numStates);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ *states = (SVGA3dTextureState*) &cmd[1];
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginSetRenderState --
+ *
+ * Begin a SETRENDERSTATE command. This reserves space for it in
+ * the FIFO, and returns a pointer to the command's texture state
+ * array. This function must be paired with SVGA_FIFOCommitAll().
+ *
+ * This command sets rendering state which is global to the context.
+ *
+ * XXX: Individual render states need documentation. However,
+ * they are very similar to the render states defined by
+ * Direct3D. The D3D documentation is a good starting point
+ * for understanding SVGA3D render states.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginSetRenderState(struct svga_winsys_context *swc,
+ SVGA3dRenderState **states, // OUT
+ uint32 numStates) // IN
+{
+ SVGA3dCmdSetRenderState *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SETRENDERSTATE,
+ sizeof *cmd + sizeof **states * numStates,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ *states = (SVGA3dRenderState*) &cmd[1];
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_BeginQuery--
+ *
+ * Issues a SVGA_3D_CMD_BEGIN_QUERY command.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Commits space in the FIFO memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_BeginQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type) // IN
+{
+ SVGA3dCmdBeginQuery *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_BEGIN_QUERY,
+ sizeof *cmd,
+ 0);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->type = type;
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_EndQuery--
+ *
+ * Issues a SVGA_3D_CMD_END_QUERY command.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Commits space in the FIFO memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_EndQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type, // IN
+ struct svga_winsys_buffer *buffer) // IN/OUT
+{
+ SVGA3dCmdEndQuery *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_END_QUERY,
+ sizeof *cmd,
+ 1);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->type = type;
+
+ swc->region_relocation(swc, &cmd->guestResult, buffer, 0,
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SVGA3D_WaitForQuery--
+ *
+ * Issues a SVGA_3D_CMD_WAIT_FOR_QUERY command. This reserves space
+ * for it in the FIFO. This doesn't actually wait for the query to
+ * finish but instead tells the host to start a wait at the driver
+ * level. The caller can wait on the status variable in the
+ * guestPtr memory or send an insert fence instruction after this
+ * command and wait on the fence.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Commits space in the FIFO memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+enum pipe_error
+SVGA3D_WaitForQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type, // IN
+ struct svga_winsys_buffer *buffer) // IN/OUT
+{
+ SVGA3dCmdWaitForQuery *cmd;
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_WAIT_FOR_QUERY,
+ sizeof *cmd,
+ 1);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cmd->cid = swc->cid;
+ cmd->type = type;
+
+ swc->region_relocation(swc, &cmd->guestResult, buffer, 0,
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
diff --git a/src/gallium/drivers/svga/svga_cmd.h b/src/gallium/drivers/svga/svga_cmd.h
new file mode 100644
index 0000000000..8041054769
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_cmd.h
@@ -0,0 +1,235 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/*
+ * svga_cmd.h --
+ *
+ * Command construction utility for the SVGA3D protocol used by
+ * the VMware SVGA device, based on the svgautil library.
+ */
+
+#ifndef __SVGA3D_H__
+#define __SVGA3D_H__
+
+
+#include "svga_types.h"
+#include "svga_reg.h"
+#include "svga3d_reg.h"
+
+#include "pipe/p_defines.h"
+
+
+struct pipe_buffer;
+struct pipe_surface;
+struct svga_transfer;
+struct svga_winsys_context;
+struct svga_winsys_buffer;
+struct svga_winsys_surface;
+
+
+/*
+ * SVGA Device Interoperability
+ */
+
+void *
+SVGA3D_FIFOReserve(struct svga_winsys_context *swc, uint32 cmd, uint32 cmdSize, uint32 nr_relocs);
+
+void
+SVGA_FIFOCommitAll(struct svga_winsys_context *swc);
+
+
+/*
+ * Context Management
+ */
+
+enum pipe_error
+SVGA3D_DefineContext(struct svga_winsys_context *swc);
+
+enum pipe_error
+SVGA3D_DestroyContext(struct svga_winsys_context *swc);
+
+
+/*
+ * Surface Management
+ */
+
+enum pipe_error
+SVGA3D_BeginDefineSurface(struct svga_winsys_context *swc,
+ struct svga_winsys_surface *sid,
+ SVGA3dSurfaceFlags flags,
+ SVGA3dSurfaceFormat format,
+ SVGA3dSurfaceFace **faces,
+ SVGA3dSize **mipSizes,
+ uint32 numMipSizes);
+enum pipe_error
+SVGA3D_DefineSurface2D(struct svga_winsys_context *swc,
+ struct svga_winsys_surface *sid,
+ uint32 width,
+ uint32 height,
+ SVGA3dSurfaceFormat format);
+enum pipe_error
+SVGA3D_DestroySurface(struct svga_winsys_context *swc,
+ struct svga_winsys_surface *sid);
+
+
+/*
+ * Surface Operations
+ */
+
+enum pipe_error
+SVGA3D_SurfaceDMA(struct svga_winsys_context *swc,
+ struct svga_transfer *st,
+ SVGA3dTransferType transfer,
+ const SVGA3dCopyBox *boxes,
+ uint32 numBoxes);
+
+enum pipe_error
+SVGA3D_BufferDMA(struct svga_winsys_context *swc,
+ struct svga_winsys_buffer *guest,
+ struct svga_winsys_surface *host,
+ SVGA3dTransferType transfer,
+ uint32 size,
+ uint32 offset,
+ SVGA3dSurfaceDMAFlags flags);
+
+/*
+ * Drawing Operations
+ */
+
+
+enum pipe_error
+SVGA3D_BeginClear(struct svga_winsys_context *swc,
+ SVGA3dClearFlag flags,
+ uint32 color, float depth, uint32 stencil,
+ SVGA3dRect **rects, uint32 numRects);
+
+enum pipe_error
+SVGA3D_ClearRect(struct svga_winsys_context *swc,
+ SVGA3dClearFlag flags, uint32 color, float depth,
+ uint32 stencil, uint32 x, uint32 y, uint32 w, uint32 h);
+
+enum pipe_error
+SVGA3D_BeginDrawPrimitives(struct svga_winsys_context *swc,
+ SVGA3dVertexDecl **decls,
+ uint32 numVertexDecls,
+ SVGA3dPrimitiveRange **ranges,
+ uint32 numRanges);
+
+/*
+ * Blits
+ */
+
+enum pipe_error
+SVGA3D_BeginSurfaceCopy(struct svga_winsys_context *swc,
+ struct pipe_surface *src,
+ struct pipe_surface *dest,
+ SVGA3dCopyBox **boxes, uint32 numBoxes);
+
+
+enum pipe_error
+SVGA3D_SurfaceStretchBlt(struct svga_winsys_context *swc,
+ struct pipe_surface *src,
+ struct pipe_surface *dest,
+ SVGA3dBox *boxSrc, SVGA3dBox *boxDest,
+ SVGA3dStretchBltMode mode);
+
+/*
+ * Shared FFP/Shader Render State
+ */
+
+enum pipe_error
+SVGA3D_SetRenderTarget(struct svga_winsys_context *swc,
+ SVGA3dRenderTargetType type,
+ struct pipe_surface *surface);
+
+enum pipe_error
+SVGA3D_SetZRange(struct svga_winsys_context *swc,
+ float zMin, float zMax);
+
+enum pipe_error
+SVGA3D_SetViewport(struct svga_winsys_context *swc,
+ SVGA3dRect *rect);
+
+enum pipe_error
+SVGA3D_SetScissorRect(struct svga_winsys_context *swc,
+ SVGA3dRect *rect);
+
+enum pipe_error
+SVGA3D_SetClipPlane(struct svga_winsys_context *swc,
+ uint32 index, const float *plane);
+
+enum pipe_error
+SVGA3D_BeginSetTextureState(struct svga_winsys_context *swc,
+ SVGA3dTextureState **states,
+ uint32 numStates);
+
+enum pipe_error
+SVGA3D_BeginSetRenderState(struct svga_winsys_context *swc,
+ SVGA3dRenderState **states,
+ uint32 numStates);
+
+
+/*
+ * Shaders
+ */
+
+enum pipe_error
+SVGA3D_DefineShader(struct svga_winsys_context *swc,
+ uint32 shid, SVGA3dShaderType type,
+ const uint32 *bytecode, uint32 bytecodeLen);
+
+enum pipe_error
+SVGA3D_DestroyShader(struct svga_winsys_context *swc,
+ uint32 shid, SVGA3dShaderType type);
+
+enum pipe_error
+SVGA3D_SetShaderConst(struct svga_winsys_context *swc,
+ uint32 reg, SVGA3dShaderType type,
+ SVGA3dShaderConstType ctype, const void *value);
+
+enum pipe_error
+SVGA3D_SetShader(struct svga_winsys_context *swc,
+ SVGA3dShaderType type, uint32 shid);
+
+
+/*
+ * Queries
+ */
+
+enum pipe_error
+SVGA3D_BeginQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type);
+
+enum pipe_error
+SVGA3D_EndQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type,
+ struct svga_winsys_buffer *buffer);
+
+enum pipe_error
+SVGA3D_WaitForQuery(struct svga_winsys_context *swc,
+ SVGA3dQueryType type,
+ struct svga_winsys_buffer *buffer);
+
+#endif /* __SVGA3D_H__ */
diff --git a/src/gallium/drivers/svga/svga_context.c b/src/gallium/drivers/svga/svga_context.c
new file mode 100644
index 0000000000..c3de12b4a3
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_context.c
@@ -0,0 +1,271 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_upload_mgr.h"
+
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_screen_texture.h"
+#include "svga_screen_buffer.h"
+#include "svga_winsys.h"
+#include "svga_swtnl.h"
+#include "svga_draw.h"
+#include "svga_debug.h"
+#include "svga_state.h"
+
+
+static void svga_destroy( struct pipe_context *pipe )
+{
+ struct svga_context *svga = svga_context( pipe );
+ unsigned shader;
+
+ svga_cleanup_framebuffer( svga );
+ svga_cleanup_tss_binding( svga );
+
+ svga_hwtnl_destroy( svga->hwtnl );
+
+ svga_cleanup_vertex_state(svga);
+
+ svga->swc->destroy(svga->swc);
+
+ svga_destroy_swtnl( svga );
+
+ u_upload_destroy( svga->upload_vb );
+ u_upload_destroy( svga->upload_ib );
+
+ for(shader = 0; shader < PIPE_SHADER_TYPES; ++shader)
+ pipe_buffer_reference( &svga->curr.cb[shader], NULL );
+
+ FREE( svga );
+}
+
+static unsigned int
+svga_is_texture_referenced( struct pipe_context *pipe,
+ struct pipe_texture *texture,
+ unsigned face, unsigned level)
+{
+ struct svga_texture *tex = svga_texture(texture);
+ struct svga_screen *ss = svga_screen(pipe->screen);
+
+ /**
+ * The screen does not cache texture writes.
+ */
+
+ if (!tex->handle || ss->sws->surface_is_flushed(ss->sws, tex->handle))
+ return PIPE_UNREFERENCED;
+
+ /**
+ * sws->surface_is_flushed() does not distinguish between read references
+ * and write references. So assume a reference is both.
+ */
+
+ return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+static unsigned int
+svga_is_buffer_referenced( struct pipe_context *pipe,
+ struct pipe_buffer *buf)
+
+{
+ struct svga_screen *ss = svga_screen(pipe->screen);
+ struct svga_buffer *sbuf = svga_buffer(buf);
+
+ /**
+ * XXX: Check this.
+ * The screen may cache buffer writes, but when we map, we map out
+ * of those cached writes, so we don't need to set a
+ * PIPE_REFERENCED_FOR_WRITE flag for cached buffers.
+ */
+
+ if (!sbuf->handle || ss->sws->surface_is_flushed(ss->sws, sbuf->handle))
+ return PIPE_UNREFERENCED;
+
+ /**
+ * sws->surface_is_flushed() does not distinguish between read references
+ * and write references. So assume a reference is both,
+ * however, we make an exception for index- and vertex buffers, to avoid
+ * a flush in st_bufferobj_get_subdata, during display list replay.
+ */
+
+ if (sbuf->base.usage & (PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_INDEX))
+ return PIPE_REFERENCED_FOR_READ;
+
+ return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
+}
+
+
+struct pipe_context *svga_context_create( struct pipe_screen *screen )
+{
+ struct svga_screen *svgascreen = svga_screen(screen);
+ struct svga_context *svga = NULL;
+ enum pipe_error ret;
+
+ svga = CALLOC_STRUCT(svga_context);
+ if (svga == NULL)
+ goto error1;
+
+ svga->pipe.winsys = screen->winsys;
+ svga->pipe.screen = screen;
+ svga->pipe.destroy = svga_destroy;
+ svga->pipe.clear = svga_clear;
+
+ svga->pipe.is_texture_referenced = svga_is_texture_referenced;
+ svga->pipe.is_buffer_referenced = svga_is_buffer_referenced;
+
+ svga->swc = svgascreen->sws->context_create(svgascreen->sws);
+ if(!svga->swc)
+ goto error2;
+
+ svga_init_blend_functions(svga);
+ svga_init_blit_functions(svga);
+ svga_init_depth_stencil_functions(svga);
+ svga_init_draw_functions(svga);
+ svga_init_flush_functions(svga);
+ svga_init_misc_functions(svga);
+ svga_init_rasterizer_functions(svga);
+ svga_init_sampler_functions(svga);
+ svga_init_fs_functions(svga);
+ svga_init_vs_functions(svga);
+ svga_init_vertex_functions(svga);
+ svga_init_constbuffer_functions(svga);
+ svga_init_query_functions(svga);
+
+ /* debug */
+ svga->debug.no_swtnl = debug_get_bool_option("SVGA_NO_SWTNL", FALSE);
+ svga->debug.force_swtnl = debug_get_bool_option("SVGA_FORCE_SWTNL", FALSE);
+ svga->debug.use_min_mipmap = debug_get_bool_option("SVGA_USE_MIN_MIPMAP", FALSE);
+ svga->debug.disable_shader = debug_get_num_option("SVGA_DISABLE_SHADER", ~0);
+
+ if (!svga_init_swtnl(svga))
+ goto error3;
+
+ svga->upload_ib = u_upload_create( svga->pipe.screen,
+ 32 * 1024,
+ 16,
+ PIPE_BUFFER_USAGE_INDEX );
+ if (svga->upload_ib == NULL)
+ goto error4;
+
+ svga->upload_vb = u_upload_create( svga->pipe.screen,
+ 128 * 1024,
+ 16,
+ PIPE_BUFFER_USAGE_VERTEX );
+ if (svga->upload_vb == NULL)
+ goto error5;
+
+ svga->hwtnl = svga_hwtnl_create( svga,
+ svga->upload_ib,
+ svga->swc );
+ if (svga->hwtnl == NULL)
+ goto error6;
+
+
+ ret = svga_emit_initial_state( svga );
+ if (ret)
+ goto error7;
+
+ /* Avoid shortcircuiting state with initial value of zero.
+ */
+ memset(&svga->state.hw_clear, 0xcd, sizeof(svga->state.hw_clear));
+ memset(&svga->state.hw_clear.framebuffer, 0x0,
+ sizeof(svga->state.hw_clear.framebuffer));
+
+ memset(&svga->state.hw_draw, 0xcd, sizeof(svga->state.hw_draw));
+ memset(&svga->state.hw_draw.views, 0x0, sizeof(svga->state.hw_draw.views));
+ svga->state.hw_draw.num_views = 0;
+
+ svga->dirty = ~0;
+ svga->state.white_fs_id = SVGA3D_INVALID_ID;
+
+ LIST_INITHEAD(&svga->dirty_buffers);
+
+ return &svga->pipe;
+
+error7:
+ svga_hwtnl_destroy( svga->hwtnl );
+error6:
+ u_upload_destroy( svga->upload_vb );
+error5:
+ u_upload_destroy( svga->upload_ib );
+error4:
+ svga_destroy_swtnl(svga);
+error3:
+ svga->swc->destroy(svga->swc);
+error2:
+ FREE(svga);
+error1:
+ return NULL;
+}
+
+
+void svga_context_flush( struct svga_context *svga,
+ struct pipe_fence_handle **pfence )
+{
+ struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
+
+ svga->curr.nr_fbs = 0;
+
+ /* Unmap upload manager buffers:
+ */
+ u_upload_flush(svga->upload_vb);
+ u_upload_flush(svga->upload_ib);
+
+ /* Flush screen, to ensure that texture dma uploads are processed
+ * before submitting commands.
+ */
+ svga_screen_flush(svgascreen, NULL);
+
+ svga_context_flush_buffers(svga);
+
+ /* Flush pending commands to hardware:
+ */
+ svga->swc->flush(svga->swc, pfence);
+
+ if (SVGA_DEBUG & DEBUG_SYNC) {
+ if (pfence && *pfence)
+ svga->pipe.screen->fence_finish( svga->pipe.screen, *pfence, 0);
+ }
+}
+
+
+void svga_hwtnl_flush_retry( struct svga_context *svga )
+{
+ enum pipe_error ret = PIPE_OK;
+
+ ret = svga_hwtnl_flush( svga->hwtnl );
+ if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
+ svga_context_flush( svga, NULL );
+ ret = svga_hwtnl_flush( svga->hwtnl );
+ }
+
+ assert(ret == 0);
+}
+
diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h
new file mode 100644
index 0000000000..e650a251d1
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_context.h
@@ -0,0 +1,448 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_CONTEXT_H
+#define SVGA_CONTEXT_H
+
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_state.h"
+
+#include "util/u_double_list.h"
+
+#include "tgsi/tgsi_scan.h"
+
+
+#define SVGA_TEX_UNITS 8
+
+struct draw_vertex_shader;
+struct svga_shader_result;
+struct SVGACmdMemory;
+struct u_upload_mgr;
+
+
+struct svga_shader
+{
+ const struct tgsi_token *tokens;
+
+ struct tgsi_shader_info info;
+
+ struct svga_shader_result *results;
+
+ unsigned id;
+
+ boolean use_sm30;
+};
+
+struct svga_fragment_shader
+{
+ struct svga_shader base;
+};
+
+struct svga_vertex_shader
+{
+ struct svga_shader base;
+
+ struct draw_vertex_shader *draw_shader;
+};
+
+
+struct svga_cache_context;
+struct svga_tracked_state;
+
+struct svga_blend_state {
+
+ boolean need_white_fragments;
+
+ /* Should be per-render-target:
+ */
+ struct {
+ uint8_t writemask;
+
+ boolean blend_enable;
+ uint8_t srcblend;
+ uint8_t dstblend;
+ uint8_t blendeq;
+
+ boolean separate_alpha_blend_enable;
+ uint8_t srcblend_alpha;
+ uint8_t dstblend_alpha;
+ uint8_t blendeq_alpha;
+
+ } rt[1];
+};
+
+struct svga_depth_stencil_state {
+ unsigned zfunc:8;
+ unsigned zenable:1;
+ unsigned zwriteenable:1;
+
+ unsigned alphatestenable:1;
+ unsigned alphafunc:8;
+
+ struct {
+ unsigned enabled:1;
+ unsigned func:8;
+ unsigned fail:8;
+ unsigned zfail:8;
+ unsigned pass:8;
+ } stencil[2];
+
+ /* SVGA3D has one ref/mask/writemask triple shared between front &
+ * back face stencil. We really need two:
+ */
+ unsigned stencil_ref:8;
+ unsigned stencil_mask:8;
+ unsigned stencil_writemask:8;
+
+ float alpharef;
+};
+
+#define SVGA_UNFILLED_DISABLE 0
+#define SVGA_UNFILLED_LINE 1
+#define SVGA_UNFILLED_POINT 2
+
+#define SVGA_PIPELINE_FLAG_POINTS (1<<PIPE_PRIM_POINTS)
+#define SVGA_PIPELINE_FLAG_LINES (1<<PIPE_PRIM_LINES)
+#define SVGA_PIPELINE_FLAG_TRIS (1<<PIPE_PRIM_TRIANGLES)
+
+struct svga_rasterizer_state {
+ struct pipe_rasterizer_state templ; /* needed for draw module */
+
+ unsigned shademode:8;
+ unsigned cullmode:8;
+ unsigned scissortestenable:1;
+ unsigned multisampleantialias:1;
+ unsigned antialiasedlineenable:1;
+ unsigned lastpixel:1;
+
+ unsigned linepattern;
+
+ float slopescaledepthbias;
+ float depthbias;
+ float pointsize;
+ float pointsize_min;
+ float pointsize_max;
+
+ unsigned hw_unfilled:16; /* PIPE_POLYGON_MODE_x */
+ unsigned need_pipeline:16; /* which prims do we need help for? */
+};
+
+struct svga_sampler_state {
+ unsigned mipfilter;
+ unsigned magfilter;
+ unsigned minfilter;
+ unsigned aniso_level;
+ float lod_bias;
+ unsigned addressu;
+ unsigned addressv;
+ unsigned addressw;
+ unsigned bordercolor;
+ unsigned normalized_coords:1;
+ unsigned compare_mode:1;
+ unsigned compare_func:3;
+
+ unsigned min_lod;
+ unsigned view_min_lod;
+ unsigned view_max_lod;
+};
+
+/* Use to calculate differences between state emitted to hardware and
+ * current driver-calculated state.
+ */
+struct svga_state
+{
+ const struct svga_blend_state *blend;
+ const struct svga_depth_stencil_state *depth;
+ const struct svga_rasterizer_state *rast;
+ const struct svga_sampler_state *sampler[PIPE_MAX_SAMPLERS];
+
+ struct pipe_texture *texture[PIPE_MAX_SAMPLERS]; /* or texture ID's? */
+ struct svga_fragment_shader *fs;
+ struct svga_vertex_shader *vs;
+
+ struct pipe_vertex_buffer vb[PIPE_MAX_ATTRIBS];
+ struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS];
+ struct pipe_buffer *cb[PIPE_SHADER_TYPES];
+
+ struct pipe_framebuffer_state framebuffer;
+ float depthscale;
+
+ /* Hack to limit the number of different render targets between
+ * flushes. Helps avoid blowing out our surface cache in EXA.
+ */
+ int nr_fbs;
+
+ struct pipe_poly_stipple poly_stipple;
+ struct pipe_scissor_state scissor;
+ struct pipe_blend_color blend_color;
+ struct pipe_clip_state clip;
+ struct pipe_viewport_state viewport;
+
+ const unsigned *edgeflags;
+
+ unsigned num_samplers;
+ unsigned num_textures;
+ unsigned num_vertex_elements;
+ unsigned num_vertex_buffers;
+ unsigned reduced_prim;
+
+ struct {
+ unsigned flag_1d;
+ unsigned flag_srgb;
+ } tex_flags;
+
+ boolean any_user_vertex_buffers;
+
+ unsigned zero_stride_vertex_elements;
+ unsigned num_zero_stride_vertex_elements;
+ /* ### maybe dynamically allocate this */
+ float zero_stride_constants[PIPE_MAX_ATTRIBS*4];
+};
+
+#define RS_MAX 97
+#define TS_MAX 30
+#define CB_MAX 256
+
+struct svga_prescale {
+ float translate[4];
+ float scale[4];
+ boolean enabled;
+};
+
+
+/* Updated by calling svga_update_state( SVGA_STATE_HW_VIEWPORT )
+ */
+struct svga_hw_clear_state
+{
+ struct {
+ unsigned x,y,w,h;
+ } viewport;
+
+ struct {
+ float zmin, zmax;
+ } depthrange;
+
+ struct pipe_framebuffer_state framebuffer;
+ struct svga_prescale prescale;
+};
+
+struct svga_hw_view_state
+{
+ struct pipe_texture *texture;
+ struct svga_sampler_view *v;
+ unsigned min_lod;
+ unsigned max_lod;
+ int dirty;
+};
+
+/* Updated by calling svga_update_state( SVGA_STATE_HW_DRAW )
+ */
+struct svga_hw_draw_state
+{
+ unsigned rs[RS_MAX];
+ unsigned ts[16][TS_MAX];
+ float cb[PIPE_SHADER_TYPES][CB_MAX][4];
+
+ unsigned shader_id[PIPE_SHADER_TYPES];
+
+ struct svga_shader_result *fs;
+ struct svga_shader_result *vs;
+ struct svga_hw_view_state views[PIPE_MAX_SAMPLERS];
+
+ unsigned num_views;
+};
+
+
+/* Updated by calling svga_update_state( SVGA_STATE_NEED_SWTNL )
+ */
+struct svga_sw_state
+{
+ unsigned ve_format[PIPE_MAX_ATTRIBS]; /* NEW_VELEMENT */
+
+ /* which parts we need */
+ boolean need_swvfetch;
+ boolean need_pipeline;
+ boolean need_swtnl;
+};
+
+
+/* Queue some state updates (like rss) and submit them to hardware in
+ * a single packet.
+ */
+struct svga_hw_queue;
+
+struct svga_query;
+
+struct svga_context
+{
+ struct pipe_context pipe;
+ struct svga_winsys_context *swc;
+
+ struct {
+ boolean no_swtnl;
+ boolean force_swtnl;
+ boolean use_min_mipmap;
+
+ /* incremented for each shader */
+ unsigned shader_id;
+
+ unsigned disable_shader;
+ } debug;
+
+ struct {
+ struct draw_context *draw;
+ struct vbuf_render *backend;
+ unsigned hw_prim;
+ boolean new_vbuf;
+ boolean new_vdecl;
+ } swtnl;
+
+ struct {
+ unsigned dirty[4];
+
+ unsigned texture_timestamp;
+ unsigned next_fs_id;
+ unsigned next_vs_id;
+
+ /* Internally generated shaders:
+ */
+ unsigned white_fs_id;
+
+ /*
+ */
+ struct svga_sw_state sw;
+ struct svga_hw_draw_state hw_draw;
+ struct svga_hw_clear_state hw_clear;
+ } state;
+
+ struct svga_state curr; /* state from the state tracker */
+ unsigned dirty; /* statechanges since last update_state() */
+
+ struct u_upload_mgr *upload_ib;
+ struct u_upload_mgr *upload_vb;
+ struct svga_hwtnl *hwtnl;
+
+ /** The occlusion query currently in progress */
+ struct svga_query *sq;
+
+ /** List of buffers with queued transfers */
+ struct list_head dirty_buffers;
+};
+
+/* A flag for each state_tracker state object:
+ */
+#define SVGA_NEW_BLEND 0x1
+#define SVGA_NEW_DEPTH_STENCIL 0x2
+#define SVGA_NEW_RAST 0x4
+#define SVGA_NEW_SAMPLER 0x8
+#define SVGA_NEW_TEXTURE 0x10
+#define SVGA_NEW_VBUFFER 0x20
+#define SVGA_NEW_VELEMENT 0x40
+#define SVGA_NEW_FS 0x80
+#define SVGA_NEW_VS 0x100
+#define SVGA_NEW_FS_CONST_BUFFER 0x200
+#define SVGA_NEW_VS_CONST_BUFFER 0x400
+#define SVGA_NEW_FRAME_BUFFER 0x800
+#define SVGA_NEW_STIPPLE 0x1000
+#define SVGA_NEW_SCISSOR 0x2000
+#define SVGA_NEW_BLEND_COLOR 0x5000
+#define SVGA_NEW_CLIP 0x8000
+#define SVGA_NEW_VIEWPORT 0x10000
+#define SVGA_NEW_PRESCALE 0x20000
+#define SVGA_NEW_REDUCED_PRIMITIVE 0x40000
+#define SVGA_NEW_TEXTURE_BINDING 0x80000
+#define SVGA_NEW_NEED_PIPELINE 0x100000
+#define SVGA_NEW_NEED_SWVFETCH 0x200000
+#define SVGA_NEW_NEED_SWTNL 0x400000
+#define SVGA_NEW_FS_RESULT 0x800000
+#define SVGA_NEW_VS_RESULT 0x1000000
+#define SVGA_NEW_EDGEFLAGS 0x2000000
+#define SVGA_NEW_ZERO_STRIDE 0x4000000
+#define SVGA_NEW_TEXTURE_FLAGS 0x8000000
+
+
+
+
+
+/***********************************************************************
+ * svga_clear.c:
+ */
+void svga_clear(struct pipe_context *pipe,
+ unsigned buffers,
+ const float *rgba,
+ double depth,
+ unsigned stencil);
+
+
+/***********************************************************************
+ * svga_screen_texture.c:
+ */
+void svga_mark_surfaces_dirty(struct svga_context *svga);
+
+
+
+
+void svga_init_state_functions( struct svga_context *svga );
+void svga_init_flush_functions( struct svga_context *svga );
+void svga_init_string_functions( struct svga_context *svga );
+void svga_init_blit_functions(struct svga_context *svga);
+
+void svga_init_blend_functions( struct svga_context *svga );
+void svga_init_depth_stencil_functions( struct svga_context *svga );
+void svga_init_misc_functions( struct svga_context *svga );
+void svga_init_rasterizer_functions( struct svga_context *svga );
+void svga_init_sampler_functions( struct svga_context *svga );
+void svga_init_fs_functions( struct svga_context *svga );
+void svga_init_vs_functions( struct svga_context *svga );
+void svga_init_vertex_functions( struct svga_context *svga );
+void svga_init_constbuffer_functions( struct svga_context *svga );
+void svga_init_draw_functions( struct svga_context *svga );
+void svga_init_query_functions( struct svga_context *svga );
+
+void svga_cleanup_vertex_state( struct svga_context *svga );
+void svga_cleanup_tss_binding( struct svga_context *svga );
+void svga_cleanup_framebuffer( struct svga_context *svga );
+
+void svga_context_flush( struct svga_context *svga,
+ struct pipe_fence_handle **pfence );
+
+void svga_hwtnl_flush_retry( struct svga_context *svga );
+
+
+/***********************************************************************
+ * Inline conversion functions. These are better-typed than the
+ * macros used previously:
+ */
+static INLINE struct svga_context *
+svga_context( struct pipe_context *pipe )
+{
+ return (struct svga_context *)pipe;
+}
+
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_debug.h b/src/gallium/drivers/svga/svga_debug.h
new file mode 100644
index 0000000000..3a3fcd8fae
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_debug.h
@@ -0,0 +1,75 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_DEBUG_H
+#define SVGA_DEBUG_H
+
+#include "pipe/p_compiler.h"
+#include "util/u_debug.h"
+
+#define DEBUG_DMA 0x1
+#define DEBUG_TGSI 0x4
+#define DEBUG_PIPE 0x8
+#define DEBUG_STATE 0x10
+#define DEBUG_SCREEN 0x20
+#define DEBUG_TEX 0x40
+#define DEBUG_SWTNL 0x80
+#define DEBUG_CONSTS 0x100
+#define DEBUG_VIEWPORT 0x200
+#define DEBUG_VIEWS 0x400
+#define DEBUG_PERF 0x800 /* print something when we hit any slow path operation */
+#define DEBUG_FLUSH 0x1000 /* flush after every draw */
+#define DEBUG_SYNC 0x2000 /* sync after every flush */
+#define DEBUG_QUERY 0x4000
+#define DEBUG_CACHE 0x8000
+
+#ifdef DEBUG
+extern int SVGA_DEBUG;
+#define DBSTR(x) x
+#else
+#define SVGA_DEBUG 0
+#define DBSTR(x) ""
+#endif
+
+static INLINE void
+SVGA_DBG( unsigned flag, const char *fmt, ... )
+{
+#ifdef DEBUG
+ if (SVGA_DEBUG & flag)
+ {
+ va_list args;
+
+ va_start( args, fmt );
+ debug_vprintf( fmt, args );
+ va_end( args );
+ }
+#else
+ (void)flag;
+ (void)fmt;
+#endif
+}
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c
new file mode 100644
index 0000000000..8db40d0fd5
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_draw.c
@@ -0,0 +1,377 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include "svga_context.h"
+#include "svga_draw.h"
+#include "svga_draw_private.h"
+#include "svga_debug.h"
+#include "svga_screen.h"
+#include "svga_screen_buffer.h"
+#include "svga_screen_texture.h"
+#include "svga_winsys.h"
+#include "svga_cmd.h"
+
+
+struct svga_hwtnl *svga_hwtnl_create( struct svga_context *svga,
+ struct u_upload_mgr *upload_ib,
+ struct svga_winsys_context *swc )
+{
+ struct svga_hwtnl *hwtnl = CALLOC_STRUCT(svga_hwtnl);
+ if (hwtnl == NULL)
+ goto fail;
+
+ hwtnl->svga = svga;
+ hwtnl->upload_ib = upload_ib;
+
+ hwtnl->cmd.swc = swc;
+
+ return hwtnl;
+
+fail:
+ return NULL;
+}
+
+void svga_hwtnl_destroy( struct svga_hwtnl *hwtnl )
+{
+ int i, j;
+
+ for (i = 0; i < PIPE_PRIM_MAX; i++) {
+ for (j = 0; j < IDX_CACHE_MAX; j++) {
+ pipe_buffer_reference( &hwtnl->index_cache[i][j].buffer,
+ NULL );
+ }
+ }
+
+ for (i = 0; i < hwtnl->cmd.vdecl_count; i++)
+ pipe_buffer_reference(&hwtnl->cmd.vdecl_vb[i], NULL);
+
+ for (i = 0; i < hwtnl->cmd.prim_count; i++)
+ pipe_buffer_reference(&hwtnl->cmd.prim_ib[i], NULL);
+
+
+ FREE(hwtnl);
+}
+
+
+void svga_hwtnl_set_flatshade( struct svga_hwtnl *hwtnl,
+ boolean flatshade,
+ boolean flatshade_first )
+{
+ hwtnl->hw_pv = PV_FIRST;
+ hwtnl->api_pv = (flatshade && !flatshade_first) ? PV_LAST : PV_FIRST;
+}
+
+void svga_hwtnl_set_unfilled( struct svga_hwtnl *hwtnl,
+ unsigned mode )
+{
+ hwtnl->api_fillmode = mode;
+}
+
+void svga_hwtnl_reset_vdecl( struct svga_hwtnl *hwtnl,
+ unsigned count )
+{
+ unsigned i;
+
+ assert(hwtnl->cmd.prim_count == 0);
+
+ for (i = count; i < hwtnl->cmd.vdecl_count; i++) {
+ pipe_buffer_reference(&hwtnl->cmd.vdecl_vb[i],
+ NULL);
+ }
+
+ hwtnl->cmd.vdecl_count = count;
+}
+
+
+void svga_hwtnl_vdecl( struct svga_hwtnl *hwtnl,
+ unsigned i,
+ const SVGA3dVertexDecl *decl,
+ struct pipe_buffer *vb)
+{
+ assert(hwtnl->cmd.prim_count == 0);
+
+ assert( i < hwtnl->cmd.vdecl_count );
+
+ hwtnl->cmd.vdecl[i] = *decl;
+
+ pipe_buffer_reference(&hwtnl->cmd.vdecl_vb[i],
+ vb);
+}
+
+
+
+enum pipe_error
+svga_hwtnl_flush( struct svga_hwtnl *hwtnl )
+{
+ struct svga_winsys_context *swc = hwtnl->cmd.swc;
+ struct svga_context *svga = hwtnl->svga;
+ enum pipe_error ret;
+
+ if (hwtnl->cmd.prim_count) {
+ struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
+ struct svga_winsys_surface *ib_handle[QSZ];
+ struct svga_winsys_surface *handle;
+ SVGA3dVertexDecl *vdecl;
+ SVGA3dPrimitiveRange *prim;
+ unsigned i;
+
+ for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
+ handle = svga_buffer_handle(svga, hwtnl->cmd.vdecl_vb[i]);
+ if (handle == NULL)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ vb_handle[i] = handle;
+ }
+
+ for (i = 0; i < hwtnl->cmd.prim_count; i++) {
+ if (hwtnl->cmd.prim_ib[i]) {
+ handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]);
+ if (handle == NULL)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+ }
+ else
+ handle = NULL;
+
+ ib_handle[i] = handle;
+ }
+
+ SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n",
+ svga_surface(svga->curr.framebuffer.cbufs[0])->handle,
+ hwtnl->cmd.prim_count);
+
+ ret = SVGA3D_BeginDrawPrimitives(swc,
+ &vdecl,
+ hwtnl->cmd.vdecl_count,
+ &prim,
+ hwtnl->cmd.prim_count);
+ if (ret != PIPE_OK)
+ return ret;
+
+
+ memcpy( vdecl,
+ hwtnl->cmd.vdecl,
+ hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]);
+
+ for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
+ /* Given rangeHint is considered to be relative to indexBias, and
+ * indexBias varies per primitive, we cannot accurately supply an
+ * rangeHint when emitting more than one primitive per draw command.
+ */
+ if (hwtnl->cmd.prim_count == 1) {
+ vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0];
+ vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1;
+ }
+ else {
+ vdecl[i].rangeHint.first = 0;
+ vdecl[i].rangeHint.last = 0;
+ }
+
+ swc->surface_relocation(swc,
+ &vdecl[i].array.surfaceId,
+ vb_handle[i],
+ PIPE_BUFFER_USAGE_GPU_READ);
+ }
+
+ memcpy( prim,
+ hwtnl->cmd.prim,
+ hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]);
+
+ for (i = 0; i < hwtnl->cmd.prim_count; i++) {
+ swc->surface_relocation(swc,
+ &prim[i].indexArray.surfaceId,
+ ib_handle[i],
+ PIPE_BUFFER_USAGE_GPU_READ);
+ pipe_buffer_reference(&hwtnl->cmd.prim_ib[i], NULL);
+ }
+
+ SVGA_FIFOCommitAll( swc );
+ hwtnl->cmd.prim_count = 0;
+ }
+
+ return PIPE_OK;
+}
+
+
+
+
+
+/***********************************************************************
+ * Internal functions:
+ */
+
+enum pipe_error svga_hwtnl_prim( struct svga_hwtnl *hwtnl,
+ const SVGA3dPrimitiveRange *range,
+ unsigned min_index,
+ unsigned max_index,
+ struct pipe_buffer *ib )
+{
+ int ret = PIPE_OK;
+
+#ifdef DEBUG
+ {
+ unsigned i;
+ for (i = 0; i < hwtnl->cmd.vdecl_count; i++) {
+ struct pipe_buffer *vb = hwtnl->cmd.vdecl_vb[i];
+ unsigned size = vb ? vb->size : 0;
+ unsigned offset = hwtnl->cmd.vdecl[i].array.offset;
+ unsigned stride = hwtnl->cmd.vdecl[i].array.stride;
+ unsigned index_bias = range->indexBias;
+ unsigned width;
+
+ assert(vb);
+ assert(size);
+ assert(offset < size);
+ assert(index_bias >= 0);
+ assert(min_index <= max_index);
+ assert(offset + index_bias*stride < size);
+ assert(offset + (index_bias + min_index)*stride < size);
+
+ switch (hwtnl->cmd.vdecl[i].identity.type) {
+ case SVGA3D_DECLTYPE_FLOAT1:
+ width = 4;
+ break;
+ case SVGA3D_DECLTYPE_FLOAT2:
+ width = 4*2;
+ break;
+ case SVGA3D_DECLTYPE_FLOAT3:
+ width = 4*3;
+ break;
+ case SVGA3D_DECLTYPE_FLOAT4:
+ width = 4*4;
+ break;
+ case SVGA3D_DECLTYPE_D3DCOLOR:
+ width = 4;
+ break;
+ case SVGA3D_DECLTYPE_UBYTE4:
+ width = 1*4;
+ break;
+ case SVGA3D_DECLTYPE_SHORT2:
+ width = 2*2;
+ break;
+ case SVGA3D_DECLTYPE_SHORT4:
+ width = 2*4;
+ break;
+ case SVGA3D_DECLTYPE_UBYTE4N:
+ width = 1*4;
+ break;
+ case SVGA3D_DECLTYPE_SHORT2N:
+ width = 2*2;
+ break;
+ case SVGA3D_DECLTYPE_SHORT4N:
+ width = 2*4;
+ break;
+ case SVGA3D_DECLTYPE_USHORT2N:
+ width = 2*2;
+ break;
+ case SVGA3D_DECLTYPE_USHORT4N:
+ width = 2*4;
+ break;
+ case SVGA3D_DECLTYPE_UDEC3:
+ width = 4;
+ break;
+ case SVGA3D_DECLTYPE_DEC3N:
+ width = 4;
+ break;
+ case SVGA3D_DECLTYPE_FLOAT16_2:
+ width = 2*2;
+ break;
+ case SVGA3D_DECLTYPE_FLOAT16_4:
+ width = 2*4;
+ break;
+ default:
+ assert(0);
+ width = 0;
+ break;
+ }
+
+ assert(!stride || width <= stride);
+ assert(offset + (index_bias + max_index)*stride + width <= size);
+ }
+
+ assert(range->indexWidth == range->indexArray.stride);
+
+ if(ib) {
+ unsigned size = ib->size;
+ unsigned offset = range->indexArray.offset;
+ unsigned stride = range->indexArray.stride;
+ unsigned count;
+
+ assert(size);
+ assert(offset < size);
+ assert(stride);
+
+ switch (range->primType) {
+ case SVGA3D_PRIMITIVE_POINTLIST:
+ count = range->primitiveCount;
+ break;
+ case SVGA3D_PRIMITIVE_LINELIST:
+ count = range->primitiveCount * 2;
+ break;
+ case SVGA3D_PRIMITIVE_LINESTRIP:
+ count = range->primitiveCount + 1;
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLELIST:
+ count = range->primitiveCount * 3;
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLESTRIP:
+ count = range->primitiveCount + 2;
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLEFAN:
+ count = range->primitiveCount + 2;
+ break;
+ default:
+ assert(0);
+ count = 0;
+ break;
+ }
+
+ assert(offset + count*stride <= size);
+ }
+ }
+#endif
+
+ if (hwtnl->cmd.prim_count+1 >= QSZ) {
+ ret = svga_hwtnl_flush( hwtnl );
+ if (ret != PIPE_OK)
+ return ret;
+ }
+
+ /* min/max indices are relative to bias */
+ hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index;
+ hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index;
+
+ hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range;
+
+ pipe_buffer_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib);
+ hwtnl->cmd.prim_count++;
+
+ return ret;
+}
diff --git a/src/gallium/drivers/svga/svga_draw.h b/src/gallium/drivers/svga/svga_draw.h
new file mode 100644
index 0000000000..14553b17b5
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_draw.h
@@ -0,0 +1,83 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_DRAW_H
+#define SVGA_DRAW_H
+
+#include "pipe/p_compiler.h"
+
+#include "svga_hw_reg.h"
+
+struct svga_hwtnl;
+struct svga_winsys_context;
+struct svga_screen;
+struct svga_context;
+struct pipe_buffer;
+struct u_upload_mgr;
+
+struct svga_hwtnl *svga_hwtnl_create( struct svga_context *svga,
+ struct u_upload_mgr *upload_ib,
+ struct svga_winsys_context *swc );
+
+void svga_hwtnl_destroy( struct svga_hwtnl *hwtnl );
+
+void svga_hwtnl_set_flatshade( struct svga_hwtnl *hwtnl,
+ boolean flatshade,
+ boolean flatshade_first );
+
+void svga_hwtnl_set_unfilled( struct svga_hwtnl *hwtnl,
+ unsigned mode );
+
+void svga_hwtnl_vdecl( struct svga_hwtnl *hwtnl,
+ unsigned i,
+ const SVGA3dVertexDecl *decl,
+ struct pipe_buffer *vb);
+
+void svga_hwtnl_reset_vdecl( struct svga_hwtnl *hwtnl,
+ unsigned count );
+
+
+enum pipe_error
+svga_hwtnl_draw_arrays( struct svga_hwtnl *hwtnl,
+ unsigned prim,
+ unsigned start,
+ unsigned count);
+
+enum pipe_error
+svga_hwtnl_draw_range_elements( struct svga_hwtnl *hwtnl,
+ struct pipe_buffer *indexBuffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim,
+ unsigned start,
+ unsigned count,
+ unsigned bias );
+
+enum pipe_error
+svga_hwtnl_flush( struct svga_hwtnl *hwtnl );
+
+
+#endif /* SVGA_DRAW_H_ */
diff --git a/src/gallium/drivers/svga/svga_draw_arrays.c b/src/gallium/drivers/svga/svga_draw_arrays.c
new file mode 100644
index 0000000000..75492dffca
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_draw_arrays.c
@@ -0,0 +1,297 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "pipe/p_inlines.h"
+#include "util/u_prim.h"
+#include "indices/u_indices.h"
+
+#include "svga_hw_reg.h"
+#include "svga_draw.h"
+#include "svga_draw_private.h"
+#include "svga_context.h"
+
+
+#define DBG 0
+
+
+
+
+static enum pipe_error generate_indices( struct svga_hwtnl *hwtnl,
+ unsigned nr,
+ unsigned index_size,
+ u_generate_func generate,
+ struct pipe_buffer **out_buf )
+{
+ struct pipe_screen *screen = hwtnl->svga->pipe.screen;
+ unsigned size = index_size * nr;
+ struct pipe_buffer *dst = NULL;
+ void *dst_map = NULL;
+
+ dst = screen->buffer_create( screen, 32,
+ PIPE_BUFFER_USAGE_INDEX |
+ PIPE_BUFFER_USAGE_CPU_WRITE |
+ PIPE_BUFFER_USAGE_GPU_READ,
+ size );
+ if (dst == NULL)
+ goto fail;
+
+ dst_map = pipe_buffer_map( screen, dst, PIPE_BUFFER_USAGE_CPU_WRITE );
+ if (dst_map == NULL)
+ goto fail;
+
+ generate( nr,
+ dst_map );
+
+ pipe_buffer_unmap( screen, dst );
+
+ *out_buf = dst;
+ return PIPE_OK;
+
+fail:
+ if (dst_map)
+ screen->buffer_unmap( screen, dst );
+
+ if (dst)
+ screen->buffer_destroy( dst );
+
+ return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+static boolean compare( unsigned cached_nr,
+ unsigned nr,
+ unsigned type )
+{
+ if (type == U_GENERATE_REUSABLE)
+ return cached_nr >= nr;
+ else
+ return cached_nr == nr;
+}
+
+static enum pipe_error retrieve_or_generate_indices( struct svga_hwtnl *hwtnl,
+ unsigned prim,
+ unsigned gen_type,
+ unsigned gen_nr,
+ unsigned gen_size,
+ u_generate_func generate,
+ struct pipe_buffer **out_buf )
+{
+ enum pipe_error ret = PIPE_OK;
+ int i;
+
+ for (i = 0; i < IDX_CACHE_MAX; i++) {
+ if (hwtnl->index_cache[prim][i].buffer != NULL &&
+ hwtnl->index_cache[prim][i].generate == generate)
+ {
+ if (compare(hwtnl->index_cache[prim][i].gen_nr, gen_nr, gen_type))
+ {
+ pipe_buffer_reference( out_buf,
+ hwtnl->index_cache[prim][i].buffer );
+
+ if (DBG)
+ debug_printf("%s retrieve %d/%d\n", __FUNCTION__, i, gen_nr);
+
+ return PIPE_OK;
+ }
+ else if (gen_type == U_GENERATE_REUSABLE)
+ {
+ pipe_buffer_reference( &hwtnl->index_cache[prim][i].buffer,
+ NULL );
+
+ if (DBG)
+ debug_printf("%s discard %d/%d\n", __FUNCTION__,
+ i, hwtnl->index_cache[prim][i].gen_nr);
+
+ break;
+ }
+ }
+ }
+
+ if (i == IDX_CACHE_MAX)
+ {
+ unsigned smallest = 0;
+ unsigned smallest_size = ~0;
+
+ for (i = 0; i < IDX_CACHE_MAX && smallest_size; i++) {
+ if (hwtnl->index_cache[prim][i].buffer == NULL)
+ {
+ smallest = i;
+ smallest_size = 0;
+ }
+ else if (hwtnl->index_cache[prim][i].gen_nr < smallest)
+ {
+ smallest = i;
+ smallest_size = hwtnl->index_cache[prim][i].gen_nr;
+ }
+ }
+
+ assert (smallest != IDX_CACHE_MAX);
+
+ pipe_buffer_reference( &hwtnl->index_cache[prim][smallest].buffer,
+ NULL );
+
+ if (DBG)
+ debug_printf("%s discard smallest %d/%d\n", __FUNCTION__,
+ smallest, smallest_size);
+
+ i = smallest;
+ }
+
+
+ ret = generate_indices( hwtnl,
+ gen_nr,
+ gen_size,
+ generate,
+ out_buf );
+ if (ret != PIPE_OK)
+ return ret;
+
+
+ hwtnl->index_cache[prim][i].generate = generate;
+ hwtnl->index_cache[prim][i].gen_nr = gen_nr;
+ pipe_buffer_reference( &hwtnl->index_cache[prim][i].buffer,
+ *out_buf );
+
+ if (DBG)
+ debug_printf("%s cache %d/%d\n", __FUNCTION__,
+ i, hwtnl->index_cache[prim][i].gen_nr);
+
+ return PIPE_OK;
+}
+
+
+
+static enum pipe_error
+simple_draw_arrays( struct svga_hwtnl *hwtnl,
+ unsigned prim, unsigned start, unsigned count )
+{
+ SVGA3dPrimitiveRange range;
+ unsigned hw_prim;
+ unsigned hw_count;
+
+ hw_prim = svga_translate_prim(prim, count, &hw_count);
+ if (hw_count == 0)
+ return PIPE_ERROR_BAD_INPUT;
+
+ range.primType = hw_prim;
+ range.primitiveCount = hw_count;
+ range.indexArray.surfaceId = SVGA3D_INVALID_ID;
+ range.indexArray.offset = 0;
+ range.indexArray.stride = 0;
+ range.indexWidth = 0;
+ range.indexBias = start;
+
+ /* Min/max index should be calculated prior to applying bias, so we
+ * end up with min_index = 0, max_index = count - 1 and everybody
+ * looking at those numbers knows to adjust them by
+ * range.indexBias.
+ */
+ return svga_hwtnl_prim( hwtnl, &range, 0, count - 1, NULL );
+}
+
+
+
+
+
+
+
+
+
+
+enum pipe_error
+svga_hwtnl_draw_arrays( struct svga_hwtnl *hwtnl,
+ unsigned prim,
+ unsigned start,
+ unsigned count)
+{
+ unsigned gen_prim, gen_size, gen_nr, gen_type;
+ u_generate_func gen_func;
+ enum pipe_error ret = PIPE_OK;
+
+ if (hwtnl->api_fillmode != PIPE_POLYGON_MODE_FILL &&
+ prim >= PIPE_PRIM_TRIANGLES)
+ {
+ gen_type = u_unfilled_generator( prim,
+ start,
+ count,
+ hwtnl->api_fillmode,
+ &gen_prim,
+ &gen_size,
+ &gen_nr,
+ &gen_func );
+ }
+ else {
+ gen_type = u_index_generator( svga_hw_prims,
+ prim,
+ start,
+ count,
+ hwtnl->api_pv,
+ hwtnl->hw_pv,
+ &gen_prim,
+ &gen_size,
+ &gen_nr,
+ &gen_func );
+ }
+
+ if (gen_type == U_GENERATE_LINEAR) {
+ return simple_draw_arrays( hwtnl, gen_prim, start, count );
+ }
+ else {
+ struct pipe_buffer *gen_buf = NULL;
+
+ /* Need to draw as indexed primitive.
+ * Potentially need to run the gen func to build an index buffer.
+ */
+ ret = retrieve_or_generate_indices( hwtnl,
+ prim,
+ gen_type,
+ gen_nr,
+ gen_size,
+ gen_func,
+ &gen_buf );
+ if (ret)
+ goto done;
+
+ ret = svga_hwtnl_simple_draw_range_elements( hwtnl,
+ gen_buf,
+ gen_size,
+ 0,
+ count - 1,
+ gen_prim,
+ 0,
+ gen_nr,
+ start );
+ if (ret)
+ goto done;
+
+ done:
+ if (gen_buf)
+ pipe_buffer_reference( &gen_buf, NULL );
+
+ return ret;
+ }
+}
+
diff --git a/src/gallium/drivers/svga/svga_draw_elements.c b/src/gallium/drivers/svga/svga_draw_elements.c
new file mode 100644
index 0000000000..167d817831
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_draw_elements.c
@@ -0,0 +1,255 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "util/u_prim.h"
+#include "util/u_upload_mgr.h"
+#include "indices/u_indices.h"
+
+#include "svga_cmd.h"
+#include "svga_draw.h"
+#include "svga_draw_private.h"
+#include "svga_screen_buffer.h"
+#include "svga_winsys.h"
+#include "svga_context.h"
+
+#include "svga_hw_reg.h"
+
+
+static enum pipe_error
+translate_indices( struct svga_hwtnl *hwtnl,
+ struct pipe_buffer *src,
+ unsigned offset,
+ unsigned nr,
+ unsigned index_size,
+ u_translate_func translate,
+ struct pipe_buffer **out_buf )
+{
+ struct pipe_screen *screen = hwtnl->svga->pipe.screen;
+ unsigned size = index_size * nr;
+ const void *src_map = NULL;
+ struct pipe_buffer *dst = NULL;
+ void *dst_map = NULL;
+
+ dst = screen->buffer_create( screen, 32,
+ PIPE_BUFFER_USAGE_INDEX |
+ PIPE_BUFFER_USAGE_CPU_WRITE |
+ PIPE_BUFFER_USAGE_GPU_READ,
+ size );
+ if (dst == NULL)
+ goto fail;
+
+ src_map = pipe_buffer_map( screen, src, PIPE_BUFFER_USAGE_CPU_READ );
+ if (src_map == NULL)
+ goto fail;
+
+ dst_map = pipe_buffer_map( screen, dst, PIPE_BUFFER_USAGE_CPU_WRITE );
+ if (dst_map == NULL)
+ goto fail;
+
+ translate( (const char *)src_map + offset,
+ nr,
+ dst_map );
+
+ pipe_buffer_unmap( screen, src );
+ pipe_buffer_unmap( screen, dst );
+
+ *out_buf = dst;
+ return PIPE_OK;
+
+fail:
+ if (src_map)
+ screen->buffer_unmap( screen, src );
+
+ if (dst_map)
+ screen->buffer_unmap( screen, dst );
+
+ if (dst)
+ screen->buffer_destroy( dst );
+
+ return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+
+
+
+
+enum pipe_error
+svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl,
+ struct pipe_buffer *index_buffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim,
+ unsigned start,
+ unsigned count,
+ unsigned bias )
+{
+ struct pipe_buffer *upload_buffer = NULL;
+ SVGA3dPrimitiveRange range;
+ unsigned hw_prim;
+ unsigned hw_count;
+ unsigned index_offset = start * index_size;
+ int ret = PIPE_OK;
+
+ hw_prim = svga_translate_prim(prim, count, &hw_count);
+ if (hw_count == 0)
+ goto done;
+
+ if (index_buffer &&
+ svga_buffer_is_user_buffer(index_buffer))
+ {
+ assert( index_buffer->size >= index_offset + count * index_size );
+
+ ret = u_upload_buffer( hwtnl->upload_ib,
+ index_offset,
+ count * index_size,
+ index_buffer,
+ &index_offset,
+ &upload_buffer );
+ if (ret)
+ goto done;
+
+ /* Don't need to worry about refcounting index_buffer as this is
+ * just a stack variable without a counted reference of its own.
+ * The caller holds the reference.
+ */
+ index_buffer = upload_buffer;
+ }
+
+ range.primType = hw_prim;
+ range.primitiveCount = hw_count;
+ range.indexArray.offset = index_offset;
+ range.indexArray.stride = index_size;
+ range.indexWidth = index_size;
+ range.indexBias = bias;
+
+ ret = svga_hwtnl_prim( hwtnl, &range, min_index, max_index, index_buffer );
+ if (ret)
+ goto done;
+
+done:
+ if (upload_buffer)
+ pipe_buffer_reference( &upload_buffer, NULL );
+
+ return ret;
+}
+
+
+
+
+enum pipe_error
+svga_hwtnl_draw_range_elements( struct svga_hwtnl *hwtnl,
+ struct pipe_buffer *index_buffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim, unsigned start, unsigned count,
+ unsigned bias)
+{
+ unsigned gen_prim, gen_size, gen_nr, gen_type;
+ u_translate_func gen_func;
+ enum pipe_error ret = PIPE_OK;
+
+ if (hwtnl->api_fillmode != PIPE_POLYGON_MODE_FILL &&
+ prim >= PIPE_PRIM_TRIANGLES)
+ {
+ gen_type = u_unfilled_translator( prim,
+ index_size,
+ count,
+ hwtnl->api_fillmode,
+ &gen_prim,
+ &gen_size,
+ &gen_nr,
+ &gen_func );
+ }
+ else
+ {
+ gen_type = u_index_translator( svga_hw_prims,
+ prim,
+ index_size,
+ count,
+ hwtnl->api_pv,
+ hwtnl->hw_pv,
+ &gen_prim,
+ &gen_size,
+ &gen_nr,
+ &gen_func );
+ }
+
+
+ if (gen_type == U_TRANSLATE_MEMCPY) {
+ /* No need for translation, just pass through to hardware:
+ */
+ return svga_hwtnl_simple_draw_range_elements( hwtnl, index_buffer,
+ index_size,
+ min_index,
+ max_index,
+ gen_prim, start, count, bias );
+ }
+ else {
+ struct pipe_buffer *gen_buf = NULL;
+
+ /* Need to allocate a new index buffer and run the translate
+ * func to populate it. Could potentially cache this translated
+ * index buffer with the original to avoid future
+ * re-translations. Not much point if we're just accelerating
+ * GL though, as index buffers are typically used only once
+ * there.
+ */
+ ret = translate_indices( hwtnl,
+ index_buffer,
+ start * index_size,
+ gen_nr,
+ gen_size,
+ gen_func,
+ &gen_buf );
+ if (ret)
+ goto done;
+
+ ret = svga_hwtnl_simple_draw_range_elements( hwtnl,
+ gen_buf,
+ gen_size,
+ min_index,
+ max_index,
+ gen_prim,
+ 0,
+ gen_nr,
+ bias );
+ if (ret)
+ goto done;
+
+ done:
+ if (gen_buf)
+ pipe_buffer_reference( &gen_buf, NULL );
+
+ return ret;
+ }
+}
+
+
+
+
+
diff --git a/src/gallium/drivers/svga/svga_draw_private.h b/src/gallium/drivers/svga/svga_draw_private.h
new file mode 100644
index 0000000000..9aa40e1664
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_draw_private.h
@@ -0,0 +1,158 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_DRAW_H_
+#define SVGA_DRAW_H_
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_defines.h"
+#include "indices/u_indices.h"
+#include "svga_hw_reg.h"
+#include "svga3d_shaderdefs.h"
+
+struct svga_context;
+struct u_upload_mgr;
+
+/* Should include polygon?
+ */
+static const unsigned svga_hw_prims =
+ ((1 << PIPE_PRIM_POINTS) |
+ (1 << PIPE_PRIM_LINES) |
+ (1 << PIPE_PRIM_LINE_STRIP) |
+ (1 << PIPE_PRIM_TRIANGLES) |
+ (1 << PIPE_PRIM_TRIANGLE_STRIP) |
+ (1 << PIPE_PRIM_TRIANGLE_FAN));
+
+
+static INLINE unsigned svga_translate_prim(unsigned mode,
+ unsigned count,
+ unsigned *out_count)
+{
+ switch (mode) {
+ case PIPE_PRIM_POINTS:
+ *out_count = count;
+ return SVGA3D_PRIMITIVE_POINTLIST;
+
+ case PIPE_PRIM_LINES:
+ *out_count = count / 2;
+ return SVGA3D_PRIMITIVE_LINELIST;
+
+ case PIPE_PRIM_LINE_STRIP:
+ *out_count = count - 1;
+ return SVGA3D_PRIMITIVE_LINESTRIP;
+
+ case PIPE_PRIM_TRIANGLES:
+ *out_count = count / 3;
+ return SVGA3D_PRIMITIVE_TRIANGLELIST;
+
+ case PIPE_PRIM_TRIANGLE_STRIP:
+ *out_count = count - 2;
+ return SVGA3D_PRIMITIVE_TRIANGLESTRIP;
+
+ case PIPE_PRIM_TRIANGLE_FAN:
+ *out_count = count - 2;
+ return SVGA3D_PRIMITIVE_TRIANGLEFAN;
+
+ default:
+ assert(0);
+ *out_count = 0;
+ return 0;
+ }
+}
+
+
+struct index_cache {
+ u_generate_func generate;
+ unsigned gen_nr;
+
+ /* If non-null, this buffer is filled by calling
+ * generate(nr, map(buffer))
+ */
+ struct pipe_buffer *buffer;
+};
+
+#define QSZ 32
+
+struct draw_cmd {
+ struct svga_winsys_context *swc;
+
+ SVGA3dVertexDecl vdecl[SVGA3D_INPUTREG_MAX];
+ struct pipe_buffer *vdecl_vb[SVGA3D_INPUTREG_MAX];
+ unsigned vdecl_count;
+
+ SVGA3dPrimitiveRange prim[QSZ];
+ struct pipe_buffer *prim_ib[QSZ];
+ unsigned prim_count;
+ unsigned min_index[QSZ];
+ unsigned max_index[QSZ];
+};
+
+#define IDX_CACHE_MAX 8
+
+struct svga_hwtnl {
+ struct svga_context *svga;
+ struct u_upload_mgr *upload_ib;
+
+ /* Flatshade information:
+ */
+ unsigned api_pv;
+ unsigned hw_pv;
+ unsigned api_fillmode;
+
+ /* Cache the results of running a particular generate func on each
+ * primitive type.
+ */
+ struct index_cache index_cache[PIPE_PRIM_MAX][IDX_CACHE_MAX];
+
+ /* Try to build the maximal draw command packet before emitting:
+ */
+ struct draw_cmd cmd;
+};
+
+
+
+/***********************************************************************
+ * Internal functions
+ */
+enum pipe_error
+svga_hwtnl_prim( struct svga_hwtnl *hwtnl,
+ const SVGA3dPrimitiveRange *range,
+ unsigned min_index,
+ unsigned max_index,
+ struct pipe_buffer *ib );
+
+enum pipe_error
+svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl,
+ struct pipe_buffer *indexBuffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim,
+ unsigned start,
+ unsigned count,
+ unsigned bias );
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_hw_reg.h b/src/gallium/drivers/svga/svga_hw_reg.h
new file mode 100644
index 0000000000..183f4b918e
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_hw_reg.h
@@ -0,0 +1,42 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_HW_REG_H
+#define SVGA_HW_REG_H
+
+#include "pipe/p_compiler.h"
+
+#if defined(PIPE_CC_GCC)
+#ifndef HAVE_STDINT_H
+#define HAVE_STDINT_H
+#endif
+#endif
+
+#include "svga_types.h"
+
+#include "svga3d_reg.h"
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_pipe_blend.c b/src/gallium/drivers/svga/svga_pipe_blend.c
new file mode 100644
index 0000000000..855d228755
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_blend.c
@@ -0,0 +1,246 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+
+#include "svga_hw_reg.h"
+
+
+static INLINE unsigned
+svga_translate_blend_factor(unsigned factor)
+{
+ switch (factor) {
+ case PIPE_BLENDFACTOR_ZERO: return SVGA3D_BLENDOP_ZERO;
+ case PIPE_BLENDFACTOR_SRC_ALPHA: return SVGA3D_BLENDOP_SRCALPHA;
+ case PIPE_BLENDFACTOR_ONE: return SVGA3D_BLENDOP_ONE;
+ case PIPE_BLENDFACTOR_SRC_COLOR: return SVGA3D_BLENDOP_SRCCOLOR;
+ case PIPE_BLENDFACTOR_INV_SRC_COLOR: return SVGA3D_BLENDOP_INVSRCCOLOR;
+ case PIPE_BLENDFACTOR_DST_COLOR: return SVGA3D_BLENDOP_DESTCOLOR;
+ case PIPE_BLENDFACTOR_INV_DST_COLOR: return SVGA3D_BLENDOP_INVDESTCOLOR;
+ case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return SVGA3D_BLENDOP_INVSRCALPHA;
+ case PIPE_BLENDFACTOR_DST_ALPHA: return SVGA3D_BLENDOP_DESTALPHA;
+ case PIPE_BLENDFACTOR_INV_DST_ALPHA: return SVGA3D_BLENDOP_INVDESTALPHA;
+ case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return SVGA3D_BLENDOP_SRCALPHASAT;
+ case PIPE_BLENDFACTOR_CONST_COLOR: return SVGA3D_BLENDOP_BLENDFACTOR;
+ case PIPE_BLENDFACTOR_INV_CONST_COLOR: return SVGA3D_BLENDOP_INVBLENDFACTOR;
+ case PIPE_BLENDFACTOR_CONST_ALPHA: return SVGA3D_BLENDOP_BLENDFACTOR; /* ? */
+ case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return SVGA3D_BLENDOP_INVBLENDFACTOR; /* ? */
+ default:
+ assert(0);
+ return SVGA3D_BLENDOP_ZERO;
+ }
+}
+
+static INLINE unsigned
+svga_translate_blend_func(unsigned mode)
+{
+ switch (mode) {
+ case PIPE_BLEND_ADD: return SVGA3D_BLENDEQ_ADD;
+ case PIPE_BLEND_SUBTRACT: return SVGA3D_BLENDEQ_SUBTRACT;
+ case PIPE_BLEND_REVERSE_SUBTRACT: return SVGA3D_BLENDEQ_REVSUBTRACT;
+ case PIPE_BLEND_MIN: return SVGA3D_BLENDEQ_MINIMUM;
+ case PIPE_BLEND_MAX: return SVGA3D_BLENDEQ_MAXIMUM;
+ default:
+ assert(0);
+ return SVGA3D_BLENDEQ_ADD;
+ }
+}
+
+
+static void *
+svga_create_blend_state(struct pipe_context *pipe,
+ const struct pipe_blend_state *templ)
+{
+ struct svga_blend_state *blend = CALLOC_STRUCT( svga_blend_state );
+ unsigned i;
+
+
+ /* Fill in the per-rendertarget blend state. We currently only
+ * have one rendertarget.
+ */
+ for (i = 0; i < 1; i++) {
+ /* No way to set this in SVGA3D, and no way to correctly implement it on
+ * top of D3D9 API. Instead we try to simulate with various blend modes.
+ */
+ if (templ->logicop_enable) {
+ switch (templ->logicop_func) {
+ case PIPE_LOGICOP_XOR:
+ blend->need_white_fragments = TRUE;
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_SUBTRACT;
+ break;
+ case PIPE_LOGICOP_CLEAR:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_COPY:
+ blend->rt[i].blend_enable = FALSE;
+ break;
+ case PIPE_LOGICOP_COPY_INVERTED:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_NOOP:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_SET:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_INVERT:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_AND:
+ /* Approximate with minimum - works for the 0 & anything case: */
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_AND_REVERSE:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_AND_INVERTED:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_OR:
+ /* Approximate with maximum - works for the 1 | anything case: */
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_OR_REVERSE:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_OR_INVERTED:
+ blend->rt[i].blend_enable = TRUE;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_NAND:
+ case PIPE_LOGICOP_NOR:
+ case PIPE_LOGICOP_EQUIV:
+ /* Fill these in with plausible values */
+ blend->rt[i].blend_enable = FALSE;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ else {
+ blend->rt[i].blend_enable = templ->blend_enable;
+
+ if (templ->blend_enable) {
+ blend->rt[i].srcblend = svga_translate_blend_factor(templ->rgb_src_factor);
+ blend->rt[i].dstblend = svga_translate_blend_factor(templ->rgb_dst_factor);
+ blend->rt[i].blendeq = svga_translate_blend_func(templ->rgb_func);
+ blend->rt[i].srcblend_alpha = svga_translate_blend_factor(templ->alpha_src_factor);
+ blend->rt[i].dstblend_alpha = svga_translate_blend_factor(templ->alpha_dst_factor);
+ blend->rt[i].blendeq_alpha = svga_translate_blend_func(templ->alpha_func);
+
+ if (blend->rt[i].srcblend_alpha != blend->rt[i].srcblend ||
+ blend->rt[i].dstblend_alpha != blend->rt[i].dstblend ||
+ blend->rt[i].blendeq_alpha != blend->rt[i].blendeq)
+ {
+ blend->rt[i].separate_alpha_blend_enable = TRUE;
+ }
+ }
+ }
+
+ blend->rt[i].writemask = templ->colormask;
+ }
+
+ return blend;
+}
+
+static void svga_bind_blend_state(struct pipe_context *pipe,
+ void *blend)
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.blend = (struct svga_blend_state*)blend;
+ svga->dirty |= SVGA_NEW_BLEND;
+}
+
+
+static void svga_delete_blend_state(struct pipe_context *pipe, void *blend)
+{
+ FREE(blend);
+}
+
+static void svga_set_blend_color( struct pipe_context *pipe,
+ const struct pipe_blend_color *blend_color )
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.blend_color = *blend_color;
+
+ svga->dirty |= SVGA_NEW_BLEND;
+}
+
+
+void svga_init_blend_functions( struct svga_context *svga )
+{
+ svga->pipe.create_blend_state = svga_create_blend_state;
+ svga->pipe.bind_blend_state = svga_bind_blend_state;
+ svga->pipe.delete_blend_state = svga_delete_blend_state;
+
+ svga->pipe.set_blend_color = svga_set_blend_color;
+}
+
+
+
diff --git a/src/gallium/drivers/svga/svga_pipe_blit.c b/src/gallium/drivers/svga/svga_pipe_blit.c
new file mode 100644
index 0000000000..4f575b06e6
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_blit.c
@@ -0,0 +1,92 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_screen_texture.h"
+#include "svga_context.h"
+#include "svga_debug.h"
+#include "svga_cmd.h"
+
+#define FILE_DEBUG_FLAG DEBUG_BLIT
+
+
+static void svga_surface_copy(struct pipe_context *pipe,
+ struct pipe_surface *dest,
+ unsigned destx, unsigned desty,
+ struct pipe_surface *src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
+{
+ struct svga_context *svga = svga_context(pipe);
+ SVGA3dCopyBox *box;
+ enum pipe_error ret;
+
+ svga_hwtnl_flush_retry( svga );
+
+ SVGA_DBG(DEBUG_DMA, "blit to sid %p (%d,%d), from sid %p (%d,%d) sz %dx%d\n",
+ svga_surface(dest)->handle,
+ destx, desty,
+ svga_surface(src)->handle,
+ srcx, srcy,
+ width, height);
+
+ ret = SVGA3D_BeginSurfaceCopy(svga->swc,
+ src,
+ dest,
+ &box,
+ 1);
+ if(ret != PIPE_OK) {
+
+ svga_context_flush(svga, NULL);
+
+ ret = SVGA3D_BeginSurfaceCopy(svga->swc,
+ src,
+ dest,
+ &box,
+ 1);
+ assert(ret == PIPE_OK);
+ }
+
+ box->x = destx;
+ box->y = desty;
+ box->z = 0;
+ box->w = width;
+ box->h = height;
+ box->d = 1;
+ box->srcx = srcx;
+ box->srcy = srcy;
+ box->srcz = 0;
+
+ SVGA_FIFOCommitAll(svga->swc);
+
+ svga_surface(dest)->dirty = TRUE;
+ svga_propagate_surface(pipe, dest);
+}
+
+
+void
+svga_init_blit_functions(struct svga_context *svga)
+{
+ svga->pipe.surface_copy = svga_surface_copy;
+}
diff --git a/src/gallium/drivers/svga/svga_pipe_clear.c b/src/gallium/drivers/svga/svga_pipe_clear.c
new file mode 100644
index 0000000000..6195c3897e
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_clear.c
@@ -0,0 +1,125 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+#include "svga_debug.h"
+
+#include "pipe/p_defines.h"
+#include "util/u_pack_color.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_screen_texture.h"
+
+
+static enum pipe_error
+try_clear(struct svga_context *svga,
+ unsigned buffers,
+ const float *rgba,
+ double depth,
+ unsigned stencil)
+{
+ int ret = PIPE_OK;
+ SVGA3dRect rect = { 0, 0, 0, 0 };
+ boolean restore_viewport = FALSE;
+ SVGA3dClearFlag flags = 0;
+ struct pipe_framebuffer_state *fb = &svga->curr.framebuffer;
+ unsigned color = 0;
+
+ ret = svga_update_state(svga, SVGA_STATE_HW_CLEAR);
+ if (ret)
+ return ret;
+
+ if ((buffers & PIPE_CLEAR_COLOR) && fb->cbufs[0]) {
+ flags |= SVGA3D_CLEAR_COLOR;
+ util_pack_color(rgba, PIPE_FORMAT_A8R8G8B8_UNORM, &color);
+
+ rect.w = fb->cbufs[0]->width;
+ rect.h = fb->cbufs[0]->height;
+ }
+
+ if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && fb->zsbuf) {
+ flags |= SVGA3D_CLEAR_DEPTH;
+
+ if (svga->curr.framebuffer.zsbuf->format == PIPE_FORMAT_Z24S8_UNORM)
+ flags |= SVGA3D_CLEAR_STENCIL;
+
+ rect.w = MAX2(rect.w, fb->zsbuf->width);
+ rect.h = MAX2(rect.h, fb->zsbuf->height);
+ }
+
+ if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) {
+ restore_viewport = TRUE;
+ ret = SVGA3D_SetViewport(svga->swc, &rect);
+ if (ret)
+ return ret;
+ }
+
+ ret = SVGA3D_ClearRect(svga->swc, flags, color, depth, stencil,
+ rect.x, rect.y, rect.w, rect.h);
+ if (ret != PIPE_OK)
+ return ret;
+
+ if (restore_viewport) {
+ memcpy(&rect, &svga->state.hw_clear.viewport, sizeof rect);
+ ret = SVGA3D_SetViewport(svga->swc, &rect);
+ }
+
+ return ret;
+}
+
+/**
+ * Clear the given surface to the specified value.
+ * No masking, no scissor (clear entire buffer).
+ */
+void
+svga_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
+ double depth, unsigned stencil)
+{
+ struct svga_context *svga = svga_context( pipe );
+ int ret;
+
+ if (buffers & PIPE_CLEAR_COLOR)
+ SVGA_DBG(DEBUG_DMA, "clear sid %p\n",
+ svga_surface(svga->curr.framebuffer.cbufs[0])->handle);
+
+ ret = try_clear( svga, buffers, rgba, depth, stencil );
+
+ if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
+ /* Flush command buffer and retry:
+ */
+ svga_context_flush( svga, NULL );
+
+ ret = try_clear( svga, buffers, rgba, depth, stencil );
+ }
+
+ /*
+ * Mark target surfaces as dirty
+ * TODO Mark only cleared surfaces.
+ */
+ svga_mark_surfaces_dirty(svga);
+
+ assert (ret == PIPE_OK);
+}
diff --git a/src/gallium/drivers/svga/svga_pipe_constants.c b/src/gallium/drivers/svga/svga_pipe_constants.c
new file mode 100644
index 0000000000..10e7a12189
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_constants.c
@@ -0,0 +1,74 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_hw_reg.h"
+#include "svga_cmd.h"
+
+/***********************************************************************
+ * Constant buffers
+ */
+
+struct svga_constbuf
+{
+ unsigned type;
+ float (*data)[4];
+ unsigned count;
+};
+
+
+
+static void svga_set_constant_buffer(struct pipe_context *pipe,
+ uint shader, uint index,
+ const struct pipe_constant_buffer *buf)
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ assert(shader < PIPE_SHADER_TYPES);
+ assert(index == 0);
+
+ pipe_buffer_reference( &svga->curr.cb[shader],
+ buf->buffer );
+
+ if (shader == PIPE_SHADER_FRAGMENT)
+ svga->dirty |= SVGA_NEW_FS_CONST_BUFFER;
+ else
+ svga->dirty |= SVGA_NEW_VS_CONST_BUFFER;
+}
+
+
+
+void svga_init_constbuffer_functions( struct svga_context *svga )
+{
+ svga->pipe.set_constant_buffer = svga_set_constant_buffer;
+}
+
diff --git a/src/gallium/drivers/svga/svga_pipe_depthstencil.c b/src/gallium/drivers/svga/svga_pipe_depthstencil.c
new file mode 100644
index 0000000000..df636c08a0
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_depthstencil.c
@@ -0,0 +1,153 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_hw_reg.h"
+
+
+static INLINE unsigned
+svga_translate_compare_func(unsigned func)
+{
+ switch (func) {
+ case PIPE_FUNC_NEVER: return SVGA3D_CMP_NEVER;
+ case PIPE_FUNC_LESS: return SVGA3D_CMP_LESS;
+ case PIPE_FUNC_LEQUAL: return SVGA3D_CMP_LESSEQUAL;
+ case PIPE_FUNC_GREATER: return SVGA3D_CMP_GREATER;
+ case PIPE_FUNC_GEQUAL: return SVGA3D_CMP_GREATEREQUAL;
+ case PIPE_FUNC_NOTEQUAL: return SVGA3D_CMP_NOTEQUAL;
+ case PIPE_FUNC_EQUAL: return SVGA3D_CMP_EQUAL;
+ case PIPE_FUNC_ALWAYS: return SVGA3D_CMP_ALWAYS;
+ default:
+ assert(0);
+ return SVGA3D_CMP_ALWAYS;
+ }
+}
+
+static INLINE unsigned
+svga_translate_stencil_op(unsigned op)
+{
+ switch (op) {
+ case PIPE_STENCIL_OP_KEEP: return SVGA3D_STENCILOP_KEEP;
+ case PIPE_STENCIL_OP_ZERO: return SVGA3D_STENCILOP_ZERO;
+ case PIPE_STENCIL_OP_REPLACE: return SVGA3D_STENCILOP_REPLACE;
+ case PIPE_STENCIL_OP_INCR: return SVGA3D_STENCILOP_INCR;
+ case PIPE_STENCIL_OP_DECR: return SVGA3D_STENCILOP_DECR;
+ case PIPE_STENCIL_OP_INCR_WRAP: return SVGA3D_STENCILOP_INCRSAT; /* incorrect? */
+ case PIPE_STENCIL_OP_DECR_WRAP: return SVGA3D_STENCILOP_DECRSAT; /* incorrect? */
+ case PIPE_STENCIL_OP_INVERT: return SVGA3D_STENCILOP_INVERT;
+ default:
+ assert(0);
+ return SVGA3D_STENCILOP_KEEP;
+ }
+}
+
+
+static void *
+svga_create_depth_stencil_state(struct pipe_context *pipe,
+ const struct pipe_depth_stencil_alpha_state *templ)
+{
+ struct svga_depth_stencil_state *ds = CALLOC_STRUCT( svga_depth_stencil_state );
+
+ /* Don't try to figure out CW/CCW correspondence with
+ * stencil[0]/[1] at this point. Presumably this can change as
+ * back/front face are modified.
+ */
+ ds->stencil[0].enabled = templ->stencil[0].enabled;
+ if (ds->stencil[0].enabled) {
+ ds->stencil[0].func = svga_translate_compare_func(templ->stencil[0].func);
+ ds->stencil[0].fail = svga_translate_stencil_op(templ->stencil[0].fail_op);
+ ds->stencil[0].zfail = svga_translate_stencil_op(templ->stencil[0].zfail_op);
+ ds->stencil[0].pass = svga_translate_stencil_op(templ->stencil[0].zpass_op);
+
+ /* SVGA3D has one ref/mask/writemask triple shared between front &
+ * back face stencil. We really need two:
+ */
+ ds->stencil_ref = templ->stencil[0].ref_value & 0xff;
+ ds->stencil_mask = templ->stencil[0].valuemask & 0xff;
+ ds->stencil_writemask = templ->stencil[0].writemask & 0xff;
+ }
+
+
+ ds->stencil[1].enabled = templ->stencil[1].enabled;
+ if (templ->stencil[1].enabled) {
+ ds->stencil[1].func = svga_translate_compare_func(templ->stencil[1].func);
+ ds->stencil[1].fail = svga_translate_stencil_op(templ->stencil[1].fail_op);
+ ds->stencil[1].zfail = svga_translate_stencil_op(templ->stencil[1].zfail_op);
+ ds->stencil[1].pass = svga_translate_stencil_op(templ->stencil[1].zpass_op);
+
+ ds->stencil_ref = templ->stencil[1].ref_value & 0xff;
+ ds->stencil_mask = templ->stencil[1].valuemask & 0xff;
+ ds->stencil_writemask = templ->stencil[1].writemask & 0xff;
+ }
+
+
+ ds->zenable = templ->depth.enabled;
+ if (ds->zenable) {
+ ds->zfunc = svga_translate_compare_func(templ->depth.func);
+ ds->zwriteenable = templ->depth.writemask;
+ }
+
+ ds->alphatestenable = templ->alpha.enabled;
+ if (ds->alphatestenable) {
+ ds->alphafunc = svga_translate_compare_func(templ->alpha.func);
+ ds->alpharef = templ->alpha.ref_value;
+ }
+
+ return ds;
+}
+
+static void svga_bind_depth_stencil_state(struct pipe_context *pipe,
+ void *depth_stencil)
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil;
+ svga->dirty |= SVGA_NEW_DEPTH_STENCIL;
+}
+
+static void svga_delete_depth_stencil_state(struct pipe_context *pipe,
+ void *depth_stencil)
+{
+ FREE(depth_stencil);
+}
+
+
+
+void svga_init_depth_stencil_functions( struct svga_context *svga )
+{
+ svga->pipe.create_depth_stencil_alpha_state = svga_create_depth_stencil_state;
+ svga->pipe.bind_depth_stencil_alpha_state = svga_bind_depth_stencil_state;
+ svga->pipe.delete_depth_stencil_alpha_state = svga_delete_depth_stencil_state;
+}
+
+
+
+
diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c
new file mode 100644
index 0000000000..71a552862e
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_draw.c
@@ -0,0 +1,261 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "pipe/p_inlines.h"
+#include "util/u_prim.h"
+#include "util/u_time.h"
+#include "indices/u_indices.h"
+
+#include "svga_hw_reg.h"
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_winsys.h"
+#include "svga_draw.h"
+#include "svga_state.h"
+#include "svga_swtnl.h"
+#include "svga_debug.h"
+
+
+
+static enum pipe_error
+retry_draw_range_elements( struct svga_context *svga,
+ struct pipe_buffer *index_buffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim,
+ unsigned start,
+ unsigned count,
+ boolean do_retry )
+{
+ enum pipe_error ret = 0;
+
+ svga_hwtnl_set_unfilled( svga->hwtnl,
+ svga->curr.rast->hw_unfilled );
+
+ svga_hwtnl_set_flatshade( svga->hwtnl,
+ svga->curr.rast->templ.flatshade,
+ svga->curr.rast->templ.flatshade_first );
+
+
+ ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
+ if (ret)
+ goto retry;
+
+ ret = svga_hwtnl_draw_range_elements( svga->hwtnl,
+ index_buffer, index_size,
+ min_index, max_index,
+ prim, start, count, 0 );
+ if (ret)
+ goto retry;
+
+ if (svga->curr.any_user_vertex_buffers) {
+ ret = svga_hwtnl_flush( svga->hwtnl );
+ if (ret)
+ goto retry;
+ }
+
+ return PIPE_OK;
+
+retry:
+ svga_context_flush( svga, NULL );
+
+ if (do_retry)
+ {
+ return retry_draw_range_elements( svga,
+ index_buffer, index_size,
+ min_index, max_index,
+ prim, start, count,
+ FALSE );
+ }
+
+ return ret;
+}
+
+
+static enum pipe_error
+retry_draw_arrays( struct svga_context *svga,
+ unsigned prim,
+ unsigned start,
+ unsigned count,
+ boolean do_retry )
+{
+ enum pipe_error ret;
+
+ svga_hwtnl_set_unfilled( svga->hwtnl,
+ svga->curr.rast->hw_unfilled );
+
+ svga_hwtnl_set_flatshade( svga->hwtnl,
+ svga->curr.rast->templ.flatshade,
+ svga->curr.rast->templ.flatshade_first );
+
+ ret = svga_update_state( svga, SVGA_STATE_HW_DRAW );
+ if (ret)
+ goto retry;
+
+ ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim,
+ start, count );
+ if (ret)
+ goto retry;
+
+ if (svga->curr.any_user_vertex_buffers) {
+ ret = svga_hwtnl_flush( svga->hwtnl );
+ if (ret)
+ goto retry;
+ }
+
+ return 0;
+
+retry:
+ if (ret == PIPE_ERROR_OUT_OF_MEMORY && do_retry)
+ {
+ svga_context_flush( svga, NULL );
+
+ return retry_draw_arrays( svga,
+ prim,
+ start,
+ count,
+ FALSE );
+ }
+
+ return ret;
+}
+
+
+
+
+
+static boolean
+svga_draw_range_elements( struct pipe_context *pipe,
+ struct pipe_buffer *index_buffer,
+ unsigned index_size,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim, unsigned start, unsigned count)
+{
+ struct svga_context *svga = svga_context( pipe );
+ unsigned reduced_prim = u_reduced_prim(prim);
+ enum pipe_error ret = 0;
+
+ if (!u_trim_pipe_prim( prim, &count ))
+ return TRUE;
+
+ /*
+ * Mark currently bound target surfaces as dirty
+ * doesn't really matter if it is done before drawing.
+ *
+ * TODO If we ever normaly return something other then
+ * true we should not mark it as dirty then.
+ */
+ svga_mark_surfaces_dirty(svga_context(pipe));
+
+ if (svga->curr.reduced_prim != reduced_prim) {
+ svga->curr.reduced_prim = reduced_prim;
+ svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
+ }
+
+ svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL );
+
+#ifdef DEBUG
+ if (svga->curr.vs->base.id == svga->debug.disable_shader ||
+ svga->curr.fs->base.id == svga->debug.disable_shader)
+ return 0;
+#endif
+
+ if (svga->state.sw.need_swtnl)
+ {
+ ret = svga_swtnl_draw_range_elements( svga,
+ index_buffer,
+ index_size,
+ min_index, max_index,
+ prim,
+ start, count );
+ }
+ else {
+ if (index_buffer) {
+ ret = retry_draw_range_elements( svga,
+ index_buffer,
+ index_size,
+ min_index,
+ max_index,
+ prim,
+ start,
+ count,
+ TRUE );
+ }
+ else {
+ ret = retry_draw_arrays( svga,
+ prim,
+ start,
+ count,
+ TRUE );
+ }
+ }
+
+ if (SVGA_DEBUG & DEBUG_FLUSH) {
+ static unsigned id;
+ debug_printf("%s %d\n", __FUNCTION__, id++);
+ if (id > 1300)
+ util_time_sleep( 2000 );
+
+ svga_hwtnl_flush_retry( svga );
+ svga_context_flush(svga, NULL);
+ }
+
+ return ret == PIPE_OK;
+}
+
+
+static boolean
+svga_draw_elements( struct pipe_context *pipe,
+ struct pipe_buffer *index_buffer,
+ unsigned index_size,
+ unsigned prim, unsigned start, unsigned count)
+{
+ return svga_draw_range_elements( pipe, index_buffer,
+ index_size,
+ 0, 0xffffffff,
+ prim, start, count );
+}
+
+static boolean
+svga_draw_arrays( struct pipe_context *pipe,
+ unsigned prim, unsigned start, unsigned count)
+{
+ return svga_draw_range_elements(pipe, NULL, 0,
+ start, start + count - 1,
+ prim,
+ start, count);
+}
+
+
+void svga_init_draw_functions( struct svga_context *svga )
+{
+ svga->pipe.draw_arrays = svga_draw_arrays;
+ svga->pipe.draw_elements = svga_draw_elements;
+ svga->pipe.draw_range_elements = svga_draw_range_elements;
+}
diff --git a/src/gallium/drivers/svga/svga_pipe_flush.c b/src/gallium/drivers/svga/svga_pipe_flush.c
new file mode 100644
index 0000000000..0becb0765a
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_flush.c
@@ -0,0 +1,71 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_defines.h"
+#include "svga_screen.h"
+#include "svga_screen_texture.h"
+#include "svga_context.h"
+#include "svga_winsys.h"
+#include "svga_draw.h"
+#include "svga_debug.h"
+
+#include "svga_hw_reg.h"
+
+
+
+
+static void svga_flush( struct pipe_context *pipe,
+ unsigned flags,
+ struct pipe_fence_handle **fence )
+{
+ struct svga_context *svga = svga_context(pipe);
+ int i;
+
+ /* Emit buffered drawing commands.
+ */
+ svga_hwtnl_flush_retry( svga );
+
+ /* Emit back-copy from render target view to texture.
+ */
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (svga->curr.framebuffer.cbufs[i])
+ svga_propagate_surface(pipe, svga->curr.framebuffer.cbufs[i]);
+ }
+ if (svga->curr.framebuffer.zsbuf)
+ svga_propagate_surface(pipe, svga->curr.framebuffer.zsbuf);
+
+ /* Flush command queue.
+ */
+ svga_context_flush(svga, fence);
+
+ SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "%s flags %x fence_ptr %p\n",
+ __FUNCTION__, flags, fence ? *fence : 0x0);
+}
+
+
+void svga_init_flush_functions( struct svga_context *svga )
+{
+ svga->pipe.flush = svga_flush;
+}
diff --git a/src/gallium/drivers/svga/svga_pipe_fs.c b/src/gallium/drivers/svga/svga_pipe_fs.c
new file mode 100644
index 0000000000..e3be840d92
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_fs.c
@@ -0,0 +1,124 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_text.h"
+
+#include "svga_screen.h"
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_tgsi.h"
+#include "svga_hw_reg.h"
+#include "svga_cmd.h"
+#include "svga_draw.h"
+#include "svga_debug.h"
+
+
+/***********************************************************************
+ * Fragment shaders
+ */
+
+static void *
+svga_create_fs_state(struct pipe_context *pipe,
+ const struct pipe_shader_state *templ)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_screen *svgascreen = svga_screen(pipe->screen);
+ struct svga_fragment_shader *fs;
+
+ fs = CALLOC_STRUCT(svga_fragment_shader);
+ if (!fs)
+ return NULL;
+
+ fs->base.tokens = tgsi_dup_tokens(templ->tokens);
+
+ /* Collect basic info that we'll need later:
+ */
+ tgsi_scan_shader(fs->base.tokens, &fs->base.info);
+
+ fs->base.id = svga->debug.shader_id++;
+ fs->base.use_sm30 = svgascreen->use_ps30;
+
+ if (SVGA_DEBUG & DEBUG_TGSI || 0) {
+ debug_printf("%s id: %u, inputs: %u, outputs: %u\n",
+ __FUNCTION__, fs->base.id,
+ fs->base.info.num_inputs, fs->base.info.num_outputs);
+ }
+
+ return fs;
+}
+
+static void
+svga_bind_fs_state(struct pipe_context *pipe, void *shader)
+{
+ struct svga_fragment_shader *fs = (struct svga_fragment_shader *) shader;
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.fs = fs;
+ svga->dirty |= SVGA_NEW_FS;
+}
+
+static
+void svga_delete_fs_state(struct pipe_context *pipe, void *shader)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_fragment_shader *fs = (struct svga_fragment_shader *) shader;
+ struct svga_shader_result *result, *tmp;
+ enum pipe_error ret;
+
+ svga_hwtnl_flush_retry( svga );
+
+ for (result = fs->base.results; result; result = tmp ) {
+ tmp = result->next;
+
+ ret = SVGA3D_DestroyShader(svga->swc,
+ result->id,
+ SVGA3D_SHADERTYPE_PS );
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_DestroyShader(svga->swc,
+ result->id,
+ SVGA3D_SHADERTYPE_PS );
+ assert(ret == PIPE_OK);
+ }
+
+ svga_destroy_shader_result( result );
+ }
+
+ FREE((void *)fs->base.tokens);
+ FREE(fs);
+}
+
+
+void svga_init_fs_functions( struct svga_context *svga )
+{
+ svga->pipe.create_fs_state = svga_create_fs_state;
+ svga->pipe.bind_fs_state = svga_bind_fs_state;
+ svga->pipe.delete_fs_state = svga_delete_fs_state;
+}
+
diff --git a/src/gallium/drivers/svga/svga_pipe_misc.c b/src/gallium/drivers/svga/svga_pipe_misc.c
new file mode 100644
index 0000000000..58cb1e6e23
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_misc.c
@@ -0,0 +1,187 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "svga_context.h"
+#include "svga_screen_texture.h"
+#include "svga_state.h"
+#include "svga_winsys.h"
+
+#include "svga_hw_reg.h"
+
+
+
+
+static void svga_set_scissor_state( struct pipe_context *pipe,
+ const struct pipe_scissor_state *scissor )
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ memcpy( &svga->curr.scissor, scissor, sizeof(*scissor) );
+ svga->dirty |= SVGA_NEW_SCISSOR;
+}
+
+
+static void svga_set_polygon_stipple( struct pipe_context *pipe,
+ const struct pipe_poly_stipple *stipple )
+{
+ /* overridden by the draw module */
+}
+
+
+void svga_cleanup_framebuffer(struct svga_context *svga)
+{
+ struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
+ struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
+ int i;
+
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ pipe_surface_reference(&curr->cbufs[i], NULL);
+ pipe_surface_reference(&hw->cbufs[i], NULL);
+ }
+
+ pipe_surface_reference(&curr->zsbuf, NULL);
+ pipe_surface_reference(&hw->zsbuf, NULL);
+}
+
+
+#define DEPTH_BIAS_SCALE_FACTOR_D16 ((float)(1<<15))
+#define DEPTH_BIAS_SCALE_FACTOR_D24S8 ((float)(1<<23))
+#define DEPTH_BIAS_SCALE_FACTOR_D32 ((float)(1<<31))
+
+
+static void svga_set_framebuffer_state(struct pipe_context *pipe,
+ const struct pipe_framebuffer_state *fb)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct pipe_framebuffer_state *dst = &svga->curr.framebuffer;
+ boolean propagate = FALSE;
+ int i;
+
+ dst->width = fb->width;
+ dst->height = fb->height;
+ dst->nr_cbufs = fb->nr_cbufs;
+
+ /* check if we need to propaget any of the target surfaces */
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (dst->cbufs[i] && dst->cbufs[i] != fb->cbufs[i])
+ if (svga_surface_needs_propagation(dst->cbufs[i]))
+ propagate = TRUE;
+ }
+
+ if (propagate) {
+ /* make sure that drawing calls comes before propagation calls */
+ svga_hwtnl_flush_retry( svga );
+
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+ if (dst->cbufs[i] && dst->cbufs[i] != fb->cbufs[i])
+ svga_propagate_surface(pipe, dst->cbufs[i]);
+ }
+
+ /* XXX: Actually the virtual hardware may support rendertargets with
+ * different size, depending on the host API and driver, but since we cannot
+ * know that make no such assumption here. */
+ for(i = 0; i < fb->nr_cbufs; ++i) {
+ if (fb->zsbuf && fb->cbufs[i]) {
+ assert(fb->zsbuf->width == fb->cbufs[i]->width);
+ assert(fb->zsbuf->height == fb->cbufs[i]->height);
+ }
+ }
+
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+ pipe_surface_reference(&dst->cbufs[i], fb->cbufs[i]);
+ pipe_surface_reference(&dst->zsbuf, fb->zsbuf);
+
+
+ if (svga->curr.framebuffer.zsbuf)
+ {
+ switch (svga->curr.framebuffer.zsbuf->format) {
+ case PIPE_FORMAT_Z16_UNORM:
+ svga->curr.depthscale = 1.0f / DEPTH_BIAS_SCALE_FACTOR_D16;
+ break;
+ case PIPE_FORMAT_S8Z24_UNORM:
+ case PIPE_FORMAT_X8Z24_UNORM:
+ case PIPE_FORMAT_Z24S8_UNORM:
+ case PIPE_FORMAT_Z24X8_UNORM:
+ svga->curr.depthscale = 1.0f / DEPTH_BIAS_SCALE_FACTOR_D24S8;
+ break;
+ case PIPE_FORMAT_Z32_UNORM:
+ svga->curr.depthscale = 1.0f / DEPTH_BIAS_SCALE_FACTOR_D32;
+ break;
+ case PIPE_FORMAT_Z32_FLOAT:
+ svga->curr.depthscale = 1.0f / ((float)(1<<23));
+ break;
+ default:
+ svga->curr.depthscale = 0.0f;
+ break;
+ }
+ }
+ else {
+ svga->curr.depthscale = 0.0f;
+ }
+
+ svga->dirty |= SVGA_NEW_FRAME_BUFFER;
+}
+
+
+
+static void svga_set_clip_state( struct pipe_context *pipe,
+ const struct pipe_clip_state *clip )
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.clip = *clip; /* struct copy */
+
+ svga->dirty |= SVGA_NEW_CLIP;
+}
+
+
+
+/* Called when driver state tracker notices changes to the viewport
+ * matrix:
+ */
+static void svga_set_viewport_state( struct pipe_context *pipe,
+ const struct pipe_viewport_state *viewport )
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.viewport = *viewport; /* struct copy */
+
+ svga->dirty |= SVGA_NEW_VIEWPORT;
+}
+
+
+
+void svga_init_misc_functions( struct svga_context *svga )
+{
+ svga->pipe.set_scissor_state = svga_set_scissor_state;
+ svga->pipe.set_polygon_stipple = svga_set_polygon_stipple;
+ svga->pipe.set_framebuffer_state = svga_set_framebuffer_state;
+ svga->pipe.set_clip_state = svga_set_clip_state;
+ svga->pipe.set_viewport_state = svga_set_viewport_state;
+}
+
+
diff --git a/src/gallium/drivers/svga/svga_pipe_query.c b/src/gallium/drivers/svga/svga_pipe_query.c
new file mode 100644
index 0000000000..01336b0a2c
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_query.c
@@ -0,0 +1,267 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_state.h"
+#include "pipe/p_context.h"
+#include "util/u_memory.h"
+
+#include "svga_cmd.h"
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_screen_buffer.h"
+#include "svga_winsys.h"
+#include "svga_draw.h"
+#include "svga_debug.h"
+
+
+/* Fixme: want a public base class for all pipe structs, even if there
+ * isn't much in them.
+ */
+struct pipe_query {
+ int dummy;
+};
+
+struct svga_query {
+ struct pipe_query base;
+ SVGA3dQueryType type;
+ struct svga_winsys_buffer *hwbuf;
+ volatile SVGA3dQueryResult *queryResult;
+ struct pipe_fence_handle *fence;
+};
+
+/***********************************************************************
+ * Inline conversion functions. These are better-typed than the
+ * macros used previously:
+ */
+static INLINE struct svga_query *
+svga_query( struct pipe_query *q )
+{
+ return (struct svga_query *)q;
+}
+
+static boolean svga_get_query_result(struct pipe_context *pipe,
+ struct pipe_query *q,
+ boolean wait,
+ uint64_t *result);
+
+static struct pipe_query *svga_create_query( struct pipe_context *pipe,
+ unsigned query_type )
+{
+ struct svga_screen *svgascreen = svga_screen(pipe->screen);
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_query *sq;
+
+ SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__);
+
+ sq = CALLOC_STRUCT(svga_query);
+ if (!sq)
+ goto no_sq;
+
+ sq->type = SVGA3D_QUERYTYPE_OCCLUSION;
+
+ sq->hwbuf = svga_winsys_buffer_create(svgascreen,
+ 1,
+ SVGA_BUFFER_USAGE_PINNED,
+ sizeof *sq->queryResult);
+ if(!sq->hwbuf)
+ goto no_hwbuf;
+
+ sq->queryResult = (SVGA3dQueryResult *)sws->buffer_map(sws,
+ sq->hwbuf,
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+ if(!sq->queryResult)
+ goto no_query_result;
+
+ sq->queryResult->totalSize = sizeof *sq->queryResult;
+ sq->queryResult->state = SVGA3D_QUERYSTATE_NEW;
+
+ /*
+ * We request the buffer to be pinned and assume it is always mapped.
+ *
+ * The reason is that we don't want to wait for fences when checking the
+ * query status.
+ */
+ sws->buffer_unmap(sws, sq->hwbuf);
+
+ return &sq->base;
+
+no_query_result:
+ sws->buffer_destroy(sws, sq->hwbuf);
+no_hwbuf:
+ FREE(sq);
+no_sq:
+ return NULL;
+}
+
+static void svga_destroy_query(struct pipe_context *pipe,
+ struct pipe_query *q)
+{
+ struct svga_screen *svgascreen = svga_screen(pipe->screen);
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_query *sq = svga_query( q );
+
+ SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__);
+ sws->buffer_destroy(sws, sq->hwbuf);
+ sws->fence_reference(sws, &sq->fence, NULL);
+ FREE(sq);
+}
+
+static void svga_begin_query(struct pipe_context *pipe,
+ struct pipe_query *q)
+{
+ struct svga_screen *svgascreen = svga_screen(pipe->screen);
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_context *svga = svga_context( pipe );
+ struct svga_query *sq = svga_query( q );
+ enum pipe_error ret;
+
+ SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__);
+
+ assert(!svga->sq);
+
+ /* Need to flush out buffered drawing commands so that they don't
+ * get counted in the query results.
+ */
+ svga_hwtnl_flush_retry(svga);
+
+ if(sq->queryResult->state == SVGA3D_QUERYSTATE_PENDING) {
+ /* The application doesn't care for the pending query result. We cannot
+ * let go the existing buffer and just get a new one because its storage
+ * may be reused for other purposes and clobbered by the host when it
+ * determines the query result. So the only option here is to wait for
+ * the existing query's result -- not a big deal, given that no sane
+ * application would do this.
+ */
+ uint64_t result;
+
+ svga_get_query_result(pipe, q, TRUE, &result);
+
+ assert(sq->queryResult->state != SVGA3D_QUERYSTATE_PENDING);
+ }
+
+ sq->queryResult->state = SVGA3D_QUERYSTATE_NEW;
+ sws->fence_reference(sws, &sq->fence, NULL);
+
+ ret = SVGA3D_BeginQuery(svga->swc, sq->type);
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_BeginQuery(svga->swc, sq->type);
+ assert(ret == PIPE_OK);
+ }
+
+ svga->sq = sq;
+}
+
+static void svga_end_query(struct pipe_context *pipe,
+ struct pipe_query *q)
+{
+ struct svga_context *svga = svga_context( pipe );
+ struct svga_query *sq = svga_query( q );
+ enum pipe_error ret;
+
+ SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__);
+ assert(svga->sq == sq);
+
+ svga_hwtnl_flush_retry(svga);
+
+ /* Set to PENDING before sending EndQuery. */
+ sq->queryResult->state = SVGA3D_QUERYSTATE_PENDING;
+
+ ret = SVGA3D_EndQuery( svga->swc, sq->type, sq->hwbuf);
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_EndQuery( svga->swc, sq->type, sq->hwbuf);
+ assert(ret == PIPE_OK);
+ }
+
+ /* TODO: Delay flushing. We don't really need to flush here, just ensure
+ * that there is one flush before svga_get_query_result attempts to get the
+ * result */
+ svga_context_flush(svga, NULL);
+
+ svga->sq = NULL;
+}
+
+static boolean svga_get_query_result(struct pipe_context *pipe,
+ struct pipe_query *q,
+ boolean wait,
+ uint64_t *result)
+{
+ struct svga_context *svga = svga_context( pipe );
+ struct svga_screen *svgascreen = svga_screen( pipe->screen );
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_query *sq = svga_query( q );
+ SVGA3dQueryState state;
+
+ SVGA_DBG(DEBUG_QUERY, "%s wait: %d\n", __FUNCTION__);
+
+ /* The query status won't be updated by the host unless
+ * SVGA_3D_CMD_WAIT_FOR_QUERY is emitted. Unfortunately this will cause a
+ * synchronous wait on the host */
+ if(!sq->fence) {
+ enum pipe_error ret;
+
+ ret = SVGA3D_WaitForQuery( svga->swc, sq->type, sq->hwbuf);
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_WaitForQuery( svga->swc, sq->type, sq->hwbuf);
+ assert(ret == PIPE_OK);
+ }
+
+ svga_context_flush(svga, &sq->fence);
+
+ assert(sq->fence);
+ }
+
+ state = sq->queryResult->state;
+ if(state == SVGA3D_QUERYSTATE_PENDING) {
+ if(!wait)
+ return FALSE;
+
+ sws->fence_finish(sws, sq->fence, 0);
+
+ state = sq->queryResult->state;
+ }
+
+ assert(state == SVGA3D_QUERYSTATE_SUCCEEDED ||
+ state == SVGA3D_QUERYSTATE_FAILED);
+
+ *result = (uint64_t)sq->queryResult->result32;
+
+ SVGA_DBG(DEBUG_QUERY, "%s result %d\n", __FUNCTION__, (unsigned)*result);
+
+ return TRUE;
+}
+
+
+
+void svga_init_query_functions( struct svga_context *svga )
+{
+ svga->pipe.create_query = svga_create_query;
+ svga->pipe.destroy_query = svga_destroy_query;
+ svga->pipe.begin_query = svga_begin_query;
+ svga->pipe.end_query = svga_end_query;
+ svga->pipe.get_query_result = svga_get_query_result;
+}
diff --git a/src/gallium/drivers/svga/svga_pipe_rasterizer.c b/src/gallium/drivers/svga/svga_pipe_rasterizer.c
new file mode 100644
index 0000000000..b03f8eb9cf
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_rasterizer.c
@@ -0,0 +1,250 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "draw/draw_context.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+
+#include "svga_hw_reg.h"
+
+/* Hardware frontwinding is always set up as SVGA3D_FRONTWINDING_CW.
+ */
+static SVGA3dFace svga_translate_cullmode( unsigned mode,
+ unsigned front_winding )
+{
+ switch (mode) {
+ case PIPE_WINDING_NONE:
+ return SVGA3D_FACE_NONE;
+ case PIPE_WINDING_CCW:
+ return SVGA3D_FACE_BACK;
+ case PIPE_WINDING_CW:
+ return SVGA3D_FACE_FRONT;
+ case PIPE_WINDING_BOTH:
+ return SVGA3D_FACE_FRONT_BACK;
+ default:
+ assert(0);
+ return SVGA3D_FACE_NONE;
+ }
+}
+
+static SVGA3dShadeMode svga_translate_flatshade( unsigned mode )
+{
+ return mode ? SVGA3D_SHADEMODE_FLAT : SVGA3D_SHADEMODE_SMOOTH;
+}
+
+
+static void *
+svga_create_rasterizer_state(struct pipe_context *pipe,
+ const struct pipe_rasterizer_state *templ)
+{
+ struct svga_rasterizer_state *rast = CALLOC_STRUCT( svga_rasterizer_state );
+ /* need this for draw module. */
+ rast->templ = *templ;
+
+ /* light_twoside - XXX: need fragment shader varient */
+ /* poly_smooth - XXX: no fallback available */
+ /* poly_stipple_enable - draw module */
+ /* point_sprite - ? */
+ /* point_size_per_vertex - ? */
+ /* sprite_coord_mode - ??? */
+ /* bypass_vs_viewport_and_clip - handled by viewport setup */
+ /* flatshade_first - handled by index translation */
+ /* gl_rasterization_rules - XXX - viewport code */
+ /* line_width - draw module */
+ /* fill_cw, fill_ccw - draw module or index translation */
+
+ rast->shademode = svga_translate_flatshade( templ->flatshade );
+ rast->cullmode = svga_translate_cullmode( templ->cull_mode,
+ templ->front_winding );
+ rast->scissortestenable = templ->scissor;
+ rast->multisampleantialias = templ->multisample;
+ rast->antialiasedlineenable = templ->line_smooth;
+ rast->lastpixel = templ->line_last_pixel;
+ rast->pointsize = templ->point_size;
+ rast->pointsize_min = templ->point_size_min;
+ rast->pointsize_max = templ->point_size_max;
+ rast->hw_unfilled = PIPE_POLYGON_MODE_FILL;
+
+ /* Use swtnl + decomposition implement these:
+ */
+ if (templ->poly_stipple_enable)
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+
+ if (templ->line_width != 1.0 &&
+ templ->line_width != 0.0)
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_LINES;
+
+ if (templ->line_stipple_enable) {
+ /* LinePattern not implemented on all backends.
+ */
+ if (0) {
+ SVGA3dLinePattern lp;
+ lp.repeat = templ->line_stipple_factor + 1;
+ lp.pattern = templ->line_stipple_pattern;
+ rast->linepattern = lp.uintValue;
+ }
+ else {
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_LINES;
+ }
+ }
+
+ if (templ->point_smooth)
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_POINTS;
+
+ {
+ boolean offset_cw = templ->offset_cw;
+ boolean offset_ccw = templ->offset_ccw;
+ boolean offset = 0;
+ int fill_cw = templ->fill_cw;
+ int fill_ccw = templ->fill_ccw;
+ int fill = PIPE_POLYGON_MODE_FILL;
+
+ switch (templ->cull_mode) {
+ case PIPE_WINDING_BOTH:
+ offset = 0;
+ fill = PIPE_POLYGON_MODE_FILL;
+ break;
+
+ case PIPE_WINDING_CW:
+ offset = offset_ccw;
+ fill = fill_ccw;
+ break;
+
+ case PIPE_WINDING_CCW:
+ offset = offset_cw;
+ fill = fill_cw;
+ break;
+
+ case PIPE_WINDING_NONE:
+ if (fill_cw != fill_ccw || offset_cw != offset_ccw)
+ {
+ /* Always need the draw module to work out different
+ * front/back fill modes:
+ */
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+ }
+ else {
+ offset = offset_ccw;
+ fill = fill_ccw;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ /* Unfilled primitive modes aren't implemented on all virtual
+ * hardware. We can do some unfilled processing with index
+ * translation, but otherwise need the draw module:
+ */
+ if (fill != PIPE_POLYGON_MODE_FILL &&
+ (templ->flatshade ||
+ templ->light_twoside ||
+ offset ||
+ templ->cull_mode != PIPE_WINDING_NONE))
+ {
+ fill = PIPE_POLYGON_MODE_FILL;
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+ }
+
+ /* If we are decomposing to lines, and lines need the pipeline,
+ * then we also need the pipeline for tris.
+ */
+ if (fill == PIPE_POLYGON_MODE_LINE &&
+ (rast->need_pipeline & SVGA_PIPELINE_FLAG_LINES))
+ {
+ fill = PIPE_POLYGON_MODE_FILL;
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+ }
+
+ /* Similarly for points:
+ */
+ if (fill == PIPE_POLYGON_MODE_POINT &&
+ (rast->need_pipeline & SVGA_PIPELINE_FLAG_POINTS))
+ {
+ fill = PIPE_POLYGON_MODE_FILL;
+ rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+ }
+
+ if (offset) {
+ rast->slopescaledepthbias = templ->offset_scale;
+ rast->depthbias = templ->offset_units;
+ }
+
+ rast->hw_unfilled = fill;
+ }
+
+
+
+
+ if (rast->need_pipeline & SVGA_PIPELINE_FLAG_TRIS) {
+ /* Turn off stuff which will get done in the draw module:
+ */
+ rast->hw_unfilled = PIPE_POLYGON_MODE_FILL;
+ rast->slopescaledepthbias = 0;
+ rast->depthbias = 0;
+ }
+
+ return rast;
+}
+
+static void svga_bind_rasterizer_state( struct pipe_context *pipe,
+ void *state )
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_rasterizer_state *raster = (struct svga_rasterizer_state *)state;
+
+ svga->curr.rast = raster;
+
+ draw_set_rasterizer_state(svga->swtnl.draw, raster ? &raster->templ : NULL);
+
+ svga->dirty |= SVGA_NEW_RAST;
+}
+
+static void svga_delete_rasterizer_state(struct pipe_context *pipe,
+ void *raster)
+{
+ FREE(raster);
+}
+
+
+void svga_init_rasterizer_functions( struct svga_context *svga )
+{
+ svga->pipe.create_rasterizer_state = svga_create_rasterizer_state;
+ svga->pipe.bind_rasterizer_state = svga_bind_rasterizer_state;
+ svga->pipe.delete_rasterizer_state = svga_delete_rasterizer_state;
+}
+
+
+/***********************************************************************
+ * Hardware state update
+ */
+
diff --git a/src/gallium/drivers/svga/svga_pipe_sampler.c b/src/gallium/drivers/svga/svga_pipe_sampler.c
new file mode 100644
index 0000000000..b4e57c5d15
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_sampler.c
@@ -0,0 +1,243 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/u_pack_color.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_context.h"
+#include "svga_screen_texture.h"
+#include "svga_state.h"
+
+#include "svga_hw_reg.h"
+
+#include "svga_debug.h"
+
+static INLINE unsigned
+translate_wrap_mode(unsigned wrap)
+{
+ switch (wrap) {
+ case PIPE_TEX_WRAP_REPEAT:
+ return SVGA3D_TEX_ADDRESS_WRAP;
+
+ case PIPE_TEX_WRAP_CLAMP:
+ return SVGA3D_TEX_ADDRESS_CLAMP;
+
+ case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+ /* Unfortunately SVGA3D_TEX_ADDRESS_EDGE not respected by
+ * hardware.
+ */
+ return SVGA3D_TEX_ADDRESS_CLAMP;
+
+ case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+ return SVGA3D_TEX_ADDRESS_BORDER;
+
+ case PIPE_TEX_WRAP_MIRROR_REPEAT:
+ return SVGA3D_TEX_ADDRESS_MIRROR;
+
+ case PIPE_TEX_WRAP_MIRROR_CLAMP:
+ case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
+ case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
+ return SVGA3D_TEX_ADDRESS_MIRRORONCE;
+
+ default:
+ assert(0);
+ return SVGA3D_TEX_ADDRESS_WRAP;
+ }
+}
+
+static INLINE unsigned translate_img_filter( unsigned filter )
+{
+ switch (filter) {
+ case PIPE_TEX_FILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST;
+ case PIPE_TEX_FILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR;
+ case PIPE_TEX_FILTER_ANISO: return SVGA3D_TEX_FILTER_ANISOTROPIC;
+ default:
+ assert(0);
+ return SVGA3D_TEX_FILTER_NEAREST;
+ }
+}
+
+static INLINE unsigned translate_mip_filter( unsigned filter )
+{
+ switch (filter) {
+ case PIPE_TEX_MIPFILTER_NONE: return SVGA3D_TEX_FILTER_NONE;
+ case PIPE_TEX_MIPFILTER_NEAREST: return SVGA3D_TEX_FILTER_NEAREST;
+ case PIPE_TEX_MIPFILTER_LINEAR: return SVGA3D_TEX_FILTER_LINEAR;
+ default:
+ assert(0);
+ return SVGA3D_TEX_FILTER_NONE;
+ }
+}
+
+static void *
+svga_create_sampler_state(struct pipe_context *pipe,
+ const struct pipe_sampler_state *sampler)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_sampler_state *cso = CALLOC_STRUCT( svga_sampler_state );
+
+ cso->mipfilter = translate_mip_filter(sampler->min_mip_filter);
+ cso->magfilter = translate_img_filter( sampler->mag_img_filter );
+ cso->minfilter = translate_img_filter( sampler->min_img_filter );
+ cso->aniso_level = MAX2( (unsigned) sampler->max_anisotropy, 1 );
+ cso->lod_bias = sampler->lod_bias;
+ cso->addressu = translate_wrap_mode(sampler->wrap_s);
+ cso->addressv = translate_wrap_mode(sampler->wrap_t);
+ cso->addressw = translate_wrap_mode(sampler->wrap_r);
+ cso->normalized_coords = sampler->normalized_coords;
+ cso->compare_mode = sampler->compare_mode;
+ cso->compare_func = sampler->compare_func;
+
+ {
+ ubyte r = float_to_ubyte(sampler->border_color[0]);
+ ubyte g = float_to_ubyte(sampler->border_color[1]);
+ ubyte b = float_to_ubyte(sampler->border_color[2]);
+ ubyte a = float_to_ubyte(sampler->border_color[3]);
+
+ util_pack_color_ub( r, g, b, a,
+ PIPE_FORMAT_B8G8R8A8_UNORM,
+ &cso->bordercolor );
+ }
+
+ /* No SVGA3D support for:
+ * - min/max LOD clamping
+ */
+ cso->min_lod = 0;
+ cso->view_min_lod = MAX2(sampler->min_lod, 0);
+ cso->view_max_lod = MAX2(sampler->max_lod, 0);
+
+ /* Use min_mipmap */
+ if (svga->debug.use_min_mipmap) {
+ if (cso->view_min_lod == cso->view_max_lod) {
+ cso->min_lod = cso->view_min_lod;
+ cso->view_min_lod = 0;
+ cso->view_max_lod = 1000; /* Just a high number */
+ cso->mipfilter = SVGA3D_TEX_FILTER_NONE;
+ }
+ }
+
+ SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n",
+ cso->min_lod, cso->view_min_lod, cso->view_max_lod,
+ cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING");
+
+ return cso;
+}
+
+static void svga_bind_sampler_states(struct pipe_context *pipe,
+ unsigned num, void **sampler)
+{
+ struct svga_context *svga = svga_context(pipe);
+ unsigned i;
+
+ assert(num <= PIPE_MAX_SAMPLERS);
+
+ /* Check for no-op */
+ if (num == svga->curr.num_samplers &&
+ !memcmp(svga->curr.sampler, sampler, num * sizeof(void *))) {
+ debug_printf("sampler noop\n");
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ svga->curr.sampler[i] = sampler[i];
+
+ for (i = num; i < svga->curr.num_samplers; i++)
+ svga->curr.sampler[i] = NULL;
+
+ svga->curr.num_samplers = num;
+ svga->dirty |= SVGA_NEW_SAMPLER;
+}
+
+static void svga_delete_sampler_state(struct pipe_context *pipe,
+ void *sampler)
+{
+ FREE(sampler);
+}
+
+
+static void svga_set_sampler_textures(struct pipe_context *pipe,
+ unsigned num,
+ struct pipe_texture **texture)
+{
+ struct svga_context *svga = svga_context(pipe);
+ unsigned flag_1d = 0;
+ unsigned flag_srgb = 0;
+ uint i;
+
+ assert(num <= PIPE_MAX_SAMPLERS);
+
+ /* Check for no-op */
+ if (num == svga->curr.num_textures &&
+ !memcmp(svga->curr.texture, texture, num * sizeof(struct pipe_texture *))) {
+ if (0) debug_printf("texture noop\n");
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ pipe_texture_reference(&svga->curr.texture[i],
+ texture[i]);
+
+ if (!texture[i])
+ continue;
+
+ if (texture[i]->format == PIPE_FORMAT_A8R8G8B8_SRGB)
+ flag_srgb |= 1 << i;
+
+ if (texture[i]->target == PIPE_TEXTURE_1D)
+ flag_1d |= 1 << i;
+ }
+
+ for (i = num; i < svga->curr.num_textures; i++)
+ pipe_texture_reference(&svga->curr.texture[i],
+ NULL);
+
+ svga->curr.num_textures = num;
+ svga->dirty |= SVGA_NEW_TEXTURE_BINDING;
+
+ if (flag_srgb != svga->curr.tex_flags.flag_srgb ||
+ flag_1d != svga->curr.tex_flags.flag_1d)
+ {
+ svga->dirty |= SVGA_NEW_TEXTURE_FLAGS;
+ svga->curr.tex_flags.flag_1d = flag_1d;
+ svga->curr.tex_flags.flag_srgb = flag_srgb;
+ }
+}
+
+
+
+void svga_init_sampler_functions( struct svga_context *svga )
+{
+ svga->pipe.create_sampler_state = svga_create_sampler_state;
+ svga->pipe.bind_fragment_sampler_states = svga_bind_sampler_states;
+ svga->pipe.delete_sampler_state = svga_delete_sampler_state;
+ svga->pipe.set_fragment_sampler_textures = svga_set_sampler_textures;
+}
+
+
+
diff --git a/src/gallium/drivers/svga/svga_pipe_vertex.c b/src/gallium/drivers/svga/svga_pipe_vertex.c
new file mode 100644
index 0000000000..28e2787e0d
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_vertex.c
@@ -0,0 +1,115 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+
+#include "svga_screen.h"
+#include "svga_screen_buffer.h"
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_winsys.h"
+
+#include "svga_hw_reg.h"
+
+
+static void svga_set_vertex_buffers(struct pipe_context *pipe,
+ unsigned count,
+ const struct pipe_vertex_buffer *buffers)
+{
+ struct svga_context *svga = svga_context(pipe);
+ unsigned i;
+ boolean any_user_buffer = FALSE;
+
+ /* Check for no change */
+ if (count == svga->curr.num_vertex_buffers &&
+ memcmp(svga->curr.vb, buffers, count * sizeof buffers[0]) == 0)
+ return;
+
+ /* Adjust refcounts */
+ for (i = 0; i < count; i++) {
+ pipe_buffer_reference(&svga->curr.vb[i].buffer, buffers[i].buffer);
+ if (svga_buffer(buffers[i].buffer)->user)
+ any_user_buffer = TRUE;
+ }
+
+ for ( ; i < svga->curr.num_vertex_buffers; i++)
+ pipe_buffer_reference(&svga->curr.vb[i].buffer, NULL);
+
+ /* Copy remaining data */
+ memcpy(svga->curr.vb, buffers, count * sizeof buffers[0]);
+ svga->curr.num_vertex_buffers = count;
+ svga->curr.any_user_vertex_buffers = any_user_buffer;
+
+ svga->dirty |= SVGA_NEW_VBUFFER;
+}
+
+static void svga_set_vertex_elements(struct pipe_context *pipe,
+ unsigned count,
+ const struct pipe_vertex_element *elements)
+{
+ struct svga_context *svga = svga_context(pipe);
+ unsigned i;
+
+ for (i = 0; i < count; i++)
+ svga->curr.ve[i] = elements[i];
+
+ svga->curr.num_vertex_elements = count;
+ svga->dirty |= SVGA_NEW_VELEMENT;
+}
+
+
+static void svga_set_edgeflags(struct pipe_context *pipe,
+ const unsigned *bitfield)
+{
+ struct svga_context *svga = svga_context(pipe);
+
+ if (bitfield != NULL || svga->curr.edgeflags != NULL) {
+ svga->curr.edgeflags = bitfield;
+ svga->dirty |= SVGA_NEW_EDGEFLAGS;
+ }
+}
+
+
+void svga_cleanup_vertex_state( struct svga_context *svga )
+{
+ unsigned i;
+
+ for (i = 0 ; i < svga->curr.num_vertex_buffers; i++)
+ pipe_buffer_reference(&svga->curr.vb[i].buffer, NULL);
+}
+
+
+void svga_init_vertex_functions( struct svga_context *svga )
+{
+ svga->pipe.set_vertex_buffers = svga_set_vertex_buffers;
+ svga->pipe.set_vertex_elements = svga_set_vertex_elements;
+ svga->pipe.set_edgeflags = svga_set_edgeflags;
+}
+
+
diff --git a/src/gallium/drivers/svga/svga_pipe_vs.c b/src/gallium/drivers/svga/svga_pipe_vs.c
new file mode 100644
index 0000000000..c104c41f5f
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_pipe_vs.c
@@ -0,0 +1,189 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "draw/draw_context.h"
+#include "pipe/p_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_text.h"
+
+#include "svga_screen.h"
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_tgsi.h"
+#include "svga_hw_reg.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+
+
+static const struct tgsi_token *substitute_vs(
+ unsigned shader_id,
+ const struct tgsi_token *old_tokens )
+{
+#if 0
+ if (shader_id == 12) {
+ static struct tgsi_token tokens[300];
+
+ const char *text =
+ "VERT\n"
+ "DCL IN[0]\n"
+ "DCL IN[1]\n"
+ "DCL IN[2]\n"
+ "DCL OUT[0], POSITION\n"
+ "DCL TEMP[0..4]\n"
+ "IMM FLT32 { 1.0000, 1.0000, 1.0000, 1.0000 }\n"
+ "IMM FLT32 { 0.45, 1.0000, 1.0000, 1.0000 }\n"
+ "IMM FLT32 { 1.297863, 0.039245, 0.035993, 0.035976}\n"
+ "IMM FLT32 { -0.019398, 1.696131, -0.202151, -0.202050 }\n"
+ "IMM FLT32 { 0.051711, -0.348713, -0.979204, -0.978714 }\n"
+ "IMM FLT32 { 0.000000, 0.000003, 139.491577, 141.421356 }\n"
+ "DCL CONST[0..7]\n"
+ "DCL CONST[9..16]\n"
+ " MOV TEMP[2], IMM[0]\n"
+
+ " MOV TEMP[2].xyz, IN[2]\n"
+ " MOV TEMP[2].xyz, IN[0]\n"
+ " MOV TEMP[2].xyz, IN[1]\n"
+
+ " MUL TEMP[1], IMM[3], TEMP[2].yyyy\n"
+ " MAD TEMP[3], IMM[2], TEMP[2].xxxx, TEMP[1]\n"
+ " MAD TEMP[1], IMM[4], TEMP[2].zzzz, TEMP[3]\n"
+ " MAD TEMP[4], IMM[5], TEMP[2].wwww, TEMP[1]\n"
+
+ " MOV OUT[0], TEMP[4]\n"
+ " END\n";
+
+ if (!tgsi_text_translate( text,
+ tokens,
+ Elements(tokens) ))
+ {
+ assert(0);
+ return NULL;
+ }
+
+ return tokens;
+ }
+#endif
+
+ return old_tokens;
+}
+
+
+/***********************************************************************
+ * Vertex shaders
+ */
+
+static void *
+svga_create_vs_state(struct pipe_context *pipe,
+ const struct pipe_shader_state *templ)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_screen *svgascreen = svga_screen(pipe->screen);
+ struct svga_vertex_shader *vs = CALLOC_STRUCT(svga_vertex_shader);
+ if (!vs)
+ return NULL;
+
+ /* substitute a debug shader?
+ */
+ vs->base.tokens = tgsi_dup_tokens(substitute_vs(svga->debug.shader_id,
+ templ->tokens));
+
+
+ /* Collect basic info that we'll need later:
+ */
+ tgsi_scan_shader(vs->base.tokens, &vs->base.info);
+
+ {
+ /* Need to do construct a new template in case we substitued a
+ * debug shader.
+ */
+ struct pipe_shader_state tmp2 = *templ;
+ tmp2.tokens = vs->base.tokens;
+ vs->draw_shader = draw_create_vertex_shader(svga->swtnl.draw, &tmp2);
+ }
+
+ vs->base.id = svga->debug.shader_id++;
+ vs->base.use_sm30 = svgascreen->use_vs30;
+
+ if (SVGA_DEBUG & DEBUG_TGSI || 0) {
+ debug_printf("%s id: %u, inputs: %u, outputs: %u\n",
+ __FUNCTION__, vs->base.id,
+ vs->base.info.num_inputs, vs->base.info.num_outputs);
+ }
+
+ return vs;
+}
+
+static void svga_bind_vs_state(struct pipe_context *pipe, void *shader)
+{
+ struct svga_vertex_shader *vs = (struct svga_vertex_shader *)shader;
+ struct svga_context *svga = svga_context(pipe);
+
+ svga->curr.vs = vs;
+ svga->dirty |= SVGA_NEW_VS;
+}
+
+
+static void svga_delete_vs_state(struct pipe_context *pipe, void *shader)
+{
+ struct svga_context *svga = svga_context(pipe);
+ struct svga_vertex_shader *vs = (struct svga_vertex_shader *)shader;
+ struct svga_shader_result *result, *tmp;
+ enum pipe_error ret;
+
+ svga_hwtnl_flush_retry( svga );
+
+ draw_delete_vertex_shader(svga->swtnl.draw, vs->draw_shader);
+
+ for (result = vs->base.results; result; result = tmp ) {
+ tmp = result->next;
+
+ ret = SVGA3D_DestroyShader(svga->swc,
+ result->id,
+ SVGA3D_SHADERTYPE_VS );
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_DestroyShader(svga->swc,
+ result->id,
+ SVGA3D_SHADERTYPE_VS );
+ assert(ret == PIPE_OK);
+ }
+
+ svga_destroy_shader_result( result );
+ }
+
+ FREE((void *)vs->base.tokens);
+ FREE(vs);
+}
+
+
+void svga_init_vs_functions( struct svga_context *svga )
+{
+ svga->pipe.create_vs_state = svga_create_vs_state;
+ svga->pipe.bind_vs_state = svga_bind_vs_state;
+ svga->pipe.delete_vs_state = svga_delete_vs_state;
+}
+
diff --git a/src/gallium/drivers/svga/svga_screen.c b/src/gallium/drivers/svga/svga_screen.c
new file mode 100644
index 0000000000..fc1b3c980e
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen.c
@@ -0,0 +1,440 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "util/u_memory.h"
+#include "pipe/p_inlines.h"
+#include "util/u_string.h"
+#include "util/u_math.h"
+
+#include "svga_winsys.h"
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_screen_texture.h"
+#include "svga_screen_buffer.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+
+#include "svga_hw_reg.h"
+#include "svga3d_shaderdefs.h"
+
+
+#ifdef DEBUG
+int SVGA_DEBUG = 0;
+
+static const struct debug_named_value svga_debug_flags[] = {
+ { "dma", DEBUG_DMA },
+ { "tgsi", DEBUG_TGSI },
+ { "pipe", DEBUG_PIPE },
+ { "state", DEBUG_STATE },
+ { "screen", DEBUG_SCREEN },
+ { "tex", DEBUG_TEX },
+ { "swtnl", DEBUG_SWTNL },
+ { "const", DEBUG_CONSTS },
+ { "viewport", DEBUG_VIEWPORT },
+ { "views", DEBUG_VIEWS },
+ { "perf", DEBUG_PERF },
+ { "flush", DEBUG_FLUSH },
+ { "sync", DEBUG_SYNC },
+ { "cache", DEBUG_CACHE },
+ {NULL, 0}
+};
+#endif
+
+static const char *
+svga_get_vendor( struct pipe_screen *pscreen )
+{
+ return "VMware, Inc.";
+}
+
+
+static const char *
+svga_get_name( struct pipe_screen *pscreen )
+{
+#ifdef DEBUG
+ /* Only return internal details in the DEBUG version:
+ */
+ return "SVGA3D; build: DEBUG; mutex: " PIPE_ATOMIC;
+#else
+ return "SVGA3D; build: RELEASE; ";
+#endif
+}
+
+
+
+
+static float
+svga_get_paramf(struct pipe_screen *screen, int param)
+{
+ struct svga_screen *svgascreen = svga_screen(screen);
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ SVGA3dDevCapResult result;
+
+ switch (param) {
+ case PIPE_CAP_MAX_LINE_WIDTH:
+ /* fall-through */
+ case PIPE_CAP_MAX_LINE_WIDTH_AA:
+ return 7.0;
+
+ case PIPE_CAP_MAX_POINT_WIDTH:
+ /* fall-through */
+ case PIPE_CAP_MAX_POINT_WIDTH_AA:
+ /* Keep this to a reasonable size to avoid failures in
+ * conform/pntaa.c:
+ */
+ return 80.0;
+
+ case PIPE_CAP_MAX_TEXTURE_ANISOTROPY:
+ return 4.0;
+
+ case PIPE_CAP_MAX_TEXTURE_LOD_BIAS:
+ return 16.0;
+
+ case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
+ return 16;
+ case PIPE_CAP_NPOT_TEXTURES:
+ return 1;
+ case PIPE_CAP_TWO_SIDED_STENCIL:
+ return 1;
+ case PIPE_CAP_GLSL:
+ return svgascreen->use_ps30 && svgascreen->use_vs30;
+ case PIPE_CAP_ANISOTROPIC_FILTER:
+ return 1;
+ case PIPE_CAP_POINT_SPRITE:
+ return 1;
+ case PIPE_CAP_MAX_RENDER_TARGETS:
+ if(!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_RENDER_TARGETS, &result))
+ return 1;
+ if(!result.u)
+ return 1;
+ return MIN2(result.u, PIPE_MAX_COLOR_BUFS);
+ case PIPE_CAP_OCCLUSION_QUERY:
+ return 1;
+ case PIPE_CAP_TEXTURE_SHADOW_MAP:
+ return 1;
+ case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
+ return SVGA_MAX_TEXTURE_LEVELS;
+ case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
+ return 8; /* max 128x128x128 */
+ case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
+ return SVGA_MAX_TEXTURE_LEVELS;
+
+ case PIPE_CAP_TEXTURE_MIRROR_REPEAT: /* req. for GL 1.4 */
+ return 1;
+
+ case PIPE_CAP_BLEND_EQUATION_SEPARATE: /* req. for GL 1.5 */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+/* This is a fairly pointless interface
+ */
+static int
+svga_get_param(struct pipe_screen *screen, int param)
+{
+ return (int) svga_get_paramf( screen, param );
+}
+
+
+static INLINE SVGA3dDevCapIndex
+svga_translate_format_cap(enum pipe_format format)
+{
+ switch(format) {
+
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8;
+ case PIPE_FORMAT_X8R8G8B8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8;
+
+ case PIPE_FORMAT_R5G6B5_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_R5G6B5;
+ case PIPE_FORMAT_A1R5G5B5_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5;
+ case PIPE_FORMAT_A4R4G4B4_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4;
+
+ case PIPE_FORMAT_Z16_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_Z_D16;
+ case PIPE_FORMAT_Z24S8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8;
+ case PIPE_FORMAT_Z24X8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8;
+
+ case PIPE_FORMAT_A8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_ALPHA8;
+ case PIPE_FORMAT_L8_UNORM:
+ return SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8;
+
+ case PIPE_FORMAT_DXT1_RGB:
+ case PIPE_FORMAT_DXT1_RGBA:
+ return SVGA3D_DEVCAP_SURFACEFMT_DXT1;
+ case PIPE_FORMAT_DXT3_RGBA:
+ return SVGA3D_DEVCAP_SURFACEFMT_DXT3;
+ case PIPE_FORMAT_DXT5_RGBA:
+ return SVGA3D_DEVCAP_SURFACEFMT_DXT5;
+
+ default:
+ return SVGA3D_DEVCAP_MAX;
+ }
+}
+
+
+static boolean
+svga_is_format_supported( struct pipe_screen *screen,
+ enum pipe_format format,
+ enum pipe_texture_target target,
+ unsigned tex_usage,
+ unsigned geom_flags )
+{
+ struct svga_winsys_screen *sws = svga_screen(screen)->sws;
+ SVGA3dDevCapIndex index;
+ SVGA3dDevCapResult result;
+
+ assert(tex_usage);
+
+ /* Override host capabilities */
+ if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) {
+ switch(format) {
+
+ /* Often unsupported/problematic. This means we end up with the same
+ * visuals for all virtual hardware implementations.
+ */
+ case PIPE_FORMAT_A4R4G4B4_UNORM:
+ case PIPE_FORMAT_A1R5G5B5_UNORM:
+ return FALSE;
+
+ /* Simulate ability to render into compressed textures */
+ case PIPE_FORMAT_DXT1_RGB:
+ case PIPE_FORMAT_DXT1_RGBA:
+ case PIPE_FORMAT_DXT3_RGBA:
+ case PIPE_FORMAT_DXT5_RGBA:
+ return TRUE;
+
+ default:
+ break;
+ }
+ }
+
+ /* Try to query the host */
+ index = svga_translate_format_cap(format);
+ if( index < SVGA3D_DEVCAP_MAX &&
+ sws->get_cap(sws, index, &result) )
+ {
+ SVGA3dSurfaceFormatCaps mask;
+
+ mask.value = 0;
+ if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET)
+ mask.offscreenRenderTarget = 1;
+ if (tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL)
+ mask.zStencil = 1;
+ if (tex_usage & PIPE_TEXTURE_USAGE_SAMPLER)
+ mask.texture = 1;
+
+ if ((result.u & mask.value) == mask.value)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* Use our translate functions directly rather than relying on a
+ * duplicated list of supported formats which is prone to getting
+ * out of sync:
+ */
+ if(tex_usage & (PIPE_TEXTURE_USAGE_RENDER_TARGET | PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
+ return svga_translate_format_render(format) != SVGA3D_FORMAT_INVALID;
+ else
+ return svga_translate_format(format) != SVGA3D_FORMAT_INVALID;
+}
+
+
+static void
+svga_fence_reference(struct pipe_screen *screen,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+ struct svga_winsys_screen *sws = svga_screen(screen)->sws;
+ sws->fence_reference(sws, ptr, fence);
+}
+
+
+static int
+svga_fence_signalled(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ struct svga_winsys_screen *sws = svga_screen(screen)->sws;
+ return sws->fence_signalled(sws, fence, flag);
+}
+
+
+static int
+svga_fence_finish(struct pipe_screen *screen,
+ struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ struct svga_winsys_screen *sws = svga_screen(screen)->sws;
+
+ SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "%s fence_ptr %p\n",
+ __FUNCTION__, fence);
+
+ return sws->fence_finish(sws, fence, flag);
+}
+
+
+static void
+svga_destroy_screen( struct pipe_screen *screen )
+{
+ struct svga_screen *svgascreen = svga_screen(screen);
+
+ svga_screen_cache_cleanup(svgascreen);
+
+ pipe_mutex_destroy(svgascreen->swc_mutex);
+ pipe_mutex_destroy(svgascreen->tex_mutex);
+
+ svgascreen->swc->destroy(svgascreen->swc);
+
+ svgascreen->sws->destroy(svgascreen->sws);
+
+ FREE(svgascreen);
+}
+
+
+/**
+ * Create a new svga_screen object
+ */
+struct pipe_screen *
+svga_screen_create(struct svga_winsys_screen *sws)
+{
+ struct svga_screen *svgascreen;
+ struct pipe_screen *screen;
+ SVGA3dDevCapResult result;
+
+#ifdef DEBUG
+ SVGA_DEBUG = debug_get_flags_option("SVGA_DEBUG", svga_debug_flags, 0 );
+#endif
+
+ svgascreen = CALLOC_STRUCT(svga_screen);
+ if (!svgascreen)
+ goto error1;
+
+ svgascreen->debug.force_level_surface_view =
+ debug_get_bool_option("SVGA_FORCE_LEVEL_SURFACE_VIEW", FALSE);
+ svgascreen->debug.force_surface_view =
+ debug_get_bool_option("SVGA_FORCE_SURFACE_VIEW", FALSE);
+ svgascreen->debug.force_sampler_view =
+ debug_get_bool_option("SVGA_FORCE_SAMPLER_VIEW", FALSE);
+ svgascreen->debug.no_surface_view =
+ debug_get_bool_option("SVGA_NO_SURFACE_VIEW", FALSE);
+ svgascreen->debug.no_sampler_view =
+ debug_get_bool_option("SVGA_NO_SAMPLER_VIEW", FALSE);
+
+ screen = &svgascreen->screen;
+
+ screen->destroy = svga_destroy_screen;
+ screen->get_name = svga_get_name;
+ screen->get_vendor = svga_get_vendor;
+ screen->get_param = svga_get_param;
+ screen->get_paramf = svga_get_paramf;
+ screen->is_format_supported = svga_is_format_supported;
+ screen->fence_reference = svga_fence_reference;
+ screen->fence_signalled = svga_fence_signalled;
+ screen->fence_finish = svga_fence_finish;
+ svgascreen->sws = sws;
+
+ svga_screen_init_texture_functions(screen);
+ svga_screen_init_buffer_functions(screen);
+
+ svgascreen->use_ps30 =
+ sws->get_cap(sws, SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION, &result) &&
+ result.u >= SVGA3DPSVERSION_30 ? TRUE : FALSE;
+
+ svgascreen->use_vs30 =
+ sws->get_cap(sws, SVGA3D_DEVCAP_VERTEX_SHADER_VERSION, &result) &&
+ result.u >= SVGA3DVSVERSION_30 ? TRUE : FALSE;
+
+#if 1
+ /* Shader model 2.0 is unsupported at the moment. */
+ if(!svgascreen->use_ps30 || !svgascreen->use_vs30)
+ goto error2;
+#else
+ if(debug_get_bool_option("SVGA_NO_SM30", FALSE))
+ svgascreen->use_vs30 = svgascreen->use_ps30 = FALSE;
+#endif
+
+ svgascreen->swc = sws->context_create(sws);
+ if(!svgascreen->swc)
+ goto error2;
+
+ pipe_mutex_init(svgascreen->tex_mutex);
+ pipe_mutex_init(svgascreen->swc_mutex);
+
+ LIST_INITHEAD(&svgascreen->cached_buffers);
+
+ svga_screen_cache_init(svgascreen);
+
+ return screen;
+error2:
+ FREE(svgascreen);
+error1:
+ return NULL;
+}
+
+void svga_screen_flush( struct svga_screen *svgascreen,
+ struct pipe_fence_handle **pfence )
+{
+ struct pipe_fence_handle *fence = NULL;
+
+ SVGA_DBG(DEBUG_PERF, "%s\n", __FUNCTION__);
+
+ pipe_mutex_lock(svgascreen->swc_mutex);
+ svgascreen->swc->flush(svgascreen->swc, &fence);
+ pipe_mutex_unlock(svgascreen->swc_mutex);
+
+ svga_screen_cache_flush(svgascreen, fence);
+
+ if(pfence)
+ *pfence = fence;
+ else
+ svgascreen->sws->fence_reference(svgascreen->sws, &fence, NULL);
+}
+
+struct svga_winsys_screen *
+svga_winsys_screen(struct pipe_screen *screen)
+{
+ return svga_screen(screen)->sws;
+}
+
+#ifdef DEBUG
+struct svga_screen *
+svga_screen(struct pipe_screen *screen)
+{
+ assert(screen);
+ assert(screen->destroy == svga_destroy_screen);
+ return (struct svga_screen *)screen;
+}
+#endif
diff --git a/src/gallium/drivers/svga/svga_screen.h b/src/gallium/drivers/svga/svga_screen.h
new file mode 100644
index 0000000000..b94ca7fc1c
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen.h
@@ -0,0 +1,95 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_SCREEN_H
+#define SVGA_SCREEN_H
+
+
+#include "pipe/p_screen.h"
+#include "pipe/p_thread.h"
+
+#include "util/u_double_list.h"
+
+#include "svga_screen_cache.h"
+
+
+struct svga_winsys_screen;
+struct svga_winsys_context;
+struct SVGACmdMemory;
+
+#define SVGA_COMBINE_USERBUFFERS 1
+
+/**
+ * Subclass of pipe_screen
+ */
+struct svga_screen
+{
+ struct pipe_screen screen;
+ struct svga_winsys_screen *sws;
+
+ unsigned use_ps30;
+ unsigned use_vs30;
+
+ struct {
+ boolean force_level_surface_view;
+ boolean force_surface_view;
+ boolean no_surface_view;
+ boolean force_sampler_view;
+ boolean no_sampler_view;
+ } debug;
+
+ /* The screen needs its own context */
+ struct svga_winsys_context *swc;
+ struct SVGACmdMemory *fifo;
+
+ unsigned texture_timestamp;
+ pipe_mutex tex_mutex;
+ pipe_mutex swc_mutex; /* Protects the use of swc and dirty_buffers */
+
+ /**
+ * List of buffers with cached GMR. Ordered from the most recently used to
+ * the least recently used
+ */
+ struct list_head cached_buffers;
+
+ struct svga_host_surface_cache cache;
+};
+
+#ifndef DEBUG
+/** cast wrapper */
+static INLINE struct svga_screen *
+svga_screen(struct pipe_screen *pscreen)
+{
+ return (struct svga_screen *) pscreen;
+}
+#else
+struct svga_screen *
+svga_screen(struct pipe_screen *screen);
+#endif
+
+void svga_screen_flush( struct svga_screen *svga_screen,
+ struct pipe_fence_handle **pfence );
+
+#endif /* SVGA_SCREEN_H */
diff --git a/src/gallium/drivers/svga/svga_screen_buffer.c b/src/gallium/drivers/svga/svga_screen_buffer.c
new file mode 100644
index 0000000000..1f8a889672
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_buffer.c
@@ -0,0 +1,824 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_thread.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_screen_buffer.h"
+#include "svga_winsys.h"
+#include "svga_debug.h"
+
+
+/**
+ * Vertex and index buffers have to be treated slightly differently from
+ * regular guest memory regions because the SVGA device sees them as
+ * surfaces, and the state tracker can create/destroy without the pipe
+ * driver, therefore we must do the uploads from the vws.
+ */
+static INLINE boolean
+svga_buffer_needs_hw_storage(unsigned usage)
+{
+ return usage & (PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_INDEX);
+}
+
+
+static INLINE enum pipe_error
+svga_buffer_create_host_surface(struct svga_screen *ss,
+ struct svga_buffer *sbuf)
+{
+ if(!sbuf->handle) {
+ sbuf->key.flags = 0;
+
+ sbuf->key.format = SVGA3D_BUFFER;
+ if(sbuf->base.usage & PIPE_BUFFER_USAGE_VERTEX)
+ sbuf->key.flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER;
+ if(sbuf->base.usage & PIPE_BUFFER_USAGE_INDEX)
+ sbuf->key.flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER;
+
+ sbuf->key.size.width = sbuf->base.size;
+ sbuf->key.size.height = 1;
+ sbuf->key.size.depth = 1;
+
+ sbuf->key.numFaces = 1;
+ sbuf->key.numMipLevels = 1;
+ sbuf->key.cachable = 1;
+
+ SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n", sbuf->base.size);
+
+ sbuf->handle = svga_screen_surface_create(ss, &sbuf->key);
+ if(!sbuf->handle)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ /* Always set the discard flag on the first time the buffer is written
+ * as svga_screen_surface_create might have passed a recycled host
+ * buffer.
+ */
+ sbuf->hw.flags.discard = TRUE;
+
+ SVGA_DBG(DEBUG_DMA, " --> got sid %p sz %d (buffer)\n", sbuf->handle, sbuf->base.size);
+ }
+
+ return PIPE_OK;
+}
+
+
+static INLINE void
+svga_buffer_destroy_host_surface(struct svga_screen *ss,
+ struct svga_buffer *sbuf)
+{
+ if(sbuf->handle) {
+ SVGA_DBG(DEBUG_DMA, " ungrab sid %p sz %d\n", sbuf->handle, sbuf->base.size);
+ svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle);
+ }
+}
+
+
+static INLINE void
+svga_buffer_destroy_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf)
+{
+ struct svga_winsys_screen *sws = ss->sws;
+
+ assert(!sbuf->map.count);
+ assert(sbuf->hw.buf);
+ if(sbuf->hw.buf) {
+ sws->buffer_destroy(sws, sbuf->hw.buf);
+ sbuf->hw.buf = NULL;
+ assert(sbuf->head.prev && sbuf->head.next);
+ LIST_DEL(&sbuf->head);
+#ifdef DEBUG
+ sbuf->head.next = sbuf->head.prev = NULL;
+#endif
+ }
+}
+
+static INLINE enum pipe_error
+svga_buffer_backup(struct svga_screen *ss, struct svga_buffer *sbuf)
+{
+ if (sbuf->hw.buf && sbuf->hw.num_ranges) {
+ void *src;
+
+ if (!sbuf->swbuf)
+ sbuf->swbuf = align_malloc(sbuf->base.size, sbuf->base.alignment);
+ if (!sbuf->swbuf)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ src = ss->sws->buffer_map(ss->sws, sbuf->hw.buf,
+ PIPE_BUFFER_USAGE_CPU_READ);
+ if (!src)
+ return PIPE_ERROR;
+
+ memcpy(sbuf->swbuf, src, sbuf->base.size);
+ ss->sws->buffer_unmap(ss->sws, sbuf->hw.buf);
+ }
+
+ return PIPE_OK;
+}
+
+/**
+ * Try to make GMR space available by freeing the hardware storage of
+ * unmapped
+ */
+boolean
+svga_buffer_free_cached_hw_storage(struct svga_screen *ss)
+{
+ struct list_head *curr;
+ struct svga_buffer *sbuf;
+ enum pipe_error ret = PIPE_OK;
+
+ curr = ss->cached_buffers.prev;
+
+ /* free the least recently used buffer's hw storage which is not mapped */
+ do {
+ if(curr == &ss->cached_buffers)
+ return FALSE;
+
+ sbuf = LIST_ENTRY(struct svga_buffer, curr, head);
+
+ curr = curr->prev;
+ if (sbuf->map.count == 0)
+ ret = svga_buffer_backup(ss, sbuf);
+
+ } while(sbuf->map.count != 0 || ret != PIPE_OK);
+
+ svga_buffer_destroy_hw_storage(ss, sbuf);
+
+ return TRUE;
+}
+
+struct svga_winsys_buffer *
+svga_winsys_buffer_create( struct svga_screen *ss,
+ unsigned alignment,
+ unsigned usage,
+ unsigned size )
+{
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_winsys_buffer *buf;
+
+ /* Just try */
+ buf = sws->buffer_create(sws, alignment, usage, size);
+ if(!buf) {
+
+ SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "flushing screen to find %d bytes GMR\n",
+ size);
+
+ /* Try flushing all pending DMAs */
+ svga_screen_flush(ss, NULL);
+ buf = sws->buffer_create(sws, alignment, usage, size);
+
+ SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "evicting buffers to find %d bytes GMR\n",
+ size);
+
+ /* Try evicing all buffer storage */
+ while(!buf && svga_buffer_free_cached_hw_storage(ss))
+ buf = sws->buffer_create(sws, alignment, usage, size);
+ }
+
+ return buf;
+}
+
+
+/**
+ * Allocate DMA'ble storage for the buffer.
+ *
+ * Called before mapping a buffer.
+ */
+static INLINE enum pipe_error
+svga_buffer_create_hw_storage(struct svga_screen *ss,
+ struct svga_buffer *sbuf)
+{
+ if(!sbuf->hw.buf) {
+ unsigned alignment = sbuf->base.alignment;
+ unsigned usage = 0;
+ unsigned size = sbuf->base.size;
+
+ sbuf->hw.buf = svga_winsys_buffer_create(ss, alignment, usage, size);
+ if(!sbuf->hw.buf)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ assert(!sbuf->needs_flush);
+ assert(!sbuf->head.prev && !sbuf->head.next);
+ LIST_ADD(&sbuf->head, &ss->cached_buffers);
+ }
+
+ return PIPE_OK;
+}
+
+
+/**
+ * Variant of SVGA3D_BufferDMA which leaves the copy box temporarily in blank.
+ */
+static enum pipe_error
+svga_buffer_upload_command(struct svga_context *svga,
+ struct svga_buffer *sbuf)
+{
+ struct svga_winsys_context *swc = svga->swc;
+ struct svga_winsys_buffer *guest = sbuf->hw.buf;
+ struct svga_winsys_surface *host = sbuf->handle;
+ SVGA3dTransferType transfer = SVGA3D_WRITE_HOST_VRAM;
+ SVGA3dSurfaceDMAFlags flags = sbuf->hw.flags;
+ SVGA3dCmdSurfaceDMA *cmd;
+ uint32 numBoxes = sbuf->hw.num_ranges;
+ SVGA3dCopyBox *boxes;
+ SVGA3dCmdSurfaceDMASuffix *pSuffix;
+ unsigned region_flags;
+ unsigned surface_flags;
+ struct pipe_buffer *dummy;
+
+ if(transfer == SVGA3D_WRITE_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ }
+ else if(transfer == SVGA3D_READ_HOST_VRAM) {
+ region_flags = PIPE_BUFFER_USAGE_GPU_WRITE;
+ surface_flags = PIPE_BUFFER_USAGE_GPU_READ;
+ }
+ else {
+ assert(0);
+ return PIPE_ERROR_BAD_INPUT;
+ }
+
+ assert(numBoxes);
+
+ cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_SURFACE_DMA,
+ sizeof *cmd + numBoxes * sizeof *boxes + sizeof *pSuffix,
+ 2);
+ if(!cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ swc->region_relocation(swc, &cmd->guest.ptr, guest, 0, region_flags);
+ cmd->guest.pitch = 0;
+
+ swc->surface_relocation(swc, &cmd->host.sid, host, surface_flags);
+ cmd->host.face = 0;
+ cmd->host.mipmap = 0;
+
+ cmd->transfer = transfer;
+
+ sbuf->hw.boxes = (SVGA3dCopyBox *)&cmd[1];
+ sbuf->hw.svga = svga;
+
+ /* Increment reference count */
+ dummy = NULL;
+ pipe_buffer_reference(&dummy, &sbuf->base);
+
+ pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + numBoxes * sizeof *boxes);
+ pSuffix->suffixSize = sizeof *pSuffix;
+ pSuffix->maximumOffset = sbuf->base.size;
+ pSuffix->flags = flags;
+
+ swc->commit(swc);
+
+ return PIPE_OK;
+}
+
+
+/**
+ * Patch up the upload DMA command reserved by svga_buffer_upload_command
+ * with the final ranges.
+ */
+static void
+svga_buffer_upload_flush(struct svga_context *svga,
+ struct svga_buffer *sbuf)
+{
+ struct svga_screen *ss = svga_screen(svga->pipe.screen);
+ SVGA3dCopyBox *boxes;
+ unsigned i;
+
+ assert(sbuf->handle);
+ assert(sbuf->hw.buf);
+ assert(sbuf->hw.num_ranges);
+ assert(sbuf->hw.svga == svga);
+ assert(sbuf->hw.boxes);
+
+ /*
+ * Patch the DMA command with the final copy box.
+ */
+
+ SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
+
+ boxes = sbuf->hw.boxes;
+ for(i = 0; i < sbuf->hw.num_ranges; ++i) {
+ SVGA_DBG(DEBUG_DMA, " bytes %u - %u\n",
+ sbuf->hw.ranges[i].start, sbuf->hw.ranges[i].end);
+
+ boxes[i].x = sbuf->hw.ranges[i].start;
+ boxes[i].y = 0;
+ boxes[i].z = 0;
+ boxes[i].w = sbuf->hw.ranges[i].end - sbuf->hw.ranges[i].start;
+ boxes[i].h = 1;
+ boxes[i].d = 1;
+ boxes[i].srcx = sbuf->hw.ranges[i].start;
+ boxes[i].srcy = 0;
+ boxes[i].srcz = 0;
+ }
+
+ sbuf->hw.num_ranges = 0;
+ memset(&sbuf->hw.flags, 0, sizeof sbuf->hw.flags);
+
+ assert(sbuf->head.prev && sbuf->head.next);
+ LIST_DEL(&sbuf->head);
+ sbuf->needs_flush = FALSE;
+ /* XXX: do we care about cached_buffers any more ?*/
+ LIST_ADD(&sbuf->head, &ss->cached_buffers);
+
+ sbuf->hw.svga = NULL;
+ sbuf->hw.boxes = NULL;
+
+ /* Decrement reference count */
+ pipe_buffer_reference((struct pipe_buffer **)&sbuf, NULL);
+}
+
+
+/**
+ * Queue a DMA upload of a range of this buffer to the host.
+ *
+ * This function only notes the range down. It doesn't actually emit a DMA
+ * upload command. That only happens when a context tries to refer to this
+ * buffer, and the DMA upload command is added to that context's command buffer.
+ *
+ * We try to lump as many contiguous DMA transfers together as possible.
+ */
+static void
+svga_buffer_upload_queue(struct svga_buffer *sbuf,
+ unsigned start,
+ unsigned end)
+{
+ unsigned i;
+
+ assert(sbuf->hw.buf);
+ assert(end > start);
+
+ /*
+ * Try to grow one of the ranges.
+ *
+ * Note that it is not this function task to care about overlapping ranges,
+ * as the GMR was already given so it is too late to do anything. Situations
+ * where overlapping ranges may pose a problem should be detected via
+ * pipe_context::is_buffer_referenced and the context that refers to the
+ * buffer should be flushed.
+ */
+
+ for(i = 0; i < sbuf->hw.num_ranges; ++i) {
+ if(start <= sbuf->hw.ranges[i].end && sbuf->hw.ranges[i].start <= end) {
+ sbuf->hw.ranges[i].start = MIN2(sbuf->hw.ranges[i].start, start);
+ sbuf->hw.ranges[i].end = MAX2(sbuf->hw.ranges[i].end, end);
+ return;
+ }
+ }
+
+ /*
+ * We cannot add a new range to an existing DMA command, so patch-up the
+ * pending DMA upload and start clean.
+ */
+
+ if(sbuf->needs_flush)
+ svga_buffer_upload_flush(sbuf->hw.svga, sbuf);
+
+ assert(!sbuf->needs_flush);
+ assert(!sbuf->hw.svga);
+ assert(!sbuf->hw.boxes);
+
+ /*
+ * Add a new range.
+ */
+
+ sbuf->hw.ranges[sbuf->hw.num_ranges].start = start;
+ sbuf->hw.ranges[sbuf->hw.num_ranges].end = end;
+ ++sbuf->hw.num_ranges;
+}
+
+
+static void *
+svga_buffer_map_range( struct pipe_screen *screen,
+ struct pipe_buffer *buf,
+ unsigned offset, unsigned length,
+ unsigned usage )
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_buffer *sbuf = svga_buffer( buf );
+ void *map;
+
+ if(sbuf->swbuf) {
+ /* User/malloc buffer */
+ map = sbuf->swbuf;
+ }
+ else {
+ if(!sbuf->hw.buf) {
+ struct svga_winsys_surface *handle = sbuf->handle;
+
+ if(svga_buffer_create_hw_storage(ss, sbuf) != PIPE_OK)
+ return NULL;
+
+ /* Populate the hardware storage if the host surface pre-existed */
+ if((usage & PIPE_BUFFER_USAGE_CPU_READ) && handle) {
+ SVGA3dSurfaceDMAFlags flags;
+ enum pipe_error ret;
+ struct pipe_fence_handle *fence = NULL;
+
+ SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "dma from sid %p (buffer), bytes %u - %u\n",
+ sbuf->handle, 0, sbuf->base.size);
+
+ memset(&flags, 0, sizeof flags);
+
+ ret = SVGA3D_BufferDMA(ss->swc,
+ sbuf->hw.buf,
+ sbuf->handle,
+ SVGA3D_READ_HOST_VRAM,
+ sbuf->base.size,
+ 0,
+ flags);
+ if(ret != PIPE_OK) {
+ ss->swc->flush(ss->swc, NULL);
+
+ ret = SVGA3D_BufferDMA(ss->swc,
+ sbuf->hw.buf,
+ sbuf->handle,
+ SVGA3D_READ_HOST_VRAM,
+ sbuf->base.size,
+ 0,
+ flags);
+ assert(ret == PIPE_OK);
+ }
+
+ ss->swc->flush(ss->swc, &fence);
+ sws->fence_finish(sws, fence, 0);
+ sws->fence_reference(sws, &fence, NULL);
+ }
+ }
+ else {
+ if((usage & PIPE_BUFFER_USAGE_CPU_READ) && !sbuf->needs_flush) {
+ /* We already had the hardware storage but we would have to issue
+ * a download if we hadn't, so move the buffer to the begginning
+ * of the LRU list.
+ */
+ assert(sbuf->head.prev && sbuf->head.next);
+ LIST_DEL(&sbuf->head);
+ LIST_ADD(&sbuf->head, &ss->cached_buffers);
+ }
+ }
+
+ map = sws->buffer_map(sws, sbuf->hw.buf, usage);
+ }
+
+ if(map) {
+ pipe_mutex_lock(ss->swc_mutex);
+
+ ++sbuf->map.count;
+
+ if (usage & PIPE_BUFFER_USAGE_CPU_WRITE) {
+ assert(sbuf->map.count <= 1);
+ sbuf->map.writing = TRUE;
+ if (usage & PIPE_BUFFER_USAGE_FLUSH_EXPLICIT)
+ sbuf->map.flush_explicit = TRUE;
+ }
+
+ pipe_mutex_unlock(ss->swc_mutex);
+ }
+
+ return map;
+}
+
+static void
+svga_buffer_flush_mapped_range( struct pipe_screen *screen,
+ struct pipe_buffer *buf,
+ unsigned offset, unsigned length)
+{
+ struct svga_buffer *sbuf = svga_buffer( buf );
+ struct svga_screen *ss = svga_screen(screen);
+
+ pipe_mutex_lock(ss->swc_mutex);
+ assert(sbuf->map.writing);
+ if(sbuf->map.writing) {
+ assert(sbuf->map.flush_explicit);
+ if(sbuf->hw.buf)
+ svga_buffer_upload_queue(sbuf, offset, offset + length);
+ }
+ pipe_mutex_unlock(ss->swc_mutex);
+}
+
+static void
+svga_buffer_unmap( struct pipe_screen *screen,
+ struct pipe_buffer *buf)
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_buffer *sbuf = svga_buffer( buf );
+
+ pipe_mutex_lock(ss->swc_mutex);
+
+ assert(sbuf->map.count);
+ if(sbuf->map.count)
+ --sbuf->map.count;
+
+ if(sbuf->hw.buf)
+ sws->buffer_unmap(sws, sbuf->hw.buf);
+
+ if(sbuf->map.writing) {
+ if(!sbuf->map.flush_explicit) {
+ /* No mapped range was flushed -- flush the whole buffer */
+ SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n");
+
+ if(sbuf->hw.buf)
+ svga_buffer_upload_queue(sbuf, 0, sbuf->base.size);
+ }
+
+ sbuf->map.writing = FALSE;
+ sbuf->map.flush_explicit = FALSE;
+ }
+
+ pipe_mutex_unlock(ss->swc_mutex);
+}
+
+static void
+svga_buffer_destroy( struct pipe_buffer *buf )
+{
+ struct svga_screen *ss = svga_screen(buf->screen);
+ struct svga_buffer *sbuf = svga_buffer( buf );
+
+ assert(!p_atomic_read(&buf->reference.count));
+
+ assert(!sbuf->needs_flush);
+
+ if(sbuf->handle) {
+ SVGA_DBG(DEBUG_DMA, "release sid %p sz %d\n", sbuf->handle, sbuf->base.size);
+ svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle);
+ }
+
+ if(sbuf->hw.buf)
+ svga_buffer_destroy_hw_storage(ss, sbuf);
+
+ if(sbuf->swbuf && !sbuf->user)
+ align_free(sbuf->swbuf);
+
+ FREE(sbuf);
+}
+
+static struct pipe_buffer *
+svga_buffer_create(struct pipe_screen *screen,
+ unsigned alignment,
+ unsigned usage,
+ unsigned size)
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_buffer *sbuf;
+
+ sbuf = CALLOC_STRUCT(svga_buffer);
+ if(!sbuf)
+ goto error1;
+
+ sbuf->magic = SVGA_BUFFER_MAGIC;
+
+ pipe_reference_init(&sbuf->base.reference, 1);
+ sbuf->base.screen = screen;
+ sbuf->base.alignment = alignment;
+ sbuf->base.usage = usage;
+ sbuf->base.size = size;
+
+ if(svga_buffer_needs_hw_storage(usage)) {
+ if(svga_buffer_create_host_surface(ss, sbuf) != PIPE_OK)
+ goto error2;
+ }
+ else {
+ if(alignment < sizeof(void*))
+ alignment = sizeof(void*);
+
+ usage |= PIPE_BUFFER_USAGE_CPU_READ_WRITE;
+
+ sbuf->swbuf = align_malloc(size, alignment);
+ if(!sbuf->swbuf)
+ goto error2;
+ }
+
+ return &sbuf->base;
+
+error2:
+ FREE(sbuf);
+error1:
+ return NULL;
+}
+
+static struct pipe_buffer *
+svga_user_buffer_create(struct pipe_screen *screen,
+ void *ptr,
+ unsigned bytes)
+{
+ struct svga_buffer *sbuf;
+
+ sbuf = CALLOC_STRUCT(svga_buffer);
+ if(!sbuf)
+ goto no_sbuf;
+
+ sbuf->magic = SVGA_BUFFER_MAGIC;
+
+ sbuf->swbuf = ptr;
+ sbuf->user = TRUE;
+
+ pipe_reference_init(&sbuf->base.reference, 1);
+ sbuf->base.screen = screen;
+ sbuf->base.alignment = 1;
+ sbuf->base.usage = 0;
+ sbuf->base.size = bytes;
+
+ return &sbuf->base;
+
+no_sbuf:
+ return NULL;
+}
+
+
+void
+svga_screen_init_buffer_functions(struct pipe_screen *screen)
+{
+ screen->buffer_create = svga_buffer_create;
+ screen->user_buffer_create = svga_user_buffer_create;
+ screen->buffer_map_range = svga_buffer_map_range;
+ screen->buffer_flush_mapped_range = svga_buffer_flush_mapped_range;
+ screen->buffer_unmap = svga_buffer_unmap;
+ screen->buffer_destroy = svga_buffer_destroy;
+}
+
+
+/**
+ * Copy the contents of the user buffer / malloc buffer to a hardware buffer.
+ */
+static INLINE enum pipe_error
+svga_buffer_update_hw(struct svga_screen *ss, struct svga_buffer *sbuf)
+{
+ if(!sbuf->hw.buf) {
+ enum pipe_error ret;
+ void *map;
+
+ assert(sbuf->swbuf);
+ if(!sbuf->swbuf)
+ return PIPE_ERROR;
+
+ ret = svga_buffer_create_hw_storage(ss, sbuf);
+ assert(ret == PIPE_OK);
+ if(ret != PIPE_OK)
+ return ret;
+
+ pipe_mutex_lock(ss->swc_mutex);
+ map = ss->sws->buffer_map(ss->sws, sbuf->hw.buf, PIPE_BUFFER_USAGE_CPU_WRITE);
+ assert(map);
+ if(!map) {
+ pipe_mutex_unlock(ss->swc_mutex);
+ return PIPE_ERROR_OUT_OF_MEMORY;
+ }
+
+ memcpy(map, sbuf->swbuf, sbuf->base.size);
+ ss->sws->buffer_unmap(ss->sws, sbuf->hw.buf);
+
+ /* This user/malloc buffer is now indistinguishable from a gpu buffer */
+ assert(!sbuf->map.count);
+ if(!sbuf->map.count) {
+ if(sbuf->user)
+ sbuf->user = FALSE;
+ else
+ align_free(sbuf->swbuf);
+ sbuf->swbuf = NULL;
+ }
+
+ svga_buffer_upload_queue(sbuf, 0, sbuf->base.size);
+ }
+
+ pipe_mutex_unlock(ss->swc_mutex);
+ return PIPE_OK;
+}
+
+
+struct svga_winsys_surface *
+svga_buffer_handle(struct svga_context *svga,
+ struct pipe_buffer *buf)
+{
+ struct pipe_screen *screen = svga->pipe.screen;
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_buffer *sbuf;
+ enum pipe_error ret;
+
+ if(!buf)
+ return NULL;
+
+ sbuf = svga_buffer(buf);
+
+ assert(!sbuf->map.count);
+
+ if(!sbuf->handle) {
+ ret = svga_buffer_create_host_surface(ss, sbuf);
+ if(ret != PIPE_OK)
+ return NULL;
+
+ ret = svga_buffer_update_hw(ss, sbuf);
+ if(ret != PIPE_OK)
+ return NULL;
+ }
+
+ if(!sbuf->needs_flush && sbuf->hw.num_ranges) {
+ /* Queue the buffer for flushing */
+ ret = svga_buffer_upload_command(svga, sbuf);
+ if(ret != PIPE_OK)
+ /* XXX: Should probably have a richer return value */
+ return NULL;
+
+ assert(sbuf->hw.svga == svga);
+
+ sbuf->needs_flush = TRUE;
+ assert(sbuf->head.prev && sbuf->head.next);
+ LIST_DEL(&sbuf->head);
+ LIST_ADDTAIL(&sbuf->head, &svga->dirty_buffers);
+ }
+
+ return sbuf->handle;
+}
+
+struct pipe_buffer *
+svga_screen_buffer_wrap_surface(struct pipe_screen *screen,
+ enum SVGA3dSurfaceFormat format,
+ struct svga_winsys_surface *srf)
+{
+ struct pipe_buffer *buf;
+ struct svga_buffer *sbuf;
+ struct svga_winsys_screen *sws = svga_winsys_screen(screen);
+
+ buf = svga_buffer_create(screen, 0, SVGA_BUFFER_USAGE_WRAPPED, 0);
+ if (!buf)
+ return NULL;
+
+ sbuf = svga_buffer(buf);
+
+ /*
+ * We are not the creator of this surface and therefore we must not
+ * cache it for reuse. Set the cacheable flag to zero in the key to
+ * prevent this.
+ */
+ sbuf->key.format = format;
+ sbuf->key.cachable = 0;
+ sws->surface_reference(sws, &sbuf->handle, srf);
+
+ return buf;
+}
+
+
+struct svga_winsys_surface *
+svga_screen_buffer_get_winsys_surface(struct pipe_buffer *buffer)
+{
+ struct svga_winsys_screen *sws = svga_winsys_screen(buffer->screen);
+ struct svga_winsys_surface *vsurf = NULL;
+
+ assert(svga_buffer(buffer)->key.cachable == 0);
+ svga_buffer(buffer)->key.cachable = 0;
+ sws->surface_reference(sws, &vsurf, svga_buffer(buffer)->handle);
+ return vsurf;
+}
+
+void
+svga_context_flush_buffers(struct svga_context *svga)
+{
+ struct list_head *curr, *next;
+ struct svga_buffer *sbuf;
+
+ curr = svga->dirty_buffers.next;
+ next = curr->next;
+ while(curr != &svga->dirty_buffers) {
+ sbuf = LIST_ENTRY(struct svga_buffer, curr, head);
+
+ assert(p_atomic_read(&sbuf->base.reference.count) != 0);
+ assert(sbuf->needs_flush);
+
+ svga_buffer_upload_flush(svga, sbuf);
+
+ curr = next;
+ next = curr->next;
+ }
+}
diff --git a/src/gallium/drivers/svga/svga_screen_buffer.h b/src/gallium/drivers/svga/svga_screen_buffer.h
new file mode 100644
index 0000000000..5d7af5a7c5
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_buffer.h
@@ -0,0 +1,190 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_BUFFER_H
+#define SVGA_BUFFER_H
+
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_state.h"
+
+#include "util/u_double_list.h"
+
+#include "svga_screen_cache.h"
+
+
+#define SVGA_BUFFER_MAGIC 0x344f9005
+
+/**
+ * Maximum number of discontiguous ranges
+ */
+#define SVGA_BUFFER_MAX_RANGES 32
+
+
+struct svga_screen;
+struct svga_context;
+struct svga_winsys_buffer;
+struct svga_winsys_surface;
+
+
+struct svga_buffer_range
+{
+ unsigned start;
+ unsigned end;
+};
+
+
+/**
+ * Describe a
+ *
+ * This holds the information to emit a SVGA3dCmdSurfaceDMA.
+ */
+struct svga_buffer_upload
+{
+ /**
+ * Guest memory region.
+ */
+ struct svga_winsys_buffer *buf;
+
+ struct svga_buffer_range ranges[SVGA_BUFFER_MAX_RANGES];
+ unsigned num_ranges;
+
+ SVGA3dSurfaceDMAFlags flags;
+
+ /**
+ * Pointer to the DMA copy box *inside* the command buffer.
+ */
+ SVGA3dCopyBox *boxes;
+
+ /**
+ * Context that has the pending DMA to this buffer.
+ */
+ struct svga_context *svga;
+};
+
+
+/**
+ * SVGA pipe buffer.
+ */
+struct svga_buffer
+{
+ struct pipe_buffer base;
+
+ /**
+ * Marker to detect bad casts in runtime.
+ */
+ uint32_t magic;
+
+ /**
+ * Regular (non DMA'able) memory.
+ *
+ * Used for user buffers or for buffers which we know before hand that can
+ * never be used by the virtual hardware directly, such as constant buffers.
+ */
+ void *swbuf;
+
+ /**
+ * Whether swbuf was created by the user or not.
+ */
+ boolean user;
+
+ /**
+ * DMA'ble memory.
+ *
+ * A piece of GMR memory. It is created when mapping the buffer, and will be
+ * used to upload/download vertex data from the host.
+ */
+ struct svga_buffer_upload hw;
+
+ /**
+ * Creation key for the host surface handle.
+ *
+ * This structure describes all the host surface characteristics so that it
+ * can be looked up in cache, since creating a host surface is often a slow
+ * operation.
+ */
+ struct svga_host_surface_cache_key key;
+
+ /**
+ * Host surface handle.
+ *
+ * This is a platform independent abstraction for host SID. We create when
+ * trying to bind
+ */
+ struct svga_winsys_surface *handle;
+
+ struct {
+ unsigned count;
+ boolean writing;
+ boolean flush_explicit;
+ } map;
+
+ boolean needs_flush;
+ struct list_head head;
+};
+
+
+static INLINE struct svga_buffer *
+svga_buffer(struct pipe_buffer *buffer)
+{
+ if (buffer) {
+ assert(((struct svga_buffer *)buffer)->magic == SVGA_BUFFER_MAGIC);
+ return (struct svga_buffer *)buffer;
+ }
+ return NULL;
+}
+
+
+/**
+ * Returns TRUE for user buffers. We may
+ * decide to use an alternate upload path for these buffers.
+ */
+static INLINE boolean
+svga_buffer_is_user_buffer( struct pipe_buffer *buffer )
+{
+ return svga_buffer(buffer)->user;
+}
+
+
+void
+svga_screen_init_buffer_functions(struct pipe_screen *screen);
+
+struct svga_winsys_surface *
+svga_buffer_handle(struct svga_context *svga,
+ struct pipe_buffer *buf);
+
+void
+svga_context_flush_buffers(struct svga_context *svga);
+
+boolean
+svga_buffer_free_cached_hw_storage(struct svga_screen *ss);
+
+struct svga_winsys_buffer *
+svga_winsys_buffer_create(struct svga_screen *ss,
+ unsigned alignment,
+ unsigned usage,
+ unsigned size);
+
+#endif /* SVGA_BUFFER_H */
diff --git a/src/gallium/drivers/svga/svga_screen_cache.c b/src/gallium/drivers/svga/svga_screen_cache.c
new file mode 100644
index 0000000000..8a06383f61
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_cache.c
@@ -0,0 +1,338 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "util/u_memory.h"
+#include "util/u_hash.h"
+
+#include "svga_debug.h"
+#include "svga_winsys.h"
+#include "svga_screen.h"
+#include "svga_screen_cache.h"
+
+
+#define SVGA_SURFACE_CACHE_ENABLED 1
+
+
+/**
+ * Compute the bucket for this key.
+ */
+static INLINE unsigned
+svga_screen_cache_bucket(const struct svga_host_surface_cache_key *key)
+{
+ return util_hash_crc32( key, sizeof *key ) % SVGA_HOST_SURFACE_CACHE_BUCKETS;
+}
+
+
+static INLINE struct svga_winsys_surface *
+svga_screen_cache_lookup(struct svga_screen *svgascreen,
+ const struct svga_host_surface_cache_key *key)
+{
+ struct svga_host_surface_cache *cache = &svgascreen->cache;
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_host_surface_cache_entry *entry;
+ struct svga_winsys_surface *handle = NULL;
+ struct list_head *curr, *next;
+ unsigned bucket;
+ unsigned tries = 0;
+
+ assert(key->cachable);
+
+ bucket = svga_screen_cache_bucket(key);
+
+ pipe_mutex_lock(cache->mutex);
+
+ curr = cache->bucket[bucket].next;
+ next = curr->next;
+ while(curr != &cache->bucket[bucket]) {
+ ++tries;
+
+ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, bucket_head);
+
+ assert(entry->handle);
+
+ if(memcmp(&entry->key, key, sizeof *key) == 0 &&
+ sws->fence_signalled( sws, entry->fence, 0 ) == 0) {
+ assert(sws->surface_is_flushed(sws, entry->handle));
+
+ handle = entry->handle; // Reference is transfered here.
+ entry->handle = NULL;
+
+ LIST_DEL(&entry->bucket_head);
+
+ LIST_DEL(&entry->head);
+
+ LIST_ADD(&entry->head, &cache->empty);
+
+ break;
+ }
+
+ curr = next;
+ next = curr->next;
+ }
+
+ pipe_mutex_unlock(cache->mutex);
+
+ if (SVGA_DEBUG & DEBUG_DMA)
+ debug_printf("%s: cache %s after %u tries (bucket %d)\n", __FUNCTION__,
+ handle ? "hit" : "miss", tries, bucket);
+
+ return handle;
+}
+
+
+/*
+ * Transfers a handle reference.
+ */
+
+static INLINE void
+svga_screen_cache_add(struct svga_screen *svgascreen,
+ const struct svga_host_surface_cache_key *key,
+ struct svga_winsys_surface **p_handle)
+{
+ struct svga_host_surface_cache *cache = &svgascreen->cache;
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_host_surface_cache_entry *entry = NULL;
+ struct svga_winsys_surface *handle = *p_handle;
+
+ assert(key->cachable);
+
+ assert(handle);
+ if(!handle)
+ return;
+
+ *p_handle = NULL;
+ pipe_mutex_lock(cache->mutex);
+
+ if(!LIST_IS_EMPTY(&cache->empty)) {
+ /* use the first empty entry */
+ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->empty.next, head);
+
+ LIST_DEL(&entry->head);
+ }
+ else if(!LIST_IS_EMPTY(&cache->unused)) {
+ /* free the last used buffer and reuse its entry */
+ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->unused.prev, head);
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "unref sid %p (make space)\n", entry->handle);
+ sws->surface_reference(sws, &entry->handle, NULL);
+
+ LIST_DEL(&entry->bucket_head);
+
+ LIST_DEL(&entry->head);
+ }
+
+ if(entry) {
+ entry->handle = handle;
+ memcpy(&entry->key, key, sizeof entry->key);
+
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "cache sid %p\n", entry->handle);
+ LIST_ADD(&entry->head, &cache->validated);
+ }
+ else {
+ /* Couldn't cache the buffer -- this really shouldn't happen */
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "unref sid %p (couldn't find space)\n", handle);
+ sws->surface_reference(sws, &handle, NULL);
+ }
+
+ pipe_mutex_unlock(cache->mutex);
+}
+
+
+/**
+ * Called during the screen flush to move all buffers not in a validate list
+ * into the unused list.
+ */
+void
+svga_screen_cache_flush(struct svga_screen *svgascreen,
+ struct pipe_fence_handle *fence)
+{
+ struct svga_host_surface_cache *cache = &svgascreen->cache;
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_host_surface_cache_entry *entry;
+ struct list_head *curr, *next;
+ unsigned bucket;
+
+ pipe_mutex_lock(cache->mutex);
+
+ curr = cache->validated.next;
+ next = curr->next;
+ while(curr != &cache->validated) {
+ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, curr, head);
+
+ assert(entry->handle);
+
+ if(sws->surface_is_flushed(sws, entry->handle)) {
+ LIST_DEL(&entry->head);
+
+ svgascreen->sws->fence_reference(svgascreen->sws, &entry->fence, fence);
+
+ LIST_ADD(&entry->head, &cache->unused);
+
+ bucket = svga_screen_cache_bucket(&entry->key);
+ LIST_ADD(&entry->bucket_head, &cache->bucket[bucket]);
+ }
+
+ curr = next;
+ next = curr->next;
+ }
+
+ pipe_mutex_unlock(cache->mutex);
+}
+
+
+void
+svga_screen_cache_cleanup(struct svga_screen *svgascreen)
+{
+ struct svga_host_surface_cache *cache = &svgascreen->cache;
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ unsigned i;
+
+ for(i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i) {
+ if(cache->entries[i].handle) {
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "unref sid %p (shutdown)\n", cache->entries[i].handle);
+ sws->surface_reference(sws, &cache->entries[i].handle, NULL);
+ }
+
+ if(cache->entries[i].fence)
+ svgascreen->sws->fence_reference(svgascreen->sws, &cache->entries[i].fence, NULL);
+ }
+
+ pipe_mutex_destroy(cache->mutex);
+}
+
+
+enum pipe_error
+svga_screen_cache_init(struct svga_screen *svgascreen)
+{
+ struct svga_host_surface_cache *cache = &svgascreen->cache;
+ unsigned i;
+
+ pipe_mutex_init(cache->mutex);
+
+ for(i = 0; i < SVGA_HOST_SURFACE_CACHE_BUCKETS; ++i)
+ LIST_INITHEAD(&cache->bucket[i]);
+
+ LIST_INITHEAD(&cache->unused);
+
+ LIST_INITHEAD(&cache->validated);
+
+ LIST_INITHEAD(&cache->empty);
+ for(i = 0; i < SVGA_HOST_SURFACE_CACHE_SIZE; ++i)
+ LIST_ADDTAIL(&cache->entries[i].head, &cache->empty);
+
+ return PIPE_OK;
+}
+
+
+struct svga_winsys_surface *
+svga_screen_surface_create(struct svga_screen *svgascreen,
+ struct svga_host_surface_cache_key *key)
+{
+ struct svga_winsys_screen *sws = svgascreen->sws;
+ struct svga_winsys_surface *handle = NULL;
+ boolean cachable = SVGA_SURFACE_CACHE_ENABLED && key->cachable;
+
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "%s sz %dx%dx%d mips %d faces %d cachable %d\n",
+ __FUNCTION__,
+ key->size.width,
+ key->size.height,
+ key->size.depth,
+ key->numMipLevels,
+ key->numFaces,
+ key->cachable);
+
+ if (cachable) {
+ if (key->format == SVGA3D_BUFFER) {
+ /* For buffers, round the buffer size up to the nearest power
+ * of two to increase the probability of cache hits. Keep
+ * texture surface dimensions unchanged.
+ */
+ uint32_t size = 1;
+ while(size < key->size.width)
+ size <<= 1;
+ key->size.width = size;
+ }
+
+ handle = svga_screen_cache_lookup(svgascreen, key);
+ if (handle) {
+ if (key->format == SVGA3D_BUFFER)
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "reuse sid %p sz %d (buffer)\n", handle,
+ key->size.width);
+ else
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ "reuse sid %p sz %dx%dx%d mips %d faces %d\n", handle,
+ key->size.width,
+ key->size.height,
+ key->size.depth,
+ key->numMipLevels,
+ key->numFaces);
+ }
+ }
+
+ if (!handle) {
+ handle = sws->surface_create(sws,
+ key->flags,
+ key->format,
+ key->size,
+ key->numFaces,
+ key->numMipLevels);
+ if (handle)
+ SVGA_DBG(DEBUG_CACHE|DEBUG_DMA,
+ " CREATE sid %p sz %dx%dx%d\n",
+ handle,
+ key->size.width,
+ key->size.height,
+ key->size.depth);
+ }
+
+ return handle;
+}
+
+
+void
+svga_screen_surface_destroy(struct svga_screen *svgascreen,
+ const struct svga_host_surface_cache_key *key,
+ struct svga_winsys_surface **p_handle)
+{
+ struct svga_winsys_screen *sws = svgascreen->sws;
+
+ /* We only set the cachable flag for surfaces of which we are the
+ * exclusive owner. So just hold onto our existing reference in
+ * that case.
+ */
+ if(SVGA_SURFACE_CACHE_ENABLED && key->cachable) {
+ svga_screen_cache_add(svgascreen, key, p_handle);
+ }
+ else {
+ SVGA_DBG(DEBUG_DMA,
+ "unref sid %p (uncachable)\n", *p_handle);
+ sws->surface_reference(sws, p_handle, NULL);
+ }
+}
diff --git a/src/gallium/drivers/svga/svga_screen_cache.h b/src/gallium/drivers/svga/svga_screen_cache.h
new file mode 100644
index 0000000000..f5aa740d40
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_cache.h
@@ -0,0 +1,144 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_SCREEN_CACHE_H_
+#define SVGA_SCREEN_CACHE_H_
+
+
+#include "svga_types.h"
+#include "svga_reg.h"
+#include "svga3d_reg.h"
+
+#include "pipe/p_thread.h"
+
+#include "util/u_double_list.h"
+
+
+/* Guess the storage size of cached surfaces and try and keep it under
+ * this amount:
+ */
+#define SVGA_HOST_SURFACE_CACHE_BYTES 16*1024*1024
+
+/* Maximum number of discrete surfaces in the cache:
+ */
+#define SVGA_HOST_SURFACE_CACHE_SIZE 1024
+
+/* Number of hash buckets:
+ */
+#define SVGA_HOST_SURFACE_CACHE_BUCKETS 256
+
+
+struct svga_winsys_surface;
+struct svga_screen;
+
+/**
+ * Same as svga_winsys_screen::surface_create.
+ */
+struct svga_host_surface_cache_key
+{
+ SVGA3dSurfaceFlags flags;
+ SVGA3dSurfaceFormat format;
+ SVGA3dSize size;
+ uint32_t numFaces:24;
+ uint32_t numMipLevels:7;
+ uint32_t cachable:1; /* False if this is a shared surface */
+};
+
+
+struct svga_host_surface_cache_entry
+{
+ /**
+ * Head for the LRU list, svga_host_surface_cache::unused, and
+ * svga_host_surface_cache::empty
+ */
+ struct list_head head;
+
+ /** Head for the bucket lists. */
+ struct list_head bucket_head;
+
+ struct svga_host_surface_cache_key key;
+ struct svga_winsys_surface *handle;
+
+ struct pipe_fence_handle *fence;
+};
+
+
+/**
+ * Cache of the host surfaces.
+ *
+ * A cache entry can be in the following stages:
+ * 1. empty
+ * 2. holding a buffer in a validate list
+ * 3. holding a flushed buffer (not in any validate list) with an active fence
+ * 4. holding a flushed buffer with an expired fence
+ *
+ * An entry progresses from 1 -> 2 -> 3 -> 4. When we need an entry to put a
+ * buffer into we preferencial take from 1, or from the least recentely used
+ * buffer from 3/4.
+ */
+struct svga_host_surface_cache
+{
+ pipe_mutex mutex;
+
+ /* Unused buffers are put in buckets to speed up lookups */
+ struct list_head bucket[SVGA_HOST_SURFACE_CACHE_BUCKETS];
+
+ /* Entries with unused buffers, ordered from most to least recently used
+ * (3 and 4) */
+ struct list_head unused;
+
+ /* Entries with buffers still in validate lists (2) */
+ struct list_head validated;
+
+ /** Empty entries (1) */
+ struct list_head empty;
+
+ /** The actual storage for the entries */
+ struct svga_host_surface_cache_entry entries[SVGA_HOST_SURFACE_CACHE_SIZE];
+};
+
+
+void
+svga_screen_cache_cleanup(struct svga_screen *svgascreen);
+
+void
+svga_screen_cache_flush(struct svga_screen *svgascreen,
+ struct pipe_fence_handle *fence);
+
+enum pipe_error
+svga_screen_cache_init(struct svga_screen *svgascreen);
+
+
+struct svga_winsys_surface *
+svga_screen_surface_create(struct svga_screen *svgascreen,
+ struct svga_host_surface_cache_key *key);
+
+void
+svga_screen_surface_destroy(struct svga_screen *svgascreen,
+ const struct svga_host_surface_cache_key *key,
+ struct svga_winsys_surface **handle);
+
+
+#endif /* SVGA_SCREEN_CACHE_H_ */
diff --git a/src/gallium/drivers/svga/svga_screen_texture.c b/src/gallium/drivers/svga/svga_screen_texture.c
new file mode 100644
index 0000000000..6e10d65a20
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_texture.c
@@ -0,0 +1,1089 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "svga_cmd.h"
+
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_thread.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "svga_screen.h"
+#include "svga_context.h"
+#include "svga_screen_texture.h"
+#include "svga_screen_buffer.h"
+#include "svga_winsys.h"
+#include "svga_debug.h"
+#include "svga_screen_buffer.h"
+
+#include <util/u_string.h>
+
+
+/* XXX: This isn't a real hardware flag, but just a hack for kernel to
+ * know about primary surfaces. Find a better way to accomplish this.
+ */
+#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
+
+
+/*
+ * Helper function and arrays
+ */
+
+SVGA3dSurfaceFormat
+svga_translate_format(enum pipe_format format)
+{
+ switch(format) {
+
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ return SVGA3D_A8R8G8B8;
+ case PIPE_FORMAT_X8R8G8B8_UNORM:
+ return SVGA3D_X8R8G8B8;
+
+ /* Required for GL2.1:
+ */
+ case PIPE_FORMAT_A8R8G8B8_SRGB:
+ return SVGA3D_A8R8G8B8;
+
+ case PIPE_FORMAT_R5G6B5_UNORM:
+ return SVGA3D_R5G6B5;
+ case PIPE_FORMAT_A1R5G5B5_UNORM:
+ return SVGA3D_A1R5G5B5;
+ case PIPE_FORMAT_A4R4G4B4_UNORM:
+ return SVGA3D_A4R4G4B4;
+
+
+ /* XXX: Doesn't seem to work properly.
+ case PIPE_FORMAT_Z32_UNORM:
+ return SVGA3D_Z_D32;
+ */
+ case PIPE_FORMAT_Z16_UNORM:
+ return SVGA3D_Z_D16;
+ case PIPE_FORMAT_Z24S8_UNORM:
+ return SVGA3D_Z_D24S8;
+ case PIPE_FORMAT_Z24X8_UNORM:
+ return SVGA3D_Z_D24X8;
+
+ case PIPE_FORMAT_A8_UNORM:
+ return SVGA3D_ALPHA8;
+ case PIPE_FORMAT_L8_UNORM:
+ return SVGA3D_LUMINANCE8;
+
+ case PIPE_FORMAT_DXT1_RGB:
+ case PIPE_FORMAT_DXT1_RGBA:
+ return SVGA3D_DXT1;
+ case PIPE_FORMAT_DXT3_RGBA:
+ return SVGA3D_DXT3;
+ case PIPE_FORMAT_DXT5_RGBA:
+ return SVGA3D_DXT5;
+
+ default:
+ return SVGA3D_FORMAT_INVALID;
+ }
+}
+
+
+SVGA3dSurfaceFormat
+svga_translate_format_render(enum pipe_format format)
+{
+ switch(format) {
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ case PIPE_FORMAT_X8R8G8B8_UNORM:
+ case PIPE_FORMAT_A1R5G5B5_UNORM:
+ case PIPE_FORMAT_A4R4G4B4_UNORM:
+ case PIPE_FORMAT_R5G6B5_UNORM:
+ case PIPE_FORMAT_Z24S8_UNORM:
+ case PIPE_FORMAT_Z24X8_UNORM:
+ case PIPE_FORMAT_Z32_UNORM:
+ case PIPE_FORMAT_Z16_UNORM:
+ case PIPE_FORMAT_L8_UNORM:
+ return svga_translate_format(format);
+
+#if 1
+ /* For on host conversion */
+ case PIPE_FORMAT_DXT1_RGB:
+ return SVGA3D_X8R8G8B8;
+ case PIPE_FORMAT_DXT1_RGBA:
+ case PIPE_FORMAT_DXT3_RGBA:
+ case PIPE_FORMAT_DXT5_RGBA:
+ return SVGA3D_A8R8G8B8;
+#endif
+
+ default:
+ return SVGA3D_FORMAT_INVALID;
+ }
+}
+
+
+static INLINE void
+svga_transfer_dma_band(struct svga_transfer *st,
+ SVGA3dTransferType transfer,
+ unsigned y, unsigned h, unsigned srcy)
+{
+ struct svga_texture *texture = svga_texture(st->base.texture);
+ struct svga_screen *screen = svga_screen(texture->base.screen);
+ SVGA3dCopyBox box;
+ enum pipe_error ret;
+
+ SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
+ transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
+ texture->handle,
+ st->base.face,
+ st->base.x,
+ y,
+ st->base.zslice,
+ st->base.x + st->base.width,
+ y + h,
+ st->base.zslice + 1,
+ texture->base.block.size*8/(texture->base.block.width*texture->base.block.height));
+
+ box.x = st->base.x;
+ box.y = y;
+ box.z = st->base.zslice;
+ box.w = st->base.width;
+ box.h = h;
+ box.d = 1;
+ box.srcx = 0;
+ box.srcy = srcy;
+ box.srcz = 0;
+
+ pipe_mutex_lock(screen->swc_mutex);
+ ret = SVGA3D_SurfaceDMA(screen->swc, st, transfer, &box, 1);
+ if(ret != PIPE_OK) {
+ screen->swc->flush(screen->swc, NULL);
+ ret = SVGA3D_SurfaceDMA(screen->swc, st, transfer, &box, 1);
+ assert(ret == PIPE_OK);
+ }
+ pipe_mutex_unlock(screen->swc_mutex);
+}
+
+
+static INLINE void
+svga_transfer_dma(struct svga_transfer *st,
+ SVGA3dTransferType transfer)
+{
+ struct svga_texture *texture = svga_texture(st->base.texture);
+ struct svga_screen *screen = svga_screen(texture->base.screen);
+ struct svga_winsys_screen *sws = screen->sws;
+ struct pipe_fence_handle *fence = NULL;
+
+ if (transfer == SVGA3D_READ_HOST_VRAM) {
+ SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
+ }
+
+
+ if(!st->swbuf) {
+ /* Do the DMA transfer in a single go */
+
+ svga_transfer_dma_band(st, transfer, st->base.y, st->base.height, 0);
+
+ if(transfer == SVGA3D_READ_HOST_VRAM) {
+ svga_screen_flush(screen, &fence);
+ sws->fence_finish(sws, fence, 0);
+ //sws->fence_reference(sws, &fence, NULL);
+ }
+ }
+ else {
+ unsigned y, h, srcy;
+ h = st->hw_nblocksy * st->base.block.height;
+ srcy = 0;
+ for(y = 0; y < st->base.height; y += h) {
+ unsigned offset, length;
+ void *hw, *sw;
+
+ if (y + h > st->base.height)
+ h = st->base.height - y;
+
+ /* Transfer band must be aligned to pixel block boundaries */
+ assert(y % st->base.block.height == 0);
+ assert(h % st->base.block.height == 0);
+
+ offset = y * st->base.stride / st->base.block.height;
+ length = h * st->base.stride / st->base.block.height;
+
+ sw = (uint8_t *)st->swbuf + offset;
+
+ if(transfer == SVGA3D_WRITE_HOST_VRAM) {
+ /* Wait for the previous DMAs to complete */
+ /* TODO: keep one DMA (at half the size) in the background */
+ if(y) {
+ svga_screen_flush(screen, &fence);
+ sws->fence_finish(sws, fence, 0);
+ //sws->fence_reference(sws, &fence, NULL);
+ }
+
+ hw = sws->buffer_map(sws, st->hwbuf, PIPE_BUFFER_USAGE_CPU_WRITE);
+ assert(hw);
+ if(hw) {
+ memcpy(hw, sw, length);
+ sws->buffer_unmap(sws, st->hwbuf);
+ }
+ }
+
+ svga_transfer_dma_band(st, transfer, y, h, srcy);
+
+ if(transfer == SVGA3D_READ_HOST_VRAM) {
+ svga_screen_flush(screen, &fence);
+ sws->fence_finish(sws, fence, 0);
+
+ hw = sws->buffer_map(sws, st->hwbuf, PIPE_BUFFER_USAGE_CPU_READ);
+ assert(hw);
+ if(hw) {
+ memcpy(sw, hw, length);
+ sws->buffer_unmap(sws, st->hwbuf);
+ }
+ }
+ }
+ }
+}
+
+
+static struct pipe_texture *
+svga_texture_create(struct pipe_screen *screen,
+ const struct pipe_texture *templat)
+{
+ struct svga_screen *svgascreen = svga_screen(screen);
+ struct svga_texture *tex = CALLOC_STRUCT(svga_texture);
+ unsigned width, height, depth;
+ unsigned level;
+
+ if (!tex)
+ goto error1;
+
+ tex->base = *templat;
+ pipe_reference_init(&tex->base.reference, 1);
+ tex->base.screen = screen;
+
+ assert(templat->last_level < SVGA_MAX_TEXTURE_LEVELS);
+ if(templat->last_level >= SVGA_MAX_TEXTURE_LEVELS)
+ goto error2;
+
+ width = templat->width0;
+ height = templat->height0;
+ depth = templat->depth0;
+ for(level = 0; level <= templat->last_level; ++level) {
+ tex->base.nblocksx[level] = pf_get_nblocksx(&tex->base.block, width);
+ tex->base.nblocksy[level] = pf_get_nblocksy(&tex->base.block, height);
+ width = u_minify(width, 1);
+ height = u_minify(height, 1);
+ depth = u_minify(depth, 1);
+ }
+
+ tex->key.flags = 0;
+ tex->key.size.width = templat->width0;
+ tex->key.size.height = templat->height0;
+ tex->key.size.depth = templat->depth0;
+
+ if(templat->target == PIPE_TEXTURE_CUBE) {
+ tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
+ tex->key.numFaces = 6;
+ }
+ else {
+ tex->key.numFaces = 1;
+ }
+
+ if(templat->tex_usage & PIPE_TEXTURE_USAGE_SAMPLER)
+ tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
+
+ if(templat->tex_usage & PIPE_TEXTURE_USAGE_PRIMARY)
+ tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT;
+
+ /*
+ * XXX: Never pass the SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
+ * know beforehand whether a texture will be used as a rendertarget or not
+ * and it always requests PIPE_TEXTURE_USAGE_RENDER_TARGET, therefore
+ * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
+ */
+#if 0
+ if((templat->tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) &&
+ !pf_is_compressed(templat->format))
+ tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
+#endif
+
+ if(templat->tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL)
+ tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
+
+ tex->key.numMipLevels = templat->last_level + 1;
+
+ tex->key.format = svga_translate_format(templat->format);
+ if(tex->key.format == SVGA3D_FORMAT_INVALID)
+ goto error2;
+
+ tex->key.cachable = 1;
+
+ SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle);
+ tex->handle = svga_screen_surface_create(svgascreen, &tex->key);
+ if (tex->handle)
+ SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle);
+
+ return &tex->base;
+
+error2:
+ FREE(tex);
+error1:
+ return NULL;
+}
+
+
+static struct pipe_texture *
+svga_texture_blanket(struct pipe_screen * screen,
+ const struct pipe_texture *base,
+ const unsigned *stride,
+ struct pipe_buffer *buffer)
+{
+ struct svga_texture *tex;
+ struct svga_buffer *sbuf = svga_buffer(buffer);
+ struct svga_winsys_screen *sws = svga_winsys_screen(screen);
+ assert(screen);
+
+ /* Only supports one type */
+ if (base->target != PIPE_TEXTURE_2D ||
+ base->last_level != 0 ||
+ base->depth0 != 1) {
+ return NULL;
+ }
+
+ /**
+ * We currently can't do texture blanket on
+ * SVGA3D_BUFFER. Need to blit to a temporary surface?
+ */
+
+ assert(sbuf->handle);
+ if (!sbuf->handle)
+ return NULL;
+
+ if (svga_translate_format(base->format) != sbuf->key.format) {
+ unsigned f1 = svga_translate_format(base->format);
+ unsigned f2 = sbuf->key.format;
+
+ /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */
+ if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) ||
+ (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) ||
+ (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) ) ) {
+ debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2);
+ return NULL;
+ }
+ }
+
+ tex = CALLOC_STRUCT(svga_texture);
+ if (!tex)
+ return NULL;
+
+ tex->base = *base;
+
+
+ if (sbuf->key.format == 1)
+ tex->base.format = PIPE_FORMAT_X8R8G8B8_UNORM;
+ else if (sbuf->key.format == 2)
+ tex->base.format = PIPE_FORMAT_A8R8G8B8_UNORM;
+
+ pipe_reference_init(&tex->base.reference, 1);
+ tex->base.screen = screen;
+
+ SVGA_DBG(DEBUG_DMA, "blanket sid %p\n", sbuf->handle);
+
+ /* We don't own this storage, so don't try to cache it.
+ */
+ assert(sbuf->key.cachable == 0);
+ tex->key.cachable = 0;
+ sws->surface_reference(sws, &tex->handle, sbuf->handle);
+
+ return &tex->base;
+}
+
+
+static void
+svga_texture_destroy(struct pipe_texture *pt)
+{
+ struct svga_screen *ss = svga_screen(pt->screen);
+ struct svga_texture *tex = (struct svga_texture *)pt;
+
+ ss->texture_timestamp++;
+
+ svga_sampler_view_reference(&tex->cached_view, NULL);
+
+ /*
+ DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
+ */
+ SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
+ svga_screen_surface_destroy(ss, &tex->key, &tex->handle);
+
+ FREE(tex);
+}
+
+
+static void
+svga_texture_copy_handle(struct svga_context *svga,
+ struct svga_screen *ss,
+ struct svga_winsys_surface *src_handle,
+ unsigned src_x, unsigned src_y, unsigned src_z,
+ unsigned src_level, unsigned src_face,
+ struct svga_winsys_surface *dst_handle,
+ unsigned dst_x, unsigned dst_y, unsigned dst_z,
+ unsigned dst_level, unsigned dst_face,
+ unsigned width, unsigned height, unsigned depth)
+{
+ struct svga_surface dst, src;
+ enum pipe_error ret;
+ SVGA3dCopyBox box, *boxes;
+
+ assert(svga || ss);
+
+ src.handle = src_handle;
+ src.real_level = src_level;
+ src.real_face = src_face;
+ src.real_zslice = 0;
+
+ dst.handle = dst_handle;
+ dst.real_level = dst_level;
+ dst.real_face = dst_face;
+ dst.real_zslice = 0;
+
+ box.x = dst_x;
+ box.y = dst_y;
+ box.z = dst_z;
+ box.w = width;
+ box.h = height;
+ box.d = depth;
+ box.srcx = src_x;
+ box.srcy = src_y;
+ box.srcz = src_z;
+
+/*
+ SVGA_DBG(DEBUG_VIEWS, "mipcopy src: %p %u (%ux%ux%u), dst: %p %u (%ux%ux%u)\n",
+ src_handle, src_level, src_x, src_y, src_z,
+ dst_handle, dst_level, dst_x, dst_y, dst_z);
+*/
+
+ if (svga) {
+ ret = SVGA3D_BeginSurfaceCopy(svga->swc,
+ &src.base,
+ &dst.base,
+ &boxes, 1);
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_BeginSurfaceCopy(svga->swc,
+ &src.base,
+ &dst.base,
+ &boxes, 1);
+ assert(ret == PIPE_OK);
+ }
+ *boxes = box;
+ SVGA_FIFOCommitAll(svga->swc);
+ } else {
+ pipe_mutex_lock(ss->swc_mutex);
+ ret = SVGA3D_BeginSurfaceCopy(ss->swc,
+ &src.base,
+ &dst.base,
+ &boxes, 1);
+ if(ret != PIPE_OK) {
+ ss->swc->flush(ss->swc, NULL);
+ ret = SVGA3D_BeginSurfaceCopy(ss->swc,
+ &src.base,
+ &dst.base,
+ &boxes, 1);
+ assert(ret == PIPE_OK);
+ }
+ *boxes = box;
+ SVGA_FIFOCommitAll(ss->swc);
+ pipe_mutex_unlock(ss->swc_mutex);
+ }
+}
+
+static struct svga_winsys_surface *
+svga_texture_view_surface(struct pipe_context *pipe,
+ struct svga_texture *tex,
+ SVGA3dSurfaceFormat format,
+ unsigned start_mip,
+ unsigned num_mip,
+ int face_pick,
+ int zslice_pick,
+ struct svga_host_surface_cache_key *key) /* OUT */
+{
+ struct svga_screen *ss = svga_screen(tex->base.screen);
+ struct svga_winsys_surface *handle;
+ int i, j;
+ unsigned z_offset = 0;
+
+ SVGA_DBG(DEBUG_PERF,
+ "svga: Create surface view: face %d zslice %d mips %d..%d\n",
+ face_pick, zslice_pick, start_mip, start_mip+num_mip-1);
+
+ key->flags = 0;
+ key->format = format;
+ key->numMipLevels = num_mip;
+ key->size.width = u_minify(tex->base.width0, start_mip);
+ key->size.height = u_minify(tex->base.height0, start_mip);
+ key->size.depth = zslice_pick < 0 ? u_minify(tex->base.depth0, start_mip) : 1;
+ key->cachable = 1;
+ assert(key->size.depth == 1);
+
+ if(tex->base.target == PIPE_TEXTURE_CUBE && face_pick < 0) {
+ key->flags |= SVGA3D_SURFACE_CUBEMAP;
+ key->numFaces = 6;
+ } else {
+ key->numFaces = 1;
+ }
+
+ if(key->format == SVGA3D_FORMAT_INVALID) {
+ key->cachable = 0;
+ return NULL;
+ }
+
+ SVGA_DBG(DEBUG_DMA, "surface_create for texture view\n");
+ handle = svga_screen_surface_create(ss, key);
+ if (!handle) {
+ key->cachable = 0;
+ return NULL;
+ }
+
+ SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture view)\n", handle);
+
+ if (face_pick < 0)
+ face_pick = 0;
+
+ if (zslice_pick >= 0)
+ z_offset = zslice_pick;
+
+ for (i = 0; i < key->numMipLevels; i++) {
+ for (j = 0; j < key->numFaces; j++) {
+ if(tex->defined[j + face_pick][i + start_mip]) {
+ unsigned depth = (zslice_pick < 0 ?
+ u_minify(tex->base.depth0, i + start_mip) :
+ 1);
+
+ svga_texture_copy_handle(svga_context(pipe),
+ ss,
+ tex->handle,
+ 0, 0, z_offset,
+ i + start_mip,
+ j + face_pick,
+ handle, 0, 0, 0, i, j,
+ u_minify(tex->base.width0, i + start_mip),
+ u_minify(tex->base.height0, i + start_mip),
+ depth);
+ }
+ }
+ }
+
+ return handle;
+}
+
+
+static struct pipe_surface *
+svga_get_tex_surface(struct pipe_screen *screen,
+ struct pipe_texture *pt,
+ unsigned face, unsigned level, unsigned zslice,
+ unsigned flags)
+{
+ struct svga_texture *tex = svga_texture(pt);
+ struct svga_surface *s;
+ boolean render = flags & PIPE_BUFFER_USAGE_GPU_WRITE ? TRUE : FALSE;
+ boolean view = FALSE;
+ SVGA3dSurfaceFormat format;
+
+ s = CALLOC_STRUCT(svga_surface);
+ if (!s)
+ return NULL;
+
+ pipe_reference_init(&s->base.reference, 1);
+ pipe_texture_reference(&s->base.texture, pt);
+ s->base.format = pt->format;
+ s->base.width = u_minify(pt->width0, level);
+ s->base.height = u_minify(pt->height0, level);
+ s->base.usage = flags;
+ s->base.level = level;
+ s->base.face = face;
+ s->base.zslice = zslice;
+
+ if (!render)
+ format = svga_translate_format(pt->format);
+ else
+ format = svga_translate_format_render(pt->format);
+
+ assert(format != SVGA3D_FORMAT_INVALID);
+ assert(!(flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE));
+
+
+ if (svga_screen(screen)->debug.force_surface_view)
+ view = TRUE;
+
+ /* Currently only used for compressed textures */
+ if (render &&
+ format != svga_translate_format(pt->format)) {
+ view = TRUE;
+ }
+
+ if (level != 0 &&
+ svga_screen(screen)->debug.force_level_surface_view)
+ view = TRUE;
+
+ if (pt->target == PIPE_TEXTURE_3D)
+ view = TRUE;
+
+ if (svga_screen(screen)->debug.no_surface_view)
+ view = FALSE;
+
+ if (view) {
+ SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u face %u z %u, %p\n",
+ pt, level, face, zslice, s);
+
+ s->handle = svga_texture_view_surface(NULL, tex, format, level, 1, face, zslice,
+ &s->key);
+ s->real_face = 0;
+ s->real_level = 0;
+ s->real_zslice = 0;
+ } else {
+ struct svga_winsys_screen *sws = svga_winsys_screen(screen);
+
+ SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, face %u, z %u, %p\n",
+ pt, level, face, zslice, s);
+
+ memset(&s->key, 0, sizeof s->key);
+ sws->surface_reference(sws, &s->handle, tex->handle);
+ s->real_face = face;
+ s->real_level = level;
+ s->real_zslice = zslice;
+ }
+
+ return &s->base;
+}
+
+
+static void
+svga_tex_surface_destroy(struct pipe_surface *surf)
+{
+ struct svga_surface *s = svga_surface(surf);
+ struct svga_screen *ss = svga_screen(surf->texture->screen);
+
+ SVGA_DBG(DEBUG_DMA, "unref sid %p (tex surface)\n", s->handle);
+ assert(s->key.cachable == 0);
+ svga_screen_surface_destroy(ss, &s->key, &s->handle);
+ pipe_texture_reference(&surf->texture, NULL);
+ FREE(surf);
+}
+
+
+static INLINE void
+svga_mark_surface_dirty(struct pipe_surface *surf)
+{
+ struct svga_surface *s = svga_surface(surf);
+
+ if(!s->dirty) {
+ struct svga_texture *tex = svga_texture(surf->texture);
+
+ s->dirty = TRUE;
+
+ if (s->handle == tex->handle)
+ tex->defined[surf->face][surf->level] = TRUE;
+ else {
+ /* this will happen later in svga_propagate_surface */
+ }
+ }
+}
+
+
+void svga_mark_surfaces_dirty(struct svga_context *svga)
+{
+ unsigned i;
+
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (svga->curr.framebuffer.cbufs[i])
+ svga_mark_surface_dirty(svga->curr.framebuffer.cbufs[i]);
+ }
+ if (svga->curr.framebuffer.zsbuf)
+ svga_mark_surface_dirty(svga->curr.framebuffer.zsbuf);
+}
+
+/**
+ * Progagate any changes from surfaces to texture.
+ * pipe is optional context to inline the blit command in.
+ */
+void
+svga_propagate_surface(struct pipe_context *pipe, struct pipe_surface *surf)
+{
+ struct svga_surface *s = svga_surface(surf);
+ struct svga_texture *tex = svga_texture(surf->texture);
+ struct svga_screen *ss = svga_screen(surf->texture->screen);
+
+ if (!s->dirty)
+ return;
+
+ s->dirty = FALSE;
+ ss->texture_timestamp++;
+ tex->view_age[surf->level] = ++(tex->age);
+
+ if (s->handle != tex->handle) {
+ SVGA_DBG(DEBUG_VIEWS, "svga: Surface propagate: tex %p, level %u, from %p\n", tex, surf->level, surf);
+ svga_texture_copy_handle(svga_context(pipe), ss,
+ s->handle, 0, 0, 0, s->real_level, s->real_face,
+ tex->handle, 0, 0, surf->zslice, surf->level, surf->face,
+ u_minify(tex->base.width0, surf->level),
+ u_minify(tex->base.height0, surf->level), 1);
+ tex->defined[surf->face][surf->level] = TRUE;
+ }
+}
+
+/**
+ * Check if we should call svga_propagate_surface on the surface.
+ */
+extern boolean
+svga_surface_needs_propagation(struct pipe_surface *surf)
+{
+ struct svga_surface *s = svga_surface(surf);
+ struct svga_texture *tex = svga_texture(surf->texture);
+
+ return s->dirty && s->handle != tex->handle;
+}
+
+
+static struct pipe_transfer *
+svga_get_tex_transfer(struct pipe_screen *screen,
+ struct pipe_texture *texture,
+ unsigned face, unsigned level, unsigned zslice,
+ enum pipe_transfer_usage usage, unsigned x, unsigned y,
+ unsigned w, unsigned h)
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_transfer *st;
+
+ /* We can't map texture storage directly */
+ if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
+ return NULL;
+
+ st = CALLOC_STRUCT(svga_transfer);
+ if (!st)
+ return NULL;
+
+ st->base.format = texture->format;
+ st->base.block = texture->block;
+ st->base.x = x;
+ st->base.y = y;
+ st->base.width = w;
+ st->base.height = h;
+ st->base.nblocksx = pf_get_nblocksx(&texture->block, w);
+ st->base.nblocksy = pf_get_nblocksy(&texture->block, h);
+ st->base.stride = st->base.nblocksx*st->base.block.size;
+ st->base.usage = usage;
+ st->base.face = face;
+ st->base.level = level;
+ st->base.zslice = zslice;
+
+ st->hw_nblocksy = st->base.nblocksy;
+
+ st->hwbuf = svga_winsys_buffer_create(ss,
+ 1,
+ 0,
+ st->hw_nblocksy*st->base.stride);
+ while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
+ st->hwbuf = svga_winsys_buffer_create(ss,
+ 1,
+ 0,
+ st->hw_nblocksy*st->base.stride);
+ }
+
+ if(!st->hwbuf)
+ goto no_hwbuf;
+
+ if(st->hw_nblocksy < st->base.nblocksy) {
+ /* We couldn't allocate a hardware buffer big enough for the transfer,
+ * so allocate regular malloc memory instead */
+ debug_printf("%s: failed to allocate %u KB of DMA, splitting into %u x %u KB DMA transfers\n",
+ __FUNCTION__,
+ (st->base.nblocksy*st->base.stride + 1023)/1024,
+ (st->base.nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy,
+ (st->hw_nblocksy*st->base.stride + 1023)/1024);
+ st->swbuf = MALLOC(st->base.nblocksy*st->base.stride);
+ if(!st->swbuf)
+ goto no_swbuf;
+ }
+
+ pipe_texture_reference(&st->base.texture, texture);
+
+ if (usage & PIPE_TRANSFER_READ)
+ svga_transfer_dma(st, SVGA3D_READ_HOST_VRAM);
+
+ return &st->base;
+
+no_swbuf:
+ sws->buffer_destroy(sws, st->hwbuf);
+no_hwbuf:
+ FREE(st);
+ return NULL;
+}
+
+
+static void *
+svga_transfer_map( struct pipe_screen *screen,
+ struct pipe_transfer *transfer )
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_transfer *st = svga_transfer(transfer);
+
+ if(st->swbuf)
+ return st->swbuf;
+ else
+ /* The wait for read transfers already happened when svga_transfer_dma
+ * was called. */
+ return sws->buffer_map(sws, st->hwbuf,
+ pipe_transfer_buffer_flags(transfer));
+}
+
+
+static void
+svga_transfer_unmap(struct pipe_screen *screen,
+ struct pipe_transfer *transfer)
+{
+ struct svga_screen *ss = svga_screen(screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_transfer *st = svga_transfer(transfer);
+
+ if(!st->swbuf)
+ sws->buffer_unmap(sws, st->hwbuf);
+}
+
+
+static void
+svga_tex_transfer_destroy(struct pipe_transfer *transfer)
+{
+ struct svga_texture *tex = svga_texture(transfer->texture);
+ struct svga_screen *ss = svga_screen(transfer->texture->screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_transfer *st = svga_transfer(transfer);
+
+ if (st->base.usage & PIPE_TRANSFER_WRITE) {
+ svga_transfer_dma(st, SVGA3D_WRITE_HOST_VRAM);
+ ss->texture_timestamp++;
+ tex->view_age[transfer->level] = ++(tex->age);
+ tex->defined[transfer->face][transfer->level] = TRUE;
+ }
+
+ pipe_texture_reference(&st->base.texture, NULL);
+ FREE(st->swbuf);
+ sws->buffer_destroy(sws, st->hwbuf);
+ FREE(st);
+}
+
+void
+svga_screen_init_texture_functions(struct pipe_screen *screen)
+{
+ screen->texture_create = svga_texture_create;
+ screen->texture_destroy = svga_texture_destroy;
+ screen->get_tex_surface = svga_get_tex_surface;
+ screen->tex_surface_destroy = svga_tex_surface_destroy;
+ screen->texture_blanket = svga_texture_blanket;
+ screen->get_tex_transfer = svga_get_tex_transfer;
+ screen->transfer_map = svga_transfer_map;
+ screen->transfer_unmap = svga_transfer_unmap;
+ screen->tex_transfer_destroy = svga_tex_transfer_destroy;
+}
+
+/***********************************************************************
+ */
+
+struct svga_sampler_view *
+svga_get_tex_sampler_view(struct pipe_context *pipe, struct pipe_texture *pt,
+ unsigned min_lod, unsigned max_lod)
+{
+ struct svga_screen *ss = svga_screen(pt->screen);
+ struct svga_winsys_screen *sws = ss->sws;
+ struct svga_texture *tex = svga_texture(pt);
+ struct svga_sampler_view *sv = NULL;
+ SVGA3dSurfaceFormat format = svga_translate_format(pt->format);
+ boolean view = TRUE;
+
+ assert(pt);
+ assert(min_lod >= 0);
+ assert(min_lod <= max_lod);
+ assert(max_lod <= pt->last_level);
+
+
+ /* Is a view needed */
+ {
+ /*
+ * Can't control max lod. For first level views and when we only
+ * look at one level we disable mip filtering to achive the same
+ * results as a view.
+ */
+ if (min_lod == 0 && max_lod >= pt->last_level)
+ view = FALSE;
+
+ if (pf_is_compressed(pt->format) && view) {
+ format = svga_translate_format_render(pt->format);
+ }
+
+ if (ss->debug.no_sampler_view)
+ view = FALSE;
+
+ if (ss->debug.force_sampler_view)
+ view = TRUE;
+ }
+
+ /* First try the cache */
+ if (view) {
+ pipe_mutex_lock(ss->tex_mutex);
+ if (tex->cached_view &&
+ tex->cached_view->min_lod == min_lod &&
+ tex->cached_view->max_lod == max_lod) {
+ svga_sampler_view_reference(&sv, tex->cached_view);
+ pipe_mutex_unlock(ss->tex_mutex);
+ SVGA_DBG(DEBUG_VIEWS, "svga: Sampler view: reuse %p, %u %u, last %u\n",
+ pt, min_lod, max_lod, pt->last_level);
+ svga_validate_sampler_view(svga_context(pipe), sv);
+ return sv;
+ }
+ pipe_mutex_unlock(ss->tex_mutex);
+ }
+
+ sv = CALLOC_STRUCT(svga_sampler_view);
+ pipe_reference_init(&sv->reference, 1);
+ sv->texture = tex;
+ sv->min_lod = min_lod;
+ sv->max_lod = max_lod;
+
+ /* No view needed just use the whole texture */
+ if (!view) {
+ SVGA_DBG(DEBUG_VIEWS,
+ "svga: Sampler view: no %p, mips %u..%u, nr %u, size (%ux%ux%u), last %u\n",
+ pt, min_lod, max_lod,
+ max_lod - min_lod + 1,
+ pt->width0,
+ pt->height0,
+ pt->depth0,
+ pt->last_level);
+ sv->key.cachable = 0;
+ sws->surface_reference(sws, &sv->handle, tex->handle);
+ return sv;
+ }
+
+ SVGA_DBG(DEBUG_VIEWS,
+ "svga: Sampler view: yes %p, mips %u..%u, nr %u, size (%ux%ux%u), last %u\n",
+ pt, min_lod, max_lod,
+ max_lod - min_lod + 1,
+ pt->width0,
+ pt->height0,
+ pt->depth0,
+ pt->last_level);
+
+ sv->age = tex->age;
+ sv->handle = svga_texture_view_surface(pipe, tex, format,
+ min_lod,
+ max_lod - min_lod + 1,
+ -1, -1,
+ &sv->key);
+
+ if (!sv->handle) {
+ assert(0);
+ sv->key.cachable = 0;
+ sws->surface_reference(sws, &sv->handle, tex->handle);
+ return sv;
+ }
+
+ pipe_mutex_lock(ss->tex_mutex);
+ svga_sampler_view_reference(&tex->cached_view, sv);
+ pipe_mutex_unlock(ss->tex_mutex);
+
+ return sv;
+}
+
+void
+svga_validate_sampler_view(struct svga_context *svga, struct svga_sampler_view *v)
+{
+ struct svga_texture *tex = v->texture;
+ unsigned numFaces;
+ unsigned age = 0;
+ int i, k;
+
+ assert(svga);
+
+ if (v->handle == v->texture->handle)
+ return;
+
+ age = tex->age;
+
+ if(tex->base.target == PIPE_TEXTURE_CUBE)
+ numFaces = 6;
+ else
+ numFaces = 1;
+
+ for (i = v->min_lod; i <= v->max_lod; i++) {
+ for (k = 0; k < numFaces; k++) {
+ if (v->age < tex->view_age[i])
+ svga_texture_copy_handle(svga, NULL,
+ tex->handle, 0, 0, 0, i, k,
+ v->handle, 0, 0, 0, i - v->min_lod, k,
+ u_minify(tex->base.width0, i),
+ u_minify(tex->base.height0, i),
+ u_minify(tex->base.depth0, i));
+ }
+ }
+
+ v->age = age;
+}
+
+void
+svga_destroy_sampler_view_priv(struct svga_sampler_view *v)
+{
+ struct svga_screen *ss = svga_screen(v->texture->base.screen);
+
+ SVGA_DBG(DEBUG_DMA, "unref sid %p (sampler view)\n", v->handle);
+ svga_screen_surface_destroy(ss, &v->key, &v->handle);
+
+ FREE(v);
+}
+
+boolean
+svga_screen_buffer_from_texture(struct pipe_texture *texture,
+ struct pipe_buffer **buffer,
+ unsigned *stride)
+{
+ struct svga_texture *stex = svga_texture(texture);
+
+ *buffer = svga_screen_buffer_wrap_surface
+ (texture->screen,
+ svga_translate_format(texture->format),
+ stex->handle);
+
+ *stride = pf_get_nblocksx(&texture->block, texture->width0) *
+ texture->block.size;
+
+ return *buffer != NULL;
+}
+
+
+struct svga_winsys_surface *
+svga_screen_texture_get_winsys_surface(struct pipe_texture *texture)
+{
+ struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);
+ struct svga_winsys_surface *vsurf = NULL;
+
+ assert(svga_texture(texture)->key.cachable == 0);
+ svga_texture(texture)->key.cachable = 0;
+ sws->surface_reference(sws, &vsurf, svga_texture(texture)->handle);
+ return vsurf;
+}
diff --git a/src/gallium/drivers/svga/svga_screen_texture.h b/src/gallium/drivers/svga/svga_screen_texture.h
new file mode 100644
index 0000000000..1cc4063e65
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_screen_texture.h
@@ -0,0 +1,187 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_TEXTURE_H
+#define SVGA_TEXTURE_H
+
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_state.h"
+#include "svga_screen_cache.h"
+
+struct pipe_context;
+struct pipe_screen;
+struct svga_context;
+struct svga_winsys_surface;
+enum SVGA3dSurfaceFormat;
+
+
+#define SVGA_MAX_TEXTURE_LEVELS 12 /* 2048x2048 */
+
+
+/**
+ * A sampler's view into a texture
+ *
+ * We currently cache one sampler view on
+ * the texture and in there by holding a reference
+ * from the texture to the sampler view.
+ *
+ * Because of this we can not hold a refernce to the
+ * texture from the sampler view. So the user
+ * of the sampler views must make sure that the
+ * texture has a reference take for as long as
+ * the sampler view is refrenced.
+ *
+ * Just unreferencing the sampler_view before the
+ * texture is enough.
+ */
+struct svga_sampler_view
+{
+ struct pipe_reference reference;
+
+ struct svga_texture *texture;
+
+ int min_lod;
+ int max_lod;
+
+ unsigned age;
+
+ struct svga_host_surface_cache_key key;
+ struct svga_winsys_surface *handle;
+};
+
+
+struct svga_texture
+{
+ struct pipe_texture base;
+
+ boolean defined[6][PIPE_MAX_TEXTURE_LEVELS];
+
+ struct svga_sampler_view *cached_view;
+
+ unsigned view_age[SVGA_MAX_TEXTURE_LEVELS];
+ unsigned age;
+
+ boolean views_modified;
+
+ /**
+ * Creation key for the host surface handle.
+ *
+ * This structure describes all the host surface characteristics so that it
+ * can be looked up in cache, since creating a host surface is often a slow
+ * operation.
+ */
+ struct svga_host_surface_cache_key key;
+ struct svga_winsys_surface *handle;
+};
+
+
+struct svga_surface
+{
+ struct pipe_surface base;
+
+ struct svga_host_surface_cache_key key;
+ struct svga_winsys_surface *handle;
+
+ unsigned real_face;
+ unsigned real_level;
+ unsigned real_zslice;
+
+ boolean dirty;
+};
+
+
+struct svga_transfer
+{
+ struct pipe_transfer base;
+
+ struct svga_winsys_buffer *hwbuf;
+
+ /* Height of the hardware buffer in pixel blocks */
+ unsigned hw_nblocksy;
+
+ /* Temporary malloc buffer when we can't allocate a hardware buffer
+ * big enough */
+ void *swbuf;
+};
+
+
+static INLINE struct svga_texture *
+svga_texture(struct pipe_texture *texture)
+{
+ return (struct svga_texture *)texture;
+}
+
+static INLINE struct svga_surface *
+svga_surface(struct pipe_surface *surface)
+{
+ assert(surface);
+ return (struct svga_surface *)surface;
+}
+
+static INLINE struct svga_transfer *
+svga_transfer(struct pipe_transfer *transfer)
+{
+ assert(transfer);
+ return (struct svga_transfer *)transfer;
+}
+
+extern struct svga_sampler_view *
+svga_get_tex_sampler_view(struct pipe_context *pipe,
+ struct pipe_texture *pt,
+ unsigned min_lod, unsigned max_lod);
+
+void
+svga_validate_sampler_view(struct svga_context *svga, struct svga_sampler_view *v);
+
+void
+svga_destroy_sampler_view_priv(struct svga_sampler_view *v);
+
+static INLINE void
+svga_sampler_view_reference(struct svga_sampler_view **ptr, struct svga_sampler_view *v)
+{
+ struct svga_sampler_view *old = *ptr;
+
+ if (pipe_reference((struct pipe_reference **)ptr, &v->reference))
+ svga_destroy_sampler_view_priv(old);
+}
+
+extern void
+svga_propagate_surface(struct pipe_context *pipe, struct pipe_surface *surf);
+
+extern boolean
+svga_surface_needs_propagation(struct pipe_surface *surf);
+
+extern void
+svga_screen_init_texture_functions(struct pipe_screen *screen);
+
+enum SVGA3dSurfaceFormat
+svga_translate_format(enum pipe_format format);
+
+enum SVGA3dSurfaceFormat
+svga_translate_format_render(enum pipe_format format);
+
+
+#endif /* SVGA_TEXTURE_H */
diff --git a/src/gallium/drivers/svga/svga_state.c b/src/gallium/drivers/svga/svga_state.c
new file mode 100644
index 0000000000..1c21d3acfe
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state.c
@@ -0,0 +1,278 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "util/u_debug.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "draw/draw_context.h"
+
+#include "svga_context.h"
+#include "svga_screen.h"
+#include "svga_state.h"
+#include "svga_draw.h"
+#include "svga_cmd.h"
+#include "svga_hw_reg.h"
+
+/* This is just enough to decide whether we need to use the draw
+ * module (swtnl) or not.
+ */
+static const struct svga_tracked_state *need_swtnl_state[] =
+{
+ &svga_update_need_swvfetch,
+ &svga_update_need_pipeline,
+ &svga_update_need_swtnl,
+ NULL
+};
+
+
+/* Atoms to update hardware state prior to emitting a clear or draw
+ * packet.
+ */
+static const struct svga_tracked_state *hw_clear_state[] =
+{
+ &svga_hw_scissor,
+ &svga_hw_viewport,
+ &svga_hw_framebuffer,
+ NULL
+};
+
+
+/* Atoms to update hardware state prior to emitting a draw packet.
+ */
+static const struct svga_tracked_state *hw_draw_state[] =
+{
+ &svga_hw_update_zero_stride,
+ &svga_hw_fs,
+ &svga_hw_vs,
+ &svga_hw_rss,
+ &svga_hw_tss,
+ &svga_hw_tss_binding,
+ &svga_hw_clip_planes,
+ &svga_hw_vdecl,
+ &svga_hw_fs_parameters,
+ &svga_hw_vs_parameters,
+ NULL
+};
+
+
+static const struct svga_tracked_state *swtnl_draw_state[] =
+{
+ &svga_update_swtnl_draw,
+ &svga_update_swtnl_vdecl,
+ NULL
+};
+
+/* Flattens the graph of state dependencies. Could swap the positions
+ * of hw_clear_state and need_swtnl_state without breaking anything.
+ */
+static const struct svga_tracked_state **state_levels[] =
+{
+ need_swtnl_state,
+ hw_clear_state,
+ hw_draw_state,
+ swtnl_draw_state
+};
+
+
+
+static unsigned check_state( unsigned a,
+ unsigned b )
+{
+ return (a & b);
+}
+
+static void accumulate_state( unsigned *a,
+ unsigned b )
+{
+ *a |= b;
+}
+
+
+static void xor_states( unsigned *result,
+ unsigned a,
+ unsigned b )
+{
+ *result = a ^ b;
+}
+
+
+
+static int update_state( struct svga_context *svga,
+ const struct svga_tracked_state *atoms[],
+ unsigned *state )
+{
+ boolean debug = TRUE;
+ enum pipe_error ret = 0;
+ unsigned i;
+
+ ret = svga_hwtnl_flush( svga->hwtnl );
+ if (ret != 0)
+ return ret;
+
+ if (debug) {
+ /* Debug version which enforces various sanity checks on the
+ * state flags which are generated and checked to help ensure
+ * state atoms are ordered correctly in the list.
+ */
+ unsigned examined, prev;
+
+ examined = 0;
+ prev = *state;
+
+ for (i = 0; atoms[i] != NULL; i++) {
+ unsigned generated;
+
+ assert(atoms[i]->dirty);
+ assert(atoms[i]->update);
+
+ if (check_state(*state, atoms[i]->dirty)) {
+ if (0)
+ debug_printf("update: %s\n", atoms[i]->name);
+ ret = atoms[i]->update( svga, *state );
+ if (ret != 0)
+ return ret;
+ }
+
+ /* generated = (prev ^ state)
+ * if (examined & generated)
+ * fail;
+ */
+ xor_states(&generated, prev, *state);
+ if (check_state(examined, generated)) {
+ debug_printf("state atom %s generated state already examined\n",
+ atoms[i]->name);
+ assert(0);
+ }
+
+ prev = *state;
+ accumulate_state(&examined, atoms[i]->dirty);
+ }
+ }
+ else {
+ for (i = 0; atoms[i] != NULL; i++) {
+ if (check_state(*state, atoms[i]->dirty)) {
+ ret = atoms[i]->update( svga, *state );
+ if (ret != 0)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+int svga_update_state( struct svga_context *svga,
+ unsigned max_level )
+{
+ struct svga_screen *screen = svga_screen(svga->pipe.screen);
+ int ret = 0;
+ int i;
+
+ /* Check for updates to bound textures. This can't be done in an
+ * atom as there is no flag which could provoke this test, and we
+ * cannot create one.
+ */
+ if (svga->state.texture_timestamp != screen->texture_timestamp) {
+ svga->state.texture_timestamp = screen->texture_timestamp;
+ svga->dirty |= SVGA_NEW_TEXTURE;
+ }
+
+ for (i = 0; i <= max_level; i++) {
+ svga->dirty |= svga->state.dirty[i];
+
+ if (svga->dirty) {
+ ret = update_state( svga,
+ state_levels[i],
+ &svga->dirty );
+ if (ret != 0)
+ return ret;
+
+ svga->state.dirty[i] = 0;
+ }
+ }
+
+ for (; i < SVGA_STATE_MAX; i++)
+ svga->state.dirty[i] |= svga->dirty;
+
+ svga->dirty = 0;
+ return 0;
+}
+
+
+
+
+void svga_update_state_retry( struct svga_context *svga,
+ unsigned max_level )
+{
+ int ret;
+
+ ret = svga_update_state( svga, max_level );
+
+ if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
+ svga_context_flush(svga, NULL);
+ ret = svga_update_state( svga, max_level );
+ }
+
+ assert( ret == 0 );
+}
+
+
+
+#define EMIT_RS(_rs, _count, _name, _value) \
+do { \
+ _rs[_count].state = _name; \
+ _rs[_count].uintValue = _value; \
+ _count++; \
+} while (0)
+
+
+/* Setup any hardware state which will be constant through the life of
+ * a context.
+ */
+enum pipe_error svga_emit_initial_state( struct svga_context *svga )
+{
+ SVGA3dRenderState *rs;
+ unsigned count = 0;
+ const unsigned COUNT = 2;
+ enum pipe_error ret;
+
+ ret = SVGA3D_BeginSetRenderState( svga->swc, &rs, COUNT );
+ if (ret)
+ return ret;
+
+ /* Always use D3D style coordinate space as this is the only one
+ * which is implemented on all backends.
+ */
+ EMIT_RS(rs, count, SVGA3D_RS_COORDINATETYPE, SVGA3D_COORDINATE_LEFTHANDED );
+ EMIT_RS(rs, count, SVGA3D_RS_FRONTWINDING, SVGA3D_FRONTWINDING_CW );
+
+ assert( COUNT == count );
+ SVGA_FIFOCommitAll( svga->swc );
+
+ return 0;
+
+}
diff --git a/src/gallium/drivers/svga/svga_state.h b/src/gallium/drivers/svga/svga_state.h
new file mode 100644
index 0000000000..22d5a6d552
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state.h
@@ -0,0 +1,95 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_STATE_H
+#define SVGA_STATE_H
+
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_defines.h"
+
+struct svga_context;
+
+
+void svga_init_state( struct svga_context *svga );
+void svga_destroy_state( struct svga_context *svga );
+
+
+struct svga_tracked_state {
+ const char *name;
+ unsigned dirty;
+ int (*update)( struct svga_context *svga, unsigned dirty );
+};
+
+/* NEED_SWTNL
+ */
+extern struct svga_tracked_state svga_update_need_swvfetch;
+extern struct svga_tracked_state svga_update_need_pipeline;
+extern struct svga_tracked_state svga_update_need_swtnl;
+
+/* HW_CLEAR
+ */
+extern struct svga_tracked_state svga_hw_viewport;
+extern struct svga_tracked_state svga_hw_scissor;
+extern struct svga_tracked_state svga_hw_framebuffer;
+
+/* HW_DRAW
+ */
+extern struct svga_tracked_state svga_hw_vs;
+extern struct svga_tracked_state svga_hw_fs;
+extern struct svga_tracked_state svga_hw_rss;
+extern struct svga_tracked_state svga_hw_tss;
+extern struct svga_tracked_state svga_hw_tss_binding;
+extern struct svga_tracked_state svga_hw_clip_planes;
+extern struct svga_tracked_state svga_hw_vdecl;
+extern struct svga_tracked_state svga_hw_fs_parameters;
+extern struct svga_tracked_state svga_hw_vs_parameters;
+extern struct svga_tracked_state svga_hw_update_zero_stride;
+
+/* SWTNL_DRAW
+ */
+extern struct svga_tracked_state svga_update_swtnl_draw;
+extern struct svga_tracked_state svga_update_swtnl_vdecl;
+
+/* Bring the hardware fully up-to-date so that we can emit draw
+ * commands.
+ */
+#define SVGA_STATE_NEED_SWTNL 0
+#define SVGA_STATE_HW_CLEAR 1
+#define SVGA_STATE_HW_DRAW 2
+#define SVGA_STATE_SWTNL_DRAW 3
+#define SVGA_STATE_MAX 4
+
+
+enum pipe_error svga_update_state( struct svga_context *svga,
+ unsigned level );
+
+void svga_update_state_retry( struct svga_context *svga,
+ unsigned level );
+
+
+enum pipe_error svga_emit_initial_state( struct svga_context *svga );
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_state_constants.c b/src/gallium/drivers/svga/svga_state_constants.c
new file mode 100644
index 0000000000..209ed28245
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_constants.c
@@ -0,0 +1,239 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+#include "svga_tgsi.h"
+#include "svga_debug.h"
+
+#include "svga_hw_reg.h"
+
+/***********************************************************************
+ * Hardware update
+ */
+
+/* Convert from PIPE_SHADER_* to SVGA3D_SHADERTYPE_*
+ */
+static int svga_shader_type( int unit )
+{
+ return unit + 1;
+}
+
+
+static int emit_const( struct svga_context *svga,
+ int unit,
+ int i,
+ const float *value )
+{
+ int ret = PIPE_OK;
+
+ if (memcmp(svga->state.hw_draw.cb[unit][i], value, 4 * sizeof(float)) != 0) {
+ if (SVGA_DEBUG & DEBUG_CONSTS)
+ debug_printf("%s %s %d: %f %f %f %f\n",
+ __FUNCTION__,
+ unit == PIPE_SHADER_VERTEX ? "VERT" : "FRAG",
+ i,
+ value[0],
+ value[1],
+ value[2],
+ value[3]);
+
+ ret = SVGA3D_SetShaderConst( svga->swc,
+ i,
+ svga_shader_type(unit),
+ SVGA3D_CONST_TYPE_FLOAT,
+ value );
+ if (ret)
+ return ret;
+
+ memcpy(svga->state.hw_draw.cb[unit][i], value, 4 * sizeof(float));
+ }
+
+ return ret;
+}
+
+static int emit_consts( struct svga_context *svga,
+ int offset,
+ int unit )
+{
+ struct pipe_screen *screen = svga->pipe.screen;
+ unsigned count;
+ const float (*data)[4] = NULL;
+ unsigned i;
+ int ret = PIPE_OK;
+
+ if (svga->curr.cb[unit] == NULL)
+ goto done;
+
+ count = svga->curr.cb[unit]->size / (4 * sizeof(float));
+
+ data = (const float (*)[4])pipe_buffer_map(screen,
+ svga->curr.cb[unit],
+ PIPE_BUFFER_USAGE_CPU_READ);
+ if (data == NULL) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = emit_const( svga, unit, offset + i, data[i] );
+ if (ret)
+ goto done;
+ }
+
+done:
+ if (data)
+ pipe_buffer_unmap(screen, svga->curr.cb[unit]);
+
+ return ret;
+}
+
+static int emit_fs_consts( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct svga_shader_result *result = svga->state.hw_draw.fs;
+ const struct svga_fs_compile_key *key = &result->key.fkey;
+ int ret = 0;
+
+ ret = emit_consts( svga, 0, PIPE_SHADER_FRAGMENT );
+ if (ret)
+ return ret;
+
+ /* The internally generated fragment shader for xor blending
+ * doesn't have a 'result' struct. It should be fixed to avoid
+ * this special case, but work around it with a NULL check:
+ */
+ if (result != NULL &&
+ key->num_unnormalized_coords)
+ {
+ unsigned offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;
+ int i;
+
+ for (i = 0; i < key->num_textures; i++) {
+ if (key->tex[i].unnormalized) {
+ struct pipe_texture *tex = svga->curr.texture[i];
+ float data[4];
+
+ data[0] = 1.0 / (float)tex->width0;
+ data[1] = 1.0 / (float)tex->height0;
+ data[2] = 1.0;
+ data[3] = 1.0;
+
+ ret = emit_const( svga,
+ PIPE_SHADER_FRAGMENT,
+ key->tex[i].width_height_idx + offset,
+ data );
+ if (ret)
+ return ret;
+ }
+ }
+
+ offset += key->num_unnormalized_coords;
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_hw_fs_parameters =
+{
+ "hw fs params",
+ (SVGA_NEW_FS_CONST_BUFFER |
+ SVGA_NEW_FS_RESULT |
+ SVGA_NEW_TEXTURE_BINDING),
+ emit_fs_consts
+};
+
+/***********************************************************************
+ */
+
+static int emit_vs_consts( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct svga_shader_result *result = svga->state.hw_draw.vs;
+ const struct svga_vs_compile_key *key = &result->key.vkey;
+ int ret = 0;
+ unsigned offset;
+
+ /* SVGA_NEW_VS_RESULT
+ */
+ if (result == NULL)
+ return 0;
+
+ /* SVGA_NEW_VS_CONST_BUFFER
+ */
+ ret = emit_consts( svga, 0, PIPE_SHADER_VERTEX );
+ if (ret)
+ return ret;
+
+ offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;
+
+ /* SVGA_NEW_VS_RESULT
+ */
+ if (key->need_prescale) {
+ ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
+ svga->state.hw_clear.prescale.scale );
+ if (ret)
+ return ret;
+
+ ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
+ svga->state.hw_clear.prescale.translate );
+ if (ret)
+ return ret;
+ }
+
+ /* SVGA_NEW_ZERO_STRIDE
+ */
+ if (key->zero_stride_vertex_elements) {
+ unsigned i, curr_zero_stride = 0;
+ for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
+ if (key->zero_stride_vertex_elements & (1 << i)) {
+ ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
+ svga->curr.zero_stride_constants +
+ 4 * curr_zero_stride );
+ if (ret)
+ return ret;
+ ++curr_zero_stride;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_hw_vs_parameters =
+{
+ "hw vs params",
+ (SVGA_NEW_VS_CONST_BUFFER |
+ SVGA_NEW_ZERO_STRIDE |
+ SVGA_NEW_VS_RESULT),
+ emit_vs_consts
+};
+
diff --git a/src/gallium/drivers/svga/svga_state_framebuffer.c b/src/gallium/drivers/svga/svga_state_framebuffer.c
new file mode 100644
index 0000000000..cfdcae4ee4
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_framebuffer.c
@@ -0,0 +1,458 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+#include "svga_debug.h"
+
+#include "svga_hw_reg.h"
+
+
+/***********************************************************************
+ * Hardware state update
+ */
+
+
+static int emit_framebuffer( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
+ struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
+ unsigned i;
+ enum pipe_error ret;
+
+ /* XXX: Need shadow state in svga->hw to eliminate redundant
+ * uploads, especially of NULL buffers.
+ */
+
+ for(i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
+ if (curr->cbufs[i] != hw->cbufs[i]) {
+ if (svga->curr.nr_fbs++ > 8)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, curr->cbufs[i]);
+ if (ret != PIPE_OK)
+ return ret;
+
+ pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
+ }
+ }
+
+
+ if (curr->zsbuf != hw->zsbuf) {
+ ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf);
+ if (ret != PIPE_OK)
+ return ret;
+
+ if (curr->zsbuf &&
+ curr->zsbuf->format == PIPE_FORMAT_Z24S8_UNORM) {
+ ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, curr->zsbuf);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ else {
+ ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+
+ pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
+ }
+
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_hw_framebuffer =
+{
+ "hw framebuffer state",
+ SVGA_NEW_FRAME_BUFFER,
+ emit_framebuffer
+};
+
+
+
+
+/***********************************************************************
+ */
+
+static int emit_viewport( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct pipe_viewport_state *viewport = &svga->curr.viewport;
+ struct svga_prescale prescale;
+ SVGA3dRect rect;
+ /* Not sure if this state is relevant with POSITIONT. Probably
+ * not, but setting to 0,1 avoids some state pingponging.
+ */
+ float range_min = 0.0;
+ float range_max = 1.0;
+ float flip = -1.0;
+ boolean degenerate = FALSE;
+ enum pipe_error ret;
+
+ float fb_width = svga->curr.framebuffer.width;
+ float fb_height = svga->curr.framebuffer.height;
+
+ memset( &prescale, 0, sizeof(prescale) );
+
+ if (svga->curr.rast->templ.bypass_vs_clip_and_viewport) {
+
+ /* Avoid POSITIONT as it has a non trivial implementation outside the D3D
+ * API. Always generate a vertex shader.
+ */
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = svga->curr.framebuffer.width;
+ rect.h = svga->curr.framebuffer.height;
+
+ prescale.scale[0] = 2.0 / (float)rect.w;
+ prescale.scale[1] = - 2.0 / (float)rect.h;
+ prescale.scale[2] = 1.0;
+ prescale.scale[3] = 1.0;
+ prescale.translate[0] = -1.0f;
+ prescale.translate[1] = 1.0f;
+ prescale.translate[2] = 0;
+ prescale.translate[3] = 0;
+ prescale.enabled = TRUE;
+ } else {
+
+ /* Examine gallium viewport transformation and produce a screen
+ * rectangle and possibly vertex shader pre-transformation to
+ * get the same results.
+ */
+ float fx = viewport->scale[0] * -1.0 + viewport->translate[0];
+ float fy = flip * viewport->scale[1] * -1.0 + viewport->translate[1];
+ float fw = viewport->scale[0] * 2;
+ float fh = flip * viewport->scale[1] * 2;
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "\ninitial %f,%f %fx%f\n",
+ fx,
+ fy,
+ fw,
+ fh);
+
+ prescale.scale[0] = 1.0;
+ prescale.scale[1] = 1.0;
+ prescale.scale[2] = 1.0;
+ prescale.scale[3] = 1.0;
+ prescale.translate[0] = 0;
+ prescale.translate[1] = 0;
+ prescale.translate[2] = 0;
+ prescale.translate[3] = 0;
+ prescale.enabled = TRUE;
+
+
+
+ if (fw < 0) {
+ prescale.scale[0] *= -1.0;
+ prescale.translate[0] += -fw;
+ fw = -fw;
+ fx = viewport->scale[0] * 1.0 + viewport->translate[0];
+ }
+
+ if (fh < 0) {
+ prescale.scale[1] *= -1.0;
+ prescale.translate[1] += -fh;
+ fh = -fh;
+ fy = flip * viewport->scale[1] * 1.0 + viewport->translate[1];
+ }
+
+ if (fx < 0) {
+ prescale.translate[0] += fx;
+ prescale.scale[0] *= fw / (fw + fx);
+ fw += fx;
+ fx = 0;
+ }
+
+ if (fy < 0) {
+ prescale.translate[1] += fy;
+ prescale.scale[1] *= fh / (fh + fy);
+ fh += fy;
+ fy = 0;
+ }
+
+ if (fx + fw > fb_width) {
+ prescale.scale[0] *= fw / (fb_width - fx);
+ prescale.translate[0] -= fx * (fw / (fb_width - fx));
+ prescale.translate[0] += fx;
+ fw = fb_width - fx;
+
+ }
+
+ if (fy + fh > fb_height) {
+ prescale.scale[1] *= fh / (fb_height - fy);
+ prescale.translate[1] -= fy * (fh / (fb_height - fy));
+ prescale.translate[1] += fy;
+ fh = fb_height - fy;
+ }
+
+ if (fw < 0 || fh < 0) {
+ fw = fh = fx = fy = 0;
+ degenerate = TRUE;
+ goto out;
+ }
+
+
+ /* D3D viewport is integer space. Convert fx,fy,etc. to
+ * integers.
+ *
+ * TODO: adjust pretranslate correct for any subpixel error
+ * introduced converting to integers.
+ */
+ rect.x = fx;
+ rect.y = fy;
+ rect.w = fw;
+ rect.h = fh;
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "viewport error %f,%f %fx%f\n",
+ fabs((float)rect.x - fx),
+ fabs((float)rect.y - fy),
+ fabs((float)rect.w - fw),
+ fabs((float)rect.h - fh));
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "viewport %d,%d %dx%d\n",
+ rect.x,
+ rect.y,
+ rect.w,
+ rect.h);
+
+
+ /* Finally, to get GL rasterization rules, need to tweak the
+ * screen-space coordinates slightly relative to D3D which is
+ * what hardware implements natively.
+ */
+ if (svga->curr.rast->templ.gl_rasterization_rules) {
+ float adjust_x = 0.0;
+ float adjust_y = 0.0;
+
+ switch (svga->curr.reduced_prim) {
+ case PIPE_PRIM_LINES:
+ adjust_x = -0.5;
+ adjust_y = 0;
+ break;
+ case PIPE_PRIM_POINTS:
+ case PIPE_PRIM_TRIANGLES:
+ adjust_x = -0.375;
+ adjust_y = -0.5;
+ break;
+ }
+
+ prescale.translate[0] += adjust_x;
+ prescale.translate[1] += adjust_y;
+ prescale.translate[2] = 0.5; /* D3D clip space */
+ prescale.scale[2] = 0.5; /* D3D clip space */
+ }
+
+
+ range_min = viewport->scale[2] * -1.0 + viewport->translate[2];
+ range_max = viewport->scale[2] * 1.0 + viewport->translate[2];
+
+ /* D3D (and by implication SVGA) doesn't like dealing with zmax
+ * less than zmin. Detect that case, flip the depth range and
+ * invert our z-scale factor to achieve the same effect.
+ */
+ if (range_min > range_max) {
+ float range_tmp;
+ range_tmp = range_min;
+ range_min = range_max;
+ range_max = range_tmp;
+ prescale.scale[2] = -prescale.scale[2];
+ }
+ }
+
+ if (prescale.enabled) {
+ float H[2];
+ float J[2];
+ int i;
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "prescale %f,%f %fx%f\n",
+ prescale.translate[0],
+ prescale.translate[1],
+ prescale.scale[0],
+ prescale.scale[1]);
+
+ H[0] = (float)rect.w / 2.0;
+ H[1] = -(float)rect.h / 2.0;
+ J[0] = (float)rect.x + (float)rect.w / 2.0;
+ J[1] = (float)rect.y + (float)rect.h / 2.0;
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "H %f,%f\n"
+ "J %fx%f\n",
+ H[0],
+ H[1],
+ J[0],
+ J[1]);
+
+ /* Adjust prescale to take into account the fact that it is
+ * going to be applied prior to the perspective divide and
+ * viewport transformation.
+ *
+ * Vwin = H(Vc/Vc.w) + J
+ *
+ * We want to tweak Vwin with scale and translation from above,
+ * as in:
+ *
+ * Vwin' = S Vwin + T
+ *
+ * But we can only modify the values at Vc. Plugging all the
+ * above together, and rearranging, eventually we get:
+ *
+ * Vwin' = H(Vc'/Vc'.w) + J
+ * where:
+ * Vc' = SVc + KVc.w
+ * K = (T + (S-1)J) / H
+ *
+ * Overwrite prescale.translate with values for K:
+ */
+ for (i = 0; i < 2; i++) {
+ prescale.translate[i] = ((prescale.translate[i] +
+ (prescale.scale[i] - 1.0) * J[i]) / H[i]);
+ }
+
+ SVGA_DBG(DEBUG_VIEWPORT,
+ "clipspace %f,%f %fx%f\n",
+ prescale.translate[0],
+ prescale.translate[1],
+ prescale.scale[0],
+ prescale.scale[1]);
+ }
+
+out:
+ if (degenerate) {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = 1;
+ rect.h = 1;
+ prescale.enabled = FALSE;
+ }
+
+ if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) {
+ ret = SVGA3D_SetViewport(svga->swc, &rect);
+ if(ret != PIPE_OK)
+ return ret;
+
+ memcpy(&svga->state.hw_clear.viewport, &rect, sizeof(rect));
+ assert(sizeof(rect) == sizeof(svga->state.hw_clear.viewport));
+ }
+
+ if (svga->state.hw_clear.depthrange.zmin != range_min ||
+ svga->state.hw_clear.depthrange.zmax != range_max)
+ {
+ ret = SVGA3D_SetZRange(svga->swc, range_min, range_max );
+ if(ret != PIPE_OK)
+ return ret;
+
+ svga->state.hw_clear.depthrange.zmin = range_min;
+ svga->state.hw_clear.depthrange.zmax = range_max;
+ }
+
+ if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) {
+ svga->dirty |= SVGA_NEW_PRESCALE;
+ svga->state.hw_clear.prescale = prescale;
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_hw_viewport =
+{
+ "hw viewport state",
+ ( SVGA_NEW_FRAME_BUFFER |
+ SVGA_NEW_VIEWPORT |
+ SVGA_NEW_RAST |
+ SVGA_NEW_REDUCED_PRIMITIVE ),
+ emit_viewport
+};
+
+
+/***********************************************************************
+ * Scissor state
+ */
+static int emit_scissor_rect( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct pipe_scissor_state *scissor = &svga->curr.scissor;
+ SVGA3dRect rect;
+
+ rect.x = scissor->minx;
+ rect.y = scissor->miny;
+ rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */
+ rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */
+
+ return SVGA3D_SetScissorRect(svga->swc, &rect);
+}
+
+
+struct svga_tracked_state svga_hw_scissor =
+{
+ "hw scissor state",
+ SVGA_NEW_SCISSOR,
+ emit_scissor_rect
+};
+
+
+/***********************************************************************
+ * Userclip state
+ */
+
+static int emit_clip_planes( struct svga_context *svga,
+ unsigned dirty )
+{
+ unsigned i;
+ enum pipe_error ret;
+
+ /* TODO: just emit directly from svga_set_clip_state()?
+ */
+ for (i = 0; i < svga->curr.clip.nr; i++) {
+ ret = SVGA3D_SetClipPlane( svga->swc,
+ i,
+ svga->curr.clip.ucp[i] );
+ if(ret != PIPE_OK)
+ return ret;
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_hw_clip_planes =
+{
+ "hw viewport state",
+ SVGA_NEW_CLIP,
+ emit_clip_planes
+};
diff --git a/src/gallium/drivers/svga/svga_state_fs.c b/src/gallium/drivers/svga/svga_state_fs.c
new file mode 100644
index 0000000000..6ec38ed3e4
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_fs.c
@@ -0,0 +1,282 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+#include "svga_tgsi.h"
+
+#include "svga_hw_reg.h"
+
+
+
+static INLINE int compare_fs_keys( const struct svga_fs_compile_key *a,
+ const struct svga_fs_compile_key *b )
+{
+ unsigned keysize = svga_fs_key_size( a );
+ return memcmp( a, b, keysize );
+}
+
+
+static struct svga_shader_result *search_fs_key( struct svga_fragment_shader *fs,
+ const struct svga_fs_compile_key *key )
+{
+ struct svga_shader_result *result = fs->base.results;
+
+ assert(key);
+
+ for ( ; result; result = result->next) {
+ if (compare_fs_keys( key, &result->key.fkey ) == 0)
+ return result;
+ }
+
+ return NULL;
+}
+
+
+static enum pipe_error compile_fs( struct svga_context *svga,
+ struct svga_fragment_shader *fs,
+ const struct svga_fs_compile_key *key,
+ struct svga_shader_result **out_result )
+{
+ struct svga_shader_result *result;
+ enum pipe_error ret;
+
+ result = svga_translate_fragment_program( fs, key );
+ if (result == NULL) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+
+ ret = SVGA3D_DefineShader(svga->swc,
+ svga->state.next_fs_id,
+ SVGA3D_SHADERTYPE_PS,
+ result->tokens,
+ result->nr_tokens * sizeof result->tokens[0]);
+ if (ret)
+ goto fail;
+
+ *out_result = result;
+ result->id = svga->state.next_fs_id++;
+ result->next = fs->base.results;
+ fs->base.results = result;
+ return PIPE_OK;
+
+fail:
+ if (result)
+ svga_destroy_shader_result( result );
+ return ret;
+}
+
+/* The blend workaround for simulating logicop xor behaviour requires
+ * that the incoming fragment color be white. This change achieves
+ * that by hooking up a hard-wired fragment shader that just emits
+ * color 1,1,1,1
+ *
+ * This is a slightly incomplete solution as it assumes that the
+ * actual bound shader has no other effects beyond generating a
+ * fragment color. In particular shaders containing TEXKIL and/or
+ * depth-write will not have the correct behaviour, nor will those
+ * expecting to use alphatest.
+ *
+ * These are avoidable issues, but they are not much worse than the
+ * unavoidable ones associated with this technique, so it's not clear
+ * how much effort should be expended trying to resolve them - the
+ * ultimate result will still not be correct in most cases.
+ *
+ * Shader below was generated with:
+ * SVGA_DEBUG=tgsi ./mesa/progs/fp/fp-tri white.txt
+ */
+static int emit_white_fs( struct svga_context *svga )
+{
+ int ret;
+
+ /* ps_3_0
+ * def c0, 1.000000, 0.000000, 0.000000, 1.000000
+ * mov oC0, c0.x
+ * end
+ */
+ static const unsigned white_tokens[] = {
+ 0xffff0300,
+ 0x05000051,
+ 0xa00f0000,
+ 0x3f800000,
+ 0x00000000,
+ 0x00000000,
+ 0x3f800000,
+ 0x02000001,
+ 0x800f0800,
+ 0xa0000000,
+ 0x0000ffff,
+ };
+
+ ret = SVGA3D_DefineShader(svga->swc,
+ svga->state.next_fs_id,
+ SVGA3D_SHADERTYPE_PS,
+ white_tokens,
+ sizeof(white_tokens));
+ if (ret)
+ return ret;
+
+ svga->state.white_fs_id = svga->state.next_fs_id++;
+ return 0;
+}
+
+
+/* SVGA_NEW_TEXTURE_BINDING
+ * SVGA_NEW_RAST
+ * SVGA_NEW_NEED_SWTNL
+ * SVGA_NEW_SAMPLER
+ */
+static int make_fs_key( const struct svga_context *svga,
+ struct svga_fs_compile_key *key )
+{
+ int i;
+ int idx = 0;
+
+ memset(key, 0, sizeof *key);
+
+ /* Only need fragment shader fixup for twoside lighting if doing
+ * hwtnl. Otherwise the draw module does the whole job for us.
+ *
+ * SVGA_NEW_SWTNL
+ */
+ if (!svga->state.sw.need_swtnl) {
+ /* SVGA_NEW_RAST
+ */
+ key->light_twoside = svga->curr.rast->templ.light_twoside;
+ key->front_cw = (svga->curr.rast->templ.front_winding ==
+ PIPE_WINDING_CW);
+ }
+
+
+ /* XXX: want to limit this to the textures that the shader actually
+ * refers to.
+ *
+ * SVGA_NEW_TEXTURE_BINDING | SVGA_NEW_SAMPLER
+ */
+ for (i = 0; i < svga->curr.num_textures; i++) {
+ if (svga->curr.texture[i]) {
+ assert(svga->curr.sampler[i]);
+ key->tex[i].texture_target = svga->curr.texture[i]->target;
+ if (!svga->curr.sampler[i]->normalized_coords) {
+ key->tex[i].width_height_idx = idx++;
+ key->tex[i].unnormalized = TRUE;
+ ++key->num_unnormalized_coords;
+ }
+ }
+ }
+ key->num_textures = svga->curr.num_textures;
+
+ idx = 0;
+ for (i = 0; i < svga->curr.num_samplers; ++i) {
+ if (svga->curr.sampler[i]) {
+ key->tex[i].compare_mode = svga->curr.sampler[i]->compare_mode;
+ key->tex[i].compare_func = svga->curr.sampler[i]->compare_func;
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int emit_hw_fs( struct svga_context *svga,
+ unsigned dirty )
+{
+ struct svga_shader_result *result = NULL;
+ unsigned id = SVGA3D_INVALID_ID;
+ int ret = 0;
+
+ /* SVGA_NEW_BLEND
+ */
+ if (svga->curr.blend->need_white_fragments) {
+ if (svga->state.white_fs_id == SVGA3D_INVALID_ID) {
+ ret = emit_white_fs( svga );
+ if (ret)
+ return ret;
+ }
+ id = svga->state.white_fs_id;
+ }
+ else {
+ struct svga_fragment_shader *fs = svga->curr.fs;
+ struct svga_fs_compile_key key;
+
+ /* SVGA_NEW_TEXTURE_BINDING
+ * SVGA_NEW_RAST
+ * SVGA_NEW_NEED_SWTNL
+ * SVGA_NEW_SAMPLER
+ */
+ ret = make_fs_key( svga, &key );
+ if (ret)
+ return ret;
+
+ result = search_fs_key( fs, &key );
+ if (!result) {
+ ret = compile_fs( svga, fs, &key, &result );
+ if (ret)
+ return ret;
+ }
+
+ assert (result);
+ id = result->id;
+ }
+
+ assert(id != SVGA3D_INVALID_ID);
+
+ if (id != svga->state.hw_draw.shader_id[PIPE_SHADER_FRAGMENT]) {
+ ret = SVGA3D_SetShader(svga->swc,
+ SVGA3D_SHADERTYPE_PS,
+ id );
+ if (ret)
+ return ret;
+
+ svga->dirty |= SVGA_NEW_FS_RESULT;
+ svga->state.hw_draw.shader_id[PIPE_SHADER_FRAGMENT] = id;
+ svga->state.hw_draw.fs = result;
+ }
+
+ return 0;
+}
+
+struct svga_tracked_state svga_hw_fs =
+{
+ "fragment shader (hwtnl)",
+ (SVGA_NEW_FS |
+ SVGA_NEW_TEXTURE_BINDING |
+ SVGA_NEW_NEED_SWTNL |
+ SVGA_NEW_RAST |
+ SVGA_NEW_SAMPLER |
+ SVGA_NEW_BLEND),
+ emit_hw_fs
+};
+
+
+
diff --git a/src/gallium/drivers/svga/svga_state_need_swtnl.c b/src/gallium/drivers/svga/svga_state_need_swtnl.c
new file mode 100644
index 0000000000..00201b8091
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_need_swtnl.c
@@ -0,0 +1,200 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_state.h"
+
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_debug.h"
+#include "svga_hw_reg.h"
+
+/***********************************************************************
+ */
+
+static INLINE SVGA3dDeclType
+svga_translate_vertex_format(enum pipe_format format)
+{
+ switch (format) {
+ case PIPE_FORMAT_R32_FLOAT: return SVGA3D_DECLTYPE_FLOAT1;
+ case PIPE_FORMAT_R32G32_FLOAT: return SVGA3D_DECLTYPE_FLOAT2;
+ case PIPE_FORMAT_R32G32B32_FLOAT: return SVGA3D_DECLTYPE_FLOAT3;
+ case PIPE_FORMAT_R32G32B32A32_FLOAT: return SVGA3D_DECLTYPE_FLOAT4;
+ case PIPE_FORMAT_B8G8R8A8_UNORM: return SVGA3D_DECLTYPE_D3DCOLOR;
+ case PIPE_FORMAT_R8G8B8A8_USCALED: return SVGA3D_DECLTYPE_UBYTE4;
+ case PIPE_FORMAT_R16G16_SSCALED: return SVGA3D_DECLTYPE_SHORT2;
+ case PIPE_FORMAT_R16G16B16A16_SSCALED: return SVGA3D_DECLTYPE_SHORT4;
+ case PIPE_FORMAT_R8G8B8A8_UNORM: return SVGA3D_DECLTYPE_UBYTE4N;
+ case PIPE_FORMAT_R16G16_SNORM: return SVGA3D_DECLTYPE_SHORT2N;
+ case PIPE_FORMAT_R16G16B16A16_SNORM: return SVGA3D_DECLTYPE_SHORT4N;
+ case PIPE_FORMAT_R16G16_UNORM: return SVGA3D_DECLTYPE_USHORT2N;
+ case PIPE_FORMAT_R16G16B16A16_UNORM: return SVGA3D_DECLTYPE_USHORT4N;
+
+ /* These formats don't exist yet:
+ *
+ case PIPE_FORMAT_R10G10B10_USCALED: return SVGA3D_DECLTYPE_UDEC3;
+ case PIPE_FORMAT_R10G10B10_SNORM: return SVGA3D_DECLTYPE_DEC3N;
+ case PIPE_FORMAT_R16G16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_2;
+ case PIPE_FORMAT_R16G16B16A16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_4;
+ */
+
+ default:
+ /* There are many formats without hardware support. This case
+ * will be hit regularly, meaning we'll need swvfetch.
+ */
+ return SVGA3D_DECLTYPE_MAX;
+ }
+}
+
+
+static int update_need_swvfetch( struct svga_context *svga,
+ unsigned dirty )
+{
+ unsigned i;
+ boolean need_swvfetch = FALSE;
+
+ for (i = 0; i < svga->curr.num_vertex_elements; i++) {
+ svga->state.sw.ve_format[i] = svga_translate_vertex_format(svga->curr.ve[i].src_format);
+ if (svga->state.sw.ve_format[i] == SVGA3D_DECLTYPE_MAX) {
+ need_swvfetch = TRUE;
+ break;
+ }
+ }
+
+ if (need_swvfetch != svga->state.sw.need_swvfetch) {
+ svga->state.sw.need_swvfetch = need_swvfetch;
+ svga->dirty |= SVGA_NEW_NEED_SWVFETCH;
+ }
+
+ return 0;
+}
+
+struct svga_tracked_state svga_update_need_swvfetch =
+{
+ "update need_swvfetch",
+ ( SVGA_NEW_VELEMENT ),
+ update_need_swvfetch
+};
+
+
+/***********************************************************************
+ */
+
+static int update_need_pipeline( struct svga_context *svga,
+ unsigned dirty )
+{
+
+ boolean need_pipeline = FALSE;
+
+ /* SVGA_NEW_RAST, SVGA_NEW_REDUCED_PRIMITIVE
+ */
+ if (svga->curr.rast->need_pipeline & (1 << svga->curr.reduced_prim)) {
+ SVGA_DBG(DEBUG_SWTNL, "%s: rast need_pipeline (%d) & prim (%x)\n",
+ __FUNCTION__,
+ svga->curr.rast->need_pipeline,
+ (1 << svga->curr.reduced_prim) );
+ need_pipeline = TRUE;
+ }
+
+ /* SVGA_NEW_EDGEFLAGS
+ */
+ if (svga->curr.rast->hw_unfilled != PIPE_POLYGON_MODE_FILL &&
+ svga->curr.reduced_prim == PIPE_PRIM_TRIANGLES &&
+ svga->curr.edgeflags != NULL) {
+ SVGA_DBG(DEBUG_SWTNL, "%s: edgeflags\n", __FUNCTION__);
+ need_pipeline = TRUE;
+ }
+
+ /* SVGA_NEW_CLIP
+ */
+ if (!svga->curr.rast->templ.bypass_vs_clip_and_viewport &&
+ svga->curr.clip.nr) {
+ SVGA_DBG(DEBUG_SWTNL, "%s: userclip\n", __FUNCTION__);
+ need_pipeline = TRUE;
+ }
+
+ if (need_pipeline != svga->state.sw.need_pipeline) {
+ svga->state.sw.need_pipeline = need_pipeline;
+ svga->dirty |= SVGA_NEW_NEED_PIPELINE;
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_update_need_pipeline =
+{
+ "need pipeline",
+ (SVGA_NEW_RAST |
+ SVGA_NEW_CLIP |
+ SVGA_NEW_REDUCED_PRIMITIVE),
+ update_need_pipeline
+};
+
+
+/***********************************************************************
+ */
+
+static int update_need_swtnl( struct svga_context *svga,
+ unsigned dirty )
+{
+ boolean need_swtnl;
+
+ if (svga->debug.no_swtnl) {
+ svga->state.sw.need_swvfetch = 0;
+ svga->state.sw.need_pipeline = 0;
+ }
+
+ need_swtnl = (svga->state.sw.need_swvfetch ||
+ svga->state.sw.need_pipeline);
+
+ if (svga->debug.force_swtnl) {
+ need_swtnl = 1;
+ }
+
+ if (need_swtnl != svga->state.sw.need_swtnl) {
+ SVGA_DBG(DEBUG_SWTNL|DEBUG_PERF,
+ "%s need_swvfetch: %s, need_pipeline %s\n",
+ __FUNCTION__,
+ svga->state.sw.need_swvfetch ? "true" : "false",
+ svga->state.sw.need_pipeline ? "true" : "false");
+
+ svga->state.sw.need_swtnl = need_swtnl;
+ svga->dirty |= SVGA_NEW_NEED_SWTNL;
+ svga->swtnl.new_vdecl = TRUE;
+ }
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_update_need_swtnl =
+{
+ "need swtnl",
+ (SVGA_NEW_NEED_PIPELINE |
+ SVGA_NEW_NEED_SWVFETCH),
+ update_need_swtnl
+};
diff --git a/src/gallium/drivers/svga/svga_state_rss.c b/src/gallium/drivers/svga/svga_state_rss.c
new file mode 100644
index 0000000000..8b6803a285
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_rss.c
@@ -0,0 +1,268 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+
+#include "svga_hw_reg.h"
+
+
+
+struct rs_queue {
+ unsigned rs_count;
+ SVGA3dRenderState rs[SVGA3D_RS_MAX];
+};
+
+
+#define EMIT_RS(svga, value, token, fail) \
+do { \
+ if (svga->state.hw_draw.rs[SVGA3D_RS_##token] != value) { \
+ svga_queue_rs( &queue, SVGA3D_RS_##token, value ); \
+ svga->state.hw_draw.rs[SVGA3D_RS_##token] = value; \
+ } \
+} while (0)
+
+#define EMIT_RS_FLOAT(svga, fvalue, token, fail) \
+do { \
+ unsigned value = fui(fvalue); \
+ if (svga->state.hw_draw.rs[SVGA3D_RS_##token] != value) { \
+ svga_queue_rs( &queue, SVGA3D_RS_##token, value ); \
+ svga->state.hw_draw.rs[SVGA3D_RS_##token] = value; \
+ } \
+} while (0)
+
+
+static INLINE void
+svga_queue_rs( struct rs_queue *q,
+ unsigned rss,
+ unsigned value )
+{
+ q->rs[q->rs_count].state = rss;
+ q->rs[q->rs_count].uintValue = value;
+ q->rs_count++;
+}
+
+
+/* Compare old and new render states and emit differences between them
+ * to hardware. Simplest implementation would be to emit the whole of
+ * the "to" state.
+ */
+static int emit_rss( struct svga_context *svga,
+ unsigned dirty )
+{
+ struct rs_queue queue;
+
+ queue.rs_count = 0;
+
+ if (dirty & SVGA_NEW_BLEND) {
+ const struct svga_blend_state *curr = svga->curr.blend;
+
+ EMIT_RS( svga, curr->rt[0].writemask, COLORWRITEENABLE, fail );
+ EMIT_RS( svga, curr->rt[0].blend_enable, BLENDENABLE, fail );
+
+ if (curr->rt[0].blend_enable) {
+ EMIT_RS( svga, curr->rt[0].srcblend, SRCBLEND, fail );
+ EMIT_RS( svga, curr->rt[0].dstblend, DSTBLEND, fail );
+ EMIT_RS( svga, curr->rt[0].blendeq, BLENDEQUATION, fail );
+
+ EMIT_RS( svga, curr->rt[0].separate_alpha_blend_enable,
+ SEPARATEALPHABLENDENABLE, fail );
+
+ if (curr->rt[0].separate_alpha_blend_enable) {
+ EMIT_RS( svga, curr->rt[0].srcblend_alpha, SRCBLENDALPHA, fail );
+ EMIT_RS( svga, curr->rt[0].dstblend_alpha, DSTBLENDALPHA, fail );
+ EMIT_RS( svga, curr->rt[0].blendeq_alpha, BLENDEQUATIONALPHA, fail );
+ }
+ }
+ }
+
+
+ if (dirty & (SVGA_NEW_DEPTH_STENCIL | SVGA_NEW_RAST)) {
+ const struct svga_depth_stencil_state *curr = svga->curr.depth;
+ const struct svga_rasterizer_state *rast = svga->curr.rast;
+
+ if (!curr->stencil[0].enabled)
+ {
+ /* Stencil disabled
+ */
+ EMIT_RS( svga, FALSE, STENCILENABLE, fail );
+ EMIT_RS( svga, FALSE, STENCILENABLE2SIDED, fail );
+ }
+ else if (curr->stencil[0].enabled && !curr->stencil[1].enabled)
+ {
+ /* Regular stencil
+ */
+ EMIT_RS( svga, TRUE, STENCILENABLE, fail );
+ EMIT_RS( svga, FALSE, STENCILENABLE2SIDED, fail );
+
+ EMIT_RS( svga, curr->stencil[0].func, STENCILFUNC, fail );
+ EMIT_RS( svga, curr->stencil[0].fail, STENCILFAIL, fail );
+ EMIT_RS( svga, curr->stencil[0].zfail, STENCILZFAIL, fail );
+ EMIT_RS( svga, curr->stencil[0].pass, STENCILPASS, fail );
+
+ EMIT_RS( svga, curr->stencil_ref, STENCILREF, fail );
+ EMIT_RS( svga, curr->stencil_mask, STENCILMASK, fail );
+ EMIT_RS( svga, curr->stencil_writemask, STENCILWRITEMASK, fail );
+ }
+ else
+ {
+ int cw, ccw;
+
+ /* Hardware frontwinding is always CW, so if ours is also CW,
+ * then our definition of front face agrees with hardware.
+ * Otherwise need to flip.
+ */
+ if (rast->templ.front_winding == PIPE_WINDING_CW) {
+ cw = 0;
+ ccw = 1;
+ }
+ else {
+ cw = 1;
+ ccw = 0;
+ }
+
+ /* Twoside stencil
+ */
+ EMIT_RS( svga, TRUE, STENCILENABLE, fail );
+ EMIT_RS( svga, TRUE, STENCILENABLE2SIDED, fail );
+
+ EMIT_RS( svga, curr->stencil[cw].func, STENCILFUNC, fail );
+ EMIT_RS( svga, curr->stencil[cw].fail, STENCILFAIL, fail );
+ EMIT_RS( svga, curr->stencil[cw].zfail, STENCILZFAIL, fail );
+ EMIT_RS( svga, curr->stencil[cw].pass, STENCILPASS, fail );
+
+ EMIT_RS( svga, curr->stencil[ccw].func, CCWSTENCILFUNC, fail );
+ EMIT_RS( svga, curr->stencil[ccw].fail, CCWSTENCILFAIL, fail );
+ EMIT_RS( svga, curr->stencil[ccw].zfail, CCWSTENCILZFAIL, fail );
+ EMIT_RS( svga, curr->stencil[ccw].pass, CCWSTENCILPASS, fail );
+
+ EMIT_RS( svga, curr->stencil_ref, STENCILREF, fail );
+ EMIT_RS( svga, curr->stencil_mask, STENCILMASK, fail );
+ EMIT_RS( svga, curr->stencil_writemask, STENCILWRITEMASK, fail );
+ }
+
+ EMIT_RS( svga, curr->zenable, ZENABLE, fail );
+ if (curr->zenable) {
+ EMIT_RS( svga, curr->zfunc, ZFUNC, fail );
+ EMIT_RS( svga, curr->zwriteenable, ZWRITEENABLE, fail );
+ }
+
+ EMIT_RS( svga, curr->alphatestenable, ALPHATESTENABLE, fail );
+ if (curr->alphatestenable) {
+ EMIT_RS( svga, curr->alphafunc, ALPHAFUNC, fail );
+ EMIT_RS_FLOAT( svga, curr->alpharef, ALPHAREF, fail );
+ }
+ }
+
+
+ if (dirty & SVGA_NEW_RAST)
+ {
+ const struct svga_rasterizer_state *curr = svga->curr.rast;
+
+ /* Shademode: still need to rearrange index list to move
+ * flat-shading PV first vertex.
+ */
+ EMIT_RS( svga, curr->shademode, SHADEMODE, fail );
+ EMIT_RS( svga, curr->cullmode, CULLMODE, fail );
+ EMIT_RS( svga, curr->scissortestenable, SCISSORTESTENABLE, fail );
+ EMIT_RS( svga, curr->multisampleantialias, MULTISAMPLEANTIALIAS, fail );
+ EMIT_RS( svga, curr->lastpixel, LASTPIXEL, fail );
+ EMIT_RS( svga, curr->linepattern, LINEPATTERN, fail );
+ EMIT_RS_FLOAT( svga, curr->pointsize, POINTSIZE, fail );
+ EMIT_RS_FLOAT( svga, curr->pointsize_min, POINTSIZEMIN, fail );
+ EMIT_RS_FLOAT( svga, curr->pointsize_max, POINTSIZEMAX, fail );
+ }
+
+ if (dirty & (SVGA_NEW_RAST | SVGA_NEW_FRAME_BUFFER | SVGA_NEW_NEED_PIPELINE))
+ {
+ const struct svga_rasterizer_state *curr = svga->curr.rast;
+ float slope = 0.0;
+ float bias = 0.0;
+
+ /* Need to modify depth bias according to bound depthbuffer
+ * format. Don't do hardware depthbias while the software
+ * pipeline is active.
+ */
+ if (!svga->state.sw.need_pipeline &&
+ svga->curr.framebuffer.zsbuf)
+ {
+ slope = curr->slopescaledepthbias;
+ bias = svga->curr.depthscale * curr->depthbias;
+ }
+
+ EMIT_RS_FLOAT( svga, slope, SLOPESCALEDEPTHBIAS, fail );
+ EMIT_RS_FLOAT( svga, bias, DEPTHBIAS, fail );
+ }
+
+
+ if (queue.rs_count) {
+ SVGA3dRenderState *rs;
+
+ if (SVGA3D_BeginSetRenderState( svga->swc,
+ &rs,
+ queue.rs_count ) != PIPE_OK)
+ goto fail;
+
+ memcpy( rs,
+ queue.rs,
+ queue.rs_count * sizeof queue.rs[0]);
+
+ SVGA_FIFOCommitAll( svga->swc );
+ }
+
+ /* Also blend color:
+ */
+
+ return 0;
+
+fail:
+ /* XXX: need to poison cached hardware state on failure to ensure
+ * dirty state gets re-emitted. Fix this by re-instating partial
+ * FIFOCommit command and only updating cached hw state once the
+ * initial allocation has succeeded.
+ */
+ memset(svga->state.hw_draw.rs, 0xcd, sizeof(svga->state.hw_draw.rs));
+
+ return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+
+struct svga_tracked_state svga_hw_rss =
+{
+ "hw rss state",
+
+ (SVGA_NEW_BLEND |
+ SVGA_NEW_DEPTH_STENCIL |
+ SVGA_NEW_RAST |
+ SVGA_NEW_FRAME_BUFFER |
+ SVGA_NEW_NEED_PIPELINE),
+
+ emit_rss
+};
diff --git a/src/gallium/drivers/svga/svga_state_tss.c b/src/gallium/drivers/svga/svga_state_tss.c
new file mode 100644
index 0000000000..b313794520
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_tss.c
@@ -0,0 +1,279 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+
+#include "svga_screen_texture.h"
+#include "svga_winsys.h"
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+
+#include "svga_hw_reg.h"
+
+
+void svga_cleanup_tss_binding(struct svga_context *svga)
+{
+ int i;
+ unsigned count = MAX2( svga->curr.num_textures,
+ svga->state.hw_draw.num_views );
+
+ for (i = 0; i < count; i++) {
+ struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+
+ svga_sampler_view_reference(&view->v, NULL);
+ pipe_texture_reference( &svga->curr.texture[i], NULL );
+ pipe_texture_reference( &view->texture, NULL );
+
+ view->dirty = 1;
+ }
+}
+
+
+static int
+update_tss_binding(struct svga_context *svga,
+ unsigned dirty )
+{
+ unsigned i;
+ unsigned count = MAX2( svga->curr.num_textures,
+ svga->state.hw_draw.num_views );
+ unsigned min_lod;
+ unsigned max_lod;
+
+
+ struct {
+ struct {
+ unsigned unit;
+ struct svga_hw_view_state *view;
+ } bind[PIPE_MAX_SAMPLERS];
+
+ unsigned bind_count;
+ } queue;
+
+ queue.bind_count = 0;
+
+ for (i = 0; i < count; i++) {
+ const struct svga_sampler_state *s = svga->curr.sampler[i];
+ struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+
+ /* get min max lod */
+ if (svga->curr.texture[i]) {
+ min_lod = MAX2(s->view_min_lod, 0);
+ max_lod = MIN2(s->view_max_lod, svga->curr.texture[i]->last_level);
+ } else {
+ min_lod = 0;
+ max_lod = 0;
+ }
+
+ if (view->texture != svga->curr.texture[i] ||
+ view->min_lod != min_lod ||
+ view->max_lod != max_lod) {
+
+ svga_sampler_view_reference(&view->v, NULL);
+ pipe_texture_reference( &view->texture, svga->curr.texture[i] );
+
+ view->dirty = TRUE;
+ view->min_lod = min_lod;
+ view->max_lod = max_lod;
+
+ if (svga->curr.texture[i])
+ view->v = svga_get_tex_sampler_view(&svga->pipe,
+ svga->curr.texture[i],
+ min_lod,
+ max_lod);
+ }
+
+ if (view->dirty) {
+ queue.bind[queue.bind_count].unit = i;
+ queue.bind[queue.bind_count].view = view;
+ queue.bind_count++;
+ }
+ else if (view->v) {
+ svga_validate_sampler_view(svga, view->v);
+ }
+ }
+
+ svga->state.hw_draw.num_views = svga->curr.num_textures;
+
+ if (queue.bind_count) {
+ SVGA3dTextureState *ts;
+
+ if (SVGA3D_BeginSetTextureState( svga->swc,
+ &ts,
+ queue.bind_count ) != PIPE_OK)
+ goto fail;
+
+ for (i = 0; i < queue.bind_count; i++) {
+ ts[i].stage = queue.bind[i].unit;
+ ts[i].name = SVGA3D_TS_BIND_TEXTURE;
+
+ if (queue.bind[i].view->v) {
+ svga->swc->surface_relocation(svga->swc,
+ &ts[i].value,
+ queue.bind[i].view->v->handle,
+ PIPE_BUFFER_USAGE_GPU_READ);
+ }
+ else {
+ ts[i].value = SVGA3D_INVALID_ID;
+ }
+
+ queue.bind[i].view->dirty = FALSE;
+ }
+
+ SVGA_FIFOCommitAll( svga->swc );
+ }
+
+ return 0;
+
+fail:
+ return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+
+struct svga_tracked_state svga_hw_tss_binding = {
+ "texture binding emit",
+ SVGA_NEW_TEXTURE_BINDING |
+ SVGA_NEW_SAMPLER,
+ update_tss_binding
+};
+
+
+/***********************************************************************
+ */
+
+struct ts_queue {
+ unsigned ts_count;
+ SVGA3dTextureState ts[PIPE_MAX_SAMPLERS*SVGA3D_TS_MAX];
+};
+
+
+#define EMIT_TS(svga, unit, val, token, fail) \
+do { \
+ if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \
+ svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \
+ svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \
+ } \
+} while (0)
+
+#define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail) \
+do { \
+ unsigned val = fui(fvalue); \
+ if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \
+ svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \
+ svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \
+ } \
+} while (0)
+
+
+static INLINE void
+svga_queue_tss( struct ts_queue *q,
+ unsigned unit,
+ unsigned tss,
+ unsigned value )
+{
+ assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
+ q->ts[q->ts_count].stage = unit;
+ q->ts[q->ts_count].name = tss;
+ q->ts[q->ts_count].value = value;
+ q->ts_count++;
+}
+
+
+static int
+update_tss(struct svga_context *svga,
+ unsigned dirty )
+{
+ unsigned i;
+ struct ts_queue queue;
+
+ queue.ts_count = 0;
+ for (i = 0; i < svga->curr.num_samplers; i++) {
+ if (svga->curr.sampler[i]) {
+ const struct svga_sampler_state *curr = svga->curr.sampler[i];
+
+ EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
+ EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
+ EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
+ EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
+ EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
+ EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
+ EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
+ EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
+ EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
+ // TEXCOORDINDEX -- hopefully not needed
+
+ if (svga->curr.tex_flags.flag_1d & (1 << i)) {
+ debug_printf("wrap 1d tex %d\n", i);
+ EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
+ }
+ else
+ EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
+
+ if (svga->curr.tex_flags.flag_srgb & (1 << i))
+ EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
+ else
+ EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
+
+ }
+ }
+
+ if (queue.ts_count) {
+ SVGA3dTextureState *ts;
+
+ if (SVGA3D_BeginSetTextureState( svga->swc,
+ &ts,
+ queue.ts_count ) != PIPE_OK)
+ goto fail;
+
+ memcpy( ts,
+ queue.ts,
+ queue.ts_count * sizeof queue.ts[0]);
+
+ SVGA_FIFOCommitAll( svga->swc );
+ }
+
+ return 0;
+
+fail:
+ /* XXX: need to poison cached hardware state on failure to ensure
+ * dirty state gets re-emitted. Fix this by re-instating partial
+ * FIFOCommit command and only updating cached hw state once the
+ * initial allocation has succeeded.
+ */
+ memset(svga->state.hw_draw.ts, 0xcd, sizeof(svga->state.hw_draw.ts));
+
+ return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+
+struct svga_tracked_state svga_hw_tss = {
+ "texture state emit",
+ (SVGA_NEW_SAMPLER |
+ SVGA_NEW_TEXTURE_FLAGS),
+ update_tss
+};
+
diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c
new file mode 100644
index 0000000000..c534308f50
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_vdecl.c
@@ -0,0 +1,182 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_upload_mgr.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_draw.h"
+#include "svga_tgsi.h"
+#include "svga_screen.h"
+#include "svga_screen_buffer.h"
+
+#include "svga_hw_reg.h"
+
+
+static int
+upload_user_buffers( struct svga_context *svga )
+{
+ enum pipe_error ret = PIPE_OK;
+ int i;
+ int nr;
+
+ if (0)
+ debug_printf("%s: %d\n", __FUNCTION__, svga->curr.num_vertex_buffers);
+
+ nr = svga->curr.num_vertex_buffers;
+
+ for (i = 0; i < nr; i++)
+ {
+ if (svga_buffer_is_user_buffer(svga->curr.vb[i].buffer))
+ {
+ struct pipe_buffer *upload_buffer = NULL;
+ unsigned offset = /*svga->curr.vb[i].buffer_offset*/ 0;
+ unsigned size = svga->curr.vb[i].buffer->size /*- offset*/;
+ unsigned upload_offset;
+
+ ret = u_upload_buffer( svga->upload_vb,
+ offset,
+ size,
+ svga->curr.vb[i].buffer,
+ &upload_offset,
+ &upload_buffer );
+ if (ret)
+ return ret;
+
+ if (0)
+ debug_printf("%s: %d: orig buf %p upl buf %p ofs %d sz %d\n",
+ __FUNCTION__,
+ i,
+ svga->curr.vb[i].buffer,
+ upload_buffer, upload_offset, size);
+
+ /* Make sure we release the old buffer and end up with the
+ * correct refcount on the uploaded buffer.
+ */
+ pipe_buffer_reference( &svga->curr.vb[i].buffer, NULL );
+ svga->curr.vb[i].buffer = upload_buffer;
+ svga->curr.vb[i].buffer_offset = upload_offset;
+ }
+ }
+
+ if (0)
+ debug_printf("%s: DONE\n", __FUNCTION__);
+
+ return ret;
+}
+
+
+/***********************************************************************
+ */
+
+
+static int emit_hw_vs_vdecl( struct svga_context *svga,
+ unsigned dirty )
+{
+ const struct pipe_vertex_element *ve = svga->curr.ve;
+ SVGA3dVertexDecl decl;
+ unsigned i;
+
+ assert(svga->curr.num_vertex_elements >=
+ svga->curr.vs->base.info.file_count[TGSI_FILE_INPUT]);
+
+ svga_hwtnl_reset_vdecl( svga->hwtnl,
+ svga->curr.num_vertex_elements );
+
+ for (i = 0; i < svga->curr.num_vertex_elements; i++) {
+ const struct pipe_vertex_buffer *vb = &svga->curr.vb[ve[i].vertex_buffer_index];
+ unsigned usage, index;
+
+
+ svga_generate_vdecl_semantics( i, &usage, &index );
+
+ /* SVGA_NEW_VELEMENT
+ */
+ decl.identity.type = svga->state.sw.ve_format[i];
+ decl.identity.method = SVGA3D_DECLMETHOD_DEFAULT;
+ decl.identity.usage = usage;
+ decl.identity.usageIndex = index;
+ decl.array.stride = vb->stride;
+ decl.array.offset = (vb->buffer_offset +
+ ve[i].src_offset);
+
+ svga_hwtnl_vdecl( svga->hwtnl,
+ i,
+ &decl,
+ vb->buffer );
+ }
+
+ return 0;
+}
+
+
+static int emit_hw_vdecl( struct svga_context *svga,
+ unsigned dirty )
+{
+ int ret = 0;
+
+ /* SVGA_NEW_NEED_SWTNL
+ */
+ if (svga->state.sw.need_swtnl)
+ return 0; /* Do not emit during swtnl */
+
+ /* If we get to here, we know that we're going to draw. Upload
+ * userbuffers now and try to combine multiple userbuffers from
+ * multiple draw calls into a single host buffer for performance.
+ */
+ if (svga->curr.any_user_vertex_buffers &&
+ SVGA_COMBINE_USERBUFFERS)
+ {
+ ret = upload_user_buffers( svga );
+ if (ret)
+ return ret;
+
+ svga->curr.any_user_vertex_buffers = FALSE;
+ }
+
+ return emit_hw_vs_vdecl( svga, dirty );
+}
+
+
+struct svga_tracked_state svga_hw_vdecl =
+{
+ "hw vertex decl state (hwtnl version)",
+ ( SVGA_NEW_NEED_SWTNL |
+ SVGA_NEW_VELEMENT |
+ SVGA_NEW_VBUFFER |
+ SVGA_NEW_RAST |
+ SVGA_NEW_FS |
+ SVGA_NEW_VS ),
+ emit_hw_vdecl
+};
+
+
+
+
+
+
diff --git a/src/gallium/drivers/svga/svga_state_vs.c b/src/gallium/drivers/svga/svga_state_vs.c
new file mode 100644
index 0000000000..a947745732
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_state_vs.c
@@ -0,0 +1,239 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "pipe/p_inlines.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "translate/translate.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_cmd.h"
+#include "svga_tgsi.h"
+
+#include "svga_hw_reg.h"
+
+/***********************************************************************
+ */
+
+
+static INLINE int compare_vs_keys( const struct svga_vs_compile_key *a,
+ const struct svga_vs_compile_key *b )
+{
+ unsigned keysize = svga_vs_key_size( a );
+ return memcmp( a, b, keysize );
+}
+
+
+static struct svga_shader_result *search_vs_key( struct svga_vertex_shader *vs,
+ const struct svga_vs_compile_key *key )
+{
+ struct svga_shader_result *result = vs->base.results;
+
+ assert(key);
+
+ for ( ; result; result = result->next) {
+ if (compare_vs_keys( key, &result->key.vkey ) == 0)
+ return result;
+ }
+
+ return NULL;
+}
+
+
+static enum pipe_error compile_vs( struct svga_context *svga,
+ struct svga_vertex_shader *vs,
+ const struct svga_vs_compile_key *key,
+ struct svga_shader_result **out_result )
+{
+ struct svga_shader_result *result;
+ enum pipe_error ret = PIPE_OK;
+
+ result = svga_translate_vertex_program( vs, key );
+ if (result == NULL) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+ ret = SVGA3D_DefineShader(svga->swc,
+ svga->state.next_vs_id,
+ SVGA3D_SHADERTYPE_VS,
+ result->tokens,
+ result->nr_tokens * sizeof result->tokens[0]);
+ if (ret)
+ goto fail;
+
+ *out_result = result;
+ result->id = svga->state.next_vs_id++;
+ result->next = vs->base.results;
+ vs->base.results = result;
+ return PIPE_OK;
+
+fail:
+ if (result)
+ svga_destroy_shader_result( result );
+ return ret;
+}
+
+/* SVGA_NEW_PRESCALE, SVGA_NEW_RAST, SVGA_NEW_ZERO_STRIDE
+ */
+static int make_vs_key( struct svga_context *svga,
+ struct svga_vs_compile_key *key )
+{
+ memset(key, 0, sizeof *key);
+ key->need_prescale = svga->state.hw_clear.prescale.enabled;
+ key->allow_psiz = svga->curr.rast->templ.point_size_per_vertex;
+ key->zero_stride_vertex_elements =
+ svga->curr.zero_stride_vertex_elements;
+ key->num_zero_stride_vertex_elements =
+ svga->curr.num_zero_stride_vertex_elements;
+ return 0;
+}
+
+
+
+static int emit_hw_vs( struct svga_context *svga,
+ unsigned dirty )
+{
+ struct svga_shader_result *result = NULL;
+ unsigned id = SVGA3D_INVALID_ID;
+ int ret = 0;
+
+ /* SVGA_NEW_NEED_SWTNL */
+ if (!svga->state.sw.need_swtnl) {
+ struct svga_vertex_shader *vs = svga->curr.vs;
+ struct svga_vs_compile_key key;
+
+ ret = make_vs_key( svga, &key );
+ if (ret)
+ return ret;
+
+ result = search_vs_key( vs, &key );
+ if (!result) {
+ ret = compile_vs( svga, vs, &key, &result );
+ if (ret)
+ return ret;
+ }
+
+ assert (result);
+ id = result->id;
+ }
+
+ if (id != svga->state.hw_draw.shader_id[PIPE_SHADER_VERTEX]) {
+ ret = SVGA3D_SetShader(svga->swc,
+ SVGA3D_SHADERTYPE_VS,
+ id );
+ if (ret)
+ return ret;
+
+ svga->dirty |= SVGA_NEW_VS_RESULT;
+ svga->state.hw_draw.shader_id[PIPE_SHADER_VERTEX] = id;
+ svga->state.hw_draw.vs = result;
+ }
+
+ return 0;
+}
+
+struct svga_tracked_state svga_hw_vs =
+{
+ "vertex shader (hwtnl)",
+ (SVGA_NEW_VS |
+ SVGA_NEW_PRESCALE |
+ SVGA_NEW_NEED_SWTNL |
+ SVGA_NEW_ZERO_STRIDE),
+ emit_hw_vs
+};
+
+
+/***********************************************************************
+ */
+static int update_zero_stride( struct svga_context *svga,
+ unsigned dirty )
+{
+ unsigned i;
+
+ svga->curr.zero_stride_vertex_elements = 0;
+ svga->curr.num_zero_stride_vertex_elements = 0;
+
+ for (i = 0; i < svga->curr.num_vertex_elements; i++) {
+ const struct pipe_vertex_element *vel = &svga->curr.ve[i];
+ const struct pipe_vertex_buffer *vbuffer = &svga->curr.vb[
+ vel->vertex_buffer_index];
+ if (vbuffer->stride == 0) {
+ unsigned const_idx =
+ svga->curr.num_zero_stride_vertex_elements;
+ struct translate *translate;
+ struct translate_key key;
+ void *mapped_buffer;
+
+ svga->curr.zero_stride_vertex_elements |= (1 << i);
+ ++svga->curr.num_zero_stride_vertex_elements;
+
+ key.output_stride = 4 * sizeof(float);
+ key.nr_elements = 1;
+ key.element[0].input_format = vel->src_format;
+ key.element[0].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ key.element[0].input_buffer = vel->vertex_buffer_index;
+ key.element[0].input_offset = vel->src_offset;
+ key.element[0].output_offset = const_idx * 4 * sizeof(float);
+
+ translate_key_sanitize(&key);
+ /* translate_generic_create is technically private but
+ * we don't want to code-generate, just want generic
+ * translation */
+ translate = translate_generic_create(&key);
+
+ assert(vel->src_offset == 0);
+
+ mapped_buffer = pipe_buffer_map_range(svga->pipe.screen,
+ vbuffer->buffer,
+ vel->src_offset,
+ pf_get_size(vel->src_format),
+ PIPE_BUFFER_USAGE_CPU_READ);
+ translate->set_buffer(translate, vel->vertex_buffer_index,
+ mapped_buffer,
+ vbuffer->stride);
+ translate->run(translate, 0, 1,
+ svga->curr.zero_stride_constants);
+
+ pipe_buffer_unmap(svga->pipe.screen,
+ vbuffer->buffer);
+ translate->release(translate);
+ }
+ }
+
+ if (svga->curr.num_zero_stride_vertex_elements)
+ svga->dirty |= SVGA_NEW_ZERO_STRIDE;
+
+ return 0;
+}
+
+struct svga_tracked_state svga_hw_update_zero_stride =
+{
+ "update zero_stride",
+ ( SVGA_NEW_VELEMENT |
+ SVGA_NEW_VBUFFER ),
+ update_zero_stride
+};
diff --git a/src/gallium/drivers/svga/svga_swtnl.h b/src/gallium/drivers/svga/svga_swtnl.h
new file mode 100644
index 0000000000..4882f26b17
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_swtnl.h
@@ -0,0 +1,52 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_SWTNL_H
+#define SVGA_SWTNL_H
+
+#include "pipe/p_compiler.h"
+
+struct svga_context;
+struct pipe_context;
+struct pipe_buffer;
+struct vbuf_render;
+
+
+boolean svga_init_swtnl( struct svga_context *svga );
+void svga_destroy_swtnl( struct svga_context *svga );
+
+
+enum pipe_error
+svga_swtnl_draw_range_elements(struct svga_context *svga,
+ struct pipe_buffer *indexBuffer,
+ unsigned indexSize,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim,
+ unsigned start,
+ unsigned count);
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_swtnl_backend.c b/src/gallium/drivers/svga/svga_swtnl_backend.c
new file mode 100644
index 0000000000..b4f757a47a
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_swtnl_backend.c
@@ -0,0 +1,349 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "draw/draw_vbuf.h"
+#include "draw/draw_context.h"
+#include "draw/draw_vertex.h"
+
+#include "util/u_debug.h"
+#include "pipe/p_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/u_simple_shaders.h"
+
+#include "svga_context.h"
+#include "svga_state.h"
+#include "svga_swtnl.h"
+
+#include "svga_types.h"
+#include "svga_reg.h"
+#include "svga3d_reg.h"
+#include "svga_draw.h"
+#include "svga_swtnl_private.h"
+
+
+static const struct vertex_info *
+svga_vbuf_render_get_vertex_info( struct vbuf_render *render )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+
+ svga_swtnl_update_vdecl(svga);
+
+ return &svga_render->vertex_info;
+}
+
+
+static boolean
+svga_vbuf_render_allocate_vertices( struct vbuf_render *render,
+ ushort vertex_size,
+ ushort nr_vertices )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+ struct pipe_screen *screen = svga->pipe.screen;
+ size_t size = (size_t)nr_vertices * (size_t)vertex_size;
+ boolean new_vbuf = FALSE;
+ boolean new_ibuf = FALSE;
+
+ if (svga_render->vertex_size != vertex_size)
+ svga->swtnl.new_vdecl = TRUE;
+ svga_render->vertex_size = (size_t)vertex_size;
+
+ if (svga->swtnl.new_vbuf)
+ new_ibuf = new_vbuf = TRUE;
+ svga->swtnl.new_vbuf = FALSE;
+
+ if (svga_render->vbuf_size < svga_render->vbuf_offset + svga_render->vbuf_used + size)
+ new_vbuf = TRUE;
+
+ if (new_vbuf)
+ pipe_buffer_reference(&svga_render->vbuf, NULL);
+ if (new_ibuf)
+ pipe_buffer_reference(&svga_render->ibuf, NULL);
+
+ if (!svga_render->vbuf) {
+ svga_render->vbuf_size = MAX2(size, svga_render->vbuf_alloc_size);
+ svga_render->vbuf = pipe_buffer_create(screen,
+ 0,
+ PIPE_BUFFER_USAGE_VERTEX,
+ svga_render->vbuf_size);
+ if(!svga_render->vbuf) {
+ svga_context_flush(svga, NULL);
+ svga_render->vbuf = pipe_buffer_create(screen,
+ 0,
+ PIPE_BUFFER_USAGE_VERTEX,
+ svga_render->vbuf_size);
+ assert(svga_render->vbuf);
+ }
+
+ svga->swtnl.new_vdecl = TRUE;
+ svga_render->vbuf_offset = 0;
+ } else {
+ svga_render->vbuf_offset += svga_render->vbuf_used;
+ }
+
+ svga_render->vbuf_used = 0;
+
+ if (svga->swtnl.new_vdecl)
+ svga_render->vdecl_offset = svga_render->vbuf_offset;
+
+ return TRUE;
+}
+
+static void *
+svga_vbuf_render_map_vertices( struct vbuf_render *render )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+ struct pipe_screen *screen = svga->pipe.screen;
+
+ char *ptr = (char*)pipe_buffer_map(screen,
+ svga_render->vbuf,
+ PIPE_BUFFER_USAGE_CPU_WRITE |
+ PIPE_BUFFER_USAGE_FLUSH_EXPLICIT);
+ return ptr + svga_render->vbuf_offset;
+}
+
+static void
+svga_vbuf_render_unmap_vertices( struct vbuf_render *render,
+ ushort min_index,
+ ushort max_index )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+ struct pipe_screen *screen = svga->pipe.screen;
+ unsigned offset, length;
+ size_t used = svga_render->vertex_size * ((size_t)max_index + 1);
+
+ offset = svga_render->vbuf_offset + svga_render->vertex_size * min_index;
+ length = svga_render->vertex_size * (max_index + 1 - min_index);
+ pipe_buffer_flush_mapped_range(screen, svga_render->vbuf, offset, length);
+ pipe_buffer_unmap(screen, svga_render->vbuf);
+ svga_render->min_index = min_index;
+ svga_render->max_index = max_index;
+ svga_render->vbuf_used = MAX2(svga_render->vbuf_used, used);
+}
+
+static boolean
+svga_vbuf_render_set_primitive( struct vbuf_render *render,
+ unsigned prim )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ svga_render->prim = prim;
+
+ return TRUE;
+}
+
+static void
+svga_vbuf_sumbit_state( struct svga_vbuf_render *svga_render )
+{
+ struct svga_context *svga = svga_render->svga;
+ SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS];
+ enum pipe_error ret;
+ int i;
+
+ /* if the vdecl or vbuf hasn't changed do nothing */
+ if (!svga->swtnl.new_vdecl)
+ return;
+
+ memcpy(vdecl, svga_render->vdecl, sizeof(vdecl));
+
+ /* flush the hw state */
+ ret = svga_hwtnl_flush(svga->hwtnl);
+ if (ret) {
+ svga_context_flush(svga, NULL);
+ ret = svga_hwtnl_flush(svga->hwtnl);
+ /* if we hit this path we might become synced with hw */
+ svga->swtnl.new_vbuf = TRUE;
+ assert(ret == 0);
+ }
+
+ svga_hwtnl_reset_vdecl(svga->hwtnl, svga_render->vdecl_count);
+
+ for (i = 0; i < svga_render->vdecl_count; i++) {
+ vdecl[i].array.offset += svga_render->vdecl_offset;
+
+ svga_hwtnl_vdecl( svga->hwtnl,
+ i,
+ &vdecl[i],
+ svga_render->vbuf );
+ }
+
+ /* We have already taken care of flatshading, so let the hwtnl
+ * module use whatever is most convenient:
+ */
+ if (svga->state.sw.need_pipeline) {
+ svga_hwtnl_set_flatshade(svga->hwtnl, FALSE, FALSE);
+ svga_hwtnl_set_unfilled(svga->hwtnl, PIPE_POLYGON_MODE_FILL);
+ }
+ else {
+ svga_hwtnl_set_flatshade( svga->hwtnl,
+ svga->curr.rast->templ.flatshade,
+ svga->curr.rast->templ.flatshade_first );
+
+ svga_hwtnl_set_unfilled( svga->hwtnl,
+ svga->curr.rast->hw_unfilled );
+ }
+
+ svga->swtnl.new_vdecl = FALSE;
+}
+
+static void
+svga_vbuf_render_draw_arrays( struct vbuf_render *render,
+ unsigned start,
+ uint nr )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+ unsigned bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size;
+ enum pipe_error ret = 0;
+
+ svga_vbuf_sumbit_state(svga_render);
+
+ /* Need to call update_state() again as the draw module may have
+ * altered some of our state behind our backs. Testcase:
+ * redbook/polys.c
+ */
+ svga_update_state_retry( svga, SVGA_STATE_HW_DRAW );
+
+ ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr);
+ if (ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr);
+ svga->swtnl.new_vbuf = TRUE;
+ assert(ret == PIPE_OK);
+ }
+}
+
+
+static void
+svga_vbuf_render_draw( struct vbuf_render *render,
+ const ushort *indices,
+ uint nr_indices)
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+ struct svga_context *svga = svga_render->svga;
+ struct pipe_screen *screen = svga->pipe.screen;
+ unsigned bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size;
+ boolean ret;
+ size_t size = 2 * nr_indices;
+
+ assert(( svga_render->vbuf_offset - svga_render->vdecl_offset) % svga_render->vertex_size == 0);
+
+ if (svga_render->ibuf_size < svga_render->ibuf_offset + size)
+ pipe_buffer_reference(&svga_render->ibuf, NULL);
+
+ if (!svga_render->ibuf) {
+ svga_render->ibuf_size = MAX2(size, svga_render->ibuf_alloc_size);
+ svga_render->ibuf = pipe_buffer_create(screen,
+ 0,
+ PIPE_BUFFER_USAGE_VERTEX,
+ svga_render->ibuf_size);
+ svga_render->ibuf_offset = 0;
+ }
+
+ pipe_buffer_write(screen, svga_render->ibuf,
+ svga_render->ibuf_offset, 2 * nr_indices, indices);
+
+
+ /* off to hardware */
+ svga_vbuf_sumbit_state(svga_render);
+
+ /* Need to call update_state() again as the draw module may have
+ * altered some of our state behind our backs. Testcase:
+ * redbook/polys.c
+ */
+ svga_update_state_retry( svga, SVGA_STATE_HW_DRAW );
+
+ ret = svga_hwtnl_draw_range_elements(svga->hwtnl,
+ svga_render->ibuf,
+ 2,
+ svga_render->min_index,
+ svga_render->max_index,
+ svga_render->prim,
+ svga_render->ibuf_offset / 2, nr_indices, bias);
+ if(ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = svga_hwtnl_draw_range_elements(svga->hwtnl,
+ svga_render->ibuf,
+ 2,
+ svga_render->min_index,
+ svga_render->max_index,
+ svga_render->prim,
+ svga_render->ibuf_offset / 2, nr_indices, bias);
+ svga->swtnl.new_vbuf = TRUE;
+ assert(ret == PIPE_OK);
+ }
+
+ svga_render->ibuf_offset += size;
+}
+
+
+static void
+svga_vbuf_render_release_vertices( struct vbuf_render *render )
+{
+
+}
+
+
+static void
+svga_vbuf_render_destroy( struct vbuf_render *render )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(render);
+
+ pipe_buffer_reference(&svga_render->vbuf, NULL);
+ pipe_buffer_reference(&svga_render->ibuf, NULL);
+ FREE(svga_render);
+}
+
+
+/**
+ * Create a new primitive render.
+ */
+struct vbuf_render *
+svga_vbuf_render_create( struct svga_context *svga )
+{
+ struct svga_vbuf_render *svga_render = CALLOC_STRUCT(svga_vbuf_render);
+
+ svga_render->svga = svga;
+ svga_render->ibuf_size = 0;
+ svga_render->vbuf_size = 0;
+ svga_render->ibuf_alloc_size = 4*1024;
+ svga_render->vbuf_alloc_size = 64*1024;
+ svga_render->base.max_vertex_buffer_bytes = 64*1024/10;
+ svga_render->base.max_indices = 65536;
+ svga_render->base.get_vertex_info = svga_vbuf_render_get_vertex_info;
+ svga_render->base.allocate_vertices = svga_vbuf_render_allocate_vertices;
+ svga_render->base.map_vertices = svga_vbuf_render_map_vertices;
+ svga_render->base.unmap_vertices = svga_vbuf_render_unmap_vertices;
+ svga_render->base.set_primitive = svga_vbuf_render_set_primitive;
+ svga_render->base.draw = svga_vbuf_render_draw;
+ svga_render->base.draw_arrays = svga_vbuf_render_draw_arrays;
+ svga_render->base.release_vertices = svga_vbuf_render_release_vertices;
+ svga_render->base.destroy = svga_vbuf_render_destroy;
+
+ return &svga_render->base;
+}
diff --git a/src/gallium/drivers/svga/svga_swtnl_draw.c b/src/gallium/drivers/svga/svga_swtnl_draw.c
new file mode 100644
index 0000000000..8b14c913f7
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_swtnl_draw.c
@@ -0,0 +1,170 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_state.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_swtnl.h"
+#include "svga_state.h"
+#include "svga_swtnl_private.h"
+
+
+
+enum pipe_error
+svga_swtnl_draw_range_elements(struct svga_context *svga,
+ struct pipe_buffer *indexBuffer,
+ unsigned indexSize,
+ unsigned min_index,
+ unsigned max_index,
+ unsigned prim, unsigned start, unsigned count)
+{
+ struct draw_context *draw = svga->swtnl.draw;
+ unsigned i;
+ const void *map;
+ enum pipe_error ret;
+
+ assert(!svga->dirty);
+ assert(svga->state.sw.need_swtnl);
+ assert(draw);
+
+ ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW);
+ if (ret) {
+ svga_context_flush(svga, NULL);
+ ret = svga_update_state(svga, SVGA_STATE_SWTNL_DRAW);
+ svga->swtnl.new_vbuf = TRUE;
+ assert(ret == PIPE_OK);
+ }
+
+ /*
+ * Map vertex buffers
+ */
+ for (i = 0; i < svga->curr.num_vertex_buffers; i++) {
+ map = pipe_buffer_map(svga->pipe.screen,
+ svga->curr.vb[i].buffer,
+ PIPE_BUFFER_USAGE_CPU_READ);
+
+ draw_set_mapped_vertex_buffer(draw, i, map);
+ }
+
+ /* Map index buffer, if present */
+ if (indexBuffer) {
+ map = pipe_buffer_map(svga->pipe.screen, indexBuffer,
+ PIPE_BUFFER_USAGE_CPU_READ);
+
+ draw_set_mapped_element_buffer_range(draw,
+ indexSize,
+ min_index,
+ max_index,
+ map);
+ }
+
+ if (svga->curr.cb[PIPE_SHADER_VERTEX]) {
+ map = pipe_buffer_map(svga->pipe.screen,
+ svga->curr.cb[PIPE_SHADER_VERTEX],
+ PIPE_BUFFER_USAGE_CPU_READ);
+ assert(map);
+ draw_set_mapped_constant_buffer(
+ draw,
+ map,
+ svga->curr.cb[PIPE_SHADER_VERTEX]->size);
+ }
+
+ draw_arrays(svga->swtnl.draw, prim, start, count);
+
+ draw_flush(svga->swtnl.draw);
+
+ /* Ensure the draw module didn't touch this */
+ assert(i == svga->curr.num_vertex_buffers);
+
+ /*
+ * unmap vertex/index buffers
+ */
+ for (i = 0; i < svga->curr.num_vertex_buffers; i++) {
+ pipe_buffer_unmap(svga->pipe.screen, svga->curr.vb[i].buffer);
+ draw_set_mapped_vertex_buffer(draw, i, NULL);
+ }
+
+ if (indexBuffer) {
+ pipe_buffer_unmap(svga->pipe.screen, indexBuffer);
+ draw_set_mapped_element_buffer(draw, 0, NULL);
+ }
+
+ if (svga->curr.cb[PIPE_SHADER_VERTEX]) {
+ pipe_buffer_unmap(svga->pipe.screen,
+ svga->curr.cb[PIPE_SHADER_VERTEX]);
+ }
+
+ return ret;
+}
+
+
+
+
+boolean svga_init_swtnl( struct svga_context *svga )
+{
+ svga->swtnl.backend = svga_vbuf_render_create(svga);
+ if(!svga->swtnl.backend)
+ goto fail;
+
+ /*
+ * Create drawing context and plug our rendering stage into it.
+ */
+ svga->swtnl.draw = draw_create();
+ if (svga->swtnl.draw == NULL)
+ goto fail;
+
+
+ draw_set_rasterize_stage(svga->swtnl.draw,
+ draw_vbuf_stage( svga->swtnl.draw, svga->swtnl.backend ));
+
+ draw_set_render(svga->swtnl.draw, svga->swtnl.backend);
+
+ draw_install_aaline_stage(svga->swtnl.draw, &svga->pipe);
+ draw_install_aapoint_stage(svga->swtnl.draw, &svga->pipe);
+ draw_install_pstipple_stage(svga->swtnl.draw, &svga->pipe);
+
+ draw_set_driver_clipping(svga->swtnl.draw, debug_get_bool_option("SVGA_SWTNL_FSE", FALSE));
+
+ return TRUE;
+
+fail:
+ if (svga->swtnl.backend)
+ svga->swtnl.backend->destroy( svga->swtnl.backend );
+
+ if (svga->swtnl.draw)
+ draw_destroy( svga->swtnl.draw );
+
+ return FALSE;
+}
+
+
+void svga_destroy_swtnl( struct svga_context *svga )
+{
+ draw_destroy( svga->swtnl.draw );
+}
diff --git a/src/gallium/drivers/svga/svga_swtnl_private.h b/src/gallium/drivers/svga/svga_swtnl_private.h
new file mode 100644
index 0000000000..9bbb42910f
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_swtnl_private.h
@@ -0,0 +1,93 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_SWTNL_PRIVATE_H
+#define SVGA_SWTNL_PRIVATE_H
+
+#include "svga_swtnl.h"
+#include "draw/draw_vertex.h"
+
+#include "svga_types.h"
+#include "svga3d_reg.h"
+
+/**
+ * Primitive renderer for svga.
+ */
+struct svga_vbuf_render {
+ struct vbuf_render base;
+
+ struct svga_context *svga;
+ struct vertex_info vertex_info;
+
+ unsigned vertex_size;
+
+ unsigned prim;
+
+ struct pipe_buffer *vbuf;
+ struct pipe_buffer *ibuf;
+
+ /* current size of buffer */
+ size_t vbuf_size;
+ size_t ibuf_size;
+
+ /* size of that the buffer should be */
+ size_t vbuf_alloc_size;
+ size_t ibuf_alloc_size;
+
+ /* current write place */
+ size_t vbuf_offset;
+ size_t ibuf_offset;
+
+ /* currently used */
+ size_t vbuf_used;
+
+ SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS];
+ unsigned vdecl_offset;
+ unsigned vdecl_count;
+
+ ushort min_index;
+ ushort max_index;
+};
+
+/**
+ * Basically a cast wrapper.
+ */
+static INLINE struct svga_vbuf_render *
+svga_vbuf_render( struct vbuf_render *render )
+{
+ assert(render);
+ return (struct svga_vbuf_render *)render;
+}
+
+
+struct vbuf_render *
+svga_vbuf_render_create( struct svga_context *svga );
+
+
+int
+svga_swtnl_update_vdecl( struct svga_context *svga );
+
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_swtnl_state.c b/src/gallium/drivers/svga/svga_swtnl_state.c
new file mode 100644
index 0000000000..1616312113
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_swtnl_state.c
@@ -0,0 +1,242 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_state.h"
+#include "util/u_memory.h"
+
+#include "svga_context.h"
+#include "svga_swtnl.h"
+#include "svga_state.h"
+
+#include "svga_swtnl_private.h"
+
+
+#define SVGA_POINT_ADJ_X -0.375
+#define SVGA_POINT_ADJ_Y -0.5
+
+#define SVGA_LINE_ADJ_X -0.5
+#define SVGA_LINE_ADJ_Y -0.5
+
+#define SVGA_TRIANGLE_ADJ_X -0.375
+#define SVGA_TRIANGLE_ADJ_Y -0.5
+
+
+static void set_draw_viewport( struct svga_context *svga )
+{
+ struct pipe_viewport_state vp = svga->curr.viewport;
+ float adjx = 0;
+ float adjy = 0;
+
+ switch (svga->curr.reduced_prim) {
+ case PIPE_PRIM_POINTS:
+ adjx = SVGA_POINT_ADJ_X;
+ adjy = SVGA_POINT_ADJ_Y;
+ break;
+ case PIPE_PRIM_LINES:
+ /* XXX: This is to compensate for the fact that wide lines are
+ * going to be drawn with triangles, but we're not catching all
+ * cases where that will happen.
+ */
+ if (svga->curr.rast->templ.line_width > 1.0)
+ {
+ adjx = SVGA_LINE_ADJ_X + 0.175;
+ adjy = SVGA_LINE_ADJ_Y - 0.175;
+ }
+ else {
+ adjx = SVGA_LINE_ADJ_X;
+ adjy = SVGA_LINE_ADJ_Y;
+ }
+ break;
+ case PIPE_PRIM_TRIANGLES:
+ adjx += SVGA_TRIANGLE_ADJ_X;
+ adjy += SVGA_TRIANGLE_ADJ_Y;
+ break;
+ }
+
+ vp.translate[0] += adjx;
+ vp.translate[1] += adjy;
+
+ draw_set_viewport_state(svga->swtnl.draw, &vp);
+}
+
+static int update_swtnl_draw( struct svga_context *svga,
+ unsigned dirty )
+{
+ draw_flush( svga->swtnl.draw );
+
+ if (dirty & SVGA_NEW_VS)
+ draw_bind_vertex_shader(svga->swtnl.draw,
+ svga->curr.vs->draw_shader);
+
+ if (dirty & SVGA_NEW_VBUFFER)
+ draw_set_vertex_buffers(svga->swtnl.draw,
+ svga->curr.num_vertex_buffers,
+ svga->curr.vb);
+
+ if (dirty & SVGA_NEW_VELEMENT)
+ draw_set_vertex_elements(svga->swtnl.draw,
+ svga->curr.num_vertex_elements,
+ svga->curr.ve );
+
+ if (dirty & SVGA_NEW_CLIP)
+ draw_set_clip_state(svga->swtnl.draw,
+ &svga->curr.clip);
+
+ if (dirty & (SVGA_NEW_VIEWPORT |
+ SVGA_NEW_REDUCED_PRIMITIVE |
+ SVGA_NEW_RAST))
+ set_draw_viewport( svga );
+
+ if (dirty & SVGA_NEW_RAST)
+ draw_set_rasterizer_state(svga->swtnl.draw,
+ &svga->curr.rast->templ);
+
+ if (dirty & SVGA_NEW_FRAME_BUFFER)
+ draw_set_mrd(svga->swtnl.draw,
+ svga->curr.depthscale);
+
+ if (dirty & SVGA_NEW_EDGEFLAGS)
+ draw_set_edgeflags( svga->swtnl.draw,
+ svga->curr.edgeflags );
+
+ return 0;
+}
+
+
+struct svga_tracked_state svga_update_swtnl_draw =
+{
+ "update draw module state",
+ (SVGA_NEW_VS |
+ SVGA_NEW_VBUFFER |
+ SVGA_NEW_VELEMENT |
+ SVGA_NEW_CLIP |
+ SVGA_NEW_VIEWPORT |
+ SVGA_NEW_RAST |
+ SVGA_NEW_FRAME_BUFFER |
+ SVGA_NEW_REDUCED_PRIMITIVE |
+ SVGA_NEW_EDGEFLAGS),
+ update_swtnl_draw
+};
+
+
+int svga_swtnl_update_vdecl( struct svga_context *svga )
+{
+ struct svga_vbuf_render *svga_render = svga_vbuf_render(svga->swtnl.backend);
+ struct draw_context *draw = svga->swtnl.draw;
+ struct vertex_info *vinfo = &svga_render->vertex_info;
+ SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS];
+ const enum interp_mode colorInterp =
+ svga->curr.rast->templ.flatshade ? INTERP_CONSTANT : INTERP_LINEAR;
+ const struct svga_fragment_shader *fs = svga->curr.fs;
+ int offset = 0;
+ int nr_decls = 0;
+ int src, i;
+
+ memset(vinfo, 0, sizeof(*vinfo));
+ memset(vdecl, 0, sizeof(vdecl));
+
+ /* always add position */
+ src = draw_find_vs_output(draw, TGSI_SEMANTIC_POSITION, 0);
+ draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_LINEAR, src);
+ vinfo->attrib[0].emit = EMIT_4F;
+ vdecl[0].array.offset = offset;
+ vdecl[0].identity.type = SVGA3D_DECLTYPE_FLOAT4;
+ vdecl[0].identity.usage = SVGA3D_DECLUSAGE_POSITIONT;
+ vdecl[0].identity.usageIndex = 0;
+ offset += 16;
+ nr_decls++;
+
+ for (i = 0; i < fs->base.info.num_inputs; i++) {
+ unsigned name = fs->base.info.input_semantic_name[i];
+ unsigned index = fs->base.info.input_semantic_index[i];
+ src = draw_find_vs_output(draw, name, index);
+ vdecl[nr_decls].array.offset = offset;
+ vdecl[nr_decls].identity.usageIndex = fs->base.info.input_semantic_index[i];
+
+ switch (name) {
+ case TGSI_SEMANTIC_COLOR:
+ draw_emit_vertex_attr(vinfo, EMIT_4F, colorInterp, src);
+ vdecl[nr_decls].identity.usage = SVGA3D_DECLUSAGE_COLOR;
+ vdecl[nr_decls].identity.type = SVGA3D_DECLTYPE_FLOAT4;
+ offset += 16;
+ nr_decls++;
+ break;
+ case TGSI_SEMANTIC_GENERIC:
+ draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, src);
+ vdecl[nr_decls].identity.usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ vdecl[nr_decls].identity.type = SVGA3D_DECLTYPE_FLOAT4;
+ vdecl[nr_decls].identity.usageIndex += 1;
+ offset += 16;
+ nr_decls++;
+ break;
+ case TGSI_SEMANTIC_FOG:
+ draw_emit_vertex_attr(vinfo, EMIT_1F, INTERP_PERSPECTIVE, src);
+ vdecl[nr_decls].identity.usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ vdecl[nr_decls].identity.type = SVGA3D_DECLTYPE_FLOAT1;
+ assert(vdecl[nr_decls].identity.usageIndex == 0);
+ offset += 4;
+ nr_decls++;
+ break;
+ case TGSI_SEMANTIC_POSITION:
+ /* generated internally, not a vertex shader output */
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ draw_compute_vertex_size(vinfo);
+
+ svga_render->vdecl_count = nr_decls;
+ for (i = 0; i < svga_render->vdecl_count; i++)
+ vdecl[i].array.stride = offset;
+
+ if (memcmp(svga_render->vdecl, vdecl, sizeof(vdecl)) == 0)
+ return 0;
+
+ memcpy(svga_render->vdecl, vdecl, sizeof(vdecl));
+ svga->swtnl.new_vdecl = TRUE;
+
+ return 0;
+}
+
+
+static int update_swtnl_vdecl( struct svga_context *svga,
+ unsigned dirty )
+{
+ return svga_swtnl_update_vdecl( svga );
+}
+
+
+struct svga_tracked_state svga_update_swtnl_vdecl =
+{
+ "update draw module vdecl",
+ (SVGA_NEW_VS |
+ SVGA_NEW_FS),
+ update_swtnl_vdecl
+};
diff --git a/src/gallium/drivers/svga/svga_tgsi.c b/src/gallium/drivers/svga/svga_tgsi.c
new file mode 100644
index 0000000000..b8ef137c01
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi.c
@@ -0,0 +1,280 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_shader_tokens.h"
+#include "pipe/p_defines.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_scan.h"
+#include "util/u_memory.h"
+
+#include "svgadump/svga_shader_dump.h"
+
+#include "svga_context.h"
+#include "svga_tgsi.h"
+#include "svga_tgsi_emit.h"
+#include "svga_debug.h"
+
+#include "svga_hw_reg.h"
+#include "svga3d_shaderdefs.h"
+
+
+/* Sinkhole used only in error conditions.
+ */
+static char err_buf[128];
+
+#if 0
+static void svga_destroy_shader_emitter( struct svga_shader_emitter *emit )
+{
+ if (emit->buf != err_buf)
+ FREE(emit->buf);
+}
+#endif
+
+
+static boolean svga_shader_expand( struct svga_shader_emitter *emit )
+{
+ char *new_buf;
+ unsigned newsize = emit->size * 2;
+
+ if(emit->buf != err_buf)
+ new_buf = REALLOC(emit->buf, emit->size, newsize);
+ else
+ new_buf = NULL;
+
+ if (new_buf == NULL) {
+ emit->ptr = err_buf;
+ emit->buf = err_buf;
+ emit->size = sizeof(err_buf);
+ return FALSE;
+ }
+
+ emit->size = newsize;
+ emit->ptr = new_buf + (emit->ptr - emit->buf);
+ emit->buf = new_buf;
+ return TRUE;
+}
+
+static INLINE boolean reserve( struct svga_shader_emitter *emit,
+ unsigned nr_dwords )
+{
+ if (emit->ptr - emit->buf + nr_dwords * sizeof(unsigned) >= emit->size) {
+ if (!svga_shader_expand( emit ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+boolean svga_shader_emit_dword( struct svga_shader_emitter *emit,
+ unsigned dword )
+{
+ if (!reserve(emit, 1))
+ return FALSE;
+
+ *(unsigned *)emit->ptr = dword;
+ emit->ptr += sizeof dword;
+ return TRUE;
+}
+
+boolean svga_shader_emit_dwords( struct svga_shader_emitter *emit,
+ const unsigned *dwords,
+ unsigned nr )
+{
+ if (!reserve(emit, nr))
+ return FALSE;
+
+ memcpy( emit->ptr, dwords, nr * sizeof *dwords );
+ emit->ptr += nr * sizeof *dwords;
+ return TRUE;
+}
+
+boolean svga_shader_emit_opcode( struct svga_shader_emitter *emit,
+ unsigned opcode )
+{
+ SVGA3dShaderInstToken *here;
+
+ if (!reserve(emit, 1))
+ return FALSE;
+
+ here = (SVGA3dShaderInstToken *)emit->ptr;
+ here->value = opcode;
+
+ if (emit->insn_offset) {
+ SVGA3dShaderInstToken *prev = (SVGA3dShaderInstToken *)(emit->buf +
+ emit->insn_offset);
+ prev->size = (here - prev) - 1;
+ }
+
+ emit->insn_offset = emit->ptr - emit->buf;
+ emit->ptr += sizeof(unsigned);
+ return TRUE;
+}
+
+#define SVGA3D_PS_2X (SVGA3D_PS_20 | 1)
+#define SVGA3D_VS_2X (SVGA3D_VS_20 | 1)
+
+static boolean svga_shader_emit_header( struct svga_shader_emitter *emit )
+{
+ SVGA3dShaderVersion header;
+
+ memset( &header, 0, sizeof header );
+
+ switch (emit->unit) {
+ case PIPE_SHADER_FRAGMENT:
+ header.value = emit->use_sm30 ? SVGA3D_PS_30 : SVGA3D_PS_2X;
+ break;
+ case PIPE_SHADER_VERTEX:
+ header.value = emit->use_sm30 ? SVGA3D_VS_30 : SVGA3D_VS_2X;
+ break;
+ }
+
+ return svga_shader_emit_dword( emit, header.value );
+}
+
+
+
+
+
+/* Parse TGSI shader and translate to SVGA/DX9 serialized
+ * representation.
+ *
+ * In this function SVGA shader is emitted to an in-memory buffer that
+ * can be dynamically grown. Once we've finished and know how large
+ * it is, it will be copied to a hardware buffer for upload.
+ */
+static struct svga_shader_result *
+svga_tgsi_translate( const struct svga_shader *shader,
+ union svga_compile_key key,
+ unsigned unit )
+{
+ struct svga_shader_result *result = NULL;
+ struct svga_shader_emitter emit;
+ int ret = 0;
+
+ memset(&emit, 0, sizeof(emit));
+
+ emit.use_sm30 = shader->use_sm30;
+ emit.size = 1024;
+ emit.buf = MALLOC(emit.size);
+ if (emit.buf == NULL) {
+ ret = PIPE_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+ emit.ptr = emit.buf;
+ emit.unit = unit;
+ emit.key = key;
+
+ tgsi_scan_shader( shader->tokens, &emit.info);
+
+ emit.imm_start = emit.info.file_max[TGSI_FILE_CONSTANT] + 1;
+
+ if (unit == PIPE_SHADER_FRAGMENT)
+ emit.imm_start += key.fkey.num_unnormalized_coords;
+
+ if (unit == PIPE_SHADER_VERTEX) {
+ emit.imm_start += key.vkey.need_prescale ? 2 : 0;
+ emit.imm_start += key.vkey.num_zero_stride_vertex_elements;
+ }
+
+ emit.nr_hw_const = (emit.imm_start + emit.info.file_max[TGSI_FILE_IMMEDIATE] + 1);
+
+ emit.nr_hw_temp = emit.info.file_max[TGSI_FILE_TEMPORARY] + 1;
+ emit.in_main_func = TRUE;
+
+ if (!svga_shader_emit_header( &emit ))
+ goto fail;
+
+ if (!svga_shader_emit_instructions( &emit, shader->tokens ))
+ goto fail;
+
+ result = CALLOC_STRUCT(svga_shader_result);
+ if (result == NULL)
+ goto fail;
+
+ result->shader = shader;
+ result->tokens = (const unsigned *)emit.buf;
+ result->nr_tokens = (emit.ptr - emit.buf) / sizeof(unsigned);
+ memcpy(&result->key, &key, sizeof key);
+
+ if (SVGA_DEBUG & DEBUG_TGSI)
+ {
+ debug_printf( "#####################################\n" );
+ debug_printf( "Shader %u below\n", shader->id );
+ tgsi_dump( shader->tokens, 0 );
+ if (SVGA_DEBUG & DEBUG_TGSI) {
+ debug_printf( "Shader %u compiled below\n", shader->id );
+ svga_shader_dump( result->tokens,
+ result->nr_tokens ,
+ FALSE );
+ }
+ debug_printf( "#####################################\n" );
+ }
+
+ return result;
+
+fail:
+ FREE(result);
+ FREE(emit.buf);
+ return NULL;
+}
+
+
+
+
+struct svga_shader_result *
+svga_translate_fragment_program( const struct svga_fragment_shader *fs,
+ const struct svga_fs_compile_key *fkey )
+{
+ union svga_compile_key key;
+ memcpy(&key.fkey, fkey, sizeof *fkey);
+
+ return svga_tgsi_translate( &fs->base,
+ key,
+ PIPE_SHADER_FRAGMENT );
+}
+
+struct svga_shader_result *
+svga_translate_vertex_program( const struct svga_vertex_shader *vs,
+ const struct svga_vs_compile_key *vkey )
+{
+ union svga_compile_key key;
+ memcpy(&key.vkey, vkey, sizeof *vkey);
+
+ return svga_tgsi_translate( &vs->base,
+ key,
+ PIPE_SHADER_VERTEX );
+}
+
+
+void svga_destroy_shader_result( struct svga_shader_result *result )
+{
+ FREE((unsigned *)result->tokens);
+ FREE(result);
+}
+
diff --git a/src/gallium/drivers/svga/svga_tgsi.h b/src/gallium/drivers/svga/svga_tgsi.h
new file mode 100644
index 0000000000..896c90a89a
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi.h
@@ -0,0 +1,139 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_TGSI_H
+#define SVGA_TGSI_H
+
+#include "pipe/p_state.h"
+
+#include "svga_hw_reg.h"
+
+struct svga_fragment_shader;
+struct svga_vertex_shader;
+struct svga_shader;
+struct tgsi_shader_info;
+struct tgsi_token;
+
+
+struct svga_vs_compile_key
+{
+ ubyte need_prescale:1;
+ ubyte allow_psiz:1;
+ unsigned zero_stride_vertex_elements;
+ ubyte num_zero_stride_vertex_elements:6;
+};
+
+struct svga_fs_compile_key
+{
+ boolean light_twoside:1;
+ boolean front_cw:1;
+ ubyte num_textures;
+ ubyte num_unnormalized_coords;
+ struct {
+ ubyte compare_mode : 1;
+ ubyte compare_func : 3;
+ ubyte unnormalized : 1;
+
+ ubyte width_height_idx : 7;
+
+ ubyte texture_target;
+ } tex[PIPE_MAX_SAMPLERS];
+};
+
+union svga_compile_key {
+ struct svga_vs_compile_key vkey;
+ struct svga_fs_compile_key fkey;
+};
+
+struct svga_shader_result
+{
+ const struct svga_shader *shader;
+
+ /* Parameters used to generate this compilation result:
+ */
+ union svga_compile_key key;
+
+ /* Compiled shader tokens:
+ */
+ const unsigned *tokens;
+ unsigned nr_tokens;
+
+ /* SVGA Shader ID:
+ */
+ unsigned id;
+
+ /* Next compilation result:
+ */
+ struct svga_shader_result *next;
+};
+
+
+/* TGSI doesn't provide use with VS input semantics (they're actually
+ * pretty meaningless), so we just generate some plausible ones here.
+ * This is called both from within the TGSI translator and when
+ * building vdecls to ensure they match up.
+ *
+ * The real use of this information is matching vertex elements to
+ * fragment shader inputs in the case where vertex shader is disabled.
+ */
+static INLINE void svga_generate_vdecl_semantics( unsigned idx,
+ unsigned *usage,
+ unsigned *usage_index )
+{
+ if (idx == 0) {
+ *usage = SVGA3D_DECLUSAGE_POSITION;
+ *usage_index = 0;
+ }
+ else {
+ *usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ *usage_index = idx - 1;
+ }
+}
+
+
+
+static INLINE unsigned svga_vs_key_size( const struct svga_vs_compile_key *key )
+{
+ return sizeof *key;
+}
+
+static INLINE unsigned svga_fs_key_size( const struct svga_fs_compile_key *key )
+{
+ return (const char *)&key->tex[key->num_textures].texture_target -
+ (const char *)key;
+}
+
+struct svga_shader_result *
+svga_translate_fragment_program( const struct svga_fragment_shader *fs,
+ const struct svga_fs_compile_key *fkey );
+
+struct svga_shader_result *
+svga_translate_vertex_program( const struct svga_vertex_shader *fs,
+ const struct svga_vs_compile_key *vkey );
+
+
+void svga_destroy_shader_result( struct svga_shader_result *result );
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_tgsi_decl_sm20.c b/src/gallium/drivers/svga/svga_tgsi_decl_sm20.c
new file mode 100644
index 0000000000..23b3ace7f3
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi_decl_sm20.c
@@ -0,0 +1,280 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_parse.h"
+#include "util/u_memory.h"
+
+#include "svga_tgsi_emit.h"
+#include "svga_context.h"
+
+
+
+
+static boolean ps20_input( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ struct src_register reg;
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ switch (semantic.Name) {
+ case TGSI_SEMANTIC_POSITION:
+ /* Special case:
+ */
+ reg = src_register( SVGA3DREG_MISCTYPE,
+ SVGA3DMISCREG_POSITION );
+ break;
+ case TGSI_SEMANTIC_COLOR:
+ reg = src_register( SVGA3DREG_INPUT,
+ semantic.Index );
+ break;
+ case TGSI_SEMANTIC_FOG:
+ assert(semantic.Index == 0);
+ reg = src_register( SVGA3DREG_TEXTURE, 0 );
+ break;
+ case TGSI_SEMANTIC_GENERIC:
+ reg = src_register( SVGA3DREG_TEXTURE,
+ semantic.Index + 1 );
+ break;
+ default:
+ assert(0);
+ return TRUE;
+ }
+
+ emit->input_map[idx] = reg;
+
+ dcl.dst = dst( reg );
+
+ dcl.usage = 0;
+ dcl.index = 0;
+
+ dcl.values[0] |= 1<<31;
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+
+static boolean ps20_output( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3dShaderDestToken reg;
+
+ switch (semantic.Name) {
+ case TGSI_SEMANTIC_COLOR:
+ if (semantic.Index < PIPE_MAX_COLOR_BUFS) {
+ unsigned cbuf = semantic.Index;
+
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_col[cbuf] = emit->output_map[idx];
+ emit->true_col[cbuf] = dst_register( SVGA3DREG_COLOROUT,
+ semantic.Index );
+ }
+ else {
+ assert(0);
+ reg = dst_register( SVGA3DREG_COLOROUT, 0 );
+ }
+ break;
+ case TGSI_SEMANTIC_POSITION:
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_pos = emit->output_map[idx];
+ emit->true_pos = dst_register( SVGA3DREG_DEPTHOUT,
+ semantic.Index );
+ break;
+ default:
+ assert(0);
+ reg = dst_register( SVGA3DREG_COLOROUT, 0 );
+ break;
+ }
+
+ return TRUE;
+}
+
+
+static boolean vs20_input( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ emit->input_map[idx] = src_register( SVGA3DREG_INPUT, idx );
+ dcl.dst = dst_register( SVGA3DREG_INPUT, idx );
+
+ assert(dcl.dst.reserved0);
+
+ /* Mesa doesn't provide use with VS input semantics (they're
+ * actually pretty meaningless), so we just generate some plausible
+ * ones here. This has to match what we declare in the vdecl code
+ * in svga_pipe_vertex.c.
+ */
+ if (idx == 0) {
+ dcl.usage = SVGA3D_DECLUSAGE_POSITION;
+ dcl.index = 0;
+ }
+ else {
+ dcl.usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ dcl.index = idx - 1;
+ }
+
+ dcl.values[0] |= 1<<31;
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+
+static boolean vs20_output( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ /* Don't emit dcl instruction for vs20 inputs
+ */
+
+ /* Just build the register map table:
+ */
+ switch (semantic.Name) {
+ case TGSI_SEMANTIC_POSITION:
+ assert(semantic.Index == 0);
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_pos = emit->output_map[idx];
+ emit->true_pos = dst_register( SVGA3DREG_RASTOUT,
+ SVGA3DRASTOUT_POSITION);
+ break;
+ case TGSI_SEMANTIC_PSIZE:
+ assert(semantic.Index == 0);
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_psiz = emit->output_map[idx];
+ emit->true_psiz = dst_register( SVGA3DREG_RASTOUT,
+ SVGA3DRASTOUT_PSIZE );
+ break;
+ case TGSI_SEMANTIC_FOG:
+ assert(semantic.Index == 0);
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEXCRDOUT, 0 );
+ break;
+ case TGSI_SEMANTIC_COLOR:
+ /* oD0 */
+ emit->output_map[idx] = dst_register( SVGA3DREG_ATTROUT,
+ semantic.Index );
+ break;
+ case TGSI_SEMANTIC_GENERIC:
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEXCRDOUT,
+ semantic.Index + 1 );
+ break;
+ default:
+ assert(0);
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP, 0 );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean ps20_sampler( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ dcl.dst = dst_register( SVGA3DREG_SAMPLER, idx );
+ dcl.type = svga_tgsi_sampler_type( emit, idx );
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+
+boolean svga_translate_decl_sm20( struct svga_shader_emitter *emit,
+ const struct tgsi_full_declaration *decl )
+{
+ unsigned first = decl->Range.First;
+ unsigned last = decl->Range.Last;
+ unsigned semantic = 0;
+ unsigned semantic_idx = 0;
+ unsigned idx;
+
+ if (decl->Declaration.Semantic) {
+ semantic = decl->Semantic.Name;
+ semantic_idx = decl->Semantic.Index;
+ }
+
+ for( idx = first; idx <= last; idx++ ) {
+ boolean ok;
+
+ switch (decl->Declaration.File) {
+ case TGSI_FILE_SAMPLER:
+ assert (emit->unit == PIPE_SHADER_FRAGMENT);
+ ok = ps20_sampler( emit, decl->Semantic, idx );
+ break;
+
+ case TGSI_FILE_INPUT:
+ if (emit->unit == PIPE_SHADER_VERTEX)
+ ok = vs20_input( emit, decl->Semantic, idx );
+ else
+ ok = ps20_input( emit, decl->Semantic, idx );
+ break;
+
+ case TGSI_FILE_OUTPUT:
+ if (emit->unit == PIPE_SHADER_VERTEX)
+ ok = vs20_output( emit, decl->Semantic, idx );
+ else
+ ok = ps20_output( emit, decl->Semantic, idx );
+ break;
+
+ default:
+ /* don't need to declare other vars */
+ ok = TRUE;
+ }
+
+ if (!ok)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
diff --git a/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c b/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c
new file mode 100644
index 0000000000..d1c7336dec
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c
@@ -0,0 +1,385 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_parse.h"
+#include "util/u_memory.h"
+
+#include "svga_tgsi_emit.h"
+#include "svga_context.h"
+
+static boolean translate_vs_ps_semantic( struct tgsi_declaration_semantic semantic,
+ unsigned *usage,
+ unsigned *idx )
+{
+ switch (semantic.Name) {
+ case TGSI_SEMANTIC_POSITION:
+ *idx = semantic.Index;
+ *usage = SVGA3D_DECLUSAGE_POSITION;
+ break;
+ case TGSI_SEMANTIC_COLOR:
+
+ *idx = semantic.Index;
+ *usage = SVGA3D_DECLUSAGE_COLOR;
+ break;
+ case TGSI_SEMANTIC_BCOLOR:
+ *idx = semantic.Index + 2; /* sharing with COLOR */
+ *usage = SVGA3D_DECLUSAGE_COLOR;
+ break;
+ case TGSI_SEMANTIC_FOG:
+ *idx = 0;
+ assert(semantic.Index == 0);
+ *usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ break;
+ case TGSI_SEMANTIC_PSIZE:
+ *idx = semantic.Index;
+ *usage = SVGA3D_DECLUSAGE_PSIZE;
+ break;
+ case TGSI_SEMANTIC_GENERIC:
+ *idx = semantic.Index + 1; /* texcoord[0] is reserved for fog */
+ *usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ break;
+ case TGSI_SEMANTIC_NORMAL:
+ *idx = semantic.Index;
+ *usage = SVGA3D_DECLUSAGE_NORMAL;
+ break;
+ default:
+ assert(0);
+ *usage = SVGA3D_DECLUSAGE_TEXCOORD;
+ *idx = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static boolean emit_decl( struct svga_shader_emitter *emit,
+ SVGA3dShaderDestToken reg,
+ unsigned usage,
+ unsigned index )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ dcl.dst = reg;
+ dcl.usage = usage;
+ dcl.index = index;
+ dcl.values[0] |= 1<<31;
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+static boolean emit_vface_decl( struct svga_shader_emitter *emit )
+{
+ if (!emit->emitted_vface) {
+ SVGA3dShaderDestToken reg =
+ dst_register( SVGA3DREG_MISCTYPE,
+ SVGA3DMISCREG_FACE );
+
+ if (!emit_decl( emit, reg, 0, 0 ))
+ return FALSE;
+
+ emit->emitted_vface = TRUE;
+ }
+ return TRUE;
+}
+
+static boolean ps30_input( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ unsigned usage, index;
+ SVGA3dShaderDestToken reg;
+
+ if (semantic.Name == TGSI_SEMANTIC_POSITION) {
+ emit->input_map[idx] = src_register( SVGA3DREG_MISCTYPE,
+ SVGA3DMISCREG_POSITION );
+
+ emit->input_map[idx].base.swizzle = TRANSLATE_SWIZZLE( TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_Y );
+
+ reg = writemask( dst(emit->input_map[idx]),
+ TGSI_WRITEMASK_XY );
+
+ return emit_decl( emit, reg, 0, 0 );
+ }
+ else if (emit->key.fkey.light_twoside &&
+ (semantic.Name == TGSI_SEMANTIC_COLOR)) {
+
+ if (!translate_vs_ps_semantic( semantic, &usage, &index ))
+ return FALSE;
+
+ emit->internal_color_idx[emit->internal_color_count] = idx;
+ emit->input_map[idx] = src_register( SVGA3DREG_INPUT, emit->ps30_input_count );
+ emit->ps30_input_count++;
+ emit->internal_color_count++;
+
+ reg = dst( emit->input_map[idx] );
+
+ if (!emit_decl( emit, reg, usage, index ))
+ return FALSE;
+
+ semantic.Name = TGSI_SEMANTIC_BCOLOR;
+ if (!translate_vs_ps_semantic( semantic, &usage, &index ))
+ return FALSE;
+
+ reg = dst_register( SVGA3DREG_INPUT, emit->ps30_input_count++ );
+
+ if (!emit_decl( emit, reg, usage, index ))
+ return FALSE;
+
+ if (!emit_vface_decl( emit ))
+ return FALSE;
+
+ return TRUE;
+ }
+ else if (semantic.Name == TGSI_SEMANTIC_FACE) {
+ if (!emit_vface_decl( emit ))
+ return FALSE;
+ emit->emit_frontface = TRUE;
+ emit->internal_frontface_idx = idx;
+ return TRUE;
+ }
+ else {
+
+ if (!translate_vs_ps_semantic( semantic, &usage, &index ))
+ return FALSE;
+
+ emit->input_map[idx] = src_register( SVGA3DREG_INPUT, emit->ps30_input_count++ );
+ reg = dst( emit->input_map[idx] );
+
+ return emit_decl( emit, reg, usage, index );
+ }
+
+}
+
+
+/* PS output registers are the same as 2.0
+ */
+static boolean ps30_output( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3dShaderDestToken reg;
+
+ switch (semantic.Name) {
+ case TGSI_SEMANTIC_COLOR:
+ emit->output_map[idx] = dst_register( SVGA3DREG_COLOROUT,
+ semantic.Index );
+ break;
+ case TGSI_SEMANTIC_POSITION:
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_pos = emit->output_map[idx];
+ emit->true_pos = dst_register( SVGA3DREG_DEPTHOUT,
+ semantic.Index );
+ break;
+ default:
+ assert(0);
+ reg = dst_register( SVGA3DREG_COLOROUT, 0 );
+ break;
+ }
+
+ return TRUE;
+}
+
+
+/* We still make up the input semantics the same as in 2.0
+ */
+static boolean vs30_input( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+ unsigned usage, index;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ if (emit->key.vkey.zero_stride_vertex_elements & (1 << idx)) {
+ unsigned i;
+ unsigned offset = 0;
+ unsigned start_idx = emit->info.file_max[TGSI_FILE_CONSTANT] + 1;
+ /* adjust for prescale constants */
+ start_idx += emit->key.vkey.need_prescale ? 2 : 0;
+ /* compute the offset from the start of zero stride constants */
+ for (i = 0; i < PIPE_MAX_ATTRIBS && i < idx; ++i) {
+ if (emit->key.vkey.zero_stride_vertex_elements & (1<<i))
+ ++offset;
+ }
+ emit->input_map[idx] = src_register( SVGA3DREG_CONST,
+ start_idx + offset );
+ } else {
+ emit->input_map[idx] = src_register( SVGA3DREG_INPUT, idx );
+ dcl.dst = dst_register( SVGA3DREG_INPUT, idx );
+
+ assert(dcl.dst.reserved0);
+
+ svga_generate_vdecl_semantics( idx, &usage, &index );
+
+ dcl.usage = usage;
+ dcl.index = index;
+ dcl.values[0] |= 1<<31;
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+ }
+ return TRUE;
+}
+
+/* VS3.0 outputs have proper declarations and semantic info for
+ * matching against PS inputs.
+ */
+static boolean vs30_output( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+ unsigned usage, index;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ if (!translate_vs_ps_semantic( semantic, &usage, &index ))
+ return FALSE;
+
+ dcl.dst = dst_register( SVGA3DREG_OUTPUT, idx );
+ dcl.usage = usage;
+ dcl.index = index;
+ dcl.values[0] |= 1<<31;
+
+ if (semantic.Name == TGSI_SEMANTIC_POSITION) {
+ assert(idx == 0);
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_pos = emit->output_map[idx];
+ emit->true_pos = dcl.dst;
+ }
+ else if (semantic.Name == TGSI_SEMANTIC_PSIZE) {
+ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+ emit->temp_psiz = emit->output_map[idx];
+
+ /* This has the effect of not declaring psiz (below) and not
+ * emitting the final MOV to true_psiz in the postamble.
+ */
+ if (!emit->key.vkey.allow_psiz)
+ return TRUE;
+
+ emit->true_psiz = dcl.dst;
+ }
+ else {
+ emit->output_map[idx] = dcl.dst;
+ }
+
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+static boolean ps30_sampler( struct svga_shader_emitter *emit,
+ struct tgsi_declaration_semantic semantic,
+ unsigned idx )
+{
+ SVGA3DOpDclArgs dcl;
+ SVGA3dShaderInstToken opcode;
+
+ opcode = inst_token( SVGA3DOP_DCL );
+ dcl.values[0] = 0;
+ dcl.values[1] = 0;
+
+ dcl.dst = dst_register( SVGA3DREG_SAMPLER, idx );
+ dcl.type = svga_tgsi_sampler_type( emit, idx );
+ dcl.values[0] |= 1<<31;
+
+ return (emit_instruction(emit, opcode) &&
+ svga_shader_emit_dwords( emit, dcl.values, Elements(dcl.values)));
+}
+
+
+boolean svga_translate_decl_sm30( struct svga_shader_emitter *emit,
+ const struct tgsi_full_declaration *decl )
+{
+ unsigned first = decl->Range.First;
+ unsigned last = decl->Range.Last;
+ unsigned semantic = 0;
+ unsigned semantic_idx = 0;
+ unsigned idx;
+
+ if (decl->Declaration.Semantic) {
+ semantic = decl->Semantic.Name;
+ semantic_idx = decl->Semantic.Index;
+ }
+
+ for( idx = first; idx <= last; idx++ ) {
+ boolean ok;
+
+ switch (decl->Declaration.File) {
+ case TGSI_FILE_SAMPLER:
+ assert (emit->unit == PIPE_SHADER_FRAGMENT);
+ ok = ps30_sampler( emit, decl->Semantic, idx );
+ break;
+
+ case TGSI_FILE_INPUT:
+ if (emit->unit == PIPE_SHADER_VERTEX)
+ ok = vs30_input( emit, decl->Semantic, idx );
+ else
+ ok = ps30_input( emit, decl->Semantic, idx );
+ break;
+
+ case TGSI_FILE_OUTPUT:
+ if (emit->unit == PIPE_SHADER_VERTEX)
+ ok = vs30_output( emit, decl->Semantic, idx );
+ else
+ ok = ps30_output( emit, decl->Semantic, idx );
+ break;
+
+ default:
+ /* don't need to declare other vars */
+ ok = TRUE;
+ }
+
+ if (!ok)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
diff --git a/src/gallium/drivers/svga/svga_tgsi_emit.h b/src/gallium/drivers/svga/svga_tgsi_emit.h
new file mode 100644
index 0000000000..2557824293
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi_emit.h
@@ -0,0 +1,345 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_TGSI_EMIT_H
+#define SVGA_TGSI_EMIT_H
+
+#include "tgsi/tgsi_scan.h"
+#include "svga_hw_reg.h"
+#include "svga_tgsi.h"
+#include "svga3d_shaderdefs.h"
+
+struct src_register
+{
+ SVGA3dShaderSrcToken base;
+ SVGA3dShaderSrcToken indirect;
+};
+
+
+struct svga_arl_consts {
+ int number;
+ int idx;
+ int swizzle;
+ int arl_num;
+};
+
+/* Internal functions:
+ */
+
+struct svga_shader_emitter
+{
+ boolean use_sm30;
+
+ unsigned size;
+ char *buf;
+ char *ptr;
+
+ union svga_compile_key key;
+ struct tgsi_shader_info info;
+ int unit;
+
+ int imm_start;
+
+ int nr_hw_const;
+ int nr_hw_temp;
+
+ int insn_offset;
+
+ int internal_temp_count;
+ int internal_imm_count;
+
+ int internal_color_idx[2]; /* diffuse, specular */
+ int internal_color_count;
+
+ boolean emitted_vface;
+ boolean emit_frontface;
+ int internal_frontface_idx;
+
+ int ps30_input_count;
+
+ boolean in_main_func;
+
+ boolean created_zero_immediate;
+ int zero_immediate_idx;
+
+ boolean created_loop_const;
+ int loop_const_idx;
+
+ boolean created_sincos_consts;
+ int sincos_consts_idx;
+
+ unsigned label[32];
+ unsigned nr_labels;
+
+ struct src_register input_map[PIPE_MAX_ATTRIBS];
+ SVGA3dShaderDestToken output_map[PIPE_MAX_ATTRIBS];
+
+ struct src_register imm_0055;
+ SVGA3dShaderDestToken temp_pos;
+ SVGA3dShaderDestToken true_pos;
+
+ SVGA3dShaderDestToken temp_col[PIPE_MAX_COLOR_BUFS];
+ SVGA3dShaderDestToken true_col[PIPE_MAX_COLOR_BUFS];
+
+ SVGA3dShaderDestToken temp_psiz;
+ SVGA3dShaderDestToken true_psiz;
+
+ struct svga_arl_consts arl_consts[12];
+ int num_arl_consts;
+ int current_arl;
+};
+
+
+boolean svga_shader_emit_dword( struct svga_shader_emitter *emit,
+ unsigned dword );
+
+boolean svga_shader_emit_dwords( struct svga_shader_emitter *emit,
+ const unsigned *dwords,
+ unsigned nr );
+
+boolean svga_shader_emit_opcode( struct svga_shader_emitter *emit,
+ unsigned opcode );
+
+boolean svga_shader_emit_instructions( struct svga_shader_emitter *emit,
+ const struct tgsi_token *tokens );
+
+boolean svga_translate_decl_sm20( struct svga_shader_emitter *emit,
+ const struct tgsi_full_declaration *decl );
+
+boolean svga_translate_decl_sm30( struct svga_shader_emitter *emit,
+ const struct tgsi_full_declaration *decl );
+
+
+static INLINE boolean emit_dst( struct svga_shader_emitter *emit,
+ SVGA3dShaderDestToken dest )
+{
+ assert(dest.reserved0);
+ return svga_shader_emit_dword( emit, dest.value );
+}
+
+static INLINE boolean emit_src( struct svga_shader_emitter *emit,
+ const struct src_register src )
+{
+ if (src.base.relAddr) {
+ assert(src.base.reserved0);
+ assert(src.indirect.reserved0);
+ return (svga_shader_emit_dword( emit, src.base.value ) &&
+ svga_shader_emit_dword( emit, src.indirect.value ));
+ }
+ else {
+ assert(src.base.reserved0);
+ return svga_shader_emit_dword( emit, src.base.value );
+ }
+}
+
+
+static INLINE boolean emit_instruction( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken opcode )
+{
+ return svga_shader_emit_opcode( emit, opcode.value );
+}
+
+
+static INLINE boolean emit_op1( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0 )
+{
+ return (emit_instruction( emit, inst ) &&
+ emit_dst( emit, dest ) &&
+ emit_src( emit, src0 ));
+}
+
+static INLINE boolean emit_op2( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0,
+ struct src_register src1 )
+{
+ return (emit_instruction( emit, inst ) &&
+ emit_dst( emit, dest ) &&
+ emit_src( emit, src0 ) &&
+ emit_src( emit, src1 ));
+}
+
+static INLINE boolean emit_op3( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0,
+ struct src_register src1,
+ struct src_register src2 )
+{
+ return (emit_instruction( emit, inst ) &&
+ emit_dst( emit, dest ) &&
+ emit_src( emit, src0 ) &&
+ emit_src( emit, src1 ) &&
+ emit_src( emit, src2 ));
+}
+
+
+#define TRANSLATE_SWIZZLE(x,y,z,w) ((x) | ((y) << 2) | ((z) << 4) | ((w) << 6))
+#define SWIZZLE_XYZW \
+ TRANSLATE_SWIZZLE(TGSI_SWIZZLE_X,TGSI_SWIZZLE_Y,TGSI_SWIZZLE_Z,TGSI_SWIZZLE_W)
+#define SWIZZLE_XXXX \
+ TRANSLATE_SWIZZLE(TGSI_SWIZZLE_X,TGSI_SWIZZLE_X,TGSI_SWIZZLE_X,TGSI_SWIZZLE_X)
+#define SWIZZLE_YYYY \
+ TRANSLATE_SWIZZLE(TGSI_SWIZZLE_Y,TGSI_SWIZZLE_Y,TGSI_SWIZZLE_Y,TGSI_SWIZZLE_Y)
+#define SWIZZLE_ZZZZ \
+ TRANSLATE_SWIZZLE(TGSI_SWIZZLE_Z,TGSI_SWIZZLE_Z,TGSI_SWIZZLE_Z,TGSI_SWIZZLE_Z)
+#define SWIZZLE_WWWW \
+ TRANSLATE_SWIZZLE(TGSI_SWIZZLE_W,TGSI_SWIZZLE_W,TGSI_SWIZZLE_W,TGSI_SWIZZLE_W)
+
+
+
+static INLINE SVGA3dShaderInstToken
+inst_token( unsigned opcode )
+{
+ SVGA3dShaderInstToken inst;
+
+ inst.value = 0;
+ inst.op = opcode;
+
+ return inst;
+}
+
+static INLINE SVGA3dShaderDestToken
+dst_register( unsigned file,
+ int number )
+{
+ SVGA3dShaderDestToken dest;
+
+ dest.value = 0;
+ dest.num = number;
+ dest.type_upper = file >> 3;
+ dest.relAddr = 0;
+ dest.reserved1 = 0;
+ dest.mask = 0xf;
+ dest.dstMod = 0;
+ dest.shfScale = 0;
+ dest.type_lower = file & 0x7;
+ dest.reserved0 = 1; /* is_reg */
+
+ return dest;
+}
+
+static INLINE SVGA3dShaderDestToken
+writemask( SVGA3dShaderDestToken dest,
+ unsigned mask )
+{
+ dest.mask &= mask;
+ return dest;
+}
+
+
+static INLINE SVGA3dShaderSrcToken
+src_token( unsigned file, int number )
+{
+ SVGA3dShaderSrcToken src;
+
+ src.value = 0;
+ src.num = number;
+ src.type_upper = file >> 3;
+ src.relAddr = 0;
+ src.reserved1 = 0;
+ src.swizzle = SWIZZLE_XYZW;
+ src.srcMod = 0;
+ src.type_lower = file & 0x7;
+ src.reserved0 = 1; /* is_reg */
+
+ return src;
+}
+
+
+static INLINE struct src_register
+absolute( struct src_register src )
+{
+ src.base.srcMod = SVGA3DSRCMOD_ABS;
+
+ return src;
+}
+
+
+static INLINE struct src_register
+negate( struct src_register src )
+{
+ switch (src.base.srcMod) {
+ case SVGA3DSRCMOD_ABS:
+ src.base.srcMod = SVGA3DSRCMOD_ABSNEG;
+ break;
+ case SVGA3DSRCMOD_ABSNEG:
+ src.base.srcMod = SVGA3DSRCMOD_ABS;
+ break;
+ case SVGA3DSRCMOD_NEG:
+ src.base.srcMod = SVGA3DSRCMOD_NONE;
+ break;
+ case SVGA3DSRCMOD_NONE:
+ src.base.srcMod = SVGA3DSRCMOD_NEG;
+ break;
+ }
+ return src;
+}
+
+
+static INLINE struct src_register
+src_register( unsigned file, int number )
+{
+ struct src_register src;
+
+ src.base = src_token( file, number );
+ src.indirect.value = 0;
+
+ return src;
+}
+
+static INLINE SVGA3dShaderDestToken dst( struct src_register src )
+{
+ return dst_register( SVGA3dShaderGetRegType( src.base.value ),
+ src.base.num );
+}
+
+static INLINE struct src_register src( SVGA3dShaderDestToken dst )
+{
+ return src_register( SVGA3dShaderGetRegType( dst.value ),
+ dst.num );
+}
+
+static INLINE ubyte svga_tgsi_sampler_type( struct svga_shader_emitter *emit,
+ int idx )
+{
+ switch (emit->key.fkey.tex[idx].texture_target) {
+ case PIPE_TEXTURE_1D:
+ return SVGA3DSAMP_2D;
+ case PIPE_TEXTURE_2D:
+ return SVGA3DSAMP_2D;
+ case PIPE_TEXTURE_3D:
+ return SVGA3DSAMP_VOLUME;
+ case PIPE_TEXTURE_CUBE:
+ return SVGA3DSAMP_CUBE;
+ }
+
+ return SVGA3DSAMP_UNKNOWN;
+}
+
+#endif
diff --git a/src/gallium/drivers/svga/svga_tgsi_insn.c b/src/gallium/drivers/svga/svga_tgsi_insn.c
new file mode 100644
index 0000000000..1670da8bfa
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_tgsi_insn.c
@@ -0,0 +1,2716 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_parse.h"
+#include "util/u_memory.h"
+
+#include "svga_tgsi_emit.h"
+#include "svga_context.h"
+
+
+static boolean emit_vs_postamble( struct svga_shader_emitter *emit );
+static boolean emit_ps_postamble( struct svga_shader_emitter *emit );
+
+
+
+
+static unsigned
+translate_opcode(
+ uint opcode )
+{
+ switch (opcode) {
+ case TGSI_OPCODE_ABS: return SVGA3DOP_ABS;
+ case TGSI_OPCODE_ADD: return SVGA3DOP_ADD;
+ case TGSI_OPCODE_BREAKC: return SVGA3DOP_BREAKC;
+ case TGSI_OPCODE_DDX: return SVGA3DOP_DSX;
+ case TGSI_OPCODE_DDY: return SVGA3DOP_DSY;
+ case TGSI_OPCODE_DP2A: return SVGA3DOP_DP2ADD;
+ case TGSI_OPCODE_DP3: return SVGA3DOP_DP3;
+ case TGSI_OPCODE_DP4: return SVGA3DOP_DP4;
+ case TGSI_OPCODE_ENDFOR: return SVGA3DOP_ENDLOOP;
+ case TGSI_OPCODE_FRC: return SVGA3DOP_FRC;
+ case TGSI_OPCODE_BGNFOR: return SVGA3DOP_LOOP;
+ case TGSI_OPCODE_MAD: return SVGA3DOP_MAD;
+ case TGSI_OPCODE_MAX: return SVGA3DOP_MAX;
+ case TGSI_OPCODE_MIN: return SVGA3DOP_MIN;
+ case TGSI_OPCODE_MOV: return SVGA3DOP_MOV;
+ case TGSI_OPCODE_MUL: return SVGA3DOP_MUL;
+ case TGSI_OPCODE_NOP: return SVGA3DOP_NOP;
+ case TGSI_OPCODE_NRM4: return SVGA3DOP_NRM;
+ case TGSI_OPCODE_SSG: return SVGA3DOP_SGN;
+ default:
+ debug_printf("Unkown opcode %u\n", opcode);
+ assert( 0 );
+ return SVGA3DOP_LAST_INST;
+ }
+}
+
+
+static unsigned translate_file( unsigned file )
+{
+ switch (file) {
+ case TGSI_FILE_TEMPORARY: return SVGA3DREG_TEMP;
+ case TGSI_FILE_INPUT: return SVGA3DREG_INPUT;
+ case TGSI_FILE_OUTPUT: return SVGA3DREG_OUTPUT; /* VS3.0+ only */
+ case TGSI_FILE_IMMEDIATE: return SVGA3DREG_CONST;
+ case TGSI_FILE_CONSTANT: return SVGA3DREG_CONST;
+ case TGSI_FILE_SAMPLER: return SVGA3DREG_SAMPLER;
+ case TGSI_FILE_ADDRESS: return SVGA3DREG_ADDR;
+ default:
+ assert( 0 );
+ return SVGA3DREG_TEMP;
+ }
+}
+
+
+
+
+
+
+static SVGA3dShaderDestToken
+translate_dst_register( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn,
+ unsigned idx )
+{
+ const struct tgsi_full_dst_register *reg = &insn->Dst[idx];
+ SVGA3dShaderDestToken dest;
+
+ switch (reg->Register.File) {
+ case TGSI_FILE_OUTPUT:
+ /* Output registers encode semantic information in their name.
+ * Need to lookup a table built at decl time:
+ */
+ dest = emit->output_map[reg->Register.Index];
+ break;
+
+ default:
+ dest = dst_register( translate_file( reg->Register.File ),
+ reg->Register.Index );
+ break;
+ }
+
+ dest.mask = reg->Register.WriteMask;
+
+ if (insn->Instruction.Saturate)
+ dest.dstMod = SVGA3DDSTMOD_SATURATE;
+
+ return dest;
+}
+
+
+static struct src_register
+swizzle( struct src_register src,
+ int x,
+ int y,
+ int z,
+ int w )
+{
+ x = (src.base.swizzle >> (x * 2)) & 0x3;
+ y = (src.base.swizzle >> (y * 2)) & 0x3;
+ z = (src.base.swizzle >> (z * 2)) & 0x3;
+ w = (src.base.swizzle >> (w * 2)) & 0x3;
+
+ src.base.swizzle = TRANSLATE_SWIZZLE(x,y,z,w);
+
+ return src;
+}
+
+static struct src_register
+scalar( struct src_register src,
+ int comp )
+{
+ return swizzle( src, comp, comp, comp, comp );
+}
+
+static INLINE boolean
+svga_arl_needs_adjustment( const struct svga_shader_emitter *emit )
+{
+ int i;
+
+ for (i = 0; i < emit->num_arl_consts; ++i) {
+ if (emit->arl_consts[i].arl_num == emit->current_arl)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static INLINE int
+svga_arl_adjustment( const struct svga_shader_emitter *emit )
+{
+ int i;
+
+ for (i = 0; i < emit->num_arl_consts; ++i) {
+ if (emit->arl_consts[i].arl_num == emit->current_arl)
+ return emit->arl_consts[i].number;
+ }
+ return 0;
+}
+
+static struct src_register
+translate_src_register( const struct svga_shader_emitter *emit,
+ const struct tgsi_full_src_register *reg )
+{
+ struct src_register src;
+
+ switch (reg->Register.File) {
+ case TGSI_FILE_INPUT:
+ /* Input registers are referred to by their semantic name rather
+ * than by index. Use the mapping build up from the decls:
+ */
+ src = emit->input_map[reg->Register.Index];
+ break;
+
+ case TGSI_FILE_IMMEDIATE:
+ /* Immediates are appended after TGSI constants in the D3D
+ * constant buffer.
+ */
+ src = src_register( translate_file( reg->Register.File ),
+ reg->Register.Index +
+ emit->imm_start );
+ break;
+
+ default:
+ src = src_register( translate_file( reg->Register.File ),
+ reg->Register.Index );
+
+ break;
+ }
+
+ /* Indirect addressing (for coninstant buffer lookups only)
+ */
+ if (reg->Register.Indirect)
+ {
+ /* we shift the offset towards the minimum */
+ if (svga_arl_needs_adjustment( emit )) {
+ src.base.num -= svga_arl_adjustment( emit );
+ }
+ src.base.relAddr = 1;
+
+ /* Not really sure what should go in the second token:
+ */
+ src.indirect = src_token( SVGA3DREG_ADDR,
+ reg->Indirect.Index );
+
+ src.indirect.swizzle = SWIZZLE_XXXX;
+ }
+
+ src = swizzle( src,
+ reg->Register.SwizzleX,
+ reg->Register.SwizzleY,
+ reg->Register.SwizzleZ,
+ reg->Register.SwizzleW );
+
+ /* src.mod isn't a bitfield, unfortunately:
+ * See tgsi_util_get_full_src_register_sign_mode for implementation details.
+ */
+ if (reg->Register.Absolute) {
+ if (reg->Register.Negate)
+ src.base.srcMod = SVGA3DSRCMOD_ABSNEG;
+ else
+ src.base.srcMod = SVGA3DSRCMOD_ABS;
+ }
+ else {
+ if (reg->Register.Negate)
+ src.base.srcMod = SVGA3DSRCMOD_NEG;
+ else
+ src.base.srcMod = SVGA3DSRCMOD_NONE;
+ }
+
+ return src;
+}
+
+
+/*
+ * Get a temporary register, return -1 if none available
+ */
+static INLINE SVGA3dShaderDestToken
+get_temp( struct svga_shader_emitter *emit )
+{
+ int i = emit->nr_hw_temp + emit->internal_temp_count++;
+
+ return dst_register( SVGA3DREG_TEMP, i );
+}
+
+/* Release a single temp. Currently only effective if it was the last
+ * allocated temp, otherwise release will be delayed until the next
+ * call to reset_temp_regs().
+ */
+static INLINE void
+release_temp( struct svga_shader_emitter *emit,
+ SVGA3dShaderDestToken temp )
+{
+ if (temp.num == emit->internal_temp_count - 1)
+ emit->internal_temp_count--;
+}
+
+static void reset_temp_regs( struct svga_shader_emitter *emit )
+{
+ emit->internal_temp_count = 0;
+}
+
+
+static boolean submit_op0( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest )
+{
+ return (emit_instruction( emit, inst ) &&
+ emit_dst( emit, dest ));
+}
+
+static boolean submit_op1( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0 )
+{
+ return emit_op1( emit, inst, dest, src0 );
+}
+
+
+/* SVGA shaders may not refer to >1 constant register in a single
+ * instruction. This function checks for that usage and inserts a
+ * move to temporary if detected.
+ *
+ * The same applies to input registers -- at most a single input
+ * register may be read by any instruction.
+ */
+static boolean submit_op2( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0,
+ struct src_register src1 )
+{
+ SVGA3dShaderDestToken temp;
+ SVGA3dShaderRegType type0, type1;
+ boolean need_temp = FALSE;
+
+ temp.value = 0;
+ type0 = SVGA3dShaderGetRegType( src0.base.value );
+ type1 = SVGA3dShaderGetRegType( src1.base.value );
+
+ if (type0 == SVGA3DREG_CONST &&
+ type1 == SVGA3DREG_CONST &&
+ src0.base.num != src1.base.num)
+ need_temp = TRUE;
+
+ if (type0 == SVGA3DREG_INPUT &&
+ type1 == SVGA3DREG_INPUT &&
+ src0.base.num != src1.base.num)
+ need_temp = TRUE;
+
+ if (need_temp)
+ {
+ temp = get_temp( emit );
+
+ if (!emit_op1( emit, inst_token( SVGA3DOP_MOV ), temp, src0 ))
+ return FALSE;
+
+ src0 = src( temp );
+ }
+
+ if (!emit_op2( emit, inst, dest, src0, src1 ))
+ return FALSE;
+
+ if (need_temp)
+ release_temp( emit, temp );
+
+ return TRUE;
+}
+
+
+/* SVGA shaders may not refer to >1 constant register in a single
+ * instruction. This function checks for that usage and inserts a
+ * move to temporary if detected.
+ */
+static boolean submit_op3( struct svga_shader_emitter *emit,
+ SVGA3dShaderInstToken inst,
+ SVGA3dShaderDestToken dest,
+ struct src_register src0,
+ struct src_register src1,
+ struct src_register src2 )
+{
+ SVGA3dShaderDestToken temp0;
+ SVGA3dShaderDestToken temp1;
+ boolean need_temp0 = FALSE;
+ boolean need_temp1 = FALSE;
+ SVGA3dShaderRegType type0, type1, type2;
+
+ temp0.value = 0;
+ temp1.value = 0;
+ type0 = SVGA3dShaderGetRegType( src0.base.value );
+ type1 = SVGA3dShaderGetRegType( src1.base.value );
+ type2 = SVGA3dShaderGetRegType( src2.base.value );
+
+ if (inst.op != SVGA3DOP_SINCOS) {
+ if (type0 == SVGA3DREG_CONST &&
+ ((type1 == SVGA3DREG_CONST && src0.base.num != src1.base.num) ||
+ (type2 == SVGA3DREG_CONST && src0.base.num != src2.base.num)))
+ need_temp0 = TRUE;
+
+ if (type1 == SVGA3DREG_CONST &&
+ (type2 == SVGA3DREG_CONST && src1.base.num != src2.base.num))
+ need_temp1 = TRUE;
+ }
+
+ if (type0 == SVGA3DREG_INPUT &&
+ ((type1 == SVGA3DREG_INPUT && src0.base.num != src1.base.num) ||
+ (type2 == SVGA3DREG_INPUT && src0.base.num != src2.base.num)))
+ need_temp0 = TRUE;
+
+ if (type1 == SVGA3DREG_INPUT &&
+ (type2 == SVGA3DREG_INPUT && src1.base.num != src2.base.num))
+ need_temp1 = TRUE;
+
+ if (need_temp0)
+ {
+ temp0 = get_temp( emit );
+
+ if (!emit_op1( emit, inst_token( SVGA3DOP_MOV ), temp0, src0 ))
+ return FALSE;
+
+ src0 = src( temp0 );
+ }
+
+ if (need_temp1)
+ {
+ temp1 = get_temp( emit );
+
+ if (!emit_op1( emit, inst_token( SVGA3DOP_MOV ), temp1, src1 ))
+ return FALSE;
+
+ src1 = src( temp1 );
+ }
+
+ if (!emit_op3( emit, inst, dest, src0, src1, src2 ))
+ return FALSE;
+
+ if (need_temp1)
+ release_temp( emit, temp1 );
+ if (need_temp0)
+ release_temp( emit, temp0 );
+ return TRUE;
+}
+
+
+static boolean emit_def_const( struct svga_shader_emitter *emit,
+ SVGA3dShaderConstType type,
+ unsigned idx,
+ float a,
+ float b,
+ float c,
+ float d )
+{
+ SVGA3DOpDefArgs def;
+ SVGA3dShaderInstToken opcode;
+
+ switch (type) {
+ case SVGA3D_CONST_TYPE_FLOAT:
+ opcode = inst_token( SVGA3DOP_DEF );
+ def.dst = dst_register( SVGA3DREG_CONST, idx );
+ def.constValues[0] = a;
+ def.constValues[1] = b;
+ def.constValues[2] = c;
+ def.constValues[3] = d;
+ break;
+ case SVGA3D_CONST_TYPE_INT:
+ opcode = inst_token( SVGA3DOP_DEFI );
+ def.dst = dst_register( SVGA3DREG_CONSTINT, idx );
+ def.constIValues[0] = (int)a;
+ def.constIValues[1] = (int)b;
+ def.constIValues[2] = (int)c;
+ def.constIValues[3] = (int)d;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if (!emit_instruction(emit, opcode) ||
+ !svga_shader_emit_dwords( emit, def.values, Elements(def.values)))
+ return FALSE;
+
+ return TRUE;
+}
+
+static INLINE boolean
+create_zero_immediate( struct svga_shader_emitter *emit )
+{
+ unsigned idx = emit->nr_hw_const++;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT,
+ idx, 0, 0, 0, 1 ))
+ return FALSE;
+
+ emit->zero_immediate_idx = idx;
+ emit->created_zero_immediate = TRUE;
+
+ return TRUE;
+}
+
+static INLINE boolean
+create_loop_const( struct svga_shader_emitter *emit )
+{
+ unsigned idx = emit->nr_hw_const++;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_INT, idx,
+ 255, /* iteration count */
+ 0, /* initial value */
+ 1, /* step size */
+ 0 /* not used, must be 0 */))
+ return FALSE;
+
+ emit->loop_const_idx = idx;
+ emit->created_loop_const = TRUE;
+
+ return TRUE;
+}
+
+static INLINE boolean
+create_sincos_consts( struct svga_shader_emitter *emit )
+{
+ unsigned idx = emit->nr_hw_const++;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT, idx,
+ -1.5500992e-006f,
+ -2.1701389e-005f,
+ 0.0026041667f,
+ 0.00026041668f ))
+ return FALSE;
+
+ emit->sincos_consts_idx = idx;
+ idx = emit->nr_hw_const++;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT, idx,
+ -0.020833334f,
+ -0.12500000f,
+ 1.0f,
+ 0.50000000f ))
+ return FALSE;
+
+ emit->created_sincos_consts = TRUE;
+
+ return TRUE;
+}
+
+static INLINE boolean
+create_arl_consts( struct svga_shader_emitter *emit )
+{
+ int i;
+
+ for (i = 0; i < emit->num_arl_consts; i += 4) {
+ int j;
+ unsigned idx = emit->nr_hw_const++;
+ float vals[4];
+ for (j = 0; j < 4 && (j + i) < emit->num_arl_consts; ++j) {
+ vals[j] = emit->arl_consts[i + j].number;
+ emit->arl_consts[i + j].idx = idx;
+ switch (j) {
+ case 0:
+ emit->arl_consts[i + 0].swizzle = TGSI_SWIZZLE_X;
+ break;
+ case 1:
+ emit->arl_consts[i + 0].swizzle = TGSI_SWIZZLE_Y;
+ break;
+ case 2:
+ emit->arl_consts[i + 0].swizzle = TGSI_SWIZZLE_Z;
+ break;
+ case 3:
+ emit->arl_consts[i + 0].swizzle = TGSI_SWIZZLE_W;
+ break;
+ }
+ }
+ while (j < 4)
+ vals[j++] = 0;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT, idx,
+ vals[0], vals[1],
+ vals[2], vals[3]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static INLINE struct src_register
+get_vface( struct svga_shader_emitter *emit )
+{
+ assert(emit->emitted_vface);
+ return src_register(SVGA3DREG_MISCTYPE,
+ SVGA3DMISCREG_FACE);
+}
+
+/* returns {0, 0, 0, 1} immediate */
+static INLINE struct src_register
+get_zero_immediate( struct svga_shader_emitter *emit )
+{
+ assert(emit->created_zero_immediate);
+ assert(emit->zero_immediate_idx >= 0);
+ return src_register( SVGA3DREG_CONST,
+ emit->zero_immediate_idx );
+}
+
+/* returns the loop const */
+static INLINE struct src_register
+get_loop_const( struct svga_shader_emitter *emit )
+{
+ assert(emit->created_loop_const);
+ assert(emit->loop_const_idx >= 0);
+ return src_register( SVGA3DREG_CONSTINT,
+ emit->loop_const_idx );
+}
+
+/* returns a sincos const */
+static INLINE struct src_register
+get_sincos_const( struct svga_shader_emitter *emit,
+ unsigned index )
+{
+ assert(emit->created_sincos_consts);
+ assert(emit->sincos_consts_idx >= 0);
+ assert(index == 0 || index == 1);
+ return src_register( SVGA3DREG_CONST,
+ emit->sincos_consts_idx + index );
+}
+
+static INLINE struct src_register
+get_fake_arl_const( struct svga_shader_emitter *emit )
+{
+ struct src_register reg;
+ int idx = 0, swizzle = 0, i;
+
+ for (i = 0; i < emit->num_arl_consts; ++ i) {
+ if (emit->arl_consts[i].arl_num == emit->current_arl) {
+ idx = emit->arl_consts[i].idx;
+ swizzle = emit->arl_consts[i].swizzle;
+ }
+ }
+
+ reg = src_register( SVGA3DREG_CONST, idx );
+ return scalar(reg, swizzle);
+}
+
+static INLINE struct src_register
+get_tex_dimensions( struct svga_shader_emitter *emit, int sampler_num )
+{
+ int idx;
+ struct src_register reg;
+
+ /* the width/height indexes start right after constants */
+ idx = emit->key.fkey.tex[sampler_num].width_height_idx +
+ emit->info.file_max[TGSI_FILE_CONSTANT] + 1;
+
+ reg = src_register( SVGA3DREG_CONST, idx );
+ return reg;
+}
+
+static boolean emit_fake_arl(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register src1 = get_fake_arl_const( emit );
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ SVGA3dShaderDestToken tmp = get_temp( emit );
+
+ if (!submit_op1(emit, inst_token( SVGA3DOP_MOV ), tmp, src0))
+ return FALSE;
+
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ), tmp, src( tmp ),
+ src1))
+ return FALSE;
+
+ /* replicate the original swizzle */
+ src1 = src(tmp);
+ src1.base.swizzle = src0.base.swizzle;
+
+ return submit_op1( emit, inst_token( SVGA3DOP_MOVA ),
+ dst, src1 );
+}
+
+static boolean emit_if(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ const struct src_register src = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register zero = get_zero_immediate( emit );
+ SVGA3dShaderInstToken if_token = inst_token( SVGA3DOP_IFC );
+
+ if_token.control = SVGA3DOPCOMPC_NE;
+ zero = scalar(zero, TGSI_SWIZZLE_X);
+
+ return (emit_instruction( emit, if_token ) &&
+ emit_src( emit, src ) &&
+ emit_src( emit, zero ) );
+}
+
+static boolean emit_endif(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ return (emit_instruction( emit,
+ inst_token( SVGA3DOP_ENDIF )));
+}
+
+static boolean emit_else(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ return (emit_instruction( emit,
+ inst_token( SVGA3DOP_ELSE )));
+}
+
+/* Translate the following TGSI FLR instruction.
+ * FLR DST, SRC
+ * To the following SVGA3D instruction sequence.
+ * FRC TMP, SRC
+ * SUB DST, SRC, TMP
+ */
+static boolean emit_floor(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* FRC TMP, SRC */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_FRC ), temp, src0 ))
+ return FALSE;
+
+ /* SUB DST, SRC, TMP */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ), dst, src0,
+ negate( src( temp ) ) ))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/* Translate the following TGSI CMP instruction.
+ * CMP DST, SRC0, SRC1, SRC2
+ * To the following SVGA3D instruction sequence.
+ * CMP DST, SRC0, SRC2, SRC1
+ */
+static boolean emit_cmp(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ const struct src_register src2 = translate_src_register(
+ emit, &insn->Src[2] );
+
+ /* CMP DST, SRC0, SRC2, SRC1 */
+ return submit_op3( emit, inst_token( SVGA3DOP_CMP ), dst, src0, src2, src1);
+}
+
+
+
+/* Translate the following TGSI DIV instruction.
+ * DIV DST.xy, SRC0, SRC1
+ * To the following SVGA3D instruction sequence.
+ * RCP TMP.x, SRC1.xxxx
+ * RCP TMP.y, SRC1.yyyy
+ * MUL DST.xy, SRC0, TMP
+ */
+static boolean emit_div(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+ int i;
+
+ /* For each enabled element, perform a RCP instruction. Note that
+ * RCP is scalar in SVGA3D:
+ */
+ for (i = 0; i < 4; i++) {
+ unsigned channel = 1 << i;
+ if (dst.mask & channel) {
+ /* RCP TMP.?, SRC1.???? */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_RCP ),
+ writemask(temp, channel),
+ scalar(src1, i) ))
+ return FALSE;
+ }
+ }
+
+ /* Then multiply them out with a single mul:
+ *
+ * MUL DST, SRC0, TMP
+ */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ), dst, src0,
+ src( temp ) ))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Translate the following TGSI DP2 instruction.
+ * DP2 DST, SRC1, SRC2
+ * To the following SVGA3D instruction sequence.
+ * MUL TMP, SRC1, SRC2
+ * ADD DST, TMP.xxxx, TMP.yyyy
+ */
+static boolean emit_dp2(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+ struct src_register temp_src0, temp_src1;
+
+ /* MUL TMP, SRC1, SRC2 */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ), temp, src0, src1 ))
+ return FALSE;
+
+ temp_src0 = scalar(src( temp ), TGSI_SWIZZLE_X);
+ temp_src1 = scalar(src( temp ), TGSI_SWIZZLE_Y);
+
+ /* ADD DST, TMP.xxxx, TMP.yyyy */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ), dst,
+ temp_src0, temp_src1 ))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/* Translate the following TGSI DPH instruction.
+ * DPH DST, SRC1, SRC2
+ * To the following SVGA3D instruction sequence.
+ * DP3 TMP, SRC1, SRC2
+ * ADD DST, TMP, SRC2.wwww
+ */
+static boolean emit_dph(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* DP3 TMP, SRC1, SRC2 */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_DP3 ), temp, src0, src1 ))
+ return FALSE;
+
+ src1 = scalar(src1, TGSI_SWIZZLE_W);
+
+ /* ADD DST, TMP, SRC2.wwww */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ), dst,
+ src( temp ), src1 ))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Translate the following TGSI DST instruction.
+ * NRM DST, SRC
+ * To the following SVGA3D instruction sequence.
+ * DP3 TMP, SRC, SRC
+ * RSQ TMP, TMP
+ * MUL DST, SRC, TMP
+ */
+static boolean emit_nrm(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* DP3 TMP, SRC, SRC */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_DP3 ), temp, src0, src0 ))
+ return FALSE;
+
+ /* RSQ TMP, TMP */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_RSQ ), temp, src( temp )))
+ return FALSE;
+
+ /* MUL DST, SRC, TMP */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ), dst,
+ src0, src( temp )))
+ return FALSE;
+
+ return TRUE;
+
+}
+
+static boolean do_emit_sincos(struct svga_shader_emitter *emit,
+ SVGA3dShaderDestToken dst,
+ struct src_register src0)
+{
+ src0 = scalar(src0, TGSI_SWIZZLE_X);
+
+ if (emit->use_sm30) {
+ return submit_op1( emit, inst_token( SVGA3DOP_SINCOS ),
+ dst, src0 );
+ } else {
+ struct src_register const1 = get_sincos_const( emit, 0 );
+ struct src_register const2 = get_sincos_const( emit, 1 );
+
+ return submit_op3( emit, inst_token( SVGA3DOP_SINCOS ),
+ dst, src0, const1, const2 );
+ }
+}
+
+static boolean emit_sincos(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* SCS TMP SRC */
+ if (!do_emit_sincos(emit, writemask(temp, TGSI_WRITEMASK_XY), src0 ))
+ return FALSE;
+
+ /* MOV DST TMP */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), dst, src( temp ) ))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * SCS TMP SRC
+ * MOV DST TMP.yyyy
+ */
+static boolean emit_sin(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* SCS TMP SRC */
+ if (!do_emit_sincos(emit, writemask(temp, TGSI_WRITEMASK_Y), src0))
+ return FALSE;
+
+ src0 = scalar(src( temp ), TGSI_SWIZZLE_Y);
+
+ /* MOV DST TMP.yyyy */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), dst, src0 ))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * SCS TMP SRC
+ * MOV DST TMP.xxxx
+ */
+static boolean emit_cos(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ /* SCS TMP SRC */
+ if (!do_emit_sincos( emit, writemask(temp, TGSI_WRITEMASK_X), src0 ))
+ return FALSE;
+
+ src0 = scalar(src( temp ), TGSI_SWIZZLE_X);
+
+ /* MOV DST TMP.xxxx */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), dst, src0 ))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * ADD DST SRC0, negate(SRC0)
+ */
+static boolean emit_sub(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+
+ src1 = negate(src1);
+
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ), dst,
+ src0, src1 ))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static boolean emit_kil(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst;
+ const struct tgsi_full_src_register *reg = &insn->Src[0];
+ struct src_register src0;
+
+ inst = inst_token( SVGA3DOP_TEXKILL );
+ src0 = translate_src_register( emit, reg );
+
+ if (reg->Register.Absolute ||
+ reg->Register.Negate ||
+ reg->Register.Indirect ||
+ reg->Register.SwizzleX != 0 ||
+ reg->Register.SwizzleY != 1 ||
+ reg->Register.SwizzleZ != 2 ||
+ reg->Register.File != TGSI_FILE_TEMPORARY)
+ {
+ SVGA3dShaderDestToken temp = get_temp( emit );
+
+ submit_op1( emit, inst_token( SVGA3DOP_MOV ), temp, src0 );
+ src0 = src( temp );
+ }
+
+ return submit_op0( emit, inst, dst(src0) );
+}
+
+
+/* mesa state tracker always emits kilp as an unconditional
+ * kil */
+static boolean emit_kilp(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst;
+ SVGA3dShaderDestToken temp;
+ struct src_register one = get_zero_immediate( emit );
+
+ inst = inst_token( SVGA3DOP_TEXKILL );
+ one = scalar( one, TGSI_SWIZZLE_W );
+
+ /* texkill doesn't allow negation on the operand so lets move
+ * negation of {1} to a temp register */
+ temp = get_temp( emit );
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), temp,
+ negate( one ) ))
+ return FALSE;
+
+ return submit_op0( emit, inst, temp );
+}
+
+/* Implement conditionals by initializing destination reg to 'fail',
+ * then set predicate reg with UFOP_SETP, then move 'pass' to dest
+ * based on predicate reg.
+ *
+ * SETP src0, cmp, src1 -- do this first to avoid aliasing problems.
+ * MOV dst, fail
+ * MOV dst, pass, p0
+ */
+static boolean
+emit_conditional(struct svga_shader_emitter *emit,
+ unsigned compare_func,
+ SVGA3dShaderDestToken dst,
+ struct src_register src0,
+ struct src_register src1,
+ struct src_register pass,
+ struct src_register fail)
+{
+ SVGA3dShaderDestToken pred_reg = dst_register( SVGA3DREG_PREDICATE, 0 );
+ SVGA3dShaderInstToken setp_token, mov_token;
+ setp_token = inst_token( SVGA3DOP_SETP );
+
+ switch (compare_func) {
+ case PIPE_FUNC_NEVER:
+ return submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ dst, fail );
+ break;
+ case PIPE_FUNC_LESS:
+ setp_token.control = SVGA3DOPCOMP_LT;
+ break;
+ case PIPE_FUNC_EQUAL:
+ setp_token.control = SVGA3DOPCOMP_EQ;
+ break;
+ case PIPE_FUNC_LEQUAL:
+ setp_token.control = SVGA3DOPCOMP_LE;
+ break;
+ case PIPE_FUNC_GREATER:
+ setp_token.control = SVGA3DOPCOMP_GT;
+ break;
+ case PIPE_FUNC_NOTEQUAL:
+ setp_token.control = SVGA3DOPCOMPC_NE;
+ break;
+ case PIPE_FUNC_GEQUAL:
+ setp_token.control = SVGA3DOPCOMP_GE;
+ break;
+ case PIPE_FUNC_ALWAYS:
+ return submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ dst, pass );
+ break;
+ }
+
+ /* SETP src0, COMPOP, src1 */
+ if (!submit_op2( emit, setp_token, pred_reg,
+ src0, src1 ))
+ return FALSE;
+
+ mov_token = inst_token( SVGA3DOP_MOV );
+
+ /* MOV dst, fail */
+ if (!submit_op1( emit, mov_token, dst,
+ fail ))
+ return FALSE;
+
+ /* MOV dst, pass (predicated)
+ *
+ * Note that the predicate reg (and possible modifiers) is passed
+ * as the first source argument.
+ */
+ mov_token.predicated = 1;
+ if (!submit_op2( emit, mov_token, dst,
+ src( pred_reg ), pass ))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static boolean
+emit_select(struct svga_shader_emitter *emit,
+ unsigned compare_func,
+ SVGA3dShaderDestToken dst,
+ struct src_register src0,
+ struct src_register src1 )
+{
+ /* There are some SVGA instructions which implement some selects
+ * directly, but they are only available in the vertex shader.
+ */
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ switch (compare_func) {
+ case PIPE_FUNC_GEQUAL:
+ return submit_op2( emit, inst_token( SVGA3DOP_SGE ), dst, src0, src1 );
+ case PIPE_FUNC_LEQUAL:
+ return submit_op2( emit, inst_token( SVGA3DOP_SGE ), dst, src1, src0 );
+ case PIPE_FUNC_GREATER:
+ return submit_op2( emit, inst_token( SVGA3DOP_SLT ), dst, src1, src0 );
+ case PIPE_FUNC_LESS:
+ return submit_op2( emit, inst_token( SVGA3DOP_SLT ), dst, src0, src1 );
+ default:
+ break;
+ }
+ }
+
+
+ /* Otherwise, need to use the setp approach:
+ */
+ {
+ struct src_register one, zero;
+ /* zero immediate is 0,0,0,1 */
+ zero = get_zero_immediate( emit );
+ one = scalar( zero, TGSI_SWIZZLE_W );
+ zero = scalar( zero, TGSI_SWIZZLE_X );
+
+ return emit_conditional(
+ emit,
+ compare_func,
+ dst,
+ src0,
+ src1,
+ one, zero);
+ }
+}
+
+
+static boolean emit_select_op(struct svga_shader_emitter *emit,
+ unsigned compare,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+
+ return emit_select( emit, compare, dst, src0, src1 );
+}
+
+
+/* Translate texture instructions to SVGA3D representation.
+ */
+static boolean emit_tex2(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn,
+ SVGA3dShaderDestToken dst )
+{
+ SVGA3dShaderInstToken inst;
+ struct src_register src0;
+ struct src_register src1;
+
+ inst.value = 0;
+ inst.op = SVGA3DOP_TEX;
+
+ switch (insn->Instruction.Opcode) {
+ case TGSI_OPCODE_TEX:
+ break;
+ case TGSI_OPCODE_TXP:
+ inst.control = SVGA3DOPCONT_PROJECT;
+ break;
+ case TGSI_OPCODE_TXB:
+ inst.control = SVGA3DOPCONT_BIAS;
+ break;
+ default:
+ assert(0);
+ return FALSE;
+ }
+
+ src0 = translate_src_register( emit, &insn->Src[0] );
+ src1 = translate_src_register( emit, &insn->Src[1] );
+
+ if (emit->key.fkey.tex[src1.base.num].unnormalized) {
+ struct src_register wh = get_tex_dimensions( emit, src1.base.num );
+ SVGA3dShaderDestToken tmp = get_temp( emit );
+
+ /* MUL tmp, SRC0, WH */
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ),
+ tmp, src0, wh ))
+ return FALSE;
+ src0 = src( tmp );
+ }
+
+ return submit_op2( emit, inst, dst, src0, src1 );
+}
+
+
+
+
+/* Translate texture instructions to SVGA3D representation.
+ */
+static boolean emit_tex3(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn,
+ SVGA3dShaderDestToken dst )
+{
+ SVGA3dShaderInstToken inst;
+ struct src_register src0;
+ struct src_register src1;
+ struct src_register src2;
+
+ inst.value = 0;
+
+ switch (insn->Instruction.Opcode) {
+ case TGSI_OPCODE_TXD:
+ inst.op = SVGA3DOP_TEXLDD;
+ break;
+ case TGSI_OPCODE_TXL:
+ inst.op = SVGA3DOP_TEXLDL;
+ break;
+ }
+
+ src0 = translate_src_register( emit, &insn->Src[0] );
+ src1 = translate_src_register( emit, &insn->Src[1] );
+ src2 = translate_src_register( emit, &insn->Src[2] );
+
+ return submit_op3( emit, inst, dst, src0, src1, src2 );
+}
+
+
+static boolean emit_tex(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderDestToken dst =
+ translate_dst_register( emit, insn, 0 );
+ struct src_register src0 =
+ translate_src_register( emit, &insn->Src[0] );
+ struct src_register src1 =
+ translate_src_register( emit, &insn->Src[1] );
+
+ SVGA3dShaderDestToken tex_result;
+
+ /* check for shadow samplers */
+ boolean compare = (emit->key.fkey.tex[src1.base.num].compare_mode ==
+ PIPE_TEX_COMPARE_R_TO_TEXTURE);
+
+
+ /* If doing compare processing, need to put this value into a
+ * temporary so it can be used as a source later on.
+ */
+ if (compare ||
+ (!emit->use_sm30 && dst.mask != TGSI_WRITEMASK_XYZW) ) {
+ tex_result = get_temp( emit );
+ }
+ else {
+ tex_result = dst;
+ }
+
+ switch(insn->Instruction.Opcode) {
+ case TGSI_OPCODE_TEX:
+ case TGSI_OPCODE_TXB:
+ case TGSI_OPCODE_TXP:
+ if (!emit_tex2( emit, insn, tex_result ))
+ return FALSE;
+ break;
+ case TGSI_OPCODE_TXL:
+ case TGSI_OPCODE_TXD:
+ if (!emit_tex3( emit, insn, tex_result ))
+ return FALSE;
+ break;
+ default:
+ assert(0);
+ }
+
+
+ if (compare) {
+ SVGA3dShaderDestToken src0_zdivw = get_temp( emit );
+ struct src_register tex_src_x = scalar(src(tex_result), TGSI_SWIZZLE_Y);
+ struct src_register one =
+ scalar( get_zero_immediate( emit ), TGSI_SWIZZLE_W );
+
+ /* Divide texcoord R by Q */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_RCP ),
+ src0_zdivw,
+ scalar(src0, TGSI_SWIZZLE_W) ))
+ return FALSE;
+
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ),
+ src0_zdivw,
+ scalar(src0, TGSI_SWIZZLE_Z),
+ src(src0_zdivw) ))
+ return FALSE;
+
+ if (!emit_select(
+ emit,
+ emit->key.fkey.tex[src1.base.num].compare_func,
+ dst,
+ src(src0_zdivw),
+ tex_src_x))
+ return FALSE;
+
+ return submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask( dst, TGSI_WRITEMASK_W),
+ one );
+ }
+ else if (!emit->use_sm30 && dst.mask != TGSI_WRITEMASK_XYZW)
+ {
+ if (!emit_op1( emit, inst_token( SVGA3DOP_MOV ), dst, src(tex_result) ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean emit_bgnloop2( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst = inst_token( SVGA3DOP_LOOP );
+ struct src_register loop_reg = src_register( SVGA3DREG_LOOP, 0 );
+ struct src_register const_int = get_loop_const( emit );
+
+ return (emit_instruction( emit, inst ) &&
+ emit_src( emit, loop_reg ) &&
+ emit_src( emit, const_int ) );
+}
+
+static boolean emit_endloop2( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst = inst_token( SVGA3DOP_ENDLOOP );
+ return emit_instruction( emit, inst );
+}
+
+static boolean emit_brk( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst = inst_token( SVGA3DOP_BREAK );
+ return emit_instruction( emit, inst );
+}
+
+static boolean emit_scalar_op1( struct svga_shader_emitter *emit,
+ unsigned opcode,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst;
+ SVGA3dShaderDestToken dst;
+ struct src_register src;
+
+ inst = inst_token( opcode );
+ dst = translate_dst_register( emit, insn, 0 );
+ src = translate_src_register( emit, &insn->Src[0] );
+ src = scalar( src, TGSI_SWIZZLE_X );
+
+ return submit_op1( emit, inst, dst, src );
+}
+
+
+static boolean emit_simple_instruction(struct svga_shader_emitter *emit,
+ unsigned opcode,
+ const struct tgsi_full_instruction *insn )
+{
+ const struct tgsi_full_src_register *src = insn->Src;
+ SVGA3dShaderInstToken inst;
+ SVGA3dShaderDestToken dst;
+
+ inst = inst_token( opcode );
+ dst = translate_dst_register( emit, insn, 0 );
+
+ switch (insn->Instruction.NumSrcRegs) {
+ case 0:
+ return submit_op0( emit, inst, dst );
+ case 1:
+ return submit_op1( emit, inst, dst,
+ translate_src_register( emit, &src[0] ));
+ case 2:
+ return submit_op2( emit, inst, dst,
+ translate_src_register( emit, &src[0] ),
+ translate_src_register( emit, &src[1] ) );
+ case 3:
+ return submit_op3( emit, inst, dst,
+ translate_src_register( emit, &src[0] ),
+ translate_src_register( emit, &src[1] ),
+ translate_src_register( emit, &src[2] ) );
+ default:
+ assert(0);
+ return FALSE;
+ }
+}
+
+static boolean emit_arl(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ ++emit->current_arl;
+ if (svga_arl_needs_adjustment( emit )) {
+ return emit_fake_arl( emit, insn );
+ } else {
+ /* no need to adjust, just emit straight arl */
+ return emit_simple_instruction(emit, SVGA3DOP_MOVA, insn);
+ }
+}
+
+static boolean alias_src_dst( struct src_register src,
+ SVGA3dShaderDestToken dst )
+{
+ if (src.base.num != dst.num)
+ return FALSE;
+
+ if (SVGA3dShaderGetRegType(dst.value) !=
+ SVGA3dShaderGetRegType(src.base.value))
+ return FALSE;
+
+ return TRUE;
+}
+
+static boolean emit_pow(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ boolean need_tmp = FALSE;
+
+ /* POW can only output to a temporary */
+ if (insn->Dst[0].Register.File != TGSI_FILE_TEMPORARY)
+ need_tmp = TRUE;
+
+ /* POW src1 must not be the same register as dst */
+ if (alias_src_dst( src1, dst ))
+ need_tmp = TRUE;
+
+ /* it's a scalar op */
+ src0 = scalar( src0, TGSI_SWIZZLE_X );
+ src1 = scalar( src1, TGSI_SWIZZLE_X );
+
+ if (need_tmp) {
+ SVGA3dShaderDestToken tmp = writemask(get_temp( emit ), TGSI_WRITEMASK_X );
+
+ if (!submit_op2(emit, inst_token( SVGA3DOP_POW ), tmp, src0, src1))
+ return FALSE;
+
+ return submit_op1(emit, inst_token( SVGA3DOP_MOV ), dst, scalar(src(tmp), 0) );
+ }
+ else {
+ return submit_op2(emit, inst_token( SVGA3DOP_POW ), dst, src0, src1);
+ }
+}
+
+static boolean emit_xpd(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ boolean need_dst_tmp = FALSE;
+
+ /* XPD can only output to a temporary */
+ if (SVGA3dShaderGetRegType(dst.value) != SVGA3DREG_TEMP)
+ need_dst_tmp = TRUE;
+
+ /* The dst reg must not be the same as src0 or src1*/
+ if (alias_src_dst(src0, dst) ||
+ alias_src_dst(src1, dst))
+ need_dst_tmp = TRUE;
+
+ if (need_dst_tmp) {
+ SVGA3dShaderDestToken tmp = get_temp( emit );
+
+ /* Obey DX9 restrictions on mask:
+ */
+ tmp.mask = dst.mask & TGSI_WRITEMASK_XYZ;
+
+ if (!submit_op2(emit, inst_token( SVGA3DOP_CRS ), tmp, src0, src1))
+ return FALSE;
+
+ if (!submit_op1(emit, inst_token( SVGA3DOP_MOV ), dst, src( tmp )))
+ return FALSE;
+ }
+ else {
+ if (!submit_op2(emit, inst_token( SVGA3DOP_CRS ), dst, src0, src1))
+ return FALSE;
+ }
+
+ /* Need to emit 1.0 to dst.w?
+ */
+ if (dst.mask & TGSI_WRITEMASK_W) {
+ struct src_register zero = get_zero_immediate( emit );
+
+ if (!submit_op1(emit,
+ inst_token( SVGA3DOP_MOV ),
+ writemask(dst, TGSI_WRITEMASK_W),
+ zero))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static boolean emit_lrp(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ SVGA3dShaderDestToken tmp;
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ const struct src_register src2 = translate_src_register(
+ emit, &insn->Src[2] );
+ boolean need_dst_tmp = FALSE;
+
+ /* The dst reg must not be the same as src0 or src2 */
+ if (alias_src_dst(src0, dst) ||
+ alias_src_dst(src2, dst))
+ need_dst_tmp = TRUE;
+
+ if (need_dst_tmp) {
+ tmp = get_temp( emit );
+ tmp.mask = dst.mask;
+ }
+ else {
+ tmp = dst;
+ }
+
+ if (!submit_op3(emit, inst_token( SVGA3DOP_LRP ), tmp, src0, src1, src2))
+ return FALSE;
+
+ if (need_dst_tmp) {
+ if (!submit_op1(emit, inst_token( SVGA3DOP_MOV ), dst, src( tmp )))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static boolean emit_dst_insn(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ /* SVGA/DX9 has a DST instruction, but only for vertex shaders:
+ */
+ return emit_simple_instruction(emit, SVGA3DOP_DST, insn);
+ }
+ else {
+
+ /* result[0] = 1 * 1;
+ * result[1] = a[1] * b[1];
+ * result[2] = a[2] * 1;
+ * result[3] = 1 * b[3];
+ */
+
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ SVGA3dShaderDestToken tmp;
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ const struct src_register src1 = translate_src_register(
+ emit, &insn->Src[1] );
+ struct src_register zero = get_zero_immediate( emit );
+ boolean need_tmp = FALSE;
+
+ if (SVGA3dShaderGetRegType(dst.value) != SVGA3DREG_TEMP ||
+ alias_src_dst(src0, dst) ||
+ alias_src_dst(src1, dst))
+ need_tmp = TRUE;
+
+ if (need_tmp) {
+ tmp = get_temp( emit );
+ }
+ else {
+ tmp = dst;
+ }
+
+ /* tmp.xw = 1.0
+ */
+ if (tmp.mask & TGSI_WRITEMASK_XW) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask(tmp, TGSI_WRITEMASK_XW ),
+ scalar( zero, 3 )))
+ return FALSE;
+ }
+
+ /* tmp.yz = src0
+ */
+ if (tmp.mask & TGSI_WRITEMASK_YZ) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask(tmp, TGSI_WRITEMASK_YZ ),
+ src0))
+ return FALSE;
+ }
+
+ /* tmp.yw = tmp * src1
+ */
+ if (tmp.mask & TGSI_WRITEMASK_YW) {
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ),
+ writemask(tmp, TGSI_WRITEMASK_YW ),
+ src(tmp),
+ src1))
+ return FALSE;
+ }
+
+ /* dst = tmp
+ */
+ if (need_tmp) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ dst,
+ src(tmp)))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+static boolean emit_exp(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 =
+ translate_src_register( emit, &insn->Src[0] );
+ struct src_register zero = get_zero_immediate( emit );
+ SVGA3dShaderDestToken fraction;
+
+ if (dst.mask & TGSI_WRITEMASK_Y)
+ fraction = dst;
+ else if (dst.mask & TGSI_WRITEMASK_X)
+ fraction = get_temp( emit );
+
+ /* If y is being written, fill it with src0 - floor(src0).
+ */
+ if (dst.mask & TGSI_WRITEMASK_XY) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_FRC ),
+ writemask( fraction, TGSI_WRITEMASK_Y ),
+ src0 ))
+ return FALSE;
+ }
+
+ /* If x is being written, fill it with 2 ^ floor(src0).
+ */
+ if (dst.mask & TGSI_WRITEMASK_X) {
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ),
+ writemask( dst, dst.mask & TGSI_WRITEMASK_X ),
+ src0,
+ scalar( negate( src( fraction ) ), TGSI_SWIZZLE_Y ) ) )
+ return FALSE;
+
+ if (!submit_op1( emit, inst_token( SVGA3DOP_EXP ),
+ writemask( dst, dst.mask & TGSI_WRITEMASK_X ),
+ scalar( src( dst ), TGSI_SWIZZLE_X ) ) )
+ return FALSE;
+
+ if (!(dst.mask & TGSI_WRITEMASK_Y))
+ release_temp( emit, fraction );
+ }
+
+ /* If z is being written, fill it with 2 ^ src0 (partial precision).
+ */
+ if (dst.mask & TGSI_WRITEMASK_Z) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_EXPP ),
+ writemask( dst, dst.mask & TGSI_WRITEMASK_Z ),
+ src0 ) )
+ return FALSE;
+ }
+
+ /* If w is being written, fill it with one.
+ */
+ if (dst.mask & TGSI_WRITEMASK_W) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask(dst, TGSI_WRITEMASK_W),
+ scalar( zero, TGSI_SWIZZLE_W ) ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean emit_lit(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ /* SVGA/DX9 has a LIT instruction, but only for vertex shaders:
+ */
+ return emit_simple_instruction(emit, SVGA3DOP_LIT, insn);
+ }
+ else {
+
+ /* D3D vs. GL semantics can be fairly easily accomodated by
+ * variations on this sequence.
+ *
+ * GL:
+ * tmp.y = src.x
+ * tmp.z = pow(src.y,src.w)
+ * p0 = src0.xxxx > 0
+ * result = zero.wxxw
+ * (p0) result.yz = tmp
+ *
+ * D3D:
+ * tmp.y = src.x
+ * tmp.z = pow(src.y,src.w)
+ * p0 = src0.xxyy > 0
+ * result = zero.wxxw
+ * (p0) result.yz = tmp
+ *
+ * Will implement the GL version for now.
+ */
+
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ SVGA3dShaderDestToken tmp = get_temp( emit );
+ const struct src_register src0 = translate_src_register(
+ emit, &insn->Src[0] );
+ struct src_register zero = get_zero_immediate( emit );
+
+ /* tmp = pow(src.y, src.w)
+ */
+ if (dst.mask & TGSI_WRITEMASK_Z) {
+ if (!submit_op2(emit, inst_token( SVGA3DOP_POW ),
+ tmp,
+ scalar(src0, 1),
+ scalar(src0, 3)))
+ return FALSE;
+ }
+
+ /* tmp.y = src.x
+ */
+ if (dst.mask & TGSI_WRITEMASK_Y) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask(tmp, TGSI_WRITEMASK_Y ),
+ scalar(src0, 0)))
+ return FALSE;
+ }
+
+ /* Can't quite do this with emit conditional due to the extra
+ * writemask on the predicated mov:
+ */
+ {
+ SVGA3dShaderDestToken pred_reg = dst_register( SVGA3DREG_PREDICATE, 0 );
+ SVGA3dShaderInstToken setp_token, mov_token;
+ struct src_register predsrc;
+
+ setp_token = inst_token( SVGA3DOP_SETP );
+ mov_token = inst_token( SVGA3DOP_MOV );
+
+ setp_token.control = SVGA3DOPCOMP_GT;
+
+ /* D3D vs GL semantics:
+ */
+ if (0)
+ predsrc = swizzle(src0, 0, 0, 1, 1); /* D3D */
+ else
+ predsrc = swizzle(src0, 0, 0, 0, 0); /* GL */
+
+ /* SETP src0.xxyy, GT, {0}.x */
+ if (!submit_op2( emit, setp_token, pred_reg,
+ predsrc,
+ swizzle(zero, 0, 0, 0, 0) ))
+ return FALSE;
+
+ /* MOV dst, fail */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), dst,
+ swizzle(zero, 3, 0, 0, 3 )))
+ return FALSE;
+
+ /* MOV dst.yz, tmp (predicated)
+ *
+ * Note that the predicate reg (and possible modifiers) is passed
+ * as the first source argument.
+ */
+ if (dst.mask & TGSI_WRITEMASK_YZ) {
+ mov_token.predicated = 1;
+ if (!submit_op2( emit, mov_token,
+ writemask(dst, TGSI_WRITEMASK_YZ),
+ src( pred_reg ), src( tmp ) ))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+static boolean emit_ex2( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ SVGA3dShaderInstToken inst;
+ SVGA3dShaderDestToken dst;
+ struct src_register src0;
+
+ inst = inst_token( SVGA3DOP_EXP );
+ dst = translate_dst_register( emit, insn, 0 );
+ src0 = translate_src_register( emit, &insn->Src[0] );
+ src0 = scalar( src0, TGSI_SWIZZLE_X );
+
+ if (dst.mask != TGSI_WRITEMASK_XYZW) {
+ SVGA3dShaderDestToken tmp = get_temp( emit );
+
+ if (!submit_op1( emit, inst, tmp, src0 ))
+ return FALSE;
+
+ return submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ dst,
+ scalar( src( tmp ), TGSI_SWIZZLE_X ) );
+ }
+
+ return submit_op1( emit, inst, dst, src0 );
+}
+
+
+static boolean emit_log(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register( emit, insn, 0 );
+ struct src_register src0 =
+ translate_src_register( emit, &insn->Src[0] );
+ struct src_register zero = get_zero_immediate( emit );
+ SVGA3dShaderDestToken abs_tmp;
+ struct src_register abs_src0;
+ SVGA3dShaderDestToken log2_abs;
+
+ if (dst.mask & TGSI_WRITEMASK_Z)
+ log2_abs = dst;
+ else if (dst.mask & TGSI_WRITEMASK_XY)
+ log2_abs = get_temp( emit );
+
+ /* If z is being written, fill it with log2( abs( src0 ) ).
+ */
+ if (dst.mask & TGSI_WRITEMASK_XYZ) {
+ if (!src0.base.srcMod || src0.base.srcMod == SVGA3DSRCMOD_ABS)
+ abs_src0 = src0;
+ else {
+ abs_tmp = get_temp( emit );
+
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ abs_tmp,
+ src0 ) )
+ return FALSE;
+
+ abs_src0 = src( abs_tmp );
+ }
+
+ abs_src0 = absolute( scalar( abs_src0, TGSI_SWIZZLE_X ) );
+
+ if (!submit_op1( emit, inst_token( SVGA3DOP_LOG ),
+ writemask( log2_abs, TGSI_WRITEMASK_Z ),
+ abs_src0 ) )
+ return FALSE;
+ }
+
+ if (dst.mask & TGSI_WRITEMASK_XY) {
+ SVGA3dShaderDestToken floor_log2;
+
+ if (dst.mask & TGSI_WRITEMASK_X)
+ floor_log2 = dst;
+ else
+ floor_log2 = get_temp( emit );
+
+ /* If x is being written, fill it with floor( log2( abs( src0 ) ) ).
+ */
+ if (!submit_op1( emit, inst_token( SVGA3DOP_FRC ),
+ writemask( floor_log2, TGSI_WRITEMASK_X ),
+ scalar( src( log2_abs ), TGSI_SWIZZLE_Z ) ) )
+ return FALSE;
+
+ if (!submit_op2( emit, inst_token( SVGA3DOP_ADD ),
+ writemask( floor_log2, TGSI_WRITEMASK_X ),
+ scalar( src( log2_abs ), TGSI_SWIZZLE_Z ),
+ negate( src( floor_log2 ) ) ) )
+ return FALSE;
+
+ /* If y is being written, fill it with
+ * abs ( src0 ) / ( 2 ^ floor( log2( abs( src0 ) ) ) ).
+ */
+ if (dst.mask & TGSI_WRITEMASK_Y) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_EXP ),
+ writemask( dst, TGSI_WRITEMASK_Y ),
+ negate( scalar( src( floor_log2 ),
+ TGSI_SWIZZLE_X ) ) ) )
+ return FALSE;
+
+ if (!submit_op2( emit, inst_token( SVGA3DOP_MUL ),
+ writemask( dst, TGSI_WRITEMASK_Y ),
+ src( dst ),
+ abs_src0 ) )
+ return FALSE;
+ }
+
+ if (!(dst.mask & TGSI_WRITEMASK_X))
+ release_temp( emit, floor_log2 );
+
+ if (!(dst.mask & TGSI_WRITEMASK_Z))
+ release_temp( emit, log2_abs );
+ }
+
+ if (dst.mask & TGSI_WRITEMASK_XYZ && src0.base.srcMod &&
+ src0.base.srcMod != SVGA3DSRCMOD_ABS)
+ release_temp( emit, abs_tmp );
+
+ /* If w is being written, fill it with one.
+ */
+ if (dst.mask & TGSI_WRITEMASK_W) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ),
+ writemask(dst, TGSI_WRITEMASK_W),
+ scalar( zero, TGSI_SWIZZLE_W ) ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static boolean emit_bgnsub( struct svga_shader_emitter *emit,
+ unsigned position,
+ const struct tgsi_full_instruction *insn )
+{
+ unsigned i;
+
+ /* Note that we've finished the main function and are now emitting
+ * subroutines. This affects how we terminate the generated
+ * shader.
+ */
+ emit->in_main_func = FALSE;
+
+ for (i = 0; i < emit->nr_labels; i++) {
+ if (emit->label[i] == position) {
+ return (emit_instruction( emit, inst_token( SVGA3DOP_RET ) ) &&
+ emit_instruction( emit, inst_token( SVGA3DOP_LABEL ) ) &&
+ emit_src( emit, src_register( SVGA3DREG_LABEL, i )));
+ }
+ }
+
+ assert(0);
+ return TRUE;
+}
+
+static boolean emit_call( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn )
+{
+ unsigned position = insn->Label.Label;
+ unsigned i;
+
+ for (i = 0; i < emit->nr_labels; i++) {
+ if (emit->label[i] == position)
+ break;
+ }
+
+ if (emit->nr_labels == Elements(emit->label))
+ return FALSE;
+
+ if (i == emit->nr_labels) {
+ emit->label[i] = position;
+ emit->nr_labels++;
+ }
+
+ return (emit_instruction( emit, inst_token( SVGA3DOP_CALL ) ) &&
+ emit_src( emit, src_register( SVGA3DREG_LABEL, i )));
+}
+
+
+static boolean emit_end( struct svga_shader_emitter *emit )
+{
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ return emit_vs_postamble( emit );
+ }
+ else {
+ return emit_ps_postamble( emit );
+ }
+}
+
+
+
+static boolean svga_emit_instruction( struct svga_shader_emitter *emit,
+ unsigned position,
+ const struct tgsi_full_instruction *insn )
+{
+ switch (insn->Instruction.Opcode) {
+
+ case TGSI_OPCODE_ARL:
+ return emit_arl( emit, insn );
+
+ case TGSI_OPCODE_TEX:
+ case TGSI_OPCODE_TXB:
+ case TGSI_OPCODE_TXP:
+ case TGSI_OPCODE_TXL:
+ case TGSI_OPCODE_TXD:
+ return emit_tex( emit, insn );
+
+ case TGSI_OPCODE_BGNSUB:
+ return emit_bgnsub( emit, position, insn );
+
+ case TGSI_OPCODE_ENDSUB:
+ return TRUE;
+
+ case TGSI_OPCODE_CAL:
+ return emit_call( emit, insn );
+
+ case TGSI_OPCODE_FLR:
+ case TGSI_OPCODE_TRUNC: /* should be TRUNC, not FLR */
+ return emit_floor( emit, insn );
+
+ case TGSI_OPCODE_CMP:
+ return emit_cmp( emit, insn );
+
+ case TGSI_OPCODE_DIV:
+ return emit_div( emit, insn );
+
+ case TGSI_OPCODE_DP2:
+ return emit_dp2( emit, insn );
+
+ case TGSI_OPCODE_DPH:
+ return emit_dph( emit, insn );
+
+ case TGSI_OPCODE_NRM:
+ return emit_nrm( emit, insn );
+
+ case TGSI_OPCODE_COS:
+ return emit_cos( emit, insn );
+
+ case TGSI_OPCODE_SIN:
+ return emit_sin( emit, insn );
+
+ case TGSI_OPCODE_SCS:
+ return emit_sincos( emit, insn );
+
+ case TGSI_OPCODE_END:
+ /* TGSI always finishes the main func with an END */
+ return emit_end( emit );
+
+ case TGSI_OPCODE_KIL:
+ return emit_kil( emit, insn );
+
+ /* Selection opcodes. The underlying language is fairly
+ * non-orthogonal about these.
+ */
+ case TGSI_OPCODE_SEQ:
+ return emit_select_op( emit, PIPE_FUNC_EQUAL, insn );
+
+ case TGSI_OPCODE_SNE:
+ return emit_select_op( emit, PIPE_FUNC_NOTEQUAL, insn );
+
+ case TGSI_OPCODE_SGT:
+ return emit_select_op( emit, PIPE_FUNC_GREATER, insn );
+
+ case TGSI_OPCODE_SGE:
+ return emit_select_op( emit, PIPE_FUNC_GEQUAL, insn );
+
+ case TGSI_OPCODE_SLT:
+ return emit_select_op( emit, PIPE_FUNC_LESS, insn );
+
+ case TGSI_OPCODE_SLE:
+ return emit_select_op( emit, PIPE_FUNC_LEQUAL, insn );
+
+ case TGSI_OPCODE_SUB:
+ return emit_sub( emit, insn );
+
+ case TGSI_OPCODE_POW:
+ return emit_pow( emit, insn );
+
+ case TGSI_OPCODE_EX2:
+ return emit_ex2( emit, insn );
+
+ case TGSI_OPCODE_EXP:
+ return emit_exp( emit, insn );
+
+ case TGSI_OPCODE_LOG:
+ return emit_log( emit, insn );
+
+ case TGSI_OPCODE_LG2:
+ return emit_scalar_op1( emit, SVGA3DOP_LOG, insn );
+
+ case TGSI_OPCODE_RSQ:
+ return emit_scalar_op1( emit, SVGA3DOP_RSQ, insn );
+
+ case TGSI_OPCODE_RCP:
+ return emit_scalar_op1( emit, SVGA3DOP_RCP, insn );
+
+ case TGSI_OPCODE_CONT:
+ case TGSI_OPCODE_RET:
+ /* This is a noop -- we tell mesa that we can't support RET
+ * within a function (early return), so this will always be
+ * followed by an ENDSUB.
+ */
+ return TRUE;
+
+ /* These aren't actually used by any of the frontends we care
+ * about:
+ */
+ case TGSI_OPCODE_CLAMP:
+ case TGSI_OPCODE_ROUND:
+ case TGSI_OPCODE_AND:
+ case TGSI_OPCODE_OR:
+ case TGSI_OPCODE_I2F:
+ case TGSI_OPCODE_NOT:
+ case TGSI_OPCODE_SHL:
+ case TGSI_OPCODE_SHR:
+ case TGSI_OPCODE_XOR:
+ return FALSE;
+
+ case TGSI_OPCODE_IF:
+ return emit_if( emit, insn );
+ case TGSI_OPCODE_ELSE:
+ return emit_else( emit, insn );
+ case TGSI_OPCODE_ENDIF:
+ return emit_endif( emit, insn );
+
+ case TGSI_OPCODE_BGNLOOP:
+ return emit_bgnloop2( emit, insn );
+ case TGSI_OPCODE_ENDLOOP:
+ return emit_endloop2( emit, insn );
+ case TGSI_OPCODE_BRK:
+ return emit_brk( emit, insn );
+
+ case TGSI_OPCODE_XPD:
+ return emit_xpd( emit, insn );
+
+ case TGSI_OPCODE_KILP:
+ return emit_kilp( emit, insn );
+
+ case TGSI_OPCODE_DST:
+ return emit_dst_insn( emit, insn );
+
+ case TGSI_OPCODE_LIT:
+ return emit_lit( emit, insn );
+
+ case TGSI_OPCODE_LRP:
+ return emit_lrp( emit, insn );
+
+ default: {
+ unsigned opcode = translate_opcode(insn->Instruction.Opcode);
+
+ if (opcode == SVGA3DOP_LAST_INST)
+ return FALSE;
+
+ if (!emit_simple_instruction( emit, opcode, insn ))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+static boolean svga_emit_immediate( struct svga_shader_emitter *emit,
+ struct tgsi_full_immediate *imm)
+{
+ static const float id[4] = {0,0,0,1};
+ float value[4];
+ unsigned i;
+
+ assert(1 <= imm->Immediate.NrTokens && imm->Immediate.NrTokens <= 5);
+ for (i = 0; i < imm->Immediate.NrTokens - 1; i++)
+ value[i] = imm->u[i].Float;
+
+ for ( ; i < 4; i++ )
+ value[i] = id[i];
+
+ return emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT,
+ emit->imm_start + emit->internal_imm_count++,
+ value[0], value[1], value[2], value[3]);
+}
+
+static boolean make_immediate( struct svga_shader_emitter *emit,
+ float a,
+ float b,
+ float c,
+ float d,
+ struct src_register *out )
+{
+ unsigned idx = emit->nr_hw_const++;
+
+ if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT,
+ idx, a, b, c, d ))
+ return FALSE;
+
+ *out = src_register( SVGA3DREG_CONST, idx );
+
+ return TRUE;
+}
+
+static boolean emit_vs_preamble( struct svga_shader_emitter *emit )
+{
+ if (!emit->key.vkey.need_prescale) {
+ if (!make_immediate( emit, 0, 0, .5, .5,
+ &emit->imm_0055))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean emit_ps_preamble( struct svga_shader_emitter *emit )
+{
+ unsigned i;
+
+ /* For SM20, need to initialize the temporaries we're using to hold
+ * color outputs to some value. Shaders which don't set all of
+ * these values are likely to be rejected by the DX9 runtime.
+ */
+ if (!emit->use_sm30) {
+ struct src_register zero = get_zero_immediate( emit );
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (SVGA3dShaderGetRegType(emit->true_col[i].value) != 0) {
+
+ if (!submit_op1( emit,
+ inst_token(SVGA3DOP_MOV),
+ emit->temp_col[i],
+ zero ))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean emit_ps_postamble( struct svga_shader_emitter *emit )
+{
+ unsigned i;
+
+ /* PS oDepth is incredibly fragile and it's very hard to catch the
+ * types of usage that break it during shader emit. Easier just to
+ * redirect the main program to a temporary and then only touch
+ * oDepth with a hand-crafted MOV below.
+ */
+ if (SVGA3dShaderGetRegType(emit->true_pos.value) != 0) {
+
+ if (!submit_op1( emit,
+ inst_token(SVGA3DOP_MOV),
+ emit->true_pos,
+ scalar(src(emit->temp_pos), TGSI_SWIZZLE_Z) ))
+ return FALSE;
+ }
+
+ /* Similarly for SM20 color outputs... Luckily SM30 isn't so
+ * fragile.
+ */
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (SVGA3dShaderGetRegType(emit->true_col[i].value) != 0) {
+
+ if (!submit_op1( emit,
+ inst_token(SVGA3DOP_MOV),
+ emit->true_col[i],
+ src(emit->temp_col[i]) ))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean emit_vs_postamble( struct svga_shader_emitter *emit )
+{
+ /* PSIZ output is incredibly fragile and it's very hard to catch
+ * the types of usage that break it during shader emit. Easier
+ * just to redirect the main program to a temporary and then only
+ * touch PSIZ with a hand-crafted MOV below.
+ */
+ if (SVGA3dShaderGetRegType(emit->true_psiz.value) != 0) {
+
+ if (!submit_op1( emit,
+ inst_token(SVGA3DOP_MOV),
+ emit->true_psiz,
+ scalar(src(emit->temp_psiz), TGSI_SWIZZLE_X) ))
+ return FALSE;
+ }
+
+ /* Need to perform various manipulations on vertex position to cope
+ * with the different GL and D3D clip spaces.
+ */
+ if (emit->key.vkey.need_prescale) {
+ SVGA3dShaderDestToken temp_pos = emit->temp_pos;
+ SVGA3dShaderDestToken pos = emit->true_pos;
+ unsigned offset = emit->info.file_max[TGSI_FILE_CONSTANT] + 1;
+ struct src_register prescale_scale = src_register( SVGA3DREG_CONST,
+ offset + 0 );
+ struct src_register prescale_trans = src_register( SVGA3DREG_CONST,
+ offset + 1 );
+
+ /* MUL temp_pos.xyz, temp_pos, prescale.scale
+ * MAD result.position, temp_pos.wwww, prescale.trans, temp_pos
+ * --> Note that prescale.trans.w == 0
+ */
+ if (!submit_op2( emit,
+ inst_token(SVGA3DOP_MUL),
+ writemask(temp_pos, TGSI_WRITEMASK_XYZ),
+ src(temp_pos),
+ prescale_scale ))
+ return FALSE;
+
+ if (!submit_op3( emit,
+ inst_token(SVGA3DOP_MAD),
+ pos,
+ swizzle(src(temp_pos), 3, 3, 3, 3),
+ prescale_trans,
+ src(temp_pos)))
+ return FALSE;
+ }
+ else {
+ SVGA3dShaderDestToken temp_pos = emit->temp_pos;
+ SVGA3dShaderDestToken pos = emit->true_pos;
+ struct src_register imm_0055 = emit->imm_0055;
+
+ /* Adjust GL clipping coordinate space to hardware (D3D-style):
+ *
+ * DP4 temp_pos.z, {0,0,.5,.5}, temp_pos
+ * MOV result.position, temp_pos
+ */
+ if (!submit_op2( emit,
+ inst_token(SVGA3DOP_DP4),
+ writemask(temp_pos, TGSI_WRITEMASK_Z),
+ imm_0055,
+ src(temp_pos) ))
+ return FALSE;
+
+ if (!submit_op1( emit,
+ inst_token(SVGA3DOP_MOV),
+ pos,
+ src(temp_pos) ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ 0: IF VFACE :4
+ 1: COLOR = FrontColor;
+ 2: ELSE
+ 3: COLOR = BackColor;
+ 4: ENDIF
+ */
+static boolean emit_light_twoside( struct svga_shader_emitter *emit )
+{
+ struct src_register vface, zero;
+ struct src_register front[2];
+ struct src_register back[2];
+ SVGA3dShaderDestToken color[2];
+ int count = emit->internal_color_count;
+ int i;
+ SVGA3dShaderInstToken if_token;
+
+ if (count == 0)
+ return TRUE;
+
+ vface = get_vface( emit );
+ zero = get_zero_immediate( emit );
+
+ /* Can't use get_temp() to allocate the color reg as such
+ * temporaries will be reclaimed after each instruction by the call
+ * to reset_temp_regs().
+ */
+ for (i = 0; i < count; i++) {
+ color[i] = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+
+ front[i] = emit->input_map[emit->internal_color_idx[i]];
+
+ /* Back is always the next input:
+ */
+ back[i] = front[i];
+ back[i].base.num = front[i].base.num + 1;
+
+ /* Reassign the input_map to the actual front-face color:
+ */
+ emit->input_map[emit->internal_color_idx[i]] = src(color[i]);
+ }
+
+ if_token = inst_token( SVGA3DOP_IFC );
+
+ if (emit->key.fkey.front_cw)
+ if_token.control = SVGA3DOPCOMP_GT;
+ else
+ if_token.control = SVGA3DOPCOMP_LT;
+
+ zero = scalar(zero, TGSI_SWIZZLE_X);
+
+ if (!(emit_instruction( emit, if_token ) &&
+ emit_src( emit, vface ) &&
+ emit_src( emit, zero ) ))
+ return FALSE;
+
+ for (i = 0; i < count; i++) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), color[i], front[i] ))
+ return FALSE;
+ }
+
+ if (!(emit_instruction( emit, inst_token( SVGA3DOP_ELSE))))
+ return FALSE;
+
+ for (i = 0; i < count; i++) {
+ if (!submit_op1( emit, inst_token( SVGA3DOP_MOV ), color[i], back[i] ))
+ return FALSE;
+ }
+
+ if (!emit_instruction( emit, inst_token( SVGA3DOP_ENDIF ) ))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ 0: SETP_GT TEMP, VFACE, 0
+ where TEMP is a fake frontface register
+ */
+static boolean emit_frontface( struct svga_shader_emitter *emit )
+{
+ struct src_register vface, zero;
+ SVGA3dShaderDestToken temp;
+ struct src_register pass, fail;
+
+ vface = get_vface( emit );
+ zero = get_zero_immediate( emit );
+
+ /* Can't use get_temp() to allocate the fake frontface reg as such
+ * temporaries will be reclaimed after each instruction by the call
+ * to reset_temp_regs().
+ */
+ temp = dst_register( SVGA3DREG_TEMP,
+ emit->nr_hw_temp++ );
+
+ if (emit->key.fkey.front_cw) {
+ pass = scalar( zero, TGSI_SWIZZLE_W );
+ fail = scalar( zero, TGSI_SWIZZLE_X );
+ } else {
+ pass = scalar( zero, TGSI_SWIZZLE_X );
+ fail = scalar( zero, TGSI_SWIZZLE_W );
+ }
+
+ if (!emit_conditional(emit, PIPE_FUNC_GREATER,
+ temp, vface, scalar( zero, TGSI_SWIZZLE_X ),
+ pass, fail))
+ return FALSE;
+
+ /* Reassign the input_map to the actual front-face color:
+ */
+ emit->input_map[emit->internal_frontface_idx] = src(temp);
+
+ return TRUE;
+}
+
+static INLINE boolean
+needs_to_create_zero( struct svga_shader_emitter *emit )
+{
+ int i;
+
+ if (emit->unit == PIPE_SHADER_FRAGMENT) {
+ if (!emit->use_sm30)
+ return TRUE;
+
+ if (emit->key.fkey.light_twoside)
+ return TRUE;
+
+ if (emit->emit_frontface)
+ return TRUE;
+
+ if (emit->info.opcode_count[TGSI_OPCODE_DST] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_LIT] >= 1)
+ return TRUE;
+ }
+
+ if (emit->info.opcode_count[TGSI_OPCODE_IF] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SGE] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SGT] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SLE] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SLT] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SNE] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SEQ] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_EXP] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_LOG] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_XPD] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_KILP] >= 1)
+ return TRUE;
+
+ for (i = 0; i < emit->key.fkey.num_textures; i++) {
+ if (emit->key.fkey.tex[i].compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static INLINE boolean
+needs_to_create_loop_const( struct svga_shader_emitter *emit )
+{
+ return (emit->info.opcode_count[TGSI_OPCODE_BGNLOOP] >= 1);
+}
+
+static INLINE boolean
+needs_to_create_sincos_consts( struct svga_shader_emitter *emit )
+{
+ return !emit->use_sm30 && (emit->info.opcode_count[TGSI_OPCODE_SIN] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_COS] >= 1 ||
+ emit->info.opcode_count[TGSI_OPCODE_SCS] >= 1);
+}
+
+static INLINE boolean
+needs_to_create_arl_consts( struct svga_shader_emitter *emit )
+{
+ return (emit->num_arl_consts > 0);
+}
+
+static INLINE boolean
+pre_parse_add_indirect( struct svga_shader_emitter *emit,
+ int num, int current_arl)
+{
+ int i;
+ assert(num < 0);
+
+ for (i = 0; i < emit->num_arl_consts; ++i) {
+ if (emit->arl_consts[i].arl_num == current_arl)
+ break;
+ }
+ /* new entry */
+ if (emit->num_arl_consts == i) {
+ ++emit->num_arl_consts;
+ }
+ emit->arl_consts[i].number = (emit->arl_consts[i].number > num) ?
+ num :
+ emit->arl_consts[i].number;
+ emit->arl_consts[i].arl_num = current_arl;
+ return TRUE;
+}
+
+static boolean
+pre_parse_instruction( struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn,
+ int current_arl)
+{
+ if (insn->Src[0].Register.Indirect &&
+ insn->Src[0].Indirect.File == TGSI_FILE_ADDRESS) {
+ const struct tgsi_full_src_register *reg = &insn->Src[0];
+ if (reg->Register.Index < 0) {
+ pre_parse_add_indirect(emit, reg->Register.Index, current_arl);
+ }
+ }
+
+ if (insn->Src[1].Register.Indirect &&
+ insn->Src[1].Indirect.File == TGSI_FILE_ADDRESS) {
+ const struct tgsi_full_src_register *reg = &insn->Src[1];
+ if (reg->Register.Index < 0) {
+ pre_parse_add_indirect(emit, reg->Register.Index, current_arl);
+ }
+ }
+
+ if (insn->Src[2].Register.Indirect &&
+ insn->Src[2].Indirect.File == TGSI_FILE_ADDRESS) {
+ const struct tgsi_full_src_register *reg = &insn->Src[2];
+ if (reg->Register.Index < 0) {
+ pre_parse_add_indirect(emit, reg->Register.Index, current_arl);
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean
+pre_parse_tokens( struct svga_shader_emitter *emit,
+ const struct tgsi_token *tokens )
+{
+ struct tgsi_parse_context parse;
+ int current_arl = 0;
+
+ tgsi_parse_init( &parse, tokens );
+
+ while (!tgsi_parse_end_of_tokens( &parse )) {
+ tgsi_parse_token( &parse );
+ switch (parse.FullToken.Token.Type) {
+ case TGSI_TOKEN_TYPE_IMMEDIATE:
+ case TGSI_TOKEN_TYPE_DECLARATION:
+ break;
+ case TGSI_TOKEN_TYPE_INSTRUCTION:
+ if (parse.FullToken.FullInstruction.Instruction.Opcode ==
+ TGSI_OPCODE_ARL) {
+ ++current_arl;
+ }
+ if (!pre_parse_instruction( emit, &parse.FullToken.FullInstruction,
+ current_arl ))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+
+ }
+ return TRUE;
+}
+
+static boolean svga_shader_emit_helpers( struct svga_shader_emitter *emit )
+
+{
+ if (needs_to_create_zero( emit )) {
+ create_zero_immediate( emit );
+ }
+ if (needs_to_create_loop_const( emit )) {
+ create_loop_const( emit );
+ }
+ if (needs_to_create_sincos_consts( emit )) {
+ create_sincos_consts( emit );
+ }
+ if (needs_to_create_arl_consts( emit )) {
+ create_arl_consts( emit );
+ }
+
+ if (emit->unit == PIPE_SHADER_FRAGMENT) {
+ if (!emit_ps_preamble( emit ))
+ return FALSE;
+
+ if (emit->key.fkey.light_twoside) {
+ if (!emit_light_twoside( emit ))
+ return FALSE;
+ }
+ if (emit->emit_frontface) {
+ if (!emit_frontface( emit ))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+boolean svga_shader_emit_instructions( struct svga_shader_emitter *emit,
+ const struct tgsi_token *tokens )
+{
+ struct tgsi_parse_context parse;
+ boolean ret = TRUE;
+ boolean helpers_emitted = FALSE;
+ unsigned line_nr = 0;
+
+ tgsi_parse_init( &parse, tokens );
+ emit->internal_imm_count = 0;
+
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ ret = emit_vs_preamble( emit );
+ if (!ret)
+ goto done;
+ }
+
+ pre_parse_tokens(emit, tokens);
+
+ while (!tgsi_parse_end_of_tokens( &parse )) {
+ tgsi_parse_token( &parse );
+
+ switch (parse.FullToken.Token.Type) {
+ case TGSI_TOKEN_TYPE_IMMEDIATE:
+ ret = svga_emit_immediate( emit, &parse.FullToken.FullImmediate );
+ if (!ret)
+ goto done;
+ break;
+
+ case TGSI_TOKEN_TYPE_DECLARATION:
+ if (emit->use_sm30)
+ ret = svga_translate_decl_sm30( emit, &parse.FullToken.FullDeclaration );
+ else
+ ret = svga_translate_decl_sm20( emit, &parse.FullToken.FullDeclaration );
+ if (!ret)
+ goto done;
+ break;
+
+ case TGSI_TOKEN_TYPE_INSTRUCTION:
+ if (!helpers_emitted) {
+ if (!svga_shader_emit_helpers( emit ))
+ goto done;
+ helpers_emitted = TRUE;
+ }
+ ret = svga_emit_instruction( emit,
+ line_nr++,
+ &parse.FullToken.FullInstruction );
+ if (!ret)
+ goto done;
+ break;
+ default:
+ break;
+ }
+
+ reset_temp_regs( emit );
+ }
+
+ /* Need to terminate the current subroutine. Note that the
+ * hardware doesn't tolerate shaders without sub-routines
+ * terminating with RET+END.
+ */
+ if (!emit->in_main_func) {
+ ret = emit_instruction( emit, inst_token( SVGA3DOP_RET ) );
+ if (!ret)
+ goto done;
+ }
+
+ /* Need to terminate the whole shader:
+ */
+ ret = emit_instruction( emit, inst_token( SVGA3DOP_END ) );
+ if (!ret)
+ goto done;
+
+done:
+ assert(ret);
+ tgsi_parse_free( &parse );
+ return ret;
+}
+
diff --git a/src/gallium/drivers/svga/svga_winsys.h b/src/gallium/drivers/svga/svga_winsys.h
new file mode 100644
index 0000000000..59f299c185
--- /dev/null
+++ b/src/gallium/drivers/svga/svga_winsys.h
@@ -0,0 +1,299 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * VMware SVGA specific winsys interface.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ *
+ * Documentation taken from the VMware SVGA DDK.
+ */
+
+#ifndef SVGA_WINSYS_H_
+#define SVGA_WINSYS_H_
+
+
+#include "svga_types.h"
+#include "svga_reg.h"
+#include "svga3d_reg.h"
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_defines.h"
+
+
+struct svga_winsys_screen;
+struct svga_winsys_buffer;
+struct pipe_screen;
+struct pipe_context;
+struct pipe_fence_handle;
+struct pipe_texture;
+struct svga_region;
+
+
+#define SVGA_BUFFER_USAGE_PINNED (PIPE_BUFFER_USAGE_CUSTOM << 0)
+#define SVGA_BUFFER_USAGE_WRAPPED (PIPE_BUFFER_USAGE_CUSTOM << 1)
+
+
+/** Opaque surface handle */
+struct svga_winsys_surface;
+
+/** Opaque buffer handle */
+struct svga_winsys_handle;
+
+
+/**
+ * SVGA per-context winsys interface.
+ */
+struct svga_winsys_context
+{
+ void
+ (*destroy)(struct svga_winsys_context *swc);
+
+ void *
+ (*reserve)(struct svga_winsys_context *swc,
+ uint32_t nr_bytes, uint32_t nr_relocs );
+
+ /**
+ * Emit a relocation for a host surface.
+ *
+ * @param flags PIPE_BUFFER_USAGE_GPU_READ/WRITE
+ *
+ * NOTE: Order of this call does matter. It should be the same order
+ * as relocations appear in the command buffer.
+ */
+ void
+ (*surface_relocation)(struct svga_winsys_context *swc,
+ uint32 *sid,
+ struct svga_winsys_surface *surface,
+ unsigned flags);
+
+ /**
+ * Emit a relocation for a guest memory region.
+ *
+ * @param flags PIPE_BUFFER_USAGE_GPU_READ/WRITE
+ *
+ * NOTE: Order of this call does matter. It should be the same order
+ * as relocations appear in the command buffer.
+ */
+ void
+ (*region_relocation)(struct svga_winsys_context *swc,
+ struct SVGAGuestPtr *ptr,
+ struct svga_winsys_buffer *buffer,
+ uint32 offset,
+ unsigned flags);
+
+ void
+ (*commit)(struct svga_winsys_context *swc);
+
+ enum pipe_error
+ (*flush)(struct svga_winsys_context *swc,
+ struct pipe_fence_handle **pfence);
+
+ /**
+ * Context ID used to fill in the commands
+ *
+ * Context IDs are arbitrary small non-negative integers,
+ * global to the entire SVGA device.
+ */
+ uint32 cid;
+};
+
+
+/**
+ * SVGA per-screen winsys interface.
+ */
+struct svga_winsys_screen
+{
+ void
+ (*destroy)(struct svga_winsys_screen *sws);
+
+ boolean
+ (*get_cap)(struct svga_winsys_screen *sws,
+ SVGA3dDevCapIndex index,
+ SVGA3dDevCapResult *result);
+
+ /**
+ * Create a new context.
+ *
+ * Context objects encapsulate all render state, and shader
+ * objects are per-context.
+ *
+ * Surfaces are not per-context. The same surface can be shared
+ * between multiple contexts, and surface operations can occur
+ * without a context.
+ */
+ struct svga_winsys_context *
+ (*context_create)(struct svga_winsys_screen *sws);
+
+
+ /**
+ * This creates a "surface" object in the SVGA3D device,
+ * and returns the surface ID (sid). Surfaces are generic
+ * containers for host VRAM objects like textures, vertex
+ * buffers, and depth/stencil buffers.
+ *
+ * Surfaces are hierarchial:
+ *
+ * - Surface may have multiple faces (for cube maps)
+ *
+ * - Each face has a list of mipmap levels
+ *
+ * - Each mipmap image may have multiple volume
+ * slices, if the image is three dimensional.
+ *
+ * - Each slice is a 2D array of 'blocks'
+ *
+ * - Each block may be one or more pixels.
+ * (Usually 1, more for DXT or YUV formats.)
+ *
+ * Surfaces are generic host VRAM objects. The SVGA3D device
+ * may optimize surfaces according to the format they were
+ * created with, but this format does not limit the ways in
+ * which the surface may be used. For example, a depth surface
+ * can be used as a texture, or a floating point image may
+ * be used as a vertex buffer. Some surface usages may be
+ * lower performance, due to software emulation, but any
+ * usage should work with any surface.
+ */
+ struct svga_winsys_surface *
+ (*surface_create)(struct svga_winsys_screen *sws,
+ SVGA3dSurfaceFlags flags,
+ SVGA3dSurfaceFormat format,
+ SVGA3dSize size,
+ uint32 numFaces,
+ uint32 numMipLevels);
+
+ /**
+ * Whether this surface is sitting in a validate list
+ */
+ boolean
+ (*surface_is_flushed)(struct svga_winsys_screen *sws,
+ struct svga_winsys_surface *surface);
+
+ /**
+ * Reference a SVGA3D surface object. This allows sharing of a
+ * surface between different objects.
+ */
+ void
+ (*surface_reference)(struct svga_winsys_screen *sws,
+ struct svga_winsys_surface **pdst,
+ struct svga_winsys_surface *src);
+
+ /**
+ * Buffer management. Buffer attributes are mostly fixed over its lifetime.
+ *
+ * Remember that gallium gets to choose the interface it needs, and the
+ * window systems must then implement that interface (rather than the
+ * other way around...).
+ *
+ * usage is a bitmask of PIPE_BUFFER_USAGE_PIXEL/VERTEX/INDEX/CONSTANT. This
+ * usage argument is only an optimization hint, not a guarantee, therefore
+ * proper behavior must be observed in all circumstances.
+ *
+ * alignment indicates the client's alignment requirements, eg for
+ * SSE instructions.
+ */
+ struct svga_winsys_buffer *
+ (*buffer_create)( struct svga_winsys_screen *sws,
+ unsigned alignment,
+ unsigned usage,
+ unsigned size );
+
+ /**
+ * Map the entire data store of a buffer object into the client's address.
+ * flags is a bitmask of:
+ * - PIPE_BUFFER_USAGE_CPU_READ/WRITE
+ * - PIPE_BUFFER_USAGE_DONTBLOCK
+ * - PIPE_BUFFER_USAGE_UNSYNCHRONIZED
+ */
+ void *
+ (*buffer_map)( struct svga_winsys_screen *sws,
+ struct svga_winsys_buffer *buf,
+ unsigned usage );
+
+ void
+ (*buffer_unmap)( struct svga_winsys_screen *sws,
+ struct svga_winsys_buffer *buf );
+
+ void
+ (*buffer_destroy)( struct svga_winsys_screen *sws,
+ struct svga_winsys_buffer *buf );
+
+
+ /**
+ * Reference a fence object.
+ */
+ void
+ (*fence_reference)( struct svga_winsys_screen *sws,
+ struct pipe_fence_handle **pdst,
+ struct pipe_fence_handle *src );
+
+ /**
+ * Checks whether the fence has been signalled.
+ * \param flags driver-specific meaning
+ * \return zero on success.
+ */
+ int (*fence_signalled)( struct svga_winsys_screen *sws,
+ struct pipe_fence_handle *fence,
+ unsigned flag );
+
+ /**
+ * Wait for the fence to finish.
+ * \param flags driver-specific meaning
+ * \return zero on success.
+ */
+ int (*fence_finish)( struct svga_winsys_screen *sws,
+ struct pipe_fence_handle *fence,
+ unsigned flag );
+
+};
+
+
+struct pipe_context *
+svga_context_create(struct pipe_screen *screen);
+
+struct pipe_screen *
+svga_screen_create(struct svga_winsys_screen *sws);
+
+struct svga_winsys_screen *
+svga_winsys_screen(struct pipe_screen *screen);
+
+struct pipe_buffer *
+svga_screen_buffer_wrap_surface(struct pipe_screen *screen,
+ enum SVGA3dSurfaceFormat format,
+ struct svga_winsys_surface *srf);
+
+struct svga_winsys_surface *
+svga_screen_texture_get_winsys_surface(struct pipe_texture *texture);
+struct svga_winsys_surface *
+svga_screen_buffer_get_winsys_surface(struct pipe_buffer *buffer);
+
+boolean
+svga_screen_buffer_from_texture(struct pipe_texture *texture,
+ struct pipe_buffer **buffer,
+ unsigned *stride);
+
+#endif /* SVGA_WINSYS_H_ */
diff --git a/src/gallium/drivers/svga/svgadump/svga_dump.c b/src/gallium/drivers/svga/svgadump/svga_dump.c
new file mode 100644
index 0000000000..910afa2528
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_dump.c
@@ -0,0 +1,1736 @@
+/**********************************************************
+ * Copyright 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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * Dump SVGA commands.
+ *
+ * Generated automatically from svga3d_reg.h by svga_dump.py.
+ */
+
+#include "svga_types.h"
+#include "svga_shader_dump.h"
+#include "svga3d_reg.h"
+
+#include "util/u_debug.h"
+#include "svga_dump.h"
+
+static void
+dump_SVGA3dVertexDecl(const SVGA3dVertexDecl *cmd)
+{
+ switch((*cmd).identity.type) {
+ case SVGA3D_DECLTYPE_FLOAT1:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT1\n");
+ break;
+ case SVGA3D_DECLTYPE_FLOAT2:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT2\n");
+ break;
+ case SVGA3D_DECLTYPE_FLOAT3:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT3\n");
+ break;
+ case SVGA3D_DECLTYPE_FLOAT4:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT4\n");
+ break;
+ case SVGA3D_DECLTYPE_D3DCOLOR:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_D3DCOLOR\n");
+ break;
+ case SVGA3D_DECLTYPE_UBYTE4:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_UBYTE4\n");
+ break;
+ case SVGA3D_DECLTYPE_SHORT2:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_SHORT2\n");
+ break;
+ case SVGA3D_DECLTYPE_SHORT4:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_SHORT4\n");
+ break;
+ case SVGA3D_DECLTYPE_UBYTE4N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_UBYTE4N\n");
+ break;
+ case SVGA3D_DECLTYPE_SHORT2N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_SHORT2N\n");
+ break;
+ case SVGA3D_DECLTYPE_SHORT4N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_SHORT4N\n");
+ break;
+ case SVGA3D_DECLTYPE_USHORT2N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_USHORT2N\n");
+ break;
+ case SVGA3D_DECLTYPE_USHORT4N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_USHORT4N\n");
+ break;
+ case SVGA3D_DECLTYPE_UDEC3:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_UDEC3\n");
+ break;
+ case SVGA3D_DECLTYPE_DEC3N:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_DEC3N\n");
+ break;
+ case SVGA3D_DECLTYPE_FLOAT16_2:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT16_2\n");
+ break;
+ case SVGA3D_DECLTYPE_FLOAT16_4:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_FLOAT16_4\n");
+ break;
+ case SVGA3D_DECLTYPE_MAX:
+ debug_printf("\t\t.identity.type = SVGA3D_DECLTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.identity.type = %i\n", (*cmd).identity.type);
+ break;
+ }
+ switch((*cmd).identity.method) {
+ case SVGA3D_DECLMETHOD_DEFAULT:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_DEFAULT\n");
+ break;
+ case SVGA3D_DECLMETHOD_PARTIALU:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_PARTIALU\n");
+ break;
+ case SVGA3D_DECLMETHOD_PARTIALV:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_PARTIALV\n");
+ break;
+ case SVGA3D_DECLMETHOD_CROSSUV:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_CROSSUV\n");
+ break;
+ case SVGA3D_DECLMETHOD_UV:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_UV\n");
+ break;
+ case SVGA3D_DECLMETHOD_LOOKUP:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_LOOKUP\n");
+ break;
+ case SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED:
+ debug_printf("\t\t.identity.method = SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED\n");
+ break;
+ default:
+ debug_printf("\t\t.identity.method = %i\n", (*cmd).identity.method);
+ break;
+ }
+ switch((*cmd).identity.usage) {
+ case SVGA3D_DECLUSAGE_POSITION:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_POSITION\n");
+ break;
+ case SVGA3D_DECLUSAGE_BLENDWEIGHT:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_BLENDWEIGHT\n");
+ break;
+ case SVGA3D_DECLUSAGE_BLENDINDICES:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_BLENDINDICES\n");
+ break;
+ case SVGA3D_DECLUSAGE_NORMAL:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_NORMAL\n");
+ break;
+ case SVGA3D_DECLUSAGE_PSIZE:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_PSIZE\n");
+ break;
+ case SVGA3D_DECLUSAGE_TEXCOORD:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_TEXCOORD\n");
+ break;
+ case SVGA3D_DECLUSAGE_TANGENT:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_TANGENT\n");
+ break;
+ case SVGA3D_DECLUSAGE_BINORMAL:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_BINORMAL\n");
+ break;
+ case SVGA3D_DECLUSAGE_TESSFACTOR:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_TESSFACTOR\n");
+ break;
+ case SVGA3D_DECLUSAGE_POSITIONT:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_POSITIONT\n");
+ break;
+ case SVGA3D_DECLUSAGE_COLOR:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_COLOR\n");
+ break;
+ case SVGA3D_DECLUSAGE_FOG:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_FOG\n");
+ break;
+ case SVGA3D_DECLUSAGE_DEPTH:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_DEPTH\n");
+ break;
+ case SVGA3D_DECLUSAGE_SAMPLE:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_SAMPLE\n");
+ break;
+ case SVGA3D_DECLUSAGE_MAX:
+ debug_printf("\t\t.identity.usage = SVGA3D_DECLUSAGE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.identity.usage = %i\n", (*cmd).identity.usage);
+ break;
+ }
+ debug_printf("\t\t.identity.usageIndex = %u\n", (*cmd).identity.usageIndex);
+ debug_printf("\t\t.array.surfaceId = %u\n", (*cmd).array.surfaceId);
+ debug_printf("\t\t.array.offset = %u\n", (*cmd).array.offset);
+ debug_printf("\t\t.array.stride = %u\n", (*cmd).array.stride);
+ debug_printf("\t\t.rangeHint.first = %u\n", (*cmd).rangeHint.first);
+ debug_printf("\t\t.rangeHint.last = %u\n", (*cmd).rangeHint.last);
+}
+
+static void
+dump_SVGA3dTextureState(const SVGA3dTextureState *cmd)
+{
+ debug_printf("\t\t.stage = %u\n", (*cmd).stage);
+ switch((*cmd).name) {
+ case SVGA3D_TS_INVALID:
+ debug_printf("\t\t.name = SVGA3D_TS_INVALID\n");
+ break;
+ case SVGA3D_TS_BIND_TEXTURE:
+ debug_printf("\t\t.name = SVGA3D_TS_BIND_TEXTURE\n");
+ break;
+ case SVGA3D_TS_COLOROP:
+ debug_printf("\t\t.name = SVGA3D_TS_COLOROP\n");
+ break;
+ case SVGA3D_TS_COLORARG1:
+ debug_printf("\t\t.name = SVGA3D_TS_COLORARG1\n");
+ break;
+ case SVGA3D_TS_COLORARG2:
+ debug_printf("\t\t.name = SVGA3D_TS_COLORARG2\n");
+ break;
+ case SVGA3D_TS_ALPHAOP:
+ debug_printf("\t\t.name = SVGA3D_TS_ALPHAOP\n");
+ break;
+ case SVGA3D_TS_ALPHAARG1:
+ debug_printf("\t\t.name = SVGA3D_TS_ALPHAARG1\n");
+ break;
+ case SVGA3D_TS_ALPHAARG2:
+ debug_printf("\t\t.name = SVGA3D_TS_ALPHAARG2\n");
+ break;
+ case SVGA3D_TS_ADDRESSU:
+ debug_printf("\t\t.name = SVGA3D_TS_ADDRESSU\n");
+ break;
+ case SVGA3D_TS_ADDRESSV:
+ debug_printf("\t\t.name = SVGA3D_TS_ADDRESSV\n");
+ break;
+ case SVGA3D_TS_MIPFILTER:
+ debug_printf("\t\t.name = SVGA3D_TS_MIPFILTER\n");
+ break;
+ case SVGA3D_TS_MAGFILTER:
+ debug_printf("\t\t.name = SVGA3D_TS_MAGFILTER\n");
+ break;
+ case SVGA3D_TS_MINFILTER:
+ debug_printf("\t\t.name = SVGA3D_TS_MINFILTER\n");
+ break;
+ case SVGA3D_TS_BORDERCOLOR:
+ debug_printf("\t\t.name = SVGA3D_TS_BORDERCOLOR\n");
+ break;
+ case SVGA3D_TS_TEXCOORDINDEX:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXCOORDINDEX\n");
+ break;
+ case SVGA3D_TS_TEXTURETRANSFORMFLAGS:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXTURETRANSFORMFLAGS\n");
+ break;
+ case SVGA3D_TS_TEXCOORDGEN:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXCOORDGEN\n");
+ break;
+ case SVGA3D_TS_BUMPENVMAT00:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVMAT00\n");
+ break;
+ case SVGA3D_TS_BUMPENVMAT01:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVMAT01\n");
+ break;
+ case SVGA3D_TS_BUMPENVMAT10:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVMAT10\n");
+ break;
+ case SVGA3D_TS_BUMPENVMAT11:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVMAT11\n");
+ break;
+ case SVGA3D_TS_TEXTURE_MIPMAP_LEVEL:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXTURE_MIPMAP_LEVEL\n");
+ break;
+ case SVGA3D_TS_TEXTURE_LOD_BIAS:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXTURE_LOD_BIAS\n");
+ break;
+ case SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL:
+ debug_printf("\t\t.name = SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL\n");
+ break;
+ case SVGA3D_TS_ADDRESSW:
+ debug_printf("\t\t.name = SVGA3D_TS_ADDRESSW\n");
+ break;
+ case SVGA3D_TS_GAMMA:
+ debug_printf("\t\t.name = SVGA3D_TS_GAMMA\n");
+ break;
+ case SVGA3D_TS_BUMPENVLSCALE:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVLSCALE\n");
+ break;
+ case SVGA3D_TS_BUMPENVLOFFSET:
+ debug_printf("\t\t.name = SVGA3D_TS_BUMPENVLOFFSET\n");
+ break;
+ case SVGA3D_TS_COLORARG0:
+ debug_printf("\t\t.name = SVGA3D_TS_COLORARG0\n");
+ break;
+ case SVGA3D_TS_ALPHAARG0:
+ debug_printf("\t\t.name = SVGA3D_TS_ALPHAARG0\n");
+ break;
+ case SVGA3D_TS_MAX:
+ debug_printf("\t\t.name = SVGA3D_TS_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.name = %i\n", (*cmd).name);
+ break;
+ }
+ debug_printf("\t\t.value = %u\n", (*cmd).value);
+ debug_printf("\t\t.floatValue = %f\n", (*cmd).floatValue);
+}
+
+static void
+dump_SVGA3dCopyBox(const SVGA3dCopyBox *cmd)
+{
+ debug_printf("\t\t.x = %u\n", (*cmd).x);
+ debug_printf("\t\t.y = %u\n", (*cmd).y);
+ debug_printf("\t\t.z = %u\n", (*cmd).z);
+ debug_printf("\t\t.w = %u\n", (*cmd).w);
+ debug_printf("\t\t.h = %u\n", (*cmd).h);
+ debug_printf("\t\t.d = %u\n", (*cmd).d);
+ debug_printf("\t\t.srcx = %u\n", (*cmd).srcx);
+ debug_printf("\t\t.srcy = %u\n", (*cmd).srcy);
+ debug_printf("\t\t.srcz = %u\n", (*cmd).srcz);
+}
+
+static void
+dump_SVGA3dCmdSetClipPlane(const SVGA3dCmdSetClipPlane *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.index = %u\n", (*cmd).index);
+ debug_printf("\t\t.plane[0] = %f\n", (*cmd).plane[0]);
+ debug_printf("\t\t.plane[1] = %f\n", (*cmd).plane[1]);
+ debug_printf("\t\t.plane[2] = %f\n", (*cmd).plane[2]);
+ debug_printf("\t\t.plane[3] = %f\n", (*cmd).plane[3]);
+}
+
+static void
+dump_SVGA3dCmdWaitForQuery(const SVGA3dCmdWaitForQuery *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_QUERYTYPE_OCCLUSION:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_OCCLUSION\n");
+ break;
+ case SVGA3D_QUERYTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+ debug_printf("\t\t.guestResult.gmrId = %u\n", (*cmd).guestResult.gmrId);
+ debug_printf("\t\t.guestResult.offset = %u\n", (*cmd).guestResult.offset);
+}
+
+static void
+dump_SVGA3dCmdSetRenderTarget(const SVGA3dCmdSetRenderTarget *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_RT_DEPTH:
+ debug_printf("\t\t.type = SVGA3D_RT_DEPTH\n");
+ break;
+ case SVGA3D_RT_STENCIL:
+ debug_printf("\t\t.type = SVGA3D_RT_STENCIL\n");
+ break;
+ default:
+ debug_printf("\t\t.type = SVGA3D_RT_COLOR%u\n", (*cmd).type - SVGA3D_RT_COLOR0);
+ break;
+ }
+ debug_printf("\t\t.target.sid = %u\n", (*cmd).target.sid);
+ debug_printf("\t\t.target.face = %u\n", (*cmd).target.face);
+ debug_printf("\t\t.target.mipmap = %u\n", (*cmd).target.mipmap);
+}
+
+static void
+dump_SVGA3dCmdSetTextureState(const SVGA3dCmdSetTextureState *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+}
+
+static void
+dump_SVGA3dCmdSurfaceCopy(const SVGA3dCmdSurfaceCopy *cmd)
+{
+ debug_printf("\t\t.src.sid = %u\n", (*cmd).src.sid);
+ debug_printf("\t\t.src.face = %u\n", (*cmd).src.face);
+ debug_printf("\t\t.src.mipmap = %u\n", (*cmd).src.mipmap);
+ debug_printf("\t\t.dest.sid = %u\n", (*cmd).dest.sid);
+ debug_printf("\t\t.dest.face = %u\n", (*cmd).dest.face);
+ debug_printf("\t\t.dest.mipmap = %u\n", (*cmd).dest.mipmap);
+}
+
+static void
+dump_SVGA3dCmdSetMaterial(const SVGA3dCmdSetMaterial *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).face) {
+ case SVGA3D_FACE_INVALID:
+ debug_printf("\t\t.face = SVGA3D_FACE_INVALID\n");
+ break;
+ case SVGA3D_FACE_NONE:
+ debug_printf("\t\t.face = SVGA3D_FACE_NONE\n");
+ break;
+ case SVGA3D_FACE_FRONT:
+ debug_printf("\t\t.face = SVGA3D_FACE_FRONT\n");
+ break;
+ case SVGA3D_FACE_BACK:
+ debug_printf("\t\t.face = SVGA3D_FACE_BACK\n");
+ break;
+ case SVGA3D_FACE_FRONT_BACK:
+ debug_printf("\t\t.face = SVGA3D_FACE_FRONT_BACK\n");
+ break;
+ case SVGA3D_FACE_MAX:
+ debug_printf("\t\t.face = SVGA3D_FACE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.face = %i\n", (*cmd).face);
+ break;
+ }
+ debug_printf("\t\t.material.diffuse[0] = %f\n", (*cmd).material.diffuse[0]);
+ debug_printf("\t\t.material.diffuse[1] = %f\n", (*cmd).material.diffuse[1]);
+ debug_printf("\t\t.material.diffuse[2] = %f\n", (*cmd).material.diffuse[2]);
+ debug_printf("\t\t.material.diffuse[3] = %f\n", (*cmd).material.diffuse[3]);
+ debug_printf("\t\t.material.ambient[0] = %f\n", (*cmd).material.ambient[0]);
+ debug_printf("\t\t.material.ambient[1] = %f\n", (*cmd).material.ambient[1]);
+ debug_printf("\t\t.material.ambient[2] = %f\n", (*cmd).material.ambient[2]);
+ debug_printf("\t\t.material.ambient[3] = %f\n", (*cmd).material.ambient[3]);
+ debug_printf("\t\t.material.specular[0] = %f\n", (*cmd).material.specular[0]);
+ debug_printf("\t\t.material.specular[1] = %f\n", (*cmd).material.specular[1]);
+ debug_printf("\t\t.material.specular[2] = %f\n", (*cmd).material.specular[2]);
+ debug_printf("\t\t.material.specular[3] = %f\n", (*cmd).material.specular[3]);
+ debug_printf("\t\t.material.emissive[0] = %f\n", (*cmd).material.emissive[0]);
+ debug_printf("\t\t.material.emissive[1] = %f\n", (*cmd).material.emissive[1]);
+ debug_printf("\t\t.material.emissive[2] = %f\n", (*cmd).material.emissive[2]);
+ debug_printf("\t\t.material.emissive[3] = %f\n", (*cmd).material.emissive[3]);
+ debug_printf("\t\t.material.shininess = %f\n", (*cmd).material.shininess);
+}
+
+static void
+dump_SVGA3dCmdSetLightData(const SVGA3dCmdSetLightData *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.index = %u\n", (*cmd).index);
+ switch((*cmd).data.type) {
+ case SVGA3D_LIGHTTYPE_INVALID:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_INVALID\n");
+ break;
+ case SVGA3D_LIGHTTYPE_POINT:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_POINT\n");
+ break;
+ case SVGA3D_LIGHTTYPE_SPOT1:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_SPOT1\n");
+ break;
+ case SVGA3D_LIGHTTYPE_SPOT2:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_SPOT2\n");
+ break;
+ case SVGA3D_LIGHTTYPE_DIRECTIONAL:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_DIRECTIONAL\n");
+ break;
+ case SVGA3D_LIGHTTYPE_MAX:
+ debug_printf("\t\t.data.type = SVGA3D_LIGHTTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.data.type = %i\n", (*cmd).data.type);
+ break;
+ }
+ debug_printf("\t\t.data.inWorldSpace = %u\n", (*cmd).data.inWorldSpace);
+ debug_printf("\t\t.data.diffuse[0] = %f\n", (*cmd).data.diffuse[0]);
+ debug_printf("\t\t.data.diffuse[1] = %f\n", (*cmd).data.diffuse[1]);
+ debug_printf("\t\t.data.diffuse[2] = %f\n", (*cmd).data.diffuse[2]);
+ debug_printf("\t\t.data.diffuse[3] = %f\n", (*cmd).data.diffuse[3]);
+ debug_printf("\t\t.data.specular[0] = %f\n", (*cmd).data.specular[0]);
+ debug_printf("\t\t.data.specular[1] = %f\n", (*cmd).data.specular[1]);
+ debug_printf("\t\t.data.specular[2] = %f\n", (*cmd).data.specular[2]);
+ debug_printf("\t\t.data.specular[3] = %f\n", (*cmd).data.specular[3]);
+ debug_printf("\t\t.data.ambient[0] = %f\n", (*cmd).data.ambient[0]);
+ debug_printf("\t\t.data.ambient[1] = %f\n", (*cmd).data.ambient[1]);
+ debug_printf("\t\t.data.ambient[2] = %f\n", (*cmd).data.ambient[2]);
+ debug_printf("\t\t.data.ambient[3] = %f\n", (*cmd).data.ambient[3]);
+ debug_printf("\t\t.data.position[0] = %f\n", (*cmd).data.position[0]);
+ debug_printf("\t\t.data.position[1] = %f\n", (*cmd).data.position[1]);
+ debug_printf("\t\t.data.position[2] = %f\n", (*cmd).data.position[2]);
+ debug_printf("\t\t.data.position[3] = %f\n", (*cmd).data.position[3]);
+ debug_printf("\t\t.data.direction[0] = %f\n", (*cmd).data.direction[0]);
+ debug_printf("\t\t.data.direction[1] = %f\n", (*cmd).data.direction[1]);
+ debug_printf("\t\t.data.direction[2] = %f\n", (*cmd).data.direction[2]);
+ debug_printf("\t\t.data.direction[3] = %f\n", (*cmd).data.direction[3]);
+ debug_printf("\t\t.data.range = %f\n", (*cmd).data.range);
+ debug_printf("\t\t.data.falloff = %f\n", (*cmd).data.falloff);
+ debug_printf("\t\t.data.attenuation0 = %f\n", (*cmd).data.attenuation0);
+ debug_printf("\t\t.data.attenuation1 = %f\n", (*cmd).data.attenuation1);
+ debug_printf("\t\t.data.attenuation2 = %f\n", (*cmd).data.attenuation2);
+ debug_printf("\t\t.data.theta = %f\n", (*cmd).data.theta);
+ debug_printf("\t\t.data.phi = %f\n", (*cmd).data.phi);
+}
+
+static void
+dump_SVGA3dCmdSetViewport(const SVGA3dCmdSetViewport *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.rect.x = %u\n", (*cmd).rect.x);
+ debug_printf("\t\t.rect.y = %u\n", (*cmd).rect.y);
+ debug_printf("\t\t.rect.w = %u\n", (*cmd).rect.w);
+ debug_printf("\t\t.rect.h = %u\n", (*cmd).rect.h);
+}
+
+static void
+dump_SVGA3dCmdSetScissorRect(const SVGA3dCmdSetScissorRect *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.rect.x = %u\n", (*cmd).rect.x);
+ debug_printf("\t\t.rect.y = %u\n", (*cmd).rect.y);
+ debug_printf("\t\t.rect.w = %u\n", (*cmd).rect.w);
+ debug_printf("\t\t.rect.h = %u\n", (*cmd).rect.h);
+}
+
+static void
+dump_SVGA3dCopyRect(const SVGA3dCopyRect *cmd)
+{
+ debug_printf("\t\t.x = %u\n", (*cmd).x);
+ debug_printf("\t\t.y = %u\n", (*cmd).y);
+ debug_printf("\t\t.w = %u\n", (*cmd).w);
+ debug_printf("\t\t.h = %u\n", (*cmd).h);
+ debug_printf("\t\t.srcx = %u\n", (*cmd).srcx);
+ debug_printf("\t\t.srcy = %u\n", (*cmd).srcy);
+}
+
+static void
+dump_SVGA3dCmdSetShader(const SVGA3dCmdSetShader *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_SHADERTYPE_COMPILED_DX8:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_COMPILED_DX8\n");
+ break;
+ case SVGA3D_SHADERTYPE_VS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_VS\n");
+ break;
+ case SVGA3D_SHADERTYPE_PS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_PS\n");
+ break;
+ case SVGA3D_SHADERTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+ debug_printf("\t\t.shid = %u\n", (*cmd).shid);
+}
+
+static void
+dump_SVGA3dCmdEndQuery(const SVGA3dCmdEndQuery *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_QUERYTYPE_OCCLUSION:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_OCCLUSION\n");
+ break;
+ case SVGA3D_QUERYTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+ debug_printf("\t\t.guestResult.gmrId = %u\n", (*cmd).guestResult.gmrId);
+ debug_printf("\t\t.guestResult.offset = %u\n", (*cmd).guestResult.offset);
+}
+
+static void
+dump_SVGA3dSize(const SVGA3dSize *cmd)
+{
+ debug_printf("\t\t.width = %u\n", (*cmd).width);
+ debug_printf("\t\t.height = %u\n", (*cmd).height);
+ debug_printf("\t\t.depth = %u\n", (*cmd).depth);
+}
+
+static void
+dump_SVGA3dCmdDestroySurface(const SVGA3dCmdDestroySurface *cmd)
+{
+ debug_printf("\t\t.sid = %u\n", (*cmd).sid);
+}
+
+static void
+dump_SVGA3dCmdDefineContext(const SVGA3dCmdDefineContext *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+}
+
+static void
+dump_SVGA3dRect(const SVGA3dRect *cmd)
+{
+ debug_printf("\t\t.x = %u\n", (*cmd).x);
+ debug_printf("\t\t.y = %u\n", (*cmd).y);
+ debug_printf("\t\t.w = %u\n", (*cmd).w);
+ debug_printf("\t\t.h = %u\n", (*cmd).h);
+}
+
+static void
+dump_SVGA3dCmdBeginQuery(const SVGA3dCmdBeginQuery *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_QUERYTYPE_OCCLUSION:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_OCCLUSION\n");
+ break;
+ case SVGA3D_QUERYTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_QUERYTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dRenderState(const SVGA3dRenderState *cmd)
+{
+ switch((*cmd).state) {
+ case SVGA3D_RS_INVALID:
+ debug_printf("\t\t.state = SVGA3D_RS_INVALID\n");
+ break;
+ case SVGA3D_RS_ZENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_ZENABLE\n");
+ break;
+ case SVGA3D_RS_ZWRITEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_ZWRITEENABLE\n");
+ break;
+ case SVGA3D_RS_ALPHATESTENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_ALPHATESTENABLE\n");
+ break;
+ case SVGA3D_RS_DITHERENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_DITHERENABLE\n");
+ break;
+ case SVGA3D_RS_BLENDENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_BLENDENABLE\n");
+ break;
+ case SVGA3D_RS_FOGENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGENABLE\n");
+ break;
+ case SVGA3D_RS_SPECULARENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_SPECULARENABLE\n");
+ break;
+ case SVGA3D_RS_STENCILENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILENABLE\n");
+ break;
+ case SVGA3D_RS_LIGHTINGENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_LIGHTINGENABLE\n");
+ break;
+ case SVGA3D_RS_NORMALIZENORMALS:
+ debug_printf("\t\t.state = SVGA3D_RS_NORMALIZENORMALS\n");
+ break;
+ case SVGA3D_RS_POINTSPRITEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSPRITEENABLE\n");
+ break;
+ case SVGA3D_RS_POINTSCALEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSCALEENABLE\n");
+ break;
+ case SVGA3D_RS_STENCILREF:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILREF\n");
+ break;
+ case SVGA3D_RS_STENCILMASK:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILMASK\n");
+ break;
+ case SVGA3D_RS_STENCILWRITEMASK:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILWRITEMASK\n");
+ break;
+ case SVGA3D_RS_FOGSTART:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGSTART\n");
+ break;
+ case SVGA3D_RS_FOGEND:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGEND\n");
+ break;
+ case SVGA3D_RS_FOGDENSITY:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGDENSITY\n");
+ break;
+ case SVGA3D_RS_POINTSIZE:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSIZE\n");
+ break;
+ case SVGA3D_RS_POINTSIZEMIN:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSIZEMIN\n");
+ break;
+ case SVGA3D_RS_POINTSIZEMAX:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSIZEMAX\n");
+ break;
+ case SVGA3D_RS_POINTSCALE_A:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSCALE_A\n");
+ break;
+ case SVGA3D_RS_POINTSCALE_B:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSCALE_B\n");
+ break;
+ case SVGA3D_RS_POINTSCALE_C:
+ debug_printf("\t\t.state = SVGA3D_RS_POINTSCALE_C\n");
+ break;
+ case SVGA3D_RS_FOGCOLOR:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGCOLOR\n");
+ break;
+ case SVGA3D_RS_AMBIENT:
+ debug_printf("\t\t.state = SVGA3D_RS_AMBIENT\n");
+ break;
+ case SVGA3D_RS_CLIPPLANEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_CLIPPLANEENABLE\n");
+ break;
+ case SVGA3D_RS_FOGMODE:
+ debug_printf("\t\t.state = SVGA3D_RS_FOGMODE\n");
+ break;
+ case SVGA3D_RS_FILLMODE:
+ debug_printf("\t\t.state = SVGA3D_RS_FILLMODE\n");
+ break;
+ case SVGA3D_RS_SHADEMODE:
+ debug_printf("\t\t.state = SVGA3D_RS_SHADEMODE\n");
+ break;
+ case SVGA3D_RS_LINEPATTERN:
+ debug_printf("\t\t.state = SVGA3D_RS_LINEPATTERN\n");
+ break;
+ case SVGA3D_RS_SRCBLEND:
+ debug_printf("\t\t.state = SVGA3D_RS_SRCBLEND\n");
+ break;
+ case SVGA3D_RS_DSTBLEND:
+ debug_printf("\t\t.state = SVGA3D_RS_DSTBLEND\n");
+ break;
+ case SVGA3D_RS_BLENDEQUATION:
+ debug_printf("\t\t.state = SVGA3D_RS_BLENDEQUATION\n");
+ break;
+ case SVGA3D_RS_CULLMODE:
+ debug_printf("\t\t.state = SVGA3D_RS_CULLMODE\n");
+ break;
+ case SVGA3D_RS_ZFUNC:
+ debug_printf("\t\t.state = SVGA3D_RS_ZFUNC\n");
+ break;
+ case SVGA3D_RS_ALPHAFUNC:
+ debug_printf("\t\t.state = SVGA3D_RS_ALPHAFUNC\n");
+ break;
+ case SVGA3D_RS_STENCILFUNC:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILFUNC\n");
+ break;
+ case SVGA3D_RS_STENCILFAIL:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILFAIL\n");
+ break;
+ case SVGA3D_RS_STENCILZFAIL:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILZFAIL\n");
+ break;
+ case SVGA3D_RS_STENCILPASS:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILPASS\n");
+ break;
+ case SVGA3D_RS_ALPHAREF:
+ debug_printf("\t\t.state = SVGA3D_RS_ALPHAREF\n");
+ break;
+ case SVGA3D_RS_FRONTWINDING:
+ debug_printf("\t\t.state = SVGA3D_RS_FRONTWINDING\n");
+ break;
+ case SVGA3D_RS_COORDINATETYPE:
+ debug_printf("\t\t.state = SVGA3D_RS_COORDINATETYPE\n");
+ break;
+ case SVGA3D_RS_ZBIAS:
+ debug_printf("\t\t.state = SVGA3D_RS_ZBIAS\n");
+ break;
+ case SVGA3D_RS_RANGEFOGENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_RANGEFOGENABLE\n");
+ break;
+ case SVGA3D_RS_COLORWRITEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_COLORWRITEENABLE\n");
+ break;
+ case SVGA3D_RS_VERTEXMATERIALENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_VERTEXMATERIALENABLE\n");
+ break;
+ case SVGA3D_RS_DIFFUSEMATERIALSOURCE:
+ debug_printf("\t\t.state = SVGA3D_RS_DIFFUSEMATERIALSOURCE\n");
+ break;
+ case SVGA3D_RS_SPECULARMATERIALSOURCE:
+ debug_printf("\t\t.state = SVGA3D_RS_SPECULARMATERIALSOURCE\n");
+ break;
+ case SVGA3D_RS_AMBIENTMATERIALSOURCE:
+ debug_printf("\t\t.state = SVGA3D_RS_AMBIENTMATERIALSOURCE\n");
+ break;
+ case SVGA3D_RS_EMISSIVEMATERIALSOURCE:
+ debug_printf("\t\t.state = SVGA3D_RS_EMISSIVEMATERIALSOURCE\n");
+ break;
+ case SVGA3D_RS_TEXTUREFACTOR:
+ debug_printf("\t\t.state = SVGA3D_RS_TEXTUREFACTOR\n");
+ break;
+ case SVGA3D_RS_LOCALVIEWER:
+ debug_printf("\t\t.state = SVGA3D_RS_LOCALVIEWER\n");
+ break;
+ case SVGA3D_RS_SCISSORTESTENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_SCISSORTESTENABLE\n");
+ break;
+ case SVGA3D_RS_BLENDCOLOR:
+ debug_printf("\t\t.state = SVGA3D_RS_BLENDCOLOR\n");
+ break;
+ case SVGA3D_RS_STENCILENABLE2SIDED:
+ debug_printf("\t\t.state = SVGA3D_RS_STENCILENABLE2SIDED\n");
+ break;
+ case SVGA3D_RS_CCWSTENCILFUNC:
+ debug_printf("\t\t.state = SVGA3D_RS_CCWSTENCILFUNC\n");
+ break;
+ case SVGA3D_RS_CCWSTENCILFAIL:
+ debug_printf("\t\t.state = SVGA3D_RS_CCWSTENCILFAIL\n");
+ break;
+ case SVGA3D_RS_CCWSTENCILZFAIL:
+ debug_printf("\t\t.state = SVGA3D_RS_CCWSTENCILZFAIL\n");
+ break;
+ case SVGA3D_RS_CCWSTENCILPASS:
+ debug_printf("\t\t.state = SVGA3D_RS_CCWSTENCILPASS\n");
+ break;
+ case SVGA3D_RS_VERTEXBLEND:
+ debug_printf("\t\t.state = SVGA3D_RS_VERTEXBLEND\n");
+ break;
+ case SVGA3D_RS_SLOPESCALEDEPTHBIAS:
+ debug_printf("\t\t.state = SVGA3D_RS_SLOPESCALEDEPTHBIAS\n");
+ break;
+ case SVGA3D_RS_DEPTHBIAS:
+ debug_printf("\t\t.state = SVGA3D_RS_DEPTHBIAS\n");
+ break;
+ case SVGA3D_RS_OUTPUTGAMMA:
+ debug_printf("\t\t.state = SVGA3D_RS_OUTPUTGAMMA\n");
+ break;
+ case SVGA3D_RS_ZVISIBLE:
+ debug_printf("\t\t.state = SVGA3D_RS_ZVISIBLE\n");
+ break;
+ case SVGA3D_RS_LASTPIXEL:
+ debug_printf("\t\t.state = SVGA3D_RS_LASTPIXEL\n");
+ break;
+ case SVGA3D_RS_CLIPPING:
+ debug_printf("\t\t.state = SVGA3D_RS_CLIPPING\n");
+ break;
+ case SVGA3D_RS_WRAP0:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP0\n");
+ break;
+ case SVGA3D_RS_WRAP1:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP1\n");
+ break;
+ case SVGA3D_RS_WRAP2:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP2\n");
+ break;
+ case SVGA3D_RS_WRAP3:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP3\n");
+ break;
+ case SVGA3D_RS_WRAP4:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP4\n");
+ break;
+ case SVGA3D_RS_WRAP5:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP5\n");
+ break;
+ case SVGA3D_RS_WRAP6:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP6\n");
+ break;
+ case SVGA3D_RS_WRAP7:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP7\n");
+ break;
+ case SVGA3D_RS_WRAP8:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP8\n");
+ break;
+ case SVGA3D_RS_WRAP9:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP9\n");
+ break;
+ case SVGA3D_RS_WRAP10:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP10\n");
+ break;
+ case SVGA3D_RS_WRAP11:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP11\n");
+ break;
+ case SVGA3D_RS_WRAP12:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP12\n");
+ break;
+ case SVGA3D_RS_WRAP13:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP13\n");
+ break;
+ case SVGA3D_RS_WRAP14:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP14\n");
+ break;
+ case SVGA3D_RS_WRAP15:
+ debug_printf("\t\t.state = SVGA3D_RS_WRAP15\n");
+ break;
+ case SVGA3D_RS_MULTISAMPLEANTIALIAS:
+ debug_printf("\t\t.state = SVGA3D_RS_MULTISAMPLEANTIALIAS\n");
+ break;
+ case SVGA3D_RS_MULTISAMPLEMASK:
+ debug_printf("\t\t.state = SVGA3D_RS_MULTISAMPLEMASK\n");
+ break;
+ case SVGA3D_RS_INDEXEDVERTEXBLENDENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_INDEXEDVERTEXBLENDENABLE\n");
+ break;
+ case SVGA3D_RS_TWEENFACTOR:
+ debug_printf("\t\t.state = SVGA3D_RS_TWEENFACTOR\n");
+ break;
+ case SVGA3D_RS_ANTIALIASEDLINEENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_ANTIALIASEDLINEENABLE\n");
+ break;
+ case SVGA3D_RS_COLORWRITEENABLE1:
+ debug_printf("\t\t.state = SVGA3D_RS_COLORWRITEENABLE1\n");
+ break;
+ case SVGA3D_RS_COLORWRITEENABLE2:
+ debug_printf("\t\t.state = SVGA3D_RS_COLORWRITEENABLE2\n");
+ break;
+ case SVGA3D_RS_COLORWRITEENABLE3:
+ debug_printf("\t\t.state = SVGA3D_RS_COLORWRITEENABLE3\n");
+ break;
+ case SVGA3D_RS_SEPARATEALPHABLENDENABLE:
+ debug_printf("\t\t.state = SVGA3D_RS_SEPARATEALPHABLENDENABLE\n");
+ break;
+ case SVGA3D_RS_SRCBLENDALPHA:
+ debug_printf("\t\t.state = SVGA3D_RS_SRCBLENDALPHA\n");
+ break;
+ case SVGA3D_RS_DSTBLENDALPHA:
+ debug_printf("\t\t.state = SVGA3D_RS_DSTBLENDALPHA\n");
+ break;
+ case SVGA3D_RS_BLENDEQUATIONALPHA:
+ debug_printf("\t\t.state = SVGA3D_RS_BLENDEQUATIONALPHA\n");
+ break;
+ case SVGA3D_RS_MAX:
+ debug_printf("\t\t.state = SVGA3D_RS_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.state = %i\n", (*cmd).state);
+ break;
+ }
+ debug_printf("\t\t.uintValue = %u\n", (*cmd).uintValue);
+ debug_printf("\t\t.floatValue = %f\n", (*cmd).floatValue);
+}
+
+static void
+dump_SVGA3dVertexDivisor(const SVGA3dVertexDivisor *cmd)
+{
+ debug_printf("\t\t.value = %u\n", (*cmd).value);
+ debug_printf("\t\t.count = %u\n", (*cmd).count);
+ debug_printf("\t\t.indexedData = %u\n", (*cmd).indexedData);
+ debug_printf("\t\t.instanceData = %u\n", (*cmd).instanceData);
+}
+
+static void
+dump_SVGA3dCmdDefineShader(const SVGA3dCmdDefineShader *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.shid = %u\n", (*cmd).shid);
+ switch((*cmd).type) {
+ case SVGA3D_SHADERTYPE_COMPILED_DX8:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_COMPILED_DX8\n");
+ break;
+ case SVGA3D_SHADERTYPE_VS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_VS\n");
+ break;
+ case SVGA3D_SHADERTYPE_PS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_PS\n");
+ break;
+ case SVGA3D_SHADERTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dCmdSetShaderConst(const SVGA3dCmdSetShaderConst *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.reg = %u\n", (*cmd).reg);
+ switch((*cmd).type) {
+ case SVGA3D_SHADERTYPE_COMPILED_DX8:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_COMPILED_DX8\n");
+ break;
+ case SVGA3D_SHADERTYPE_VS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_VS\n");
+ break;
+ case SVGA3D_SHADERTYPE_PS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_PS\n");
+ break;
+ case SVGA3D_SHADERTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+ switch((*cmd).ctype) {
+ case SVGA3D_CONST_TYPE_FLOAT:
+ debug_printf("\t\t.ctype = SVGA3D_CONST_TYPE_FLOAT\n");
+ debug_printf("\t\t.values[0] = %f\n", *(const float *)&(*cmd).values[0]);
+ debug_printf("\t\t.values[1] = %f\n", *(const float *)&(*cmd).values[1]);
+ debug_printf("\t\t.values[2] = %f\n", *(const float *)&(*cmd).values[2]);
+ debug_printf("\t\t.values[3] = %f\n", *(const float *)&(*cmd).values[3]);
+ break;
+ case SVGA3D_CONST_TYPE_INT:
+ debug_printf("\t\t.ctype = SVGA3D_CONST_TYPE_INT\n");
+ debug_printf("\t\t.values[0] = %u\n", (*cmd).values[0]);
+ debug_printf("\t\t.values[1] = %u\n", (*cmd).values[1]);
+ debug_printf("\t\t.values[2] = %u\n", (*cmd).values[2]);
+ debug_printf("\t\t.values[3] = %u\n", (*cmd).values[3]);
+ break;
+ case SVGA3D_CONST_TYPE_BOOL:
+ debug_printf("\t\t.ctype = SVGA3D_CONST_TYPE_BOOL\n");
+ debug_printf("\t\t.values[0] = %u\n", (*cmd).values[0]);
+ debug_printf("\t\t.values[1] = %u\n", (*cmd).values[1]);
+ debug_printf("\t\t.values[2] = %u\n", (*cmd).values[2]);
+ debug_printf("\t\t.values[3] = %u\n", (*cmd).values[3]);
+ break;
+ default:
+ debug_printf("\t\t.ctype = %i\n", (*cmd).ctype);
+ debug_printf("\t\t.values[0] = %u\n", (*cmd).values[0]);
+ debug_printf("\t\t.values[1] = %u\n", (*cmd).values[1]);
+ debug_printf("\t\t.values[2] = %u\n", (*cmd).values[2]);
+ debug_printf("\t\t.values[3] = %u\n", (*cmd).values[3]);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dCmdSetZRange(const SVGA3dCmdSetZRange *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.zRange.min = %f\n", (*cmd).zRange.min);
+ debug_printf("\t\t.zRange.max = %f\n", (*cmd).zRange.max);
+}
+
+static void
+dump_SVGA3dCmdDrawPrimitives(const SVGA3dCmdDrawPrimitives *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.numVertexDecls = %u\n", (*cmd).numVertexDecls);
+ debug_printf("\t\t.numRanges = %u\n", (*cmd).numRanges);
+}
+
+static void
+dump_SVGA3dCmdSetLightEnabled(const SVGA3dCmdSetLightEnabled *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.index = %u\n", (*cmd).index);
+ debug_printf("\t\t.enabled = %u\n", (*cmd).enabled);
+}
+
+static void
+dump_SVGA3dPrimitiveRange(const SVGA3dPrimitiveRange *cmd)
+{
+ switch((*cmd).primType) {
+ case SVGA3D_PRIMITIVE_INVALID:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_INVALID\n");
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLELIST:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_TRIANGLELIST\n");
+ break;
+ case SVGA3D_PRIMITIVE_POINTLIST:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_POINTLIST\n");
+ break;
+ case SVGA3D_PRIMITIVE_LINELIST:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_LINELIST\n");
+ break;
+ case SVGA3D_PRIMITIVE_LINESTRIP:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_LINESTRIP\n");
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLESTRIP:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_TRIANGLESTRIP\n");
+ break;
+ case SVGA3D_PRIMITIVE_TRIANGLEFAN:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_TRIANGLEFAN\n");
+ break;
+ case SVGA3D_PRIMITIVE_MAX:
+ debug_printf("\t\t.primType = SVGA3D_PRIMITIVE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.primType = %i\n", (*cmd).primType);
+ break;
+ }
+ debug_printf("\t\t.primitiveCount = %u\n", (*cmd).primitiveCount);
+ debug_printf("\t\t.indexArray.surfaceId = %u\n", (*cmd).indexArray.surfaceId);
+ debug_printf("\t\t.indexArray.offset = %u\n", (*cmd).indexArray.offset);
+ debug_printf("\t\t.indexArray.stride = %u\n", (*cmd).indexArray.stride);
+ debug_printf("\t\t.indexWidth = %u\n", (*cmd).indexWidth);
+ debug_printf("\t\t.indexBias = %i\n", (*cmd).indexBias);
+}
+
+static void
+dump_SVGA3dCmdPresent(const SVGA3dCmdPresent *cmd)
+{
+ debug_printf("\t\t.sid = %u\n", (*cmd).sid);
+}
+
+static void
+dump_SVGA3dCmdSetRenderState(const SVGA3dCmdSetRenderState *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+}
+
+static void
+dump_SVGA3dCmdSurfaceStretchBlt(const SVGA3dCmdSurfaceStretchBlt *cmd)
+{
+ debug_printf("\t\t.src.sid = %u\n", (*cmd).src.sid);
+ debug_printf("\t\t.src.face = %u\n", (*cmd).src.face);
+ debug_printf("\t\t.src.mipmap = %u\n", (*cmd).src.mipmap);
+ debug_printf("\t\t.dest.sid = %u\n", (*cmd).dest.sid);
+ debug_printf("\t\t.dest.face = %u\n", (*cmd).dest.face);
+ debug_printf("\t\t.dest.mipmap = %u\n", (*cmd).dest.mipmap);
+ debug_printf("\t\t.boxSrc.x = %u\n", (*cmd).boxSrc.x);
+ debug_printf("\t\t.boxSrc.y = %u\n", (*cmd).boxSrc.y);
+ debug_printf("\t\t.boxSrc.z = %u\n", (*cmd).boxSrc.z);
+ debug_printf("\t\t.boxSrc.w = %u\n", (*cmd).boxSrc.w);
+ debug_printf("\t\t.boxSrc.h = %u\n", (*cmd).boxSrc.h);
+ debug_printf("\t\t.boxSrc.d = %u\n", (*cmd).boxSrc.d);
+ debug_printf("\t\t.boxDest.x = %u\n", (*cmd).boxDest.x);
+ debug_printf("\t\t.boxDest.y = %u\n", (*cmd).boxDest.y);
+ debug_printf("\t\t.boxDest.z = %u\n", (*cmd).boxDest.z);
+ debug_printf("\t\t.boxDest.w = %u\n", (*cmd).boxDest.w);
+ debug_printf("\t\t.boxDest.h = %u\n", (*cmd).boxDest.h);
+ debug_printf("\t\t.boxDest.d = %u\n", (*cmd).boxDest.d);
+ switch((*cmd).mode) {
+ case SVGA3D_STRETCH_BLT_POINT:
+ debug_printf("\t\t.mode = SVGA3D_STRETCH_BLT_POINT\n");
+ break;
+ case SVGA3D_STRETCH_BLT_LINEAR:
+ debug_printf("\t\t.mode = SVGA3D_STRETCH_BLT_LINEAR\n");
+ break;
+ case SVGA3D_STRETCH_BLT_MAX:
+ debug_printf("\t\t.mode = SVGA3D_STRETCH_BLT_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.mode = %i\n", (*cmd).mode);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dCmdSurfaceDMA(const SVGA3dCmdSurfaceDMA *cmd)
+{
+ debug_printf("\t\t.guest.ptr.gmrId = %u\n", (*cmd).guest.ptr.gmrId);
+ debug_printf("\t\t.guest.ptr.offset = %u\n", (*cmd).guest.ptr.offset);
+ debug_printf("\t\t.guest.pitch = %u\n", (*cmd).guest.pitch);
+ debug_printf("\t\t.host.sid = %u\n", (*cmd).host.sid);
+ debug_printf("\t\t.host.face = %u\n", (*cmd).host.face);
+ debug_printf("\t\t.host.mipmap = %u\n", (*cmd).host.mipmap);
+ switch((*cmd).transfer) {
+ case SVGA3D_WRITE_HOST_VRAM:
+ debug_printf("\t\t.transfer = SVGA3D_WRITE_HOST_VRAM\n");
+ break;
+ case SVGA3D_READ_HOST_VRAM:
+ debug_printf("\t\t.transfer = SVGA3D_READ_HOST_VRAM\n");
+ break;
+ default:
+ debug_printf("\t\t.transfer = %i\n", (*cmd).transfer);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dCmdSurfaceDMASuffix(const SVGA3dCmdSurfaceDMASuffix *cmd)
+{
+ debug_printf("\t\t.suffixSize = %u\n", (*cmd).suffixSize);
+ debug_printf("\t\t.maximumOffset = %u\n", (*cmd).maximumOffset);
+ debug_printf("\t\t.flags.discard = %u\n", (*cmd).flags.discard);
+ debug_printf("\t\t.flags.unsynchronized = %u\n", (*cmd).flags.unsynchronized);
+}
+
+static void
+dump_SVGA3dCmdSetTransform(const SVGA3dCmdSetTransform *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).type) {
+ case SVGA3D_TRANSFORM_INVALID:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_INVALID\n");
+ break;
+ case SVGA3D_TRANSFORM_WORLD:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_WORLD\n");
+ break;
+ case SVGA3D_TRANSFORM_VIEW:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_VIEW\n");
+ break;
+ case SVGA3D_TRANSFORM_PROJECTION:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_PROJECTION\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE0:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE0\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE1:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE1\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE2:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE2\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE3:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE3\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE4:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE4\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE5:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE5\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE6:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE6\n");
+ break;
+ case SVGA3D_TRANSFORM_TEXTURE7:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_TEXTURE7\n");
+ break;
+ case SVGA3D_TRANSFORM_WORLD1:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_WORLD1\n");
+ break;
+ case SVGA3D_TRANSFORM_WORLD2:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_WORLD2\n");
+ break;
+ case SVGA3D_TRANSFORM_WORLD3:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_WORLD3\n");
+ break;
+ case SVGA3D_TRANSFORM_MAX:
+ debug_printf("\t\t.type = SVGA3D_TRANSFORM_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+ debug_printf("\t\t.matrix[0] = %f\n", (*cmd).matrix[0]);
+ debug_printf("\t\t.matrix[1] = %f\n", (*cmd).matrix[1]);
+ debug_printf("\t\t.matrix[2] = %f\n", (*cmd).matrix[2]);
+ debug_printf("\t\t.matrix[3] = %f\n", (*cmd).matrix[3]);
+ debug_printf("\t\t.matrix[4] = %f\n", (*cmd).matrix[4]);
+ debug_printf("\t\t.matrix[5] = %f\n", (*cmd).matrix[5]);
+ debug_printf("\t\t.matrix[6] = %f\n", (*cmd).matrix[6]);
+ debug_printf("\t\t.matrix[7] = %f\n", (*cmd).matrix[7]);
+ debug_printf("\t\t.matrix[8] = %f\n", (*cmd).matrix[8]);
+ debug_printf("\t\t.matrix[9] = %f\n", (*cmd).matrix[9]);
+ debug_printf("\t\t.matrix[10] = %f\n", (*cmd).matrix[10]);
+ debug_printf("\t\t.matrix[11] = %f\n", (*cmd).matrix[11]);
+ debug_printf("\t\t.matrix[12] = %f\n", (*cmd).matrix[12]);
+ debug_printf("\t\t.matrix[13] = %f\n", (*cmd).matrix[13]);
+ debug_printf("\t\t.matrix[14] = %f\n", (*cmd).matrix[14]);
+ debug_printf("\t\t.matrix[15] = %f\n", (*cmd).matrix[15]);
+}
+
+static void
+dump_SVGA3dCmdDestroyShader(const SVGA3dCmdDestroyShader *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ debug_printf("\t\t.shid = %u\n", (*cmd).shid);
+ switch((*cmd).type) {
+ case SVGA3D_SHADERTYPE_COMPILED_DX8:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_COMPILED_DX8\n");
+ break;
+ case SVGA3D_SHADERTYPE_VS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_VS\n");
+ break;
+ case SVGA3D_SHADERTYPE_PS:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_PS\n");
+ break;
+ case SVGA3D_SHADERTYPE_MAX:
+ debug_printf("\t\t.type = SVGA3D_SHADERTYPE_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.type = %i\n", (*cmd).type);
+ break;
+ }
+}
+
+static void
+dump_SVGA3dCmdDestroyContext(const SVGA3dCmdDestroyContext *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+}
+
+static void
+dump_SVGA3dCmdClear(const SVGA3dCmdClear *cmd)
+{
+ debug_printf("\t\t.cid = %u\n", (*cmd).cid);
+ switch((*cmd).clearFlag) {
+ case SVGA3D_CLEAR_COLOR:
+ debug_printf("\t\t.clearFlag = SVGA3D_CLEAR_COLOR\n");
+ break;
+ case SVGA3D_CLEAR_DEPTH:
+ debug_printf("\t\t.clearFlag = SVGA3D_CLEAR_DEPTH\n");
+ break;
+ case SVGA3D_CLEAR_STENCIL:
+ debug_printf("\t\t.clearFlag = SVGA3D_CLEAR_STENCIL\n");
+ break;
+ default:
+ debug_printf("\t\t.clearFlag = %i\n", (*cmd).clearFlag);
+ break;
+ }
+ debug_printf("\t\t.color = %u\n", (*cmd).color);
+ debug_printf("\t\t.depth = %f\n", (*cmd).depth);
+ debug_printf("\t\t.stencil = %u\n", (*cmd).stencil);
+}
+
+static void
+dump_SVGA3dCmdDefineSurface(const SVGA3dCmdDefineSurface *cmd)
+{
+ debug_printf("\t\t.sid = %u\n", (*cmd).sid);
+ switch((*cmd).surfaceFlags) {
+ case SVGA3D_SURFACE_CUBEMAP:
+ debug_printf("\t\t.surfaceFlags = SVGA3D_SURFACE_CUBEMAP\n");
+ break;
+ case SVGA3D_SURFACE_HINT_STATIC:
+ debug_printf("\t\t.surfaceFlags = SVGA3D_SURFACE_HINT_STATIC\n");
+ break;
+ case SVGA3D_SURFACE_HINT_DYNAMIC:
+ debug_printf("\t\t.surfaceFlags = SVGA3D_SURFACE_HINT_DYNAMIC\n");
+ break;
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ debug_printf("\t\t.surfaceFlags = SVGA3D_SURFACE_HINT_INDEXBUFFER\n");
+ break;
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ debug_printf("\t\t.surfaceFlags = SVGA3D_SURFACE_HINT_VERTEXBUFFER\n");
+ break;
+ default:
+ debug_printf("\t\t.surfaceFlags = %i\n", (*cmd).surfaceFlags);
+ break;
+ }
+ switch((*cmd).format) {
+ case SVGA3D_FORMAT_INVALID:
+ debug_printf("\t\t.format = SVGA3D_FORMAT_INVALID\n");
+ break;
+ case SVGA3D_X8R8G8B8:
+ debug_printf("\t\t.format = SVGA3D_X8R8G8B8\n");
+ break;
+ case SVGA3D_A8R8G8B8:
+ debug_printf("\t\t.format = SVGA3D_A8R8G8B8\n");
+ break;
+ case SVGA3D_R5G6B5:
+ debug_printf("\t\t.format = SVGA3D_R5G6B5\n");
+ break;
+ case SVGA3D_X1R5G5B5:
+ debug_printf("\t\t.format = SVGA3D_X1R5G5B5\n");
+ break;
+ case SVGA3D_A1R5G5B5:
+ debug_printf("\t\t.format = SVGA3D_A1R5G5B5\n");
+ break;
+ case SVGA3D_A4R4G4B4:
+ debug_printf("\t\t.format = SVGA3D_A4R4G4B4\n");
+ break;
+ case SVGA3D_Z_D32:
+ debug_printf("\t\t.format = SVGA3D_Z_D32\n");
+ break;
+ case SVGA3D_Z_D16:
+ debug_printf("\t\t.format = SVGA3D_Z_D16\n");
+ break;
+ case SVGA3D_Z_D24S8:
+ debug_printf("\t\t.format = SVGA3D_Z_D24S8\n");
+ break;
+ case SVGA3D_Z_D15S1:
+ debug_printf("\t\t.format = SVGA3D_Z_D15S1\n");
+ break;
+ case SVGA3D_LUMINANCE8:
+ debug_printf("\t\t.format = SVGA3D_LUMINANCE8\n");
+ break;
+ case SVGA3D_LUMINANCE4_ALPHA4:
+ debug_printf("\t\t.format = SVGA3D_LUMINANCE4_ALPHA4\n");
+ break;
+ case SVGA3D_LUMINANCE16:
+ debug_printf("\t\t.format = SVGA3D_LUMINANCE16\n");
+ break;
+ case SVGA3D_LUMINANCE8_ALPHA8:
+ debug_printf("\t\t.format = SVGA3D_LUMINANCE8_ALPHA8\n");
+ break;
+ case SVGA3D_DXT1:
+ debug_printf("\t\t.format = SVGA3D_DXT1\n");
+ break;
+ case SVGA3D_DXT2:
+ debug_printf("\t\t.format = SVGA3D_DXT2\n");
+ break;
+ case SVGA3D_DXT3:
+ debug_printf("\t\t.format = SVGA3D_DXT3\n");
+ break;
+ case SVGA3D_DXT4:
+ debug_printf("\t\t.format = SVGA3D_DXT4\n");
+ break;
+ case SVGA3D_DXT5:
+ debug_printf("\t\t.format = SVGA3D_DXT5\n");
+ break;
+ case SVGA3D_BUMPU8V8:
+ debug_printf("\t\t.format = SVGA3D_BUMPU8V8\n");
+ break;
+ case SVGA3D_BUMPL6V5U5:
+ debug_printf("\t\t.format = SVGA3D_BUMPL6V5U5\n");
+ break;
+ case SVGA3D_BUMPX8L8V8U8:
+ debug_printf("\t\t.format = SVGA3D_BUMPX8L8V8U8\n");
+ break;
+ case SVGA3D_BUMPL8V8U8:
+ debug_printf("\t\t.format = SVGA3D_BUMPL8V8U8\n");
+ break;
+ case SVGA3D_ARGB_S10E5:
+ debug_printf("\t\t.format = SVGA3D_ARGB_S10E5\n");
+ break;
+ case SVGA3D_ARGB_S23E8:
+ debug_printf("\t\t.format = SVGA3D_ARGB_S23E8\n");
+ break;
+ case SVGA3D_A2R10G10B10:
+ debug_printf("\t\t.format = SVGA3D_A2R10G10B10\n");
+ break;
+ case SVGA3D_V8U8:
+ debug_printf("\t\t.format = SVGA3D_V8U8\n");
+ break;
+ case SVGA3D_Q8W8V8U8:
+ debug_printf("\t\t.format = SVGA3D_Q8W8V8U8\n");
+ break;
+ case SVGA3D_CxV8U8:
+ debug_printf("\t\t.format = SVGA3D_CxV8U8\n");
+ break;
+ case SVGA3D_X8L8V8U8:
+ debug_printf("\t\t.format = SVGA3D_X8L8V8U8\n");
+ break;
+ case SVGA3D_A2W10V10U10:
+ debug_printf("\t\t.format = SVGA3D_A2W10V10U10\n");
+ break;
+ case SVGA3D_ALPHA8:
+ debug_printf("\t\t.format = SVGA3D_ALPHA8\n");
+ break;
+ case SVGA3D_R_S10E5:
+ debug_printf("\t\t.format = SVGA3D_R_S10E5\n");
+ break;
+ case SVGA3D_R_S23E8:
+ debug_printf("\t\t.format = SVGA3D_R_S23E8\n");
+ break;
+ case SVGA3D_RG_S10E5:
+ debug_printf("\t\t.format = SVGA3D_RG_S10E5\n");
+ break;
+ case SVGA3D_RG_S23E8:
+ debug_printf("\t\t.format = SVGA3D_RG_S23E8\n");
+ break;
+ case SVGA3D_BUFFER:
+ debug_printf("\t\t.format = SVGA3D_BUFFER\n");
+ break;
+ case SVGA3D_Z_D24X8:
+ debug_printf("\t\t.format = SVGA3D_Z_D24X8\n");
+ break;
+ case SVGA3D_FORMAT_MAX:
+ debug_printf("\t\t.format = SVGA3D_FORMAT_MAX\n");
+ break;
+ default:
+ debug_printf("\t\t.format = %i\n", (*cmd).format);
+ break;
+ }
+ debug_printf("\t\t.face[0].numMipLevels = %u\n", (*cmd).face[0].numMipLevels);
+ debug_printf("\t\t.face[1].numMipLevels = %u\n", (*cmd).face[1].numMipLevels);
+ debug_printf("\t\t.face[2].numMipLevels = %u\n", (*cmd).face[2].numMipLevels);
+ debug_printf("\t\t.face[3].numMipLevels = %u\n", (*cmd).face[3].numMipLevels);
+ debug_printf("\t\t.face[4].numMipLevels = %u\n", (*cmd).face[4].numMipLevels);
+ debug_printf("\t\t.face[5].numMipLevels = %u\n", (*cmd).face[5].numMipLevels);
+}
+
+
+void
+svga_dump_commands(const void *commands, uint32_t size)
+{
+ const uint8_t *next = commands;
+ const uint8_t *last = next + size;
+
+ assert(size % sizeof(uint32_t) == 0);
+
+ while(next < last) {
+ const uint32_t cmd_id = *(const uint32_t *)next;
+
+ if(SVGA_3D_CMD_BASE <= cmd_id && cmd_id < SVGA_3D_CMD_MAX) {
+ const SVGA3dCmdHeader *header = (const SVGA3dCmdHeader *)next;
+ const uint8_t *body = (const uint8_t *)&header[1];
+
+ next = (const uint8_t *)body + header->size;
+ if(next > last)
+ break;
+
+ switch(cmd_id) {
+ case SVGA_3D_CMD_SURFACE_DEFINE:
+ debug_printf("\tSVGA_3D_CMD_SURFACE_DEFINE\n");
+ {
+ const SVGA3dCmdDefineSurface *cmd = (const SVGA3dCmdDefineSurface *)body;
+ dump_SVGA3dCmdDefineSurface(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dSize) <= next) {
+ dump_SVGA3dSize((const SVGA3dSize *)body);
+ body += sizeof(SVGA3dSize);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SURFACE_DESTROY:
+ debug_printf("\tSVGA_3D_CMD_SURFACE_DESTROY\n");
+ {
+ const SVGA3dCmdDestroySurface *cmd = (const SVGA3dCmdDestroySurface *)body;
+ dump_SVGA3dCmdDestroySurface(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SURFACE_COPY:
+ debug_printf("\tSVGA_3D_CMD_SURFACE_COPY\n");
+ {
+ const SVGA3dCmdSurfaceCopy *cmd = (const SVGA3dCmdSurfaceCopy *)body;
+ dump_SVGA3dCmdSurfaceCopy(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dCopyBox) <= next) {
+ dump_SVGA3dCopyBox((const SVGA3dCopyBox *)body);
+ body += sizeof(SVGA3dCopyBox);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SURFACE_STRETCHBLT:
+ debug_printf("\tSVGA_3D_CMD_SURFACE_STRETCHBLT\n");
+ {
+ const SVGA3dCmdSurfaceStretchBlt *cmd = (const SVGA3dCmdSurfaceStretchBlt *)body;
+ dump_SVGA3dCmdSurfaceStretchBlt(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SURFACE_DMA:
+ debug_printf("\tSVGA_3D_CMD_SURFACE_DMA\n");
+ {
+ const SVGA3dCmdSurfaceDMA *cmd = (const SVGA3dCmdSurfaceDMA *)body;
+ dump_SVGA3dCmdSurfaceDMA(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dCopyBox) <= next) {
+ dump_SVGA3dCopyBox((const SVGA3dCopyBox *)body);
+ body += sizeof(SVGA3dCopyBox);
+ }
+ while(body + sizeof(SVGA3dCmdSurfaceDMASuffix) <= next) {
+ dump_SVGA3dCmdSurfaceDMASuffix((const SVGA3dCmdSurfaceDMASuffix *)body);
+ body += sizeof(SVGA3dCmdSurfaceDMASuffix);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_CONTEXT_DEFINE:
+ debug_printf("\tSVGA_3D_CMD_CONTEXT_DEFINE\n");
+ {
+ const SVGA3dCmdDefineContext *cmd = (const SVGA3dCmdDefineContext *)body;
+ dump_SVGA3dCmdDefineContext(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_CONTEXT_DESTROY:
+ debug_printf("\tSVGA_3D_CMD_CONTEXT_DESTROY\n");
+ {
+ const SVGA3dCmdDestroyContext *cmd = (const SVGA3dCmdDestroyContext *)body;
+ dump_SVGA3dCmdDestroyContext(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETTRANSFORM:
+ debug_printf("\tSVGA_3D_CMD_SETTRANSFORM\n");
+ {
+ const SVGA3dCmdSetTransform *cmd = (const SVGA3dCmdSetTransform *)body;
+ dump_SVGA3dCmdSetTransform(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETZRANGE:
+ debug_printf("\tSVGA_3D_CMD_SETZRANGE\n");
+ {
+ const SVGA3dCmdSetZRange *cmd = (const SVGA3dCmdSetZRange *)body;
+ dump_SVGA3dCmdSetZRange(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETRENDERSTATE:
+ debug_printf("\tSVGA_3D_CMD_SETRENDERSTATE\n");
+ {
+ const SVGA3dCmdSetRenderState *cmd = (const SVGA3dCmdSetRenderState *)body;
+ dump_SVGA3dCmdSetRenderState(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dRenderState) <= next) {
+ dump_SVGA3dRenderState((const SVGA3dRenderState *)body);
+ body += sizeof(SVGA3dRenderState);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SETRENDERTARGET:
+ debug_printf("\tSVGA_3D_CMD_SETRENDERTARGET\n");
+ {
+ const SVGA3dCmdSetRenderTarget *cmd = (const SVGA3dCmdSetRenderTarget *)body;
+ dump_SVGA3dCmdSetRenderTarget(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETTEXTURESTATE:
+ debug_printf("\tSVGA_3D_CMD_SETTEXTURESTATE\n");
+ {
+ const SVGA3dCmdSetTextureState *cmd = (const SVGA3dCmdSetTextureState *)body;
+ dump_SVGA3dCmdSetTextureState(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dTextureState) <= next) {
+ dump_SVGA3dTextureState((const SVGA3dTextureState *)body);
+ body += sizeof(SVGA3dTextureState);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SETMATERIAL:
+ debug_printf("\tSVGA_3D_CMD_SETMATERIAL\n");
+ {
+ const SVGA3dCmdSetMaterial *cmd = (const SVGA3dCmdSetMaterial *)body;
+ dump_SVGA3dCmdSetMaterial(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETLIGHTDATA:
+ debug_printf("\tSVGA_3D_CMD_SETLIGHTDATA\n");
+ {
+ const SVGA3dCmdSetLightData *cmd = (const SVGA3dCmdSetLightData *)body;
+ dump_SVGA3dCmdSetLightData(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETLIGHTENABLED:
+ debug_printf("\tSVGA_3D_CMD_SETLIGHTENABLED\n");
+ {
+ const SVGA3dCmdSetLightEnabled *cmd = (const SVGA3dCmdSetLightEnabled *)body;
+ dump_SVGA3dCmdSetLightEnabled(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETVIEWPORT:
+ debug_printf("\tSVGA_3D_CMD_SETVIEWPORT\n");
+ {
+ const SVGA3dCmdSetViewport *cmd = (const SVGA3dCmdSetViewport *)body;
+ dump_SVGA3dCmdSetViewport(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SETCLIPPLANE:
+ debug_printf("\tSVGA_3D_CMD_SETCLIPPLANE\n");
+ {
+ const SVGA3dCmdSetClipPlane *cmd = (const SVGA3dCmdSetClipPlane *)body;
+ dump_SVGA3dCmdSetClipPlane(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_CLEAR:
+ debug_printf("\tSVGA_3D_CMD_CLEAR\n");
+ {
+ const SVGA3dCmdClear *cmd = (const SVGA3dCmdClear *)body;
+ dump_SVGA3dCmdClear(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dRect) <= next) {
+ dump_SVGA3dRect((const SVGA3dRect *)body);
+ body += sizeof(SVGA3dRect);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_PRESENT:
+ debug_printf("\tSVGA_3D_CMD_PRESENT\n");
+ {
+ const SVGA3dCmdPresent *cmd = (const SVGA3dCmdPresent *)body;
+ dump_SVGA3dCmdPresent(cmd);
+ body = (const uint8_t *)&cmd[1];
+ while(body + sizeof(SVGA3dCopyRect) <= next) {
+ dump_SVGA3dCopyRect((const SVGA3dCopyRect *)body);
+ body += sizeof(SVGA3dCopyRect);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SHADER_DEFINE:
+ debug_printf("\tSVGA_3D_CMD_SHADER_DEFINE\n");
+ {
+ const SVGA3dCmdDefineShader *cmd = (const SVGA3dCmdDefineShader *)body;
+ dump_SVGA3dCmdDefineShader(cmd);
+ body = (const uint8_t *)&cmd[1];
+ svga_shader_dump((const uint32_t *)body,
+ (unsigned)(next - body)/sizeof(uint32_t),
+ FALSE );
+ body = next;
+ }
+ break;
+ case SVGA_3D_CMD_SHADER_DESTROY:
+ debug_printf("\tSVGA_3D_CMD_SHADER_DESTROY\n");
+ {
+ const SVGA3dCmdDestroyShader *cmd = (const SVGA3dCmdDestroyShader *)body;
+ dump_SVGA3dCmdDestroyShader(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SET_SHADER:
+ debug_printf("\tSVGA_3D_CMD_SET_SHADER\n");
+ {
+ const SVGA3dCmdSetShader *cmd = (const SVGA3dCmdSetShader *)body;
+ dump_SVGA3dCmdSetShader(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_SET_SHADER_CONST:
+ debug_printf("\tSVGA_3D_CMD_SET_SHADER_CONST\n");
+ {
+ const SVGA3dCmdSetShaderConst *cmd = (const SVGA3dCmdSetShaderConst *)body;
+ dump_SVGA3dCmdSetShaderConst(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_DRAW_PRIMITIVES:
+ debug_printf("\tSVGA_3D_CMD_DRAW_PRIMITIVES\n");
+ {
+ const SVGA3dCmdDrawPrimitives *cmd = (const SVGA3dCmdDrawPrimitives *)body;
+ unsigned i, j;
+ dump_SVGA3dCmdDrawPrimitives(cmd);
+ body = (const uint8_t *)&cmd[1];
+ for(i = 0; i < cmd->numVertexDecls; ++i) {
+ dump_SVGA3dVertexDecl((const SVGA3dVertexDecl *)body);
+ body += sizeof(SVGA3dVertexDecl);
+ }
+ for(j = 0; j < cmd->numRanges; ++j) {
+ dump_SVGA3dPrimitiveRange((const SVGA3dPrimitiveRange *)body);
+ body += sizeof(SVGA3dPrimitiveRange);
+ }
+ while(body + sizeof(SVGA3dVertexDivisor) <= next) {
+ dump_SVGA3dVertexDivisor((const SVGA3dVertexDivisor *)body);
+ body += sizeof(SVGA3dVertexDivisor);
+ }
+ }
+ break;
+ case SVGA_3D_CMD_SETSCISSORRECT:
+ debug_printf("\tSVGA_3D_CMD_SETSCISSORRECT\n");
+ {
+ const SVGA3dCmdSetScissorRect *cmd = (const SVGA3dCmdSetScissorRect *)body;
+ dump_SVGA3dCmdSetScissorRect(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_BEGIN_QUERY:
+ debug_printf("\tSVGA_3D_CMD_BEGIN_QUERY\n");
+ {
+ const SVGA3dCmdBeginQuery *cmd = (const SVGA3dCmdBeginQuery *)body;
+ dump_SVGA3dCmdBeginQuery(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_END_QUERY:
+ debug_printf("\tSVGA_3D_CMD_END_QUERY\n");
+ {
+ const SVGA3dCmdEndQuery *cmd = (const SVGA3dCmdEndQuery *)body;
+ dump_SVGA3dCmdEndQuery(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ case SVGA_3D_CMD_WAIT_FOR_QUERY:
+ debug_printf("\tSVGA_3D_CMD_WAIT_FOR_QUERY\n");
+ {
+ const SVGA3dCmdWaitForQuery *cmd = (const SVGA3dCmdWaitForQuery *)body;
+ dump_SVGA3dCmdWaitForQuery(cmd);
+ body = (const uint8_t *)&cmd[1];
+ }
+ break;
+ default:
+ debug_printf("\t0x%08x\n", cmd_id);
+ break;
+ }
+
+ while(body + sizeof(uint32_t) <= next) {
+ debug_printf("\t\t0x%08x\n", *(const uint32_t *)body);
+ body += sizeof(uint32_t);
+ }
+ while(body + sizeof(uint32_t) <= next)
+ debug_printf("\t\t0x%02x\n", *body++);
+ }
+ else if(cmd_id == SVGA_CMD_FENCE) {
+ debug_printf("\tSVGA_CMD_FENCE\n");
+ debug_printf("\t\t0x%08x\n", ((const uint32_t *)next)[1]);
+ next += 2*sizeof(uint32_t);
+ }
+ else {
+ debug_printf("\t0x%08x\n", cmd_id);
+ next += sizeof(uint32_t);
+ }
+ }
+}
+
diff --git a/src/gallium/drivers/svga/svgadump/svga_dump.h b/src/gallium/drivers/svga/svgadump/svga_dump.h
new file mode 100644
index 0000000000..69a8702087
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_dump.h
@@ -0,0 +1,34 @@
+/**********************************************************
+ * Copyright 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.
+ *
+ **********************************************************/
+
+#ifndef SVGA_DUMP_H_
+#define SVGA_DUMP_H_
+
+#include "pipe/p_compiler.h"
+
+void
+svga_dump_commands(const void *commands, uint32_t size);
+
+#endif /* SVGA_DUMP_H_ */
diff --git a/src/gallium/drivers/svga/svgadump/svga_dump.py b/src/gallium/drivers/svga/svgadump/svga_dump.py
new file mode 100755
index 0000000000..288e753296
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_dump.py
@@ -0,0 +1,329 @@
+#!/usr/bin/env python
+'''
+Generates dumper for the SVGA 3D command stream using pygccxml.
+
+Jose Fonseca <jfonseca@vmware.com>
+'''
+
+copyright = '''
+/**********************************************************
+ * Copyright 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.
+ *
+ **********************************************************/
+ '''
+
+import os
+import sys
+
+from pygccxml import parser
+from pygccxml import declarations
+
+from pygccxml.declarations import algorithm
+from pygccxml.declarations import decl_visitor
+from pygccxml.declarations import type_traits
+from pygccxml.declarations import type_visitor
+
+
+enums = True
+
+
+class decl_dumper_t(decl_visitor.decl_visitor_t):
+
+ def __init__(self, instance = '', decl = None):
+ decl_visitor.decl_visitor_t.__init__(self)
+ self._instance = instance
+ self.decl = decl
+
+ def clone(self):
+ return decl_dumper_t(self._instance, self.decl)
+
+ def visit_class(self):
+ class_ = self.decl
+ assert self.decl.class_type in ('struct', 'union')
+
+ for variable in class_.variables():
+ if variable.name != '':
+ #print 'variable = %r' % variable.name
+ dump_type(self._instance + '.' + variable.name, variable.type)
+
+ def visit_enumeration(self):
+ if enums:
+ print ' switch(%s) {' % ("(*cmd)" + self._instance,)
+ for name, value in self.decl.values:
+ print ' case %s:' % (name,)
+ print ' debug_printf("\\t\\t%s = %s\\n");' % (self._instance, name)
+ print ' break;'
+ print ' default:'
+ print ' debug_printf("\\t\\t%s = %%i\\n", %s);' % (self._instance, "(*cmd)" + self._instance)
+ print ' break;'
+ print ' }'
+ else:
+ print ' debug_printf("\\t\\t%s = %%i\\n", %s);' % (self._instance, "(*cmd)" + self._instance)
+
+
+def dump_decl(instance, decl):
+ dumper = decl_dumper_t(instance, decl)
+ algorithm.apply_visitor(dumper, decl)
+
+
+class type_dumper_t(type_visitor.type_visitor_t):
+
+ def __init__(self, instance, type_):
+ type_visitor.type_visitor_t.__init__(self)
+ self.instance = instance
+ self.type = type_
+
+ def clone(self):
+ return type_dumper_t(self.instance, self.type)
+
+ def visit_char(self):
+ self.print_instance('%i')
+
+ def visit_unsigned_char(self):
+ self.print_instance('%u')
+
+ def visit_signed_char(self):
+ self.print_instance('%i')
+
+ def visit_wchar(self):
+ self.print_instance('%i')
+
+ def visit_short_int(self):
+ self.print_instance('%i')
+
+ def visit_short_unsigned_int(self):
+ self.print_instance('%u')
+
+ def visit_bool(self):
+ self.print_instance('%i')
+
+ def visit_int(self):
+ self.print_instance('%i')
+
+ def visit_unsigned_int(self):
+ self.print_instance('%u')
+
+ def visit_long_int(self):
+ self.print_instance('%li')
+
+ def visit_long_unsigned_int(self):
+ self.print_instance('%lu')
+
+ def visit_long_long_int(self):
+ self.print_instance('%lli')
+
+ def visit_long_long_unsigned_int(self):
+ self.print_instance('%llu')
+
+ def visit_float(self):
+ self.print_instance('%f')
+
+ def visit_double(self):
+ self.print_instance('%f')
+
+ def visit_array(self):
+ for i in range(type_traits.array_size(self.type)):
+ dump_type(self.instance + '[%i]' % i, type_traits.base_type(self.type))
+
+ def visit_pointer(self):
+ self.print_instance('%p')
+
+ def visit_declarated(self):
+ #print 'decl = %r' % self.type.decl_string
+ decl = type_traits.remove_declarated(self.type)
+ dump_decl(self.instance, decl)
+
+ def print_instance(self, format):
+ print ' debug_printf("\\t\\t%s = %s\\n", %s);' % (self.instance, format, "(*cmd)" + self.instance)
+
+
+def dump_type(instance, type_):
+ type_ = type_traits.remove_alias(type_)
+ visitor = type_dumper_t(instance, type_)
+ algorithm.apply_visitor(visitor, type_)
+
+
+def dump_struct(decls, class_):
+ print 'static void'
+ print 'dump_%s(const %s *cmd)' % (class_.name, class_.name)
+ print '{'
+ dump_decl('', class_)
+ print '}'
+ print ''
+
+
+cmds = [
+ ('SVGA_3D_CMD_SURFACE_DEFINE', 'SVGA3dCmdDefineSurface', (), 'SVGA3dSize'),
+ ('SVGA_3D_CMD_SURFACE_DESTROY', 'SVGA3dCmdDestroySurface', (), None),
+ ('SVGA_3D_CMD_SURFACE_COPY', 'SVGA3dCmdSurfaceCopy', (), 'SVGA3dCopyBox'),
+ ('SVGA_3D_CMD_SURFACE_STRETCHBLT', 'SVGA3dCmdSurfaceStretchBlt', (), None),
+ ('SVGA_3D_CMD_SURFACE_DMA', 'SVGA3dCmdSurfaceDMA', (), 'SVGA3dCopyBox'),
+ ('SVGA_3D_CMD_CONTEXT_DEFINE', 'SVGA3dCmdDefineContext', (), None),
+ ('SVGA_3D_CMD_CONTEXT_DESTROY', 'SVGA3dCmdDestroyContext', (), None),
+ ('SVGA_3D_CMD_SETTRANSFORM', 'SVGA3dCmdSetTransform', (), None),
+ ('SVGA_3D_CMD_SETZRANGE', 'SVGA3dCmdSetZRange', (), None),
+ ('SVGA_3D_CMD_SETRENDERSTATE', 'SVGA3dCmdSetRenderState', (), 'SVGA3dRenderState'),
+ ('SVGA_3D_CMD_SETRENDERTARGET', 'SVGA3dCmdSetRenderTarget', (), None),
+ ('SVGA_3D_CMD_SETTEXTURESTATE', 'SVGA3dCmdSetTextureState', (), 'SVGA3dTextureState'),
+ ('SVGA_3D_CMD_SETMATERIAL', 'SVGA3dCmdSetMaterial', (), None),
+ ('SVGA_3D_CMD_SETLIGHTDATA', 'SVGA3dCmdSetLightData', (), None),
+ ('SVGA_3D_CMD_SETLIGHTENABLED', 'SVGA3dCmdSetLightEnabled', (), None),
+ ('SVGA_3D_CMD_SETVIEWPORT', 'SVGA3dCmdSetViewport', (), None),
+ ('SVGA_3D_CMD_SETCLIPPLANE', 'SVGA3dCmdSetClipPlane', (), None),
+ ('SVGA_3D_CMD_CLEAR', 'SVGA3dCmdClear', (), 'SVGA3dRect'),
+ ('SVGA_3D_CMD_PRESENT', 'SVGA3dCmdPresent', (), 'SVGA3dCopyRect'),
+ ('SVGA_3D_CMD_SHADER_DEFINE', 'SVGA3dCmdDefineShader', (), None),
+ ('SVGA_3D_CMD_SHADER_DESTROY', 'SVGA3dCmdDestroyShader', (), None),
+ ('SVGA_3D_CMD_SET_SHADER', 'SVGA3dCmdSetShader', (), None),
+ ('SVGA_3D_CMD_SET_SHADER_CONST', 'SVGA3dCmdSetShaderConst', (), None),
+ ('SVGA_3D_CMD_DRAW_PRIMITIVES', 'SVGA3dCmdDrawPrimitives', (('SVGA3dVertexDecl', 'numVertexDecls'), ('SVGA3dPrimitiveRange', 'numRanges')), 'SVGA3dVertexDivisor'),
+ ('SVGA_3D_CMD_SETSCISSORRECT', 'SVGA3dCmdSetScissorRect', (), None),
+ ('SVGA_3D_CMD_BEGIN_QUERY', 'SVGA3dCmdBeginQuery', (), None),
+ ('SVGA_3D_CMD_END_QUERY', 'SVGA3dCmdEndQuery', (), None),
+ ('SVGA_3D_CMD_WAIT_FOR_QUERY', 'SVGA3dCmdWaitForQuery', (), None),
+ #('SVGA_3D_CMD_PRESENT_READBACK', None, (), None),
+]
+
+def dump_cmds():
+ print r'''
+void
+svga_dump_commands(const void *commands, uint32_t size)
+{
+ const uint8_t *next = commands;
+ const uint8_t *last = next + size;
+
+ assert(size % sizeof(uint32_t) == 0);
+
+ while(next < last) {
+ const uint32_t cmd_id = *(const uint32_t *)next;
+
+ if(SVGA_3D_CMD_BASE <= cmd_id && cmd_id < SVGA_3D_CMD_MAX) {
+ const SVGA3dCmdHeader *header = (const SVGA3dCmdHeader *)next;
+ const uint8_t *body = (const uint8_t *)&header[1];
+
+ next = (const uint8_t *)body + header->size;
+ if(next > last)
+ break;
+'''
+
+ print ' switch(cmd_id) {'
+ indexes = 'ijklmn'
+ for id, header, body, footer in cmds:
+ print ' case %s:' % id
+ print ' debug_printf("\\t%s\\n");' % id
+ print ' {'
+ print ' const %s *cmd = (const %s *)body;' % (header, header)
+ if len(body):
+ print ' unsigned ' + ', '.join(indexes[:len(body)]) + ';'
+ print ' dump_%s(cmd);' % header
+ print ' body = (const uint8_t *)&cmd[1];'
+ for i in range(len(body)):
+ struct, count = body[i]
+ idx = indexes[i]
+ print ' for(%s = 0; %s < cmd->%s; ++%s) {' % (idx, idx, count, idx)
+ print ' dump_%s((const %s *)body);' % (struct, struct)
+ print ' body += sizeof(%s);' % struct
+ print ' }'
+ if footer is not None:
+ print ' while(body + sizeof(%s) <= next) {' % footer
+ print ' dump_%s((const %s *)body);' % (footer, footer)
+ print ' body += sizeof(%s);' % footer
+ print ' }'
+ if id == 'SVGA_3D_CMD_SHADER_DEFINE':
+ print ' sh_svga_dump((const uint32_t *)body, (unsigned)(next - body)/sizeof(uint32_t));'
+ print ' body = next;'
+ print ' }'
+ print ' break;'
+ print ' default:'
+ print ' debug_printf("\\t0x%08x\\n", cmd_id);'
+ print ' break;'
+ print ' }'
+
+ print r'''
+ while(body + sizeof(uint32_t) <= next) {
+ debug_printf("\t\t0x%08x\n", *(const uint32_t *)body);
+ body += sizeof(uint32_t);
+ }
+ while(body + sizeof(uint32_t) <= next)
+ debug_printf("\t\t0x%02x\n", *body++);
+ }
+ else if(cmd_id == SVGA_CMD_FENCE) {
+ debug_printf("\tSVGA_CMD_FENCE\n");
+ debug_printf("\t\t0x%08x\n", ((const uint32_t *)next)[1]);
+ next += 2*sizeof(uint32_t);
+ }
+ else {
+ debug_printf("\t0x%08x\n", cmd_id);
+ next += sizeof(uint32_t);
+ }
+ }
+}
+'''
+
+def main():
+ print copyright.strip()
+ print
+ print '/**'
+ print ' * @file'
+ print ' * Dump SVGA commands.'
+ print ' *'
+ print ' * Generated automatically from svga3d_reg.h by svga_dump.py.'
+ print ' */'
+ print
+ print '#include "svga_types.h"'
+ print '#include "svga_shader_dump.h"'
+ print '#include "svga3d_reg.h"'
+ print
+ print '#include "pipe/p_debug.h"'
+ print '#include "svga_dump.h"'
+ print
+
+ config = parser.config_t(
+ include_paths = ['include'],
+ compiler = 'gcc',
+ )
+
+ headers = [
+ 'include/svga_types.h',
+ 'include/svga3d_reg.h',
+ ]
+
+ decls = parser.parse(headers, config, parser.COMPILATION_MODE.ALL_AT_ONCE)
+ global_ns = declarations.get_global_namespace(decls)
+
+ names = set()
+ for id, header, body, footer in cmds:
+ names.add(header)
+ for struct, count in body:
+ names.add(struct)
+ if footer is not None:
+ names.add(footer)
+
+ for class_ in global_ns.classes(lambda decl: decl.name in names):
+ dump_struct(decls, class_)
+
+ dump_cmds()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/gallium/drivers/svga/svgadump/svga_shader.h b/src/gallium/drivers/svga/svgadump/svga_shader.h
new file mode 100644
index 0000000000..9217af2dd9
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_shader.h
@@ -0,0 +1,220 @@
+/**********************************************************
+ * Copyright 2007-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * SVGA Shader Token Definitions
+ *
+ * @author Michal Krol <michal@vmware.com>
+ */
+
+#ifndef ST_SHADER_SVGA_H
+#define ST_SHADER_SVGA_H
+
+#include "pipe/p_compiler.h"
+
+struct sh_op
+{
+ unsigned opcode:16;
+ unsigned control:8;
+ unsigned length:4;
+ unsigned predicated:1;
+ unsigned unused:1;
+ unsigned coissue:1;
+ unsigned is_reg:1;
+};
+
+struct sh_reg
+{
+ unsigned number:11;
+ unsigned type_hi:2;
+ unsigned relative:1;
+ unsigned unused:14;
+ unsigned type_lo:3;
+ unsigned is_reg:1;
+};
+
+static INLINE unsigned
+sh_reg_type( struct sh_reg reg )
+{
+ return reg.type_lo | (reg.type_hi << 3);
+}
+
+struct sh_cdata
+{
+ float xyzw[4];
+};
+
+struct sh_def
+{
+ struct sh_op op;
+ struct sh_reg reg;
+ struct sh_cdata cdata;
+};
+
+struct sh_defb
+{
+ struct sh_op op;
+ struct sh_reg reg;
+ uint data;
+};
+
+struct sh_idata
+{
+ int xyzw[4];
+};
+
+struct sh_defi
+{
+ struct sh_op op;
+ struct sh_reg reg;
+ struct sh_idata idata;
+};
+
+#define PS_TEXTURETYPE_UNKNOWN SVGA3DSAMP_UNKNOWN
+#define PS_TEXTURETYPE_2D SVGA3DSAMP_2D
+#define PS_TEXTURETYPE_CUBE SVGA3DSAMP_CUBE
+#define PS_TEXTURETYPE_VOLUME SVGA3DSAMP_VOLUME
+
+struct ps_sampleinfo
+{
+ unsigned unused:27;
+ unsigned texture_type:4;
+ unsigned is_reg:1;
+};
+
+struct vs_semantic
+{
+ unsigned usage:5;
+ unsigned unused1:11;
+ unsigned usage_index:4;
+ unsigned unused2:12;
+};
+
+struct sh_dstreg
+{
+ unsigned number:11;
+ unsigned type_hi:2;
+ unsigned relative:1;
+ unsigned unused:2;
+ unsigned write_mask:4;
+ unsigned modifier:4;
+ unsigned shift_scale:4;
+ unsigned type_lo:3;
+ unsigned is_reg:1;
+};
+
+static INLINE unsigned
+sh_dstreg_type( struct sh_dstreg reg )
+{
+ return reg.type_lo | (reg.type_hi << 3);
+}
+
+struct sh_dcl
+{
+ struct sh_op op;
+ union {
+ struct {
+ struct ps_sampleinfo sampleinfo;
+ } ps;
+ struct {
+ struct vs_semantic semantic;
+ } vs;
+ } u;
+ struct sh_dstreg reg;
+};
+
+
+struct sh_srcreg
+{
+ unsigned number:11;
+ unsigned type_hi:2;
+ unsigned relative:1;
+ unsigned unused:2;
+ unsigned swizzle_x:2;
+ unsigned swizzle_y:2;
+ unsigned swizzle_z:2;
+ unsigned swizzle_w:2;
+ unsigned modifier:4;
+ unsigned type_lo:3;
+ unsigned is_reg:1;
+};
+
+static INLINE unsigned
+sh_srcreg_type( struct sh_srcreg reg )
+{
+ return reg.type_lo | (reg.type_hi << 3);
+}
+
+struct sh_dstop
+{
+ struct sh_op op;
+ struct sh_dstreg dst;
+};
+
+struct sh_srcop
+{
+ struct sh_op op;
+ struct sh_srcreg src;
+};
+
+struct sh_src2op
+{
+ struct sh_op op;
+ struct sh_srcreg src0;
+ struct sh_srcreg src1;
+};
+
+struct sh_unaryop
+{
+ struct sh_op op;
+ struct sh_dstreg dst;
+ struct sh_srcreg src;
+};
+
+struct sh_binaryop
+{
+ struct sh_op op;
+ struct sh_dstreg dst;
+ struct sh_srcreg src0;
+ struct sh_srcreg src1;
+};
+
+struct sh_trinaryop
+{
+ struct sh_op op;
+ struct sh_dstreg dst;
+ struct sh_srcreg src0;
+ struct sh_srcreg src1;
+ struct sh_srcreg src2;
+};
+
+struct sh_comment
+{
+ unsigned opcode:16;
+ unsigned size:16;
+};
+
+#endif /* ST_SHADER_SVGA_H */
diff --git a/src/gallium/drivers/svga/svgadump/svga_shader_dump.c b/src/gallium/drivers/svga/svgadump/svga_shader_dump.c
new file mode 100644
index 0000000000..b0e7fdf378
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_shader_dump.c
@@ -0,0 +1,654 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * SVGA Shader Dump Facilities
+ *
+ * @author Michal Krol <michal@vmware.com>
+ */
+
+#include "svga_shader.h"
+#include "svga_shader_dump.h"
+#include "svga_shader_op.h"
+#include "util/u_debug.h"
+
+#include "../svga_hw_reg.h"
+#include "svga3d_shaderdefs.h"
+
+struct dump_info
+{
+ SVGA3dShaderVersion version;
+ boolean is_ps;
+};
+
+static void dump_op( struct sh_op op, const char *mnemonic )
+{
+ assert( op.predicated == 0 );
+ assert( op.is_reg == 0 );
+
+ if (op.coissue)
+ debug_printf( "+" );
+ debug_printf( "%s", mnemonic );
+ switch (op.control) {
+ case 0:
+ break;
+ case SVGA3DOPCONT_PROJECT:
+ debug_printf( "p" );
+ break;
+ case SVGA3DOPCONT_BIAS:
+ debug_printf( "b" );
+ break;
+ default:
+ assert( 0 );
+ }
+}
+
+
+static void dump_comp_op( struct sh_op op, const char *mnemonic )
+{
+ assert( op.is_reg == 0 );
+
+ if (op.coissue)
+ debug_printf( "+" );
+ debug_printf( "%s", mnemonic );
+ switch (op.control) {
+ case SVGA3DOPCOMP_RESERVED0:
+ break;
+ case SVGA3DOPCOMP_GT:
+ debug_printf("_gt");
+ break;
+ case SVGA3DOPCOMP_EQ:
+ debug_printf("_eq");
+ break;
+ case SVGA3DOPCOMP_GE:
+ debug_printf("_ge");
+ break;
+ case SVGA3DOPCOMP_LT:
+ debug_printf("_lt");
+ break;
+ case SVGA3DOPCOMPC_NE:
+ debug_printf("_ne");
+ break;
+ case SVGA3DOPCOMP_LE:
+ debug_printf("_le");
+ break;
+ case SVGA3DOPCOMP_RESERVED1:
+ default:
+ assert( 0 );
+ }
+}
+
+
+static void dump_reg( struct sh_reg reg, struct sh_srcreg *indreg, const struct dump_info *di )
+{
+ assert( sh_reg_type( reg ) == SVGA3DREG_CONST || reg.relative == 0 );
+ assert( reg.is_reg == 1 );
+
+ switch (sh_reg_type( reg )) {
+ case SVGA3DREG_TEMP:
+ debug_printf( "r%u", reg.number );
+ break;
+
+ case SVGA3DREG_INPUT:
+ debug_printf( "v%u", reg.number );
+ break;
+
+ case SVGA3DREG_CONST:
+ if (reg.relative) {
+ if (sh_srcreg_type( *indreg ) == SVGA3DREG_LOOP)
+ debug_printf( "c[aL+%u]", reg.number );
+ else
+ debug_printf( "c[a%u.x+%u]", indreg->number, reg.number );
+ }
+ else
+ debug_printf( "c%u", reg.number );
+ break;
+
+ case SVGA3DREG_ADDR: /* VS */
+ /* SVGA3DREG_TEXTURE */ /* PS */
+ if (di->is_ps)
+ debug_printf( "t%u", reg.number );
+ else
+ debug_printf( "a%u", reg.number );
+ break;
+
+ case SVGA3DREG_RASTOUT:
+ switch (reg.number) {
+ case 0 /*POSITION*/:
+ debug_printf( "oPos" );
+ break;
+ case 1 /*FOG*/:
+ debug_printf( "oFog" );
+ break;
+ case 2 /*POINT_SIZE*/:
+ debug_printf( "oPts" );
+ break;
+ default:
+ assert( 0 );
+ debug_printf( "???" );
+ }
+ break;
+
+ case SVGA3DREG_ATTROUT:
+ assert( reg.number < 2 );
+ debug_printf( "oD%u", reg.number );
+ break;
+
+ case SVGA3DREG_TEXCRDOUT:
+ /* SVGA3DREG_OUTPUT */
+ debug_printf( "oT%u", reg.number );
+ break;
+
+ case SVGA3DREG_COLOROUT:
+ debug_printf( "oC%u", reg.number );
+ break;
+
+ case SVGA3DREG_DEPTHOUT:
+ debug_printf( "oD%u", reg.number );
+ break;
+
+ case SVGA3DREG_SAMPLER:
+ debug_printf( "s%u", reg.number );
+ break;
+
+ case SVGA3DREG_CONSTBOOL:
+ assert( !reg.relative );
+ debug_printf( "b%u", reg.number );
+ break;
+
+ case SVGA3DREG_CONSTINT:
+ assert( !reg.relative );
+ debug_printf( "i%u", reg.number );
+ break;
+
+ case SVGA3DREG_LOOP:
+ assert( reg.number == 0 );
+ debug_printf( "aL" );
+ break;
+
+ case SVGA3DREG_MISCTYPE:
+ switch (reg.number) {
+ case SVGA3DMISCREG_POSITION:
+ debug_printf( "vPos" );
+ break;
+ case SVGA3DMISCREG_FACE:
+ debug_printf( "vFace" );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case SVGA3DREG_LABEL:
+ debug_printf( "l%u", reg.number );
+ break;
+
+ case SVGA3DREG_PREDICATE:
+ debug_printf( "p%u", reg.number );
+ break;
+
+
+ default:
+ assert( 0 );
+ debug_printf( "???" );
+ }
+}
+
+static void dump_cdata( struct sh_cdata cdata )
+{
+ debug_printf( "%f, %f, %f, %f", cdata.xyzw[0], cdata.xyzw[1], cdata.xyzw[2], cdata.xyzw[3] );
+}
+
+static void dump_idata( struct sh_idata idata )
+{
+ debug_printf( "%d, %d, %d, %d", idata.xyzw[0], idata.xyzw[1], idata.xyzw[2], idata.xyzw[3] );
+}
+
+static void dump_bdata( boolean bdata )
+{
+ debug_printf( bdata ? "TRUE" : "FALSE" );
+}
+
+static void dump_sampleinfo( struct ps_sampleinfo sampleinfo )
+{
+ switch (sampleinfo.texture_type) {
+ case SVGA3DSAMP_2D:
+ debug_printf( "_2d" );
+ break;
+ case SVGA3DSAMP_CUBE:
+ debug_printf( "_cube" );
+ break;
+ case SVGA3DSAMP_VOLUME:
+ debug_printf( "_volume" );
+ break;
+ default:
+ assert( 0 );
+ }
+}
+
+
+static void dump_usageinfo( struct vs_semantic semantic )
+{
+ switch (semantic.usage) {
+ case SVGA3D_DECLUSAGE_POSITION:
+ debug_printf("_position" );
+ break;
+ case SVGA3D_DECLUSAGE_BLENDWEIGHT:
+ debug_printf("_blendweight" );
+ break;
+ case SVGA3D_DECLUSAGE_BLENDINDICES:
+ debug_printf("_blendindices" );
+ break;
+ case SVGA3D_DECLUSAGE_NORMAL:
+ debug_printf("_normal" );
+ break;
+ case SVGA3D_DECLUSAGE_PSIZE:
+ debug_printf("_psize" );
+ break;
+ case SVGA3D_DECLUSAGE_TEXCOORD:
+ debug_printf("_texcoord");
+ break;
+ case SVGA3D_DECLUSAGE_TANGENT:
+ debug_printf("_tangent" );
+ break;
+ case SVGA3D_DECLUSAGE_BINORMAL:
+ debug_printf("_binormal" );
+ break;
+ case SVGA3D_DECLUSAGE_TESSFACTOR:
+ debug_printf("_tessfactor" );
+ break;
+ case SVGA3D_DECLUSAGE_POSITIONT:
+ debug_printf("_positiont" );
+ break;
+ case SVGA3D_DECLUSAGE_COLOR:
+ debug_printf("_color" );
+ break;
+ case SVGA3D_DECLUSAGE_FOG:
+ debug_printf("_fog" );
+ break;
+ case SVGA3D_DECLUSAGE_DEPTH:
+ debug_printf("_depth" );
+ break;
+ case SVGA3D_DECLUSAGE_SAMPLE:
+ debug_printf("_sample");
+ break;
+ default:
+ assert( 0 );
+ return;
+ }
+
+ if (semantic.usage_index != 0) {
+ debug_printf("%d", semantic.usage_index );
+ }
+}
+
+static void dump_dstreg( struct sh_dstreg dstreg, const struct dump_info *di )
+{
+ union {
+ struct sh_reg reg;
+ struct sh_dstreg dstreg;
+ } u;
+
+ assert( (dstreg.modifier & (SVGA3DDSTMOD_SATURATE | SVGA3DDSTMOD_PARTIALPRECISION)) == dstreg.modifier );
+
+ if (dstreg.modifier & SVGA3DDSTMOD_SATURATE)
+ debug_printf( "_sat" );
+ if (dstreg.modifier & SVGA3DDSTMOD_PARTIALPRECISION)
+ debug_printf( "_pp" );
+ switch (dstreg.shift_scale) {
+ case 0:
+ break;
+ case 1:
+ debug_printf( "_x2" );
+ break;
+ case 2:
+ debug_printf( "_x4" );
+ break;
+ case 3:
+ debug_printf( "_x8" );
+ break;
+ case 13:
+ debug_printf( "_d8" );
+ break;
+ case 14:
+ debug_printf( "_d4" );
+ break;
+ case 15:
+ debug_printf( "_d2" );
+ break;
+ default:
+ assert( 0 );
+ }
+ debug_printf( " " );
+
+ u.dstreg = dstreg;
+ dump_reg( u.reg, NULL, di );
+ if (dstreg.write_mask != SVGA3DWRITEMASK_ALL) {
+ debug_printf( "." );
+ if (dstreg.write_mask & SVGA3DWRITEMASK_0)
+ debug_printf( "x" );
+ if (dstreg.write_mask & SVGA3DWRITEMASK_1)
+ debug_printf( "y" );
+ if (dstreg.write_mask & SVGA3DWRITEMASK_2)
+ debug_printf( "z" );
+ if (dstreg.write_mask & SVGA3DWRITEMASK_3)
+ debug_printf( "w" );
+ }
+}
+
+static void dump_srcreg( struct sh_srcreg srcreg, struct sh_srcreg *indreg, const struct dump_info *di )
+{
+ union {
+ struct sh_reg reg;
+ struct sh_srcreg srcreg;
+ } u;
+
+ switch (srcreg.modifier) {
+ case SVGA3DSRCMOD_NEG:
+ case SVGA3DSRCMOD_BIASNEG:
+ case SVGA3DSRCMOD_SIGNNEG:
+ case SVGA3DSRCMOD_X2NEG:
+ debug_printf( "-" );
+ break;
+ case SVGA3DSRCMOD_ABS:
+ debug_printf( "|" );
+ break;
+ case SVGA3DSRCMOD_ABSNEG:
+ debug_printf( "-|" );
+ break;
+ case SVGA3DSRCMOD_COMP:
+ debug_printf( "1-" );
+ break;
+ case SVGA3DSRCMOD_NOT:
+ debug_printf( "!" );
+ }
+
+ u.srcreg = srcreg;
+ dump_reg( u.reg, indreg, di );
+ switch (srcreg.modifier) {
+ case SVGA3DSRCMOD_NONE:
+ case SVGA3DSRCMOD_NEG:
+ case SVGA3DSRCMOD_COMP:
+ case SVGA3DSRCMOD_NOT:
+ break;
+ case SVGA3DSRCMOD_ABS:
+ case SVGA3DSRCMOD_ABSNEG:
+ debug_printf( "|" );
+ break;
+ case SVGA3DSRCMOD_BIAS:
+ case SVGA3DSRCMOD_BIASNEG:
+ debug_printf( "_bias" );
+ break;
+ case SVGA3DSRCMOD_SIGN:
+ case SVGA3DSRCMOD_SIGNNEG:
+ debug_printf( "_bx2" );
+ break;
+ case SVGA3DSRCMOD_X2:
+ case SVGA3DSRCMOD_X2NEG:
+ debug_printf( "_x2" );
+ break;
+ case SVGA3DSRCMOD_DZ:
+ debug_printf( "_dz" );
+ break;
+ case SVGA3DSRCMOD_DW:
+ debug_printf( "_dw" );
+ break;
+ default:
+ assert( 0 );
+ }
+ if (srcreg.swizzle_x != 0 || srcreg.swizzle_y != 1 || srcreg.swizzle_z != 2 || srcreg.swizzle_w != 3) {
+ debug_printf( "." );
+ if (srcreg.swizzle_x == srcreg.swizzle_y && srcreg.swizzle_y == srcreg.swizzle_z && srcreg.swizzle_z == srcreg.swizzle_w) {
+ debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
+ }
+ else {
+ debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
+ debug_printf( "%c", "xyzw"[srcreg.swizzle_y] );
+ debug_printf( "%c", "xyzw"[srcreg.swizzle_z] );
+ debug_printf( "%c", "xyzw"[srcreg.swizzle_w] );
+ }
+ }
+}
+
+void
+svga_shader_dump(
+ const unsigned *assem,
+ unsigned dwords,
+ unsigned do_binary )
+{
+ const unsigned *start = assem;
+ boolean finished = FALSE;
+ struct dump_info di;
+ unsigned i;
+
+ if (do_binary) {
+ for (i = 0; i < dwords; i++)
+ debug_printf(" 0x%08x,\n", assem[i]);
+
+ debug_printf("\n\n");
+ }
+
+ di.version.value = *assem++;
+ di.is_ps = (di.version.type == SVGA3D_PS_TYPE);
+
+ debug_printf(
+ "%s_%u_%u\n",
+ di.is_ps ? "ps" : "vs",
+ di.version.major,
+ di.version.minor );
+
+ while (!finished) {
+ struct sh_op op = *(struct sh_op *) assem;
+
+ if (assem - start >= dwords) {
+ debug_printf("... ran off end of buffer\n");
+ assert(0);
+ return;
+ }
+
+ switch (op.opcode) {
+ case SVGA3DOP_DCL:
+ {
+ struct sh_dcl dcl = *(struct sh_dcl *) assem;
+
+ debug_printf( "dcl" );
+ if (sh_dstreg_type( dcl.reg ) == SVGA3DREG_SAMPLER)
+ dump_sampleinfo( dcl.u.ps.sampleinfo );
+ else if (di.is_ps) {
+ if (di.version.major == 3 &&
+ sh_dstreg_type( dcl.reg ) != SVGA3DREG_MISCTYPE)
+ dump_usageinfo( dcl.u.vs.semantic );
+ }
+ else
+ dump_usageinfo( dcl.u.vs.semantic );
+ dump_dstreg( dcl.reg, &di );
+ debug_printf( "\n" );
+ assem += sizeof( struct sh_dcl ) / sizeof( unsigned );
+ }
+ break;
+
+ case SVGA3DOP_DEFB:
+ {
+ struct sh_defb defb = *(struct sh_defb *) assem;
+
+ debug_printf( "defb " );
+ dump_reg( defb.reg, NULL, &di );
+ debug_printf( ", " );
+ dump_bdata( defb.data );
+ debug_printf( "\n" );
+ assem += sizeof( struct sh_defb ) / sizeof( unsigned );
+ }
+ break;
+
+ case SVGA3DOP_DEFI:
+ {
+ struct sh_defi defi = *(struct sh_defi *) assem;
+
+ debug_printf( "defi " );
+ dump_reg( defi.reg, NULL, &di );
+ debug_printf( ", " );
+ dump_idata( defi.idata );
+ debug_printf( "\n" );
+ assem += sizeof( struct sh_defi ) / sizeof( unsigned );
+ }
+ break;
+
+ case SVGA3DOP_TEXCOORD:
+ assert( di.is_ps );
+ dump_op( op, "texcoord" );
+ if (0) {
+ struct sh_dstop dstop = *(struct sh_dstop *) assem;
+ dump_dstreg( dstop.dst, &di );
+ assem += sizeof( struct sh_dstop ) / sizeof( unsigned );
+ }
+ else {
+ struct sh_unaryop unaryop = *(struct sh_unaryop *) assem;
+ dump_dstreg( unaryop.dst, &di );
+ debug_printf( ", " );
+ dump_srcreg( unaryop.src, NULL, &di );
+ assem += sizeof( struct sh_unaryop ) / sizeof( unsigned );
+ }
+ debug_printf( "\n" );
+ break;
+
+ case SVGA3DOP_TEX:
+ assert( di.is_ps );
+ if (0) {
+ dump_op( op, "tex" );
+ if (0) {
+ struct sh_dstop dstop = *(struct sh_dstop *) assem;
+
+ dump_dstreg( dstop.dst, &di );
+ assem += sizeof( struct sh_dstop ) / sizeof( unsigned );
+ }
+ else {
+ struct sh_unaryop unaryop = *(struct sh_unaryop *) assem;
+
+ dump_dstreg( unaryop.dst, &di );
+ debug_printf( ", " );
+ dump_srcreg( unaryop.src, NULL, &di );
+ assem += sizeof( struct sh_unaryop ) / sizeof( unsigned );
+ }
+ }
+ else {
+ struct sh_binaryop binaryop = *(struct sh_binaryop *) assem;
+
+ dump_op( op, "texld" );
+ dump_dstreg( binaryop.dst, &di );
+ debug_printf( ", " );
+ dump_srcreg( binaryop.src0, NULL, &di );
+ debug_printf( ", " );
+ dump_srcreg( binaryop.src1, NULL, &di );
+ assem += sizeof( struct sh_binaryop ) / sizeof( unsigned );
+ }
+ debug_printf( "\n" );
+ break;
+
+ case SVGA3DOP_DEF:
+ {
+ struct sh_def def = *(struct sh_def *) assem;
+
+ debug_printf( "def " );
+ dump_reg( def.reg, NULL, &di );
+ debug_printf( ", " );
+ dump_cdata( def.cdata );
+ debug_printf( "\n" );
+ assem += sizeof( struct sh_def ) / sizeof( unsigned );
+ }
+ break;
+
+ case SVGA3DOP_PHASE:
+ debug_printf( "phase\n" );
+ assem += sizeof( struct sh_op ) / sizeof( unsigned );
+ break;
+
+ case SVGA3DOP_COMMENT:
+ {
+ struct sh_comment comment = *(struct sh_comment *)assem;
+
+ /* Ignore comment contents. */
+ assem += sizeof(struct sh_comment) / sizeof(unsigned) + comment.size;
+ }
+ break;
+
+ case SVGA3DOP_RET:
+ debug_printf( "ret\n" );
+ assem += sizeof( struct sh_op ) / sizeof( unsigned );
+ break;
+
+ case SVGA3DOP_END:
+ debug_printf( "end\n" );
+ finished = TRUE;
+ break;
+
+ default:
+ {
+ const struct sh_opcode_info *info = svga_opcode_info( op.opcode );
+ uint i;
+ uint num_src = info->num_src + op.predicated;
+ boolean not_first_arg = FALSE;
+
+ assert( info->num_dst <= 1 );
+
+ if (op.opcode == SVGA3DOP_SINCOS && di.version.major < 3)
+ num_src += 2;
+
+ dump_comp_op( op, info->mnemonic );
+ assem += sizeof( struct sh_op ) / sizeof( unsigned );
+
+ if (info->num_dst > 0) {
+ struct sh_dstreg dstreg = *(struct sh_dstreg *) assem;
+
+ dump_dstreg( dstreg, &di );
+ assem += sizeof( struct sh_dstreg ) / sizeof( unsigned );
+ not_first_arg = TRUE;
+ }
+
+ for (i = 0; i < num_src; i++) {
+ struct sh_srcreg srcreg;
+ struct sh_srcreg indreg;
+
+ srcreg = *(struct sh_srcreg *) assem;
+ assem += sizeof( struct sh_srcreg ) / sizeof( unsigned );
+ if (srcreg.relative && !di.is_ps && di.version.major >= 2) {
+ indreg = *(struct sh_srcreg *) assem;
+ assem += sizeof( struct sh_srcreg ) / sizeof( unsigned );
+ }
+
+ if (not_first_arg)
+ debug_printf( ", " );
+ else
+ debug_printf( " " );
+ dump_srcreg( srcreg, &indreg, &di );
+ not_first_arg = TRUE;
+ }
+
+ debug_printf( "\n" );
+ }
+ }
+ }
+}
diff --git a/src/gallium/drivers/svga/svgadump/svga_shader_dump.h b/src/gallium/drivers/svga/svgadump/svga_shader_dump.h
new file mode 100644
index 0000000000..a2657acb2f
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_shader_dump.h
@@ -0,0 +1,42 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * SVGA Shader Dump Facilities
+ *
+ * @author Michal Krol <michal@vmware.com>
+ */
+
+#ifndef SVGA_SHADER_DUMP_H
+#define SVGA_SHADER_DUMP_H
+
+void
+svga_shader_dump(
+ const unsigned *assem,
+ unsigned dwords,
+ unsigned do_binary );
+
+#endif /* SVGA_SHADER_DUMP_H */
diff --git a/src/gallium/drivers/svga/svgadump/svga_shader_op.c b/src/gallium/drivers/svga/svgadump/svga_shader_op.c
new file mode 100644
index 0000000000..8343bfdaab
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_shader_op.c
@@ -0,0 +1,168 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * SVGA Shader Token Opcode Info
+ *
+ * @author Michal Krol <michal@vmware.com>
+ */
+
+#include "util/u_debug.h"
+#include "svga_shader_op.h"
+
+#include "../svga_hw_reg.h"
+#include "svga3d_shaderdefs.h"
+
+#define SVGA3DOP_INVALID SVGA3DOP_END
+#define TGSI_OPCODE_INVALID TGSI_OPCODE_LAST
+
+static struct sh_opcode_info opcode_info[] =
+{
+ { "nop", 0, 0, SVGA3DOP_NOP },
+ { "mov", 1, 1, SVGA3DOP_MOV, },
+ { "add", 1, 2, SVGA3DOP_ADD, },
+ { "sub", 1, 2, SVGA3DOP_SUB, },
+ { "mad", 1, 3, SVGA3DOP_MAD, },
+ { "mul", 1, 2, SVGA3DOP_MUL, },
+ { "rcp", 1, 1, SVGA3DOP_RCP, },
+ { "rsq", 1, 1, SVGA3DOP_RSQ, },
+ { "dp3", 1, 2, SVGA3DOP_DP3, },
+ { "dp4", 1, 2, SVGA3DOP_DP4, },
+ { "min", 1, 2, SVGA3DOP_MIN, },
+ { "max", 1, 2, SVGA3DOP_MAX, },
+ { "slt", 1, 2, SVGA3DOP_SLT, },
+ { "sge", 1, 2, SVGA3DOP_SGE, },
+ { "exp", 1, 1, SVGA3DOP_EXP, },
+ { "log", 1, 1, SVGA3DOP_LOG, },
+ { "lit", 1, 1, SVGA3DOP_LIT, },
+ { "dst", 1, 2, SVGA3DOP_DST, },
+ { "lrp", 1, 3, SVGA3DOP_LRP, },
+ { "frc", 1, 1, SVGA3DOP_FRC, },
+ { "m4x4", 1, 2, SVGA3DOP_M4x4, },
+ { "m4x3", 1, 2, SVGA3DOP_M4x3, },
+ { "m3x4", 1, 2, SVGA3DOP_M3x4, },
+ { "m3x3", 1, 2, SVGA3DOP_M3x3, },
+ { "m3x2", 1, 2, SVGA3DOP_M3x2, },
+ { "call", 0, 1, SVGA3DOP_CALL, },
+ { "callnz", 0, 2, SVGA3DOP_CALLNZ, },
+ { "loop", 0, 2, SVGA3DOP_LOOP, },
+ { "ret", 0, 0, SVGA3DOP_RET, },
+ { "endloop", 0, 0, SVGA3DOP_ENDLOOP, },
+ { "label", 0, 1, SVGA3DOP_LABEL, },
+ { "dcl", 0, 0, SVGA3DOP_DCL, },
+ { "pow", 1, 2, SVGA3DOP_POW, },
+ { "crs", 1, 2, SVGA3DOP_CRS, },
+ { "sgn", 1, 3, SVGA3DOP_SGN, },
+ { "abs", 1, 1, SVGA3DOP_ABS, },
+ { "nrm", 1, 1, SVGA3DOP_NRM, }, /* 3-componenet normalization */
+ { "sincos", 1, 1, SVGA3DOP_SINCOS, },
+ { "rep", 0, 1, SVGA3DOP_REP, },
+ { "endrep", 0, 0, SVGA3DOP_ENDREP, },
+ { "if", 0, 1, SVGA3DOP_IF, },
+ { "ifc", 0, 2, SVGA3DOP_IFC, },
+ { "else", 0, 0, SVGA3DOP_ELSE, },
+ { "endif", 0, 0, SVGA3DOP_ENDIF, },
+ { "break", 0, 0, SVGA3DOP_BREAK, },
+ { "breakc", 0, 0, SVGA3DOP_BREAKC, },
+ { "mova", 1, 1, SVGA3DOP_MOVA, },
+ { "defb", 0, 0, SVGA3DOP_DEFB, },
+ { "defi", 0, 0, SVGA3DOP_DEFI, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "???", 0, 0, SVGA3DOP_INVALID, },
+ { "texcoord", 0, 0, SVGA3DOP_TEXCOORD, },
+ { "texkill", 1, 0, SVGA3DOP_TEXKILL, },
+ { "tex", 0, 0, SVGA3DOP_TEX, },
+ { "texbem", 1, 1, SVGA3DOP_TEXBEM, },
+ { "texbeml", 1, 1, SVGA3DOP_TEXBEML, },
+ { "texreg2ar", 1, 1, SVGA3DOP_TEXREG2AR, },
+ { "texreg2gb", 1, 1, SVGA3DOP_TEXREG2GB, },
+ { "texm3x2pad", 1, 1, SVGA3DOP_TEXM3x2PAD, },
+ { "texm3x2tex", 1, 1, SVGA3DOP_TEXM3x2TEX, },
+ { "texm3x3pad", 1, 1, SVGA3DOP_TEXM3x3PAD, },
+ { "texm3x3tex", 1, 1, SVGA3DOP_TEXM3x3TEX, },
+ { "reserved0", 0, 0, SVGA3DOP_RESERVED0, },
+ { "texm3x3spec", 1, 2, SVGA3DOP_TEXM3x3SPEC, },
+ { "texm3x3vspec", 1, 1, SVGA3DOP_TEXM3x3VSPEC,},
+ { "expp", 1, 1, SVGA3DOP_EXPP, },
+ { "logp", 1, 1, SVGA3DOP_LOGP, },
+ { "cnd", 1, 3, SVGA3DOP_CND, },
+ { "def", 0, 0, SVGA3DOP_DEF, },
+ { "texreg2rgb", 1, 1, SVGA3DOP_TEXREG2RGB, },
+ { "texdp3tex", 1, 1, SVGA3DOP_TEXDP3TEX, },
+ { "texm3x2depth", 1, 1, SVGA3DOP_TEXM3x2DEPTH,},
+ { "texdp3", 1, 1, SVGA3DOP_TEXDP3, },
+ { "texm3x3", 1, 1, SVGA3DOP_TEXM3x3, },
+ { "texdepth", 1, 0, SVGA3DOP_TEXDEPTH, },
+ { "cmp", 1, 3, SVGA3DOP_CMP, },
+ { "bem", 1, 2, SVGA3DOP_BEM, },
+ { "dp2add", 1, 3, SVGA3DOP_DP2ADD, },
+ { "dsx", 1, 1, SVGA3DOP_INVALID, },
+ { "dsy", 1, 1, SVGA3DOP_INVALID, },
+ { "texldd", 1, 1, SVGA3DOP_INVALID, },
+ { "setp", 1, 2, SVGA3DOP_SETP, },
+ { "texldl", 1, 1, SVGA3DOP_INVALID, },
+ { "breakp", 1, 1, SVGA3DOP_INVALID, },
+};
+
+const struct sh_opcode_info *svga_opcode_info( uint op )
+{
+ struct sh_opcode_info *info;
+
+ if (op >= sizeof( opcode_info ) / sizeof( opcode_info[0] )) {
+ /* The opcode is either PHASE, COMMENT, END or out of range.
+ */
+ assert( 0 );
+ return NULL;
+ }
+
+ info = &opcode_info[op];
+
+ if (info->svga_opcode == SVGA3DOP_INVALID) {
+ /* No valid information. Please provide number of dst/src registers.
+ */
+ assert( 0 );
+ return NULL;
+ }
+
+ /* Sanity check.
+ */
+ assert( op == info->svga_opcode );
+
+ return info;
+}
diff --git a/src/gallium/drivers/svga/svgadump/svga_shader_op.h b/src/gallium/drivers/svga/svgadump/svga_shader_op.h
new file mode 100644
index 0000000000..e558de02c5
--- /dev/null
+++ b/src/gallium/drivers/svga/svgadump/svga_shader_op.h
@@ -0,0 +1,46 @@
+/**********************************************************
+ * Copyright 2008-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.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * SVGA Shader Token Opcode Info
+ *
+ * @author Michal Krol <michal@vmware.com>
+ */
+
+#ifndef SVGA_SHADER_OP_H
+#define SVGA_SHADER_OP_H
+
+struct sh_opcode_info
+{
+ const char *mnemonic;
+ unsigned num_dst:8;
+ unsigned num_src:8;
+ unsigned svga_opcode:16;
+};
+
+const struct sh_opcode_info *svga_opcode_info( unsigned op );
+
+#endif /* SVGA_SHADER_OP_H */