[Spice-commits] 9 commits - build.bat COPYING dirs display/brush.c display/driver.c display/driver.rc display/makefile display/mspace.c display/mspace.h display/pointer.c display/quic.c display/quic_config.h display/quic_family_tmpl.c display/quic.h display/quic_rgb_tmpl.c display/quic_tmpl.c display/qxldd.h display/res.c display/res.h display/rop.c display/rop.h display/sources display/surface.c display/surface.h display/text.c display/utils.h include/murmur_hash2a.h include/os_dep.h include/qxl_driver.h include/stdint.h include/wdmhelper.h miniport/makefile miniport/minimal_snprintf.c miniport/minimal_snprintf.h miniport/qxl.c miniport/qxl.h miniport/qxl.inf miniport/qxl.rc miniport/sources miniport/wdmhelper.c scripts/buildAll.bat scripts/clean.bat wddm/dirs wddm/qxl.inf wddm/sys wddm/umd xddm/build.bat xddm/COPYING xddm/dirs xddm/display xddm/include xddm/miniport xddm/scripts

Alon Levy alon at kemper.freedesktop.org
Sun Nov 4 07:14:32 PST 2012


 COPYING                          |  339 ---
 build.bat                        |   45 
 dirs                             |    4 
 display/brush.c                  |  400 ----
 display/driver.c                 | 1590 ------------------
 display/driver.rc                |   29 
 display/makefile                 |    1 
 display/mspace.c                 | 2437 ----------------------------
 display/mspace.h                 |  150 -
 display/pointer.c                |  144 -
 display/quic.c                   | 1738 --------------------
 display/quic.h                   |   68 
 display/quic_config.h            |   54 
 display/quic_family_tmpl.c       |  118 -
 display/quic_rgb_tmpl.c          |  766 --------
 display/quic_tmpl.c              |  636 -------
 display/qxldd.h                  |  548 ------
 display/res.c                    | 3387 ---------------------------------------
 display/res.h                    |   77 
 display/rop.c                    | 1778 --------------------
 display/rop.h                    |   42 
 display/sources                  |   34 
 display/surface.c                |  407 ----
 display/surface.h                |  103 -
 display/text.c                   |  128 -
 display/utils.h                  |  123 -
 include/murmur_hash2a.h          |  152 -
 include/os_dep.h                 |   41 
 include/qxl_driver.h             |  127 -
 include/stdint.h                 |  397 ----
 include/wdmhelper.h              |   38 
 miniport/makefile                |    1 
 miniport/minimal_snprintf.c      |  708 --------
 miniport/minimal_snprintf.h      |    9 
 miniport/qxl.c                   | 1311 ---------------
 miniport/qxl.h                   |   41 
 miniport/qxl.inf                 |   97 -
 miniport/qxl.rc                  |   29 
 miniport/sources                 |   29 
 miniport/wdmhelper.c             |   64 
 scripts/buildAll.bat             |   75 
 scripts/clean.bat                |    6 
 wddm/dirs                        |    1 
 wddm/qxl.inf                     |   38 
 wddm/sys/qxlwddm.c               |   24 
 wddm/sys/sources                 |    8 
 wddm/umd/sources                 |    5 
 xddm/COPYING                     |  339 +++
 xddm/build.bat                   |   45 
 xddm/dirs                        |    4 
 xddm/display/brush.c             |  400 ++++
 xddm/display/driver.c            | 1590 ++++++++++++++++++
 xddm/display/driver.rc           |   29 
 xddm/display/makefile            |    1 
 xddm/display/mspace.c            | 2437 ++++++++++++++++++++++++++++
 xddm/display/mspace.h            |  150 +
 xddm/display/pointer.c           |  144 +
 xddm/display/quic.c              | 1738 ++++++++++++++++++++
 xddm/display/quic.h              |   68 
 xddm/display/quic_config.h       |   54 
 xddm/display/quic_family_tmpl.c  |  118 +
 xddm/display/quic_rgb_tmpl.c     |  766 ++++++++
 xddm/display/quic_tmpl.c         |  636 +++++++
 xddm/display/qxldd.h             |  548 ++++++
 xddm/display/res.c               | 3387 +++++++++++++++++++++++++++++++++++++++
 xddm/display/res.h               |   77 
 xddm/display/rop.c               | 1778 ++++++++++++++++++++
 xddm/display/rop.h               |   42 
 xddm/display/sources             |   34 
 xddm/display/surface.c           |  407 ++++
 xddm/display/surface.h           |  103 +
 xddm/display/text.c              |  128 +
 xddm/display/utils.h             |  123 +
 xddm/include/murmur_hash2a.h     |  152 +
 xddm/include/os_dep.h            |   41 
 xddm/include/qxl_driver.h        |  127 +
 xddm/include/stdint.h            |  397 ++++
 xddm/include/wdmhelper.h         |   38 
 xddm/miniport/makefile           |    1 
 xddm/miniport/minimal_snprintf.c |  708 ++++++++
 xddm/miniport/minimal_snprintf.h |    9 
 xddm/miniport/qxl.c              | 1311 +++++++++++++++
 xddm/miniport/qxl.h              |   41 
 xddm/miniport/qxl.inf            |   97 +
 xddm/miniport/qxl.rc             |   29 
 xddm/miniport/sources            |   29 
 xddm/miniport/wdmhelper.c        |   64 
 xddm/scripts/buildAll.bat        |   75 
 xddm/scripts/clean.bat           |    6 
 89 files changed, 18347 insertions(+), 18271 deletions(-)

New commits:
commit a1e302a2885993155aad81b0dce9328efed7db92
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 16:56:17 2012 +0200

    now finds all files (sys, dll) fine, get 0xe000022d in setupapi.dev.log

diff --git a/wddm/qxl.inf b/wddm/qxl.inf
index f009b77..0661c47 100644
--- a/wddm/qxl.inf
+++ b/wddm/qxl.inf
@@ -1,9 +1,9 @@
 [Version]
 Signature = "$CHICAGO$"
-DriverVer =10/25/2012,0.0.0.1
+DriverVer =10/28/2012,0.0.0.1
 Provider =%RHAT%
 Class =Display
-ClassGUID ={4d36e968-e325-11ce-bfc1-08002be10319}
+ClassGUID = {4d36e968-e325-11ce-bfc1-08002be10318}
 
 [DestinationDirs]
 DefaultDestDir =11	; system32
@@ -25,6 +25,14 @@ qxlwddm.sys
 [qxl.UserMode]
 qxlum.dll
 
+[SourceDisksNames]
+1 = %DiskId%
+
+[SourceDisksFiles]
+qxlwddm.sys = 1
+qxlum.dll = 1
+
 [Strings]
 RHAT ="Red Hat"
 QXL = "QXL"
+DiskId = "Windows 2000 Driver Installation Disk"
commit bd9aeffd549aabbecc244ff55935a56b6b9ccbe6
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 15:06:03 2012 +0200

    builds; no installation - still setupapi claims file missing

diff --git a/wddm/sys/qxlwddm.c b/wddm/sys/qxlwddm.c
index e69de29..6a3ef0e 100644
--- a/wddm/sys/qxlwddm.c
+++ b/wddm/sys/qxlwddm.c
@@ -0,0 +1,24 @@
+#include <ntddk.h>
+#include <wdm.h>
+#include <dispmprt.h>
+
+#pragma code_seg(push)
+#pragma code_seg("INIT")
+NTSTATUS DriverEntry(
+          IN  PDRIVER_OBJECT DriverObject,
+          IN  PUNICODE_STRING RegistryPath
+        )
+{
+    DRIVER_INITIALIZATION_DATA DriverInitializationData = {'\0'};
+
+    PAGED_CODE();
+
+    if (! ARGUMENT_PRESENT(DriverObject) ||
+        ! ARGUMENT_PRESENT(RegistryPath))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+    DriverInitializationData.Version = DXGKDDI_INTERFACE_VERSION;
+
+    return DxgkInitialize(DriverObject, RegistryPath, &DriverInitializationData);
+}
diff --git a/wddm/sys/sources b/wddm/sys/sources
index 3099210..ffb0745 100644
--- a/wddm/sys/sources
+++ b/wddm/sys/sources
@@ -1,3 +1,8 @@
 TARGETNAME=qxlwddm
-TARGETTYPE=DRIVER
+TARGETTYPE=MINIPORT
 SOURCES=qxlwddm.c
+TARGETLIBS=$(DDK_LIB_PATH)\displib.lib \
+    $(DDK_LIB_PATH)\ntoskrnl.lib \
+    $(DDK_LIB_PATH)\hal.lib \
+    $(DDK_LIB_PATH)\libcntpr.lib
+#MAJORCOMP=ntos
diff --git a/wddm/umd/qxlum.def b/wddm/umd/qxlum.def
new file mode 100644
index 0000000..e69de29
diff --git a/wddm/umd/sources b/wddm/umd/sources
index 3d916c9..e209432 100644
--- a/wddm/umd/sources
+++ b/wddm/umd/sources
@@ -1,3 +1,5 @@
-TARGETNAME=qxlum.dll
+TARGETNAME=qxlum
 TARGETTYPE=DYNLINK
 SOURCES=qxlum.c
+TARGETLIBS= \
+    $(DDK_LIB_PATH)\kernel32.lib
commit 7136ad4bba8a0b877f559f6fd5fba8ee8f1f8457
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:44:29 2012 +0200

    added qxlum.c to umd, not tested because sys fails to link

diff --git a/wddm/umd/qxlum.c b/wddm/umd/qxlum.c
new file mode 100644
index 0000000..e69de29
diff --git a/wddm/umd/sources b/wddm/umd/sources
index 22a0a65..3d916c9 100644
--- a/wddm/umd/sources
+++ b/wddm/umd/sources
@@ -1,3 +1,3 @@
 TARGETNAME=qxlum.dll
 TARGETTYPE=DYNLINK
-SOURCES=
+SOURCES=qxlum.c
commit e738434bab96824aef3637a710346fba1ce622c0
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:44:02 2012 +0200

    qxlwddm.sys failes to link, missing DriverEntry

diff --git a/wddm/sys/qxlwddm.c b/wddm/sys/qxlwddm.c
new file mode 100644
index 0000000..e69de29
commit e6717011bd6b1f5f97b29dcc1d96fd8e1c5f3864
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:43:41 2012 +0200

    TARGETNAME doesn't need .sys suffix

diff --git a/wddm/sys/sources b/wddm/sys/sources
index 962083c..3099210 100644
--- a/wddm/sys/sources
+++ b/wddm/sys/sources
@@ -1,3 +1,3 @@
-TARGETNAME=qxlwddm.sys
+TARGETNAME=qxlwddm
 TARGETTYPE=DRIVER
-SOURCES=
+SOURCES=qxlwddm.c
commit fa20d42f5ceb751d3250d73f97386639deb3f94a
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:34:42 2012 +0200

    wddm: passes build but builds nothing

diff --git a/wddm/dirs b/wddm/dirs
new file mode 100644
index 0000000..f592783
--- /dev/null
+++ b/wddm/dirs
@@ -0,0 +1 @@
+DIRS=sys umd
diff --git a/wddm/sys/sources b/wddm/sys/sources
new file mode 100644
index 0000000..962083c
--- /dev/null
+++ b/wddm/sys/sources
@@ -0,0 +1,3 @@
+TARGETNAME=qxlwddm.sys
+TARGETTYPE=DRIVER
+SOURCES=
diff --git a/wddm/umd/sources b/wddm/umd/sources
new file mode 100644
index 0000000..22a0a65
--- /dev/null
+++ b/wddm/umd/sources
@@ -0,0 +1,3 @@
+TARGETNAME=qxlum.dll
+TARGETTYPE=DYNLINK
+SOURCES=
commit b09336b147b438d9df026f4d322d79e71667fc95
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:25:45 2012 +0200

    wddm/qxl.inf: now finally getting a missing file error in setupapi.dev.log for qxlwddm.sys

diff --git a/wddm/qxl.inf b/wddm/qxl.inf
index 6bbdef1..f009b77 100644
--- a/wddm/qxl.inf
+++ b/wddm/qxl.inf
@@ -11,7 +11,7 @@ qxl.KernelMode =12	; drivers
 qxl.UserMode =11	; system32
 
 [Manufacturer]
-%RHAT% =qxl
+%RHAT% =q, NTx86
 
 [q.NTx86]
 %RHAT% %QXL% =dd.qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
commit 73e45e2976090dcfafa5394e3acc7f095b66596d
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Oct 28 11:05:45 2012 +0200

    wip: passes pnputil -i -a qxl.inf, but doesn't try to install anything except the inf

diff --git a/wddm/qxl.inf b/wddm/qxl.inf
new file mode 100644
index 0000000..6bbdef1
--- /dev/null
+++ b/wddm/qxl.inf
@@ -0,0 +1,30 @@
+[Version]
+Signature = "$CHICAGO$"
+DriverVer =10/25/2012,0.0.0.1
+Provider =%RHAT%
+Class =Display
+ClassGUID ={4d36e968-e325-11ce-bfc1-08002be10319}
+
+[DestinationDirs]
+DefaultDestDir =11	; system32
+qxl.KernelMode =12	; drivers
+qxl.UserMode =11	; system32
+
+[Manufacturer]
+%RHAT% =qxl
+
+[q.NTx86]
+%RHAT% %QXL% =dd.qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
+
+[dd.qxl]
+CopyFiles =qxl.KernelMode, qxl.UserMode
+
+[qxl.KernelMode]
+qxlwddm.sys
+
+[qxl.UserMode]
+qxlum.dll
+
+[Strings]
+RHAT ="Red Hat"
+QXL = "QXL"
commit 03a2959e46c8729b41168bf71b985ec41c5e6845
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Oct 25 15:54:46 2012 +0200

    move xddm driver to xddm subdir

diff --git a/COPYING b/COPYING
deleted file mode 100644
index d511905..0000000
--- a/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/build.bat b/build.bat
deleted file mode 100755
index 204756a..0000000
--- a/build.bat
+++ /dev/null
@@ -1,45 +0,0 @@
- at echo off
-
-Rem
-Rem Build and copy to target based on environment variables set by WinDDK\bin\setenv.
-Rem if an argument is supplied the build products are copied there too under a subdirectory.
-Rem
-
-Rem Just use %BUILD_ALT_DIR%, it is equivalent
-Rem set TARGET=%DDK_TARGET_OS%_%_BUILDARCH%_%BUILD_TYPE%
-
-if not DEFINED BUILD_ALT_DIR (
- echo BUILD_ALT_DIR not defined. Please run in a WinDDK Build Environment.
- goto exit
-)
-if not DEFINED SPICE_COMMON_DIR (
- set SPICE_COMMON_DIR=%CD%\spice-protocol
-)
-
-set TARGET=install_%BUILD_ALT_DIR%
-echo TARGET=%TARGET%
-if not exist %TARGET% mkdir %TARGET%
-
-if not x%1 == x set DEST=%1
-
-:build
-cd miniport
-build -cZg
-cd ../display
-build -cZg
-cd ../
-
-:copy_local
-copy display\obj%BUILD_ALT_DIR%\i386\qxldd.dll %TARGET%
-copy miniport\obj%BUILD_ALT_DIR%\i386\qxl.sys %TARGET%
-copy miniport\qxl.inf %TARGET%
-copy display\obj%BUILD_ALT_DIR%\i386\qxldd.pdb %TARGET%
-copy miniport\obj%BUILD_ALT_DIR%\i386\qxl.pdb %TARGET%
-if not defined DEST goto exit
-if exist %DEST% (
- echo copying to %DEST%
- if not exist %DEST%\%TARGET% ( mkdir "%DEST%\%TARGET%" )
- xcopy /s /y %TARGET% %DEST%\%TARGET%
-)
-
-:exit
diff --git a/dirs b/dirs
deleted file mode 100644
index 94db1d0..0000000
--- a/dirs
+++ /dev/null
@@ -1,4 +0,0 @@
-DIRS= \
-     display \
-     miniport
-
diff --git a/display/brush.c b/display/brush.c
deleted file mode 100644
index 0b9400d..0000000
--- a/display/brush.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "os_dep.h"
-#include "qxldd.h"
-#include "utils.h"
-#include "res.h"
-
-typedef struct InternalBrush {
-    ULONG format;
-    SIZEL size;
-    UINT32 stride;
-    UINT32 key;
-    UINT8 data[0];
-} InternalBrush;
-
-#define COPY1BPP(bits)                                                                  \
-static _inline void realizeBrush##bits##Copy1bpp(PDev *pdev, InternalBrush *internal,   \
-                                                 UINT8 *src, LONG src_stride,           \
-                                                 XLATEOBJ *color_trans)                 \
-{                                                                                       \
-    UINT8 *end = src + src_stride * internal->size.cy;                                  \
-    UINT8 *dest = internal->data;                                                       \
-                                                                                        \
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
-    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
-    for (; src < end; src += src_stride, dest += internal->stride) {                    \
-        UINT##bits *now = (UINT##bits *)dest;                                           \
-        int i;                                                                          \
-                                                                                        \
-        for (i = 0; i < internal->size.cx; i++) {                                       \
-            *(now++) = (UINT##bits)color_trans->pulXlate[test_bit_be(src, i)];          \
-        }                                                                               \
-    }                                                                                   \
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
-}
-
-#define COPY4BPP(bits)                                                                  \
-static _inline void realizeBrush##bits##Copy4bpp(PDev *pdev, InternalBrush *internal,   \
-                                                 UINT8 *src, LONG src_stride,           \
-                                                 XLATEOBJ *color_trans)                 \
-{                                                                                       \
-    UINT8 *dest = internal->data;                                                       \
-    UINT8 *end = dest + internal->stride * internal->size.cy;                           \
-                                                                                        \
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
-    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
-    for (; dest < end; dest += internal->stride, src += src_stride) {                   \
-        UINT8 *src_line = src;                                                          \
-        UINT8 *src_line_end = src_line + (internal->size.cx >> 1);                      \
-        UINT##bits *dest_line = (UINT##bits *)dest;                                     \
-                                                                                        \
-        for (; src_line < src_line_end; src_line++) {                                   \
-            ASSERT(pdev, (*src_line & 0x0fU) < color_trans->cEntries);                  \
-            ASSERT(pdev, ((*src_line >> 4) & 0x0fU) < color_trans->cEntries);           \
-            *(dest_line++) = (UINT##bits)color_trans->pulXlate[(*src_line >> 4) & 0x0f];\
-            *(dest_line++) = (UINT##bits)color_trans->pulXlate[*src_line & 0x0f];       \
-        }                                                                               \
-        if (internal->size.cx & 1) {                                                    \
-            *(dest_line) = (UINT##bits)color_trans->pulXlate[(*src_line >> 4) & 0x0f];  \
-        }                                                                               \
-    }                                                                                   \
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
-}
-
-#define COPY8BPP(bits)                                                                  \
-static _inline void realizeBrush##bits##Copy8bpp(PDev *pdev, InternalBrush *internal,   \
-                                                 UINT8 *src, LONG src_stride,           \
-                                                 XLATEOBJ *color_trans)                 \
-{                                                                                       \
-    UINT8 *dest = internal->data;                                                       \
-    UINT8 *end = dest + internal->stride * internal->size.cy;                           \
-                                                                                        \
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
-    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
-    for (; dest < end; dest += internal->stride, src += src_stride) {                   \
-        UINT8 *src_line = src;                                                          \
-        UINT8 *src_line_end = src_line + internal->size.cx;                             \
-        UINT##bits *dest_line = (UINT##bits *)dest;                                     \
-                                                                                        \
-        for (; src_line < src_line_end; ++dest_line, src_line++) {                      \
-            ASSERT(pdev, *src_line < color_trans->cEntries);                            \
-            *dest_line = (UINT##bits)color_trans->pulXlate[*src_line];                  \
-        }                                                                               \
-    }                                                                                   \
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
-}
-
-COPY1BPP(16);
-COPY1BPP(32);
-COPY4BPP(16);
-COPY4BPP(32);
-COPY8BPP(16);
-COPY8BPP(32);
-
-static _inline void realizeBrush32Copy16bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *dest = internal->data;
-    UINT8 *end = dest + internal->stride * internal->size.cy;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; dest < end; dest += internal->stride, src += src_stride) {
-        UINT32 *dest_line = (UINT32 *)dest;
-        UINT32 *dest_line_end = dest_line + internal->size.cx;
-        UINT16 *src_line = (UINT16 *)src;
-
-        for (; dest_line < dest_line_end; ++dest_line, src_line++) {
-            *dest_line = _16bppTo32bpp(*src_line);
-        }
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-static _inline void realizeBrush32Copy24bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *dest = internal->data;
-    UINT8 *end = dest + internal->stride * internal->size.cy;
-    int line_size = internal->size.cx << 2;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; dest < end; dest += internal->stride, src += src_stride) {
-        UINT8* dest_line = dest;
-        UINT8* dest_line_end = dest_line + line_size;
-        UINT8* src_line = src;
-
-        while (dest_line < dest_line_end) {
-            *(dest_line++) = *(src_line++);
-            *(dest_line++) = *(src_line++);
-            *(dest_line++) = *(src_line++);
-            *(dest_line++) = 0;
-        }
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-static _inline void realizeBrush32Copy32bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *now = internal->data;
-    UINT8 *end = now + internal->stride * internal->size.cy;
-    int line_size = internal->size.cx << 2;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; now < end; now += internal->stride, src += src_stride) {
-        RtlCopyMemory(now, src, line_size);
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-static _inline void realizeBrush16Copy16bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *dest = internal->data;
-    UINT8 *end = dest + internal->stride * internal->size.cy;
-    int line_size = internal->size.cx << 1;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; dest < end; dest += internal->stride, src += src_stride) {
-        RtlCopyMemory(dest, src, line_size);
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-static _inline void realizeBrush16Copy24bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *dest = internal->data;
-    UINT8 *end = dest + internal->stride * internal->size.cy;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; dest < end; dest += internal->stride, src += src_stride) {
-        UINT16 *dest_line = (UINT16 *)dest;
-        UINT16 *dest_line_end = dest_line + internal->size.cx;
-        UINT8 *src_line = src;
-
-        while (dest_line < dest_line_end) {
-            *(dest_line++) = ((UINT16)*(src_line++) >> 3) |
-                             (((UINT16)*(src_line++) & 0xf8) << 2) |
-                             (((UINT16)*(src_line++) & 0xf8) << 7);
-        }
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-UINT16 _32bppTo16bpp(UINT32 color)
-{
-    return ((color & 0xf8) >> 3) | ((color & 0xf800) >> 6) | ((color & 0xf80000) >> 9);
-}
-
-static _inline void realizeBrush16Copy32bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
-                                          LONG src_stride)
-{
-    UINT8 *now = internal->data;
-    UINT8 *end = now + internal->stride * internal->size.cy;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    for (; now < end; now += internal->stride, src += src_stride) {
-        UINT16 *dest_line = (UINT16 *)now;
-        UINT16 *dest_line_end = dest_line + internal->size.cx;
-        UINT32 *src_line = (UINT32 *)src;
-
-        while (dest_line < dest_line_end) {
-            *(dest_line++) = _32bppTo16bpp(*(src_line++));
-        }
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-}
-
-BOOL APIENTRY DrvRealizeBrush(BRUSHOBJ *brush, SURFOBJ *target, SURFOBJ *pattern, SURFOBJ *mask,
-                              XLATEOBJ *color_trans, ULONG hatch)
-{
-    PDev *pdev;
-    InternalBrush *internal;
-    int stride;
-    int size;
-
-    if (!(pdev = (PDev *)target->dhpdev)) {
-        ASSERT(NULL, 0);
-        return FALSE;
-    }
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    if (mask) {
-        DEBUG_PRINT((pdev, 0, "%s: ignoring mask\n", __FUNCTION__));
-    }
-
-    switch (pattern->iBitmapFormat) {
-    case BMF_1BPP:
-    case BMF_32BPP:
-    case BMF_24BPP:
-    case BMF_16BPP:
-    case BMF_8BPP:
-    case BMF_4BPP:
-        break;
-    default:
-        DEBUG_PRINT((pdev, 0, "%s: bad format\n", __FUNCTION__));
-        return FALSE;
-    }
-    stride = (pdev->bitmap_format == BMF_32BPP) ? pattern->sizlBitmap.cx << 2 :
-                                                 ALIGN(pattern->sizlBitmap.cx << 1, 4);
-    size = stride * pattern->sizlBitmap.cy;
-    size += sizeof(InternalBrush);
-
-    if (!(internal = (InternalBrush *)BRUSHOBJ_pvAllocRbrush(brush, size))) {
-        DEBUG_PRINT((pdev, 0, "%s: alloc failed\n", __FUNCTION__));
-        return FALSE;
-    }
-    internal->size = pattern->sizlBitmap;
-    internal->key = 0;
-    internal->stride = stride;
-    if ((internal->format = pdev->bitmap_format) == BMF_32BPP) {
-        switch (pattern->iBitmapFormat) {
-        case BMF_1BPP:
-            realizeBrush32Copy1bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        case BMF_32BPP:
-            realizeBrush32Copy32bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_24BPP:
-            realizeBrush32Copy24bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_16BPP:
-            realizeBrush32Copy16bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_8BPP:
-            realizeBrush32Copy8bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        case BMF_4BPP:
-            realizeBrush32Copy4bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        }
-    } else {
-        ASSERT(pdev, pdev->bitmap_format == BMF_16BPP);
-        switch (pattern->iBitmapFormat) {
-        case BMF_1BPP:
-            realizeBrush16Copy1bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        case BMF_32BPP:
-            realizeBrush16Copy32bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_24BPP:
-            realizeBrush16Copy24bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_16BPP:
-            realizeBrush16Copy16bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
-            break;
-        case BMF_8BPP:
-            realizeBrush16Copy8bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        case BMF_4BPP:
-            realizeBrush16Copy4bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
-            break;
-        }
-    }
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-
-static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *pattern,
-                               InternalBrush *brush, INT32 *surface_dest,
-                               QXLRect *surface_rect)
-{
-    HSURF hsurf;
-    SURFOBJ *surf_obj;
-    QXLRect area;
-    UINT32 key;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    if (brush->key && QXLGetBitsFromCache(pdev, drawable, brush->key, pattern)) {
-        DEBUG_PRINT((pdev, 13, "%s: from cache\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    if (!(hsurf = (HSURF)EngCreateBitmap(brush->size, brush->stride, brush->format, BMF_TOPDOWN,
-                                         brush->data))) {
-        DEBUG_PRINT((pdev, 0, "%s: create bitmap failed\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (!(surf_obj = EngLockSurface(hsurf))) {
-        DEBUG_PRINT((pdev, 0, "%s: lock surf failed\n", __FUNCTION__));
-        goto error_1;
-    }
-    area.left = area.top = 0;
-    area.right = brush->size.cx;
-    area.bottom = brush->size.cy;
-
-    CopyRect(surface_rect, &area);
-
-    if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE, surface_dest)) {
-        goto error_2;
-    }
-
-    brush->key = key;
-    EngUnlockSurface(surf_obj);
-    EngDeleteSurface(hsurf);
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-    return TRUE;
-
-error_2:
-    EngUnlockSurface(surf_obj);
-error_1:
-    EngDeleteSurface(hsurf);
-    return FALSE;
-}
-
-
-BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, QXLBrush *qxl_brush,
-                 BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
-                 QXLRect *surface_rect)
-{
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    ASSERT(pdev, brush);
-
-    if (brush->iSolidColor == ~0) {
-        ASSERT(pdev, brush_pos);
-
-        DEBUG_PRINT((pdev, 11, "%s: pattern\n", __FUNCTION__));
-        if (!brush->pvRbrush && !BRUSHOBJ_pvGetRbrush(brush)) {
-            DEBUG_PRINT((pdev, 0, "%s: brush realize failed\n", __FUNCTION__));
-            return FALSE;
-        }
-        qxl_brush->type = SPICE_BRUSH_TYPE_PATTERN;
-        qxl_brush->u.pattern.pos.x = brush_pos->x;
-        qxl_brush->u.pattern.pos.y = brush_pos->y;
-        if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush,
-                        surface_dest, surface_rect)) {
-            return FALSE;
-        }
-    } else {
-        qxl_brush->type = SPICE_BRUSH_TYPE_SOLID;
-        qxl_brush->u.color = brush->iSolidColor;
-        DEBUG_PRINT((pdev, 11, "%s: color 0x%x\n", __FUNCTION__, qxl_brush->u.color));
-    }
-    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
diff --git a/display/driver.c b/display/driver.c
deleted file mode 100644
index d7fdbf7..0000000
--- a/display/driver.c
+++ /dev/null
@@ -1,1590 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "stddef.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "os_dep.h"
-
-#include "winerror.h"
-#include "windef.h"
-#include "wingdi.h"
-#include "winddi.h"
-#include "devioctl.h"
-#include "ntddvdeo.h"
-
-#include "qxldd.h"
-#include "utils.h"
-#include "mspace.h"
-#include "res.h"
-#include "surface.h"
-
-#define DEVICE_NAME L"qxldd"
-
-#define QXLDD_DEBUG_PREFIX "qxldd: "
-
-static DRVFN drv_calls[] = {
-    {INDEX_DrvDisableDriver, (PFN)DrvDisableDriver},
-    {INDEX_DrvEscape, (PFN)DrvEscape},
-    {INDEX_DrvEnablePDEV, (PFN)DrvEnablePDEV},
-    {INDEX_DrvDisablePDEV, (PFN)DrvDisablePDEV},
-    {INDEX_DrvCompletePDEV, (PFN)DrvCompletePDEV},
-    {INDEX_DrvEnableSurface, (PFN)DrvEnableSurface},
-    {INDEX_DrvDisableSurface, (PFN)DrvDisableSurface},
-    {INDEX_DrvAssertMode, (PFN)DrvAssertMode},
-    {INDEX_DrvGetModes, (PFN)DrvGetModes},
-    {INDEX_DrvSynchronize, (PFN)DrvSynchronize},
-    {INDEX_DrvCopyBits, (PFN)DrvCopyBits},
-    {INDEX_DrvBitBlt, (PFN)DrvBitBlt},
-    {INDEX_DrvTextOut, (PFN)DrvTextOut},
-    {INDEX_DrvStrokePath, (PFN)DrvStrokePath},
-    {INDEX_DrvRealizeBrush, (PFN)DrvRealizeBrush},
-    {INDEX_DrvSetPointerShape, (PFN)DrvSetPointerShape},
-    {INDEX_DrvMovePointer, (PFN)DrvMovePointer},
-    {INDEX_DrvStretchBlt, (PFN)DrvStretchBlt},
-    {INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
-    {INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
-    {INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
-    {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
-    {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
-
-#ifdef CALL_TEST
-    {INDEX_DrvFillPath, (PFN)DrvFillPath},
-    {INDEX_DrvGradientFill, (PFN)DrvGradientFill},
-    {INDEX_DrvLineTo, (PFN)DrvLineTo},
-    {INDEX_DrvPlgBlt, (PFN)DrvPlgBlt},
-    {INDEX_DrvStrokeAndFillPath, (PFN)DrvStrokeAndFillPath},
-#endif
-};
-
-#ifdef CALL_TEST
-
-typedef struct CallCounter {
-    const char *name;
-    BOOL effective;
-} CallCounterInfo;
-
-static CallCounterInfo counters_info[NUM_CALL_COUNTERS] = {
-    { "DrvCopyBits", FALSE},
-    { "DrvBitBlt", TRUE},
-    { "DrvTextOut", TRUE},
-    { "DrvStrokePath", TRUE},
-    { "DrvStretchBlt", FALSE},
-    { "DrvStretchBltROP", TRUE},
-    { "TransparentBlt", FALSE},
-    { "DrvAlphaBlend", FALSE},
-
-    { "DrvFillPath", FALSE},
-    { "DrvGradientFill", FALSE},
-    { "DrvLineTo", FALSE},
-    { "DrvPlgBlt", FALSE},
-    { "DrvStrokeAndFillPath", FALSE},
-};
-
-#endif
-
-#define DBG_LEVEL 0
-
-void DebugPrintV(PDev *pdev, const char *message, va_list ap)
-{
-    if (pdev && pdev->log_buf) {
-        EngAcquireSemaphore(pdev->print_sem);
-        _snprintf(pdev->log_buf, QXL_LOG_BUF_SIZE, QXLDD_DEBUG_PREFIX);
-        _vsnprintf(pdev->log_buf + strlen(QXLDD_DEBUG_PREFIX),
-                   QXL_LOG_BUF_SIZE - strlen(QXLDD_DEBUG_PREFIX), message, ap);
-        sync_io(pdev, pdev->log_port, 0);
-        EngReleaseSemaphore(pdev->print_sem);
-    } else {
-        EngDebugPrint(QXLDD_DEBUG_PREFIX, (PCHAR)message, ap);
-    }
-}
-
-void DebugPrint(PDev *pdev, int level, const char *message, ...)
-{
-    va_list ap;
-
-    if (level > (pdev && pdev->log_level ? (int)*pdev->log_level : DBG_LEVEL)) {
-        return;
-    }
-    va_start(ap, message);
-    DebugPrintV(pdev, message, ap);
-    va_end(ap);
-}
-
-#define DRIVER_VERSION 1
-#define OS_VERSION_MAJOR 5
-#define OS_VERSION_MINOR 0
-#define MK_GDIINFO_VERSION(os_major, os_minor, drv_vers) \
-    ((drv_vers) | ((os_minor) << 8) | ((os_major) << 12))
-
-
-GDIINFO gdi_default = {
-    MK_GDIINFO_VERSION(OS_VERSION_MAJOR, OS_VERSION_MINOR, DRIVER_VERSION),
-    DT_RASDISPLAY,
-    0,                      //ulHorzSize
-    0,                      //ulVertSize
-    0,                      //ulHorzRes
-    0,                      //ulVertRes
-    0,                      //cBitsPixel
-    0,                      //cPlanes
-    0,                      //ulNumColors
-    0,                      //flRaster
-    0,                      //ulLogPixelsX
-    0,                      //ulLogPixelsY
-    TC_RA_ABLE,             //flTextCaps
-    0,                      //ulDACRed
-    0,                      //ulDACGreen
-    0,                      //ulDACBlue
-    0x0024,                 //ulAspectX
-    0x0024,                 //ulAspectY
-    0x0033,                 //ulAspectXY
-    1,                      //xStyleStep
-    1,                      //yStyleSte;
-    3,                      //denStyleStep
-    { 0, 0},               //ptlPhysOffset
-    { 0, 0},               //szlPhysSize
-    0,                      //ulNumPalReg
-
-    {                       //ciDevice
-        { 6700, 3300, 0},  //Red
-        { 2100, 7100, 0},  //Green
-        { 1400,  800, 0},  //Blue
-        { 1750, 3950, 0},  //Cyan
-        { 4050, 2050, 0},  //Magenta
-        { 4400, 5200, 0},  //Yellow
-        { 3127, 3290, 0},  //AlignmentWhite
-        20000,              //RedGamma
-        20000,              //GreenGamma
-        20000,              //BlueGamma
-        0, 0, 0, 0, 0, 0    //No dye correction for raster displays
-    },
-
-    0,                      //ulDevicePelsDPI
-    PRIMARY_ORDER_CBA,      //ulPrimaryOrder
-    HT_PATSIZE_4x4_M,       //ulHTPatternSize
-    HT_FORMAT_8BPP,         //ulHTOutputFormat
-    HT_FLAG_ADDITIVE_PRIMS, //flHTFlags
-    0,                      //ulVRefresh
-    0,                      //ulPanningHorzRes
-    0,                      //ulPanningVertRes
-    0,                      //ulBltAlignment
-    //more
-};
-
-#define SYSTM_LOGFONT {16, 7, 0, 0, 700, 0, 0, 0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
-                       CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\
-                       VARIABLE_PITCH | FF_DONTCARE, L"System"}
-#define HELVE_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
-                       CLIP_STROKE_PRECIS, PROOF_QUALITY,\
-                       VARIABLE_PITCH | FF_DONTCARE, L"MS Sans Serif"}
-#define COURI_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
-                       CLIP_STROKE_PRECIS,PROOF_QUALITY,\
-                       FIXED_PITCH | FF_DONTCARE, L"Courier"}
-
-DEVINFO dev_default = {
-    GCAPS_ARBRUSHOPAQUE | GCAPS_ARBRUSHTEXT | GCAPS_ASYNCMOVE | /* GCAPS_BEZIERS | */
-    GCAPS_GRAY16 | GCAPS_OPAQUERECT |
-    GCAPS_WINDINGFILL /*| GCAPS_LAYERED*/,
-    SYSTM_LOGFONT,      //lfDefaultFont
-    HELVE_LOGFONT,      //lfAnsiVarFont
-    COURI_LOGFONT,      //lfAnsiFixFont
-    0,                  //cFonts
-    0,                  //iDitherFormat
-    0,                  //cxDither
-    0,                  //cyDither
-    0,                  //hpalDefault
-#if (WINVER >= 0x0501)
-    GCAPS2_MOUSETRAILS |
-#endif
-    GCAPS2_ALPHACURSOR,
-};
-
-static BOOL PrepareHardware(PDev *pdev);
-
-static void mspace_print(void *user_data, char *format, ...)
-{
-    PDev *pdev = (PDev *)user_data;
-    va_list ap;
-
-    va_start(ap, format);
-    DebugPrintV(pdev, format, ap);
-    va_end(ap);
-}
-
-static void mspace_abort(void *user_data)
-{
-    mspace_print(user_data, "mspace abort");
-    EngDebugBreak();
-}
-
-BOOL DrvEnableDriver(ULONG engine_version, ULONG enable_data_size, PDRVENABLEDATA enable_data)
-{
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-    enable_data->iDriverVersion = DDI_DRIVER_VERSION_NT5;
-    enable_data->c = sizeof(drv_calls) / sizeof(DRVFN);
-    enable_data->pdrvfn = drv_calls;
-    mspace_set_abort_func(mspace_abort);
-    mspace_set_print_func(mspace_print);
-    ResInitGlobals();
-#ifndef _WIN64
-    CheckAndSetSSE2();
-#endif
-    DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
-    return TRUE;
-}
-
-ULONG DrvEscape(SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn,
-                ULONG cjOut, PVOID pvOut)
-{
-    PDev* pdev = pso ? (PDev*)pso->dhpdev : NULL;
-    int RetVal = -1;
-
-    switch (iEsc) {
-    case QXL_ESCAPE_SET_CUSTOM_DISPLAY: {
-        ULONG length;
-
-        DEBUG_PRINT((pdev, 1, "set custom display %p\n", pdev));
-        if (pdev == NULL)
-            break;
-
-        if (EngDeviceIoControl(pdev->driver, IOCTL_QXL_SET_CUSTOM_DISPLAY,
-                               pvIn, cjIn, NULL, 0, &length)) {
-            DEBUG_PRINT((pdev, 0, "%s: IOCTL_QXL_SET_CUSTOM_DISPLAY failed\n", __FUNCTION__));
-            break;
-        }
-        RetVal = 1;
-        break;
-    }
-    default:
-        DEBUG_PRINT((NULL, 1, "%s: unhandled escape code %d\n", __FUNCTION__, iEsc));
-        RetVal = 0;
-    }
-
-    DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
-    return RetVal;
-}
-
-VOID DrvDisableDriver(VOID)
-{
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-    ResDestroyGlobals();
-}
-
-DWORD GetAvailableModes(HANDLE driver, PVIDEO_MODE_INFORMATION *mode_info,
-                        DWORD *mode_info_size)
-{
-    ULONG n;
-    VIDEO_NUM_MODES modes;
-    PVIDEO_MODE_INFORMATION info;
-
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-
-    if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL, 0,
-                           &modes, sizeof(VIDEO_NUM_MODES), &n)) {
-        DEBUG_PRINT((NULL, 0, "%s: query num modes failed\n", __FUNCTION__));
-        return 0;
-    }
-
-    info = (PVIDEO_MODE_INFORMATION)EngAllocMem(FL_ZERO_MEMORY,
-                                                modes.NumModes * modes.ModeInformationLength,
-                                                ALLOC_TAG);
-    if (!info) {
-        DEBUG_PRINT((NULL, 0, "%s: memory allocation failed\n", __FUNCTION__));
-        return 0;
-    }
-
-    if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0, info,
-                           modes.NumModes * modes.ModeInformationLength, &n)) {
-        DEBUG_PRINT((NULL, 0, "%s: query modes failed\n", __FUNCTION__));
-        EngFreeMem(info);
-        return 0;
-    }
-
-    *mode_info = info;
-    *mode_info_size = modes.ModeInformationLength;
-
-    n = modes.NumModes;
-    while ( n-- ) {
-        if ( (info->NumberOfPlanes != 1 ) ||!(info->AttributeFlags & VIDEO_MODE_GRAPHICS)
-             ||((info->BitsPerPlane != 16) && (info->BitsPerPlane != 32))) {
-
-            DEBUG_PRINT((NULL, 1, "%s: unsuported mode rejecting miniport mode\n",  __FUNCTION__));
-            DEBUG_PRINT((NULL, 1, "                   width = %li height = %li\n",
-                         info->VisScreenWidth, info->VisScreenHeight));
-            DEBUG_PRINT((NULL, 1, "                   bpp = %li freq = %li\n",
-                         info->BitsPerPlane * info->NumberOfPlanes, info->Frequency));
-            info->Length = 0;
-        }
-
-        info = (PVIDEO_MODE_INFORMATION) (((PUCHAR)info) + modes.ModeInformationLength);
-    }
-    DEBUG_PRINT((NULL, 1, "%s: OK num modes %lu\n", __FUNCTION__, modes.NumModes));
-    return modes.NumModes;
-}
-
-BOOL InitializeModeFields(PDev *pdev, GDIINFO *gdi_info, DEVINFO *dev_info,
-                          DEVMODEW *dev_mode)
-{
-    ULONG n_modes;
-    PVIDEO_MODE_INFORMATION video_buff;
-    PVIDEO_MODE_INFORMATION selected_mode;
-    PVIDEO_MODE_INFORMATION video_mode;
-    VIDEO_MODE_INFORMATION vmi;
-    ULONG video_mode_size;
-
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-
-    n_modes = GetAvailableModes(pdev->driver, &video_buff, &video_mode_size);
-    if ( n_modes == 0 ) {
-        DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
-        return FALSE;
-    }
-
-#if (WINVER < 0x0501)
-    DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u\n",
-                 __FUNCTION__,
-                 dev_mode->dmFields,
-                 dev_mode->dmBitsPerPel,
-                 dev_mode->dmPelsWidth,
-                 dev_mode->dmPelsHeight,
-                 dev_mode->dmDisplayFrequency));
-#else
-    DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u orientation %u\n",
-                 __FUNCTION__,
-                 dev_mode->dmFields,
-                 dev_mode->dmBitsPerPel,
-                 dev_mode->dmPelsWidth,
-                 dev_mode->dmPelsHeight,
-                 dev_mode->dmDisplayFrequency,
-                 dev_mode->dmDisplayOrientation));
-#endif
-
-
-    selected_mode = NULL;
-    video_mode = video_buff;
-
-    while (n_modes--) {
-        if ( video_mode->Length != 0 ) {
-            DEBUG_PRINT((NULL, 1, "%s: check width = %li height = %li\n",
-                         __FUNCTION__,
-                         video_mode->VisScreenWidth,
-                         video_mode->VisScreenHeight));
-            DEBUG_PRINT((NULL, 1, "                             bpp = %li freq = %li\n",
-                         video_mode->BitsPerPlane * video_mode->NumberOfPlanes,
-                         video_mode->Frequency));
-
-            if ( (video_mode->VisScreenWidth  == dev_mode->dmPelsWidth)
-                 && (video_mode->VisScreenHeight == dev_mode->dmPelsHeight)
-                 && (video_mode->BitsPerPlane * video_mode->NumberOfPlanes
-                     == dev_mode->dmBitsPerPel)
-                 && (video_mode->Frequency == dev_mode->dmDisplayFrequency)
-#if (WINVER >= 0x0501)
-                 && (video_mode->DriverSpecificAttributeFlags
-                     == dev_mode->dmDisplayOrientation)
-#endif
-            ) {
-                selected_mode = video_mode;
-                DEBUG_PRINT((NULL, 1, "%s: found\n", __FUNCTION__));
-                break;
-            }
-        }
-        video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)video_mode) + video_mode_size);
-    }
-
-    if (!selected_mode) {
-        DEBUG_PRINT((NULL, 0, "%s: not found\n"));
-        EngFreeMem(video_buff);
-        return FALSE;
-    }
-
-    vmi = *selected_mode;
-    EngFreeMem(video_buff);
-
-    pdev->video_mode_index = vmi.ModeIndex;
-    pdev->resolution.cx = vmi.VisScreenWidth;
-    pdev->resolution.cy = vmi.VisScreenHeight;
-    pdev->max_bitmap_size = pdev->resolution.cx * pdev->resolution.cy;
-    pdev->max_bitmap_size += pdev->max_bitmap_size / 2;
-    pdev->stride = vmi.ScreenStride;
-
-    *gdi_info = gdi_default;
-
-    gdi_info->ulHorzSize = vmi.XMillimeter;
-    gdi_info->ulVertSize = vmi.YMillimeter;
-    gdi_info->ulHorzRes = vmi.VisScreenWidth;
-    gdi_info->ulVertRes = vmi.VisScreenHeight;
-    gdi_info->cBitsPixel = vmi.BitsPerPlane;
-    gdi_info->cPlanes = vmi.NumberOfPlanes;
-    gdi_info->ulVRefresh = vmi.Frequency;
-    gdi_info->ulDACRed = vmi.NumberRedBits;
-    gdi_info->ulDACGreen = vmi.NumberGreenBits;
-    gdi_info->ulDACBlue = vmi.NumberBlueBits;
-    gdi_info->ulLogPixelsX = dev_mode->dmLogPixels;
-    gdi_info->ulLogPixelsY = dev_mode->dmLogPixels;
-
-    *dev_info = dev_default;
-
-    switch ( vmi.BitsPerPlane ) {
-    case 16:
-        pdev->bitmap_format = BMF_16BPP;
-        pdev->red_mask = vmi.RedMask;
-        pdev->green_mask = vmi.GreenMask;
-        pdev->blue_mask = vmi.BlueMask;
-
-        gdi_info->ulNumColors = (ULONG)-1;
-        gdi_info->ulNumPalReg = 0;
-        gdi_info->ulHTOutputFormat = HT_FORMAT_16BPP;
-
-        dev_info->iDitherFormat = BMF_16BPP;
-        break;
-    case 32:
-        pdev->bitmap_format = BMF_32BPP;
-        pdev->red_mask = vmi.RedMask;
-        pdev->green_mask = vmi.GreenMask;
-        pdev->blue_mask = vmi.BlueMask;
-
-        gdi_info->ulNumColors = (ULONG)-1;
-        gdi_info->ulNumPalReg = 0;
-        gdi_info->ulHTOutputFormat = HT_FORMAT_32BPP;
-
-        dev_info->iDitherFormat = BMF_32BPP;
-        break;
-    default:
-        DEBUG_PRINT((NULL, 0, "%s: bit depth not supported\n", __FUNCTION__));
-        return FALSE;
-    }
-    DEBUG_PRINT((NULL, 1, "%s: exit\n", __FUNCTION__));
-    return TRUE;
-}
-
-void DestroyPalette(PDev *pdev)
-{
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-    if (pdev->palette) {
-        EngDeletePalette(pdev->palette);
-        pdev->palette = NULL;
-    }
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-}
-
-BOOL InitPalette(PDev *pdev, DEVINFO *dev_info)
-{
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    if ((pdev->palette = EngCreatePalette(PAL_BITFIELDS, 0, NULL,
-                                          pdev->red_mask,
-                                          pdev->green_mask,
-                                          pdev->blue_mask)) == NULL) {
-        DEBUG_PRINT((NULL, 0, "%s: create palette failed\n", __FUNCTION__));
-        return FALSE;
-    }
-    dev_info->hpalDefault = pdev->palette;
-
-    DEBUG_PRINT((NULL, 1, "%s: OK\n", __FUNCTION__));
-    return TRUE;
-}
-
-DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ignore3,
-                     ULONG dev_caps_size, ULONG *dev_caps, ULONG dev_inf_size,
-                     DEVINFO *in_dev_info, HDEV gdi_dev, PWSTR device_name, HANDLE driver)
-{
-    PDev *pdev;
-    GDIINFO gdi_info;
-    DEVINFO dev_info;
-
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-
-    if (!(pdev = (PDev*)EngAllocMem(FL_ZERO_MEMORY, sizeof(PDev), ALLOC_TAG))) {
-        DEBUG_PRINT((NULL, 0, "%s: pdev alloc failed\n", __FUNCTION__));
-        return NULL;
-    }
-
-    RtlZeroMemory(&gdi_info, sizeof(GDIINFO));
-    RtlCopyMemory(&gdi_info, dev_caps, MIN(dev_caps_size, sizeof(GDIINFO)));
-
-    RtlZeroMemory(&dev_info, sizeof(DEVINFO));
-    RtlCopyMemory(&dev_info, in_dev_info, MIN(dev_inf_size, sizeof(DEVINFO)));
-
-    pdev->driver = driver;
-
-    if (!InitializeModeFields(pdev, &gdi_info, &dev_info, dev_mode)) {
-        DEBUG_PRINT((NULL, 0, "%s: init mode failed\n", __FUNCTION__));
-        goto err1;
-    }
-
-    if (!InitPalette(pdev, &dev_info)) {
-        DEBUG_PRINT((NULL, 0, "%s: init palet failed\n", __FUNCTION__));
-        goto err1;
-    }
-
-    if (!ResInit(pdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: init res failed\n", __FUNCTION__));
-        goto err2;
-    }
-
-    RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
-    RtlCopyMemory(in_dev_info, &dev_info, dev_inf_size);
-
-    pdev->enabled = TRUE; /* assume no operations before a DrvEnablePDEV. */
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-    return(DHPDEV)pdev;
-
-err2:
-    DestroyPalette(pdev);
-
-err1:
-    EngFreeMem(pdev);
-
-    return NULL;
-}
-
-#ifdef DBG
-static void DebugCountAliveSurfaces(PDev *pdev)
-{
-    UINT32 i;
-    SurfaceInfo *surface_info;
-    int total = 0;
-    int of_pdev = 0;
-    int no_surf_obj = 0;
-
-    for (i = 0 ; i < pdev->n_surfaces; ++i) {
-        surface_info = GetSurfaceInfo(pdev, i);
-        if (surface_info->draw_area.base_mem != NULL) {
-            total++;
-            // all should belong to the same pdev
-            if (surface_info->u.pdev == pdev) {
-                of_pdev++;
-                if (surface_info->draw_area.surf_obj == NULL) {
-                    no_surf_obj++;
-                }
-            }
-        }
-    }
-    DEBUG_PRINT((pdev, 1, "%s: %p: %d / %d / %d (total,pdev,no_surf_obj)\n", __FUNCTION__, pdev,
-                total, of_pdev, no_surf_obj));
-}
-#else
-static void DebugCountAliveSurfaces(PDev *pdev)
-{
-}
-#endif
-
-VOID DrvDisablePDEV(DHPDEV in_pdev)
-{
-    PDev* pdev = (PDev*)in_pdev;
-
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-    ResDestroy(pdev);
-    DestroyPalette(pdev);
-    EngFreeMem(pdev);
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-}
-
-VOID DrvCompletePDEV(DHPDEV in_pdev, HDEV gdi_dev)
-{
-    PDev* pdev = (PDev*)in_pdev;
-
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-    pdev->eng = gdi_dev;
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-}
-
-static VOID HideMouse(PDev *pdev)
-{
-    QXLCursorCmd *cursor_cmd;
-
-    cursor_cmd = CursorCmd(pdev);
-    cursor_cmd->type = QXL_CURSOR_HIDE;
-
-    PushCursorCmd(pdev, cursor_cmd);
-}
-
-static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
-                                 UINT32 width, UINT32 height, INT32 stride,
-                                 QXLPHYSICAL phys_mem)
-{
-    pdev->primary_surface_create->format = format;
-    pdev->primary_surface_create->width = width;
-    pdev->primary_surface_create->height = height;
-    pdev->primary_surface_create->stride = -stride;
-    pdev->primary_surface_create->mem = phys_mem;
-
-    pdev->primary_surface_create->flags = 0;
-    pdev->primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
-
-    async_io(pdev, ASYNCABLE_CREATE_PRIMARY, 0);
-}
-
-static void DestroyPrimarySurface(PDev *pdev, int hide_mouse)
-{
-    if (hide_mouse) {
-        HideMouse(pdev);
-    }
-    async_io(pdev, ASYNCABLE_DESTROY_PRIMARY, 0);
-}
-
-static void DestroyAllSurfaces(PDev *pdev)
-{
-    HideMouse(pdev);
-    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
-}
-
-BOOL SetHardwareMode(PDev *pdev)
-{
-    VIDEO_MODE_INFORMATION video_info;
-    DWORD length;
-
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx mode %lu\n", __FUNCTION__, pdev, pdev->video_mode_index));
-
-    if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_SET_CURRENT_MODE,
-                           &pdev->video_mode_index, sizeof(DWORD),
-                           NULL, 0, &length)) {
-        DEBUG_PRINT((NULL, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx OK\n", __FUNCTION__, pdev));
-    return TRUE;
-}
-
-static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
-{
-    QXLPHYSICAL high_bits;
-
-
-    pdev->mem_slots[pdev->main_mem_slot].slot = *slot;
-
-    high_bits = pdev->main_mem_slot << pdev->slot_gen_bits;
-    high_bits |= slot->generation;
-    high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
-    pdev->mem_slots[pdev->main_mem_slot].high_bits = high_bits;
-
-    pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
-}
-
-static void RemoveVRamSlot(PDev *pdev)
-{
-    sync_io(pdev, pdev->memslot_del_port, pdev->vram_mem_slot);
-    pdev->vram_slot_initialized = FALSE;
-}
-
-static BOOLEAN CreateVRamSlot(PDev *pdev)
-{
-    QXLMemSlot *slot;
-    UINT64 high_bits;
-    UINT8 slot_id = pdev->main_mem_slot + 1;
-
-    if (slot_id >= pdev->num_mem_slot) {
-        return FALSE;
-    }
-
-    pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
-
-
-    *pdev->ram_slot_start = pdev->fb_phys;
-    *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
-
-    async_io(pdev, ASYNCABLE_MEMSLOT_ADD, slot_id);
-
-    pdev->vram_mem_slot = slot_id;
-
-    pdev->mem_slots[slot_id].slot.generation = *pdev->slots_generation;
-    pdev->mem_slots[slot_id].slot.start_phys_addr = pdev->fb_phys;
-    pdev->mem_slots[slot_id].slot.end_phys_addr = pdev->fb_phys + pdev->fb_size;
-    pdev->mem_slots[slot_id].slot.start_virt_addr = (UINT64)pdev->fb;
-    pdev->mem_slots[slot_id].slot.end_virt_addr = (UINT64)pdev->fb + pdev->fb_size;
-
-    high_bits = slot_id << pdev->slot_gen_bits;
-    high_bits |= pdev->mem_slots[slot_id].slot.generation;
-    high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
-    pdev->mem_slots[slot_id].high_bits = high_bits;
-
-    pdev->vram_slot_initialized = TRUE;
-
-    return TRUE;
-}
-
-static BOOL PrepareHardware(PDev *pdev)
-{
-    VIDEO_MEMORY video_mem;
-    VIDEO_MEMORY_INFORMATION video_mem_Info;
-    DWORD length;
-    QXLDriverInfo dev_info;
-    QXLPHYSICAL high_bits;
-
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    if (!SetHardwareMode(pdev)) {
-        DEBUG_PRINT((pdev, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-
-    if (EngDeviceIoControl( pdev->driver, IOCTL_QXL_GET_INFO, NULL,
-                            0, &dev_info, sizeof(QXLDriverInfo), &length) ) {
-        DEBUG_PRINT((pdev, 0, "%s: get qxl info failed, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-
-    if (dev_info.version != QXL_DRIVER_INFO_VERSION) {
-        DEBUG_PRINT((pdev, 0, "%s: get qxl info mismatch, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-
-    pdev->pci_revision = dev_info.pci_revision;
-    pdev->use_async = (pdev->pci_revision >= QXL_REVISION_STABLE_V10);
-    pdev->cmd_ring = dev_info.cmd_ring;
-    pdev->cursor_ring = dev_info.cursor_ring;
-    pdev->release_ring = dev_info.release_ring;
-    pdev->notify_cmd_port = dev_info.notify_cmd_port;
-    pdev->notify_cursor_port = dev_info.notify_cursor_port;
-    pdev->notify_oom_port = dev_info.notify_oom_port;
-
-    pdev->asyncable[ASYNCABLE_UPDATE_AREA][ASYNC] = dev_info.update_area_async_port;
-    pdev->asyncable[ASYNCABLE_UPDATE_AREA][SYNC] = dev_info.update_area_port;
-    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][ASYNC] = dev_info.memslot_add_async_port;
-    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][SYNC] = dev_info.memslot_add_port;
-    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][ASYNC] = dev_info.create_primary_async_port;
-    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][SYNC] = dev_info.create_primary_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][ASYNC] = dev_info.destroy_primary_async_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][SYNC] = dev_info.destroy_primary_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][ASYNC] = dev_info.destroy_surface_async_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][SYNC] = dev_info.destroy_surface_wait_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][ASYNC] = dev_info.destroy_all_surfaces_async_port;
-    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][SYNC] = dev_info.destroy_all_surfaces_port;
-    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][ASYNC] = dev_info.flush_surfaces_async_port;
-    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][SYNC] = NULL;
-
-    pdev->display_event = dev_info.display_event;
-    pdev->cursor_event = dev_info.cursor_event;
-    pdev->sleep_event = dev_info.sleep_event;
-    pdev->io_cmd_event = dev_info.io_cmd_event;
-#if (WINVER < 0x0501)
-    pdev->WaitForEvent = dev_info.WaitForEvent;
-#endif
-
-    pdev->num_io_pages = dev_info.num_pages;
-    pdev->io_pages_virt = dev_info.io_pages_virt;
-    pdev->io_pages_phys = dev_info.io_pages_phys;
-
-    pdev->dev_update_id = dev_info.update_id;
-
-    pdev->update_area = dev_info.update_area;
-    pdev->update_surface = dev_info.update_surface;
-
-    pdev->mm_clock = dev_info.mm_clock;
-
-    pdev->compression_level = dev_info.compression_level;
-
-    pdev->log_port = dev_info.log_port;
-    pdev->log_buf = dev_info.log_buf;
-    pdev->log_level = dev_info.log_level;
-
-    pdev->n_surfaces = dev_info.n_surfaces;
-
-    pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
-                                  ALLOC_TAG);
-    if (!pdev->mem_slots) {
-        DEBUG_PRINT((pdev, 0, "%s: mem slots alloc failed, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-
-    pdev->slots_generation = dev_info.slots_generation;
-    pdev->ram_slot_start = dev_info.ram_slot_start;
-    pdev->ram_slot_end = dev_info.ram_slot_end;
-    pdev->slot_id_bits = dev_info.slot_id_bits;
-    pdev->slot_gen_bits = dev_info.slot_gen_bits;
-    pdev->main_mem_slot = dev_info.main_mem_slot_id;
-    pdev->num_mem_slot = dev_info.num_mem_slot;
-
-    UpdateMainSlot(pdev, &dev_info.main_mem_slot);
-
-    video_mem.RequestedVirtualAddress = NULL;
-
-    if (EngDeviceIoControl( pdev->driver, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &video_mem,
-                            sizeof(VIDEO_MEMORY), &video_mem_Info,
-                            sizeof(video_mem_Info), &length) ) {
-        DEBUG_PRINT((pdev, 0, "%s: mapping failed, 0x%lx\n", __FUNCTION__, pdev));
-        return FALSE;
-    }
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx vals 0x%lx %ul\n", __FUNCTION__, pdev,
-                 video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
-    pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
-    pdev->fb_size = video_mem_Info.FrameBufferLength;
-    pdev->fb_phys = dev_info.fb_phys;
-
-    pdev->memslot_del_port = dev_info.memslot_del_port;
-
-    pdev->flush_release_port = dev_info.flush_release_port;
-
-    pdev->primary_memory_start = dev_info.surface0_area;
-    pdev->primary_memory_size = dev_info.surface0_area_size;
-
-    pdev->primary_surface_create = dev_info.primary_surface_create;
-
-    pdev->dev_id = dev_info.dev_id;
-
-    pdev->create_non_primary_surfaces = dev_info.create_non_primary_surfaces;
-    DEBUG_PRINT((pdev, 1, "%s: create_non_primary_surfaces = %d\n", __FUNCTION__,
-                 pdev->create_non_primary_surfaces));
-
-    CreateVRamSlot(pdev);
-
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit: 0x%lx %ul\n", __FUNCTION__, pdev,
-                 pdev->fb, pdev->fb_size));
-    return TRUE;
-}
-
-static VOID UnmapFB(PDev *pdev)
-{
-    VIDEO_MEMORY video_mem;
-    DWORD length;
-
-    if (!pdev->fb) {
-        return;
-    }
-
-    video_mem.RequestedVirtualAddress = pdev->fb;
-    pdev->fb = 0;
-    pdev->fb_size = 0;
-    if (EngDeviceIoControl(pdev->driver,
-                           IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
-                           &video_mem,
-                           sizeof(video_mem),
-                           NULL,
-                           0,
-                           &length)) {
-        DEBUG_PRINT((NULL, 0, "%s: unmpap failed, 0x%lx\n", __FUNCTION__, pdev));
-    }
-}
-
-VOID EnableQXLPrimarySurface(PDev *pdev)
-{
-    UINT32 depth, format;
-
-    switch (pdev->bitmap_format) {
-        case BMF_8BPP:
-            PANIC(pdev, "bad formart type 8bpp\n");
-        case BMF_16BPP:
-            depth = 16;
-            format = SPICE_SURFACE_FMT_16_555;
-            break;
-        case BMF_24BPP:
-        case BMF_32BPP:
-            depth = 32;
-            format = SPICE_SURFACE_FMT_32_xRGB;
-            break;
-        default:
-            PANIC(pdev, "bad formart type\n");
-    };
-
-    CreatePrimarySurface(pdev, depth, format,
-                         pdev->resolution.cx, pdev->resolution.cy,
-                         pdev->stride, pdev->surf_phys);
-    pdev->surf_enable = TRUE;
-}
-
-HSURF DrvEnableSurface(DHPDEV in_pdev)
-{
-    PDev *pdev;
-    HSURF surf;
-    DWORD length;
-    QXLPHYSICAL phys_mem;
-    UINT8 *base_mem;
-
-    pdev = (PDev*)in_pdev;
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
-
-    if (!PrepareHardware(pdev)) {
-        return FALSE;
-    }
-    InitResources(pdev);
-
-    if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
-                                           &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
-        DEBUG_PRINT((pdev, 0, "%s: create device surface failed, 0x%lx\n",
-                     __FUNCTION__, pdev));
-        goto err;
-    }
-
-    DEBUG_PRINT((pdev, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
-                 "0x%lx, 0x%lx, %lu, NULL)\n",
-                 __FUNCTION__,
-                 surf,
-                 pdev->eng,
-                 pdev,
-                 pdev->fb,
-                 pdev->stride));
-
-    pdev->surf = surf;
-    pdev->surf_phys = phys_mem;
-    pdev->surf_base = base_mem;
-
-    EnableQXLPrimarySurface(pdev);
-
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-    return surf;
-
-err:
-    DrvDisableSurface((DHPDEV)pdev);
-    DEBUG_PRINT((pdev, 0, "%s: 0x%lx err\n", __FUNCTION__, pdev));
-    return NULL;
-}
-
-VOID DisableQXLPrimarySurface(PDev *pdev, int hide_mouse)
-{
-    DrawArea drawarea;
-
-    if (pdev->surf_enable) {
-        DestroyPrimarySurface(pdev, hide_mouse);
-        pdev->surf_enable = FALSE;
-    }
-}
-
-VOID DisableQXLAllSurfaces(PDev *pdev)
-{
-    DestroyAllSurfaces(pdev);
-}
-
-VOID DrvDisableSurface(DHPDEV in_pdev)
-{
-    PDev *pdev = (PDev*)in_pdev;
-    DrawArea drawarea;
-
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    // Don't destroy the primary - it's destroyed by destroy_all_surfaces
-    // at AssertModeDisable. Also, msdn specifically mentions DrvDisableSurface
-    // should not touch the hardware, that should be done just via DrvAssertMode
-    // (http://msdn.microsoft.com/en-us/library/ff556200%28VS.85%29.aspx)
-    pdev->surf_enable = FALSE;
-    UnmapFB(pdev);
-
-    if (pdev->surf) {
-        DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
-        EngDeleteSurface(pdev->surf);
-        pdev->surf = NULL;
-    }
-
-    if (pdev->mem_slots) {
-        EngFreeMem(pdev->mem_slots);
-        pdev->mem_slots = NULL;
-    }
-
-    DebugCountAliveSurfaces(pdev);
-    ClearResources(pdev);
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-}
-
-static void FlushSurfaces(PDev *pdev)
-{
-    UINT32 surface_id;
-    SurfaceInfo *surface_info;
-    SURFOBJ *surf_obj;
-    RECTL area = {0, 0, 0, 0};
-
-    if (pdev->pci_revision < QXL_REVISION_STABLE_V10) {
-        DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_SURFACES\n", __FUNCTION__));
-        for (surface_id = pdev->n_surfaces - 1; surface_id >  0 ; --surface_id) {
-            surface_info = GetSurfaceInfo(pdev, surface_id);
-
-            if (!surface_info->draw_area.base_mem) {
-                continue;
-            }
-            surf_obj = surface_info->draw_area.surf_obj;
-            if (!surf_obj) {
-                continue;
-            }
-            area.right = surf_obj->sizlBitmap.cx;
-            area.bottom = surf_obj->sizlBitmap.cy;
-            UpdateArea(pdev,&area, surface_id);
-        }
-    } else {
-        async_io(pdev, ASYNCABLE_FLUSH_SURFACES, 0);
-    }
-}
-
-static BOOL FlushRelease(PDev *pdev)
-{
-    if (pdev->pci_revision<  QXL_REVISION_STABLE_V10) {
-        DWORD length;
-
-        DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_RELEASE\n", __FUNCTION__));
-        if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_RESET_DEVICE,
-                               NULL, 0, NULL, 0, &length)) {
-            DEBUG_PRINT((NULL, 0, "%s: reset failed 0x%lx\n", __FUNCTION__, pdev));
-            return FALSE;
-        }
-    } else {
-        /* Free release ring contents */
-        ReleaseCacheDeviceMemoryResources(pdev);
-        EmptyReleaseRing(pdev);
-        /* Get the last free list onto the release ring */
-        sync_io(pdev, pdev->flush_release_port, 0);
-        DEBUG_PRINT((pdev, 4, "%s after FLUSH_RELEASE\n", __FUNCTION__));
-        /* And release that. mspace allocators should be clean after. */
-        EmptyReleaseRing(pdev);
-    }
-    return TRUE;
-}
-
-static BOOL AssertModeDisable(PDev *pdev)
-{
-    DEBUG_PRINT((pdev, 3, "%s entry\n", __FUNCTION__));
-    /* flush command ring and update all surfaces */
-    FlushSurfaces(pdev);
-    DebugCountAliveSurfaces(pdev);
-    /*
-     * this call is redundant for
-     * pci_revision <  QXL_REVISION_STABLE_V10, due to the
-     * IOCTL_VIDEO_RESET_DEVICE in FlushRelease. However,
-     * MoveAllSurfacesToRam depends on destroy_all_surfaces
-     * in case of failure.
-     * TODO: make MoveAllSurfacesToRam send destroy_surface
-     * commands instead of create_surface commands in case
-     * of failure
-     */
-    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
-    /* move all surfaces from device to system memory */
-    if (!MoveAllSurfacesToRam(pdev)) {
-        EnableQXLPrimarySurface(pdev);
-        return FALSE;
-    }
-    if (!FlushRelease(pdev)) {
-        return FALSE;
-    }
-    RemoveVRamSlot(pdev);
-    DebugCountAliveSurfaces(pdev);
-    DEBUG_PRINT((pdev, 4, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
-        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
-        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
-        pdev->release_ring->prod, pdev->release_ring->cons,
-        pdev->free_outputs));
-    DEBUG_PRINT((pdev, 3, "%s exit\n", __FUNCTION__));
-    return TRUE;
-}
-
-static void AssertModeEnable(PDev *pdev)
-{
-    InitDeviceMemoryResources(pdev);
-    DEBUG_PRINT((pdev, 3, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
-        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
-        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
-        pdev->release_ring->prod, pdev->release_ring->cons,
-        pdev->free_outputs));
-    EnableQXLPrimarySurface(pdev);
-    CreateVRamSlot(pdev);
-    DebugCountAliveSurfaces(pdev);
-    MoveAllSurfacesToVideoRam(pdev);
-    DebugCountAliveSurfaces(pdev);
-}
-
-BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
-{
-    PDev* pdev = (PDev*)in_pdev;
-    BOOL ret = TRUE;
-
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx revision %d enable %d\n", __FUNCTION__, pdev, pdev->pci_revision, enable));
-    if (pdev->enabled == enable) {
-        DEBUG_PRINT((pdev, 1, "%s: called twice with same argument (%d)\n", __FUNCTION__,
-            enable));
-        return TRUE;
-    }
-    pdev->enabled = enable;
-    if (enable) {
-        AssertModeEnable(pdev);
-    } else {
-        ret = AssertModeDisable(pdev);
-        if (!ret) {
-            pdev->enabled = !enable;
-        }
-    }
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
-    return ret;
-}
-
-ULONG DrvGetModes(HANDLE driver, ULONG dev_modes_size, DEVMODEW *dev_modes)
-{
-    PVIDEO_MODE_INFORMATION video_modes;
-    PVIDEO_MODE_INFORMATION curr_video_mode;
-    DWORD mode_size;
-    DWORD output_size;
-    DWORD n_modes;
-
-    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
-
-    n_modes = GetAvailableModes(driver, &video_modes, &mode_size);
-
-    if (!n_modes) {
-        DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
-        return 0;
-    }
-
-    if (!dev_modes) {
-        DEBUG_PRINT((NULL, 1, "%s: query size\n", __FUNCTION__));
-        output_size = n_modes * sizeof(DEVMODEW);
-        goto out;
-    }
-
-    if (dev_modes_size < n_modes * sizeof(DEVMODEW)) {
-        DEBUG_PRINT((NULL, 0, "%s: buf to small\n", __FUNCTION__));
-        output_size = 0;
-        goto out;
-    }
-
-    output_size = 0;
-    curr_video_mode = video_modes;
-    do {
-        if (curr_video_mode->Length != 0) {
-            RtlZeroMemory(dev_modes, sizeof(DEVMODEW));
-            ASSERT(NULL, sizeof(DEVICE_NAME) < sizeof(dev_modes->dmDeviceName));
-            RtlCopyMemory(dev_modes->dmDeviceName, DEVICE_NAME, sizeof(DEVICE_NAME));
-            dev_modes->dmSpecVersion = DM_SPECVERSION;
-            dev_modes->dmDriverVersion = DM_SPECVERSION;
-            dev_modes->dmSize = sizeof(DEVMODEW);
-            dev_modes->dmBitsPerPel =   curr_video_mode->NumberOfPlanes *
-                                        curr_video_mode->BitsPerPlane;
-            dev_modes->dmPelsWidth = curr_video_mode->VisScreenWidth;
-            dev_modes->dmPelsHeight = curr_video_mode->VisScreenHeight;
-            dev_modes->dmDisplayFrequency = curr_video_mode->Frequency;
-            dev_modes->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
-                                  DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
-#if (WINVER >= 0x0501)
-            dev_modes->dmDisplayOrientation = curr_video_mode->DriverSpecificAttributeFlags;
-            dev_modes->dmFields |= DM_DISPLAYORIENTATION;
-#endif
-
-            DEBUG_PRINT((NULL, 1, "%s: mode: w %u h %u bits %u frequency %u\n",
-                         __FUNCTION__,
-                         dev_modes->dmPelsWidth,
-                         dev_modes->dmPelsHeight,
-                         dev_modes->dmBitsPerPel,
-                         dev_modes->dmDisplayFrequency));
-#if (WINVER >= 0x0501)
-            DEBUG_PRINT((NULL, 1, "             orientation %u\n",
-                         dev_modes->dmDisplayOrientation));
-#endif
-            output_size += sizeof(DEVMODEW);
-            dev_modes++;
-        }
-        curr_video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)curr_video_mode) + mode_size);
-    } while (--n_modes);
-
-    out:
-
-    EngFreeMem(video_modes);
-    DEBUG_PRINT((NULL, 1, "%s: exit %u\n", __FUNCTION__, output_size));
-    return output_size;
-}
-
-VOID DrvSynchronize(DHPDEV in_pdev, RECTL *ignored)
-{
-    PDev* pdev = (PDev*)in_pdev;
-    int notify;
-
-    DEBUG_PRINT((pdev, 3, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    DEBUG_PRINT((pdev, 4, "%s: 0x%lx done\n", __FUNCTION__, pdev));
-}
-
-char *BitmapFormatToStr(int format)
-{
-    switch (format) {
-    case BMF_1BPP:
-        return  "BMF_1BPP";
-    case BMF_4BPP:
-        return "BMF_4BPP";
-    case BMF_8BPP:
-        return "BMF_8BPP";
-    case BMF_16BPP:
-        return "BMF_16BPP";
-    case BMF_24BPP:
-        return "BMF_24BPP";
-    case BMF_32BPP:
-        return "BMF_32BPP";
-    case BMF_4RLE:
-        return "BMF_4RLE";
-    case BMF_8RLE:
-        return "BMF_8RLE";
-    case BMF_JPEG:
-        return "BMF_JPEG";
-    case BMF_PNG:
-        return "BMF_PNG";
-    default:
-        return "?";
-    }
-}
-
-char *BitmapTypeToStr(int type)
-{
-    switch (type) {
-    case STYPE_BITMAP:
-        return  "STYPE_BITMAP";
-    case STYPE_DEVICE:
-        return "STYPE_DEVICE";
-    case STYPE_DEVBITMAP:
-        return "STYPE_DEVBITMAP";
-    default:
-        return "?";
-    }
-}
-
-#include "rop.h"
-#include "utils.h"
-#include "res.h"
-
-FIX FlotaToFixed(FLOATL val, FLOATL scale)
-{
-    FLOATOBJ float_obj;
-    FIX ret;
-
-    FLOATOBJ_SetFloat(&float_obj, val);
-    FLOATOBJ_MulFloat(&float_obj, scale);
-
-    ret = FLOATOBJ_GetLong(&float_obj) << 4;
-    FLOATOBJ_MulLong(&float_obj, 16);
-    ret |= (0x0f & FLOATOBJ_GetLong(&float_obj));
-    return ret;
-}
-
-static BOOL GetCosmeticAttr(PDev *pdev, QXLDrawable *drawable, QXLLineAttr *q_line_attr,
-                            LINEATTRS *line_attr)
-{
-    q_line_attr->join_style = JOIN_MITER;
-    q_line_attr->end_style = ENDCAP_BUTT;
-    q_line_attr->width = 1 << 4;
-    q_line_attr->miter_limit = 0;
-
-    if (line_attr->fl & LA_STYLED) {
-        PFLOAT_LONG src_style = line_attr->pstyle;
-        FIX *style;
-        FIX *end;
-        UINT32 nseg;
-
-        q_line_attr->flags = (UINT8)(line_attr->fl & (LA_STYLED | LA_STARTGAP));
-        nseg = (line_attr->fl & LA_ALTERNATE) ? 2 : line_attr->cstyle;
-        if ( nseg > 100) {
-            return FALSE;
-        }
-
-        if (!(style = (FIX *)QXLGetBuf(pdev, drawable, &q_line_attr->style,
-                                       nseg * sizeof(UINT32)))) {
-            return FALSE;
-        }
-
-        if (line_attr->fl & LA_ALTERNATE) {
-            style[0] = style[1] = 1 << 4;
-        } else {
-            for ( end = style + nseg;  style < end; style++, src_style++) {
-                *style = (*src_style).l << 4;
-            }
-        }
-        q_line_attr->style_nseg = (UINT8)nseg;
-    } else {
-        q_line_attr->flags = 0;
-        q_line_attr->style_nseg = 0;
-        q_line_attr->style = 0;
-    }
-    return TRUE;
-}
-
-BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOBJ *width_transform,
-                            BRUSHOBJ *brush, POINTL *brush_pos, LINEATTRS *line_attr,
-                            MIX mix /*rop*/)
-{
-    QXLDrawable *drawable;
-    RECTFX fx_area;
-    RECTL area;
-    PDev *pdev;
-    ROP3Info *fore_rop;
-    ROP3Info *back_rop;
-    BOOL h_or_v_line;
-
-    if (!(pdev = (PDev *)surf->dhpdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    PUNT_IF_DISABLED(pdev);
-
-    CountCall(pdev, CALL_COUNTER_STROKE_PATH);
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-    ASSERT(pdev, surf && path && line_attr && clip);
-
-
-    if (line_attr->fl & (LA_STYLED | LA_ALTERNATE | LA_GEOMETRIC)) { //for now
-        // punt back to GDI result in infinite recursion
-        //return EngStrokePath(surf, path, clip, width_transform, brush, brush_pos, line_attr, mix);
-    }
-
-    ASSERT(pdev, (line_attr->fl & LA_GEOMETRIC) == 0); /* We should not get these */
-
-    PATHOBJ_vGetBounds(path, &fx_area);
-    FXToRect(&area, &fx_area);
-
-    h_or_v_line = area.bottom == area.top + 1  || area.right == area.left + 1;
-
-    if (clip) {
-        if (clip->iDComplexity == DC_TRIVIAL) {
-            clip = NULL;
-        } else {
-            SectRect(&clip->rclBounds, &area, &area);
-            if (IsEmptyRect(&area)) {
-                DEBUG_PRINT((pdev, 1, "%s: empty rect after clip\n", __FUNCTION__));
-                return TRUE;
-            }
-        }
-    }
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip, GetSurfaceId(surf)))) {
-        return FALSE;
-    }
-
-    fore_rop = &rops2[(mix - 1) & 0x0f];
-    back_rop = &rops2[((mix >> 8) - 1) & 0x0f];
-
-    if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
-        drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
-    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos,
-                            &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
-        goto err;
-    }
-
-    if (!QXLGetPath(pdev, drawable, &drawable->u.stroke.path, path)) {
-        goto err;
-    }
-    // DrvStrokePath only draws foreground pixels, unless you support dotted
-    // lines, so you only care about the low-order byte.
-    drawable->u.stroke.fore_mode = fore_rop->method_data;
-    drawable->u.stroke.back_mode = back_rop->method_data;
-
-    drawable->effect = (h_or_v_line) ? QXL_EFFECT_OPAQUE: QXL_EFFECT_BLEND;
-
-    if (!GetCosmeticAttr(pdev, drawable, &drawable->u.stroke.attr, line_attr)) {
-        goto err;
-    }
-
-    if (drawable->u.stroke.attr.flags & LA_STYLED) {
-        drawable->effect = (fore_rop->effect == back_rop->effect) ? fore_rop->effect :
-                                                                                   QXL_EFFECT_BLEND;
-    } else {
-        drawable->effect = fore_rop->effect;
-    }
-
-    if (drawable->effect == QXL_EFFECT_OPAQUE && !h_or_v_line) {
-        drawable->effect = QXL_EFFECT_OPAQUE_BRUSH;
-    }
-
-    PushDrawable(pdev, drawable);
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-    return TRUE;
-
-err:
-    ReleaseOutput(pdev, drawable->release_info.id);
-    return FALSE;
-}
-
-HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
-{
-    PDev *pdev;
-    UINT8 *base_mem;
-    UINT32 surface_id;
-    QXLPHYSICAL phys_mem;
-    HBITMAP hbitmap;
-
-    pdev = (PDev *)dhpdev;
-
-    if (!pdev->create_non_primary_surfaces) {
-        return FALSE;
-    }
-
-    if (!pdev->vram_slot_initialized || pdev->bitmap_format != format || pdev->fb == 0) {
-        DEBUG_PRINT((pdev, 3, "%s failed: %p: slot_initialized %d, format(%d,%d), fb %p\n",
-                    __FUNCTION__, pdev, pdev->vram_slot_initialized,
-                    pdev->bitmap_format, format, pdev->fb));
-        return 0;
-    }
-
-    PUNT_IF_DISABLED(pdev);
-
-    surface_id = GetFreeSurface(pdev);
-    if (!surface_id) {
-        DEBUG_PRINT((pdev, 3, "%s:%p GetFreeSurface failed\n", __FUNCTION__, pdev));
-        goto out_error;
-    }
-    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
-
-    hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
-                                 DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
-    if (!hbitmap) {
-         DEBUG_PRINT((pdev, 3, "%s:%p CreateDeviceBitmap failed\n", __FUNCTION__, pdev));
-        goto out_error2;
-    }
-
-    return hbitmap;
-
-    // to optimize the failure case
-out_error2:
-    FreeSurfaceInfo(pdev, surface_id);
-out_error:
-    return 0;
-}
-
-VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
-{
-    UINT32 surface_id;
-    SurfaceInfo *surface;
-    PDev *pdev;
-
-    surface = (SurfaceInfo *)dhsurf;
-    surface_id = GetSurfaceIdFromInfo(surface);
-    pdev = surface->u.pdev;
-
-    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
-
-    ASSERT(pdev, surface_id < pdev->n_surfaces);
-
-    DeleteDeviceBitmap(surface->u.pdev, surface_id,
-                       surface->copy ? DEVICE_BITMAP_ALLOCATION_TYPE_RAM
-                                     : DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
-}
-
-#ifdef CALL_TEST
-
-void CountCall(PDev *pdev, int counter)
-{
-    if (pdev->count_calls) {
-        int i;
-
-        pdev->call_counters[counter]++;
-        if((++pdev->total_calls % 500) == 0) {
-            DEBUG_PRINT((pdev, 0, "total eng calls is %u\n", pdev->total_calls));
-            for (i = 0; i < NUM_CALL_COUNTERS; i++) {
-                DEBUG_PRINT((pdev, 0, "%s count is %u\n",
-                             counters_info[i].name, pdev->call_counters[i]));
-            }
-        }
-        pdev->count_calls = FALSE;
-    } else if (counters_info[counter].effective) {
-        pdev->count_calls = TRUE;
-    }
-}
-
-BOOL APIENTRY DrvFillPath(
-    SURFOBJ  *pso,
-    PATHOBJ  *ppo,
-    CLIPOBJ  *pco,
-    BRUSHOBJ *pbo,
-    POINTL   *pptlBrushOrg,
-    MIX       mix,
-    FLONG     flOptions)
-{
-    PDev *pdev;
-
-    pdev = (PDev *)pso->dhpdev;
-    CountCall(pdev, CALL_COUNTER_FILL_PATH);
-
-    return EngFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
-}
-
-BOOL APIENTRY DrvGradientFill(
-    SURFOBJ         *psoDest,
-    CLIPOBJ         *pco,
-    XLATEOBJ        *pxlo,
-    TRIVERTEX       *pVertex,
-    ULONG            nVertex,
-    PVOID            pMesh,
-    ULONG            nMesh,
-    RECTL           *prclExtents,
-    POINTL          *pptlDitherOrg,
-    ULONG            ulMode)
-{
-    PDev *pdev;
-
-    pdev = (PDev *)psoDest->dhpdev;
-    CountCall(pdev, CALL_COUNTER_GRADIENT_FILL);
-    return EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
-                           pptlDitherOrg, ulMode);
-}
-
-BOOL APIENTRY DrvLineTo(
-    SURFOBJ   *pso,
-    CLIPOBJ   *pco,
-    BRUSHOBJ  *pbo,
-    LONG       x1,
-    LONG       y1,
-    LONG       x2,
-    LONG       y2,
-    RECTL     *prclBounds,
-    MIX        mix)
-{
-    PDev *pdev;
-
-    pdev = (PDev *)pso->dhpdev;
-    CountCall(pdev, CALL_COUNTER_LINE_TO);
-    return EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
-}
-
-BOOL APIENTRY DrvPlgBlt(
-    SURFOBJ         *psoTrg,
-    SURFOBJ         *psoSrc,
-    SURFOBJ         *psoMsk,
-    CLIPOBJ         *pco,
-    XLATEOBJ        *pxlo,
-    COLORADJUSTMENT *pca,
-    POINTL          *pptlBrushOrg,
-    POINTFIX        *pptfx,
-    RECTL           *prcl,
-    POINTL          *pptl,
-    ULONG            iMode)
-{
-    if (psoSrc->iType == STYPE_BITMAP) {
-        PDev *pdev;
-
-        ASSERT(NULL, psoTrg && psoTrg->iType != STYPE_BITMAP && psoTrg->dhpdev);
-        pdev = (PDev *)psoTrg->dhpdev;
-        CountCall(pdev, CALL_COUNTER_PLG_BLT);
-    }
-    return EngPlgBlt(psoTrg, psoSrc, psoMsk, pco, pxlo, pca, pptlBrushOrg, pptfx, prcl, pptl,
-                     iMode);
-}
-
-BOOL APIENTRY DrvStrokeAndFillPath(
-    SURFOBJ   *pso,
-    PATHOBJ   *ppo,
-    CLIPOBJ   *pco,
-    XFORMOBJ  *pxo,
-    BRUSHOBJ  *pboStroke,
-    LINEATTRS *plineattrs,
-    BRUSHOBJ  *pboFill,
-    POINTL    *pptlBrushOrg,
-    MIX        mixFill,
-    FLONG      flOptions)
-{
-    PDev *pdev = (PDev *)pso->dhpdev;
-    CountCall(pdev, CALL_COUNTER_STROKE_AND_FILL_PATH);
-    return EngStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, plineattrs, pboFill, pptlBrushOrg,
-                                mixFill, flOptions);
-}
-
-#endif
diff --git a/display/driver.rc b/display/driver.rc
deleted file mode 100644
index f11c9db..0000000
--- a/display/driver.rc
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <windows.h>
-
-#include <ntverp.h>
-
-#define VER_FILETYPE                VFT_DRV
-#define VER_FILESUBTYPE             VFT2_DRV_DISPLAY
-
-#undef  VER_COMPANYNAME_STR
-#undef  VER_FILEVERSION_STR
-#undef  VER_LEGALCOPYRIGHT_STR
-#undef  VER_LEGALCOPYRIGHT_YEARS
-#undef  VER_PRODUCTNAME_STR
-#undef  VER_PRODUCTVERSION_STR
-
-
-#define VER_FILEDESCRIPTION_STR     "Red Hat QXL Display Driver"
-#define VER_INTERNALNAME_STR        "qxldd.dll"
-#define VER_ORIGINALFILENAME_STR    VER_INTERNALNAME_STR
-#define VER_FILEVERSION_STR         "1.4.2.3"
-#define VER_PRODUCTNAME_STR         "Spice"
-#define VER_PRODUCTVERSION_STR      VER_FILEVERSION_STR
-
-#undef  VER_PRODUCTVERSION
-#define VER_PRODUCTVERSION           1,4,2,3
-
-#define VER_COMPANYNAME_STR         "Red Hat Inc."
-#define VER_LEGALCOPYRIGHT_STR      "© Red Hat Inc. All rights reserved."
-
-#include "common.ver"
diff --git a/display/makefile b/display/makefile
deleted file mode 100644
index 53b9a3d..0000000
--- a/display/makefile
+++ /dev/null
@@ -1 +0,0 @@
-!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/display/mspace.c b/display/mspace.c
deleted file mode 100644
index d0ba123..0000000
--- a/display/mspace.c
+++ /dev/null
@@ -1,2437 +0,0 @@
-// based on dlmalloc from Doug Lea
-
-
-// quote from the Doug Lea original file
-    /*
-      This is a version (aka dlmalloc) of malloc/free/realloc written by
-      Doug Lea and released to the public domain, as explained at
-      http://creativecommons.org/licenses/publicdomain.  Send questions,
-      comments, complaints, performance data, etc to dl at cs.oswego.edu
-
-    * Version 2.8.3 Thu Sep 22 11:16:15 2005  Doug Lea  (dl at gee)
-
-       Note: There may be an updated version of this malloc obtainable at
-               ftp://gee.cs.oswego.edu/pub/misc/malloc.c
-             Check before installing!
-    */
-
-
-#include <ntddk.h>
-
-#include "mspace.h"
-
-#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
-
-#define MALLOC_ALIGNMENT ((size_t)8U)
-#define USE_LOCKS 0
-#define malloc_getpagesize ((size_t)4096U)
-#define DEFAULT_GRANULARITY malloc_getpagesize
-#define MAX_SIZE_T (~(size_t)0)
-#define MALLOC_FAILURE_ACTION
-#define MALLINFO_FIELD_TYPE size_t
-#define FOOTERS 0
-#define INSECURE 0
-#define PROCEED_ON_ERROR 0
-#define DEBUG 0
-#define ABORT_ON_ASSERT_FAILURE 1
-#define ABORT(user_data) abort_func(user_data)
-#define USE_BUILTIN_FFS 0
-#define USE_DEV_RANDOM 0
-#define PRINT(params) print_func params
-
-
-#define MEMCPY(dest, src, n) RtlCopyMemory(dest, src, n)
-#define MEMCLEAR(dest, n) RtlZeroMemory(dest, n)
-
-
-#define M_GRANULARITY        (-1)
-
-void default_abort_func(void *user_data)
-{
-    for (;;);
-}
-
-void default_print_func(void *user_data, char *format, ...)
-{
-}
-
-static mspace_abort_t abort_func = default_abort_func;
-static mspace_print_t print_func = default_print_func;
-
-void mspace_set_abort_func(mspace_abort_t f)
-{
-    abort_func = f;
-}
-
-void mspace_set_print_func(mspace_print_t f)
-{
-    print_func = f;
-}
-
-/* ------------------------ Mallinfo declarations ------------------------ */
-
-#if !NO_MALLINFO
-/*
-  This version of malloc supports the standard SVID/XPG mallinfo
-  routine that returns a struct containing usage properties and
-  statistics. It should work on any system that has a
-  /usr/include/malloc.h defining struct mallinfo.  The main
-  declaration needed is the mallinfo struct that is returned (by-copy)
-  by mallinfo().  The malloinfo struct contains a bunch of fields that
-  are not even meaningful in this version of malloc.  These fields are
-  are instead filled by mallinfo() with other numbers that might be of
-  interest.
-
-  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
-  /usr/include/malloc.h file that includes a declaration of struct
-  mallinfo.  If so, it is included; else a compliant version is
-  declared below.  These must be precisely the same for mallinfo() to
-  work.  The original SVID version of this struct, defined on most
-  systems with mallinfo, declares all fields as ints. But some others
-  define as unsigned long. If your system defines the fields using a
-  type of different width than listed here, you MUST #include your
-  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
-*/
-
-/* #define HAVE_USR_INCLUDE_MALLOC_H */
-
-
-struct mallinfo {
-  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
-  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
-  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
-  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
-  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
-  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
-  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
-  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
-  MALLINFO_FIELD_TYPE fordblks; /* total free space */
-  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-
-#endif /* NO_MALLINFO */
-
-
-
-#ifdef DEBUG
-#if ABORT_ON_ASSERT_FAILURE
-#define assert(user_data, x) if(!(x)) ABORT(user_data)
-#else /* ABORT_ON_ASSERT_FAILURE */
-#include <assert.h>
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#else  /* DEBUG */
-#define assert(user_data, x)
-#endif /* DEBUG */
-
-/* ------------------- size_t and alignment properties -------------------- */
-
-/* The byte and bit size of a size_t */
-#define SIZE_T_SIZE         (sizeof(size_t))
-#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
-
-/* Some constants coerced to size_t */
-/* Annoying but necessary to avoid errors on some plaftorms */
-#define SIZE_T_ZERO         ((size_t)0)
-#define SIZE_T_ONE          ((size_t)1)
-#define SIZE_T_TWO          ((size_t)2)
-#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
-#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
-#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
-#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
-
-/* The bit mask value corresponding to MALLOC_ALIGNMENT */
-#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
-
-/* True if address a has acceptable alignment */
-#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
-
-/* the number of bytes to offset an address to align it */
-#define align_offset(A)\
- ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
-  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
-
-/* --------------------------- Lock preliminaries ------------------------ */
-
-#if USE_LOCKS
-
-/*
-  When locks are defined, there are up to two global locks:
-
-  * If HAVE_MORECORE, morecore_mutex protects sequences of calls to
-    MORECORE.  In many cases sys_alloc requires two calls, that should
-    not be interleaved with calls by other threads.  This does not
-    protect against direct calls to MORECORE by other threads not
-    using this lock, so there is still code to cope the best we can on
-    interference.
-
-  * magic_init_mutex ensures that mparams.magic and other
-    unique mparams values are initialized only once.
-*/
-
-
-#define USE_LOCK_BIT               (2U)
-#else  /* USE_LOCKS */
-#define USE_LOCK_BIT               (0U)
-#define INITIAL_LOCK(l)
-#endif /* USE_LOCKS */
-
-#if USE_LOCKS
-#define ACQUIRE_MAGIC_INIT_LOCK()  ACQUIRE_LOCK(&magic_init_mutex);
-#define RELEASE_MAGIC_INIT_LOCK()  RELEASE_LOCK(&magic_init_mutex);
-#else  /* USE_LOCKS */
-#define ACQUIRE_MAGIC_INIT_LOCK()
-#define RELEASE_MAGIC_INIT_LOCK()
-#endif /* USE_LOCKS */
-
-
-
-/* -----------------------  Chunk representations ------------------------ */
-
-/*
-  (The following includes lightly edited explanations by Colin Plumb.)
-
-  The malloc_chunk declaration below is misleading (but accurate and
-  necessary).  It declares a "view" into memory allowing access to
-  necessary fields at known offsets from a given base.
-
-  Chunks of memory are maintained using a `boundary tag' method as
-  originally described by Knuth.  (See the paper by Paul Wilson
-  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
-  techniques.)  Sizes of free chunks are stored both in the front of
-  each chunk and at the end.  This makes consolidating fragmented
-  chunks into bigger chunks fast.  The head fields also hold bits
-  representing whether chunks are free or in use.
-
-  Here are some pictures to make it clearer.  They are "exploded" to
-  show that the state of a chunk can be thought of as extending from
-  the high 31 bits of the head field of its header through the
-  prev_foot and PINUSE_BIT bit of the following chunk header.
-
-  A chunk that's in use looks like:
-
-   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-           | Size of previous chunk (if P = 1)                             |
-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
-         | Size of this chunk                                         1| +-+
-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         |                                                               |
-         +-                                                             -+
-         |                                                               |
-         +-                                                             -+
-         |                                                               :
-         +-      size - sizeof(size_t) available payload bytes          -+
-         :                                                               |
- chunk-> +-                                                             -+
-         |                                                               |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
-       | Size of next chunk (may or may not be in use)               | +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-    And if it's free, it looks like this:
-
-   chunk-> +-                                                             -+
-           | User payload (must be in use, or we would have merged!)       |
-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
-         | Size of this chunk                                         0| +-+
-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Next pointer                                                  |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Prev pointer                                                  |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         |                                                               :
-         +-      size - sizeof(struct chunk) unused bytes               -+
-         :                                                               |
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Size of this chunk                                            |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
-       | Size of next chunk (must be in use, or we would have merged)| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                                                               :
-       +- User payload                                                -+
-       :                                                               |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-                                                                     |0|
-                                                                     +-+
-  Note that since we always merge adjacent free chunks, the chunks
-  adjacent to a free chunk must be in use.
-
-  Given a pointer to a chunk (which can be derived trivially from the
-  payload pointer) we can, in O(1) time, find out whether the adjacent
-  chunks are free, and if so, unlink them from the lists that they
-  are on and merge them with the current chunk.
-
-  Chunks always begin on even word boundaries, so the mem portion
-  (which is returned to the user) is also on an even word boundary, and
-  thus at least double-word aligned.
-
-  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
-  chunk size (which is always a multiple of two words), is an in-use
-  bit for the *previous* chunk.  If that bit is *clear*, then the
-  word before the current chunk size contains the previous chunk
-  size, and can be used to find the front of the previous chunk.
-  The very first chunk allocated always has this bit set, preventing
-  access to non-existent (or non-owned) memory. If pinuse is set for
-  any given chunk, then you CANNOT determine the size of the
-  previous chunk, and might even get a memory addressing fault when
-  trying to do so.
-
-  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
-  the chunk size redundantly records whether the current chunk is
-  inuse. This redundancy enables usage checks within free and realloc,
-  and reduces indirection when freeing and consolidating chunks.
-
-  Each freshly allocated chunk must have both cinuse and pinuse set.
-  That is, each allocated chunk borders either a previously allocated
-  and still in-use chunk, or the base of its memory arena. This is
-  ensured by making all allocations from the the `lowest' part of any
-  found chunk.  Further, no free chunk physically borders another one,
-  so each free chunk is known to be preceded and followed by either
-  inuse chunks or the ends of memory.
-
-  Note that the `foot' of the current chunk is actually represented
-  as the prev_foot of the NEXT chunk. This makes it easier to
-  deal with alignments etc but can be very confusing when trying
-  to extend or adapt this code.
-
-  The exceptions to all this are
-
-     1. The special chunk `top' is the top-most available chunk (i.e.,
-        the one bordering the end of available memory). It is treated
-        specially.  Top is never included in any bin, is used only if
-        no other chunk is available, and is released back to the
-        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
-        the top chunk is treated as larger (and thus less well
-        fitting) than any other available chunk.  The top chunk
-        doesn't update its trailing size field since there is no next
-        contiguous chunk that would have to index off it. However,
-        space is still allocated for it (TOP_FOOT_SIZE) to enable
-        separation or merging when space is extended.
-
-     3. Chunks allocated via mmap, which have the lowest-order bit
-        (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
-        PINUSE_BIT in their head fields.  Because they are allocated
-        one-by-one, each must carry its own prev_foot field, which is
-        also used to hold the offset this chunk has within its mmapped
-        region, which is needed to preserve alignment. Each mmapped
-        chunk is trailed by the first two fields of a fake next-chunk
-        for sake of usage checks.
-
-*/
-
-struct malloc_chunk {
-  size_t               prev_foot;  /* Size of previous chunk (if free).  */
-  size_t               head;       /* Size and inuse bits. */
-  struct malloc_chunk* fd;         /* double links -- used only if free. */
-  struct malloc_chunk* bk;
-};
-
-typedef struct malloc_chunk  mchunk;
-typedef struct malloc_chunk* mchunkptr;
-typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
-typedef unsigned int bindex_t;         /* Described below */
-typedef unsigned int binmap_t;         /* Described below */
-typedef unsigned int flag_t;           /* The type of various bit flag sets */
-
-
-/* ------------------- Chunks sizes and alignments ----------------------- */
-
-#define MCHUNK_SIZE         (sizeof(mchunk))
-
-#if FOOTERS
-#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
-#else /* FOOTERS */
-#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
-#endif /* FOOTERS */
-
-/* The smallest size we can malloc is an aligned minimal chunk */
-#define MIN_CHUNK_SIZE\
-  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* conversion from malloc headers to user pointers, and back */
-#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
-#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
-/* chunk associated with aligned address A */
-#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
-
-/* Bounds on request (not chunk) sizes. */
-#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
-#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
-
-/* pad request bytes into a usable size */
-#define pad_request(req) \
-   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* pad request, checking for minimum (but not maximum) */
-#define request2size(req) \
-  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
-
-/* ------------------ Operations on head and foot fields ----------------- */
-
-/*
-  The head field of a chunk is or'ed with PINUSE_BIT when previous
-  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
-  use. If the chunk was obtained with mmap, the prev_foot field has
-  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
-  mmapped region to the base of the chunk.
-*/
-
-#define PINUSE_BIT          (SIZE_T_ONE)
-#define CINUSE_BIT          (SIZE_T_TWO)
-#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
-
-/* Head value for fenceposts */
-#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
-
-/* extraction of fields from head words */
-#define cinuse(p)           ((p)->head & CINUSE_BIT)
-#define pinuse(p)           ((p)->head & PINUSE_BIT)
-#define chunksize(p)        ((p)->head & ~(INUSE_BITS))
-
-#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
-#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)
-
-/* Treat space at ptr +/- offset as a chunk */
-#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
-#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
-
-/* Ptr to next or previous physical malloc_chunk. */
-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))
-#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
-
-/* extract next chunk's pinuse bit */
-#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
-
-/* Get/set size at footer */
-#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
-#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
-
-/* Set size, pinuse bit, and foot */
-#define set_size_and_pinuse_of_free_chunk(p, s)\
-  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
-
-/* Set size, pinuse bit, foot, and clear next pinuse */
-#define set_free_with_pinuse(p, s, n)\
-  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
-
-/* Get the internal overhead associated with chunk p */
-#define overhead_for(p) CHUNK_OVERHEAD
-
-/* Return true if malloced space is not necessarily cleared */
-#define calloc_must_clear(p) (1)
-
-
-/* ---------------------- Overlaid data structures ----------------------- */
-
-/*
-  When chunks are not in use, they are treated as nodes of either
-  lists or trees.
-
-  "Small"  chunks are stored in circular doubly-linked lists, and look
-  like this:
-
-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Size of previous chunk                            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `head:' |             Size of chunk, in bytes                         |P|
-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Forward pointer to next chunk in list             |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Back pointer to previous chunk in list            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Unused space (may be 0 bytes long)                .
-            .                                                               .
-            .                                                               |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `foot:' |             Size of chunk, in bytes                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-  Larger chunks are kept in a form of bitwise digital trees (aka
-  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
-  free chunks greater than 256 bytes, their size doesn't impose any
-  constraints on user chunk sizes.  Each node looks like:
-
-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Size of previous chunk                            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `head:' |             Size of chunk, in bytes                         |P|
-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Forward pointer to next chunk of same size        |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Back pointer to previous chunk of same size       |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to left child (child[0])                  |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to right child (child[1])                 |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to parent                                 |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             bin index of this chunk                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Unused space                                      .
-            .                                                               |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `foot:' |             Size of chunk, in bytes                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
-  of the same size are arranged in a circularly-linked list, with only
-  the oldest chunk (the next to be used, in our FIFO ordering)
-  actually in the tree.  (Tree members are distinguished by a non-null
-  parent pointer.)  If a chunk with the same size an an existing node
-  is inserted, it is linked off the existing node using pointers that
-  work in the same way as fd/bk pointers of small chunks.
-
-  Each tree contains a power of 2 sized range of chunk sizes (the
-  smallest is 0x100 <= x < 0x180), which is is divided in half at each
-  tree level, with the chunks in the smaller half of the range (0x100
-  <= x < 0x140 for the top nose) in the left subtree and the larger
-  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
-  done by inspecting individual bits.
-
-  Using these rules, each node's left subtree contains all smaller
-  sizes than its right subtree.  However, the node at the root of each
-  subtree has no particular ordering relationship to either.  (The
-  dividing line between the subtree sizes is based on trie relation.)
-  If we remove the last chunk of a given size from the interior of the
-  tree, we need to replace it with a leaf node.  The tree ordering
-  rules permit a node to be replaced by any leaf below it.
-
-  The smallest chunk in a tree (a common operation in a best-fit
-  allocator) can be found by walking a path to the leftmost leaf in
-  the tree.  Unlike a usual binary tree, where we follow left child
-  pointers until we reach a null, here we follow the right child
-  pointer any time the left one is null, until we reach a leaf with
-  both child pointers null. The smallest chunk in the tree will be
-  somewhere along that path.
-
-  The worst case number of steps to add, find, or remove a node is
-  bounded by the number of bits differentiating chunks within
-  bins. Under current bin calculations, this ranges from 6 up to 21
-  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
-  is of course much better.
-*/
-
-struct malloc_tree_chunk {
-  /* The first four fields must be compatible with malloc_chunk */
-  size_t                    prev_foot;
-  size_t                    head;
-  struct malloc_tree_chunk* fd;
-  struct malloc_tree_chunk* bk;
-
-  struct malloc_tree_chunk* child[2];
-  struct malloc_tree_chunk* parent;
-  bindex_t                  index;
-};
-
-typedef struct malloc_tree_chunk  tchunk;
-typedef struct malloc_tree_chunk* tchunkptr;
-typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
-
-/* A little helper macro for trees */
-#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
-
-/* ----------------------------- Segments -------------------------------- */
-
-/*
-  Each malloc space may include non-contiguous segments, held in a
-  list headed by an embedded malloc_segment record representing the
-  top-most space. Segments also include flags holding properties of
-  the space. Large chunks that are directly allocated by mmap are not
-  included in this list. They are instead independently created and
-  destroyed without otherwise keeping track of them.
-
-  Segment management mainly comes into play for spaces allocated by
-  MMAP.  Any call to MMAP might or might not return memory that is
-  adjacent to an existing segment.  MORECORE normally contiguously
-  extends the current space, so this space is almost always adjacent,
-  which is simpler and faster to deal with. (This is why MORECORE is
-  used preferentially to MMAP when both are available -- see
-  sys_alloc.)  When allocating using MMAP, we don't use any of the
-  hinting mechanisms (inconsistently) supported in various
-  implementations of unix mmap, or distinguish reserving from
-  committing memory. Instead, we just ask for space, and exploit
-  contiguity when we get it.  It is probably possible to do
-  better than this on some systems, but no general scheme seems
-  to be significantly better.
-
-  Management entails a simpler variant of the consolidation scheme
-  used for chunks to reduce fragmentation -- new adjacent memory is
-  normally prepended or appended to an existing segment. However,
-  there are limitations compared to chunk consolidation that mostly
-  reflect the fact that segment processing is relatively infrequent
-  (occurring only when getting memory from system) and that we
-  don't expect to have huge numbers of segments:
-
-  * Segments are not indexed, so traversal requires linear scans.  (It
-    would be possible to index these, but is not worth the extra
-    overhead and complexity for most programs on most platforms.)
-  * New segments are only appended to old ones when holding top-most
-    memory; if they cannot be prepended to others, they are held in
-    different segments.
-
-  Except for the top-most segment of an mstate, each segment record
-  is kept at the tail of its segment. Segments are added by pushing
-  segment records onto the list headed by &mstate.seg for the
-  containing mstate.
-
-  Segment flags control allocation/merge/deallocation policies:
-  * If EXTERN_BIT set, then we did not allocate this segment,
-    and so should not try to deallocate or merge with others.
-    (This currently holds only for the initial segment passed
-    into create_mspace_with_base.)
-  * If IS_MMAPPED_BIT set, the segment may be merged with
-    other surrounding mmapped segments and trimmed/de-allocated
-    using munmap.
-  * If neither bit is set, then the segment was obtained using
-    MORECORE so can be merged with surrounding MORECORE'd segments
-    and deallocated/trimmed using MORECORE with negative arguments.
-*/
-
-struct malloc_segment {
-  char*        base;             /* base address */
-  size_t       size;             /* allocated size */
-  struct malloc_segment* next;   /* ptr to next segment */
-};
-
-typedef struct malloc_segment  msegment;
-typedef struct malloc_segment* msegmentptr;
-
-/* ---------------------------- malloc_state ----------------------------- */
-
-/*
-   A malloc_state holds all of the bookkeeping for a space.
-   The main fields are:
-
-  Top
-    The topmost chunk of the currently active segment. Its size is
-    cached in topsize.  The actual size of topmost space is
-    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
-    fenceposts and segment records if necessary when getting more
-    space from the system.  The size at which to autotrim top is
-    cached from mparams in trim_check, except that it is disabled if
-    an autotrim fails.
-
-  Designated victim (dv)
-    This is the preferred chunk for servicing small requests that
-    don't have exact fits.  It is normally the chunk split off most
-    recently to service another small request.  Its size is cached in
-    dvsize. The link fields of this chunk are not maintained since it
-    is not kept in a bin.
-
-  SmallBins
-    An array of bin headers for free chunks.  These bins hold chunks
-    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
-    chunks of all the same size, spaced 8 bytes apart.  To simplify
-    use in double-linked lists, each bin header acts as a malloc_chunk
-    pointing to the real first node, if it exists (else pointing to
-    itself).  This avoids special-casing for headers.  But to avoid
-    waste, we allocate only the fd/bk pointers of bins, and then use
-    repositioning tricks to treat these as the fields of a chunk.
-
-  TreeBins
-    Treebins are pointers to the roots of trees holding a range of
-    sizes. There are 2 equally spaced treebins for each power of two
-    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
-    larger.
-
-  Bin maps
-    There is one bit map for small bins ("smallmap") and one for
-    treebins ("treemap).  Each bin sets its bit when non-empty, and
-    clears the bit when empty.  Bit operations are then used to avoid
-    bin-by-bin searching -- nearly all "search" is done without ever
-    looking at bins that won't be selected.  The bit maps
-    conservatively use 32 bits per map word, even if on 64bit system.
-    For a good description of some of the bit-based techniques used
-    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
-    supplement at http://hackersdelight.org/). Many of these are
-    intended to reduce the branchiness of paths through malloc etc, as
-    well as to reduce the number of memory locations read or written.
-
-  Segments
-    A list of segments headed by an embedded malloc_segment record
-    representing the initial space.
-
-  Address check support
-    The least_addr field is the least address ever obtained from
-    MORECORE or MMAP. Attempted frees and reallocs of any address less
-    than this are trapped (unless INSECURE is defined).
-
-  Magic tag
-    A cross-check field that should always hold same value as mparams.magic.
-
-  Flags
-    Bits recording whether to use MMAP, locks, or contiguous MORECORE
-
-  Statistics
-    Each space keeps track of current and maximum system memory
-    obtained via MORECORE or MMAP.
-
-  Locking
-    If USE_LOCKS is defined, the "mutex" lock is acquired and released
-    around every public call using this mspace.
-*/
-
-/* Bin types, widths and sizes */
-#define NSMALLBINS        (32U)
-#define NTREEBINS         (32U)
-#define SMALLBIN_SHIFT    (3U)
-#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
-#define TREEBIN_SHIFT     (8U)
-#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
-#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
-#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
-
-struct malloc_state {
-  binmap_t   smallmap;
-  binmap_t   treemap;
-  size_t     dvsize;
-  size_t     topsize;
-  char*      least_addr;
-  mchunkptr  dv;
-  mchunkptr  top;
-  size_t     magic;
-  mchunkptr  smallbins[(NSMALLBINS+1)*2];
-  tbinptr    treebins[NTREEBINS];
-  size_t     footprint;
-  size_t     max_footprint;
-  flag_t     mflags;
-  void      *user_data;
-#if USE_LOCKS
-  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
-#endif /* USE_LOCKS */
-  msegment   seg;
-};
-
-typedef struct malloc_state*    mstate;
-
-/* ------------- Global malloc_state and malloc_params ------------------- */
-
-/*
-  malloc_params holds global properties, including those that can be
-  dynamically set using mallopt. There is a single instance, mparams,
-  initialized in init_mparams.
-*/
-
-struct malloc_params {
-  size_t magic;
-  size_t page_size;
-  size_t granularity;
-  flag_t default_mflags;
-};
-
-static struct malloc_params mparams;
-
-/* The global malloc_state used for all non-"mspace" calls */
-//static struct malloc_state _gm_;
-//#define gm                 (&_gm_)
-//#define is_global(M)       ((M) == &_gm_)
-#define is_initialized(M)  ((M)->top != 0)
-
-/* -------------------------- system alloc setup ------------------------- */
-
-/* Operations on mflags */
-
-#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
-#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
-#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
-
-#define set_lock(M,L)\
- ((M)->mflags = (L)?\
-  ((M)->mflags | USE_LOCK_BIT) :\
-  ((M)->mflags & ~USE_LOCK_BIT))
-
-/* page-align a size */
-#define page_align(S)\
- (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))
-
-/* granularity-align a size */
-#define granularity_align(S)\
-  (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))
-
-#define is_page_aligned(S)\
-   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
-#define is_granularity_aligned(S)\
-   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
-
-/*  True if segment S holds address A */
-#define segment_holds(S, A)\
-  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
-
-/* Return segment holding given address */
-static msegmentptr segment_holding(mstate m, char* addr) {
-  msegmentptr sp = &m->seg;
-  for (;;) {
-    if (addr >= sp->base && addr < sp->base + sp->size)
-      return sp;
-    if ((sp = sp->next) == 0)
-      return 0;
-  }
-}
-
-/* Return true if segment contains a segment link */
-static int has_segment_link(mstate m, msegmentptr ss) {
-  msegmentptr sp = &m->seg;
-  for (;;) {
-    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
-      return 1;
-    if ((sp = sp->next) == 0)
-      return 0;
-  }
-}
-
-
-
-/*
-  TOP_FOOT_SIZE is padding at the end of a segment, including space
-  that may be needed to place segment records and fenceposts when new
-  noncontiguous segments are added.
-*/
-#define TOP_FOOT_SIZE\
-  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
-
-
-/* -------------------------------  Hooks -------------------------------- */
-
-/*
-  PREACTION should be defined to return 0 on success, and nonzero on
-  failure. If you are not using locking, you can redefine these to do
-  anything you like.
-*/
-
-#if USE_LOCKS
-
-/* Ensure locks are initialized */
-#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())
-
-#define PREACTION(M)  ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
-#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
-#else /* USE_LOCKS */
-
-#ifndef PREACTION
-#define PREACTION(M) (0)
-#endif  /* PREACTION */
-
-#ifndef POSTACTION
-#define POSTACTION(M)
-#endif  /* POSTACTION */
-
-#endif /* USE_LOCKS */
-
-/*
-  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
-  USAGE_ERROR_ACTION is triggered on detected bad frees and
-  reallocs. The argument p is an address that might have triggered the
-  fault. It is ignored by the two predefined actions, but might be
-  useful in custom actions that try to help diagnose errors.
-*/
-
-#if PROCEED_ON_ERROR
-
-/* A count of the number of corruption errors causing resets */
-int malloc_corruption_error_count;
-
-/* default corruption action */
-static void reset_on_error(mstate m);
-
-#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
-#define USAGE_ERROR_ACTION(m, p)
-
-#else /* PROCEED_ON_ERROR */
-
-#ifndef CORRUPTION_ERROR_ACTION
-#define CORRUPTION_ERROR_ACTION(m) ABORT(m->user_data)
-#endif /* CORRUPTION_ERROR_ACTION */
-
-#ifndef USAGE_ERROR_ACTION
-#define USAGE_ERROR_ACTION(m,p) ABORT(m->user_data)
-#endif /* USAGE_ERROR_ACTION */
-
-#endif /* PROCEED_ON_ERROR */
-
-/* -------------------------- Debugging setup ---------------------------- */
-
-#if ! DEBUG
-
-#define check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)
-#define check_malloced_chunk(M,P,N)
-#define check_malloc_state(M)
-#define check_top_chunk(M,P)
-
-#else /* DEBUG */
-#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
-#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
-#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
-#define check_malloc_state(M)       do_check_malloc_state(M)
-
-static void   do_check_any_chunk(mstate m, mchunkptr p);
-static void   do_check_top_chunk(mstate m, mchunkptr p);
-static void   do_check_inuse_chunk(mstate m, mchunkptr p);
-static void   do_check_free_chunk(mstate m, mchunkptr p);
-static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
-static void   do_check_tree(mstate m, tchunkptr t);
-static void   do_check_treebin(mstate m, bindex_t i);
-static void   do_check_smallbin(mstate m, bindex_t i);
-static void   do_check_malloc_state(mstate m);
-static int    bin_find(mstate m, mchunkptr x);
-static size_t traverse_and_check(mstate m);
-#endif /* DEBUG */
-
-/* ---------------------------- Indexing Bins ---------------------------- */
-
-#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
-#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)
-#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
-#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
-
-/* addressing by index. See above about smallbin repositioning */
-#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
-#define treebin_at(M,i)     (&((M)->treebins[i]))
-
-/* assign tree index for size S to variable I */
-#if defined(__GNUC__) && defined(i386)
-#define compute_tree_index(S, I)\
-{\
-  size_t X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int K;\
-    __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm"  (X));\
-    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
-  }\
-}
-#else /* GNUC */
-#define compute_tree_index(S, I)\
-{\
-  size_t X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int Y = (unsigned int)X;\
-    unsigned int N = ((Y - 0x100) >> 16) & 8;\
-    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
-    N += K;\
-    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
-    K = 14 - N + ((Y <<= K) >> 15);\
-    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
-  }\
-}
-#endif /* GNUC */
-
-/* Bit representing maximum resolved size in a treebin at i */
-#define bit_for_tree_index(i) \
-   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
-
-/* Shift placing maximum resolved bit in a treebin at i as sign bit */
-#define leftshift_for_tree_index(i) \
-   ((i == NTREEBINS-1)? 0 : \
-    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
-
-/* The size of the smallest chunk held in bin with index i */
-#define minsize_for_tree_index(i) \
-   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
-   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
-
-/* ------------------------ Operations on bin maps ----------------------- */
-
-/* bit corresponding to given index */
-#define idx2bit(i)              ((binmap_t)(1) << (i))
-
-/* Mark/Clear bits with given index */
-#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
-#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
-#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
-
-#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
-#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
-#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
-
-/* index corresponding to given bit */
-
-#if defined(__GNUC__) && defined(i386)
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int J;\
-  __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\
-  I = (bindex_t)J;\
-}
-
-#else /* GNUC */
-#if  USE_BUILTIN_FFS
-#define compute_bit2idx(X, I) I = ffs(X)-1
-
-#else /* USE_BUILTIN_FFS */
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int Y = X - 1;\
-  unsigned int K = Y >> (16-4) & 16;\
-  unsigned int N = K;        Y >>= K;\
-  N += K = Y >> (8-3) &  8;  Y >>= K;\
-  N += K = Y >> (4-2) &  4;  Y >>= K;\
-  N += K = Y >> (2-1) &  2;  Y >>= K;\
-  N += K = Y >> (1-0) &  1;  Y >>= K;\
-  I = (bindex_t)(N + Y);\
-}
-#endif /* USE_BUILTIN_FFS */
-#endif /* GNUC */
-
-/* isolate the least set bit of a bitmap */
-#define least_bit(x)         ((x) & -(x))
-
-/* mask with all bits to left of least bit of x on */
-#define left_bits(x)         ((x<<1) | -(x<<1))
-
-/* mask with all bits to left of or equal to least bit of x on */
-#define same_or_left_bits(x) ((x) | -(x))
-
-
-/* ----------------------- Runtime Check Support ------------------------- */
-
-/*
-  For security, the main invariant is that malloc/free/etc never
-  writes to a static address other than malloc_state, unless static
-  malloc_state itself has been corrupted, which cannot occur via
-  malloc (because of these checks). In essence this means that we
-  believe all pointers, sizes, maps etc held in malloc_state, but
-  check all of those linked or offsetted from other embedded data
-  structures.  These checks are interspersed with main code in a way
-  that tends to minimize their run-time cost.
-
-  When FOOTERS is defined, in addition to range checking, we also
-  verify footer fields of inuse chunks, which can be used guarantee
-  that the mstate controlling malloc/free is intact.  This is a
-  streamlined version of the approach described by William Robertson
-  et al in "Run-time Detection of Heap-based Overflows" LISA'03
-  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
-  of an inuse chunk holds the xor of its mstate and a random seed,
-  that is checked upon calls to free() and realloc().  This is
-  (probablistically) unguessable from outside the program, but can be
-  computed by any code successfully malloc'ing any chunk, so does not
-  itself provide protection against code that has already broken
-  security through some other means.  Unlike Robertson et al, we
-  always dynamically check addresses of all offset chunks (previous,
-  next, etc). This turns out to be cheaper than relying on hashes.
-*/
-
-#if !INSECURE
-/* Check if address a is at least as high as any from MORECORE or MMAP */
-#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
-/* Check if address of next chunk n is higher than base chunk p */
-#define ok_next(p, n)    ((char*)(p) < (char*)(n))
-/* Check if p has its cinuse bit on */
-#define ok_cinuse(p)     cinuse(p)
-/* Check if p has its pinuse bit on */
-#define ok_pinuse(p)     pinuse(p)
-
-#else /* !INSECURE */
-#define ok_address(M, a) (1)
-#define ok_next(b, n)    (1)
-#define ok_cinuse(p)     (1)
-#define ok_pinuse(p)     (1)
-#endif /* !INSECURE */
-
-#if (FOOTERS && !INSECURE)
-/* Check if (alleged) mstate m has expected magic field */
-#define ok_magic(M)      ((M)->magic == mparams.magic)
-#else  /* (FOOTERS && !INSECURE) */
-#define ok_magic(M)      (1)
-#endif /* (FOOTERS && !INSECURE) */
-
-
-/* In gcc, use __builtin_expect to minimize impact of checks */
-#if !INSECURE
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define RTCHECK(e)  __builtin_expect(e, 1)
-#else /* GNUC */
-#define RTCHECK(e)  (e)
-#endif /* GNUC */
-#else /* !INSECURE */
-#define RTCHECK(e)  (1)
-#endif /* !INSECURE */
-
-/* macros to set up inuse chunks with or without footers */
-
-#if !FOOTERS
-
-#define mark_inuse_foot(M,p,s)
-
-/* Set cinuse bit and pinuse bit of next chunk */
-#define set_inuse(M,p,s)\
-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
-#define set_inuse_and_pinuse(M,p,s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set size, cinuse and pinuse bit of this chunk */
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
-
-#else /* FOOTERS */
-
-/* Set foot of inuse chunk to be xor of mstate and seed */
-#define mark_inuse_foot(M,p,s)\
-  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
-
-#define get_mstate_for(p)\
-  ((mstate)(((mchunkptr)((char*)(p) +\
-    (chunksize(p))))->prev_foot ^ mparams.magic))
-
-#define set_inuse(M,p,s)\
-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
-  mark_inuse_foot(M,p,s))
-
-#define set_inuse_and_pinuse(M,p,s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
- mark_inuse_foot(M,p,s))
-
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  mark_inuse_foot(M, p, s))
-
-#endif /* !FOOTERS */
-
-/* ---------------------------- setting mparams -------------------------- */
-
-/* Initialize mparams */
-static int init_mparams(void) {
-  if (mparams.page_size == 0) {
-    size_t s;
-
-    mparams.default_mflags = USE_LOCK_BIT;
-
-#if (FOOTERS && !INSECURE)
-    {
-#if USE_DEV_RANDOM
-      int fd;
-      unsigned char buf[sizeof(size_t)];
-      /* Try to use /dev/urandom, else fall back on using time */
-      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
-          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
-        s = *((size_t *) buf);
-        close(fd);
-      }
-      else
-#endif /* USE_DEV_RANDOM */
-        s = (size_t)(time(0) ^ (size_t)0x55555555U);
-
-      s |= (size_t)8U;    /* ensure nonzero */
-      s &= ~(size_t)7U;   /* improve chances of fault for bad values */
-
-    }
-#else /* (FOOTERS && !INSECURE) */
-    s = (size_t)0x58585858U;
-#endif /* (FOOTERS && !INSECURE) */
-    ACQUIRE_MAGIC_INIT_LOCK();
-    if (mparams.magic == 0) {
-      mparams.magic = s;
-      /* Set up lock for main malloc area */
-      //INITIAL_LOCK(&gm->mutex);
-      //gm->mflags = mparams.default_mflags;
-    }
-    RELEASE_MAGIC_INIT_LOCK();
-
-
-    mparams.page_size = malloc_getpagesize;
-    mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
-                           DEFAULT_GRANULARITY : mparams.page_size);
-
-    /* Sanity-check configuration:
-       size_t must be unsigned and as wide as pointer type.
-       ints must be at least 4 bytes.
-       alignment must be at least 8.
-       Alignment, min chunk size, and page size must all be powers of 2.
-    */
-    if ((sizeof(size_t) != sizeof(char*)) ||
-        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
-        (sizeof(int) < 4)  ||
-        (MALLOC_ALIGNMENT < (size_t)8U) ||
-        ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||
-        ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||
-        ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
-        ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))
-      ABORT(NULL);
-  }
-  return 0;
-}
-
-/* support for mallopt */
-static int change_mparam(int param_number, int value) {
-  size_t val = (size_t)value;
-  init_mparams();
-  switch(param_number) {
-  case M_GRANULARITY:
-    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
-      mparams.granularity = val;
-      return 1;
-    }
-    else
-      return 0;
-  default:
-    return 0;
-  }
-}
-
-#if DEBUG
-/* ------------------------- Debugging Support --------------------------- */
-
-/* Check properties of any chunk, whether free, inuse, mmapped etc  */
-static void do_check_any_chunk(mstate m, mchunkptr p) {
-  assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
-  assert(m->user_data, ok_address(m, p));
-}
-
-/* Check properties of top chunk */
-static void do_check_top_chunk(mstate m, mchunkptr p) {
-  msegmentptr sp = segment_holding(m, (char*)p);
-  size_t  sz = chunksize(p);
-  assert(m->user_data, sp != 0);
-  assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
-  assert(m->user_data, ok_address(m, p));
-  assert(m->user_data, sz == m->topsize);
-  assert(m->user_data, sz > 0);
-  assert(m->user_data, sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
-  assert(m->user_data, pinuse(p));
-  assert(m->user_data, !next_pinuse(p));
-}
-
-/* Check properties of inuse chunks */
-static void do_check_inuse_chunk(mstate m, mchunkptr p) {
-  do_check_any_chunk(m, p);
-  assert(m->user_data, cinuse(p));
-  assert(m->user_data, next_pinuse(p));
-  /* If not pinuse, previous chunk has OK offset */
-  assert(m->user_data, pinuse(p) || next_chunk(prev_chunk(p)) == p);
-}
-
-/* Check properties of free chunks */
-static void do_check_free_chunk(mstate m, mchunkptr p) {
-  size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
-  mchunkptr next = chunk_plus_offset(p, sz);
-  do_check_any_chunk(m, p);
-  assert(m->user_data, !cinuse(p));
-  assert(m->user_data, !next_pinuse(p));
-  if (p != m->dv && p != m->top) {
-    if (sz >= MIN_CHUNK_SIZE) {
-      assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
-      assert(m->user_data, is_aligned(chunk2mem(p)));
-      assert(m->user_data, next->prev_foot == sz);
-      assert(m->user_data, pinuse(p));
-      assert(m->user_data, next == m->top || cinuse(next));
-      assert(m->user_data, p->fd->bk == p);
-      assert(m->user_data, p->bk->fd == p);
-    }
-    else  /* markers are always of size SIZE_T_SIZE */
-      assert(m->user_data, sz == SIZE_T_SIZE);
-  }
-}
-
-/* Check properties of malloced chunks at the point they are malloced */
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
-  if (mem != 0) {
-    mchunkptr p = mem2chunk(mem);
-    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
-    do_check_inuse_chunk(m, p);
-    assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
-    assert(m->user_data, sz >= MIN_CHUNK_SIZE);
-    assert(m->user_data, sz >= s);
-    /* size is less than MIN_CHUNK_SIZE more than request */
-    assert(m->user_data, sz < (s + MIN_CHUNK_SIZE));
-  }
-}
-
-/* Check a tree and its subtrees.  */
-static void do_check_tree(mstate m, tchunkptr t) {
-  tchunkptr head = 0;
-  tchunkptr u = t;
-  bindex_t tindex = t->index;
-  size_t tsize = chunksize(t);
-  bindex_t idx;
-  compute_tree_index(tsize, idx);
-  assert(m->user_data, tindex == idx);
-  assert(m->user_data, tsize >= MIN_LARGE_SIZE);
-  assert(m->user_data, tsize >= minsize_for_tree_index(idx));
-  assert(m->user_data, (idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
-
-  do { /* traverse through chain of same-sized nodes */
-    do_check_any_chunk(m, ((mchunkptr)u));
-    assert(m->user_data, u->index == tindex);
-    assert(m->user_data, chunksize(u) == tsize);
-    assert(m->user_data, !cinuse(u));
-    assert(m->user_data, !next_pinuse(u));
-    assert(m->user_data, u->fd->bk == u);
-    assert(m->user_data, u->bk->fd == u);
-    if (u->parent == 0) {
-      assert(m->user_data, u->child[0] == 0);
-      assert(m->user_data, u->child[1] == 0);
-    }
-    else {
-      assert(m->user_data, head == 0); /* only one node on chain has parent */
-      head = u;
-      assert(m->user_data, u->parent != u);
-      assert(m->user_data, u->parent->child[0] == u ||
-             u->parent->child[1] == u ||
-             *((tbinptr*)(u->parent)) == u);
-      if (u->child[0] != 0) {
-        assert(m->user_data, u->child[0]->parent == u);
-        assert(m->user_data, u->child[0] != u);
-        do_check_tree(m, u->child[0]);
-      }
-      if (u->child[1] != 0) {
-        assert(m->user_data, u->child[1]->parent == u);
-        assert(m->user_data, u->child[1] != u);
-        do_check_tree(m, u->child[1]);
-      }
-      if (u->child[0] != 0 && u->child[1] != 0) {
-        assert(m->user_data, chunksize(u->child[0]) < chunksize(u->child[1]));
-      }
-    }
-    u = u->fd;
-  } while (u != t);
-  assert(m->user_data, head != 0);
-}
-
-/*  Check all the chunks in a treebin.  */
-static void do_check_treebin(mstate m, bindex_t i) {
-  tbinptr* tb = treebin_at(m, i);
-  tchunkptr t = *tb;
-  int empty = (m->treemap & (1U << i)) == 0;
-  if (t == 0)
-    assert(m->user_data, empty);
-  if (!empty)
-    do_check_tree(m, t);
-}
-
-/*  Check all the chunks in a smallbin.  */
-static void do_check_smallbin(mstate m, bindex_t i) {
-  sbinptr b = smallbin_at(m, i);
-  mchunkptr p = b->bk;
-  unsigned int empty = (m->smallmap & (1U << i)) == 0;
-  if (p == b)
-    assert(m->user_data, empty);
-  if (!empty) {
-    for (; p != b; p = p->bk) {
-      size_t size = chunksize(p);
-      mchunkptr q;
-      /* each chunk claims to be free */
-      do_check_free_chunk(m, p);
-      /* chunk belongs in bin */
-      assert(m->user_data, small_index(size) == i);
-      assert(m->user_data, p->bk == b || chunksize(p->bk) == chunksize(p));
-      /* chunk is followed by an inuse chunk */
-      q = next_chunk(p);
-      if (q->head != FENCEPOST_HEAD)
-        do_check_inuse_chunk(m, q);
-    }
-  }
-}
-
-/* Find x in a bin. Used in other check functions. */
-static int bin_find(mstate m, mchunkptr x) {
-  size_t size = chunksize(x);
-  if (is_small(size)) {
-    bindex_t sidx = small_index(size);
-    sbinptr b = smallbin_at(m, sidx);
-    if (smallmap_is_marked(m, sidx)) {
-      mchunkptr p = b;
-      do {
-        if (p == x)
-          return 1;
-      } while ((p = p->fd) != b);
-    }
-  }
-  else {
-    bindex_t tidx;
-    compute_tree_index(size, tidx);
-    if (treemap_is_marked(m, tidx)) {
-      tchunkptr t = *treebin_at(m, tidx);
-      size_t sizebits = size << leftshift_for_tree_index(tidx);
-      while (t != 0 && chunksize(t) != size) {
-        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
-        sizebits <<= 1;
-      }
-      if (t != 0) {
-        tchunkptr u = t;
-        do {
-          if (u == (tchunkptr)x)
-            return 1;
-        } while ((u = u->fd) != t);
-      }
-    }
-  }
-  return 0;
-}
-
-/* Traverse each chunk and check it; return total */
-static size_t traverse_and_check(mstate m) {
-  size_t sum = 0;
-  if (is_initialized(m)) {
-    msegmentptr s = &m->seg;
-    sum += m->topsize + TOP_FOOT_SIZE;
-    while (s != 0) {
-      mchunkptr q = align_as_chunk(s->base);
-      mchunkptr lastq = 0;
-      assert(m->user_data, pinuse(q));
-      while (segment_holds(s, q) &&
-             q != m->top && q->head != FENCEPOST_HEAD) {
-        sum += chunksize(q);
-        if (cinuse(q)) {
-          assert(m->user_data, !bin_find(m, q));
-          do_check_inuse_chunk(m, q);
-        }
-        else {
-          assert(m->user_data, q == m->dv || bin_find(m, q));
-          assert(m->user_data, lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
-          do_check_free_chunk(m, q);
-        }
-        lastq = q;
-        q = next_chunk(q);
-      }
-      s = s->next;
-    }
-  }
-  return sum;
-}
-
-/* Check all properties of malloc_state. */
-static void do_check_malloc_state(mstate m) {
-  bindex_t i;
-  size_t total;
-  /* check bins */
-  for (i = 0; i < NSMALLBINS; ++i)
-    do_check_smallbin(m, i);
-  for (i = 0; i < NTREEBINS; ++i)
-    do_check_treebin(m, i);
-
-  if (m->dvsize != 0) { /* check dv chunk */
-    do_check_any_chunk(m, m->dv);
-    assert(m->user_data, m->dvsize == chunksize(m->dv));
-    assert(m->user_data, m->dvsize >= MIN_CHUNK_SIZE);
-    assert(m->user_data, bin_find(m, m->dv) == 0);
-  }
-
-  if (m->top != 0) {   /* check top chunk */
-    do_check_top_chunk(m, m->top);
-    assert(m->user_data, m->topsize == chunksize(m->top));
-    assert(m->user_data, m->topsize > 0);
-    assert(m->user_data, bin_find(m, m->top) == 0);
-  }
-
-  total = traverse_and_check(m);
-  assert(m->user_data, total <= m->footprint);
-  assert(m->user_data, m->footprint <= m->max_footprint);
-}
-#endif /* DEBUG */
-
-/* ----------------------------- statistics ------------------------------ */
-
-#if !NO_MALLINFO
-static struct mallinfo internal_mallinfo(mstate m) {
-  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  if (!PREACTION(m)) {
-    check_malloc_state(m);
-    if (is_initialized(m)) {
-      size_t nfree = SIZE_T_ONE; /* top always free */
-      size_t mfree = m->topsize + TOP_FOOT_SIZE;
-      size_t sum = mfree;
-      msegmentptr s = &m->seg;
-      while (s != 0) {
-        mchunkptr q = align_as_chunk(s->base);
-        while (segment_holds(s, q) &&
-               q != m->top && q->head != FENCEPOST_HEAD) {
-          size_t sz = chunksize(q);
-          sum += sz;
-          if (!cinuse(q)) {
-            mfree += sz;
-            ++nfree;
-          }
-          q = next_chunk(q);
-        }
-        s = s->next;
-      }
-
-      nm.arena    = sum;
-      nm.ordblks  = nfree;
-      nm.hblkhd   = m->footprint - sum;
-      nm.usmblks  = m->max_footprint;
-      nm.uordblks = m->footprint - mfree;
-      nm.fordblks = mfree;
-      nm.keepcost = m->topsize;
-    }
-
-    POSTACTION(m);
-  }
-  return nm;
-}
-#endif /* !NO_MALLINFO */
-
-static void internal_malloc_stats(mstate m) {
-  if (!PREACTION(m)) {
-    size_t maxfp = 0;
-    size_t fp = 0;
-    size_t used = 0;
-    check_malloc_state(m);
-    if (is_initialized(m)) {
-      msegmentptr s = &m->seg;
-      maxfp = m->max_footprint;
-      fp = m->footprint;
-      used = fp - (m->topsize + TOP_FOOT_SIZE);
-
-      while (s != 0) {
-        mchunkptr q = align_as_chunk(s->base);
-        while (segment_holds(s, q) &&
-               q != m->top && q->head != FENCEPOST_HEAD) {
-          if (!cinuse(q))
-            used -= chunksize(q);
-          q = next_chunk(q);
-        }
-        s = s->next;
-      }
-    }
-
-    PRINT((m->user_data, "max system bytes = %10lu\n", (unsigned long)(maxfp)));
-    PRINT((m->user_data, "system bytes     = %10lu\n", (unsigned long)(fp)));
-    PRINT((m->user_data, "in use bytes     = %10lu\n", (unsigned long)(used)));
-
-    POSTACTION(m);
-  }
-}
-
-/* ----------------------- Operations on smallbins ----------------------- */
-
-/*
-  Various forms of linking and unlinking are defined as macros.  Even
-  the ones for trees, which are very long but have very short typical
-  paths.  This is ugly but reduces reliance on inlining support of
-  compilers.
-*/
-
-/* Link a free chunk into a smallbin  */
-#define insert_small_chunk(M, P, S) {\
-  bindex_t I  = small_index(S);\
-  mchunkptr B = smallbin_at(M, I);\
-  mchunkptr F = B;\
-  assert((M)->user_data, S >= MIN_CHUNK_SIZE);\
-  if (!smallmap_is_marked(M, I))\
-    mark_smallmap(M, I);\
-  else if (RTCHECK(ok_address(M, B->fd)))\
-    F = B->fd;\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-  B->fd = P;\
-  F->bk = P;\
-  P->fd = F;\
-  P->bk = B;\
-}
-
-/* Unlink a chunk from a smallbin  */
-#define unlink_small_chunk(M, P, S) {\
-  mchunkptr F = P->fd;\
-  mchunkptr B = P->bk;\
-  bindex_t I = small_index(S);\
-  assert((M)->user_data, P != B);\
-  assert((M)->user_data, P != F);\
-  assert((M)->user_data, chunksize(P) == small_index2size(I));\
-  if (F == B)\
-    clear_smallmap(M, I);\
-  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
-                   (B == smallbin_at(M,I) || ok_address(M, B)))) {\
-    F->bk = B;\
-    B->fd = F;\
-  }\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-}
-
-/* Unlink the first chunk from a smallbin */
-#define unlink_first_small_chunk(M, B, P, I) {\
-  mchunkptr F = P->fd;\
-  assert((M)->user_data, P != B);\
-  assert((M)->user_data, P != F);\
-  assert((M)->user_data, chunksize(P) == small_index2size(I));\
-  if (B == F)\
-    clear_smallmap(M, I);\
-  else if (RTCHECK(ok_address(M, F))) {\
-    B->fd = F;\
-    F->bk = B;\
-  }\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-}
-
-/* Replace dv node, binning the old one */
-/* Used only when dvsize known to be small */
-#define replace_dv(M, P, S) {\
-  size_t DVS = M->dvsize;\
-  if (DVS != 0) {\
-    mchunkptr DV = M->dv;\
-    assert((M)->user_data, is_small(DVS));\
-    insert_small_chunk(M, DV, DVS);\
-  }\
-  M->dvsize = S;\
-  M->dv = P;\
-}
-
-
-/* ------------------------- Operations on trees ------------------------- */
-
-/* Insert chunk into tree */
-#define insert_large_chunk(M, X, S) {\
-  tbinptr* H;\
-  bindex_t I;\
-  compute_tree_index(S, I);\
-  H = treebin_at(M, I);\
-  X->index = I;\
-  X->child[0] = X->child[1] = 0;\
-  if (!treemap_is_marked(M, I)) {\
-    mark_treemap(M, I);\
-    *H = X;\
-    X->parent = (tchunkptr)H;\
-    X->fd = X->bk = X;\
-  }\
-  else {\
-    tchunkptr T = *H;\
-    size_t K = S << leftshift_for_tree_index(I);\
-    for (;;) {\
-      if (chunksize(T) != S) {\
-        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
-        K <<= 1;\
-        if (*C != 0)\
-          T = *C;\
-        else if (RTCHECK(ok_address(M, C))) {\
-          *C = X;\
-          X->parent = T;\
-          X->fd = X->bk = X;\
-          break;\
-        }\
-        else {\
-          CORRUPTION_ERROR_ACTION(M);\
-          break;\
-        }\
-      }\
-      else {\
-        tchunkptr F = T->fd;\
-        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
-          T->fd = F->bk = X;\
-          X->fd = F;\
-          X->bk = T;\
-          X->parent = 0;\
-          break;\
-        }\
-        else {\
-          CORRUPTION_ERROR_ACTION(M);\
-          break;\
-        }\
-      }\
-    }\
-  }\
-}
-
-/*
-  Unlink steps:
-
-  1. If x is a chained node, unlink it from its same-sized fd/bk links
-     and choose its bk node as its replacement.
-  2. If x was the last node of its size, but not a leaf node, it must
-     be replaced with a leaf node (not merely one with an open left or
-     right), to make sure that lefts and rights of descendents
-     correspond properly to bit masks.  We use the rightmost descendent
-     of x.  We could use any other leaf, but this is easy to locate and
-     tends to counteract removal of leftmosts elsewhere, and so keeps
-     paths shorter than minimally guaranteed.  This doesn't loop much
-     because on average a node in a tree is near the bottom.
-  3. If x is the base of a chain (i.e., has parent links) relink
-     x's parent and children to x's replacement (or null if none).
-*/
-
-#define unlink_large_chunk(M, X) {\
-  tchunkptr XP = X->parent;\
-  tchunkptr R;\
-  if (X->bk != X) {\
-    tchunkptr F = X->fd;\
-    R = X->bk;\
-    if (RTCHECK(ok_address(M, F))) {\
-      F->bk = R;\
-      R->fd = F;\
-    }\
-    else {\
-      CORRUPTION_ERROR_ACTION(M);\
-    }\
-  }\
-  else {\
-    tchunkptr* RP;\
-    if (((R = *(RP = &(X->child[1]))) != 0) ||\
-        ((R = *(RP = &(X->child[0]))) != 0)) {\
-      tchunkptr* CP;\
-      while ((*(CP = &(R->child[1])) != 0) ||\
-             (*(CP = &(R->child[0])) != 0)) {\
-        R = *(RP = CP);\
-      }\
-      if (RTCHECK(ok_address(M, RP)))\
-        *RP = 0;\
-      else {\
-        CORRUPTION_ERROR_ACTION(M);\
-      }\
-    }\
-  }\
-  if (XP != 0) {\
-    tbinptr* H = treebin_at(M, X->index);\
-    if (X == *H) {\
-      if ((*H = R) == 0) \
-        clear_treemap(M, X->index);\
-    }\
-    else if (RTCHECK(ok_address(M, XP))) {\
-      if (XP->child[0] == X) \
-        XP->child[0] = R;\
-      else \
-        XP->child[1] = R;\
-    }\
-    else\
-      CORRUPTION_ERROR_ACTION(M);\
-    if (R != 0) {\
-      if (RTCHECK(ok_address(M, R))) {\
-        tchunkptr C0, C1;\
-        R->parent = XP;\
-        if ((C0 = X->child[0]) != 0) {\
-          if (RTCHECK(ok_address(M, C0))) {\
-            R->child[0] = C0;\
-            C0->parent = R;\
-          }\
-          else\
-            CORRUPTION_ERROR_ACTION(M);\
-        }\
-        if ((C1 = X->child[1]) != 0) {\
-          if (RTCHECK(ok_address(M, C1))) {\
-            R->child[1] = C1;\
-            C1->parent = R;\
-          }\
-          else\
-            CORRUPTION_ERROR_ACTION(M);\
-        }\
-      }\
-      else\
-        CORRUPTION_ERROR_ACTION(M);\
-    }\
-  }\
-}
-
-/* Relays to large vs small bin operations */
-
-#define insert_chunk(M, P, S)\
-  if (is_small(S)) insert_small_chunk(M, P, S)\
-  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
-
-#define unlink_chunk(M, P, S)\
-  if (is_small(S)) unlink_small_chunk(M, P, S)\
-  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
-
-
-/* Relays to internal calls to malloc/free from realloc, memalign etc */
-
-#define internal_malloc(m, b) mspace_malloc(m, b)
-#define internal_free(m, mem) mspace_free(m,mem);
-
-
-/* -------------------------- mspace management -------------------------- */
-
-/* Initialize top chunk and its size */
-static void init_top(mstate m, mchunkptr p, size_t psize) {
-  /* Ensure alignment */
-  size_t offset = align_offset(chunk2mem(p));
-  p = (mchunkptr)((char*)p + offset);
-  psize -= offset;
-
-  m->top = p;
-  m->topsize = psize;
-  p->head = psize | PINUSE_BIT;
-  /* set size of fake trailing chunk holding overhead space only once */
-  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
-}
-
-/* Initialize bins for a new mstate that is otherwise zeroed out */
-static void init_bins(mstate m) {
-  /* Establish circular links for smallbins */
-  bindex_t i;
-  for (i = 0; i < NSMALLBINS; ++i) {
-    sbinptr bin = smallbin_at(m,i);
-    bin->fd = bin->bk = bin;
-  }
-}
-
-#if PROCEED_ON_ERROR
-
-/* default corruption action */
-static void reset_on_error(mstate m) {
-  int i;
-  ++malloc_corruption_error_count;
-  /* Reinitialize fields to forget about all memory */
-  m->smallbins = m->treebins = 0;
-  m->dvsize = m->topsize = 0;
-  m->seg.base = 0;
-  m->seg.size = 0;
-  m->seg.next = 0;
-  m->top = m->dv = 0;
-  for (i = 0; i < NTREEBINS; ++i)
-    *treebin_at(m, i) = 0;
-  init_bins(m);
-}
-#endif /* PROCEED_ON_ERROR */
-
-/* Allocate chunk and prepend remainder with chunk in successor base. */
-static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
-                           size_t nb) {
-  mchunkptr p = align_as_chunk(newbase);
-  mchunkptr oldfirst = align_as_chunk(oldbase);
-  size_t psize = (char*)oldfirst - (char*)p;
-  mchunkptr q = chunk_plus_offset(p, nb);
-  size_t qsize = psize - nb;
-  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
-
-  assert(m->user_data, (char*)oldfirst > (char*)q);
-  assert(m->user_data, pinuse(oldfirst));
-  assert(m->user_data, qsize >= MIN_CHUNK_SIZE);
-
-  /* consolidate remainder with first chunk of old base */
-  if (oldfirst == m->top) {
-    size_t tsize = m->topsize += qsize;
-    m->top = q;
-    q->head = tsize | PINUSE_BIT;
-    check_top_chunk(m, q);
-  }
-  else if (oldfirst == m->dv) {
-    size_t dsize = m->dvsize += qsize;
-    m->dv = q;
-    set_size_and_pinuse_of_free_chunk(q, dsize);
-  }
-  else {
-    if (!cinuse(oldfirst)) {
-      size_t nsize = chunksize(oldfirst);
-      unlink_chunk(m, oldfirst, nsize);
-      oldfirst = chunk_plus_offset(oldfirst, nsize);
-      qsize += nsize;
-    }
-    set_free_with_pinuse(q, qsize, oldfirst);
-    insert_chunk(m, q, qsize);
-    check_free_chunk(m, q);
-  }
-
-  check_malloced_chunk(m, chunk2mem(p), nb);
-  return chunk2mem(p);
-}
-
-/* -------------------------- System allocation -------------------------- */
-
-/* Get memory from system using MORECORE or MMAP */
-static void* sys_alloc(mstate m, size_t nb) {
-  MALLOC_FAILURE_ACTION;
-  return 0;
-}
-
-/* ---------------------------- malloc support --------------------------- */
-
-/* allocate a large request from the best fitting chunk in a treebin */
-static void* tmalloc_large(mstate m, size_t nb) {
-  tchunkptr v = 0;
-  size_t rsize = -nb; /* Unsigned negation */
-  tchunkptr t;
-  bindex_t idx;
-  compute_tree_index(nb, idx);
-
-  if ((t = *treebin_at(m, idx)) != 0) {
-    /* Traverse tree for this bin looking for node with size == nb */
-    size_t sizebits = nb << leftshift_for_tree_index(idx);
-    tchunkptr rst = 0;  /* The deepest untaken right subtree */
-    for (;;) {
-      tchunkptr rt;
-      size_t trem = chunksize(t) - nb;
-      if (trem < rsize) {
-        v = t;
-        if ((rsize = trem) == 0)
-          break;
-      }
-      rt = t->child[1];
-      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
-      if (rt != 0 && rt != t)
-        rst = rt;
-      if (t == 0) {
-        t = rst; /* set t to least subtree holding sizes > nb */
-        break;
-      }
-      sizebits <<= 1;
-    }
-  }
-
-  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
-    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
-    if (leftbits != 0) {
-      bindex_t i;
-      binmap_t leastbit = least_bit(leftbits);
-      compute_bit2idx(leastbit, i);
-      t = *treebin_at(m, i);
-    }
-  }
-
-  while (t != 0) { /* find smallest of tree or subtree */
-    size_t trem = chunksize(t) - nb;
-    if (trem < rsize) {
-      rsize = trem;
-      v = t;
-    }
-    t = leftmost_child(t);
-  }
-
-  /*  If dv is a better fit, return 0 so malloc will use it */
-  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
-    if (RTCHECK(ok_address(m, v))) { /* split */
-      mchunkptr r = chunk_plus_offset(v, nb);
-      assert(m->user_data, chunksize(v) == rsize + nb);
-      if (RTCHECK(ok_next(v, r))) {
-        unlink_large_chunk(m, v);
-        if (rsize < MIN_CHUNK_SIZE)
-          set_inuse_and_pinuse(m, v, (rsize + nb));
-        else {
-          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
-          set_size_and_pinuse_of_free_chunk(r, rsize);
-          insert_chunk(m, r, rsize);
-        }
-        return chunk2mem(v);
-      }
-    }
-    CORRUPTION_ERROR_ACTION(m);
-  }
-  return 0;
-}
-
-/* allocate a small request from the best fitting chunk in a treebin */
-static void* tmalloc_small(mstate m, size_t nb) {
-  tchunkptr t, v;
-  size_t rsize;
-  bindex_t i;
-  binmap_t leastbit = least_bit(m->treemap);
-  compute_bit2idx(leastbit, i);
-
-  v = t = *treebin_at(m, i);
-  rsize = chunksize(t) - nb;
-
-  while ((t = leftmost_child(t)) != 0) {
-    size_t trem = chunksize(t) - nb;
-    if (trem < rsize) {
-      rsize = trem;
-      v = t;
-    }
-  }
-
-  if (RTCHECK(ok_address(m, v))) {
-    mchunkptr r = chunk_plus_offset(v, nb);
-    assert(m->user_data, chunksize(v) == rsize + nb);
-    if (RTCHECK(ok_next(v, r))) {
-      unlink_large_chunk(m, v);
-      if (rsize < MIN_CHUNK_SIZE)
-        set_inuse_and_pinuse(m, v, (rsize + nb));
-      else {
-        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
-        set_size_and_pinuse_of_free_chunk(r, rsize);
-        replace_dv(m, r, rsize);
-      }
-      return chunk2mem(v);
-    }
-  }
-
-  CORRUPTION_ERROR_ACTION(m);
-  return 0;
-}
-
-/* --------------------------- realloc support --------------------------- */
-
-static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
-  if (bytes >= MAX_REQUEST) {
-    MALLOC_FAILURE_ACTION;
-    return 0;
-  }
-  if (!PREACTION(m)) {
-    mchunkptr oldp = mem2chunk(oldmem);
-    size_t oldsize = chunksize(oldp);
-    mchunkptr next = chunk_plus_offset(oldp, oldsize);
-    mchunkptr newp = 0;
-    void* extra = 0;
-
-    /* Try to either shrink or extend into top. Else malloc-copy-free */
-
-    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
-                ok_next(oldp, next) && ok_pinuse(next))) {
-      size_t nb = request2size(bytes);
-      if (oldsize >= nb) { /* already big enough */
-        size_t rsize = oldsize - nb;
-        newp = oldp;
-        if (rsize >= MIN_CHUNK_SIZE) {
-          mchunkptr remainder = chunk_plus_offset(newp, nb);
-          set_inuse(m, newp, nb);
-          set_inuse(m, remainder, rsize);
-          extra = chunk2mem(remainder);
-        }
-      }
-      else if (next == m->top && oldsize + m->topsize > nb) {
-        /* Expand into top */
-        size_t newsize = oldsize + m->topsize;
-        size_t newtopsize = newsize - nb;
-        mchunkptr newtop = chunk_plus_offset(oldp, nb);
-        set_inuse(m, oldp, nb);
-        newtop->head = newtopsize |PINUSE_BIT;
-        m->top = newtop;
-        m->topsize = newtopsize;
-        newp = oldp;
-      }
-    }
-    else {
-      USAGE_ERROR_ACTION(m, oldmem);
-      POSTACTION(m);
-      return 0;
-    }
-
-    POSTACTION(m);
-
-    if (newp != 0) {
-      if (extra != 0) {
-        internal_free(m, extra);
-      }
-      check_inuse_chunk(m, newp);
-      return chunk2mem(newp);
-    }
-    else {
-      void* newmem = internal_malloc(m, bytes);
-      if (newmem != 0) {
-        size_t oc = oldsize - overhead_for(oldp);
-        MEMCPY(newmem, oldmem, (oc < bytes)? oc : bytes);
-        internal_free(m, oldmem);
-      }
-      return newmem;
-    }
-  }
-  return 0;
-}
-
-/* --------------------------- memalign support -------------------------- */
-
-static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
-  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */
-    return internal_malloc(m, bytes);
-  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
-    alignment = MIN_CHUNK_SIZE;
-  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
-    size_t a = MALLOC_ALIGNMENT << 1;
-    while (a < alignment) a <<= 1;
-    alignment = a;
-  }
-
-  if (bytes >= MAX_REQUEST - alignment) {
-    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
-      MALLOC_FAILURE_ACTION;
-    }
-  }
-  else {
-    size_t nb = request2size(bytes);
-    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
-    char* mem = (char*)internal_malloc(m, req);
-    if (mem != 0) {
-      void* leader = 0;
-      void* trailer = 0;
-      mchunkptr p = mem2chunk(mem);
-
-      if (PREACTION(m)) return 0;
-      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
-        /*
-          Find an aligned spot inside chunk.  Since we need to give
-          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
-          the first calculation places us at a spot with less than
-          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
-          We've allocated enough total room so that this is always
-          possible.
-        */
-        char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
-                                                       alignment -
-                                                       SIZE_T_ONE)) &
-                                             -alignment));
-        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
-          br : br+alignment;
-        mchunkptr newp = (mchunkptr)pos;
-        size_t leadsize = pos - (char*)(p);
-        size_t newsize = chunksize(p) - leadsize;
-
-        /* Otherwise, give back leader, use the rest */
-        set_inuse(m, newp, newsize);
-        set_inuse(m, p, leadsize);
-        leader = chunk2mem(p);
-
-        p = newp;
-      }
-
-      assert(m->user_data, chunksize(p) >= nb);
-      assert(m->user_data, (((size_t)(chunk2mem(p))) % alignment) == 0);
-      check_inuse_chunk(m, p);
-      POSTACTION(m);
-      if (leader != 0) {
-        internal_free(m, leader);
-      }
-      if (trailer != 0) {
-        internal_free(m, trailer);
-      }
-      return chunk2mem(p);
-    }
-  }
-  return 0;
-}
-
-/* ----------------------------- user mspaces ---------------------------- */
-
-static mstate init_user_mstate(char* tbase, size_t tsize, void *user_data) {
-  size_t msize = pad_request(sizeof(struct malloc_state));
-  mchunkptr mn;
-  mchunkptr msp = align_as_chunk(tbase);
-  mstate m = (mstate)(chunk2mem(msp));
-  MEMCLEAR(m, msize);
-  INITIAL_LOCK(&m->mutex);
-  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
-  m->seg.base = m->least_addr = tbase;
-  m->seg.size = m->footprint = m->max_footprint = tsize;
-  m->magic = mparams.magic;
-  m->mflags = mparams.default_mflags;
-  m->user_data = user_data;
-  init_bins(m);
-  mn = next_chunk(mem2chunk(m));
-  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
-  check_top_chunk(m, m->top);
-  return m;
-}
-
-mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data) {
-  mstate m = 0;
-  size_t msize = pad_request(sizeof(struct malloc_state));
-  init_mparams(); /* Ensure pagesize etc initialized */
-
-  if (capacity > msize + TOP_FOOT_SIZE &&
-      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
-    m = init_user_mstate((char*)base, capacity, user_data);
-    set_lock(m, locked);
-  }
-  return (mspace)m;
-}
-
-/*
-  mspace versions of routines are near-clones of the global
-  versions. This is not so nice but better than the alternatives.
-*/
-
-
-void* mspace_malloc(mspace msp, size_t bytes) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  if (!PREACTION(ms)) {
-    void* mem;
-    size_t nb;
-    if (bytes <= MAX_SMALL_REQUEST) {
-      bindex_t idx;
-      binmap_t smallbits;
-      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
-      idx = small_index(nb);
-      smallbits = ms->smallmap >> idx;
-
-      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
-        mchunkptr b, p;
-        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
-        b = smallbin_at(ms, idx);
-        p = b->fd;
-        assert(ms->user_data, chunksize(p) == small_index2size(idx));
-        unlink_first_small_chunk(ms, b, p, idx);
-        set_inuse_and_pinuse(ms, p, small_index2size(idx));
-        mem = chunk2mem(p);
-        check_malloced_chunk(ms, mem, nb);
-        goto postaction;
-      }
-
-      else if (nb > ms->dvsize) {
-        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
-          mchunkptr b, p, r;
-          size_t rsize;
-          bindex_t i;
-          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
-          binmap_t leastbit = least_bit(leftbits);
-          compute_bit2idx(leastbit, i);
-          b = smallbin_at(ms, i);
-          p = b->fd;
-          assert(ms->user_data, chunksize(p) == small_index2size(i));
-          unlink_first_small_chunk(ms, b, p, i);
-          rsize = small_index2size(i) - nb;
-          /* Fit here cannot be remainderless if 4byte sizes */
-          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
-            set_inuse_and_pinuse(ms, p, small_index2size(i));
-          else {
-            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-            r = chunk_plus_offset(p, nb);
-            set_size_and_pinuse_of_free_chunk(r, rsize);
-            replace_dv(ms, r, rsize);
-          }
-          mem = chunk2mem(p);
-          check_malloced_chunk(ms, mem, nb);
-          goto postaction;
-        }
-
-        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
-          check_malloced_chunk(ms, mem, nb);
-          goto postaction;
-        }
-      }
-    }
-    else if (bytes >= MAX_REQUEST)
-      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
-    else {
-      nb = pad_request(bytes);
-      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
-        check_malloced_chunk(ms, mem, nb);
-        goto postaction;
-      }
-    }
-
-    if (nb <= ms->dvsize) {
-      size_t rsize = ms->dvsize - nb;
-      mchunkptr p = ms->dv;
-      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
-        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
-        ms->dvsize = rsize;
-        set_size_and_pinuse_of_free_chunk(r, rsize);
-        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-      }
-      else { /* exhaust dv */
-        size_t dvs = ms->dvsize;
-        ms->dvsize = 0;
-        ms->dv = 0;
-        set_inuse_and_pinuse(ms, p, dvs);
-      }
-      mem = chunk2mem(p);
-      check_malloced_chunk(ms, mem, nb);
-      goto postaction;
-    }
-
-    else if (nb < ms->topsize) { /* Split top */
-      size_t rsize = ms->topsize -= nb;
-      mchunkptr p = ms->top;
-      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
-      r->head = rsize | PINUSE_BIT;
-      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-      mem = chunk2mem(p);
-      check_top_chunk(ms, ms->top);
-      check_malloced_chunk(ms, mem, nb);
-      goto postaction;
-    }
-
-    mem = sys_alloc(ms, nb);
-
-  postaction:
-    POSTACTION(ms);
-    return mem;
-  }
-
-  return 0;
-}
-
-void mspace_free(mspace msp, void* mem) {
-  if (mem != 0) {
-    mchunkptr p  = mem2chunk(mem);
-#if FOOTERS
-    mstate fm = get_mstate_for(p);
-#else /* FOOTERS */
-    mstate fm = (mstate)msp;
-#endif /* FOOTERS */
-    if (!ok_magic(fm)) {
-      USAGE_ERROR_ACTION(fm, p);
-      return;
-    }
-    if (!PREACTION(fm)) {
-      check_inuse_chunk(fm, p);
-      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
-        size_t psize = chunksize(p);
-        mchunkptr next = chunk_plus_offset(p, psize);
-        if (!pinuse(p)) {
-          size_t prevsize = p->prev_foot;
-
-          mchunkptr prev = chunk_minus_offset(p, prevsize);
-          psize += prevsize;
-          p = prev;
-          if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
-            if (p != fm->dv) {
-              unlink_chunk(fm, p, prevsize);
-            }
-            else if ((next->head & INUSE_BITS) == INUSE_BITS) {
-              fm->dvsize = psize;
-              set_free_with_pinuse(p, psize, next);
-              goto postaction;
-            }
-          }
-          else
-            goto erroraction;
-        }
-
-        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
-          if (!cinuse(next)) {  /* consolidate forward */
-            if (next == fm->top) {
-              size_t tsize = fm->topsize += psize;
-              fm->top = p;
-              p->head = tsize | PINUSE_BIT;
-              if (p == fm->dv) {
-                fm->dv = 0;
-                fm->dvsize = 0;
-              }
-              goto postaction;
-            }
-            else if (next == fm->dv) {
-              size_t dsize = fm->dvsize += psize;
-              fm->dv = p;
-              set_size_and_pinuse_of_free_chunk(p, dsize);
-              goto postaction;
-            }
-            else {
-              size_t nsize = chunksize(next);
-              psize += nsize;
-              unlink_chunk(fm, next, nsize);
-              set_size_and_pinuse_of_free_chunk(p, psize);
-              if (p == fm->dv) {
-                fm->dvsize = psize;
-                goto postaction;
-              }
-            }
-          }
-          else
-            set_free_with_pinuse(p, psize, next);
-          insert_chunk(fm, p, psize);
-          check_free_chunk(fm, p);
-          goto postaction;
-        }
-      }
-    erroraction:
-      USAGE_ERROR_ACTION(fm, p);
-    postaction:
-      POSTACTION(fm);
-    }
-  }
-}
-
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
-  void* mem;
-  size_t req = 0;
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  if (n_elements != 0) {
-    req = n_elements * elem_size;
-    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
-        (req / n_elements != elem_size))
-      req = MAX_SIZE_T; /* force downstream failure on overflow */
-  }
-  mem = internal_malloc(ms, req);
-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
-    MEMCLEAR(mem, req);
-  return mem;
-}
-
-void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
-  if (oldmem == 0)
-    return mspace_malloc(msp, bytes);
-#ifdef REALLOC_ZERO_BYTES_FREES
-  if (bytes == 0) {
-    mspace_free(msp, oldmem);
-    return 0;
-  }
-#endif /* REALLOC_ZERO_BYTES_FREES */
-  else {
-#if FOOTERS
-    mchunkptr p  = mem2chunk(oldmem);
-    mstate ms = get_mstate_for(p);
-#else /* FOOTERS */
-    mstate ms = (mstate)msp;
-#endif /* FOOTERS */
-    if (!ok_magic(ms)) {
-      USAGE_ERROR_ACTION(ms,ms);
-      return 0;
-    }
-    return internal_realloc(ms, oldmem, bytes);
-  }
-}
-
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  return internal_memalign(ms, alignment, bytes);
-}
-
-void mspace_malloc_stats(mspace msp) {
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    internal_malloc_stats(ms);
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-}
-
-size_t mspace_footprint(mspace msp) {
-  size_t result;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    result = ms->footprint;
-  } else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-
-size_t mspace_max_footprint(mspace msp) {
-  size_t result;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    result = ms->max_footprint;
-  } else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-
-#if !NO_MALLINFO
-struct mallinfo mspace_mallinfo(mspace msp) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return internal_mallinfo(ms);
-}
-#endif /* NO_MALLINFO */
-
-int mspace_mallopt(int param_number, int value) {
-  return change_mparam(param_number, value);
-}
-
diff --git a/display/mspace.h b/display/mspace.h
deleted file mode 100644
index 96b0593..0000000
--- a/display/mspace.h
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef _H_MSPACE
-#define _H_MSPACE
-
-#define NO_MALLINFO 0
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-//typedef unsigned long size_t;
-typedef void (*mspace_abort_t)(void *user_data);
-typedef void (*mspace_print_t)(void *user_data, char *format, ...);
-
-void mspace_set_abort_func(mspace_abort_t f);
-void mspace_set_print_func(mspace_print_t f);
-
-/*
-  mspace is an opaque type representing an independent
-  region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
-  create_mspace creates and returns a new independent space with the
-  given initial capacity, or, if 0, the default granularity size.  It
-  returns null if there is no system memory available to create the
-  space.  If argument locked is non-zero, the space uses a separate
-  lock to control access. The capacity of the space will grow
-  dynamically as needed to service mspace_malloc requests.  You can
-  control the sizes of incremental increases of this space by
-  compiling with a different DEFAULT_GRANULARITY or dynamically
-  setting with mallopt(M_GRANULARITY, value).
-*/
-//mspace create_mspace(size_t capacity, int locked);
-
-/*
-  destroy_mspace destroys the given space, and attempts to return all
-  of its memory back to the system, returning the total number of
-  bytes freed. After destruction, the results of access to all memory
-  used by the space become undefined.
-*/
-//size_t destroy_mspace(mspace msp);
-
-/*
-  create_mspace_with_base uses the memory supplied as the initial base
-  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
-  space is used for bookkeeping, so the capacity must be at least this
-  large. (Otherwise 0 is returned.) When this initial space is
-  exhausted, additional memory will be obtained from the system.
-  Destroying this space will deallocate all additionally allocated
-  space (if possible) but not the initial base.
-*/
-mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data);
-
-/*
-  mspace_malloc behaves as malloc, but operates within
-  the given space.
-*/
-void* mspace_malloc(mspace msp, size_t bytes);
-
-/*
-  mspace_free behaves as free, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_free is not actually needed.
-  free may be called instead of mspace_free because freed chunks from
-  any space are handled by their originating spaces.
-*/
-void mspace_free(mspace msp, void* mem);
-
-/*
-  mspace_realloc behaves as realloc, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_realloc is not actually
-  needed.  realloc may be called instead of mspace_realloc because
-  realloced chunks from any space are handled by their originating
-  spaces.
-*/
-void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-
-/*
-  mspace_calloc behaves as calloc, but operates within
-  the given space.
-*/
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-
-/*
-  mspace_memalign behaves as memalign, but operates within
-  the given space.
-*/
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-
-/*
-  mspace_independent_calloc behaves as independent_calloc, but
-  operates within the given space.
-*/
-//void** mspace_independent_calloc(mspace msp, size_t n_elements,
-//                                 size_t elem_size, void* chunks[]);
-
-/*
-  mspace_independent_comalloc behaves as independent_comalloc, but
-  operates within the given space.
-*/
-//void** mspace_independent_comalloc(mspace msp, size_t n_elements,
-//                                   size_t sizes[], void* chunks[]);
-
-/*
-  mspace_footprint() returns the number of bytes obtained from the
-  system for this space.
-*/
-size_t mspace_footprint(mspace msp);
-
-/*
-  mspace_max_footprint() returns the peak number of bytes obtained from the
-  system for this space.
-*/
-size_t mspace_max_footprint(mspace msp);
-
-
-#if !NO_MALLINFO
-/*
-  mspace_mallinfo behaves as mallinfo, but reports properties of
-  the given space.
-*/
-struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
-  mspace_malloc_stats behaves as malloc_stats, but reports
-  properties of the given space.
-*/
-void mspace_malloc_stats(mspace msp);
-
-/*
-  mspace_trim behaves as malloc_trim, but
-  operates within the given space.
-*/
-//int mspace_trim(mspace msp, size_t pad);
-
-/*
-  An alias for mallopt.
-*/
-int mspace_mallopt(int, int);
-
-#ifdef __cplusplus
-};  /* end of extern "C" */
-#endif /* __cplusplus */
-
-#endif
diff --git a/display/pointer.c b/display/pointer.c
deleted file mode 100644
index d38a207..0000000
--- a/display/pointer.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "os_dep.h"
-#include "qxldd.h"
-#include "utils.h"
-#include "res.h"
-
-/* DDK quote
-
-Calls to the pointer functions are serialized by GDI. This means two different threads in the
-driver cannot execute the pointer functions simultaneously.
-
-*/
-
-ULONG APIENTRY DrvSetPointerShape(SURFOBJ *surf, SURFOBJ *mask, SURFOBJ *color_pointer,
-                                  XLATEOBJ *color_trans, LONG hot_x, LONG hot_y,
-                                  LONG pos_x, LONG pos_y, RECTL *prcl, FLONG flags)
-{
-    QXLCursorCmd *cursor_cmd;
-    PDev *pdev;
-
-    if (!(pdev = (PDev *)surf->dhpdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
-        return SPS_ERROR;
-    }
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    if (flags & SPS_CHANGE) {
-        BOOL ok;
-        cursor_cmd = CursorCmd(pdev);
-        cursor_cmd->type = QXL_CURSOR_SET;
-        if (flags & SPS_ALPHA) {
-            if (mask) {
-                DEBUG_PRINT((pdev, 0, "%s: SPS_ALPHA and mask \n", __FUNCTION__));
-            }
-            ASSERT(pdev, color_pointer);
-            ok = GetAlphaCursor(pdev, cursor_cmd, hot_x, hot_y, color_pointer);
-        } else if (!mask) {
-            ok = GetTransparentCursor(pdev, cursor_cmd);
-        } else if (color_pointer && color_pointer->iBitmapFormat != BMF_1BPP) {
-            ASSERT(pdev, mask);
-            ok = GetColorCursor(pdev, cursor_cmd, hot_x, hot_y, color_pointer, mask, color_trans);
-        } else {
-            ok = GetMonoCursor(pdev, cursor_cmd, hot_x, hot_y, mask);
-        }
-
-        if (!ok) {
-            DEBUG_PRINT((pdev, 0, "%s: get cursor failed\n", __FUNCTION__));
-            ReleaseOutput(pdev, cursor_cmd->release_info.id);
-            return SPS_ERROR;
-        }
-        if (pos_x < 0) {
-            cursor_cmd->u.set.visible = FALSE;
-            cursor_cmd->u.set.position.x = cursor_cmd->u.set.position.y = 0;
-        } else {
-            cursor_cmd->u.set.visible = TRUE;
-            cursor_cmd->u.set.position.x = (INT16)pos_x;
-            cursor_cmd->u.set.position.y = (INT16)pos_y;
-        }
-
-        PushCursorCmd(pdev, cursor_cmd);
-
-    } else {
-        cursor_cmd = CursorCmd(pdev);
-        if (pos_x < 0) {
-#ifdef DBG
-            DEBUG_PRINT((pdev, 0, "%s: no SPS_CHANGE and pos_x < 0\n", __FUNCTION__));
-#endif
-            cursor_cmd->type = QXL_CURSOR_HIDE;
-        } else {
-#ifdef DBG
-            DEBUG_PRINT((pdev, 0, "%s: no SPS_CHANGE\n", __FUNCTION__));
-#endif
-            cursor_cmd->type = QXL_CURSOR_MOVE;
-            cursor_cmd->u.position.x = (INT16)pos_x;
-            cursor_cmd->u.position.y = (INT16)pos_y;
-        }
-        PushCursorCmd(pdev, cursor_cmd);
-    }
-#if (WINVER >= 0x0501)
-    if ((flags & (SPS_LENGTHMASK | SPS_FREQMASK)) != pdev->cursor_trail){
-        pdev->cursor_trail = (flags & (SPS_LENGTHMASK | SPS_FREQMASK));
-        cursor_cmd = CursorCmd(pdev);
-        cursor_cmd->type = QXL_CURSOR_TRAIL;
-        cursor_cmd->u.trail.length = (UINT16)((flags & SPS_LENGTHMASK) >> 8);
-        cursor_cmd->u.trail.frequency = (UINT16)((flags & SPS_FREQMASK) >> 12);
-        PushCursorCmd(pdev, cursor_cmd);
-    }
-#endif
-
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-    return SPS_ACCEPT_NOEXCLUDE;
-}
-
-VOID APIENTRY DrvMovePointer(SURFOBJ *surf, LONG pos_x, LONG pos_y, RECTL *area)
-{
-    QXLCursorCmd *cursor_cmd;
-    PDev *pdev;
-
-    if (!(pdev = (PDev *)surf->dhpdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
-        return;
-    }
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    if (pos_y < 0 && pos_x >= 0) {
-        DEBUG_PRINT((pdev, 0, "%s: unexpected negative y pos\n", __FUNCTION__));
-        return;
-    }
-
-    cursor_cmd = CursorCmd(pdev);
-    if (pos_x < 0) {
-        cursor_cmd->type = QXL_CURSOR_HIDE;
-    } else {
-        cursor_cmd->type = QXL_CURSOR_MOVE;
-        cursor_cmd->u.position.x = (INT16)pos_x;
-        cursor_cmd->u.position.y = (INT16)pos_y;
-    }
-    PushCursorCmd(pdev, cursor_cmd);
-
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-}
-
diff --git a/display/quic.c b/display/quic.c
deleted file mode 100644
index ee12fab..0000000
--- a/display/quic.c
+++ /dev/null
@@ -1,1738 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-// Red Hat image compression based on SFALIC by Roman Starosolski
-// http://sun.iinf.polsl.gliwice.pl/~rstaros/sfalic/index.html
-
-#include "stddef.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "os_dep.h"
-
-#include "winerror.h"
-#include "windef.h"
-#include "wingdi.h"
-#include "winddi.h"
-#include "devioctl.h"
-#include "ntddvdeo.h"
-
-#include "qxldd.h"
-#include "utils.h"
-#include "mspace.h"
-#include "res.h"
-#include "surface.h"
-
-
-#include "quic.h"
-
-//#define DEBUG
-
-#define RLE
-#define RLE_STAT
-#define PRED_1
-//#define RLE_PRED_1
-#define RLE_PRED_2
-//#define RLE_PRED_3
-#define QUIC_RGB
-
-#define QUIC_MAGIC (*(uint32_t *)"QUIC")
-#define QUIC_VERSION_MAJOR 0U
-#define QUIC_VERSION_MINOR 1U
-#define QUIC_VERSION ((QUIC_VERSION_MAJOR << 16) | (QUIC_VERSION_MAJOR & 0xffff))
-
-#define ABS(a) ((a) >= 0 ? (a) : -(a))
-
-#ifdef ASSERT
-#undef ASSERT
-#endif
-
-#ifdef DEBUG
-
-#define ASSERT(usr, x) \
-    if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
-
-#else
-
-#define ASSERT(usr, x)
-
-#endif
-
-#define FALSE 0
-#define TRUE 1
-
-typedef uint8_t BYTE;
-
-/* maximum number of codes in family */
-#define MAXNUMCODES 8
-
-/* model evolution, warning: only 1,3 and 5 allowed */
-#define DEFevol 3
-#define MINevol 0
-#define MAXevol 5
-
-/* starting wait mask index */
-#define DEFwmistart 0
-#define MINwmistart 0
-
-/* codeword length limit */
-#define DEFmaxclen 26
-
-/* target wait mask index */
-#define DEFwmimax 6
-
-/* number of symbols to encode before increasing wait mask index */
-#define DEFwminext 2048
-#define MINwminext 1
-#define MAXwminext 100000000
-
-typedef struct QuicFamily {
-    unsigned int nGRcodewords[MAXNUMCODES];      /* indexed by code number, contains number of
-                                                    unmodofied GR codewords in the code */
-    unsigned int notGRcwlen[MAXNUMCODES];        /* indexed by code number, contains codeword
-                                                    length of the not-GR codeword */
-    unsigned int notGRprefixmask[MAXNUMCODES];   /* indexed by code number, contains mask to
-                                                    determine if the codeword is GR or not-GR */
-    unsigned int notGRsuffixlen[MAXNUMCODES];    /* indexed by code number, contains suffix
-                                                    length of the not-GR codeword */
-
-    /* array for translating distribution U to L for depths up to 8 bpp,
-    initialized by decorelateinit() */
-    BYTE xlatU2L[256];
-
-    /* array for translating distribution L to U for depths up to 8 bpp,
-       initialized by corelateinit() */
-    unsigned int xlatL2U[256];
-} QuicFamily;
-
-static QuicFamily family_8bpc;
-static QuicFamily family_5bpc;
-
-typedef unsigned COUNTER;   /* counter in the array of counters in bucket of the data model */
-
-typedef struct s_bucket {
-    COUNTER *pcounters;     /* pointer to array of counters */
-    unsigned int bestcode;  /* best code so far */
-} s_bucket;
-
-typedef struct Encoder Encoder;
-
-typedef struct CommonState {
-    Encoder *encoder;
-
-    unsigned int waitcnt;
-    unsigned int tabrand_seed;
-    unsigned int wm_trigger;
-    unsigned int wmidx;
-    unsigned int wmileft;
-
-#ifdef RLE_STAT
-    int melcstate; /* index to the state array */
-
-    int melclen;  /* contents of the state array location
-                     indexed by melcstate: the "expected"
-                     run length is 2^melclen, shorter runs are
-                     encoded by a 1 followed by the run length
-                     in binary representation, wit a fixed length
-                     of melclen bits */
-
-    unsigned long melcorder;  /* 2^ melclen */
-#endif
-} CommonState;
-
-
-#define MAX_CHANNELS 4
-
-typedef struct FamilyStat {
-    s_bucket **buckets_ptrs;
-    s_bucket *buckets_buf;
-    COUNTER *counters;
-} FamilyStat;
-
-typedef struct Channel {
-    Encoder *encoder;
-
-    int correlate_row_width;
-    BYTE *correlate_row;
-
-    s_bucket **_buckets_ptrs;
-
-    FamilyStat family_stat_8bpc;
-    FamilyStat family_stat_5bpc;
-
-    CommonState state;
-} Channel;
-
-struct Encoder {
-    QuicUsrContext *usr;
-    QuicImageType type;
-    unsigned int width;
-    unsigned int height;
-    unsigned int num_channels;
-
-    unsigned int n_buckets_8bpc;
-    unsigned int n_buckets_5bpc;
-
-    unsigned int io_available_bits;
-    uint32_t io_word;
-    uint32_t io_next_word;
-    uint32_t *io_now;
-    uint32_t *io_end;
-    uint32_t io_words_count;
-
-    int rows_completed;
-
-    Channel channels[MAX_CHANNELS];
-
-    CommonState rgb_state;
-};
-
-/* target wait mask index */
-static int wmimax = DEFwmimax;
-
-/* number of symbols to encode before increasing wait mask index */
-static int wminext = DEFwminext;
-
-/* model evolution mode */
-static int evol = DEFevol;
-
-/* bppmask[i] contains i ones as lsb-s */
-static const unsigned long int bppmask[33] = {
-    0x00000000, /* [0] */
-    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
-    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
-    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
-    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
-    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
-    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
-    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
-    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff /* [32] */
-};
-
-static const unsigned int bitat[32] = {
-    0x00000001, 0x00000002, 0x00000004, 0x00000008,
-    0x00000010, 0x00000020, 0x00000040, 0x00000080,
-    0x00000100, 0x00000200, 0x00000400, 0x00000800,
-    0x00001000, 0x00002000, 0x00004000, 0x00008000,
-    0x00010000, 0x00020000, 0x00040000, 0x00080000,
-    0x00100000, 0x00200000, 0x00400000, 0x00800000,
-    0x01000000, 0x02000000, 0x04000000, 0x08000000,
-    0x10000000, 0x20000000, 0x40000000, 0x80000000 /* [31]*/
-};
-
-
-#define TABRAND_TABSIZE 256
-#define TABRAND_SEEDMASK 0x0ff
-
-static const unsigned int tabrand_chaos[TABRAND_TABSIZE] = {
-    0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052, 0x57329b28, 0x2993868e,
-    0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac, 0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b,
-    0x9e3dce44, 0xdaabee13, 0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33,
-    0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e, 0xedd58794, 0xc5076689,
-    0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9, 0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45,
-    0x600bde29, 0xf3971ace, 0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3,
-    0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136, 0xf1840e7e, 0x6a6048c1,
-    0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d, 0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0,
-    0x8f9d8604, 0x4f86e73b, 0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484,
-    0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee, 0x92826ddf, 0x284bec73,
-    0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b, 0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76,
-    0xfc6fac0a, 0xce927e9b, 0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2,
-    0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0, 0xb7e8d590, 0xbe807feb,
-    0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c, 0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be,
-    0xb4805c77, 0x00c880fa, 0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d,
-    0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf, 0x29f8c9fb, 0x53dd6880,
-    0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119, 0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4,
-    0xc2b8a563, 0x94f2f741, 0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e,
-    0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b, 0xd161043e, 0x5d2fa2e2,
-    0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34, 0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d,
-    0xccb01948, 0x8d168df7, 0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872,
-    0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098, 0xce81675a, 0x4b372f7d,
-    0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6, 0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef,
-    0x80020447, 0x67976491, 0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1,
-    0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d, 0x624a78b4, 0x30dbee1b,
-    0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff, 0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4,
-    0x49e54438, 0x2f2577e6, 0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358,
-    0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65, 0xe0893818, 0x9e00a16a,
-    0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e, 0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97,
-    0x923a9559, 0x37a7a1f6, 0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2,
-    0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649, 0xdc0a36c0, 0x61cf2bba,
-    0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d, 0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5,
-};
-
-static unsigned int stabrand()
-{
-    //ASSERT( !(TABRAND_SEEDMASK & TABRAND_TABSIZE));
-    //ASSERT( TABRAND_SEEDMASK + 1 == TABRAND_TABSIZE );
-
-    return TABRAND_SEEDMASK;
-}
-
-static unsigned int tabrand(unsigned int *tabrand_seed)
-{
-    return tabrand_chaos[++*tabrand_seed & TABRAND_SEEDMASK];
-}
-
-static const unsigned short besttrigtab[3][11] = { /* array of wm_trigger for waitmask and evol,
-                                                    used by set_wm_trigger() */
-    /* 1 */ { 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160},
-    /* 3 */ { 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140},
-    /* 5 */ { 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160}
-};
-
-/* set wm_trigger knowing waitmask (param) and evol (glob)*/
-static void set_wm_trigger(CommonState *state)
-{
-    unsigned int wm = state->wmidx;
-    if (wm > 10) {
-        wm = 10;
-    }
-
-    ASSERT(state->encoder->usr, evol < 6);
-
-    state->wm_trigger = besttrigtab[evol / 2][wm];
-
-    ASSERT(state->encoder->usr, state->wm_trigger <= 2000);
-    ASSERT(state->encoder->usr, state->wm_trigger >= 1);
-}
-
-static int ceil_log_2(int val) /* ceil(log_2(val)) */
-{
-    int result;
-
-    //ASSERT(val>0);
-
-    if (val == 1) {
-        return 0;
-    }
-
-    result = 1;
-    val -= 1;
-    while (val >>= 1) {
-        result++;
-    }
-
-    return result;
-}
-
-/* number of leading zeroes in the byte, used by cntlzeroes(uint)*/
-static const BYTE lzeroes[256] = {
-    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* count leading zeroes */
-static unsigned int cnt_l_zeroes(const unsigned int bits)
-{
-    if (bits & 0xff800000) {
-        return lzeroes[bits >> 24];
-    } else if (bits & 0xffff8000) {
-        return 8 + lzeroes[(bits >> 16) & 0x000000ff];
-    } else if (bits & 0xffffff80) {
-        return 16 + lzeroes[(bits >> 8) & 0x000000ff];
-    } else {
-        return 24 + lzeroes[bits & 0x000000ff];
-    }
-}
-
-#define QUIC_FAMILY_8BPC
-#include "quic_family_tmpl.c"
-
-#ifdef QUIC_RGB
-#define QUIC_FAMILY_5BPC
-#include "quic_family_tmpl.c"
-#endif
-
-static void decorelate_init(QuicFamily *family, int bpc)
-{
-    const unsigned int pixelbitmask = bppmask[bpc];
-    const unsigned int pixelbitmaskshr = pixelbitmask >> 1;
-    unsigned int s;
-
-    //ASSERT(bpc <= 8);
-
-    for (s = 0; s <= pixelbitmask; s++) {
-        if (s <= pixelbitmaskshr) {
-            family->xlatU2L[s] = s << 1;
-        } else {
-            family->xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
-        }
-    }
-}
-
-static void corelate_init(QuicFamily *family, int bpc)
-{
-    const unsigned long int pixelbitmask = bppmask[bpc];
-    unsigned long int s;
-
-    //ASSERT(bpc <= 8);
-
-    for (s = 0; s <= pixelbitmask; s++) {
-        if (s & 0x01) {
-            family->xlatL2U[s] = pixelbitmask - (s >> 1);
-        } else {
-            family->xlatL2U[s] = (s >> 1);
-        }
-    }
-}
-
-static void family_init(QuicFamily *family, int bpc, int limit)
-{
-    int l;
-
-    for (l = 0; l < bpc; l++) { /* fill arrays indexed by code number */
-        int altprefixlen, altcodewords;
-
-        altprefixlen = limit - bpc;
-        if (altprefixlen > (int)(bppmask[bpc - l])) {
-            altprefixlen = bppmask[bpc - l];
-        }
-
-        altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);
-
-        family->nGRcodewords[l] = (altprefixlen << l);
-        family->notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords);
-        family->notGRprefixmask[l] = bppmask[32 - altprefixlen]; /* needed for decoding only */
-        family->notGRsuffixlen[l] = ceil_log_2(altcodewords); /* needed for decoding only */
-    }
-
-    decorelate_init(family, bpc);
-    corelate_init(family, bpc);
-}
-
-static void more_io_words(Encoder *encoder)
-{
-    uint32_t *io_ptr;
-    int num_io_words = encoder->usr->more_space(encoder->usr, &io_ptr, encoder->rows_completed);
-    if (num_io_words <= 0) {
-        encoder->usr->error(encoder->usr, "%s: no more words\n", __FUNCTION__);
-    }
-    ASSERT(encoder->usr, io_ptr);
-    encoder->io_words_count += num_io_words;
-    encoder->io_now = io_ptr;
-    encoder->io_end = encoder->io_now + num_io_words;
-}
-
-static void __write_io_word(Encoder *encoder)
-{
-    more_io_words(encoder);
-    *(encoder->io_now++) = encoder->io_word;
-}
-
-static void (*__write_io_word_ptr)(Encoder *encoder) = __write_io_word;
-
-static INLINE void write_io_word(Encoder *encoder)
-{
-    if (encoder->io_now == encoder->io_end) {
-        __write_io_word_ptr(encoder); //disable inline optimizations
-        return;
-    }
-    *(encoder->io_now++) = encoder->io_word;
-}
-
-static INLINE void encode(Encoder *encoder, unsigned int word, unsigned int len)
-{
-    int delta;
-
-    ASSERT(encoder->usr, len > 0 && len < 32);
-    ASSERT(encoder->usr, !(word & ~bppmask[len]));
-    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
-        encoder->io_available_bits = delta;
-        encoder->io_word |= word << encoder->io_available_bits;
-        return;
-    }
-    delta = -delta;
-    encoder->io_word |= word >> delta;
-    write_io_word(encoder);
-    encoder->io_available_bits = 32 - delta;
-    encoder->io_word = word << encoder->io_available_bits;
-
-    ASSERT(encoder->usr, encoder->io_available_bits < 32);
-    ASSERT(encoder->usr, (encoder->io_word & bppmask[encoder->io_available_bits]) == 0);
-}
-
-static INLINE void encode_32(Encoder *encoder, unsigned int word)
-{
-    encode(encoder, word >> 16, 16);
-    encode(encoder, word & 0x0000ffff, 16);
-}
-
-static INLINE void flush(Encoder *encoder)
-{
-    if (encoder->io_available_bits > 0 && encoder->io_available_bits != 32) {
-        encode(encoder, 0, encoder->io_available_bits);
-    }
-    encode_32(encoder, 0);
-    encode(encoder, 0, 1);
-}
-
-static void __read_io_word(Encoder *encoder)
-{
-    more_io_words(encoder);
-    encoder->io_next_word = *(encoder->io_now++);
-}
-
-static void (*__read_io_word_ptr)(Encoder *encoder) = __read_io_word;
-
-
-static INLINE void read_io_word(Encoder *encoder)
-{
-    if (encoder->io_now == encoder->io_end) {
-        __read_io_word_ptr(encoder); //disable inline optimizations
-        return;
-    }
-    ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
-    encoder->io_next_word = *(encoder->io_now++);
-}
-
-static INLINE void decode_eatbits(Encoder *encoder, int len)
-{
-    int delta;
-
-    ASSERT(encoder->usr, len > 0 && len < 32);
-    encoder->io_word <<= len;
-
-    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
-        encoder->io_available_bits = delta;
-        encoder->io_word |= encoder->io_next_word >> encoder->io_available_bits;
-        return;
-    }
-
-    delta = -delta;
-    encoder->io_word |= encoder->io_next_word << delta;
-    read_io_word(encoder);
-    encoder->io_available_bits = 32 - delta;
-    encoder->io_word |= (encoder->io_next_word >> encoder->io_available_bits);
-}
-
-static INLINE void decode_eat32bits(Encoder *encoder)
-{
-    decode_eatbits(encoder, 16);
-    decode_eatbits(encoder, 16);
-}
-
-#ifdef RLE
-
-#ifdef RLE_STAT
-
-static INLINE void encode_ones(Encoder *encoder, unsigned int n)
-{
-    unsigned int count;
-
-    for (count = n >> 5; count; count--) {
-        encode(encoder, ~0U, 32);
-    }
-
-    if ((n &= 0x1f)) {
-        encode(encoder, (1U << n) - 1, n);
-    }
-}
-
-#define MELCSTATES 32 /* number of melcode states */
-
-static int zeroLUT[256]; /* table to find out number of leading zeros */
-
-static int J[MELCSTATES] = {
-    0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7,
-    7, 8, 9, 10, 11, 12, 13, 14, 15
-};
-
-/* creates the bit counting look-up table. */
-static void init_zeroLUT()
-{
-    int i, j, k, l;
-
-    j = k = 1;
-    l = 8;
-    for (i = 0; i < 256; ++i) {
-        zeroLUT[i] = l;
-        --k;
-        if (k == 0) {
-            k = j;
-            --l;
-            j *= 2;
-        }
-    }
-}
-
-static void encoder_init_rle(CommonState *state)
-{
-    state->melcstate = 0;
-    state->melclen = J[0];
-    state->melcorder = 1 << state->melclen;
-}
-
-#ifdef QUIC_RGB
-
-static void encode_run(Encoder *encoder, unsigned int runlen) //todo: try use end of line
-{
-    int hits = 0;
-
-    while (runlen >= encoder->rgb_state.melcorder) {
-        hits++;
-        runlen -= encoder->rgb_state.melcorder;
-        if (encoder->rgb_state.melcstate < MELCSTATES) {
-            encoder->rgb_state.melclen = J[++encoder->rgb_state.melcstate];
-            encoder->rgb_state.melcorder = (1L << encoder->rgb_state.melclen);
-        }
-    }
-
-    /* send the required number of "hit" bits (one per occurrence
-       of a run of length melcorder). This number is never too big:
-       after 31 such "hit" bits, each "hit" would represent a run of 32K
-       pixels.
-    */
-    encode_ones(encoder, hits);
-
-    encode(encoder, runlen, encoder->rgb_state.melclen + 1);
-
-    /* adjust melcoder parameters */
-    if (encoder->rgb_state.melcstate) {
-        encoder->rgb_state.melclen = J[--encoder->rgb_state.melcstate];
-        encoder->rgb_state.melcorder = (1L << encoder->rgb_state.melclen);
-    }
-}
-
-#endif
-
-static void encode_channel_run(Encoder *encoder, Channel *channel, unsigned int runlen)
-{
-    //todo: try use end of line
-    int hits = 0;
-
-    while (runlen >= channel->state.melcorder) {
-        hits++;
-        runlen -= channel->state.melcorder;
-        if (channel->state.melcstate < MELCSTATES) {
-            channel->state.melclen = J[++channel->state.melcstate];
-            channel->state.melcorder = (1L << channel->state.melclen);
-        }
-    }
-
-    /* send the required number of "hit" bits (one per occurrence
-       of a run of length melcorder). This number is never too big:
-       after 31 such "hit" bits, each "hit" would represent a run of 32K
-       pixels.
-    */
-    encode_ones(encoder, hits);
-
-    encode(encoder, runlen, channel->state.melclen + 1);
-
-    /* adjust melcoder parameters */
-    if (channel->state.melcstate) {
-        channel->state.melclen = J[--channel->state.melcstate];
-        channel->state.melcorder = (1L << channel->state.melclen);
-    }
-}
-
-/* decoding routine: reads bits from the input and returns a run length. */
-/* argument is the number of pixels left to end-of-line (bound on run length) */
-
-#ifdef QUIC_RGB
-static int decode_run(Encoder *encoder)
-{
-    int runlen = 0;
-
-    do {
-        register int temp, hits;
-        temp = zeroLUT[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
-                                                                      input stream, up to 8 */
-        for (hits = 1; hits <= temp; hits++) {
-            runlen += encoder->rgb_state.melcorder;
-
-            if (encoder->rgb_state.melcstate < MELCSTATES) {
-                encoder->rgb_state.melclen = J[++encoder->rgb_state.melcstate];
-                encoder->rgb_state.melcorder = (1U << encoder->rgb_state.melclen);
-            }
-        }
-        if (temp != 8) {
-            decode_eatbits(encoder, temp + 1);  /* consume the leading
-                                                            0 of the remainder encoding */
-            break;
-        }
-        decode_eatbits(encoder, 8);
-    } while (1);
-
-    /* read the length of the remainder */
-    if (encoder->rgb_state.melclen) {
-        runlen += encoder->io_word >> (32 - encoder->rgb_state.melclen);
-        decode_eatbits(encoder, encoder->rgb_state.melclen);
-    }
-
-    /* adjust melcoder parameters */
-    if (encoder->rgb_state.melcstate) {
-        encoder->rgb_state.melclen = J[--encoder->rgb_state.melcstate];
-        encoder->rgb_state.melcorder = (1U << encoder->rgb_state.melclen);
-    }
-
-    return runlen;
-}
-
-#endif
-
-static int decode_channel_run(Encoder *encoder, Channel *channel)
-{
-    int runlen = 0;
-
-    do {
-        register int temp, hits;
-        temp = zeroLUT[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
-                                                                      input stream, up to 8 */
-        for (hits = 1; hits <= temp; hits++) {
-            runlen += channel->state.melcorder;
-
-            if (channel->state.melcstate < MELCSTATES) {
-                channel->state.melclen = J[++channel->state.melcstate];
-                channel->state.melcorder = (1U << channel->state.melclen);
-            }
-        }
-        if (temp != 8) {
-            decode_eatbits(encoder, temp + 1);  /* consume the leading
-                                                            0 of the remainder encoding */
-            break;
-        }
-        decode_eatbits(encoder, 8);
-    } while (1);
-
-    /* read the length of the remainder */
-    if (channel->state.melclen) {
-        runlen += encoder->io_word >> (32 - channel->state.melclen);
-        decode_eatbits(encoder, channel->state.melclen);
-    }
-
-    /* adjust melcoder parameters */
-    if (channel->state.melcstate) {
-        channel->state.melclen = J[--channel->state.melcstate];
-        channel->state.melcorder = (1U << channel->state.melclen);
-    }
-
-    return runlen;
-}
-
-#else
-
-static INLINE int find_msb(int x)
-{
-    int r;
-
-    __asm__("bsrl %1,%0\n\t"
-            "jnz 1f\n\t"
-            "movl $-1,%0\n"
-            "1:" : "=r" (r) : "rm" (x));
-    return r + 1;
-}
-
-static INLINE void encode_run(Encoder *encoder, unsigned int len)
-{
-    int odd = len & 1U;
-    int msb;
-
-    len &= ~1U;
-
-    while ((msb = find_msb(len))) {
-        len &= ~(1 << (msb - 1));
-        ASSERT(encoder->usr, msb < 32);
-        encode(encoder, (1 << (msb)) - 1, msb);
-        encode(encoder, 0, 1);
-    }
-
-    if (odd) {
-        encode(encoder, 2, 2);
-    } else {
-        encode(encoder, 0, 1);
-    }
-}
-
-static INLINE unsigned int decode_run(Encoder *encoder)
-{
-    unsigned int len = 0;
-    int count;
-
-    do {
-        count = 0;
-        while (encoder->io_word & (1U << 31)) {
-            decode_eatbits(encoder, 1);
-            count++;
-            ASSERT(encoder->usr, count < 32);
-        }
-        decode_eatbits(encoder, 1);
-        len += (1U << count) >> 1;
-    } while (count > 1);
-
-    return len;
-}
-
-#endif
-#endif
-
-static INLINE void init_decode_io(Encoder *encoder)
-{
-    encoder->io_next_word = encoder->io_word = *(encoder->io_now++);
-    encoder->io_available_bits = 0;
-}
-
-#ifdef __GNUC__
-#define ATTR_PACKED __attribute__ ((__packed__))
-#else
-#define ATTR_PACKED
-#pragma pack(push)
-#pragma pack(1)
-#endif
-
-typedef struct ATTR_PACKED one_byte_pixel_t {
-    BYTE a;
-} one_byte_t;
-
-typedef struct ATTR_PACKED three_bytes_pixel_t {
-    BYTE a;
-    BYTE b;
-    BYTE c;
-} three_bytes_t;
-
-typedef struct ATTR_PACKED four_bytes_pixel_t {
-    BYTE a;
-    BYTE b;
-    BYTE c;
-    BYTE d;
-} four_bytes_t;
-
-typedef struct ATTR_PACKED rgb32_pixel_t {
-    BYTE b;
-    BYTE g;
-    BYTE r;
-    BYTE pad;
-} rgb32_pixel_t;
-
-typedef struct ATTR_PACKED rgb24_pixel_t {
-    BYTE b;
-    BYTE g;
-    BYTE r;
-} rgb24_pixel_t;
-
-typedef uint16_t rgb16_pixel_t;
-
-#ifndef __GNUC__
-#pragma pack(pop)
-#endif
-
-#undef ATTR_PACKED
-
-#define ONE_BYTE
-#include "quic_tmpl.c"
-
-#define FOUR_BYTE
-#include "quic_tmpl.c"
-
-#ifdef QUIC_RGB
-
-#define QUIC_RGB32
-#include "quic_rgb_tmpl.c"
-
-#define QUIC_RGB24
-#include "quic_rgb_tmpl.c"
-
-#define QUIC_RGB16
-#include "quic_rgb_tmpl.c"
-
-#define QUIC_RGB16_TO_32
-#include "quic_rgb_tmpl.c"
-
-#else
-
-#define THREE_BYTE
-#include "quic_tmpl.c"
-
-#endif
-
-static void fill_model_structures(Encoder *encoder, FamilyStat *family_stat,
-                                  unsigned int rep_first, unsigned int first_size,
-                                  unsigned int rep_next, unsigned int mul_size,
-                                  unsigned int levels, unsigned int ncounters,
-                                  unsigned int nbuckets, unsigned int n_buckets_ptrs)
-{
-    unsigned int
-    bsize,
-    bstart,
-    bend = 0,
-    repcntr,
-    bnumber;
-
-    COUNTER * free_counter = family_stat->counters;/* first free location in the array of
-                                                      counters */
-
-    bnumber = 0;
-
-    repcntr = rep_first + 1;    /* first bucket */
-    bsize = first_size;
-
-    do { /* others */
-        if (bnumber) {
-            bstart = bend + 1;
-        } else {
-            bstart = 0;
-        }
-
-        if (!--repcntr) {
-            repcntr = rep_next;
-            bsize *= mul_size;
-        }
-
-        bend = bstart + bsize - 1;
-        if (bend + bsize >= levels) {
-            bend = levels - 1;
-        }
-
-        family_stat->buckets_buf[bnumber].pcounters = free_counter;
-        free_counter += ncounters;
-
-        ASSERT(encoder->usr, bstart < n_buckets_ptrs);
-        {
-            unsigned int i;
-            ASSERT(encoder->usr, bend < n_buckets_ptrs);
-            for (i = bstart; i <= bend; i++) {
-                family_stat->buckets_ptrs[i] = family_stat->buckets_buf + bnumber;
-            }
-        }
-
-        bnumber++;
-    } while (bend < levels - 1);
-
-    ASSERT(encoder->usr, free_counter - family_stat->counters == nbuckets * ncounters);
-}
-
-static void find_model_params(Encoder *encoder,
-                              const int bpc,
-                              unsigned int *ncounters,
-                              unsigned int *levels,
-                              unsigned int *n_buckets_ptrs,
-                              unsigned int *repfirst,
-                              unsigned int *firstsize,
-                              unsigned int *repnext,
-                              unsigned int *mulsize,
-                              unsigned int *nbuckets)
-{
-    unsigned int bsize;              /* bucket size */
-    unsigned int bstart, bend = 0;   /* bucket start and end, range : 0 to levels-1*/
-    unsigned int repcntr;            /* helper */
-
-    ASSERT(encoder->usr, bpc <= 8 && bpc > 0);
-
-
-    *ncounters = 8;
-
-    *levels = 0x1 << bpc;
-
-    *n_buckets_ptrs = 0;  /* ==0 means: not set yet */
-
-    switch (evol) {   /* set repfirst firstsize repnext mulsize */
-    case 1: /* buckets contain following numbers of contexts: 1 1 1 2 2 4 4 8 8 ... */
-        *repfirst = 3;
-        *firstsize = 1;
-        *repnext = 2;
-        *mulsize = 2;
-        break;
-    case 3: /* 1 2 4 8 16 32 64 ... */
-        *repfirst = 1;
-        *firstsize = 1;
-        *repnext = 1;
-        *mulsize = 2;
-        break;
-    case 5:                     /* 1 4 16 64 256 1024 4096 16384 65536 */
-        *repfirst = 1;
-        *firstsize = 1;
-        *repnext = 1;
-        *mulsize = 4;
-        break;
-    case 0: /* obsolete */
-    case 2: /* obsolete */
-    case 4: /* obsolete */
-        encoder->usr->error(encoder->usr, "findmodelparams(): evol value obsolete!!!\n");
-    default:
-        encoder->usr->error(encoder->usr, "findmodelparams(): evol out of range!!!\n");
-    }
-
-    *nbuckets = 0;
-    repcntr = *repfirst + 1;    /* first bucket */
-    bsize = *firstsize;
-
-    do { /* other buckets */
-        if (nbuckets) {         /* bucket start */
-            bstart = bend + 1;
-        } else {
-            bstart = 0;
-        }
-
-        if (!--repcntr) {         /* bucket size */
-            repcntr = *repnext;
-            bsize *= *mulsize;
-        }
-
-        bend = bstart + bsize - 1;  /* bucket end */
-        if (bend + bsize >= *levels) {  /* if following bucked was bigger than current one */
-            bend = *levels - 1;     /* concatenate them */
-        }
-
-        if (!*n_buckets_ptrs) {           /* array size not set yet? */
-            *n_buckets_ptrs = *levels;
- #if 0
-            if (bend == *levels - 1) {   /* this bucket is last - all in the first array */
-                *n_buckets_ptrs = *levels;
-            } else if (bsize >= 256) { /* this bucket is allowed to reside in the 2nd table */
-                b_lo_ptrs = bstart;
-                assert(bstart);     /* previous bucket exists */
-            }
- #endif
-        }
-
-        (*nbuckets)++;
-    } while (bend < *levels - 1);
-}
-
-static int init_model_structures(Encoder *encoder, FamilyStat *family_stat,
-                                 unsigned int rep_first, unsigned int first_size,
-                                 unsigned int rep_next, unsigned int mul_size,
-                                 unsigned int levels, unsigned int ncounters,
-                                 unsigned int n_buckets_ptrs, unsigned int n_buckets)
-{
-    family_stat->buckets_ptrs = (s_bucket **)encoder->usr->malloc(encoder->usr,
-                                                                  n_buckets_ptrs *
-                                                                  sizeof(s_bucket *));
-    if (!family_stat->buckets_ptrs) {
-        return FALSE;
-    }
-
-    family_stat->counters = (COUNTER *)encoder->usr->malloc(encoder->usr,
-                                                            n_buckets * sizeof(COUNTER) *
-                                                            MAXNUMCODES);
-    if (!family_stat->counters) {
-        goto error_1;
-    }
-
-    family_stat->buckets_buf = (s_bucket *)encoder->usr->malloc(encoder->usr,
-                                                                n_buckets * sizeof(s_bucket));
-    if (!family_stat->buckets_buf) {
-        goto error_2;
-    }
-
-    fill_model_structures(encoder, family_stat, rep_first, first_size, rep_next, mul_size, levels,
-                          ncounters, n_buckets, n_buckets_ptrs);
-
-    return TRUE;
-
-error_2:
-    encoder->usr->free(encoder->usr, family_stat->counters);
-
-error_1:
-    encoder->usr->free(encoder->usr, family_stat->buckets_ptrs);
-
-    return FALSE;
-}
-
-static void free_family_stat(QuicUsrContext *usr, FamilyStat *family_stat)
-{
-    usr->free(usr, family_stat->buckets_ptrs);
-    usr->free(usr, family_stat->counters);
-    usr->free(usr, family_stat->buckets_buf);
-}
-
-static int init_channel(Encoder *encoder, Channel *channel)
-{
-    unsigned int ncounters;
-    unsigned int levels;
-    unsigned int rep_first;
-    unsigned int first_size;
-    unsigned int rep_next;
-    unsigned int mul_size;
-    unsigned int n_buckets;
-    unsigned int n_buckets_ptrs;
-
-    channel->encoder = encoder;
-    channel->state.encoder = encoder;
-    channel->correlate_row_width = 0;
-    channel->correlate_row = NULL;
-
-    find_model_params(encoder, 8, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
-                      &first_size, &rep_next, &mul_size, &n_buckets);
-    encoder->n_buckets_8bpc = n_buckets;
-    if (!init_model_structures(encoder, &channel->family_stat_8bpc, rep_first, first_size,
-                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
-                               n_buckets)) {
-        return FALSE;
-    }
-
-    find_model_params(encoder, 5, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
-                      &first_size, &rep_next, &mul_size, &n_buckets);
-    encoder->n_buckets_5bpc = n_buckets;
-    if (!init_model_structures(encoder, &channel->family_stat_5bpc, rep_first, first_size,
-                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
-                               n_buckets)) {
-        free_family_stat(encoder->usr, &channel->family_stat_8bpc);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-static void destroy_channel(Channel *channel)
-{
-    QuicUsrContext *usr = channel->encoder->usr;
-    if (channel->correlate_row) {
-        usr->free(usr, channel->correlate_row - 1);
-    }
-    free_family_stat(usr, &channel->family_stat_8bpc);
-    free_family_stat(usr, &channel->family_stat_5bpc);
-}
-
-static int init_encoder(Encoder *encoder, QuicUsrContext *usr)
-{
-    int i;
-
-    encoder->usr = usr;
-    encoder->rgb_state.encoder = encoder;
-
-    for (i = 0; i < MAX_CHANNELS; i++) {
-        if (!init_channel(encoder, &encoder->channels[i])) {
-            for (--i; i >= 0; i--) {
-                destroy_channel(&encoder->channels[i]);
-            }
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-static int encoder_reste(Encoder *encoder, uint32_t *io_ptr, uint32_t *io_ptr_end)
-{
-    ASSERT(encoder->usr, ((unsigned long)io_ptr % 4) == ((unsigned long)io_ptr_end % 4));
-    ASSERT(encoder->usr, io_ptr <= io_ptr_end);
-
-    encoder->rgb_state.waitcnt = 0;
-    encoder->rgb_state.tabrand_seed = stabrand();
-    encoder->rgb_state.wmidx = DEFwmistart;
-    encoder->rgb_state.wmileft = wminext;
-    set_wm_trigger(&encoder->rgb_state);
-
-#if defined(RLE) && defined(RLE_STAT)
-    encoder_init_rle(&encoder->rgb_state);
-#endif
-
-    encoder->io_words_count = (uint32_t)(io_ptr_end - io_ptr);
-    encoder->io_now = io_ptr;
-    encoder->io_end = io_ptr_end;
-    encoder->rows_completed = 0;
-
-    return TRUE;
-}
-
-static int encoder_reste_channels(Encoder *encoder, int channels, int width, int bpc)
-{
-    int i;
-
-    encoder->num_channels = channels;
-
-    for (i = 0; i < channels; i++) {
-        s_bucket *bucket;
-        s_bucket *end_bucket;
-
-        if (encoder->channels[i].correlate_row_width < width) {
-            encoder->channels[i].correlate_row_width = 0;
-            if (encoder->channels[i].correlate_row) {
-                encoder->usr->free(encoder->usr, encoder->channels[i].correlate_row - 1);
-            }
-            if (!(encoder->channels[i].correlate_row = (BYTE *)encoder->usr->malloc(encoder->usr,
-                                                                                    width + 1))) {
-                return FALSE;
-            }
-            encoder->channels[i].correlate_row++;
-            encoder->channels[i].correlate_row_width = width;
-        }
-
-        if (bpc == 8) {
-            MEMCLEAR(encoder->channels[i].family_stat_8bpc.counters,
-                     encoder->n_buckets_8bpc * sizeof(COUNTER) * MAXNUMCODES);
-            bucket = encoder->channels[i].family_stat_8bpc.buckets_buf;
-            end_bucket = bucket + encoder->n_buckets_8bpc;
-            for (; bucket < end_bucket; bucket++) {
-                bucket->bestcode = /*BPC*/ 8 - 1;
-            }
-            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_8bpc.buckets_ptrs;
-        } else if (bpc == 5) {
-            MEMCLEAR(encoder->channels[i].family_stat_5bpc.counters,
-                     encoder->n_buckets_5bpc * sizeof(COUNTER) * MAXNUMCODES);
-            bucket = encoder->channels[i].family_stat_5bpc.buckets_buf;
-            end_bucket = bucket + encoder->n_buckets_5bpc;
-            for (; bucket < end_bucket; bucket++) {
-                bucket->bestcode = /*BPC*/ 5 - 1;
-            }
-            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_5bpc.buckets_ptrs;
-        } else {
-            encoder->usr->warn(encoder->usr, "%s: bad bpc %d\n", __FUNCTION__, bpc);
-            return FALSE;
-        }
-
-        encoder->channels[i].state.waitcnt = 0;
-        encoder->channels[i].state.tabrand_seed = stabrand();
-        encoder->channels[i].state.wmidx = DEFwmistart;
-        encoder->channels[i].state.wmileft = wminext;
-        set_wm_trigger(&encoder->channels[i].state);
-
-#if defined(RLE) && defined(RLE_STAT)
-        encoder_init_rle(&encoder->channels[i].state);
-#endif
-    }
-    return TRUE;
-}
-
-static void quic_image_params(Encoder *encoder, QuicImageType type, int *channels, int *bpc)
-{
-    ASSERT(encoder->usr, channels && bpc);
-    switch (type) {
-    case QUIC_IMAGE_TYPE_GRAY:
-        *channels = 1;
-        *bpc = 8;
-        break;
-    case QUIC_IMAGE_TYPE_RGB16:
-        *channels = 3;
-        *bpc = 5;
-#ifndef QUIC_RGB
-        encoder->usr->error(encoder->usr, "not implemented\n");
-#endif
-        break;
-    case QUIC_IMAGE_TYPE_RGB24:
-        *channels = 3;
-        *bpc = 8;
-        break;
-    case QUIC_IMAGE_TYPE_RGB32:
-        *channels = 3;
-        *bpc = 8;
-        break;
-    case QUIC_IMAGE_TYPE_RGBA:
-        *channels = 4;
-        *bpc = 8;
-        break;
-    case QUIC_IMAGE_TYPE_INVALID:
-    default:
-        *channels = 0;
-        *bpc = 0;
-        encoder->usr->error(encoder->usr, "bad image type\n");
-    }
-}
-
-#define FILL_LINES() {                                                  \
-    if (line == lines_end) {                                            \
-        int n = encoder->usr->more_lines(encoder->usr, &line);          \
-        if (n <= 0) {                                                   \
-            encoder->usr->error(encoder->usr, "more lines failed\n");   \
-        }                                                               \
-        lines_end = line + n * stride;                                  \
-    }                                                                   \
-}
-
-#define NEXT_LINE() {       \
-    line += stride;         \
-    FILL_LINES();           \
-}
-
-#define QUIC_COMPRESS_RGB(bits)                                                                 \
-        encoder->channels[0].correlate_row[-1] = 0;                                             \
-        encoder->channels[1].correlate_row[-1] = 0;                                             \
-        encoder->channels[2].correlate_row[-1] = 0;                                             \
-        quic_rgb##bits##_compress_row0(encoder, (rgb##bits##_pixel_t *)(line), width);          \
-        encoder->rows_completed++;                                                              \
-        for (row = 1; row < height; row++) {                                                    \
-            prev = line;                                                                        \
-            NEXT_LINE();                                                                        \
-            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];     \
-            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];     \
-            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];     \
-            quic_rgb##bits##_compress_row(encoder, (rgb##bits##_pixel_t *)prev,                 \
-                                          (rgb##bits##_pixel_t *)line, width);                  \
-            encoder->rows_completed++;                                                          \
-        }
-
-int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
-                uint8_t *line, unsigned int num_lines, int stride,
-                uint32_t *io_ptr, unsigned int num_io_words)
-{
-    Encoder *encoder = (Encoder *)quic;
-    uint32_t *io_ptr_end = io_ptr + num_io_words;
-    uint8_t *lines_end;
-    int row;
-    uint8_t *prev;
-    int channels;
-    int bpc;
-#ifndef QUIC_RGB
-    int i;
-#endif
-
-    ASSERT(encoder->usr, line);
-    lines_end = line + num_lines * stride;
-
-    quic_image_params(encoder, type, &channels, &bpc);
-
-    if (!encoder_reste(encoder, io_ptr, io_ptr_end) ||
-        !encoder_reste_channels(encoder, channels, width, bpc)) {
-        return QUIC_ERROR;
-    }
-
-    encoder->io_word = 0;
-    encoder->io_available_bits = 32;
-
-    encode_32(encoder, QUIC_MAGIC);
-    encode_32(encoder, QUIC_VERSION);
-    encode_32(encoder, type);
-    encode_32(encoder, width);
-    encode_32(encoder, height);
-
-    FILL_LINES();
-
-    switch (type) {
-#ifdef QUIC_RGB
-    case QUIC_IMAGE_TYPE_RGB32:
-        ASSERT(encoder->usr, ABS(stride) >= width * 4);
-        QUIC_COMPRESS_RGB(32);
-        break;
-    case QUIC_IMAGE_TYPE_RGB24:
-        ASSERT(encoder->usr, ABS(stride) >= width * 3);
-        QUIC_COMPRESS_RGB(24);
-        break;
-    case QUIC_IMAGE_TYPE_RGB16:
-        ASSERT(encoder->usr, ABS(stride) >= width * 2);
-        QUIC_COMPRESS_RGB(16);
-        break;
-    case QUIC_IMAGE_TYPE_RGBA:
-        ASSERT(encoder->usr, ABS(stride) >= width * 4);
-
-        encoder->channels[0].correlate_row[-1] = 0;
-        encoder->channels[1].correlate_row[-1] = 0;
-        encoder->channels[2].correlate_row[-1] = 0;
-        quic_rgb32_compress_row0(encoder, (rgb32_pixel_t *)(line), width);
-
-        encoder->channels[3].correlate_row[-1] = 0;
-        quic_four_compress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(line + 3), width);
-
-        encoder->rows_completed++;
-
-        for (row = 1; row < height; row++) {
-            prev = line;
-            NEXT_LINE();
-            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
-            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
-            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
-            quic_rgb32_compress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)line, width);
-
-            encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
-            quic_four_compress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
-                                   (four_bytes_t *)(line + 3), width);
-            encoder->rows_completed++;
-        }
-        break;
-#else
-    case QUIC_IMAGE_TYPE_RGB24:
-        ASSERT(encoder->usr, ABS(stride) >= width * 3);
-        for (i = 0; i < 3; i++) {
-            encoder->channels[i].correlate_row[-1] = 0;
-            quic_three_compress_row0(encoder, &encoder->channels[i], (three_bytes_t *)(line + i),
-                                     width);
-        }
-        encoder->rows_completed++;
-        for (row = 1; row < height; row++) {
-            prev = line;
-            NEXT_LINE();
-            for (i = 0; i < 3; i++) {
-                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
-                quic_three_compress_row(encoder, &encoder->channels[i], (three_bytes_t *)(prev + i),
-                                        (three_bytes_t *)(line + i), width);
-            }
-            encoder->rows_completed++;
-        }
-        break;
-    case QUIC_IMAGE_TYPE_RGB32:
-    case QUIC_IMAGE_TYPE_RGBA:
-        ASSERT(encoder->usr, ABS(stride) >= width * 4);
-        for (i = 0; i < channels; i++) {
-            encoder->channels[i].correlate_row[-1] = 0;
-            quic_four_compress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(line + i),
-                                    width);
-        }
-        encoder->rows_completed++;
-        for (row = 1; row < height; row++) {
-            prev = line;
-            NEXT_LINE();
-            for (i = 0; i < channels; i++) {
-                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
-                quic_four_compress_row(encoder, &encoder->channels[i], (four_bytes_t *)(prev + i),
-                                       (four_bytes_t *)(line + i), width);
-            }
-            encoder->rows_completed++;
-        }
-        break;
-#endif
-    case QUIC_IMAGE_TYPE_GRAY:
-        ASSERT(encoder->usr, ABS(stride) >= width);
-        encoder->channels[0].correlate_row[-1] = 0;
-        quic_one_compress_row0(encoder, &encoder->channels[0], (one_byte_t *)line, width);
-        encoder->rows_completed++;
-        for (row = 1; row < height; row++) {
-            prev = line;
-            NEXT_LINE();
-            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
-            quic_one_compress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
-                                  (one_byte_t *)line, width);
-            encoder->rows_completed++;
-        }
-        break;
-    case QUIC_IMAGE_TYPE_INVALID:
-    default:
-        encoder->usr->error(encoder->usr, "bad image type\n");
-    }
-
-    flush(encoder);
-    encoder->io_words_count -= (uint32_t)(encoder->io_end - encoder->io_now);
-
-    return encoder->io_words_count;
-}
-
-int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
-                      QuicImageType *out_type, int *out_width, int *out_height)
-{
-    Encoder *encoder = (Encoder *)quic;
-    uint32_t *io_ptr_end = io_ptr + num_io_words;
-    QuicImageType type;
-    int width;
-    int height;
-    uint32_t magic;
-    uint32_t version;
-    int channels;
-    int bpc;
-
-    if (!encoder_reste(encoder, io_ptr, io_ptr_end)) {
-        return QUIC_ERROR;
-    }
-
-    init_decode_io(encoder);
-
-    magic = encoder->io_word;
-    decode_eat32bits(encoder);
-    if (magic != QUIC_MAGIC) {
-        encoder->usr->warn(encoder->usr, "bad magic\n");
-        return QUIC_ERROR;
-    }
-
-    version = encoder->io_word;
-    decode_eat32bits(encoder);
-    if (version != QUIC_VERSION) {
-        encoder->usr->warn(encoder->usr, "bad version\n");
-        return QUIC_ERROR;
-    }
-
-    type = (QuicImageType)encoder->io_word;
-    decode_eat32bits(encoder);
-
-    width = encoder->io_word;
-    decode_eat32bits(encoder);
-
-    height = encoder->io_word;
-    decode_eat32bits(encoder);
-
-    quic_image_params(encoder, type, &channels, &bpc);
-
-    if (!encoder_reste_channels(encoder, channels, width, bpc)) {
-        return QUIC_ERROR;
-    }
-
-    *out_width = encoder->width = width;
-    *out_height = encoder->height = height;
-    *out_type = encoder->type = type;
-    return QUIC_OK;
-}
-
-#ifndef QUIC_RGB
-static void clear_row(four_bytes_t *row, int width)
-{
-    four_bytes_t *end;
-    for (end = row + width; row < end; row++) {
-        row->a = 0;
-    }
-}
-
-#endif
-
-#ifdef QUIC_RGB
-
-static void uncompress_rgba(Encoder *encoder, uint8_t *buf, int stride)
-{
-    unsigned int row;
-    uint8_t *prev;
-
-    encoder->channels[0].correlate_row[-1] = 0;
-    encoder->channels[1].correlate_row[-1] = 0;
-    encoder->channels[2].correlate_row[-1] = 0;
-    quic_rgb32_uncompress_row0(encoder, (rgb32_pixel_t *)buf, encoder->width);
-
-    encoder->channels[3].correlate_row[-1] = 0;
-    quic_four_uncompress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(buf + 3),
-                              encoder->width);
-
-    encoder->rows_completed++;
-    for (row = 1; row < encoder->height; row++) {
-        prev = buf;
-        buf += stride;
-
-        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
-        encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
-        encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
-        quic_rgb32_uncompress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)buf,
-                                  encoder->width);
-
-        encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
-        quic_four_uncompress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
-                                 (four_bytes_t *)(buf + 3), encoder->width);
-
-        encoder->rows_completed++;
-    }
-}
-
-#endif
-
-static void uncompress_gray(Encoder *encoder, uint8_t *buf, int stride)
-{
-    unsigned int row;
-    uint8_t *prev;
-
-    encoder->channels[0].correlate_row[-1] = 0;
-    quic_one_uncompress_row0(encoder, &encoder->channels[0], (one_byte_t *)buf, encoder->width);
-    encoder->rows_completed++;
-    for (row = 1; row < encoder->height; row++) {
-        prev = buf;
-        buf += stride;
-        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
-        quic_one_uncompress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
-                                (one_byte_t *)buf, encoder->width);
-        encoder->rows_completed++;
-    }
-}
-
-#define QUIC_UNCOMPRESS_RGB(prefix, type)                                                       \
-        encoder->channels[0].correlate_row[-1] = 0;                                             \
-        encoder->channels[1].correlate_row[-1] = 0;                                             \
-        encoder->channels[2].correlate_row[-1] = 0;                                             \
-        quic_rgb##prefix##_uncompress_row0(encoder, (type *)buf, encoder->width);  \
-        encoder->rows_completed++;                                                              \
-        for (row = 1; row < encoder->height; row++) {                                           \
-            prev = buf;                                                                         \
-            buf += stride;                                                                      \
-            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];     \
-            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];     \
-            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];     \
-            quic_rgb##prefix##_uncompress_row(encoder, (type *)prev, (type *)buf,               \
-                                              encoder->width);                                  \
-            encoder->rows_completed++;                                                          \
-        }
-        
-int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
-{
-    Encoder *encoder = (Encoder *)quic;
-    unsigned int row;
-    uint8_t *prev;
-#ifndef QUIC_RGB
-    int i;
-#endif
-
-    ASSERT(encoder->usr, buf);
-
-    switch (encoder->type) {
-#ifdef QUIC_RGB
-    case QUIC_IMAGE_TYPE_RGB32:
-    case QUIC_IMAGE_TYPE_RGB24:
-        if (type == QUIC_IMAGE_TYPE_RGB32) {
-            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
-            QUIC_UNCOMPRESS_RGB(32, rgb32_pixel_t);
-            break;
-        } else if (type == QUIC_IMAGE_TYPE_RGB24) {
-            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 3);
-            QUIC_UNCOMPRESS_RGB(24, rgb24_pixel_t);
-            break;
-        }
-        encoder->usr->warn(encoder->usr, "unsupported output format\n");
-        return QUIC_ERROR;
-    case QUIC_IMAGE_TYPE_RGB16:
-        if (type == QUIC_IMAGE_TYPE_RGB16) {
-            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 2);
-            QUIC_UNCOMPRESS_RGB(16, rgb16_pixel_t);
-        } else if (type == QUIC_IMAGE_TYPE_RGB32) {
-            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
-            QUIC_UNCOMPRESS_RGB(16_to_32, rgb32_pixel_t);
-        } else {
-            encoder->usr->warn(encoder->usr, "unsupported output format\n");
-            return QUIC_ERROR;
-        }
-
-        break;
-    case QUIC_IMAGE_TYPE_RGBA:
-
-        if (type != QUIC_IMAGE_TYPE_RGBA) {
-            encoder->usr->warn(encoder->usr, "unsupported output format\n");
-            return QUIC_ERROR;
-        }
-        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
-        uncompress_rgba(encoder, buf, stride);
-        break;
-#else
-    case QUIC_IMAGE_TYPE_RGB24:
-        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 3);
-        for (i = 0; i < 3; i++) {
-            encoder->channels[i].correlate_row[-1] = 0;
-            quic_three_uncompress_row0(encoder, &encoder->channels[i], (three_bytes_t *)(buf + i),
-                                       encoder->width);
-        }
-        encoder->rows_completed++;
-        for (row = 1; row < encoder->height; row++) {
-            prev = buf;
-            buf += stride;
-            for (i = 0; i < 3; i++) {
-                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
-                quic_three_uncompress_row(encoder, &encoder->channels[i],
-                                          (three_bytes_t *)(prev + i),
-                                          (three_bytes_t *)(buf + i),
-                                          encoder->width);
-            }
-            encoder->rows_completed++;
-        }
-        break;
-    case QUIC_IMAGE_TYPE_RGB32:
-        ASSERT(encoder->usr, ABS(stride) >= encoder->width * 4);
-        for (i = 0; i < 3; i++) {
-            encoder->channels[i].correlate_row[-1] = 0;
-            quic_four_uncompress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(buf + i),
-                                      encoder->width);
-        }
-        clear_row((four_bytes_t *)(buf + 3), encoder->width);
-        encoder->rows_completed++;
-        for (row = 1; row < encoder->height; row++) {
-            prev = buf;
-            buf += stride;
-            for (i = 0; i < 3; i++) {
-                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
-                quic_four_uncompress_row(encoder, &encoder->channels[i],
-                                         (four_bytes_t *)(prev + i),
-                                         (four_bytes_t *)(buf + i),
-                                         encoder->width);
-            }
-            clear_row((four_bytes_t *)(buf + 3), encoder->width);
-            encoder->rows_completed++;
-        }
-        break;
-    case QUIC_IMAGE_TYPE_RGBA:
-        ASSERT(encoder->usr, ABS(stride) >= encoder->width * 4);
-        for (i = 0; i < 4; i++) {
-            encoder->channels[i].correlate_row[-1] = 0;
-            quic_four_uncompress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(buf + i),
-                                      encoder->width);
-        }
-        encoder->rows_completed++;
-        for (row = 1; row < encoder->height; row++) {
-            prev = buf;
-            buf += stride;
-            for (i = 0; i < 4; i++) {
-                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
-                quic_four_uncompress_row(encoder, &encoder->channels[i],
-                                         (four_bytes_t *)(prev + i),
-                                         (four_bytes_t *)(buf + i),
-                                         encoder->width);
-            }
-            encoder->rows_completed++;
-        }
-        break;
-#endif
-    case QUIC_IMAGE_TYPE_GRAY:
-
-        if (type != QUIC_IMAGE_TYPE_GRAY) {
-            encoder->usr->warn(encoder->usr, "unsupported output format\n");
-            return QUIC_ERROR;
-        }
-        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width);
-        uncompress_gray(encoder, buf, stride);
-        break;
-    case QUIC_IMAGE_TYPE_INVALID:
-    default:
-        encoder->usr->error(encoder->usr, "bad image type\n");
-    }
-    return QUIC_OK;
-}
-
-static int need_init = TRUE;
-
-QuicContext *quic_create(QuicUsrContext *usr)
-{
-    Encoder *encoder;
-
-    if (!usr || need_init || !usr->error || !usr->warn || !usr->info || !usr->malloc ||
-        !usr->free || !usr->more_space || !usr->more_lines) {
-        return NULL;
-    }
-
-    if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) {
-        return NULL;
-    }
-
-    if (!init_encoder(encoder, usr)) {
-        usr->free(usr, encoder);
-        return NULL;
-    }
-    return (QuicContext *)encoder;
-}
-
-void quic_destroy(QuicContext *quic)
-{
-    Encoder *encoder = (Encoder *)quic;
-    int i;
-
-    if (!quic) {
-        return;
-    }
-
-    for (i = 0; i < MAX_CHANNELS; i++) {
-        destroy_channel(&encoder->channels[i]);
-    }
-    encoder->usr->free(encoder->usr, encoder);
-}
-
-void quic_init()
-{
-    if (!need_init) {
-        return;
-    }
-    need_init = FALSE;
-
-    family_init(&family_8bpc, 8, DEFmaxclen);
-    family_init(&family_5bpc, 5, DEFmaxclen);
-#if defined(RLE) && defined(RLE_STAT)
-    init_zeroLUT();
-#endif
-}
-
diff --git a/display/quic.h b/display/quic.h
deleted file mode 100644
index 9463760..0000000
--- a/display/quic.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef __QUIC_H
-#define __QUIC_H
-
-#include "quic_config.h"
-
-typedef enum {
-    QUIC_IMAGE_TYPE_INVALID,
-    QUIC_IMAGE_TYPE_GRAY,
-    QUIC_IMAGE_TYPE_RGB16,
-    QUIC_IMAGE_TYPE_RGB24,
-    QUIC_IMAGE_TYPE_RGB32,
-    QUIC_IMAGE_TYPE_RGBA
-} QuicImageType;
-
-#define QUIC_ERROR -1
-#define QUIC_OK 0
-
-typedef void *QuicContext;
-
-typedef struct QuicUsrContext QuicUsrContext;
-struct QuicUsrContext {
-    void (*error)(QuicUsrContext *usr, const char *fmt, ...);
-    void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
-    void (*info)(QuicUsrContext *usr, const char *fmt, ...);
-    void *(*malloc)(QuicUsrContext *usr, int size);
-    void (*free)(QuicUsrContext *usr, void *ptr);
-    int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
-    int (*more_lines)(QuicUsrContext *usr, uint8_t **lines); // on return the last line of previous
-                                                             // lines bunch must stil be valid
-};
-
-int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
-                uint8_t *lines, unsigned int num_lines, int stride,
-                uint32_t *io_ptr, unsigned int num_io_words);
-
-int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
-                      QuicImageType *type, int *width, int *height);
-int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride);
-
-
-QuicContext *quic_create(QuicUsrContext *usr);
-void quic_destroy(QuicContext *quic);
-
-void quic_init();
-
-#endif
-
diff --git a/display/quic_config.h b/display/quic_config.h
deleted file mode 100644
index 2c41ecb..0000000
--- a/display/quic_config.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef __QUIC_CONFIG_H
-#define __QUIC_CONFIG_H
-
-#include <spice/types.h>
-
-#ifdef __GNUC__
-
-#include <string.h>
-
-#define INLINE inline
-
-#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
-
-#else
-
-#ifdef QXLDD
-#include <windef.h>
-#include "os_dep.h"
-#define INLINE _inline
-#define MEMCLEAR(ptr, size) RtlZeroMemory(ptr, size)
-#else
-#include <stddef.h>
-#include <string.h>
-
-#define INLINE inline
-#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
-#endif
-
-
-#endif
-
-#endif
-
diff --git a/display/quic_family_tmpl.c b/display/quic_family_tmpl.c
deleted file mode 100644
index 695c482..0000000
--- a/display/quic_family_tmpl.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifdef QUIC_FAMILY_8BPC
-#undef QUIC_FAMILY_8BPC
-#define FNAME(name) name##_8bpc
-#define VNAME(name) name##_8bpc
-#define BPC 8
-#endif
-
-
-#ifdef QUIC_FAMILY_5BPC
-#undef QUIC_FAMILY_5BPC
-#define FNAME(name) name##_5bpc
-#define VNAME(name) name##_5bpc
-#define BPC 5
-#endif
-
-
-static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
-{
-    if (n < VNAME(family).nGRcodewords[l]) {
-        return (n >> l) + 1 + l;
-    } else {
-        return VNAME(family).notGRcwlen[l];
-    }
-}
-
-static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
-                                 unsigned int * const codewordlen)
-{
-    if (n < VNAME(family).nGRcodewords[l]) {
-        (*codeword) = bitat[l] | (n & bppmask[l]);
-        (*codewordlen) = (n >> l) + l + 1;
-    } else {
-        (*codeword) = n - VNAME(family).nGRcodewords[l];
-        (*codewordlen) = VNAME(family).notGRcwlen[l];
-    }
-}
-
-unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
-                                    unsigned int * const codewordlen)
-{
-    if (bits > VNAME(family).notGRprefixmask[l]) { /*GR*/
-        const unsigned int zeroprefix = cnt_l_zeroes(bits);       /* leading zeroes in codeword */
-        const unsigned int cwlen = zeroprefix + 1 + l;            /* codeword length */
-        (*codewordlen) = cwlen;
-        return (zeroprefix << l) | ((bits >> (32 - cwlen)) & bppmask[l]);
-    } else { /* not-GR */
-        const unsigned int cwlen = VNAME(family).notGRcwlen[l];
-        (*codewordlen) = cwlen;
-        return VNAME(family).nGRcodewords[l] + ((bits) >> (32 - cwlen) &
-                                                bppmask[VNAME(family).notGRsuffixlen[l]]);
-    }
-}
-
-/* update the bucket using just encoded curval */
-static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
-                                const BYTE curval, unsigned int bpp)
-{
-    COUNTER * const pcounters = bucket->pcounters;
-    unsigned int i;
-    unsigned int bestcode;
-    unsigned int bestcodelen;
-    //unsigned int bpp = encoder->bpp;
-
-    /* update counters, find minimum */
-
-    bestcode = bpp - 1;
-    bestcodelen = (pcounters[bestcode] += FNAME(golomb_code_len)(curval, bestcode));
-
-    for (i = bpp - 2; i < bpp; i--) { /* NOTE: expression i<bpp for signed int i would be: i>=0 */
-        const unsigned int ithcodelen = (pcounters[i] += FNAME(golomb_code_len)(curval, i));
-
-        if (ithcodelen < bestcodelen) {
-            bestcode = i;
-            bestcodelen = ithcodelen;
-        }
-    }
-
-    bucket->bestcode = bestcode; /* store the found minimum */
-
-    if (bestcodelen > state->wm_trigger) { /* halving counters? */
-        for (i = 0; i < bpp; i++) {
-            pcounters[i] >>= 1;
-        }
-    }
-}
-
-static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
-{
-    ASSERT(channel->encoder->usr, val < (0x1U << BPC));
-
-    return channel->_buckets_ptrs[val];
-}
-
-#undef FNAME
-#undef VNAME
-#undef BPC
-
diff --git a/display/quic_rgb_tmpl.c b/display/quic_rgb_tmpl.c
deleted file mode 100644
index b256d18..0000000
--- a/display/quic_rgb_tmpl.c
+++ /dev/null
@@ -1,766 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifdef QUIC_RGB32
-#undef QUIC_RGB32
-#define PIXEL rgb32_pixel_t
-#define FNAME(name) quic_rgb32_##name
-#define golomb_coding golomb_coding_8bpc
-#define golomb_decoding golomb_decoding_8bpc
-#define update_model update_model_8bpc
-#define find_bucket find_bucket_8bpc
-#define family family_8bpc
-#define BPC 8
-#define BPC_MASK 0xffU
-#define COMPRESS_IMP
-#define SET_r(pix, val) ((pix)->r = val)
-#define GET_r(pix) ((pix)->r)
-#define SET_g(pix, val) ((pix)->g = val)
-#define GET_g(pix) ((pix)->g)
-#define SET_b(pix, val) ((pix)->b = val)
-#define GET_b(pix) ((pix)->b)
-#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
-#endif
-
-#ifdef QUIC_RGB24
-#undef QUIC_RGB24
-#define PIXEL rgb24_pixel_t
-#define FNAME(name) quic_rgb24_##name
-#define golomb_coding golomb_coding_8bpc
-#define golomb_decoding golomb_decoding_8bpc
-#define update_model update_model_8bpc
-#define find_bucket find_bucket_8bpc
-#define family family_8bpc
-#define BPC 8
-#define BPC_MASK 0xffU
-#define COMPRESS_IMP
-#define SET_r(pix, val) ((pix)->r = val)
-#define GET_r(pix) ((pix)->r)
-#define SET_g(pix, val) ((pix)->g = val)
-#define GET_g(pix) ((pix)->g)
-#define SET_b(pix, val) ((pix)->b = val)
-#define GET_b(pix) ((pix)->b)
-#define UNCOMPRESS_PIX_START(pix)
-#endif
-
-#ifdef QUIC_RGB16
-#undef QUIC_RGB16
-#define PIXEL rgb16_pixel_t
-#define FNAME(name) quic_rgb16_##name
-#define golomb_coding golomb_coding_5bpc
-#define golomb_decoding golomb_decoding_5bpc
-#define update_model update_model_5bpc
-#define find_bucket find_bucket_5bpc
-#define family family_5bpc
-#define BPC 5
-#define BPC_MASK 0x1fU
-#define COMPRESS_IMP
-#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
-#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
-#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
-#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
-#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
-#define GET_b(pix) (*(pix) & 0x1f)
-#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
-#endif
-
-#ifdef QUIC_RGB16_TO_32
-#undef QUIC_RGB16_TO_32
-#define PIXEL rgb32_pixel_t
-#define FNAME(name) quic_rgb16_to_32_##name
-#define golomb_coding golomb_coding_5bpc
-#define golomb_decoding golomb_decoding_5bpc
-#define update_model update_model_5bpc
-#define find_bucket find_bucket_5bpc
-#define family family_5bpc
-#define BPC 5
-#define BPC_MASK 0x1fU
-
-#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
-#define GET_r(pix) ((pix)->r >> 3)
-#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
-#define GET_g(pix) ((pix)->g >> 3)
-#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
-#define GET_b(pix) ((pix)->b >> 3)
-#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
-#endif
-
-#define SAME_PIXEL(p1, p2)                                 \
-    (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) &&   \
-     GET_b(p1) == GET_b(p2))
-
-
-#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
-#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
-#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
-
-/*  a  */
-
-#define DECORELATE_0(channel, curr, bpc_mask)\
-    family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
-
-#define CORELATE_0(channel, curr, correlate, bpc_mask)\
-    ((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
-
-#ifdef PRED_1
-
-/*  (a+b)/2  */
-#define DECORELATE(channel, prev, curr, bpc_mask, r)                                            \
-    r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) +   \
-                        _PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
-
-#define CORELATE(channel, prev, curr, correlate, bpc_mask, r)                                   \
-    SET_##channel(r, ((family.xlatL2U[correlate] +                                              \
-          (int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
-#endif
-
-#ifdef PRED_2
-
-/*  .75a+.75b-.5c  */
-#define DECORELATE(channel, prev, curr, bpc_mask, r) {                          \
-    int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) -   \
-                        (int)(_PIXEL_C(channel, prev) << 1)) >> 2;              \
-    if (p < 0) {                                                                \
-        p = 0;                                                                  \
-    } else if ((unsigned)p > bpc_mask) {                                        \
-        p = bpc_mask;                                                           \
-    }                                                                           \
-    r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask];    \
-}
-
-#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) {                         \
-    const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) -     \
-                        (int)(_PIXEL_C(channel, prev) << 1) ) >> 2;                     \
-    const unsigned int s = family.xlatL2U[correlate];                                   \
-    if (!(p & ~bpc_mask)) {                                                             \
-        SET_##channel(r, (s + (unsigned)p) & bpc_mask);                                 \
-    } else if (p < 0) {                                                                 \
-        SET_##channel(r, s);                                                            \
-    } else {                                                                            \
-        SET_##channel(r, (s + bpc_mask) & bpc_mask);                                    \
-    }                                                                                   \
-}
-
-#endif
-
-
-#define COMPRESS_ONE_ROW0_0(channel)                                                \
-    correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)];            \
-    golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel,        \
-                  correlate_row_##channel[-1])->bestcode,                           \
-                  &codeword, &codewordlen);                                         \
-    encode(encoder, codeword, codewordlen);
-
-#define COMPRESS_ONE_ROW0(channel, index)                                               \
-    correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask);  \
-    golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel,        \
-                  correlate_row_##channel[index -1])->bestcode,                         \
-                  &codeword, &codewordlen);                                             \
-    encode(encoder, codeword, codewordlen);
-
-#define UPDATE_MODEL(index)                                                                 \
-    update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]),   \
-                correlate_row_r[index], bpc);                                               \
-    update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]),   \
-                correlate_row_g[index], bpc);                                               \
-    update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]),   \
-                correlate_row_b[index], bpc);
-
-
-#ifdef RLE_PRED_1
-#define RLE_PRED_1_IMP                                                                          \
-if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) {                                                \
-    if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) &&                         \
-                                i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) {    \
-        goto do_run;                                                                            \
-    }                                                                                           \
-}
-#else
-#define RLE_PRED_1_IMP
-#endif
-
-#ifdef RLE_PRED_2
-#define RLE_PRED_2_IMP                                                              \
-if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) {                                   \
-    if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) {  \
-        goto do_run;                                                                \
-    }                                                                               \
-}
-#else
-#define RLE_PRED_2_IMP
-#endif
-
-#ifdef RLE_PRED_3
-#define RLE_PRED_3_IMP                                                              \
-if (i > 1 &&  SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) {     \
-    goto do_run;                                                                    \
-}
-#else
-#define RLE_PRED_3_IMP
-#endif
-
-#ifdef COMPRESS_IMP
-
-static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
-                                     const PIXEL * const cur_row,
-                                     const int end,
-                                     const unsigned int waitmask,
-                                     const unsigned int bpc,
-                                     const unsigned int bpc_mask)
-{
-    Channel * const channel_r = encoder->channels;
-    Channel * const channel_g = channel_r + 1;
-    Channel * const channel_b = channel_g + 1;
-
-    BYTE * const correlate_row_r = channel_r->correlate_row;
-    BYTE * const correlate_row_g = channel_g->correlate_row;
-    BYTE * const correlate_row_b = channel_b->correlate_row;
-    int stopidx;
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (!i) {
-        unsigned int codeword, codewordlen;
-
-        COMPRESS_ONE_ROW0_0(r);
-        COMPRESS_ONE_ROW0_0(g);
-        COMPRESS_ONE_ROW0_0(b);
-
-        if (encoder->rgb_state.waitcnt) {
-            encoder->rgb_state.waitcnt--;
-        } else {
-            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-            UPDATE_MODEL(0);
-        }
-        stopidx = ++i + encoder->rgb_state.waitcnt;
-    } else {
-        stopidx = i + encoder->rgb_state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        for (; i <= stopidx; i++) {
-            unsigned int codeword, codewordlen;
-            COMPRESS_ONE_ROW0(r, i);
-            COMPRESS_ONE_ROW0(g, i);
-            COMPRESS_ONE_ROW0(b, i);
-        }
-
-        UPDATE_MODEL(stopidx);
-        stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-    }
-
-    for (; i < end; i++) {
-        unsigned int codeword, codewordlen;
-
-        COMPRESS_ONE_ROW0(r, i);
-        COMPRESS_ONE_ROW0(g, i);
-        COMPRESS_ONE_ROW0(b, i);
-    }
-    encoder->rgb_state.waitcnt = stopidx - end;
-}
-
-static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
-                                 unsigned int width)
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    int pos = 0;
-
-    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
-        if (encoder->rgb_state.wmileft) {
-            FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
-                                     bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
-            width -= encoder->rgb_state.wmileft;
-            pos += encoder->rgb_state.wmileft;
-        }
-
-        encoder->rgb_state.wmidx++;
-        set_wm_trigger(&encoder->rgb_state);
-        encoder->rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
-                                 bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)encoder->rgb_state.wmidx) {
-            encoder->rgb_state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
-    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-#define COMPRESS_ONE_0(channel) \
-    correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) -    \
-                                                (int)GET_##channel(prev_row) ) & bpc_mask]; \
-    golomb_coding(correlate_row_##channel[0],                                               \
-                  find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode,    \
-                  &codeword, &codewordlen);                                                 \
-    encode(encoder, codeword, codewordlen);
-
-#define COMPRESS_ONE(channel, index)                                                            \
-    DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask,                             \
-               correlate_row_##channel[index]);                                                 \
-    golomb_coding(correlate_row_##channel[index],                                               \
-                 find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode,  \
-                 &codeword, &codewordlen);                                                      \
-    encode(encoder, codeword, codewordlen);
-
-static void FNAME(compress_row_seg)(Encoder *encoder, int i,
-                                    const PIXEL * const prev_row,
-                                    const PIXEL * const cur_row,
-                                    const int end,
-                                    const unsigned int waitmask,
-                                    const unsigned int bpc,
-                                    const unsigned int bpc_mask)
-{
-    Channel * const channel_r = encoder->channels;
-    Channel * const channel_g = channel_r + 1;
-    Channel * const channel_b = channel_g + 1;
-
-    BYTE * const correlate_row_r = channel_r->correlate_row;
-    BYTE * const correlate_row_g = channel_g->correlate_row;
-    BYTE * const correlate_row_b = channel_b->correlate_row;
-    int stopidx;
-#ifdef RLE
-    int run_index = 0;
-    int run_size;
-#endif
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (!i) {
-        unsigned int codeword, codewordlen;
-
-        COMPRESS_ONE_0(r);
-        COMPRESS_ONE_0(g);
-        COMPRESS_ONE_0(b);
-
-        if (encoder->rgb_state.waitcnt) {
-            encoder->rgb_state.waitcnt--;
-        } else {
-            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-            UPDATE_MODEL(0);
-        }
-        stopidx = ++i + encoder->rgb_state.waitcnt;
-    } else {
-        stopidx = i + encoder->rgb_state.waitcnt;
-    }
-    for (;;) {
-        while (stopidx < end) {
-            for (; i <= stopidx; i++) {
-                unsigned int codeword, codewordlen;
-#ifdef RLE
-                RLE_PRED_1_IMP;
-                RLE_PRED_2_IMP;
-                RLE_PRED_3_IMP;
-#endif
-                COMPRESS_ONE(r, i);
-                COMPRESS_ONE(g, i);
-                COMPRESS_ONE(b, i);
-            }
-
-            UPDATE_MODEL(stopidx);
-            stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-        }
-
-        for (; i < end; i++) {
-            unsigned int codeword, codewordlen;
-#ifdef RLE
-            RLE_PRED_1_IMP;
-            RLE_PRED_2_IMP;
-            RLE_PRED_3_IMP;
-#endif
-            COMPRESS_ONE(r, i);
-            COMPRESS_ONE(g, i);
-            COMPRESS_ONE(b, i);
-        }
-        encoder->rgb_state.waitcnt = stopidx - end;
-
-        return;
-
-#ifdef RLE
-do_run:
-        run_index = i;
-        encoder->rgb_state.waitcnt = stopidx - i;
-        run_size = 0;
-
-        while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
-            run_size++;
-            if (++i == end) {
-                encode_run(encoder, run_size);
-                return;
-            }
-        }
-        encode_run(encoder, run_size);
-        stopidx = i + encoder->rgb_state.waitcnt;
-#endif
-    }
-}
-
-static void FNAME(compress_row)(Encoder *encoder,
-                                const PIXEL * const prev_row,
-                                const PIXEL * const cur_row,
-                                unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
-        if (encoder->rgb_state.wmileft) {
-            FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
-                                    pos + encoder->rgb_state.wmileft,
-                                    bppmask[encoder->rgb_state.wmidx],
-                                    bpc, bpc_mask);
-            width -= encoder->rgb_state.wmileft;
-            pos += encoder->rgb_state.wmileft;
-        }
-
-        encoder->rgb_state.wmidx++;
-        set_wm_trigger(&encoder->rgb_state);
-        encoder->rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
-                                bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)encoder->rgb_state.wmidx) {
-            encoder->rgb_state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
-    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-#endif
-
-#define UNCOMPRESS_ONE_ROW0_0(channel)                                                          \
-    correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel,           \
-                                                       correlate_row_##channel[-1])->bestcode,  \
-                                                       encoder->io_word, &codewordlen);         \
-    SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]);               \
-    decode_eatbits(encoder, codewordlen);
-
-#define UNCOMPRESS_ONE_ROW0(channel)                                                              \
-    correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel,             \
-                                                       correlate_row_##channel[i - 1])->bestcode, \
-                                                       encoder->io_word,                          \
-                                                       &codewordlen);                             \
-    SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i],       \
-                  bpc_mask));                                                                     \
-    decode_eatbits(encoder, codewordlen);
-
-static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
-                                       PIXEL * const cur_row,
-                                       const int end,
-                                       const unsigned int waitmask,
-                                       const unsigned int bpc,
-                                       const unsigned int bpc_mask)
-{
-    Channel * const channel_r = encoder->channels;
-    Channel * const channel_g = channel_r + 1;
-    Channel * const channel_b = channel_g + 1;
-
-    BYTE * const correlate_row_r = channel_r->correlate_row;
-    BYTE * const correlate_row_g = channel_g->correlate_row;
-    BYTE * const correlate_row_b = channel_b->correlate_row;
-    int stopidx;
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (!i) {
-        unsigned int codewordlen;
-
-        UNCOMPRESS_PIX_START(&cur_row[i]);
-        UNCOMPRESS_ONE_ROW0_0(r);
-        UNCOMPRESS_ONE_ROW0_0(g);
-        UNCOMPRESS_ONE_ROW0_0(b);
-
-        if (encoder->rgb_state.waitcnt) {
-            --encoder->rgb_state.waitcnt;
-        } else {
-            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-            UPDATE_MODEL(0);
-        }
-        stopidx = ++i + encoder->rgb_state.waitcnt;
-    } else {
-        stopidx = i + encoder->rgb_state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        for (; i <= stopidx; i++) {
-            unsigned int codewordlen;
-
-            UNCOMPRESS_PIX_START(&cur_row[i]);
-            UNCOMPRESS_ONE_ROW0(r);
-            UNCOMPRESS_ONE_ROW0(g);
-            UNCOMPRESS_ONE_ROW0(b);
-        }
-        UPDATE_MODEL(stopidx);
-        stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-    }
-
-    for (; i < end; i++) {
-        unsigned int codewordlen;
-
-        UNCOMPRESS_PIX_START(&cur_row[i]);
-        UNCOMPRESS_ONE_ROW0(r);
-        UNCOMPRESS_ONE_ROW0(g);
-        UNCOMPRESS_ONE_ROW0(b);
-    }
-    encoder->rgb_state.waitcnt = stopidx - end;
-}
-
-static void FNAME(uncompress_row0)(Encoder *encoder,
-                                   PIXEL * const cur_row,
-                                   unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
-        if (encoder->rgb_state.wmileft) {
-            FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
-                                       pos + encoder->rgb_state.wmileft,
-                                       bppmask[encoder->rgb_state.wmidx],
-                                       bpc, bpc_mask);
-            pos += encoder->rgb_state.wmileft;
-            width -= encoder->rgb_state.wmileft;
-        }
-
-        encoder->rgb_state.wmidx++;
-        set_wm_trigger(&encoder->rgb_state);
-        encoder->rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
-                                   bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)encoder->rgb_state.wmidx) {
-            encoder->rgb_state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
-    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-#define UNCOMPRESS_ONE_0(channel) \
-    correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel,           \
-                                                       correlate_row_##channel[-1])->bestcode,  \
-                                                       encoder->io_word, &codewordlen);         \
-    SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] +                    \
-                          GET_##channel(prev_row)) & bpc_mask);                                 \
-    decode_eatbits(encoder, codewordlen);
-
-#define UNCOMPRESS_ONE(channel)                                                                   \
-    correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel,             \
-                                                       correlate_row_##channel[i - 1])->bestcode, \
-                                                       encoder->io_word,                          \
-                                                       &codewordlen);                             \
-    CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask,            \
-             &cur_row[i]);                                                                        \
-    decode_eatbits(encoder, codewordlen);
-
-static void FNAME(uncompress_row_seg)(Encoder *encoder,
-                                      const PIXEL * const prev_row,
-                                      PIXEL * const cur_row,
-                                      int i,
-                                      const int end,
-                                      const unsigned int bpc,
-                                      const unsigned int bpc_mask)
-{
-    Channel * const channel_r = encoder->channels;
-    Channel * const channel_g = channel_r + 1;
-    Channel * const channel_b = channel_g + 1;
-
-    BYTE * const correlate_row_r = channel_r->correlate_row;
-    BYTE * const correlate_row_g = channel_g->correlate_row;
-    BYTE * const correlate_row_b = channel_b->correlate_row;
-    const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
-    int stopidx;
-#ifdef RLE
-    int run_index = 0;
-    int run_end;
-#endif
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (!i) {
-        unsigned int codewordlen;
-
-        UNCOMPRESS_PIX_START(&cur_row[i]);
-        UNCOMPRESS_ONE_0(r);
-        UNCOMPRESS_ONE_0(g);
-        UNCOMPRESS_ONE_0(b);
-
-        if (encoder->rgb_state.waitcnt) {
-            --encoder->rgb_state.waitcnt;
-        } else {
-            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-            UPDATE_MODEL(0);
-        }
-        stopidx = ++i + encoder->rgb_state.waitcnt;
-    } else {
-        stopidx = i + encoder->rgb_state.waitcnt;
-    }
-    for (;;) {
-        while (stopidx < end) {
-            for (; i <= stopidx; i++) {
-                unsigned int codewordlen;
-#ifdef RLE
-                RLE_PRED_1_IMP;
-                RLE_PRED_2_IMP;
-                RLE_PRED_3_IMP;
-#endif
-                UNCOMPRESS_PIX_START(&cur_row[i]);
-                UNCOMPRESS_ONE(r);
-                UNCOMPRESS_ONE(g);
-                UNCOMPRESS_ONE(b);
-            }
-
-            UPDATE_MODEL(stopidx);
-
-            stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
-        }
-
-        for (; i < end; i++) {
-            unsigned int codewordlen;
-#ifdef RLE
-            RLE_PRED_1_IMP;
-            RLE_PRED_2_IMP;
-            RLE_PRED_3_IMP;
-#endif
-            UNCOMPRESS_PIX_START(&cur_row[i]);
-            UNCOMPRESS_ONE(r);
-            UNCOMPRESS_ONE(g);
-            UNCOMPRESS_ONE(b);
-        }
-
-        encoder->rgb_state.waitcnt = stopidx - end;
-
-        return;
-
-#ifdef RLE
-do_run:
-        encoder->rgb_state.waitcnt = stopidx - i;
-        run_index = i;
-        run_end = i + decode_run(encoder);
-
-        for (; i < run_end; i++) {
-            UNCOMPRESS_PIX_START(&cur_row[i]);
-            SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
-            SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
-            SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
-        }
-
-        if (i == end) {
-            return;
-        }
-
-        stopidx = i + encoder->rgb_state.waitcnt;
-#endif
-    }
-}
-
-static void FNAME(uncompress_row)(Encoder *encoder,
-                                  const PIXEL * const prev_row,
-                                  PIXEL * const cur_row,
-                                  unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
-        if (encoder->rgb_state.wmileft) {
-            FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
-                                      pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
-            pos += encoder->rgb_state.wmileft;
-            width -= encoder->rgb_state.wmileft;
-        }
-
-        encoder->rgb_state.wmidx++;
-        set_wm_trigger(&encoder->rgb_state);
-        encoder->rgb_state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
-                                  pos + width, bpc, bpc_mask);
-        if (wmimax > (int)encoder->rgb_state.wmidx) {
-            encoder->rgb_state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
-    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-#undef PIXEL
-#undef FNAME
-#undef _PIXEL_A
-#undef _PIXEL_B
-#undef _PIXEL_C
-#undef SAME_PIXEL
-#undef RLE_PRED_1_IMP
-#undef RLE_PRED_2_IMP
-#undef RLE_PRED_3_IMP
-#undef UPDATE_MODEL
-#undef DECORELATE_0
-#undef DECORELATE
-#undef COMPRESS_ONE_ROW0_0
-#undef COMPRESS_ONE_ROW0
-#undef COMPRESS_ONE_0
-#undef COMPRESS_ONE
-#undef CORELATE_0
-#undef CORELATE
-#undef UNCOMPRESS_ONE_ROW0_0
-#undef UNCOMPRESS_ONE_ROW0
-#undef UNCOMPRESS_ONE_0
-#undef UNCOMPRESS_ONE
-#undef golomb_coding
-#undef golomb_decoding
-#undef update_model
-#undef find_bucket
-#undef family
-#undef BPC
-#undef BPC_MASK
-#undef COMPRESS_IMP
-#undef SET_r
-#undef GET_r
-#undef SET_g
-#undef GET_g
-#undef SET_b
-#undef GET_b
-#undef UNCOMPRESS_PIX_START
-
diff --git a/display/quic_tmpl.c b/display/quic_tmpl.c
deleted file mode 100644
index 6591d02..0000000
--- a/display/quic_tmpl.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifdef ONE_BYTE
-#undef ONE_BYTE
-#define FNAME(name) quic_one_##name
-#define PIXEL one_byte_t
-#endif
-
-#ifdef THREE_BYTE
-#undef THREE_BYTE
-#define FNAME(name) quic_three_##name
-#define PIXEL three_bytes_t
-#endif
-
-#ifdef FOUR_BYTE
-#undef FOUR_BYTE
-#define FNAME(name) quic_four_##name
-#define PIXEL four_bytes_t
-#endif
-
-#define golomb_coding golomb_coding_8bpc
-#define golomb_decoding golomb_decoding_8bpc
-#define update_model update_model_8bpc
-#define find_bucket find_bucket_8bpc
-#define family family_8bpc
-
-#define BPC 8
-#define BPC_MASK 0xffU
-
-#define _PIXEL_A ((unsigned int)curr[-1].a)
-#define _PIXEL_B ((unsigned int)prev[0].a)
-#define _PIXEL_C ((unsigned int)prev[-1].a)
-
-#ifdef RLE_PRED_1
-#define RLE_PRED_1_IMP                                                              \
-if (cur_row[i - 1].a == prev_row[i].a) {                                            \
-    if (run_index != i && prev_row[i - 1].a == prev_row[i].a &&                     \
-                        i + 1 < end && prev_row[i].a == prev_row[i + 1].a) {        \
-        goto do_run;                                                                \
-    }                                                                               \
-}
-#else
-#define RLE_PRED_1_IMP
-#endif
-
-#ifdef RLE_PRED_2
-#define RLE_PRED_2_IMP                                                     \
-if (prev_row[i - 1].a == prev_row[i].a) {                                  \
-    if (run_index != i && i > 2 && cur_row[i - 1].a == cur_row[i - 2].a) { \
-        goto do_run;                                                       \
-    }                                                                      \
-}
-#else
-#define RLE_PRED_2_IMP
-#endif
-
-#ifdef RLE_PRED_3
-#define RLE_PRED_3_IMP                                                  \
-if (i > 1 && cur_row[i - 1].a == cur_row[i - 2].a && i != run_index) {  \
-    goto do_run;                                                        \
-}
-#else
-#define RLE_PRED_3_IMP
-#endif
-
-/*  a  */
-static INLINE BYTE FNAME(decorelate_0)(const PIXEL * const curr, const unsigned int bpc_mask)
-{
-    return family.xlatU2L[(unsigned)((int)curr[0].a - (int)_PIXEL_A) & bpc_mask];
-}
-
-static INLINE void FNAME(corelate_0)(PIXEL *curr, const BYTE corelate,
-                                     const unsigned int bpc_mask)
-{
-    curr->a = (family.xlatL2U[corelate] + _PIXEL_A) & bpc_mask;
-}
-
-#ifdef PRED_1
-
-/*  (a+b)/2  */
-static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
-                                     const unsigned int bpc_mask)
-{
-    return family.xlatU2L[(unsigned)((int)curr->a - (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask];
-}
-
-
-static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
-                                   const unsigned int bpc_mask)
-{
-    curr->a = (family.xlatL2U[corelate] + (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask;
-}
-
-#endif
-
-#ifdef PRED_2
-
-/*  .75a+.75b-.5c  */
-static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
-                                     const unsigned int bpc_mask)
-{
-    int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
-
-    if (p < 0) {
-        p = 0;
-    } else if ((unsigned)p > bpc_mask) {
-        p = bpc_mask;
-    }
-
-    {
-        return family.xlatU2L[(unsigned)((int)curr->a - p) & bpc_mask];
-    }
-}
-
-static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
-                                   const unsigned int bpc_mask)
-{
-    const int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
-    const unsigned int s = family.xlatL2U[corelate];
-
-    if (!(p & ~bpc_mask)) {
-        curr->a = (s + (unsigned)p) & bpc_mask;
-    } else if (p < 0) {
-        curr->a = s;
-    } else {
-        curr->a = (s + bpc_mask) & bpc_mask;
-    }
-}
-
-#endif
-
-static void FNAME(compress_row0_seg)(Encoder *encoder, Channel *channel, int i,
-                                     const PIXEL * const cur_row,
-                                     const int end,
-                                     const unsigned int waitmask,
-                                     const unsigned int bpc,
-                                     const unsigned int bpc_mask)
-{
-    BYTE * const decorelate_drow = channel->correlate_row;
-    int stopidx;
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (i == 0) {
-        unsigned int codeword, codewordlen;
-
-        decorelate_drow[0] = family.xlatU2L[cur_row->a];
-        golomb_coding(decorelate_drow[0], find_bucket(channel, decorelate_drow[-1])->bestcode,
-                      &codeword, &codewordlen);
-        encode(encoder, codeword, codewordlen);
-
-        if (channel->state.waitcnt) {
-            channel->state.waitcnt--;
-        } else {
-            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
-            update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
-                         decorelate_drow[i], bpc);
-        }
-        stopidx = ++i + channel->state.waitcnt;
-    } else {
-        stopidx = i + channel->state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        for (; i <= stopidx; i++) {
-            unsigned int codeword, codewordlen;
-            decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
-            golomb_coding(decorelate_drow[i],
-                          find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
-                          &codewordlen);
-            encode(encoder, codeword, codewordlen);
-        }
-
-        update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
-                     decorelate_drow[stopidx], bpc);
-        stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
-    }
-
-    for (; i < end; i++) {
-        unsigned int codeword, codewordlen;
-        decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
-        golomb_coding(decorelate_drow[i], find_bucket(channel, decorelate_drow[i - 1])->bestcode,
-                      &codeword, &codewordlen);
-        encode(encoder, codeword, codewordlen);
-    }
-    channel->state.waitcnt = stopidx - end;
-}
-
-static void FNAME(compress_row0)(Encoder *encoder, Channel *channel, const PIXEL *cur_row,
-                                 unsigned int width)
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    int pos = 0;
-
-    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
-        if (channel->state.wmileft) {
-            FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + channel->state.wmileft,
-                                     bppmask[channel->state.wmidx], bpc, bpc_mask);
-            width -= channel->state.wmileft;
-            pos += channel->state.wmileft;
-        }
-
-        channel->state.wmidx++;
-        set_wm_trigger(&channel->state);
-        channel->state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + width,
-                                 bppmask[channel->state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)channel->state.wmidx) {
-            channel->state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
-    ASSERT(encoder->usr, channel->state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-static void FNAME(compress_row_seg)(Encoder *encoder, Channel *channel, int i,
-                                    const PIXEL * const prev_row,
-                                    const PIXEL * const cur_row,
-                                    const int end,
-                                    const unsigned int waitmask,
-                                    const unsigned int bpc,
-                                    const unsigned int bpc_mask)
-{
-    BYTE * const decorelate_drow = channel->correlate_row;
-    int stopidx;
-#ifdef RLE
-    int run_index = 0;
-    int run_size;
-#endif
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (!i) {
-        unsigned int codeword, codewordlen;
-
-        decorelate_drow[0] = family.xlatU2L[(unsigned)((int)cur_row->a -
-                                                       (int)prev_row->a) & bpc_mask];
-
-        golomb_coding(decorelate_drow[0],
-                      find_bucket(channel, decorelate_drow[-1])->bestcode,
-                      &codeword,
-                      &codewordlen);
-        encode(encoder, codeword, codewordlen);
-
-        if (channel->state.waitcnt) {
-            channel->state.waitcnt--;
-        } else {
-            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
-            update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
-                         decorelate_drow[0], bpc);
-        }
-        stopidx = ++i + channel->state.waitcnt;
-    } else {
-        stopidx = i + channel->state.waitcnt;
-    }
-    for (;;) {
-        while (stopidx < end) {
-            for (; i <= stopidx; i++) {
-                unsigned int codeword, codewordlen;
-#ifdef RLE
-                RLE_PRED_1_IMP;
-                RLE_PRED_2_IMP;
-                RLE_PRED_3_IMP;
-#endif
-                decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
-                golomb_coding(decorelate_drow[i],
-                              find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
-                              &codewordlen);
-                encode(encoder, codeword, codewordlen);
-            }
-
-            update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
-                         decorelate_drow[stopidx], bpc);
-            stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
-        }
-
-        for (; i < end; i++) {
-            unsigned int codeword, codewordlen;
-#ifdef RLE
-            RLE_PRED_1_IMP;
-            RLE_PRED_2_IMP;
-            RLE_PRED_3_IMP;
-#endif
-            decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
-            golomb_coding(decorelate_drow[i], find_bucket(channel,
-                                                          decorelate_drow[i - 1])->bestcode,
-                          &codeword, &codewordlen);
-            encode(encoder, codeword, codewordlen);
-        }
-        channel->state.waitcnt = stopidx - end;
-
-        return;
-
-#ifdef RLE
-do_run:
-        run_index = i;
-        channel->state.waitcnt = stopidx - i;
-        run_size = 0;
-
-        while (cur_row[i].a == cur_row[i - 1].a) {
-            run_size++;
-            if (++i == end) {
-#ifdef RLE_STAT
-                encode_channel_run(encoder, channel, run_size);
-#else
-                encode_run(encoder, run_size);
-#endif
-                return;
-            }
-        }
-#ifdef RLE_STAT
-        encode_channel_run(encoder, channel, run_size);
-#else
-        encode_run(encoder, run_size);
-#endif
-        stopidx = i + channel->state.waitcnt;
-#endif
-    }
-}
-
-static void FNAME(compress_row)(Encoder *encoder, Channel *channel,
-                                const PIXEL * const prev_row,
-                                const PIXEL * const cur_row,
-                                unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
-        if (channel->state.wmileft) {
-            FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row,
-                                    pos + channel->state.wmileft, bppmask[channel->state.wmidx],
-                                    bpc, bpc_mask);
-            width -= channel->state.wmileft;
-            pos += channel->state.wmileft;
-        }
-
-        channel->state.wmidx++;
-        set_wm_trigger(&channel->state);
-        channel->state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row, pos + width,
-                                bppmask[channel->state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)channel->state.wmidx) {
-            channel->state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
-    ASSERT(encoder->usr, channel->state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-static void FNAME(uncompress_row0_seg)(Encoder *encoder, Channel *channel, int i,
-                                       BYTE * const correlate_row,
-                                       PIXEL * const cur_row,
-                                       const int end,
-                                       const unsigned int waitmask,
-                                       const unsigned int bpc,
-                                       const unsigned int bpc_mask)
-{
-    int stopidx;
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (i == 0) {
-        unsigned int codewordlen;
-
-        correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel,
-                                                             correlate_row[-1])->bestcode,
-                                                 encoder->io_word, &codewordlen);
-        cur_row[0].a = (BYTE)family.xlatL2U[correlate_row[0]];
-        decode_eatbits(encoder, codewordlen);
-
-        if (channel->state.waitcnt) {
-            --channel->state.waitcnt;
-        } else {
-            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
-            update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
-                         correlate_row[0], bpc);
-        }
-        stopidx = ++i + channel->state.waitcnt;
-    } else {
-        stopidx = i + channel->state.waitcnt;
-    }
-
-    while (stopidx < end) {
-        struct s_bucket * pbucket = NULL;
-
-        for (; i <= stopidx; i++) {
-            unsigned int codewordlen;
-
-            pbucket = find_bucket(channel, correlate_row[i - 1]);
-            correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
-                                                     &codewordlen);
-            FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
-            decode_eatbits(encoder, codewordlen);
-        }
-
-        update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
-
-        stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
-    }
-
-    for (; i < end; i++) {
-        unsigned int codewordlen;
-
-        correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
-                                                             correlate_row[i - 1])->bestcode,
-                                                 encoder->io_word, &codewordlen);
-        FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
-        decode_eatbits(encoder, codewordlen);
-    }
-    channel->state.waitcnt = stopidx - end;
-}
-
-static void FNAME(uncompress_row0)(Encoder *encoder, Channel *channel,
-                                   PIXEL * const cur_row,
-                                   unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    BYTE * const correlate_row = channel->correlate_row;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
-        if (channel->state.wmileft) {
-            FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row,
-                                       pos + channel->state.wmileft, bppmask[channel->state.wmidx],
-                                       bpc, bpc_mask);
-            pos += channel->state.wmileft;
-            width -= channel->state.wmileft;
-        }
-
-        channel->state.wmidx++;
-        set_wm_trigger(&channel->state);
-        channel->state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row, pos + width,
-                                   bppmask[channel->state.wmidx], bpc, bpc_mask);
-        if (wmimax > (int)channel->state.wmidx) {
-            channel->state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
-    ASSERT(encoder->usr, channel->state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-static void FNAME(uncompress_row_seg)(Encoder *encoder, Channel *channel,
-                                      BYTE *correlate_row,
-                                      const PIXEL * const prev_row,
-                                      PIXEL * const cur_row,
-                                      int i,
-                                      const int end,
-                                      const unsigned int bpc,
-                                      const unsigned int bpc_mask)
-{
-    const unsigned int waitmask = bppmask[channel->state.wmidx];
-    int stopidx;
-#ifdef RLE
-    int run_index = 0;
-    int run_end;
-#endif
-
-    ASSERT(encoder->usr, end - i > 0);
-
-    if (i == 0) {
-        unsigned int codewordlen;
-
-        correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel, correlate_row[-1])->bestcode,
-                                                             encoder->io_word, &codewordlen);
-        cur_row[0].a = (family.xlatL2U[correlate_row[0]] + prev_row[0].a) & bpc_mask;
-        decode_eatbits(encoder, codewordlen);
-
-        if (channel->state.waitcnt) {
-            --channel->state.waitcnt;
-        } else {
-            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
-            update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
-                         correlate_row[0], bpc);
-        }
-        stopidx = ++i + channel->state.waitcnt;
-    } else {
-        stopidx = i + channel->state.waitcnt;
-    }
-    for (;;) {
-        while (stopidx < end) {
-            struct s_bucket * pbucket = NULL;
-
-            for (; i <= stopidx; i++) {
-                unsigned int codewordlen;
-#ifdef RLE
-                RLE_PRED_1_IMP;
-                RLE_PRED_2_IMP;
-                RLE_PRED_3_IMP;
-#endif
-                pbucket = find_bucket(channel, correlate_row[i - 1]);
-                correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
-                                                         &codewordlen);
-                FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
-                decode_eatbits(encoder, codewordlen);
-            }
-
-            update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
-
-            stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
-        }
-
-        for (; i < end; i++) {
-            unsigned int codewordlen;
-#ifdef RLE
-            RLE_PRED_1_IMP;
-            RLE_PRED_2_IMP;
-            RLE_PRED_3_IMP;
-#endif
-            correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
-                                                                 correlate_row[i - 1])->bestcode,
-                                                     encoder->io_word, &codewordlen);
-            FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
-            decode_eatbits(encoder, codewordlen);
-        }
-
-        channel->state.waitcnt = stopidx - end;
-
-        return;
-
-#ifdef RLE
-do_run:
-        channel->state.waitcnt = stopidx - i;
-        run_index = i;
-#ifdef RLE_STAT
-        run_end = i + decode_channel_run(encoder, channel);
-#else
-        run_end = i + decode_run(encoder);
-#endif
-
-        for (; i < run_end; i++) {
-            cur_row[i].a = cur_row[i - 1].a;
-        }
-
-        if (i == end) {
-            return;
-        }
-
-        stopidx = i + channel->state.waitcnt;
-#endif
-    }
-}
-
-static void FNAME(uncompress_row)(Encoder *encoder, Channel *channel,
-                                  const PIXEL * const prev_row,
-                                  PIXEL * const cur_row,
-                                  unsigned int width)
-
-{
-    const unsigned int bpc = BPC;
-    const unsigned int bpc_mask = BPC_MASK;
-    BYTE * const correlate_row = channel->correlate_row;
-    unsigned int pos = 0;
-
-    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
-        if (channel->state.wmileft) {
-            FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
-                                      pos + channel->state.wmileft, bpc, bpc_mask);
-            pos += channel->state.wmileft;
-            width -= channel->state.wmileft;
-        }
-
-        channel->state.wmidx++;
-        set_wm_trigger(&channel->state);
-        channel->state.wmileft = wminext;
-    }
-
-    if (width) {
-        FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
-                                  pos + width, bpc, bpc_mask);
-        if (wmimax > (int)channel->state.wmidx) {
-            channel->state.wmileft -= width;
-        }
-    }
-
-    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
-    ASSERT(encoder->usr, channel->state.wmidx <= 32);
-    ASSERT(encoder->usr, wminext > 0);
-}
-
-#undef PIXEL
-#undef FNAME
-#undef _PIXEL_A
-#undef _PIXEL_B
-#undef _PIXEL_C
-#undef RLE_PRED_1_IMP
-#undef RLE_PRED_2_IMP
-#undef RLE_PRED_3_IMP
-#undef golomb_coding
-#undef golomb_deoding
-#undef update_model
-#undef find_bucket
-#undef family
-#undef BPC
-#undef BPC_MASK
-
diff --git a/display/qxldd.h b/display/qxldd.h
deleted file mode 100644
index 1a1b5d5..0000000
--- a/display/qxldd.h
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef _H_QXLDD
-#define _H_QXLDD
-
-
-#include "stddef.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include "windef.h"
-#include "wingdi.h"
-#include "winddi.h"
-#include "ioaccess.h"
-#include "qxl_driver.h"
-#include "mspace.h"
-#if (WINVER < 0x0501)
-#include "wdmhelper.h"
-#endif
-
-#define ALLOC_TAG 'dlxq'
-
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1 << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-
-#define DEBUG_PRINT(arg) DebugPrint arg
-
-#ifdef DBG
-#define ASSERT(pdev, x) if (!(x)) { \
-    DebugPrint(pdev, 0, "ASSERT(%s) failed @ %s\n", #x, __FUNCTION__); \
-    EngDebugBreak();\
-}
-#define ONDBG(x) x
-#else
-#define ASSERT(pdev, x)
-#define ONDBG(x)
-#endif
-
-#define PANIC(pdev, str) {                                      \
-    DebugPrint(pdev, 0, "PANIC: %s @ %s\n", str, __FUNCTION__); \
-    EngDebugBreak();                                            \
-}
-
-#define PUNT_IF_DISABLED(pdev) \
-    do { \
-        if (!pdev->enabled) { \
-            DEBUG_PRINT((pdev, 0, "%s: punting\n", __FUNCTION__)); \
-            return FALSE; \
-        } \
-    } while (0)
-
-typedef enum {
-    QXL_SUCCESS,
-    QXL_FAILED,
-    QXL_UNSUPPORTED,
-} QXLRESULT;
-
-typedef struct Ring RingItem;
-typedef struct Ring {
-    RingItem *prev;
-    RingItem *next;
-} Ring;
-
-#define IMAGE_HASH_SHIFT 15
-#define IMAGE_HASH_SIZE (1 << IMAGE_HASH_SHIFT)
-#define IMAGE_HASH_MASK (IMAGE_HASH_SIZE - 1)
-
-#define IMAGE_POOL_SIZE (1 << 15)
-
-#define CURSOR_CACHE_SIZE (1 << 6)
-#define CURSOR_HASH_SIZE (CURSOR_CACHE_SIZE << 1)
-#define CURSOR_HASH_NASKE (CURSOR_HASH_SIZE - 1)
-
-#define PALETTE_CACHE_SIZE (1 << 6)
-#define PALETTE_HASH_SIZE (PALETTE_CACHE_SIZE << 1)
-#define PALETTE_HASH_NASKE (PALETTE_HASH_SIZE - 1)
-
-//#define CALL_TEST
-
-#ifdef CALL_TEST
-enum {
-    CALL_COUNTER_COPY_BITS,
-    CALL_COUNTER_BIT_BLT,
-    CALL_COUNTER_TEXT_OUT,
-    CALL_COUNTER_STROKE_PATH,
-    CALL_COUNTER_STRETCH_BLT,
-    CALL_COUNTER_STRETCH_BLT_ROP,
-    CALL_COUNTER_TRANSPARENT_BLT,
-    CALL_COUNTER_ALPHA_BLEND,
-
-    CALL_COUNTER_FILL_PATH,
-    CALL_COUNTER_GRADIENT_FILL,
-    CALL_COUNTER_LINE_TO,
-    CALL_COUNTER_PLG_BLT,
-    CALL_COUNTER_STROKE_AND_FILL_PATH,
-
-    NUM_CALL_COUNTERS,
-};
-#endif
-
-typedef struct QuicData QuicData;
-
-#define IMAGE_KEY_HASH_SIZE (1 << 15)
-#define IMAGE_KEY_HASH_MASK (IMAGE_KEY_HASH_SIZE - 1)
-
-typedef struct ImageKey {
-    HSURF hsurf;
-    UINT64 unique;
-    UINT32 key;
-} ImageKey;
-
-typedef struct CacheImage {
-    struct CacheImage *next;
-    RingItem lru_link;
-    UINT32 key;
-    UINT32 hits;
-    UINT8 format;
-    UINT32 width;
-    UINT32 height;
-    struct InternalImage *image;
-} CacheImage;
-
-#define NUM_UPDATE_TRACE_ITEMS 10
-typedef struct UpdateTrace {
-    RingItem link;
-    UINT32 last_time;
-    RECTL area;
-    HSURF hsurf;
-    UINT8 count;
-} UpdateTrace;
-
-typedef struct PMemSlot {
-    MemSlot slot;
-    QXLPHYSICAL high_bits;
-} PMemSlot;
-
-typedef struct MspaceInfo {
-    mspace _mspace;
-    UINT8 *mspace_start;
-    UINT8 *mspace_end;
-} MspaceInfo;
-
-enum {
-    MSPACE_TYPE_DEVRAM,
-    MSPACE_TYPE_VRAM,
-
-    NUM_MSPACES,
-};
-
-enum {
-    SYNC = 0,
-    ASYNC = 1
-};
-
-typedef enum {
-    ASYNCABLE_UPDATE_AREA = 0,
-    ASYNCABLE_MEMSLOT_ADD,
-    ASYNCABLE_CREATE_PRIMARY,
-    ASYNCABLE_DESTROY_PRIMARY,
-    ASYNCABLE_DESTROY_SURFACE,
-    ASYNCABLE_DESTROY_ALL_SURFACES,
-    ASYNCABLE_FLUSH_SURFACES,
-
-    ASYNCABLE_COUNT
-} asyncable_t;
-
-
-typedef struct PDev PDev;
-
-typedef struct DrawArea {
-   HSURF bitmap;
-   SURFOBJ* surf_obj;
-   UINT8 *base_mem;
-} DrawArea;
-
-typedef struct SurfaceInfo SurfaceInfo;
-struct SurfaceInfo {
-    DrawArea    draw_area;
-    HBITMAP     hbitmap;
-    SIZEL       size;
-    UINT8      *copy;
-    ULONG       bitmap_format;
-    INT32       stride;
-    union {
-        PDev *pdev;
-        SurfaceInfo *next_free;
-    } u;
-};
-
-#define SSE_MASK 15
-#define SSE_ALIGN 16
-
-typedef struct PDev {
-    HANDLE driver;
-    HDEV eng;
-    HPALETTE palette;
-    HSURF surf;
-    UINT8 surf_enable;
-    DWORD video_mode_index;
-    SIZEL resolution;
-    UINT32 max_bitmap_size;
-    ULONG bitmap_format;
-    UINT8 create_non_primary_surfaces;
-
-    ULONG fb_size;
-    BYTE* fb;
-    UINT64 fb_phys;
-    UINT8 vram_slot_initialized;
-    UINT8 vram_mem_slot;
-
-    ULONG stride;
-    FLONG red_mask;
-    FLONG green_mask;
-    FLONG blue_mask;
-    ULONG fp_state_size;
-
-    QXLPHYSICAL surf_phys;
-    UINT8 *surf_base;
-
-    QuicData *quic_data;
-    HSEMAPHORE quic_data_sem;
-
-    QXLCommandRing *cmd_ring;
-    QXLCursorRing *cursor_ring;
-    QXLReleaseRing *release_ring;
-    PUCHAR notify_cmd_port;
-    PUCHAR notify_cursor_port;
-    PUCHAR notify_oom_port;
-    PEVENT display_event;
-    PEVENT cursor_event;
-    PEVENT sleep_event;
-    PEVENT io_cmd_event;
-
-    PUCHAR log_port;
-    UINT8 *log_buf;
-    UINT32 *log_level;
-
-    PMemSlot *mem_slots;
-    UINT8 num_mem_slot;
-    UINT8 main_mem_slot;
-    UINT8 slot_id_bits;
-    UINT8 slot_gen_bits;
-    UINT8 *slots_generation;
-    UINT64 *ram_slot_start;
-    UINT64 *ram_slot_end;
-    QXLPHYSICAL va_slot_mask;
-
-    UINT32 num_io_pages;
-    UINT8 *io_pages_virt;
-    UINT64 io_pages_phys;
-
-    UINT32 *dev_update_id;
-
-    QXLRect *update_area;
-    UINT32 *update_surface;
-
-    UINT32 *mm_clock;
-
-    UINT32 *compression_level;
-
-    FLONG cursor_trail;
-
-#if (WINVER < 0x0501)
-    PQXLWaitForEvent WaitForEvent;
-#endif
-
-    PUCHAR asyncable[ASYNCABLE_COUNT][2];
-    HSEMAPHORE io_sem;
-    PUCHAR memslot_del_port;
-    PUCHAR flush_release_port;
-    UINT32 use_async;
-
-    UINT8* primary_memory_start;
-    UINT32 primary_memory_size;
-
-    QXLSurfaceCreate *primary_surface_create;
-
-    UINT32 dev_id;
-
-    Ring update_trace;
-    UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
-
-    UINT64 free_outputs;
-
-    MspaceInfo mspaces[NUM_MSPACES];
-
-    /*
-     * TODO: reconsider semaphores according to
-     * http://msdn.microsoft.com/en-us/library/ff568281%28v=vs.85%29.aspx
-     * 1) In order to protect the device log buffer,
-     *     the print_sem must be shared between different pdevs and
-     *     different display sessions.
-     * 2) malloc_sem: not sure what it protects. Maybe globals in mspace?
-     *    since only the enabled pdev is allocating memory, I don't
-     *    think it is required (unless it is possible to have
-     *    AssertMode(x, enable) before AssertMode(y, disable).
-     * 3) cmd_sem, cursor_sem: again, since only the enabled pdev touches the cmd rings
-     *    I don't think it is required.
-     * 4) io_sem - same as print sem. Note that we should prevent starvation between
-     *    print_sem and io_sem in DebugPrintV.
-     *
-     */
-    HSEMAPHORE malloc_sem; /* Also protects release ring */
-    HSEMAPHORE print_sem;
-    HSEMAPHORE cmd_sem;
-    HSEMAPHORE cursor_sem; /* Protects cursor_ring */
-
-    CacheImage cache_image_pool[IMAGE_POOL_SIZE];
-    Ring cache_image_lru;
-    Ring cursors_lru;
-    Ring palette_lru;
-    ImageKey image_key_lookup[IMAGE_KEY_HASH_SIZE];
-    struct CacheImage *image_cache[IMAGE_HASH_SIZE];
-    struct InternalCursor *cursor_cache[CURSOR_HASH_SIZE];
-    UINT32 num_cursors;
-    UINT32 last_cursor_id;
-    struct InternalPalette *palette_cache[PALETTE_HASH_SIZE];
-    UINT32 num_palettes;
-
-    UINT32 n_surfaces;
-    SurfaceInfo surface0_info;
-    SurfaceInfo *surfaces_info;
-    SurfaceInfo *free_surfaces;
-
-    UINT32 update_id;
-
-    UINT32 enabled; /* 1 between DrvAssertMode(TRUE) and DrvAssertMode(FALSE) */
-
-
-    UCHAR  pci_revision;
-
-#ifdef DBG
-    int num_free_pages;
-    int num_outputs;
-    int num_path_pages;
-    int num_rects_pages;
-    int num_bits_pages;
-    int num_buf_pages;
-    int num_glyphs_pages;
-    int num_cursor_pages;
-#endif
-
-#ifdef CALL_TEST
-    BOOL count_calls;
-    UINT32 total_calls;
-    UINT32 call_counters[NUM_CALL_COUNTERS];
-#endif
-} PDev;
-
-
-void DebugPrintV(PDev *pdev, const char *message, va_list ap);
-void DebugPrint(PDev *pdev, int level, const char *message, ...);
-
-void InitResources(PDev *pdev);
-void ClearResources(PDev *pdev);
-
-#ifdef CALL_TEST
-void CountCall(PDev *pdev, int counter);
-#else
-#define CountCall(a, b)
-#endif
-
-char *BitmapFormatToStr(int format);
-char *BitmapTypeToStr(int type);
-
-static _inline void RingInit(Ring *ring)
-{
-    ring->next = ring->prev = ring;
-}
-
-static _inline void RingItemInit(RingItem *item)
-{
-    item->next = item->prev = NULL;
-}
-
-static _inline BOOL RingItemIsLinked(RingItem *item)
-{
-    return !!item->next;
-}
-
-static _inline BOOL RingIsEmpty(PDev *pdev, Ring *ring)
-{
-    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
-    return ring == ring->next;
-}
-
-static _inline void RingAdd(PDev *pdev, Ring *ring, RingItem *item)
-{
-    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
-    ASSERT(pdev, item->next == NULL && item->prev == NULL);
-
-    item->next = ring->next;
-    item->prev = ring;
-    ring->next = item->next->prev = item;
-}
-
-static _inline void RingRemove(PDev *pdev, RingItem *item)
-{
-    ASSERT(pdev, item->next != NULL && item->prev != NULL);
-    ASSERT(pdev, item->next != item);
-
-    item->next->prev = item->prev;
-    item->prev->next = item->next;
-    item->prev = item->next = 0;
-}
-
-static _inline RingItem *RingGetTail(PDev *pdev, Ring *ring)
-{
-    RingItem *ret;
-
-    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
-
-    if (RingIsEmpty(pdev, ring)) {
-        return NULL;
-    }
-    ret = ring->prev;
-    return ret;
-}
-
-#if (WINVER < 0x0501)
-#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
-#else
-#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
-#endif
-
-/* Helpers for dealing with ENG_TIME_FIELDS */
-static _inline ULONG64 eng_time_diff_ms(ENG_TIME_FIELDS *b, ENG_TIME_FIELDS *a)
-{
-    ULONG64 ret = 0;
-
-    ret += b->usMilliseconds - a->usMilliseconds;
-    ret += 1000 * (b->usSecond - a->usSecond);
-    ret += 60000 * (b->usMinute - a->usMinute);
-    ret += 3600000L * (b->usHour - a->usHour);
-    // don't get into gregorian calendar, just ignore more then a single day difference
-    if (b->usDay != a->usDay) {
-        ret += (3600L * 24L * 1000L);
-    }
-    return ret;
-}
-
-#define INTERRUPT_NOT_PRESENT_TIMEOUT_MS 60000L
-#define INTERRUPT_NOT_PRESENT_TIMEOUT_100NS (INTERRUPT_NOT_PRESENT_TIMEOUT_MS * 10000L)
-
-/* Write to an ioport. For some operations we support a new port that returns
- * immediatly, and completion is signaled by an interrupt that sets io_cmd_event.
- * If the pci_revision is >= QXL_REVISION_STABLE_V10, we support it, else do
- * a regular ioport write.
- */
-static _inline void async_io(PDev *pdev, asyncable_t op, UCHAR val)
-{
-    ENG_TIME_FIELDS start, finish;
-    LARGE_INTEGER timeout;                      // 1 => 100 nanoseconds
-    ULONG64 millis;
-
-    if (pdev->use_async) {
-        EngAcquireSemaphore(pdev->io_sem);
-        WRITE_PORT_UCHAR(pdev->asyncable[op][ASYNC], val);
-        /* Our Interrupt may be taken from us unexpectedly, by a surprise removal.
-         * in which case this event will never be set. This happens only during WHQL
-         * tests (pnpdtest /surprise). So instead: Wait on a timer, if we fail, stop waiting, until
-         * we get reset. We use EngQueryLocalTime because there is no way to differentiate a return on
-         * timeout from a return on event set otherwise. */
-        timeout.QuadPart = -INTERRUPT_NOT_PRESENT_TIMEOUT_100NS; // negative  => relative
-        DEBUG_PRINT((pdev, 15, "WAIT_FOR_EVENT %d\n", (int)op));
-        EngQueryLocalTime(&start);
-        WAIT_FOR_EVENT(pdev, pdev->io_cmd_event, &timeout);
-        EngQueryLocalTime(&finish);
-        millis = eng_time_diff_ms(&finish, &start);
-        if (millis >= INTERRUPT_NOT_PRESENT_TIMEOUT_MS) {
-            pdev->use_async = 0;
-            DEBUG_PRINT((pdev, 0, "%s: timeout reached, disabling async io!\n", __FUNCTION__));
-        }
-        EngReleaseSemaphore(pdev->io_sem);
-        DEBUG_PRINT((pdev, 3, "finished async %d\n", (int)op));
-    } else {
-        if (pdev->asyncable[op][SYNC] == NULL) {
-            DEBUG_PRINT((pdev, 0, "ERROR: trying calling sync io on NULL port %d\n", op));
-        } else {
-            EngAcquireSemaphore(pdev->io_sem);
-            WRITE_PORT_UCHAR(pdev->asyncable[op][SYNC], val);
-            EngReleaseSemaphore(pdev->io_sem);
-        }
-    }
-}
-
-/*
- * Before the introduction of QXL_IO_*_ASYNC all io writes would return
- * only when their function was complete. Since qemu would only allow
- * a single outstanding io operation between all vcpu threads, they were
- * also protected from simultaneous calls between different vcpus.
- *
- * With the introduction of _ASYNC we need to explicitly lock between different
- * threads running on different vcpus, this is what this helper accomplishes.
- */
-static _inline void sync_io(PDev *pdev, PUCHAR port, UCHAR val)
-{
-    EngAcquireSemaphore(pdev->io_sem);
-    WRITE_PORT_UCHAR(port, val);
-    EngReleaseSemaphore(pdev->io_sem);
-}
-
-#ifdef DBG
-#define DUMP_VRAM_MSPACE(pdev) \
-    do { \
-        DEBUG_PRINT((pdev, 0, "%s: dumping mspace vram (%p)\n", __FUNCTION__, pdev)); \
-        if (pdev) {  \
-            mspace_malloc_stats(pdev->mspaces[MSPACE_TYPE_VRAM]._mspace); \
-        } else { \
-            DEBUG_PRINT((pdev, 0, "nothing\n")); \
-        }\
-    } while (0)
-
-#define DUMP_DEVRAM_MSPACE(pdev) \
-    do { \
-        DEBUG_PRINT((pdev, 0, "%s: dumping mspace devram (%p)\n", __FUNCTION__, pdev)); \
-        if (pdev) {  \
-            mspace_malloc_stats(pdev->mspaces[MSPACE_TYPE_DEVRAM]._mspace); \
-        } else { \
-            DEBUG_PRINT((pdev, 0, "nothing\n")); \
-        }\
-    } while (0)
-#else
-#define DUMP_VRAM_MSPACE
-#define DUMP_DEVRAM_MSPACE
-#endif
-
-#endif
diff --git a/display/res.c b/display/res.c
deleted file mode 100644
index e494271..0000000
--- a/display/res.c
+++ /dev/null
@@ -1,3387 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifdef DBG
-#include <stdio.h>
-#endif
-#include <ddraw.h>
-#include <dxmini.h>
-#include "qxldd.h"
-#include "os_dep.h"
-#include "res.h"
-#include "utils.h"
-#include "mspace.h"
-#include "quic.h"
-#include "murmur_hash2a.h"
-#include "surface.h"
-#include "rop.h"
-#include "devioctl.h"
-#include "ntddvdeo.h"
-
-static _inline QXLPHYSICAL PA(PDev *pdev, PVOID virt, UINT8 slot_id)
-{
-    PMemSlot *p_slot = &pdev->mem_slots[slot_id];
-
-    return p_slot->high_bits | ((UINT64)virt - p_slot->slot.start_virt_addr);
-}
-
-static _inline UINT64 VA(PDev *pdev, QXLPHYSICAL paddr, UINT8 slot_id)
-{
-    UINT64 virt;
-    PMemSlot *p_slot = &pdev->mem_slots[slot_id];
-
-    ASSERT(pdev, (paddr >> (64 - pdev->slot_id_bits)) == slot_id);
-    ASSERT(pdev, ((paddr << pdev->slot_id_bits) >> (64 - pdev->slot_gen_bits)) ==
-           p_slot->slot.generation);
-
-    virt = paddr & pdev->va_slot_mask;
-    virt += p_slot->slot.start_virt_addr;;
-
-    return virt;
-}
-
-#define RELEASE_RES(pdev, res) if (!--(res)->refs) (res)->free(pdev, res);
-#define GET_RES(res) (++(res)->refs)
-
-/* Debug helpers - tag each resource with this enum */
-enum {
-    RESOURCE_TYPE_DRAWABLE = 1,
-    RESOURCE_TYPE_SURFACE,
-    RESOURCE_TYPE_PATH,
-    RESOURCE_TYPE_CLIP_RECTS,
-    RESOURCE_TYPE_QUIC_IMAGE,
-    RESOURCE_TYPE_BITMAP_IMAGE,
-    RESOURCE_TYPE_SURFACE_IMAGE,
-    RESOURCE_TYPE_SRING,
-    RESOURCE_TYPE_CURSOR,
-    RESOURCE_TYPE_BUF,
-    RESOURCE_TYPE_UPDATE,
-};
-
-#ifdef DBG
-#define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
-#else
-#define RESOURCE_TYPE(res, val)
-#endif
-
-typedef struct Resource Resource;
-struct Resource {
-    UINT32 refs;
-#ifdef DBG
-    UINT32 type;
-#endif
-    void (*free)(PDev *pdev, Resource *res);
-    UINT8 res[0];
-};
-
-static void FreeMem(PDev* pdev, UINT32 mspace_type, void *ptr);
-static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
-
-
-#define PUSH_CMD(pdev) do {                             \
-    int notify;                                         \
-    SPICE_RING_PUSH(pdev->cmd_ring, notify);            \
-    if (notify) {                                       \
-        sync_io(pdev, pdev->notify_cmd_port, 0);     \
-    }                                                   \
-} while (0);
-
-#define PUSH_CURSOR_CMD(pdev) do {                      \
-    int notify;                                         \
-    SPICE_RING_PUSH(pdev->cursor_ring, notify);         \
-    if (notify) {                                       \
-        sync_io(pdev, pdev->notify_cursor_port, 0);  \
-    }                                                   \
-} while (0);
-
-
-#define MAX_OUTPUT_RES 6
-
-typedef struct QXLOutput {
-    UINT32 num_res;
-#ifdef DBG
-    UINT32 type;
-#endif
-    Resource *resources[MAX_OUTPUT_RES];
-    UINT8 data[0];
-} QXLOutput;
-
-static int have_sse2 = FALSE;
-
-#ifndef DBG
-static _inline void DebugShowOutput(PDev *pdev, QXLOutput* output)
-{
-}
-#else
-const char* resource_type_to_string(QXLOutput *output, UINT32 type)
-{
-    static char buf[1024];
-
-    switch (type) {
-    case 0: return "UNSET";
-    case RESOURCE_TYPE_DRAWABLE: return "drawable";
-    case RESOURCE_TYPE_SURFACE: {
-        QXLSurfaceCmd *surface_cmd = (QXLSurfaceCmd*)output->data;
-        _snprintf(buf, sizeof(buf) - 1, "surface %u", surface_cmd->surface_id);
-        return buf;
-    }
-    case RESOURCE_TYPE_PATH: return "path";
-    case RESOURCE_TYPE_CLIP_RECTS: return "clip_rects";
-    case RESOURCE_TYPE_QUIC_IMAGE: return "quic_image";
-    case RESOURCE_TYPE_BITMAP_IMAGE: return "bitmap_image";
-    case RESOURCE_TYPE_SURFACE_IMAGE: return "surface_image";
-    case RESOURCE_TYPE_SRING: return "sring";
-    case RESOURCE_TYPE_CURSOR: return "cursor";
-    case RESOURCE_TYPE_BUF: return "buf";
-    case RESOURCE_TYPE_UPDATE: return "update";
-    }
-    return "UNDEFINED";
-}
-
-static void DebugShowOutput(PDev *pdev, QXLOutput* output)
-{
-    UINT32 i;
-
-    DEBUG_PRINT((pdev, 11, "output: %s res %d\n", resource_type_to_string(output, output->type),
-                output->num_res));
-    for (i = 0 ; i < output->num_res ; ++i) {
-        DEBUG_PRINT((pdev, 11, "type %s\n", resource_type_to_string(output,
-            output->resources[i]->type)));
-    }
-}
-#endif
-
-UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id)
-{
-    QXLOutput *output = (QXLOutput *)output_id;
-    Resource **now;
-    Resource **end;
-    UINT64 next;
-
-    ASSERT(pdev, output_id);
-    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
-    DebugShowOutput(pdev, output);
-
-    for (now = output->resources, end = now + output->num_res; now < end; now++) {
-        RELEASE_RES(pdev, *now);
-    }
-    next = *(UINT64*)output->data;
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, output);
-    DEBUG_PRINT((pdev, 10, "%s done\n", __FUNCTION__));
-    ONDBG(pdev->num_outputs--); //todo: atomic
-    return next;
-}
-
-static void AddRes(PDev *pdev, QXLOutput *output, Resource *res)
-{
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    ASSERT(pdev, output->num_res < MAX_OUTPUT_RES);
-    res->refs++;
-    output->resources[output->num_res++] = res;
-    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
-}
-
-static _inline void DrawableAddRes(PDev *pdev, QXLDrawable *drawable, Resource *res)
-{
-    QXLOutput *output;
-
-    output = (QXLOutput *)((UINT8 *)drawable - sizeof(QXLOutput));
-    AddRes(pdev, output, res);
-}
-
- 
-static _inline void SurfaceAddRes(PDev *pdev, QXLSurfaceCmd *surface, Resource *res)
-{
-    QXLOutput *output;
-
-    output = (QXLOutput *)((UINT8 *)surface - sizeof(QXLOutput));
-    AddRes(pdev, output, res);
-}
-
-static _inline void CursorCmdAddRes(PDev *pdev, QXLCursorCmd *cmd, Resource *res)
-{
-    QXLOutput *output;
-
-    output = (QXLOutput *)((UINT8 *)cmd - sizeof(QXLOutput));
-    AddRes(pdev, output, res);
-}
-
-#define SUPPORT_SURPRISE_REMOVE
-
-
-/* Called with cursor_sem held */
-static void WaitForCursorRing(PDev* pdev)
-{
-    int wait;
-
-    DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    for (;;) {
-        SPICE_RING_PROD_WAIT(pdev->cursor_ring, wait);
-
-        if (!wait) {
-            break;
-        }
-#ifdef SUPPORT_SURPRISE_REMOVE
-        {
-            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
-            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
-            WAIT_FOR_EVENT(pdev, pdev->cursor_event, &timeout);
-            if (SPICE_RING_IS_FULL(pdev->cursor_ring)) {
-                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
-            }
-        }
-#else
-        WAIT_FOR_EVENT(pdev, pdev->cursor_event, NULL);
-#endif //SUPPORT_SURPRISE_REMOVE
-    }
-}
-
-/* Called with cmd_sem held */
-static void WaitForCmdRing(PDev* pdev)
-{
-    int wait;
-
-    DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    for (;;) {
-        SPICE_RING_PROD_WAIT(pdev->cmd_ring, wait);
-
-        if (!wait) {
-            break;
-        }
-        DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-#ifdef SUPPORT_SURPRISE_REMOVE
-        {
-            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
-            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
-            WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
-            if (SPICE_RING_IS_FULL(pdev->cmd_ring)) {
-                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
-            }
-        }
-#else
-        WAIT_FOR_EVENT(pdev, pdev->display_event, NULL);
-#endif //SUPPORT_SURPRISE_REMOVE
-    }
-}
-
-static void QXLSleep(PDev* pdev, int msec)
-{
-    LARGE_INTEGER timeout;
-
-    DEBUG_PRINT((pdev, 18, "%s: 0x%lx msec %u\n", __FUNCTION__, pdev, msec));
-    timeout.QuadPart = -msec * 1000 * 10;
-    WAIT_FOR_EVENT(pdev, pdev->sleep_event, &timeout);
-    DEBUG_PRINT((pdev, 19, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
-}
-
-/* Called with malloc_sem held */
-static void WaitForReleaseRing(PDev* pdev)
-{
-    int wait;
-
-    DEBUG_PRINT((pdev, 15, "%s: 0x%lx\n", __FUNCTION__, pdev));
-
-    for (;;) {
-        LARGE_INTEGER timeout;
-
-        if (SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-            QXLSleep(pdev, 10);
-            if (!SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-                break;
-            }
-            sync_io(pdev, pdev->notify_oom_port, 0);
-        }
-        SPICE_RING_CONS_WAIT(pdev->release_ring, wait);
-
-        if (!wait) {
-            break;
-        }
-
-        timeout.QuadPart = -30 * 1000 * 10; //30ms
-        WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
-
-        if (SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-#ifdef DBG
-            DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
-            DEBUG_PRINT((pdev, 0,
-                "\tfree %d out %d path %d rect %d bits %d buf %d glyph %d cursor %d\n",
-                         pdev->num_free_pages,
-                         pdev->num_outputs,
-                         pdev->num_path_pages,
-                         pdev->num_rects_pages,
-                         pdev->num_bits_pages,
-                         pdev->num_buf_pages,
-                         pdev->num_glyphs_pages,
-                         pdev->num_cursor_pages));
-#endif
-            //oom
-            sync_io(pdev, pdev->notify_oom_port, 0);
-        }
-    }
-    DEBUG_PRINT((pdev, 16, "%s: 0x%lx, done\n", __FUNCTION__, pdev));
-}
-
-/* Called with malloc_sem held */
-static void FlushReleaseRing(PDev *pdev)
-{
-    UINT64 output;
-    int notify;
-    int num_to_release = 50;
-
-    output = pdev->free_outputs;
-
-    while (1) {
-        while (output != 0) {
-            output = ReleaseOutput(pdev, output);
-            if (--num_to_release == 0) {
-                break;
-            }
-        }
-
-        if (output != 0 ||
-            SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-            break;
-        }
-
-        output = *SPICE_RING_CONS_ITEM(pdev->release_ring);
-        SPICE_RING_POP(pdev->release_ring, notify);
-    }
-
-    pdev->free_outputs = output;
-}
-
-void EmptyReleaseRing(PDev *pdev)
-{
-    int count = 0;
-
-    EngAcquireSemaphore(pdev->malloc_sem);
-    while (pdev->free_outputs || !SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-        FlushReleaseRing(pdev);
-        count++;
-    }
-    EngReleaseSemaphore(pdev->malloc_sem);
-    DEBUG_PRINT((pdev, 3, "%s: complete after %d rounds\n", __FUNCTION__, count));
-}
-
-// todo: separate VRAM releases from DEVRAM releases
-#define AllocMem(pdev, mspace_type, size) __AllocMem(pdev, mspace_type, size, TRUE)
-static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, BOOL force)
-{
-    UINT8 *ptr;
-
-    ASSERT(pdev, pdev && pdev->mspaces[mspace_type]._mspace);
-    DEBUG_PRINT((pdev, 12, "%s: 0x%lx %p(%d) size %u\n", __FUNCTION__, pdev,
-        pdev->mspaces[mspace_type]._mspace,
-        mspace_footprint(pdev->mspaces[mspace_type]._mspace),
-        size));
-#ifdef DBG
-    if (pdev && pdev->log_level && *pdev->log_level > 11) {
-        mspace_malloc_stats(pdev->mspaces[mspace_type]._mspace);
-    }
-#endif
-    EngAcquireSemaphore(pdev->malloc_sem);
-
-    while (1) {
-        /* Release lots of queued resources, before allocating, as we
-           want to release early to minimize fragmentation risks. */
-        FlushReleaseRing(pdev);
-
-        ptr = mspace_malloc(pdev->mspaces[mspace_type]._mspace, size);
-        if (ptr) {
-            break;
-        }
-
-        if (pdev->free_outputs != 0 ||
-            !SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-            /* We have more things to free, try that */
-            continue;
-        }
-
-        if (force) {
-            /* Ask spice to free some stuff */
-            WaitForReleaseRing(pdev);
-        } else {
-            /* Fail */
-            break;
-        }
-    }
-
-    EngReleaseSemaphore(pdev->malloc_sem);
-    ASSERT(pdev, (!ptr && !force) || (ptr >= pdev->mspaces[mspace_type].mspace_start &&
-                                      ptr < pdev->mspaces[mspace_type].mspace_end));
-    DEBUG_PRINT((pdev, 13, "%s: 0x%lx done 0x%x\n", __FUNCTION__, pdev, ptr));
-    return ptr;
-}
-
-static void FreeMem(PDev* pdev, UINT32 mspace_type, void *ptr)
-{
-    ASSERT(pdev, pdev && pdev->mspaces[mspace_type]._mspace);
-#ifdef DBG
-    if (!((UINT8 *)ptr >= pdev->mspaces[mspace_type].mspace_start &&
-                 (UINT8 *)ptr < pdev->mspaces[mspace_type].mspace_end)) {
-        DebugPrint(pdev, 0, "ASSERT failed @ %s, %p not in [%p, %p) (%d)\n", __FUNCTION__,
-            ptr, pdev->mspaces[mspace_type].mspace_start,
-            pdev->mspaces[mspace_type].mspace_end, mspace_type);
-        EngDebugBreak();
-    }
-#endif
-    EngAcquireSemaphore(pdev->malloc_sem);
-    mspace_free(pdev->mspaces[mspace_type]._mspace, ptr);
-    EngReleaseSemaphore(pdev->malloc_sem);
-}
-
-static void InitMspace(PDev *pdev, UINT32 mspace_type, UINT8 *start, size_t capacity)
-{
-    pdev->mspaces[mspace_type]._mspace = create_mspace_with_base(start, capacity, 0, pdev);
-    pdev->mspaces[mspace_type].mspace_start = start;
-    pdev->mspaces[mspace_type].mspace_end = start + capacity;
-}
-
-static void ResetCache(PDev *pdev)
-{
-    int i;
-
-    RtlZeroMemory(pdev->image_key_lookup,
-                  sizeof(pdev->image_key_lookup));
-    RtlZeroMemory(pdev->cache_image_pool,
-                  sizeof(pdev->cache_image_pool));
-    RingInit(&pdev->cache_image_lru);
-    for (i = 0; i < IMAGE_POOL_SIZE; i++) {
-        RingAdd(pdev, &pdev->cache_image_lru,
-                &pdev->cache_image_pool[i].lru_link);
-    }
-
-    RtlZeroMemory(pdev->image_cache, sizeof(pdev->image_cache));
-    RtlZeroMemory(pdev->cursor_cache, sizeof(pdev->cursor_cache));
-    RingInit(&pdev->cursors_lru);
-    pdev->num_cursors = 0;
-    pdev->last_cursor_id = 0;
-
-    RtlZeroMemory(pdev->palette_cache, sizeof(pdev->palette_cache));
-    RingInit(&pdev->palette_lru);
-    pdev->num_palettes = 0;
-}
-
-/* Init anything that resides on the device memory (pci vram and devram bars).
- * NOTE: TODO better documentation of what is on the guest ram (saved during sleep)
- * and what is on the pci device bars (bar 0 and 1, devram and vram)
- */
-void InitDeviceMemoryResources(PDev *pdev)
-{
-    UINT32 i;
-
-    DEBUG_PRINT((pdev, 0, "%s: %d, %d\n", __FUNCTION__, pdev->num_io_pages * PAGE_SIZE,
-                pdev->fb_size));
-    RtlZeroMemory(pdev->update_trace_items, sizeof(pdev->update_trace_items));
-    RingInit(&pdev->update_trace);
-    for (i = 0; i < NUM_UPDATE_TRACE_ITEMS; i++) {
-         RingAdd(pdev, &pdev->update_trace, &pdev->update_trace_items[i].link);
-    }
-    InitMspace(pdev, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
-    InitMspace(pdev, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
-    ResetCache(pdev);
-    pdev->free_outputs = 0;
-}
-
-void InitSurfaces(PDev *pdev)
-{
-    UINT32 i;
-    pdev->surfaces_info = (SurfaceInfo *)EngAllocMem(FL_ZERO_MEMORY,
-                                                     sizeof(SurfaceInfo) * pdev->n_surfaces,
-                                                     ALLOC_TAG);
-    if (!pdev->surfaces_info) {
-        PANIC(pdev, "surfaces_info allocation failed\n");
-    }
-
-    pdev->free_surfaces = &pdev->surfaces_info[1];
-    for (i = 0; i < pdev->n_surfaces - 1; i++) {
-        pdev->surfaces_info[i].u.next_free = &pdev->surfaces_info[i+1];
-    }
-}
-
-void ClearResources(PDev *pdev)
-{
-    if (pdev->surfaces_info) {
-        EngFreeMem(pdev->surfaces_info);
-        pdev->surfaces_info = NULL;
-    }
-
-    if (pdev->malloc_sem) {
-        EngDeleteSemaphore(pdev->malloc_sem);
-        pdev->malloc_sem = NULL;
-    }
-
-    if (pdev->cmd_sem) {
-        EngDeleteSemaphore(pdev->cmd_sem);
-        pdev->cmd_sem = NULL;
-    }
-
-    if (pdev->cursor_sem) {
-        EngDeleteSemaphore(pdev->cursor_sem);
-        pdev->cursor_sem = NULL;
-    }
-
-    if (pdev->print_sem) {
-        EngDeleteSemaphore(pdev->print_sem);
-        pdev->print_sem = NULL;
-    }
-}
-
-void InitResources(PDev *pdev)
-{
-    DEBUG_PRINT((pdev, 3, "%s: entry\n", __FUNCTION__));
-
-    InitSurfaces(pdev);
-    InitDeviceMemoryResources(pdev);
-
-    pdev->update_id = *pdev->dev_update_id;
-
-    pdev->malloc_sem = EngCreateSemaphore();
-    if (!pdev->malloc_sem) {
-        PANIC(pdev, "malloc sem creation failed\n");
-    }
-    pdev->cmd_sem = EngCreateSemaphore();
-    if (!pdev->cmd_sem) {
-        PANIC(pdev, "cmd sem creation failed\n");
-    }
-    pdev->cursor_sem = EngCreateSemaphore();
-    if (!pdev->cursor_sem) {
-        PANIC(pdev, "cursor sem creation failed\n");
-    }
-    pdev->print_sem = EngCreateSemaphore();
-    if (!pdev->print_sem) {
-        PANIC(pdev, "print sem creation failed\n");
-    }
-
-    ONDBG(pdev->num_outputs = 0);
-    ONDBG(pdev->num_path_pages = 0);
-    ONDBG(pdev->num_rects_pages = 0);
-    ONDBG(pdev->num_bits_pages = 0);
-    ONDBG(pdev->num_buf_pages = 0);
-    ONDBG(pdev->num_glyphs_pages = 0);
-    ONDBG(pdev->num_cursor_pages = 0);
-
-#ifdef CALL_TEST
-    pdev->count_calls = TRUE;
-    pdev->total_calls = 0;
-    for (i = 0; i < NUM_CALL_COUNTERS; i++) {
-        pdev->call_counters[i] = 0;
-    }
-#endif
-    DEBUG_PRINT((pdev, 1, "%s: exit\n", __FUNCTION__));
-}
-
-static QXLDrawable *GetDrawable(PDev *pdev)
-{
-    QXLOutput *output;
-
-    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLDrawable));
-    output->num_res = 0;
-    RESOURCE_TYPE(output, RESOURCE_TYPE_DRAWABLE);
-    ((QXLDrawable *)output->data)->release_info.id = (UINT64)output;
-    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
-    ONDBG(pdev->num_outputs++); //todo: atomic
-    return(QXLDrawable *)output->data;
-}
-
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id)
-{
-    QXLDrawable *drawable;
-
-    ASSERT(pdev, pdev && area);
-
-    drawable = GetDrawable(pdev);
-    drawable->surface_id = surface_id;
-    drawable->type = type;
-    drawable->effect = QXL_EFFECT_BLEND;
-    drawable->self_bitmap = 0;
-    drawable->mm_time = *pdev->mm_clock;
-    drawable->surfaces_dest[0] = -1;
-    drawable->surfaces_dest[1] = - 1;
-    drawable->surfaces_dest[2] = -1;
-    CopyRect(&drawable->bbox, area);
-
-    if (!SetClip(pdev, clip, drawable)) {
-        DEBUG_PRINT((pdev, 0, "%s: set clip failed\n", __FUNCTION__));
-        ReleaseOutput(pdev, drawable->release_info.id);
-        drawable = NULL;
-    }
-    return drawable;
-}
-
-void PushDrawable(PDev *pdev, QXLDrawable *drawable)
-{
-    QXLCommand *cmd;
-
-    EngAcquireSemaphore(pdev->cmd_sem);
-    WaitForCmdRing(pdev);
-    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
-    cmd->type = QXL_CMD_DRAW;
-    cmd->data = PA(pdev, drawable, pdev->main_mem_slot);
-    PUSH_CMD(pdev);
-    EngReleaseSemaphore(pdev->cmd_sem);
-}
-
-static QXLSurfaceCmd *GetSurfaceCmd(PDev *pdev)
-{
-    QXLOutput *output;
-
-    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLSurfaceCmd));
-    output->num_res = 0;
-    RESOURCE_TYPE(output, RESOURCE_TYPE_SURFACE);
-    ((QXLSurfaceCmd *)output->data)->release_info.id = (UINT64)output;
-    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
-    ONDBG(pdev->num_outputs++); //todo: atomic
-    return(QXLSurfaceCmd *)output->data;
-}
-
-QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id)
-{
-    QXLSurfaceCmd *surface_cmd;
-
-    ASSERT(pdev, pdev);
-
-    surface_cmd = GetSurfaceCmd(pdev);
-    surface_cmd->surface_id = surface_id;
-    surface_cmd->type = type;
-    surface_cmd->flags = 0;
-
-    return surface_cmd;
-}
-
-void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
-{
-    QXLCommand *cmd;
-
-    EngAcquireSemaphore(pdev->cmd_sem);
-    WaitForCmdRing(pdev);
-    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
-    cmd->type = QXL_CMD_SURFACE;
-    cmd->data = PA(pdev, surface_cmd, pdev->main_mem_slot);
-    PUSH_CMD(pdev);
-    EngReleaseSemaphore(pdev->cmd_sem);
-}
-
-QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem)
-{
-    return PA(pdev, base_mem, pdev->vram_mem_slot);
-}
-
-_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, INT32 *stride,
-                              UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
-{
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    switch (allocation_type) {
-    case DEVICE_BITMAP_ALLOCATION_TYPE_SURF0:
-        ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
-        *base_mem = pdev->primary_memory_start;
-        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
-        *stride = (x * depth / 8 + 3) & ~0x3; /* Pixman requires 4 byte aligned stride */
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
-        *stride = x * depth / 8;
-        *stride = ALIGN(*stride, 4);
-        *base_mem = AllocMem(pdev, MSPACE_TYPE_DEVRAM, (*stride) * y);
-        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
-        *stride = x * depth / 8;
-        *stride = ALIGN(*stride, 4);
-        *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE);
-        *phys_mem = SurfaceToPhysical(pdev, *base_mem);
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
-        /* used only before suspend to sleep (DrvAssertMode(FALSE)) and then released
-         * and copied back to VRAM */
-        *stride = x * depth / 8;
-        *stride = ALIGN(*stride, 4);
-        *base_mem = EngAllocMem(0 /* don't zero memory, will be copied over in a bit */,
-                                (*stride) * y, ALLOC_TAG);
-        *phys_mem = (QXLPHYSICAL)NULL; /* make sure no one uses it */
-        break;
-    default:
-        PANIC(pdev, "No allocation type");
-    }
-}
-
-void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
-{
-    GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
-}
-
-void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type)
-{
-    switch (allocation_type) {
-    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, base_mem);
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
-        FreeMem(pdev, MSPACE_TYPE_VRAM, base_mem);
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
-        EngFreeMem(base_mem);
-        break;
-    default:
-        PANIC(pdev, "bad allocation type");
-    }
-}
-
-typedef struct InternalDelSurface {
-    UINT32 surface_id;
-    UINT8 allocation_type;
-} InternalDelSurface;
-
-
-static void FreeDelSurface(PDev *pdev, Resource *res)
-{
-    InternalDelSurface *internal;
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    internal = (InternalDelSurface *)res->res;
-    QXLDelSurface(pdev, GetSurfaceInfo(pdev, internal->surface_id)->draw_area.base_mem,
-        internal->allocation_type);
-    FreeSurfaceInfo(pdev, internal->surface_id);
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-#define SURFACEDEL_ALLOC_BASE (sizeof(Resource) + sizeof(InternalDelSurface))
-
-void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type)
-{
-    Resource *surface_res;
-    InternalDelSurface *internal;
-    size_t alloc_size;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    alloc_size = SURFACEDEL_ALLOC_BASE;
-    surface_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
-    
-    surface_res->refs = 1;
-    surface_res->free = FreeDelSurface;
-    RESOURCE_TYPE(surface_res, RESOURCE_TYPE_SURFACE);
-
-    internal = (InternalDelSurface *)surface_res->res;
-    internal->surface_id = surface_id;
-    internal->allocation_type = allocation_type;
-
-    SurfaceAddRes(pdev, surface, surface_res);
-    RELEASE_RES(pdev, surface_res);
-}
-
-static void FreePath(PDev *pdev, Resource *res)
-{
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    chunk_phys = ((QXLPath *)res->res)->chunk.next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_path_pages--);
-    }
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_path_pages--);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-#define NEW_DATA_CHUNK(page_counter, size) {                                    \
-    void *ptr = AllocMem(pdev, MSPACE_TYPE_DEVRAM, size + sizeof(QXLDataChunk));                    \
-    ONDBG((*(page_counter))++);                                                 \
-    chunk->next_chunk = PA(pdev, ptr, pdev->main_mem_slot);                     \
-    ((QXLDataChunk *)ptr)->prev_chunk = PA(pdev, chunk, pdev->main_mem_slot);   \
-    chunk = (QXLDataChunk *)ptr;                                                \
-    chunk->data_size = 0;                                                       \
-    chunk->next_chunk = 0;                                                      \
-    now = chunk->data;                                                          \
-    end = now + size;                                                           \
-}
-
-#ifdef DBG
-    #define GetPathCommon __GetPathCommon
-#else
-    #define GetPathCommon(pdev, path, chunk_ptr, now_ptr, end_ptr, data_size, page_counter)\
-        __GetPathCommon(pdev, path, chunk_ptr, now_ptr, end_ptr, data_size, NULL)
-#endif
-
-#define PATH_PREALLOC_PONTS 20
-#define PATH_MAX_ALLOC_PONTS 128
-#define PATH_ALLOC_SIZE (sizeof(Resource) + sizeof(QXLPath) + sizeof(QXLPathSeg) +\
-                         sizeof(POINTFIX) * PATH_PREALLOC_PONTS)
-
-
-static void __GetPathCommon(PDev *pdev, PATHOBJ *path, QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
-                            UINT8 **end_ptr, UINT32 *data_size, int *page_counter)
-{
-    QXLDataChunk *chunk = *chunk_ptr;
-    UINT8 *now = *now_ptr;
-    UINT8 *end = *end_ptr;
-    PATHDATA data;
-    int more;
-
-    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
-    PATHOBJ_vEnumStart(path);
-
-    do {
-        int pt_buf_size;
-        UINT8 *pt_buf;
-        QXLPathSeg *seg;
-
-        more = PATHOBJ_bEnum(path, &data);
-        if (data.count == 0) {
-            break;
-        }
-
-        if (end - now < sizeof(QXLPathSeg)) {
-            size_t alloc_size = MIN(data.count << 3, sizeof(POINTFIX) * PATH_MAX_ALLOC_PONTS);
-            alloc_size += sizeof(QXLPathSeg);
-            NEW_DATA_CHUNK(page_counter, alloc_size);
-        }
-        seg = (QXLPathSeg*)now;
-        seg->flags = data.flags;
-        seg->count = data.count;
-        now = (UINT8 *)seg->points;
-        chunk->data_size += sizeof(*seg);
-        *data_size +=  sizeof(*seg);
-        pt_buf_size = data.count << 3;
-        pt_buf = (UINT8 *)data.pptfx;
-
-        do {
-            int cp_size;
-            if (end == now ) {
-                size_t alloc_size = MIN(pt_buf_size, sizeof(POINTFIX) * PATH_MAX_ALLOC_PONTS);
-                NEW_DATA_CHUNK(page_counter, alloc_size);
-            }
-
-            cp_size = (int)MIN(end - now, pt_buf_size);
-            memcpy(now, pt_buf, cp_size);
-            chunk->data_size += cp_size;
-            *data_size += cp_size;
-            now += cp_size;
-            pt_buf += cp_size;
-            pt_buf_size -= cp_size;
-        } while (pt_buf_size);
-    } while (more);
-
-    *chunk_ptr = chunk;
-    *now_ptr = now;
-    *end_ptr = end;
-    DEBUG_PRINT((pdev, 17, "%s: done\n", __FUNCTION__));
-}
-
-static Resource *__GetPath(PDev *pdev, PATHOBJ *path)
-{
-    Resource *res;
-    QXLPath *qxl_path;
-    QXLDataChunk *chunk;
-    PATHDATA data;
-    UINT8 *now;
-    UINT8 *end;
-    int more;
-
-    ASSERT(pdev, QXL_PATH_BEGIN == PD_BEGINSUBPATH && QXL_PATH_END == PD_ENDSUBPATH &&
-           QXL_PATH_CLOSE == PD_CLOSEFIGURE && QXL_PATH_BEZIER == PD_BEZIERS);
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, PATH_ALLOC_SIZE);
-    ONDBG(pdev->num_path_pages++);
-    res->refs = 1;
-    res->free = FreePath;
-    RESOURCE_TYPE(res, RESOURCE_TYPE_PATH);
-
-    qxl_path = (QXLPath *)res->res;
-    qxl_path->data_size = 0;
-    chunk = &qxl_path->chunk;
-    chunk->data_size = 0;
-    chunk->prev_chunk = 0;
-    chunk->next_chunk = 0;
-
-    now = chunk->data;
-    end = (UINT8 *)res + PATH_ALLOC_SIZE;
-    GetPathCommon(pdev, path, &chunk, &now, &end, &qxl_path->data_size,
-                  &pdev->num_path_pages);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-    return res;
-}
-
-BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path)
-{
-    Resource *path_res;
-    ASSERT(pdev, pdev && drawable && path_phys && path);
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-
-    path_res = __GetPath(pdev, path);
-    *path_phys = PA(pdev, path_res->res, pdev->main_mem_slot);
-    DrawableAddRes(pdev, drawable, path_res);
-    RELEASE_RES(pdev, path_res);
-    return TRUE;
-}
-
-
-static void FreeClipRects(PDev *pdev, Resource *res)
-{
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    chunk_phys = ((QXLClipRects *)res->res)->chunk.next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_rects_pages--);
-    }
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_rects_pages--);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-
-#define RECTS_NUM_PREALLOC 8
-#define RECTS_ALLOC_SIZE (sizeof(Resource) + sizeof(QXLClipRects) + \
-                          sizeof(QXLRect) * RECTS_NUM_PREALLOC)
-#define RECTS_NUM_ALLOC 20
-#define RECTS_CHUNK_ALLOC_SIZE (sizeof(QXLDataChunk) + sizeof(QXLRect) * RECTS_NUM_ALLOC)
-
-static Resource *GetClipRects(PDev *pdev, CLIPOBJ *clip)
-{
-    Resource *res;
-    QXLClipRects *rects;
-    QXLDataChunk *chunk;
-    QXLRect *dest;
-    QXLRect *dest_end;
-    int more;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, RECTS_ALLOC_SIZE);
-    ONDBG(pdev->num_rects_pages++);
-    res->refs = 1;
-    res->free = FreeClipRects;
-    RESOURCE_TYPE(res, RESOURCE_TYPE_CLIP_RECTS);
-    rects = (QXLClipRects *)res->res;
-    rects->num_rects = 0;
-
-    chunk = &rects->chunk;
-    chunk->data_size = 0;
-    chunk->prev_chunk = 0;
-    chunk->next_chunk = 0;
-
-    dest = (QXLRect *)chunk->data;
-    dest_end = dest + ((RECTS_ALLOC_SIZE - sizeof(Resource) - sizeof(QXLClipRects)) >> 4);
-
-    CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
-    do {
-        RECTL *now;
-        RECTL *end;
-        struct {
-            ULONG  count;
-            RECTL  rects[20];
-        } buf;
-
-        more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
-        rects->num_rects += buf.count;
-        for (now = buf.rects, end = now + buf.count; now < end; now++, dest++) {
-            if (dest == dest_end) {
-                void *page = AllocMem(pdev, MSPACE_TYPE_DEVRAM, RECTS_CHUNK_ALLOC_SIZE);
-                ONDBG(pdev->num_rects_pages++);
-                chunk->next_chunk = PA(pdev, page, pdev->main_mem_slot);
-                ((QXLDataChunk *)page)->prev_chunk = PA(pdev, chunk, pdev->main_mem_slot);
-                chunk = (QXLDataChunk *)page;
-                chunk->data_size = 0;
-                chunk->next_chunk = 0;
-                dest = (QXLRect *)chunk->data;
-                dest_end = dest + RECTS_NUM_ALLOC;
-            }
-            CopyRect(dest, now);
-            chunk->data_size += sizeof(QXLRect);
-        }
-    } while (more);
-    DEBUG_PRINT((pdev, 13, "%s: done, num_rects %d\n", __FUNCTION__, rects->num_rects));
-    return res;
-}
-
-static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable)
-{
-    Resource *rects_res;
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-
-    if (clip == NULL) {
-        drawable->clip.type = SPICE_CLIP_TYPE_NONE;
-        DEBUG_PRINT((pdev, 10, "%s: QXL_CLIP_TYPE_NONE\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    if (clip->iDComplexity == DC_RECT) {
-        QXLClipRects *rects;
-        rects_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + sizeof(QXLClipRects) +
-                                         sizeof(QXLRect));
-        rects_res->refs = 1;
-        rects_res->free = FreeClipRects;
-        RESOURCE_TYPE(rects_res, RESOURCE_TYPE_CLIP_RECTS);
-        rects = (QXLClipRects *)rects_res->res;
-        rects->num_rects = 1;
-        rects->chunk.data_size = sizeof(QXLRect);
-        rects->chunk.prev_chunk = 0;
-        rects->chunk.next_chunk = 0;
-        CopyRect((QXLRect *)rects->chunk.data, &clip->rclBounds);
-    } else {
-      rects_res = GetClipRects(pdev, clip);
-    }
-
-    DrawableAddRes(pdev, drawable, rects_res);
-    RELEASE_RES(pdev, rects_res);
-    drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
-    drawable->clip.data = PA(pdev, rects_res->res, pdev->main_mem_slot);
-    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-#ifndef _WIN64
-
-static _inline void fast_memcpy_aligment(void *dest, const void *src, size_t len)
-{
-    _asm
-    {
-        mov ecx, len
-        mov esi, src
-        mov edi, dest
-
-        cmp ecx, 128
-        jb try_to_copy64
- 
-        prefetchnta [esi]
-        copy_128:
-            prefetchnta [esi + 64]
-
-            movdqa xmm0, [esi]
-            movdqa xmm1, [esi + 16]
-            movdqa xmm2, [esi + 32]
-            movdqa xmm3, [esi + 48]
-
-            prefetchnta [esi + 128]
-
-            movntdq [edi], xmm0
-            movntdq [edi + 16], xmm1
-            movntdq [edi + 32], xmm2
-            movntdq [edi + 48], xmm3
-
-            movdqa xmm0, [esi + 64]
-            movdqa xmm1, [esi + 80]
-            movdqa xmm2, [esi + 96]
-            movdqa xmm3, [esi + 112]
-
-            movntdq [edi + 64], xmm0
-            movntdq [edi + 80], xmm1
-            movntdq [edi + 96], xmm2
-            movntdq [edi + 112], xmm3
-
-            add edi, 128
-            add esi, 128
-            sub ecx, 128
-            cmp ecx, 128
-            jae copy_128
- 
-       try_to_copy64:
-            cmp ecx, 64
-            jb try_to_copy32
-
-             movdqa xmm0, [esi]
-             movdqa xmm1, [esi + 16]
-             movdqa xmm2, [esi + 32]
-             movdqa xmm3, [esi + 48]
-
-             movntdq [edi], xmm0
-             movntdq [edi + 16], xmm1
-             movntdq [edi + 32], xmm2
-             movntdq [edi + 48], xmm3
-             
-             add edi, 64
-             add esi, 64
-             sub ecx, 64
-             prefetchnta [esi]
-
-        try_to_copy32:
-             cmp ecx, 32
-             jb try_to_copy16
-
-             movdqa xmm0, [esi]
-             movdqa xmm1, [esi + 16] 
-             movntdq [edi], xmm0
-             movntdq [edi + 16], xmm1
-
-             add edi, 32 
-             add esi, 32 
-             sub ecx, 32
-
-        try_to_copy16:
-             cmp ecx, 16
-             jb try_to_copy4
-
-             movdqa xmm0, [esi]
-             movntdq [edi], xmm0
-
-             add edi, 16
-             add esi, 16
-             sub ecx, 16
-
-
-        try_to_copy4:
-            cmp ecx, 4
-            jb try_to_copy_1 
-            movsd
-            sub ecx, 4
-            jmp try_to_copy4
-
-        try_to_copy_1:     
-            rep movsb
-
-        sfence
-    }
-}
-
-static _inline void fast_memcpy_unaligment(void *dest, const void *src, size_t len)
-{
-    _asm
-    {
-        mov ecx, len
-        mov esi, src
-        mov edi, dest
-
-        cmp ecx, 128
-        jb try_to_copy64
- 
-        prefetchnta [esi]
-        copy_128:
-            prefetchnta [esi + 64]
-
-            movdqu xmm0, [esi]
-            movdqu xmm1, [esi + 16]
-            movdqu xmm2, [esi + 32]
-            movdqu xmm3, [esi + 48]
-
-            prefetchnta [esi + 128]
-
-            movntdq [edi], xmm0
-            movntdq [edi + 16], xmm1
-            movntdq [edi + 32], xmm2
-            movntdq [edi + 48], xmm3
-
-            movdqu xmm0, [esi + 64]
-            movdqu xmm1, [esi + 80]
-            movdqu xmm2, [esi + 96]
-            movdqu xmm3, [esi + 112]
-
-            movntdq [edi + 64], xmm0
-            movntdq [edi + 80], xmm1
-            movntdq [edi + 96], xmm2
-            movntdq [edi + 112], xmm3
-
-            add edi, 128
-            add esi, 128
-            sub ecx, 128
-            cmp ecx, 128
-            jae copy_128
- 
-       try_to_copy64:
-            cmp ecx, 64
-            jb try_to_copy32
-
-             movdqu xmm0, [esi]
-             movdqu xmm1, [esi + 16]
-             movdqu xmm2, [esi + 32]
-             movdqu xmm3, [esi + 48]
-
-             movntdq [edi], xmm0
-             movntdq [edi + 16], xmm1
-             movntdq [edi + 32], xmm2
-             movntdq [edi + 48], xmm3
-             
-             add edi, 64
-             add esi, 64
-             sub ecx, 64
-             prefetchnta [esi]
-
-        try_to_copy32:
-             cmp ecx, 32
-             jb try_to_copy16
-
-             movdqu xmm0, [esi]
-             movdqu xmm1, [esi + 16] 
-             movntdq [edi], xmm0
-             movntdq [edi + 16], xmm1
-
-             add edi, 32 
-             add esi, 32 
-             sub ecx, 32
-
-        try_to_copy16:
-             cmp ecx, 16
-             jb try_to_copy4
-
-             movdqu xmm0, [esi]
-             movntdq [edi], xmm0
-
-             add edi, 16
-             add esi, 16
-             sub ecx, 16
-
-
-        try_to_copy4:
-            cmp ecx, 4
-            jb try_to_copy_1 
-            movsd
-            sub ecx, 4
-            jmp try_to_copy4
-
-        try_to_copy_1:     
-            rep movsb
-
-        sfence
-    }
-}
-
-#endif
-
-#ifdef DBG
-    #define PutBytesAlign __PutBytesAlign
-#define PutBytes(pdev, chunk, now, end, src, size, page_counter, alloc_size, use_sse)\
-    __PutBytesAlign(pdev, chunk, now, end, src, size, page_counter, alloc_size, 1, use_sse)
-#else
-#define  PutBytesAlign(pdev, chunk, now, end, src, size, page_counter, alloc_size, alignment, use_sse)\
-    __PutBytesAlign(pdev, chunk, now, end, src, size, NULL, alloc_size, alignment, use_sse)
-#define  PutBytes(pdev, chunk, now, end, src, size, page_counter, alloc_size, use_sse)\
-    __PutBytesAlign(pdev, chunk, now, end, src, size, NULL, alloc_size, 1, use_sse)
-#endif
-
-#define BITS_BUF_MAX (64 * 1024)
-
-static void __PutBytesAlign(PDev *pdev, QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
-                            UINT8 **end_ptr, UINT8 *src, int size, int *page_counter,
-                            size_t alloc_size, uint32_t alignment, BOOL use_sse)
-{
-    QXLDataChunk *chunk = *chunk_ptr;
-    UINT8 *now = *now_ptr;
-    UINT8 *end = *end_ptr;
-    int offset;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    while (size) {
-        int cp_size = (int)MIN(end - now, size);
-        if (!cp_size) {
-            size_t aligned_size;
-            ASSERT(pdev, alloc_size > 0);
-            ASSERT(pdev, BITS_BUF_MAX > alignment);
-            aligned_size = (int)MIN(alloc_size + alignment - 1, BITS_BUF_MAX);
-            aligned_size -=  aligned_size % alignment;
-            NEW_DATA_CHUNK(page_counter, aligned_size);
-            cp_size = (int)MIN(end - now, size);
-        }
-#ifndef _WIN64
-        if (use_sse) {
-            offset = (size_t)now & SSE_MASK;
-            if (offset) {
-                offset = SSE_ALIGN - offset;
-                if (offset >= cp_size) {
-                    RtlCopyMemory(now, src, cp_size);
-                    src += cp_size;
-                    now += cp_size;
-                    chunk->data_size += cp_size;
-                    size -= cp_size;
-                    continue;
-                }
-                RtlCopyMemory(now, src,  offset);
-                now += offset;
-                src += offset;
-                size -= offset;
-                cp_size -= offset;
-                chunk->data_size += offset;
-            }
-    
-            if (((size_t)src & SSE_MASK) == 0) {
-                fast_memcpy_aligment(now, src, cp_size);
-            } else {
-                fast_memcpy_unaligment(now, src, cp_size);
-            }
-        } else {
-            RtlCopyMemory(now, src, cp_size);
-        }
-#else
-        RtlCopyMemory(now, src, cp_size);
-#endif
-        src += cp_size;
-        now += cp_size;
-        chunk->data_size += cp_size;
-        size -= cp_size;
-    }
-    *chunk_ptr = chunk;
-    *now_ptr = now;
-    *end_ptr = end;
-    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
-}
-
-typedef struct InternalImage {
-    CacheImage *cache;
-    QXLImage image;
-} InternalImage;
-
-#define HSURF_HASH_VAL(h) (((unsigned long)h >> 4) ^ ((unsigned long)(h) >> 8) ^ \
-                           ((unsigned long)(h) >> 16) ^ ((unsigned long)(h) >> 24))
-
-#define IMAGE_KEY_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & IMAGE_KEY_HASH_MASK)
-
-static void ImageKeyPut(PDev *pdev, HSURF hsurf, UINT64 unique, UINT32 key)
-{
-    ImageKey *image_key;
-
-    if (!unique) {
-        return;
-    }
-    image_key = &pdev->image_key_lookup[IMAGE_KEY_HASH_VAL(hsurf)];
-    image_key->hsurf = hsurf;
-    image_key->unique = unique;
-    image_key->key = key;
-}
-
-static BOOL ImageKeyGet(PDev *pdev, HSURF hsurf, UINT64 unique, UINT32 *key)
-{
-    ImageKey *image_key;
-    BOOL res = FALSE;
-
-    if (!unique) {
-        return FALSE;
-    }
-    image_key = &pdev->image_key_lookup[IMAGE_KEY_HASH_VAL(hsurf)];
-    if (image_key->hsurf == hsurf && image_key->unique == unique) {
-        *key = image_key->key;
-        res = TRUE;
-    }
-    return res;
-}
-
-#define IMAGE_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & IMAGE_HASH_MASK)
-
-static CacheImage *ImageCacheGetByKey(PDev *pdev, UINT32 key, BOOL check_rest,
-                                      UINT8 format, UINT32 width, UINT32 height)
-{
-    CacheImage *cache_image;
-
-    cache_image = pdev->image_cache[IMAGE_HASH_VAL(key)];
-    while (cache_image) {
-        if (cache_image->key == key && (!check_rest || (cache_image->format == format &&
-            cache_image->width == width && cache_image->height == height))) {
-            break;
-        }
-        cache_image = cache_image->next;
-    }
-    return cache_image;
-}
-
-static void ImageCacheAdd(PDev *pdev, CacheImage *cache_image)
-{
-    int key;
-
-    key = IMAGE_HASH_VAL(cache_image->key);
-    cache_image->next = pdev->image_cache[key];
-    cache_image->hits = 1;
-    pdev->image_cache[key] = cache_image;
-}
-
-static void ImageCacheRemove(PDev *pdev, CacheImage *cache_image)
-{
-    CacheImage **cache_img;
-
-    if (!cache_image->hits) {
-        return;
-    }
-    cache_img = &pdev->image_cache[IMAGE_HASH_VAL(cache_image->key)];
-    while (*cache_img) {
-        if ((*cache_img)->key == cache_image->key) {
-            *cache_img = cache_image->next;
-            break;
-        }
-        cache_img = &(*cache_img)->next;
-    }
-}
-
-static CacheImage *AllocCacheImage(PDev* pdev)
-{
-    RingItem *item;
-    while (!(item = RingGetTail(pdev, &pdev->cache_image_lru))) {
-        /* malloc_sem protects release_ring too */
-        EngAcquireSemaphore(pdev->malloc_sem);
-        if (pdev->free_outputs == 0 &&
-            SPICE_RING_IS_EMPTY(pdev->release_ring)) {
-            WaitForReleaseRing(pdev);
-        }
-        FlushReleaseRing(pdev);
-        EngReleaseSemaphore(pdev->malloc_sem);
-    }
-    RingRemove(pdev, item);
-    return CONTAINEROF(item, CacheImage, lru_link);
-}
-
-#define IMAGE_HASH_INIT_VAL(width, height, format) \
-    ((UINT32)((width) & 0x1FFF) | ((UINT32)((height) & 0x1FFF) << 13) |\
-     ((UINT32)(format) << 26))
-
-static _inline void SetImageId(InternalImage *internal, BOOL cache_me, LONG width, LONG height,
-                               UINT8 format, UINT32 key)
-{
-    UINT32 image_info = IMAGE_HASH_INIT_VAL(width, height, format);
-
-    if (cache_me) {
-        QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER << 30) |
-                         image_info, key);
-        internal->image.descriptor.flags = QXL_IMAGE_CACHE;
-    } else {
-        QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER_DONT_CACHE  << 30) |
-                         image_info, key);
-        internal->image.descriptor.flags = 0;
-    }
-}
-
-typedef struct InternalPalette {
-    UINT32 refs;
-    struct InternalPalette *next;
-    RingItem lru_link;
-    QXLPalette palette;
-} InternalPalette;
-
-#define PALETTE_HASH_VAL(unique) ((int)(unique) & PALETTE_HASH_NASKE)
-
-static _inline void ReleasePalette(PDev *pdev, InternalPalette *palette)
-{
-    ASSERT(pdev, palette);
-    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
-    if (--palette->refs == 0) {
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, palette);
-    }
-}
-
-static _inline void PaletteCacheRemove(PDev *pdev, InternalPalette *palette)
-{
-    InternalPalette **internal;
-    BOOL found = FALSE;
-
-    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
-
-    ASSERT(pdev, palette->palette.unique);
-    internal = &pdev->palette_cache[PALETTE_HASH_VAL(palette->palette.unique)];
-
-    while (*internal) {
-        if ((*internal)->palette.unique == palette->palette.unique) {
-            *internal = palette->next;
-            found = TRUE;
-            break;
-        }
-        internal = &(*internal)->next;
-    }
-
-    RingRemove(pdev, &palette->lru_link);
-    ReleasePalette(pdev, palette);
-    pdev->num_palettes--;
-
-    if (!found) {
-        DEBUG_PRINT((pdev, 0, "%s: Error: palette 0x%x isn't in cache \n", __FUNCTION__, palette));
-        ASSERT(pdev, FALSE);
-    } else {
-        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
-    }
-}
-
-static _inline InternalPalette *PaletteCacheGet(PDev *pdev, UINT32 unique)
-{
-    InternalPalette *now;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    if (!unique) {
-        return NULL;
-    }
-
-    now = pdev->palette_cache[PALETTE_HASH_VAL(unique)];
-    while (now) {
-        if (now->palette.unique == unique) {
-            RingRemove(pdev, &now->lru_link);
-            RingAdd(pdev, &pdev->palette_lru, &now->lru_link);
-            now->refs++;
-            DEBUG_PRINT((pdev, 13, "%s: found\n", __FUNCTION__));
-            return now;
-        }
-        now = now->next;
-    }
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-    return NULL;
-}
-
-static void PaletteCacheClear(PDev *pdev)
-{
-    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
-    while(pdev->num_palettes) {
-        ASSERT(pdev, RingGetTail(pdev, &pdev->palette_lru));
-        PaletteCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->palette_lru),
-                                             InternalPalette, lru_link));
-    }
-}
-
-static _inline void PaletteCacheAdd(PDev *pdev, InternalPalette *palette)
-{
-    int key;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    if (!palette->palette.unique) {
-        DEBUG_PRINT((pdev, 13, "%s: not unique\n", __FUNCTION__));
-        return;
-    }
-
-    if (pdev->num_palettes == PALETTE_CACHE_SIZE) {
-        ASSERT(pdev, RingGetTail(pdev, &pdev->palette_lru));
-        PaletteCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->palette_lru),
-                                             InternalPalette, lru_link));
-    }
-
-    key = PALETTE_HASH_VAL(palette->palette.unique);
-    palette->next = pdev->palette_cache[key];
-    pdev->palette_cache[key] = palette;
-
-    RingAdd(pdev, &pdev->palette_lru, &palette->lru_link);
-    palette->refs++;
-    pdev->num_palettes++;
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-
-static _inline void GetPallette(PDev *pdev, QXLBitmap *bitmap, XLATEOBJ *color_trans)
-{
-    InternalPalette *internal;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    if (!color_trans || !(color_trans->flXlate & XO_TABLE)) {
-        bitmap->palette = 0;
-        return;
-    }
-
-    if ((internal = PaletteCacheGet(pdev, color_trans->iUniq))) {
-        DEBUG_PRINT((pdev, 12, "%s: from cache\n", __FUNCTION__));
-        bitmap->palette = PA(pdev, &internal->palette, pdev->main_mem_slot);
-        return;
-    }
-
-    internal = (InternalPalette *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(InternalPalette) +
-                                           (color_trans->cEntries << 2));
-    internal->refs = 1;
-    RingItemInit(&internal->lru_link);
-    bitmap->palette = PA(pdev, &internal->palette, pdev->main_mem_slot);
-    internal->palette.unique = color_trans->iUniq;
-    internal->palette.num_ents = (UINT16)color_trans->cEntries;
-
-    RtlCopyMemory(internal->palette.ents, color_trans->pulXlate, color_trans->cEntries << 2);
-    PaletteCacheAdd(pdev, internal);
-    DEBUG_PRINT((pdev, 12, "%s: done\n", __FUNCTION__));
-}
-
-static void FreeQuicImage(PDev *pdev, Resource *res) // todo: defer
-{
-    InternalImage *internal;
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    internal = (InternalImage *)res->res;
-    if (internal->cache) {
-        RingAdd(pdev, &pdev->cache_image_lru, &internal->cache->lru_link);
-        internal->cache->image = NULL;
-    }
-
-    chunk_phys = ((QXLDataChunk *)internal->image.quic.data)->next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_bits_pages--);
-
-    }
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_bits_pages--);
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-static _inline QuicImageType GetQuicImageType(UINT8 format)
-{
-    switch (format) {
-    case SPICE_BITMAP_FMT_32BIT:
-        return QUIC_IMAGE_TYPE_RGB32;
-    case SPICE_BITMAP_FMT_16BIT:
-        return QUIC_IMAGE_TYPE_RGB16;
-    case SPICE_BITMAP_FMT_RGBA:
-        return QUIC_IMAGE_TYPE_RGBA;
-    case SPICE_BITMAP_FMT_24BIT:
-        return QUIC_IMAGE_TYPE_RGB24;
-    default:
-        return QUIC_IMAGE_TYPE_INVALID;
-    };
-}
-
-#define QUIC_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
-#define QUIC_BUF_MAX (64 * 1024)
-#define QUIC_BUF_MIN 1024
-
-struct QuicData {
-    QuicUsrContext user;
-    PDev *pdev;
-    QuicContext *quic;
-    QXLDataChunk *chunk;
-    int chunk_io_words;
-    int prev_chunks_io_words;
-    int rows;
-    int raw_row_size;
-};
-
-static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed)
-{
-    QuicData *usr_data = (QuicData *)usr;
-    PDev *pdev = usr_data->pdev;
-    QXLDataChunk *new_chank;
-    int alloc_size;
-    int more;
-
-    ASSERT(pdev, usr_data->rows >= rows_completed);
-    more =  (rows_completed - usr_data->rows) * usr_data->raw_row_size;
-
-    alloc_size = MIN(MAX(more >> 4, QUIC_BUF_MIN), QUIC_BUF_MAX);
-    new_chank = AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLDataChunk) + alloc_size);
-    new_chank->data_size = 0;
-    new_chank->prev_chunk = PA(pdev, usr_data->chunk, pdev->main_mem_slot);
-    new_chank->next_chunk = 0;
-
-    usr_data->prev_chunks_io_words += usr_data->chunk_io_words;
-    usr_data->chunk->data_size = usr_data->chunk_io_words << 2;
-    usr_data->chunk->next_chunk = PA(pdev, new_chank, pdev->main_mem_slot);
-    usr_data->chunk = new_chank;
-
-    usr_data->chunk_io_words = alloc_size >> 2;
-
-    ONDBG(pdev->num_bits_pages++);
-
-    *io_ptr = (UINT32 *)new_chank->data;
-    return usr_data->chunk_io_words;
-}
-
-static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines)
-{
-    return 0;
-}
-
-static _inline Resource *GetQuicImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
-                                      BOOL cache_me, LONG width, LONG height, UINT8 format,
-                                      UINT8 *src, UINT32 line_size, UINT32 key)
-{
-    Resource *image_res;
-    InternalImage *internal;
-    QuicImageType type;
-    size_t alloc_size;
-    int data_size;
-    QuicData *quic_data;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev->quic_data);
-
-    if (!*pdev->compression_level) {
-        return NULL;
-    }
-
-    if ((type = GetQuicImageType(format)) == QUIC_IMAGE_TYPE_INVALID) {
-        DEBUG_PRINT((pdev, 13, "%s: unsupported\n", __FUNCTION__));
-        return NULL;
-    }
-
-    EngAcquireSemaphore(pdev->quic_data_sem);
-
-    quic_data = pdev->quic_data;
-
-    alloc_size = MIN(QUIC_ALLOC_BASE + (height * line_size >> 4), QUIC_ALLOC_BASE + QUIC_BUF_MAX);
-    alloc_size = MAX(alloc_size, QUIC_ALLOC_BASE + QUIC_BUF_MIN);
-
-    image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
-    ONDBG(pdev->num_bits_pages++);
-    image_res->refs = 1;
-    image_res->free = FreeQuicImage;
-    RESOURCE_TYPE(image_res, RESOURCE_TYPE_QUIC_IMAGE);
-
-    internal = (InternalImage *)image_res->res;
-    SetImageId(internal, cache_me, width, height, format, key);
-    internal->image.descriptor.type = SPICE_IMAGE_TYPE_QUIC;
-    internal->image.descriptor.width = width;
-    internal->image.descriptor.height = height;
-
-    quic_data->chunk = (QXLDataChunk *)internal->image.quic.data;
-    quic_data->chunk->data_size = 0;
-    quic_data->chunk->prev_chunk = 0;
-    quic_data->chunk->next_chunk = 0;
-    quic_data->prev_chunks_io_words = 0;
-    quic_data->chunk_io_words = (int)(((UINT8 *)image_res + alloc_size - quic_data->chunk->data) >> 2);
-    quic_data->rows = height;
-    quic_data->raw_row_size = line_size;
-
-    ASSERT(pdev, quic_data->chunk_io_words > 0);
-    data_size = quic_encode(quic_data->quic, type, width, height, src, height, surf->lDelta,
-                            (UINT32 *)quic_data->chunk->data, quic_data->chunk_io_words);
-    if (data_size == QUIC_ERROR) {
-        FreeQuicImage(pdev, image_res);
-        DEBUG_PRINT((pdev, 13, "%s: error\n", __FUNCTION__));
-        image_res = NULL;
-        goto out;
-    }
-
-    quic_data->chunk->data_size = (data_size - quic_data->prev_chunks_io_words) << 2;
-    internal->image.quic.data_size = data_size << 2;
-    DEBUG_PRINT((pdev, 13, "%s: done. row size %u quic size %u \n", __FUNCTION__,
-                 line_size * height, data_size << 2));
-
- out:
-    EngReleaseSemaphore(pdev->quic_data_sem);
-
-    return image_res;
-}
-
-static void FreeBitmapImage(PDev *pdev, Resource *res) // todo: defer
-{
-    InternalImage *internal;
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    internal = (InternalImage *)res->res;
-    if (internal->cache) {
-        RingAdd(pdev, &pdev->cache_image_lru, &internal->cache->lru_link);
-        internal->cache->image = NULL;
-    }
-
-    if (internal->image.bitmap.palette) {
-        QXLPalette *palette = (QXLPalette *)VA(pdev, internal->image.bitmap.palette,
-					       pdev->main_mem_slot);
-        ReleasePalette(pdev, CONTAINEROF(palette, InternalPalette, palette));
-    }
-
-    chunk_phys = ((QXLDataChunk *)(&internal->image.bitmap + 1))->next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_bits_pages--);
-
-    }
-
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_bits_pages--);
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-#ifndef _WIN64
-
-static _inline void RestoreFPU(PDev *pdev, UINT8 FPUSave[])
-{
-    void *align_addr =  (void *)ALIGN((size_t)(FPUSave), SSE_ALIGN);
-
-    _asm
-    {
-        mov esi, align_addr
-
-        movdqa xmm0, [esi]
-        movdqa xmm1, [esi + 16]
-        movdqa xmm2, [esi + 32]
-        movdqa xmm3, [esi + 48]
-    }
-}
-
-static _inline void SaveFPU(PDev *pdev, UINT8 FPUSave[])
-{
-    void *align_addr =  (void *)ALIGN((size_t)(FPUSave), SSE_ALIGN);
-
-    _asm
-    {
-        mov edi, align_addr
-    
-        movdqa [edi], xmm0
-        movdqa [edi + 16], xmm1
-        movdqa [edi + 32], xmm2
-        movdqa [edi + 48], xmm3
-    }
-}
-
-#endif
-
-static void FreeSurfaceImage(PDev *pdev, Resource *res)
-{
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-#define BITMAP_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
-
-static _inline Resource *GetBitmapImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
-                                        BOOL cache_me, LONG width, LONG height, UINT8 format,
-                                        UINT8 *src, UINT32 line_size, UINT32 key)
-{
-    Resource *image_res;
-    InternalImage *internal;
-    size_t alloc_size;
-    QXLDataChunk *chunk;
-    UINT8 *src_end;
-    UINT8 *dest;
-    UINT8 *dest_end;
-    UINT8 FPUSave[16 * 4 + 15];
-    BOOL use_sse = FALSE;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    ASSERT(pdev, width > 0 && height > 0);
-
-    ASSERT(pdev, BITS_BUF_MAX > line_size);
-    alloc_size = BITMAP_ALLOC_BASE + BITS_BUF_MAX - BITS_BUF_MAX % line_size;
-    alloc_size = MIN(BITMAP_ALLOC_BASE + height * line_size, alloc_size);
-    image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
-    ONDBG(pdev->num_bits_pages++);
-
-    image_res->refs = 1;
-    image_res->free = FreeBitmapImage;
-    RESOURCE_TYPE(image_res, RESOURCE_TYPE_BITMAP_IMAGE);
-
-    internal = (InternalImage *)image_res->res;
-    SetImageId(internal, cache_me, width, height, format, key);
-    internal->image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
-    chunk = (QXLDataChunk *)(&internal->image.bitmap + 1);
-    chunk->data_size = 0;
-    chunk->prev_chunk = 0;
-    chunk->next_chunk = 0;
-    internal->image.bitmap.data = PA(pdev, chunk, pdev->main_mem_slot);
-    internal->image.bitmap.flags = 0;
-    internal->image.descriptor.width = internal->image.bitmap.x = width;
-    internal->image.descriptor.height = internal->image.bitmap.y = height;
-    internal->image.bitmap.format = format;
-    internal->image.bitmap.stride = line_size;
-    src_end = src - surf->lDelta;
-    src += surf->lDelta * (height - 1);
-    dest = chunk->data;
-    dest_end = (UINT8 *)image_res + alloc_size;
-    alloc_size = height * line_size;
-
-#ifndef _WIN64
-    if (have_sse2 && alloc_size >= 1024) {
-        use_sse = TRUE;
-        SaveFPU(pdev, FPUSave);
-    }
-#endif
-    for (; src != src_end; src -= surf->lDelta, alloc_size -= line_size) {
-        PutBytesAlign(pdev, &chunk, &dest, &dest_end, src, line_size,
-                      &pdev->num_bits_pages, alloc_size, line_size, use_sse);
-    }
-#ifndef _WIN64
-    if (use_sse) {
-        RestoreFPU(pdev, FPUSave);
-    }
-#endif
-
-    GetPallette(pdev, &internal->image.bitmap, color_trans);
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-    return image_res;
-}
-
-#define ADAPTIVE_HASH
-
-static _inline UINT32 GetHash(UINT8 *src, INT32 width, INT32 height, UINT8 format, int high_bits_set,
-                              UINT32 line_size, LONG stride, XLATEOBJ *color_trans)
-{
-    UINT32 hash_value = IMAGE_HASH_INIT_VAL(width, height, format);
-    UINT8 *row_buf = src;
-    UINT8 last_byte = 0;
-    UINT8 reminder;
-    UINT32 i;
-    int row;
-
-    if (color_trans && color_trans->flXlate == XO_TABLE) {
-        hash_value = murmurhash2a(color_trans->pulXlate,
-                                  sizeof(*color_trans->pulXlate) * color_trans->cEntries,
-                                  hash_value);
-    }
-
-    if (format == SPICE_BITMAP_FMT_32BIT && stride == line_size) {
-        hash_value = murmurhash2ajump3((UINT32 *)row_buf, width * height, hash_value);
-    } else {
-        for (row = 0; row < height; row++) {
-    #ifdef ADAPTIVE_HASH
-            if (format ==  SPICE_BITMAP_FMT_32BIT) {
-                hash_value = murmurhash2ajump3((UINT32 *)row_buf, width, hash_value);
-            } else {
-                if (format == SPICE_BITMAP_FMT_4BIT_BE && (width & 0x1)) {
-                    last_byte = row_buf[line_size - 1] & 0xF0;
-                } else if (format == SPICE_BITMAP_FMT_1BIT_BE && (reminder = width & 0x7)) {
-                    last_byte = row_buf[line_size - 1] & ~((1 << (8 - reminder)) - 1);
-                }
-                if (last_byte) {
-                    hash_value = murmurhash2a(row_buf, line_size - 1, hash_value);
-                    hash_value = murmurhash2a(&last_byte, 1, hash_value);
-                } else {
-                    hash_value = murmurhash2a(row_buf, line_size, hash_value);
-                }
-            }
-    #else
-            hash_value = murmurhash2a(row_buf, line_size, hash_value);
-    #endif
-            row_buf += stride;
-        }
-    }
-    if (high_bits_set) {
-        hash_value ^= 1;
-    }
-    return hash_value;
-}
-
-static _inline UINT32 GetFormatLineSize(INT32 width, ULONG bitmap_format, UINT8 *format)
-{
-    switch (bitmap_format) {
-    case BMF_32BPP:
-        *format = SPICE_BITMAP_FMT_32BIT;
-        return width << 2;
-    case BMF_24BPP:
-        *format = SPICE_BITMAP_FMT_24BIT;
-        return width * 3;
-    case BMF_16BPP:
-        *format = SPICE_BITMAP_FMT_16BIT;
-        return width << 1;
-    case BMF_8BPP:
-        *format = SPICE_BITMAP_FMT_8BIT;
-        return width;
-    case BMF_4BPP:
-        *format = SPICE_BITMAP_FMT_4BIT_BE;
-        return ALIGN(width, 2) >> 1;
-    case BMF_1BPP:
-        *format = SPICE_BITMAP_FMT_1BIT_BE;
-        return ALIGN(width, 8) >> 3;
-    default:
-        return 0;
-    }
-}
-
-static BOOL CacheSizeTest(PDev *pdev, SURFOBJ *surf)
-{
-    BOOL ret = (UINT32)surf->sizlBitmap.cx * surf->sizlBitmap.cy <= pdev->max_bitmap_size;
-    if (!ret) {
-        DEBUG_PRINT((pdev, 1, "%s: cache size test failed x %d y %d max\n",
-                     __FUNCTION__,
-                     surf->sizlBitmap.cx,
-                     surf->sizlBitmap.cy,
-                     pdev->max_bitmap_size));
-    }
-    return ret;
-}
-
-static _inline UINT64 get_unique(SURFOBJ *surf, XLATEOBJ *color_trans)
-{
-    ULONG pallette_unique = color_trans ? color_trans->iUniq : 0;
-
-    // NOTE: GDI sometimes gives many instances of the exactly same SURFOBJ (hsurf & iUniq),
-    // but with (fjBitmap & BMF_DONTCACHE). This opposed to what documented in the MSDN.
-    if (!surf->iUniq || (surf->fjBitmap & BMF_DONTCACHE) || !pallette_unique) {
-        return 0;
-    } else {
-        return (surf->iUniq | ((UINT64)pallette_unique << 32));
-    }
-}
-
-BOOL QXLCheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans)
-{
-    CacheImage *cache_image;
-    UINT64 gdi_unique;
-    UINT32 key;
-    UINT8 format;
-
-    gdi_unique = get_unique(surf, color_trans);
-
-    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
-        return FALSE;
-    }
-
-    switch (surf->iBitmapFormat) {
-    case BMF_32BPP:
-        format = SPICE_BITMAP_FMT_32BIT;
-        break;
-    case BMF_24BPP:
-        format = SPICE_BITMAP_FMT_24BIT;
-        break;
-    case BMF_16BPP:
-        format = SPICE_BITMAP_FMT_16BIT;
-        break;
-    case BMF_8BPP:
-        format = SPICE_BITMAP_FMT_8BIT;
-        break;
-    case BMF_4BPP:
-        format = SPICE_BITMAP_FMT_4BIT_BE;
-        break;
-    case BMF_1BPP:
-        format = SPICE_BITMAP_FMT_1BIT_BE;
-    }
-
-
-    if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
-                                          surf->sizlBitmap.cx,
-                                          surf->sizlBitmap.cy))) {
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static CacheImage *GetCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans, int high_bits_set, UINT32 *hash_key)
-{
-    CacheImage *cache_image;
-    UINT64 gdi_unique;
-    UINT32 key;
-    UINT8 format;
-    UINT32 line_size;
-
-    gdi_unique = get_unique(surf, color_trans);
-
-    if (!(line_size = GetFormatLineSize(surf->sizlBitmap.cx, surf->iBitmapFormat, &format))) {
-        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
-        key = GetHash(surf->pvScan0, surf->sizlBitmap.cx, surf->sizlBitmap.cy, format,
-                      high_bits_set, line_size, surf->lDelta, color_trans);
-        ImageKeyPut(pdev, surf->hsurf, gdi_unique, key);
-        DEBUG_PRINT((pdev, 11, "%s: ImageKeyPut %u\n", __FUNCTION__, key));
-    } else {
-        DEBUG_PRINT((pdev, 11, "%s: ImageKeyGet %u\n", __FUNCTION__, key));
-    }
-
-    if (hash_key) {
-        *hash_key = key;
-    }
-
-    if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
-                                          surf->sizlBitmap.cx,
-                                          surf->sizlBitmap.cy))) {
-        cache_image->hits++;
-        DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
-                     key, cache_image->hits));
-        return cache_image;
-    }
-
-    if (CacheSizeTest(pdev, surf)) {
-        CacheImage *cache_image;
-        cache_image = AllocCacheImage(pdev);
-        ImageCacheRemove(pdev, cache_image);
-        cache_image->key = key;
-        cache_image->image = NULL;
-        cache_image->format = format;
-        cache_image->width = surf->sizlBitmap.cx;
-        cache_image->height = surf->sizlBitmap.cy;
-        ImageCacheAdd(pdev, cache_image);
-        RingAdd(pdev, &pdev->cache_image_lru, &cache_image->lru_link);
-        DEBUG_PRINT((pdev, 11, "%s: ImageCacheAdd %u\n", __FUNCTION__, key));
-    }
-    return NULL;
-}
-
-// TODO: reconsider
-static HSEMAPHORE image_id_sem = NULL;
-
-static _inline UINT32 get_image_serial()
-{
-    static UINT32 image_id = 0; // move to dev mem and use InterlockedIncrement
-    UINT32 ret = 0;
-
-    EngAcquireSemaphore(image_id_sem);
-    ret = ++image_id;
-    EngReleaseSemaphore(image_id_sem);
-    return ret;
-}
-
-static int rgb32_data_has_alpha(int width, int height, int stride,
-                                UINT8 *data, int *all_set_out)
-{
-    UINT32 *line, *end, alpha;
-    int has_alpha;
-
-    has_alpha = FALSE;
-    while (height-- > 0) {
-        line = (UINT32 *)data;
-        end = line + width;
-        data += stride;
-        while (line != end) {
-            alpha = *line & 0xff000000U;
-            if (alpha != 0) {
-                has_alpha = TRUE;
-                if (alpha != 0xff000000U) {
-                    *all_set_out = FALSE;
-                    return TRUE;
-                }
-            }
-            line++;
-        }
-    }
-
-    *all_set_out = has_alpha;
-    return has_alpha;
-}
-
-BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
-                  QXLRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
-                  INT32 *surface_dest)
-{
-    Resource *image_res;
-    InternalImage *internal;
-    CacheImage *cache_image;
-    UINT32 key;
-    UINT8 format;
-    UINT32 line_size;
-    UINT8 *src;
-    int high_bits_set;
-    INT32 width = area->right - area->left;
-    INT32 height = area->bottom - area->top;
-
-    ASSERT(pdev, !hash_key || use_cache);
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    if (surf->iType != STYPE_BITMAP) {
-        UINT32 alloc_size;
-
-        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
-
-        alloc_size = sizeof(Resource) + sizeof(InternalImage);
-        image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
-
-        ONDBG(pdev->num_bits_pages++);
-        image_res->refs = 1;
-        image_res->free = FreeSurfaceImage;
-        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
-
-        internal = (InternalImage *)image_res->res;
-
-        SetImageId(internal, FALSE, 0, 0, 0, 0);
-        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
-        internal->image.descriptor.width = 0;
-        internal->image.descriptor.height = 0;
-        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
-
-        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-
-        DrawableAddRes(pdev, drawable, image_res);
-
-        RELEASE_RES(pdev, image_res);
-
-        return TRUE;
-    }
-
-    if (area->left < 0 || area->right > surf->sizlBitmap.cx ||
-        area->top < 0 || area->bottom > surf->sizlBitmap.cy) {
-        DEBUG_PRINT((pdev, 0, "%s: bad dimensions\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    high_bits_set = FALSE;
-    if (surf->iBitmapFormat == BMF_32BPP) {
-        if (rgb32_data_has_alpha(width, height, surf->lDelta,
-                                 (UINT8 *)surf->pvScan0 + area->left * 4,
-                                 &high_bits_set) &&
-            !high_bits_set) {
-            return QXLGetAlphaBitmap(pdev, drawable, image_phys,
-                                     surf, area, surface_dest);
-        }
-    }
-
-    DEBUG_PRINT((pdev, 11, "%s: iUniq=%x DONTCACHE=%x w=%d h=%d cx=%d cy=%d "
-                 "hsurf=%x ctiUniq=%x XO_TABLE=%u format=%u\n", __FUNCTION__,
-                 surf->iUniq, surf->fjBitmap & BMF_DONTCACHE, width, height,
-                 surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
-                 color_trans ? color_trans->iUniq : 0,
-                 color_trans ? !!(color_trans->flXlate & XO_TABLE) : 0,
-                 surf->iBitmapFormat));
-
-    if (use_cache) {
-        cache_image = GetCacheImage(pdev, surf, color_trans, high_bits_set, hash_key);
-        if (cache_image && cache_image->image) {
-            DEBUG_PRINT((pdev, 11, "%s: cached image found %u\n", __FUNCTION__, cache_image->key));
-            internal = cache_image->image;
-            *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-            image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
-            DrawableAddRes(pdev, drawable, image_res);
-            return TRUE;
-        }
-    } else {
-        cache_image = NULL;
-    }
-
-    if (cache_image) {
-        key = cache_image->key;
-        width = surf->sizlBitmap.cx;
-        height = surf->sizlBitmap.cy;
-        src = surf->pvScan0;
-    } else {
-        int scan0_offset;
-        int dx;
-
-        key = get_image_serial();
-        switch (surf->iBitmapFormat) {
-        case BMF_32BPP:
-            dx = 0;
-            scan0_offset = area->left << 2;
-            break;
-        case BMF_24BPP:
-            dx = 0;
-            scan0_offset = area->left * 3;
-            break;
-        case BMF_16BPP:
-            dx = 0;
-            scan0_offset = area->left << 1;
-            break;
-        case BMF_8BPP:
-            dx = 0;
-            scan0_offset = area->left;
-            break;
-        case BMF_4BPP:
-            dx = area->left & 0x01;
-            scan0_offset = (area->left & ~0x01) >> 1;
-            break;
-        case BMF_1BPP:
-            dx = area->left & 0x07;
-            scan0_offset = (area->left & ~0x07) >> 3;
-            break;
-        default:
-            DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
-            return FALSE;
-        }
-        width = width + dx;
-        src = (UINT8 *)surf->pvScan0 + area->top * surf->lDelta + scan0_offset;
-
-        area->left = dx;
-        area->right = width;
-
-        area->top = 0;
-        area->bottom = height;
-    }
-
-    if (!(line_size = GetFormatLineSize(width, surf->iBitmapFormat, &format))) {
-        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (!(image_res = GetQuicImage(pdev, surf, color_trans, !!cache_image, width, height, format,
-                                   src, line_size, key))) {
-        image_res = GetBitmapImage(pdev, surf, color_trans, !!cache_image, width, height, format,
-                                   src, line_size, key);
-    }
-    internal = (InternalImage *)image_res->res;
-    if (high_bits_set) {
-        internal->image.descriptor.flags |= QXL_IMAGE_HIGH_BITS_SET;
-    }
-    if ((internal->cache = cache_image)) {
-        DEBUG_PRINT((pdev, 11, "%s: cache_me %u\n", __FUNCTION__, key));
-        cache_image->image = internal;
-        if (RingItemIsLinked(&cache_image->lru_link)) {
-            RingRemove(pdev, &cache_image->lru_link);
-        }
-    }
-    *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-    DrawableAddRes(pdev, drawable, image_res);
-    RELEASE_RES(pdev, image_res);
-    return TRUE;
-}
-
-BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys,
-                       SURFOBJ *surf, QXLRect *area, INT32 *surface_dest)
-{
-    Resource *image_res;
-    InternalImage *internal;
-    CacheImage *cache_image;
-    UINT64 gdi_unique;
-    UINT32 key;
-    UINT8 *src;
-    INT32 width = area->right - area->left;
-    INT32 height = area->bottom - area->top;
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    ASSERT(pdev, area->left >= 0 && area->right <= surf->sizlBitmap.cx &&
-           area->top >= 0 && area->bottom <= surf->sizlBitmap.cy);
-
-    DEBUG_PRINT((pdev, 11, "%s: iUniq=%x DONTCACHE=%x w=%d h=%d cx=%d cy=%d "
-                 "hsurf=%x format=%u\n", __FUNCTION__, surf->iUniq,
-                 surf->fjBitmap & BMF_DONTCACHE, width, height,
-                 surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
-                 surf->iBitmapFormat));
-
-    if (surf->iType != STYPE_BITMAP) {
-        UINT32 alloc_size;
-
-        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
-
-        alloc_size = sizeof(Resource) + sizeof(InternalImage);
-        image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
-
-        ONDBG(pdev->num_bits_pages++);
-        image_res->refs = 1;
-        image_res->free = FreeSurfaceImage;
-        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
-
-        internal = (InternalImage *)image_res->res;
-
-        SetImageId(internal, FALSE, 0, 0, 0, 0);
-        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
-        internal->image.descriptor.width = 0;
-        internal->image.descriptor.height = 0;
-        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
-
-        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-        DrawableAddRes(pdev, drawable, image_res);
-        RELEASE_RES(pdev, image_res);
-
-        return TRUE;
-    }
-
-    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
-
-    //todo: use GetCacheImage
-
-    // NOTE: Same BMF_DONTCACHE issue as in QXLGetBitmap
-    if (!surf->iUniq || (surf->fjBitmap & BMF_DONTCACHE)) {
-        gdi_unique = 0;
-    } else {
-        gdi_unique = surf->iUniq;
-    }
-
-    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
-        key = GetHash(surf->pvScan0, surf->sizlBitmap.cx, surf->sizlBitmap.cy, SPICE_BITMAP_FMT_RGBA,
-                      FALSE, surf->sizlBitmap.cx << 2, surf->lDelta, NULL);
-        ImageKeyPut(pdev, surf->hsurf, gdi_unique, key);
-        DEBUG_PRINT((pdev, 11, "%s: ImageKeyPut %u\n", __FUNCTION__, key));
-    } else {
-        DEBUG_PRINT((pdev, 11, "%s: ImageKeyGet %u\n", __FUNCTION__, key));
-    }
-
-    if (cache_image = ImageCacheGetByKey(pdev, key, TRUE, SPICE_BITMAP_FMT_RGBA,
-                                         surf->sizlBitmap.cx, surf->sizlBitmap.cy)) {
-        DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
-                     key, cache_image->hits));
-        cache_image->hits++;
-        if (internal = cache_image->image) {
-            DEBUG_PRINT((pdev, 11, "%s: cached image found %u\n", __FUNCTION__, key));
-            *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-            image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
-            DrawableAddRes(pdev, drawable, image_res);
-            return TRUE;
-        }
-    } else if (CacheSizeTest(pdev, surf)) {
-        CacheImage *cache_image;
-        cache_image = AllocCacheImage(pdev);
-        ImageCacheRemove(pdev, cache_image);
-        cache_image->key = key;
-        cache_image->image = NULL;
-        cache_image->format = SPICE_BITMAP_FMT_RGBA;
-        cache_image->width = surf->sizlBitmap.cx;
-        cache_image->height = surf->sizlBitmap.cy;
-        ImageCacheAdd(pdev, cache_image);
-        RingAdd(pdev, &pdev->cache_image_lru, &cache_image->lru_link);
-        DEBUG_PRINT((pdev, 11, "%s: ImageCacheAdd %u\n", __FUNCTION__, key));
-    }
-
-    if (cache_image) {
-        width = surf->sizlBitmap.cx;
-        height = surf->sizlBitmap.cy;
-        src = surf->pvScan0;
-    } else {
-        src = (UINT8 *)surf->pvScan0 + area->top * surf->lDelta + (area->left << 2);
-        area->left = 0;
-        area->right = width;
-        area->top = 0;
-        area->bottom = height;
-    }
-
-    if (!(image_res = GetQuicImage(pdev, surf, NULL, !!cache_image, width, height,
-                                   SPICE_BITMAP_FMT_RGBA, src, width << 2, key))) {
-        image_res = GetBitmapImage(pdev, surf, NULL, !!cache_image, width, height,
-                                   SPICE_BITMAP_FMT_RGBA, src, width << 2, key);
-    }
-    internal = (InternalImage *)image_res->res;
-    if ((internal->cache = cache_image)) {
-        DEBUG_PRINT((pdev, 11, "%s: cache_me %u\n", __FUNCTION__, key));
-        cache_image->image = internal;
-        if (RingItemIsLinked(&cache_image->lru_link)) {
-            RingRemove(pdev, &cache_image->lru_link);
-        }
-    }
-    *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-    DrawableAddRes(pdev, drawable, image_res);
-    RELEASE_RES(pdev, image_res);
-    return TRUE;
-}
-
-BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys)
-{
-    InternalImage *internal;
-    CacheImage *cache_image;
-    Resource *image_res;
-
-    if ((cache_image = ImageCacheGetByKey(pdev, hash_key, FALSE, 0, 0, 0)) &&
-        (internal = cache_image->image)) {
-        cache_image->hits++;
-        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
-        image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
-        DrawableAddRes(pdev, drawable, image_res);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, QXLQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
-                BOOL invers, LONG width, LONG height, INT32 *surface_dest)
-{
-    QXLRect area;
-
-    if (!mask) {
-        qxl_mask->bitmap = 0;
-        return TRUE;
-    }
-
-    ASSERT(pdev, pos && qxl_mask && drawable);
-    if (mask->iBitmapFormat != BMF_1BPP) {
-        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    qxl_mask->flags = invers ? SPICE_MASK_FLAGS_INVERS : 0;
-
-    area.left = pos->x;
-    area.right = area.left + width;
-    area.top = pos->y;
-    area.bottom = area.top + height;
-
-    if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE,
-                     surface_dest)) {
-        qxl_mask->pos.x = area.left;
-        qxl_mask->pos.y = area.top;
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static void FreeBuf(PDev *pdev, Resource *res)
-{
-    ONDBG(pdev->num_buf_pages--);
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-}
-
-UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size)
-{
-    Resource *buf_res;
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    if (size > PAGE_SIZE - sizeof(Resource)) {
-        DEBUG_PRINT((pdev, 0, "%s: size err\n", __FUNCTION__));
-        return NULL;
-    }
-
-    buf_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + size);
-    ONDBG(pdev->num_buf_pages++);
-    buf_res->refs = 1;
-    buf_res->free = FreeBuf;
-    RESOURCE_TYPE(buf_res, RESOURCE_TYPE_BUF);
-
-    *buf_phys = PA(pdev, buf_res->res, pdev->main_mem_slot);
-    DrawableAddRes(pdev, drawable, buf_res);
-    RELEASE_RES(pdev, buf_res);
-    return buf_res->res;
-}
-
-#ifdef UPDATE_CMD
-void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
-{
-    QXLCommand *cmd;
-    QXLOutput *output;
-    QXLUpdateCmd *updat_cmd;
-
-    DEBUG_PRINT((pdev, 12, "%s UPDATE_CMD\n", __FUNCTION__));
-
-    output = (QXLOutput *)AllocMem(pdev, sizeof(QXLOutput) + sizeof(QXLUpdateCmd));
-    RESOURCE_TYPE(output, RESOURCE_TYPE_UPDATE);
-    output->num_res = 0;
-    updat_cmd = (QXLUpdateCmd *)output->data;
-    updat_cmd->release_info.id = (UINT64)output;
-    ONDBG(pdev->num_outputs++); //todo: atomic
-
-    CopyRect(&updat_cmd->area, area);
-    updat_cmd->update_id = ++pdev->update_id;
-    updat_cmd->surface_id = surface_id;
-
-    EngAcquireSemaphore(pdev->cmd_sem);
-    WaitForCmdRing(pdev);
-    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
-    cmd->type = QXL_CMD_UPDATE;
-    cmd->data = PA(pdev, updat_cmd, pdev->main_mem_slot);
-    PUSH_CMD(pdev);
-    EngReleaseSemaphore(pdev->cmd_sem);
-    do {
-#ifdef DBG
-        {
-            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
-            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
-            WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
-            if (*pdev->dev_update_id != pdev->update_id) {
-                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
-            }
-        }
-#else
-        WAIT_FOR_EVENT(pdev, pdev->display_event, NULL);
-#endif // DEBUG
-        mb();
-    } while (*pdev->dev_update_id != pdev->update_id);
-}
-
-#else
-
-void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
-{
-    DEBUG_PRINT((pdev, 12, "%s IO\n", __FUNCTION__));
-    CopyRect(pdev->update_area, area);
-    *pdev->update_surface = surface_id;
-    async_io(pdev, ASYNCABLE_UPDATE_AREA, 0);
-}
-
-#endif
-
-static _inline void add_rast_glyphs(PDev *pdev, QXLString *str, ULONG count, GLYPHPOS *glyps,
-                                    QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
-                                    UINT8 **end_ptr, int bpp, POINTL *delta, QXLPoint **str_pos)
-{
-    GLYPHPOS *glyps_end = glyps + count;
-    QXLDataChunk *chunk = *chunk_ptr;
-    UINT8 *now = *now_ptr;
-    UINT8 *end = *end_ptr;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    for (; glyps < glyps_end; glyps++) {
-        QXLRasterGlyph *glyph;
-        UINT8 *line;
-        UINT8 *end_line;
-        UINT32 stride;
-
-        if (end - now < sizeof(*glyph)) {
-            NEW_DATA_CHUNK(&pdev->num_glyphs_pages, PAGE_SIZE);
-        }
-
-        glyph = (QXLRasterGlyph *)now;
-        if (delta) {
-            if (*str_pos) {
-                glyph->render_pos.x = (*str_pos)->x + delta->x;
-                glyph->render_pos.y = (*str_pos)->y + delta->y;
-            } else {
-                glyph->render_pos.x = glyps->ptl.x;
-                glyph->render_pos.y = glyps->ptl.y;
-            }
-            *str_pos = (QXLPoint *)&glyph->render_pos;
-        } else {
-            glyph->render_pos.x = glyps->ptl.x;
-            glyph->render_pos.y = glyps->ptl.y;
-        }
-        glyph->glyph_origin.x = glyps->pgdf->pgb->ptlOrigin.x;
-        glyph->glyph_origin.y = glyps->pgdf->pgb->ptlOrigin.y;
-        glyph->width = (UINT16)glyps->pgdf->pgb->sizlBitmap.cx;
-        glyph->height = (UINT16)glyps->pgdf->pgb->sizlBitmap.cy;
-        now += sizeof(*glyph);
-        chunk->data_size += sizeof(*glyph);
-        str->data_size += sizeof(*glyph);
-        if (!glyph->height) {
-            continue;
-        }
-
-        stride = ALIGN(glyph->width * bpp, 8) >> 3;
-        end_line = (UINT8 *)glyps->pgdf->pgb->aj - stride;
-        line = (UINT8 *)glyps->pgdf->pgb->aj + stride * (glyph->height - 1);
-
-        for (; line != end_line; line -= stride) {
-            UINT8 *bits_pos = line;
-            UINT8 *bits_end = bits_pos + stride;
-
-            for (; bits_pos != bits_end; bits_pos++) {
-                UINT8 val;
-                int i;
-                if (end - now < sizeof(*bits_pos)) {
-                    NEW_DATA_CHUNK(&pdev->num_glyphs_pages, PAGE_SIZE);
-                }
-                *(UINT8 *)now = *bits_pos;
-                now += sizeof(*bits_pos);
-                chunk->data_size += sizeof(*bits_pos);
-                str->data_size += sizeof(*bits_pos);
-            }
-        }
-    }
-    *chunk_ptr = chunk;
-    *now_ptr = now;
-    *end_ptr = end;
-    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
-}
-static _inline BOOL add_glyphs(PDev *pdev, QXLString *str, ULONG count, GLYPHPOS *glyps,
-                               QXLDataChunk **chunk, UINT8 **now, UINT8 **end, POINTL *delta,
-                               QXLPoint  **str_pos)
-{
-    if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
-        add_rast_glyphs(pdev, str, count, glyps, chunk, now, end, 1, delta, str_pos);
-    } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
-        add_rast_glyphs(pdev, str, count, glyps, chunk, now, end, 4, delta, str_pos);
-    }
-    return TRUE;
-}
-
-static void FreeSring(PDev *pdev, Resource *res)
-{
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    chunk_phys = ((QXLString *)res->res)->chunk.next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_glyphs_pages--);
-    }
-
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_glyphs_pages--);
-
-    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
-}
-
-
-#define TEXT_ALLOC_SIZE sizeof(Resource) + sizeof(QXLString) + 512
-
-BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str)
-{
-    Resource *str_res;
-    QXLString *qxl_str;
-    QXLDataChunk *chunk;
-    UINT8 *now;
-    UINT8 *end;
-    BOOL more;
-    static int id_QXLGetStr = 0;
-    POINTL  delta;
-    POINTL  *delta_ptr;
-    QXLPoint  *str_pos;
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-
-    str_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, TEXT_ALLOC_SIZE);
-    ONDBG(pdev->num_glyphs_pages++);
-    str_res->refs = 1;
-    str_res->free = FreeSring;
-    RESOURCE_TYPE(str_res, RESOURCE_TYPE_SRING);
-
-    qxl_str = (QXLString *)str_res->res;
-    qxl_str->data_size = 0;
-    qxl_str->length = (UINT16)str->cGlyphs;
-    qxl_str->flags = 0;
-
-    if (font->flFontType & FO_TYPE_RASTER) {
-        qxl_str->flags = (font->flFontType & FO_GRAY16) ?   SPICE_STRING_FLAGS_RASTER_A4 :
-                         SPICE_STRING_FLAGS_RASTER_A1;
-    }
-
-    chunk = &qxl_str->chunk;
-    chunk->data_size = 0;
-    chunk->prev_chunk = 0;
-    chunk->next_chunk = 0;
-
-    now = chunk->data;
-    end = (UINT8 *)str_res + TEXT_ALLOC_SIZE;
-
-    if (str->ulCharInc) {
-        str_pos = NULL;
-        if (str->flAccel & SO_VERTICAL) {
-            delta.x = 0;
-            delta.y = (str->flAccel & SO_REVERSED) ? -(LONG)str->ulCharInc : str->ulCharInc;
-        } else {
-            delta.x = (str->flAccel & SO_REVERSED) ? -(LONG)str->ulCharInc : str->ulCharInc;
-            delta.y = 0;
-        }
-        delta_ptr = δ
-    } else {
-        delta_ptr = NULL;
-    }
-
-    STROBJ_vEnumStart(str);
-
-    do {
-        ULONG count;
-        GLYPHPOS *glyps;
-
-        if (str->pgp) {
-            count = str->cGlyphs;
-            glyps = str->pgp;
-            more = FALSE;
-        } else {
-            more = STROBJ_bEnum(str, &count, &glyps);
-
-            if (more == DDI_ERROR) {
-                goto error;
-            }
-        }
-        if (!add_glyphs(pdev, qxl_str, count, glyps, &chunk, &now, &end, delta_ptr, &str_pos)) {
-            goto error;
-        }
-
-    } while (more);
-
-    *str_phys = PA(pdev, str_res->res, pdev->main_mem_slot);
-    DrawableAddRes(pdev, drawable, str_res);
-    RELEASE_RES(pdev, str_res);
-
-    DEBUG_PRINT((pdev, 10, "%s: done size %u\n", __FUNCTION__, qxl_str->data_size));
-    return TRUE;
-
-    error:
-    FreeSring(pdev, str_res);
-    DEBUG_PRINT((pdev, 10, "%s: error\n", __FUNCTION__));
-    return FALSE;
-}
-
-QXLCursorCmd *CursorCmd(PDev *pdev)
-{
-    QXLCursorCmd *cursor_cmd;
-    QXLOutput *output;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLCursorCmd));
-    output->num_res = 0;
-    RESOURCE_TYPE(output, RESOURCE_TYPE_CURSOR);
-    cursor_cmd = (QXLCursorCmd *)output->data;
-    cursor_cmd->release_info.id = (UINT64)output;
-    ONDBG(pdev->num_outputs++); //todo: atomic
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-    return cursor_cmd;
-}
-
-void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd)
-{
-    QXLCommand *cmd;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    EngAcquireSemaphore(pdev->cursor_sem);
-    WaitForCursorRing(pdev);
-    cmd = SPICE_RING_PROD_ITEM(pdev->cursor_ring);
-    cmd->type = QXL_CMD_CURSOR;
-    cmd->data = PA(pdev, cursor_cmd, pdev->main_mem_slot);
-    PUSH_CURSOR_CMD(pdev);
-    EngReleaseSemaphore(pdev->cursor_sem);
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-}
-
-typedef struct InternalCursor {
-    struct InternalCursor *next;
-    RingItem lru_link;
-    HSURF   hsurf;
-    ULONG   unique;
-    QXLCursor cursor;
-} InternalCursor;
-
-
-#define CURSOR_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & CURSOR_HASH_NASKE)
-
-static void CursorCacheRemove(PDev *pdev, InternalCursor *cursor)
-{
-    InternalCursor **internal;
-    BOOL found = FALSE;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    ASSERT(pdev, cursor->unique);
-    internal = &pdev->cursor_cache[CURSOR_HASH_VAL(cursor->hsurf)];
-
-    while (*internal) {
-        if ((*internal)->hsurf == cursor->hsurf) {
-            if ((*internal) == cursor) {
-                *internal = cursor->next;
-                found = TRUE;
-                break;
-            }
-            DEBUG_PRINT((pdev, 0, "%s: unexpected\n", __FUNCTION__));
-        }
-        internal = &(*internal)->next;
-    }
-
-    RingRemove(pdev, &cursor->lru_link);
-    RELEASE_RES(pdev, (Resource *)((UINT8 *)cursor - sizeof(Resource)));
-    pdev->num_cursors--;
-
-    if (!found) {
-        DEBUG_PRINT((pdev, 0, "%s: Error: cursor 0x%x isn't in cache \n", __FUNCTION__, cursor));
-        ASSERT(pdev, FALSE);
-    } else {
-        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
-    }
-
-}
-
-static void CursorCacheClear(PDev *pdev)
-{
-    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
-    while (pdev->num_cursors) {
-        ASSERT(pdev, RingGetTail(pdev, &pdev->cursors_lru));
-        CursorCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->cursors_lru),
-                                            InternalCursor, lru_link));
-    }
-}
-
-static void CursorCacheAdd(PDev *pdev, InternalCursor *cursor)
-{
-    int key;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-
-    if (!cursor->unique) {
-        return;
-    }
-
-    if (pdev->num_cursors == CURSOR_CACHE_SIZE) {
-        ASSERT(pdev, RingGetTail(pdev, &pdev->cursors_lru));
-        CursorCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->cursors_lru),
-                                            InternalCursor, lru_link));
-    }
-
-    key = CURSOR_HASH_VAL(cursor->hsurf);
-    cursor->next = pdev->cursor_cache[key];
-    pdev->cursor_cache[key] = cursor;
-
-    RingAdd(pdev, &pdev->cursors_lru, &cursor->lru_link);
-    GET_RES((Resource *)((UINT8 *)cursor - sizeof(Resource)));
-    pdev->num_cursors++;
-}
-
-static InternalCursor *CursorCacheGet(PDev *pdev, HSURF hsurf, UINT32 unique)
-{
-    InternalCursor **internal;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    if (!unique) {
-        return NULL;
-    }
-
-    internal = &pdev->cursor_cache[CURSOR_HASH_VAL(hsurf)];
-    while (*internal) {
-        InternalCursor *now = *internal;
-        if (now->hsurf == hsurf) {
-            if (now->unique == unique) {
-                RingRemove(pdev, &now->lru_link);
-                RingAdd(pdev, &pdev->cursors_lru, &now->lru_link);
-                return now;
-            }
-            CursorCacheRemove(pdev, now);
-            break;
-        }
-        internal = &now->next;
-    }
-    return NULL;
-}
-
-static void FreeCursor(PDev *pdev, Resource *res)
-{
-    QXLPHYSICAL chunk_phys;
-
-    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
-    chunk_phys = ((InternalCursor *)res->res)->cursor.chunk.next_chunk;
-    while (chunk_phys) {
-        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
-        chunk_phys = chunk->next_chunk;
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
-        ONDBG(pdev->num_cursor_pages--);
-    }
-
-    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
-    ONDBG(pdev->num_cursor_pages--);
-
-    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
-}
-
-
-typedef struct NewCursorInfo {
-    QXLCursor *cursor;
-    QXLDataChunk *chunk;
-    UINT8 *now;
-    UINT8 *end;
-} NewCursorInfo;
-
-#define CURSOR_ALLOC_SIZE (PAGE_SIZE << 1)
-
-static BOOL GetCursorCommon(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
-                            UINT16 type, NewCursorInfo *info, BOOL *in_cach)
-{
-    InternalCursor *internal;
-    QXLCursor *cursor;
-    Resource *res;
-    ULONG unique;
-    UINT8 *src;
-    UINT8 *src_end;
-    int line_size;
-    HSURF bitmap = 0;
-    SURFOBJ *local_surf = surf;
-
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    *in_cach = FALSE;
-    unique = (surf->fjBitmap & BMF_DONTCACHE) ? 0 : surf->iUniq;
-
-    if ((internal = CursorCacheGet(pdev, surf->hsurf, unique))) {
-        res = (Resource *)((UINT8 *)internal - sizeof(Resource));
-        CursorCmdAddRes(pdev, cmd, res);
-        cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
-        *in_cach = TRUE;
-        return TRUE;
-    }
-
-    if (surf->iType != STYPE_BITMAP) {
-        RECTL dest_rect;
-        POINTL src_pos;
-        ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP || surf->iBitmapFormat == BMF_16BPP);
-
-        /* copying the surface to a bitmap */
-
-        bitmap = (HSURF)EngCreateBitmap(surf->sizlBitmap, surf->lDelta, surf->iBitmapFormat,
-                                        0, NULL);
-        if (!bitmap) {
-            DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
-            return FALSE;
-        }
-
-        if (!EngAssociateSurface(bitmap, pdev->eng, 0)) {
-            DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
-            goto error;
-        }
-
-        if (!(local_surf = EngLockSurface(bitmap))) {
-            DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__));
-            goto error;
-        }
-
-        dest_rect.top = 0;
-        dest_rect.left = 0;
-        dest_rect.bottom = surf->sizlBitmap.cy;
-        dest_rect.right = surf->sizlBitmap.cx;
-
-        src_pos.x = 0;
-        src_pos.y = 0;
-            
-        if (!BitBltFromDev(pdev, surf, local_surf, NULL, NULL, NULL, &dest_rect, src_pos,
-                           NULL, NULL, NULL, 0xcccc)) {
-            goto error;
-        }
-    }
-
-    ASSERT(pdev, sizeof(Resource) + sizeof(InternalCursor) < CURSOR_ALLOC_SIZE);
-    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, CURSOR_ALLOC_SIZE);
-    ONDBG(pdev->num_cursor_pages++);
-    res->refs = 1;
-    res->free = FreeCursor;
-    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
-
-    internal = (InternalCursor *)res->res;
-    internal->hsurf = surf->hsurf;
-    internal->unique = unique;
-    RingItemInit(&internal->lru_link);
-
-    cursor = info->cursor = &internal->cursor;
-    cursor->header.type = type;
-    cursor->header.unique = unique ? ++pdev->last_cursor_id : 0;
-    cursor->header.width = (UINT16)local_surf->sizlBitmap.cx;
-    cursor->header.height = (type == SPICE_CURSOR_TYPE_MONO) ? (UINT16)local_surf->sizlBitmap.cy >> 1 :
-                            (UINT16)local_surf->sizlBitmap.cy;
-    cursor->header.hot_spot_x = (UINT16)hot_x;
-    cursor->header.hot_spot_y = (UINT16)hot_y;
-
-    cursor->data_size = 0;
-
-    info->chunk = &cursor->chunk;
-    info->chunk->data_size = 0;
-    info->chunk->prev_chunk = 0;
-    info->chunk->next_chunk = 0;
-
-    info->now = info->chunk->data;
-    info->end = (UINT8 *)res + CURSOR_ALLOC_SIZE;
-
-    switch (type) {
-    case SPICE_CURSOR_TYPE_ALPHA:
-    case SPICE_CURSOR_TYPE_COLOR32:
-        line_size = cursor->header.width << 2;
-        break;
-    case SPICE_CURSOR_TYPE_MONO:
-        line_size = ALIGN(cursor->header.width, 8) >> 3;
-        break;
-    case SPICE_CURSOR_TYPE_COLOR4:
-        line_size = ALIGN(cursor->header.width, 2) >> 1;
-        break;
-    case SPICE_CURSOR_TYPE_COLOR8:
-        line_size = cursor->header.width;
-        break;
-    case SPICE_CURSOR_TYPE_COLOR16:
-        line_size = cursor->header.width << 1;
-        break;
-    case SPICE_CURSOR_TYPE_COLOR24:
-        line_size = cursor->header.width * 3;
-        break;
-    }
-
-    cursor->data_size = line_size * local_surf->sizlBitmap.cy;
-    src = local_surf->pvScan0;
-    src_end = src + (local_surf->lDelta * local_surf->sizlBitmap.cy);
-    for (; src != src_end; src += local_surf->lDelta) {
-        PutBytes(pdev, &info->chunk, &info->now, &info->end, src, line_size,
-                 &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-    }
-
-    CursorCacheAdd(pdev, internal);
-    CursorCmdAddRes(pdev, cmd, res);
-    RELEASE_RES(pdev, res);
-    cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
-    DEBUG_PRINT((pdev, 11, "%s: done, data_size %u\n", __FUNCTION__, cursor->data_size));
-
-    if (local_surf != surf) {
-        EngUnlockSurface(local_surf);
-        EngDeleteSurface(bitmap);
-    }
-
-    return TRUE;
-error:
-    if (bitmap) {
-        ASSERT(pdev, local_surf != surf);
-        EngDeleteSurface(bitmap);
-    }
-
-    return FALSE;
-}
-
-BOOL GetAlphaCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf)
-{
-    NewCursorInfo info;
-    BOOL ret;
-    BOOL in_cache;
-
-    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP);
-    ASSERT(pdev, surf->sizlBitmap.cx > 0 && surf->sizlBitmap.cy > 0);
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ret = GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, SPICE_CURSOR_TYPE_ALPHA, &info, &in_cache);
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-    return ret;
-}
-
-BOOL GetMonoCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf)
-{
-    NewCursorInfo info;
-    BOOL ret;
-    BOOL in_cache;
-
-    ASSERT(pdev, surf->iBitmapFormat == BMF_1BPP);
-    ASSERT(pdev, surf->sizlBitmap.cy > 0 && (surf->sizlBitmap.cy & 1) == 0);
-    ASSERT(pdev, surf->sizlBitmap.cx > 0);
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    ret = GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, SPICE_CURSOR_TYPE_MONO, &info, &in_cache);
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-    return ret;
-}
-
-BOOL GetColorCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
-                    SURFOBJ *mask, XLATEOBJ *color_trans)
-{
-    NewCursorInfo info;
-    UINT16 type;
-    BOOL in_cache;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    ASSERT(pdev, surf && mask);
-    ASSERT(pdev, surf->sizlBitmap.cx > 0 && surf->sizlBitmap.cy);
-
-    if ( mask->sizlBitmap.cx != surf->sizlBitmap.cx ||
-         mask->sizlBitmap.cy != surf->sizlBitmap.cy * 2 ) {
-        DEBUG_PRINT((pdev, 0, "%s: err mask size, surf(%d, %d) mask(%d, %d)\n",
-                     __FUNCTION__,
-                     surf->sizlBitmap.cx,
-                     surf->sizlBitmap.cy,
-                     mask->sizlBitmap.cx,
-                     mask->sizlBitmap.cy));
-        return FALSE;
-    }
-
-    switch (surf->iBitmapFormat) {
-    case BMF_32BPP:
-        type = SPICE_CURSOR_TYPE_COLOR32;
-        break;
-    case BMF_24BPP:
-        type = SPICE_CURSOR_TYPE_COLOR24;
-        break;
-    case BMF_16BPP:
-        type = SPICE_CURSOR_TYPE_COLOR16;
-        break;
-    case BMF_8BPP:
-        type = SPICE_CURSOR_TYPE_COLOR8;
-        break;
-    case BMF_4BPP:
-        type = SPICE_CURSOR_TYPE_COLOR4;
-        break;
-    default:
-        DEBUG_PRINT((pdev, 0, "%s: unexpected format\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (!GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, type, &info, &in_cache)) {
-        return FALSE;
-    }
-
-    if (!in_cache) {
-        int line_size;
-        UINT8 *src;
-        UINT8 *src_end;
-
-        if (type == SPICE_CURSOR_TYPE_COLOR8) {
-
-            DEBUG_PRINT((pdev, 8, "%s: SPICE_CURSOR_TYPE_COLOR8\n", __FUNCTION__));
-            ASSERT(pdev, color_trans);
-            ASSERT(pdev, color_trans->pulXlate);
-            ASSERT(pdev, color_trans->flXlate & XO_TABLE);
-            ASSERT(pdev, color_trans->cEntries == 256);
-
-            if (pdev->bitmap_format == BMF_32BPP) {
-                PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)color_trans->pulXlate,
-                         256 << 2, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-            } else {
-                int i;
-
-                for (i = 0; i < 256; i++) {
-                    UINT32 ent = _16bppTo32bpp(color_trans->pulXlate[i]);
-                    PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)&ent,
-                             4, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-                }
-            }
-            info.cursor->data_size += 256 << 2;
-        } else if (type == SPICE_CURSOR_TYPE_COLOR4) {
-
-            ASSERT(pdev, color_trans);
-            ASSERT(pdev, color_trans->pulXlate);
-            ASSERT(pdev, color_trans->flXlate & XO_TABLE);
-            ASSERT(pdev, color_trans->cEntries == 16);
-
-            if (pdev->bitmap_format == BMF_32BPP) {
-                PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)color_trans->pulXlate,
-                         16 << 2, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-            } else {
-                int i;
-
-                for (i = 0; i < 16; i++) {
-                    UINT32 ent = _16bppTo32bpp(color_trans->pulXlate[i]);
-                    PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)&ent,
-                             4, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-                }
-            }
-            info.cursor->data_size += 16 << 2;
-        }
-
-        ASSERT(pdev, mask->iBitmapFormat == BMF_1BPP);
-        ASSERT(pdev, mask->iType == STYPE_BITMAP);
-
-        line_size = ALIGN(mask->sizlBitmap.cx, 8) >> 3;
-        info.cursor->data_size += line_size * surf->sizlBitmap.cy;
-        src = mask->pvScan0;
-        src_end = src + (mask->lDelta * surf->sizlBitmap.cy);
-
-        for (; src != src_end; src += mask->lDelta) {
-            PutBytes(pdev, &info.chunk, &info.now, &info.end, src, line_size,
-                     &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
-        }
-    }
-
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd)
-{
-    Resource *res;
-    InternalCursor *internal;
-    QXLCursor *cursor;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, sizeof(Resource) + sizeof(InternalCursor) < PAGE_SIZE);
-
-    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + sizeof(InternalCursor));
-    ONDBG(pdev->num_cursor_pages++);
-    res->refs = 1;
-    res->free = FreeCursor;
-    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
-
-    internal = (InternalCursor *)res->res;
-    internal->hsurf = NULL;
-    internal->unique = 0;
-    RingItemInit(&internal->lru_link);
-
-    cursor = &internal->cursor;
-    cursor->header.type = SPICE_CURSOR_TYPE_MONO;
-    cursor->header.unique = 0;
-    cursor->header.width = 0;
-    cursor->header.height = 0;
-    cursor->header.hot_spot_x = 0;
-    cursor->header.hot_spot_y = 0;
-    cursor->data_size = 0;
-    cursor->chunk.data_size = 0;
-
-    CursorCmdAddRes(pdev, cmd, res);
-    RELEASE_RES(pdev, res);
-    cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
-
-    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-void ReleaseCacheDeviceMemoryResources(PDev *pdev)
-{
-    DEBUG_PRINT((pdev, 0, "%s \n", __FUNCTION__));
-    PaletteCacheClear(pdev);
-    CursorCacheClear(pdev);
-}
-
-static void quic_usr_error(QuicUsrContext *usr, const char *format, ...)
-{
-    QuicData *quic_data = (QuicData *)usr;
-    va_list ap;
-
-    va_start(ap, format);
-    DebugPrintV(quic_data->pdev, format, ap);
-    va_end(ap);
-    EngDebugBreak();
-}
-
-static void quic_usr_warn(QuicUsrContext *usr, const char *format, ...)
-{
-    QuicData *quic_data = (QuicData *)usr;
-    va_list ap;
-
-    va_start(ap, format);
-    DebugPrintV(quic_data->pdev, format, ap);
-    va_end(ap);
-}
-
-static void *quic_usr_malloc(QuicUsrContext *usr, int size)
-{
-    return EngAllocMem(0, size, ALLOC_TAG);
-}
-
-static void quic_usr_free(QuicUsrContext *usr, void *ptr)
-{
-    EngFreeMem(ptr);
-}
-
-BOOL ResInit(PDev *pdev)
-{
-    QuicData *usr_data;
-
-    if (!(usr_data = EngAllocMem(FL_ZERO_MEMORY, sizeof(QuicData), ALLOC_TAG))) {
-        return FALSE;
-    }
-    usr_data->user.error = quic_usr_error;
-    usr_data->user.warn = quic_usr_warn;
-    usr_data->user.info = quic_usr_warn;
-    usr_data->user.malloc = quic_usr_malloc;
-    usr_data->user.free = quic_usr_free;
-    usr_data->user.more_space = quic_usr_more_space;
-    usr_data->user.more_lines = quic_usr_more_lines;
-    usr_data->pdev = pdev;
-    if (!(usr_data->quic = quic_create(&usr_data->user))) {
-        EngFreeMem(usr_data);
-        return FALSE;
-    }
-    pdev->quic_data = usr_data;
-    pdev->quic_data_sem = EngCreateSemaphore();
-    if (!pdev->quic_data_sem) {
-        PANIC(pdev, "quic_data_sem creation failed\n");
-    }
-    pdev->io_sem = EngCreateSemaphore();
-    if (!pdev->io_sem) {
-        PANIC(pdev, "io_sem creation failed\n");
-    }
-
-    return TRUE;
-}
-
-void ResDestroy(PDev *pdev)
-{
-    QuicData *usr_data = pdev->quic_data;
-    quic_destroy(usr_data->quic);
-    EngDeleteSemaphore(pdev->quic_data_sem);
-    EngFreeMem(usr_data);
-}
-
-void ResInitGlobals()
-{
-    image_id_sem = EngCreateSemaphore();
-    if (!image_id_sem) {
-        EngDebugBreak();
-    }
-    quic_init();
-}
-
-void ResDestroyGlobals()
-{
-    EngDeleteSemaphore(image_id_sem);
-    image_id_sem = NULL;
-}
-
-#ifndef _WIN64
-
-void CheckAndSetSSE2()
-{
-    _asm
-    {
-        mov eax, 0x0000001
-        cpuid
-        and edx, 0x4000000
-        mov have_sse2, edx
-    }
-
-    if (have_sse2) {
-        have_sse2 = TRUE;
-    }
-}
-
-#endif
diff --git a/display/res.h b/display/res.h
deleted file mode 100644
index d69986e..0000000
--- a/display/res.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef _H_RES
-#define _H_RES
-
-#include "qxldd.h"
-
-UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id);
-
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id);
-void PushDrawable(PDev *pdev, QXLDrawable *drawable);
-QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
-void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
-
-QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem);
-void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
-void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type);
-void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type);
-BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path);
-BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, QXLQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
-                BOOL invers, LONG width, LONG height, INT32 *surface_dest);
-BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, QXLBrush *qxl_brush,
-                            BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
-                            QXLRect *surface_rect);
-BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
-                  QXLRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
-                  INT32 *surface_dest);
-BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys);
-BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
-                       QXLRect *area, INT32 *surface_dest);
-BOOL QXLCheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans);
-UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size);
-BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str);
-
-void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id);
-
-QXLCursorCmd *CursorCmd(PDev *pdev);
-void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd);
-
-BOOL GetAlphaCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf);
-BOOL GetColorCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
-                    SURFOBJ *mask, XLATEOBJ *color_trans);
-BOOL GetMonoCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf);
-BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd);
-
-BOOL ResInit(PDev *pdev);
-void ResDestroy(PDev *pdev);
-void ResInitGlobals();
-void ResDestroyGlobals();
-#ifndef _WIN64
-void CheckAndSetSSE2();
-#endif
-void EmptyReleaseRing(PDev *pdev);
-void InitDeviceMemoryResources(PDev *pdev);
-void ReleaseCacheDeviceMemoryResources(PDev *pdev);
-
-#endif
diff --git a/display/rop.c b/display/rop.c
deleted file mode 100644
index 9fb3527..0000000
--- a/display/rop.c
+++ /dev/null
@@ -1,1778 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "os_dep.h"
-#include "qxldd.h"
-#include "utils.h"
-#include "res.h"
-#include "rop.h"
-#include "surface.h"
-
-
-enum ROP3type {
-    ROP3_TYPE_ERR,
-    ROP3_TYPE_FILL,
-    ROP3_TYPE_OPAQUE,
-    ROP3_TYPE_COPY,
-    ROP3_TYPE_BLEND,
-    ROP3_TYPE_BLACKNESS,
-    ROP3_TYPE_WHITENESS,
-    ROP3_TYPE_INVERS,
-    ROP3_TYPE_ROP3,
-    ROP3_TYPE_NOP,
-};
-
-
-ROP3Info rops2[] = {
-    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_BLACKNESS, SPICE_ROPD_OP_BLACKNESS},                     //0
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR |
-                                                               SPICE_ROPD_INVERS_RES},        //DPon
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                               SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_AND},  //DPna
-    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_BRUSH |
-                                                    SPICE_ROPD_OP_PUT},                       //Pn
-    {QXL_EFFECT_BLACKNESS_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                              SPICE_ROPD_INVERS_DEST | SPICE_ROPD_OP_AND},    //PDna
-    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST, ROP3_TYPE_INVERS, SPICE_ROPD_OP_INVERS},            //Dn
-    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR},    //DPx
-    {QXL_EFFECT_BLACKNESS_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                              SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES},     //DPan
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_AND},       //DPa
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR |
-                                               SPICE_ROPD_INVERS_RES},                        //DPxn
-    {QXL_EFFECT_NOP, ROP3_DEST, ROP3_TYPE_NOP, 0},                                            //D
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                            SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_OR},      //DPno
-    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_PUT},                       //P
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_DEST |
-                                               SPICE_ROPD_OP_OR},                             //PDno
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR},        //DPo
-    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_WHITENESS, SPICE_ROPD_OP_WHITENESS},                     //1
-};
-
-
-ROP3Info rops3[] = {
-
-    //todo: update rop3 effect
-
-    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_BLACKNESS, 0},                                 //0
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x01},                             //DPSoon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x02},                             //DPSona
-                                                                                    //PSon
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_OR |
-                                               SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x04},                             //SDPona
-                                                                                    //DPon
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR |
-                                               SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x06},                             //PDSxnon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x07},                             //PDSaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x08},                             //SDPnaa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x09},                             //PDSxon
-                                                                                    //DPna
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                                                   SPICE_ROPD_INVERS_BRUSH |
-                                                                   SPICE_ROPD_OP_AND},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0b},                             //PSDnaon
-                                                                                    //SPna
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_INVERS_BRUSH |
-                                                                 SPICE_ROPD_OP_AND },
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0d},                             //PDSnaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0e},                             //PDSonon
-                                                                                    //Pn
-    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_PUT},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x10},                             //PDSona
-                                                                                    //DSon
-    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_OR |
-                                             SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x12},                             //SDPxnon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x13},                             //SDPaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x14},                             //DPSxnon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x15},                             //DPSaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x16},                             //PSDPSanaxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x17},                             //SSPxDSxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x18},                             //SPxPDxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x19},                             //SDPSanaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1a},                             //PDSPaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1b},                             //SDPSxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1c},                             //PSDPaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1d},                             //DSPDxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1e},                             //PDSox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1f},                             //PDSoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x20},                             //DPSnaa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x21},                             //SDPxon
-                                                                                    //DSna
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_INVERS_SRC |
-                                                                   SPICE_ROPD_OP_AND},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x23},                             //SPDnaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x24},                             //SPxDSxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x25},                             //PDSPanaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x26},                             //SDPSaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x27},                             //SDPSxnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x28},                             //DPSxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x29},                             //PSDPSaoxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2a},                             //DPSana
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2b},                             //SSPxPDxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2c},                             //SPDSoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2d},                             //PSDnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2e},                             //PSDPxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2f},                             //PSDnoan
-                                                                                    //PSna
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_INVERS_SRC |
-                                                                 SPICE_ROPD_OP_AND},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x31},                             //SDPnaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x32},                             //SDPSoox
-    {QXL_EFFECT_OPAQUE, ROP3_SRC, ROP3_TYPE_COPY, SPICE_ROPD_INVERS_SRC |
-                                                  SPICE_ROPD_OP_PUT},               //Sn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x34},                             //SPDSaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x35},                             //SPDSxnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x36},                             //SDPox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x37},                             //SDPoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x38},                             //PSDPoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x39},                             //SPDnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3a},                             //SPDSxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3b},                             //SPDnoan
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_XOR},//PSx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3d},                             //SPDSonox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3e},                             //SPDSnaox
-                                                                                    //PSan
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_AND |
-                                                                 SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x40},                             //PSDnaa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x41},                             //DPSxon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x42},                             //SDxPDxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x43},                             //SPDSanaxn
-                                                                                    //SDna
-    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_INVERS_DEST |
-                                                              SPICE_ROPD_OP_AND},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x45},                             //DPSnaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x46},                             //DSPDaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x47},                             //PSDPxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x48},                             //SDPxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x49},                             //PDSPDaoxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4a},                             //DPSDoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4b},                             //PDSnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4c},                             //SDPana
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4d},                             //SSPxDSxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4e},                             //PDSPxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4f},                             //PDSnoan
-                                                                                    //PDna
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_DEST |
-                                                               SPICE_ROPD_OP_AND},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x51},                             //DSPnaon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x52},                             //DPSDaox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x53},                             //SPDSxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x54},                             //DPSonon
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST, ROP3_TYPE_INVERS, 0},                        //Dn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x56},                             //DPSox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x57},                             //DPSoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x58},                             //PDSPoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x59},                             //DPSnox
-    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR},
-                                                                                    //DPx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5b},                             //DPSDonox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5c},                             //DPSDxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5d},                             //DPSnoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5e},                             //DPSDnaox
-                                                                                    //DPan
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_AND |
-                                                               SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x60},                             //PDSxa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x61},                             //DSPDSaoxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x62},                             //DSPDoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x63},                             //SDPnox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x64},                             //SDPSoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x65},                             //DSPnox
-    {QXL_EFFECT_REVERT_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
-                                                     SPICE_ROPD_OP_XOR},            //DSx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x67},                             //SDPSonox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x68},                             //DSPDSonoxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x69},                             //PDSxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6a},                             //DPSax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6b},                             //PSDPSoaxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6c},                             //SDPax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6d},                             //PDSPDoaxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6e},                             //SDPSnoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6f},                             //PDSxnan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x70},                             //PDSana
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x71},                             //SSDxPDxaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x72},                             //SDPSxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x73},                             //SDPnoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x74},                             //DSPDxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x75},                             //DSPnoan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x76},                             //SDPSnaox
-                                                                                    //DSan
-    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_AND |
-                                                              SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x78},                             //PDSax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x79},                             //DSPDSoaxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7a},                             //DPSDnoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7b},                             //SDPxnan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7c},                             //SPDSnoax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7d},                             //DPSxnan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7e},                             //SPxDSxo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7f},                             //DPSaan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x80},                             //DPSaa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x81},                             //SPxDSxon
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x82},                             //DPSxna
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x83},                             //SPDSnoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x84},                             //SDPxna
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x85},                             //PDSPnoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x86},                             //DSPDSoaxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x87},                             //PDSaxn
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
-                                                  SPICE_ROPD_OP_AND},               //DSa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x89},                             //SDPSnaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8a},                             //DSPnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8b},                             //DSPDxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8c},                             //SDPnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8d},                             //SDPSxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8e},                             //SSDxPDxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8f},                             //PDSanan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x90},                             //PDSxna
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x91},                             //SDPSnoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x92},                             //DPSDPoaxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x93},                             //SPDaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x94},                             //PSDPSoaxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x95},                             //DPSaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x96},                             //DPSxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x97},                             //PSDPSonoxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x98},                             //SDPSonoxn
-                                                                                    //DSxn
-    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_XOR |
-                                                              SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9a},                             //DPSnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9b},                             //SDPSoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9c},                             //SPDnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9d},                             //DSPDoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9e},                             //DSPDSaoxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9f},                             //PDSxan
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                                    SPICE_ROPD_OP_AND},             //DPa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa1},                             //PDSPnaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa2},                             //DPSnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa3},                             //DPSDxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa4},                             //PDSPonoxn
-                                                                                    //PDxn
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR |
-                                                               SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa6},                             //DSPnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa7},                             //PDSPoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa8},                             //DPSoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa9},                             //DPSoxn
-    {QXL_EFFECT_NOP, ROP3_DEST, ROP3_TYPE_NOP, 0},                                  //D
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xab},                             //DPSono
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xac},                             //SPDSxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xad},                             //DPSDaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xae},                             //DSPnao
-                                                                                    //DPno
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                                    SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb0},                             //PDSnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb1},                             //PDSPxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb2},                             //SSPxDSxox
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb3},                             //SDPanan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb4},                             //PSDnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb5},                             //DPSDoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb6},                             //DPSDPaoxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb7},                             //SDPxan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb8},                             //PSDPxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb9},                             //DSPDaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xba},                             //DPSnao
-                                                                                    //DSno
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
-                                                       SPICE_ROPD_INVERS_SRC | SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbc},                             //SPDSanax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbd},                             //SDxPDxan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbe},                             //DPSxo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbf},                             //DPSano
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_AND},//PSa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc1},                             //SPDSnaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc2},                             //SPDSonoxn
-                                                                                    //PSxn
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_XOR |
-                                                                 SPICE_ROPD_INVERS_RES},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc4},                             //SPDnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc5},                             //SPDSxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc6},                             //SDPnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc7},                             //PSDPoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc8},                             //SDPoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc9},                             //SPDoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xca},                             //DPSDxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xcb},                             //SPDSaoxn
-    {QXL_EFFECT_OPAQUE, ROP3_SRC, ROP3_TYPE_COPY, SPICE_ROPD_OP_PUT},                     //S
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xcd},                             //SDPono
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xce},                             //SDPnao
-                                                                                    //SPno
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE,
-                                               SPICE_ROPD_INVERS_BRUSH |
-                                               SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd0},                             //PSDnoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd1},                             //PSDPxoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd2},                             //PDSnax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd3},                             //SPDSoaxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd4},                             //SSPxPDxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd5},                             //DPSanan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd6},                             //PSDPSaoxx
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd7},                             //DPSxan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd8},                             //PDSPxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd9},                             //SDPSaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xda},                             //DPSDanax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdb},                             //SPxDSxan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdc},                             //SPDnao
-                                                                                    //SDno
-    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
-                                             SPICE_ROPD_INVERS_DEST |
-                                             SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xde},                             //SDPxo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdf},                             //SDPano
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe0},                             //PDSoa
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe1},                             //PDSoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe2},                             //DSPDxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe3},                             //PSDPaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe4},                             //SDPSxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe5},                             //PDSPaoxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe6},                             //SDPSanax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe7},                             //SPxPDxan
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe8},                             //SSPxDSxax
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe9},                             //DSPDSanaxxn
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xea},                             //DPSao
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xeb},                             //DPSxno
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xec},                             //SDPao
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xed},                             //SDPxno
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
-                                                  SPICE_ROPD_OP_OR},                //DSo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xef},                             //SDPnoo
-    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_PUT},                   //P
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf1},                             //PDSono
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf2},                             //PDSnao
-                                                                                    //PSno
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE,
-                                               SPICE_ROPD_INVERS_SRC |
-                                               SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf4},                             //PSDnao
-                                                                                    //PDno
-    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                               SPICE_ROPD_INVERS_DEST |
-                                               SPICE_ROPD_OP_OR},
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf6},                             //PDSxo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf7},                             //PDSano
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf8},                             //PDSao
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf9},                             //PDSxno
-    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
-                                                    SPICE_ROPD_OP_OR},              //DPo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfb},                             //DPSnoo
-    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_OR}, //PSo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfd},                             //PSDnoo
-    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfe},                             //DPSoo
-    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_WHITENESS, 1},                                 //1
-};
-
-
-static BOOL DoFill(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush,
-                   POINTL *brush_pos, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
-                   BOOL invers_mask)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area && brush);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos,
-                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
-        !QXLGetMask(pdev, drawable, &drawable->u.fill.mask, mask, mask_pos, invers_mask,
-                     width, height, &drawable->surfaces_dest[1])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    drawable->u.fill.rop_descriptor = rop_info->method_data;
-
-    drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
-    }
-
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL GetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *bitmap_phys, SURFOBJ *surf,
-                      QXLRect *area, XLATEOBJ *color_trans, BOOL use_cache, INT32 *surface_dest)
-{
-    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
-    if (surf->iType != STYPE_BITMAP) {
-        UINT32 surface_id;
-
-        ASSERT(pdev, (PDev *)surf->dhpdev == pdev);
-        surface_id =  GetSurfaceId(surf);
-        if (surface_id == drawable->surface_id) {
-            DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
-            *bitmap_phys = 0;
-            drawable->self_bitmap = TRUE;
-            drawable->self_bitmap_area = *area;
-            area->right = area->right - area->left;
-            area->left = 0;
-            area->bottom = area->bottom - area->top;
-            area->top = 0;
-            return TRUE;
-        }
-    }
-    return QXLGetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, surf,
-                        area, color_trans, NULL, use_cache, surface_dest);
-}
-
-static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
-{
-    return (scale_mode == HALFTONE) ? SPICE_IMAGE_SCALE_MODE_INTERPOLATE :
-                                      SPICE_IMAGE_SCALE_MODE_NEAREST;
-}
-
-static BOOL DoOpaque(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
-                     RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
-                     UINT16 rop_descriptor, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask,
-                     ULONG scale_mode)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area && brush && src_rect && src);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    drawable->u.opaque.scale_mode = GdiScaleModeToQxl(scale_mode);
-    CopyRect(&drawable->u.opaque.src_area, src_rect);
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos,
-                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
-        !QXLGetMask(pdev, drawable, &drawable->u.opaque.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[1]) ||
-        !GetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, src,
-                   &drawable->u.opaque.src_area, color_trans, TRUE,
-                   &drawable->surfaces_dest[2])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
-    }
-    CopyRect(&drawable->surfaces_rects[2], src_rect);
-
-    drawable->u.opaque.rop_descriptor = rop_descriptor;
-    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL StreamTest(PDev *pdev, UINT32 surface_id, SURFOBJ *src_surf, 
-		       XLATEOBJ *color_trans, RECTL *src_rect, RECTL *dest)
-{
-    Ring *ring = &pdev->update_trace;
-    UpdateTrace *trace = (UpdateTrace *)ring->next;
-    LONG src_pixmap_pixels = src_surf->sizlBitmap.cx * src_surf->sizlBitmap.cy;
-
-    if (src_pixmap_pixels <= 128 * 128 || 
-	/* Only handle streams on primary surface */
-	surface_id != 0) {
-        return TRUE;
-    }
-
-    for (;;) {
-        if (SameRect(dest, &trace->area) || (trace->hsurf == src_surf->hsurf &&
-                                              src_pixmap_pixels / RectSize(src_rect) > 100)) {
-            UINT32 now = *pdev->mm_clock;
-            BOOL ret;
-
-            if (now != trace->last_time && now - trace->last_time < 1000 / 5) {
-                trace->last_time = now - 1; // asumong mm clock is active so delta t == 0 is
-                                            // imposibole. frocing delata t to be at least 1.
-                if (trace->count < 20) {
-                    trace->count++;
-                    ret = TRUE;
-                } else {
-                    ret = FALSE;
-                }
-            } else {
-                trace->last_time = now;
-                trace->count = 0;
-                ret = TRUE;
-            }
-            RingRemove(pdev, (RingItem *)trace);
-            RingAdd(pdev, ring, (RingItem *)trace);
-            return ret;
-        }
-        if (trace->link.next == ring) {
-            break;
-        }
-        trace = (UpdateTrace *)trace->link.next;
-    }
-    RingRemove(pdev, (RingItem *)trace);
-    trace->area = *dest;
-    trace->last_time = *pdev->mm_clock;
-
-    if (IsUniqueSurf(src_surf, color_trans)) {
-        trace->hsurf = src_surf->hsurf;
-    } else {
-        trace->hsurf = NULL;
-    }
-    trace->count = 0;
-    RingAdd(pdev, ring, (RingItem *)trace);
-
-    return TRUE;
-}
-
-static BOOL TestSplitClips(PDev *pdev, SURFOBJ *src, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *mask)
-{
-    UINT32 width;
-    UINT32 height;
-    UINT32 src_space;
-    UINT32 clip_space = 0;
-    int more;
-
-    if (!clip || mask) {
-        return FALSE;
-    }
-
-    if (src->iType != STYPE_BITMAP) {
-        return FALSE;
-    }
-
-    width = src_rect->right - src_rect->left;
-    height = src_rect->bottom - src_rect->top;
-    src_space = width * height;
-
-    if (clip->iDComplexity == DC_RECT) {
-        width = clip->rclBounds.right - clip->rclBounds.left;
-        height = clip->rclBounds.bottom - clip->rclBounds.top;
-        clip_space = width * height;
-
-        if ((src_space / clip_space) > 1) {
-            return TRUE;
-        }
-        return FALSE;
-    }
-
-    if (clip->iMode == TC_RECTANGLES) {
-        CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
-        do {
-            RECTL *now;
-            RECTL *end;
-
-            struct {
-                ULONG  count;
-                RECTL  rects[20];
-            } buf;
-
-            more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
-            for(now = buf.rects, end = now + buf.count; now < end; now++) {
-                width = now->right - now->left;
-                height = now->bottom - now->top;
-                clip_space += width * height;
-            }
-        } while (more);
-
-        if ((src_space / clip_space) > 1) {
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-static _inline BOOL DoPartialCopy(PDev *pdev, UINT32 surface_id, SURFOBJ *src, RECTL *src_rect,
-                                  RECTL *area_rect, RECTL *clip_rect, XLATEOBJ *color_trans,
-                                  ULONG scale_mode, UINT16 rop_descriptor)
-{
-    QXLDrawable *drawable;
-    RECTL clip_area;
-    UINT32 width;
-    UINT32 height;
-
-    SectRect(area_rect, clip_rect, &clip_area);
-    if (IsEmptyRect(&clip_area)) {
-        return TRUE;
-    }
-
-    width = clip_area.right - clip_area.left;
-    height = clip_area.bottom - clip_area.top;
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL, surface_id))) {
-        return FALSE;
-    }
-
-    drawable->effect = QXL_EFFECT_OPAQUE;
-    drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
-    drawable->u.copy.mask.bitmap = 0;
-    drawable->u.copy.rop_descriptor = rop_descriptor;
-
-    drawable->u.copy.src_area.top = src_rect->top + (clip_area.top - area_rect->top);
-    drawable->u.copy.src_area.bottom = drawable->u.copy.src_area.top + clip_area.bottom -
-                                       clip_area.top;
-    drawable->u.copy.src_area.left = src_rect->left + (clip_area.left - area_rect->left);
-    drawable->u.copy.src_area.right = drawable->u.copy.src_area.left + clip_area.right -
-                                      clip_area.left;
-
-    if(!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
-                  color_trans, FALSE, &drawable->surfaces_dest[0])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-    CopyRect(&drawable->surfaces_rects[0], src_rect);
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoCopy(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
-                   RECTL *src_rect, XLATEOBJ *color_trans, UINT16 rop_descriptor, SURFOBJ *mask,
-                   POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
-{
-    QXLDrawable *drawable;
-    BOOL use_cache;
-    UINT32 width;
-    UINT32 height;
-
-    ASSERT(pdev, pdev && area && src_rect && src);
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (mask) {
-        use_cache = TRUE;
-    } else {
-        use_cache = StreamTest(pdev, surface_id, src, color_trans, src_rect, area);
-    }
-
-    if (use_cache && TestSplitClips(pdev, src, src_rect, clip, mask) &&
-        !QXLCheckIfCacheImage(pdev, src, color_trans)) {
-        if (clip->iDComplexity == DC_RECT) {
-            if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, &clip->rclBounds, color_trans,
-                               scale_mode, rop_descriptor)) {
-                return FALSE;
-            }
-        } else {
-            int more;
-            ASSERT(pdev, clip->iMode == TC_RECTANGLES);
-            CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
-            do {
-                RECTL *now;
-                RECTL *end;
-
-                struct {
-                    ULONG  count;
-                    RECTL  rects[20];
-                } buf;
-                more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
-                for(now = buf.rects, end = now + buf.count; now < end; now++) {
-                    if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, now, color_trans,
-                                       scale_mode, rop_descriptor)) {
-                        return FALSE;
-                    }
-                }
-            } while (more);
-        }
-        return TRUE;
-    }
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    if (mask) {
-        drawable->effect = QXL_EFFECT_BLEND;
-    } else {
-        drawable->effect = QXL_EFFECT_OPAQUE;
-    }
-
-    drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
-    CopyRect(&drawable->u.copy.src_area, src_rect);
-    if (!QXLGetMask(pdev, drawable, &drawable->u.copy.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[0]) ||
-        !GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
-                   color_trans, use_cache, &drawable->surfaces_dest[1])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
-    }
-    CopyRect(&drawable->surfaces_rects[1], src_rect);
-
-    drawable->u.copy.rop_descriptor = rop_descriptor;
-    PushDrawable(pdev, drawable);
-    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-static BOOL DoCopyBits(PDev *pdev, UINT32 surface_id, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height; 
-
-    ASSERT(pdev, pdev && area && src_pos);
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    if (area->left == src_pos->x && area->top == src_pos->y) {
-        DEBUG_PRINT((pdev, 6, "%s: NOP\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    drawable->surfaces_dest[0] = surface_id;
-    CopyRectPoint(&drawable->surfaces_rects[0], src_pos, width, height);
-
-    CopyPoint(&drawable->u.copy_bits.src_pos, src_pos);
-    drawable->effect = QXL_EFFECT_OPAQUE;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoBlend(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
-                    RECTL *src_rect, XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask,
-                    POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height; 
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area && src_rect && src);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    drawable->u.blend.scale_mode = GdiScaleModeToQxl(scale_mode);
-    CopyRect(&drawable->u.blend.src_area, src_rect);
-    if (!QXLGetMask(pdev, drawable, &drawable->u.blend.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[0]) ||
-        !GetBitmap(pdev, drawable, &drawable->u.blend.src_bitmap, src, &drawable->u.blend.src_area,
-                   color_trans, TRUE, &drawable->surfaces_dest[1])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
-    }
-    CopyRect(&drawable->surfaces_rects[1], src_rect);
-
-    drawable->u.blend.rop_descriptor = rop_info->method_data;
-    drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoBlackness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
-                        POINTL *mask_pos, BOOL invers_mask)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!QXLGetMask(pdev, drawable, &drawable->u.blackness.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[0])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
- if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
- }
-
-    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoWhiteness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
-                        POINTL *mask_pos, BOOL invers_mask)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!QXLGetMask(pdev, drawable, &drawable->u.whiteness.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[0])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
-    }
-
-    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoInvers(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
-                     POINTL *mask_pos, BOOL invers_mask)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    if (!QXLGetMask(pdev, drawable, &drawable->u.invers.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[0])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
-    }
-
-    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_REVERT_ON_DUP;
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-static BOOL DoROP3(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
-                   RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
-                   UINT8 rop3, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
-{
-    QXLDrawable *drawable;
-    UINT32 width;
-    UINT32 height;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-    ASSERT(pdev, pdev && area && brush && src_rect && src);
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    width = area->right - area->left;
-    height = area->bottom - area->top;
-
-    drawable->u.rop3.scale_mode = GdiScaleModeToQxl(scale_mode);
-    CopyRect(&drawable->u.rop3.src_area, src_rect);
-    if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos,
-                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
-        !QXLGetMask(pdev, drawable, &drawable->u.rop3.mask, mask, mask_pos, invers_mask,
-                    width, height, &drawable->surfaces_dest[1]) ||
-        !GetBitmap(pdev, drawable, &drawable->u.rop3.src_bitmap, src, &drawable->u.rop3.src_area,
-                   color_trans, TRUE, &drawable->surfaces_dest[2])) {
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    if (mask_pos) {
-        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
-    }
-    CopyRect(&drawable->surfaces_rects[2], src_rect);
-
-    drawable->u.rop3.rop3 = rop3;
-    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_BLEND; //for now
-    PushDrawable(pdev, drawable);
-    return TRUE;
-}
-
-BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
-                   XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
-                   POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
-{
-    RECTL area;
-    SURFOBJ* surf_obj;
-    BOOL ret;
-    UINT32 surface_id;
-    SurfaceInfo *surface;
-
-    surface = (SurfaceInfo *)src->dhsurf;
-    surface_id = GetSurfaceId(src);
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    area.top = MAX(0, src_pos.y);
-    area.bottom = MIN(src_pos.y + dest_rect->bottom - dest_rect->top,
-                      surface->draw_area.surf_obj->sizlBitmap.cy);
-    area.left = MAX(0, src_pos.x);
-    area.right = MIN(src_pos.x + dest_rect->right - dest_rect->left,
-                     surface->draw_area.surf_obj->sizlBitmap.cx);
-
-    UpdateArea(pdev, &area, surface_id);
-
-    surf_obj = surface->draw_area.surf_obj;
-
-    if (rop4 == 0xcccc) {
-        ret = EngCopyBits(dest, surf_obj, clip, color_trans, dest_rect, &src_pos);
-    } else {
-        ret = EngBitBlt(dest, surf_obj, mask, clip, color_trans, dest_rect, &src_pos,
-                        mask_pos, brush, brush_pos, rop4);
-    }
-
-    return ret;
-}
-
-BOOL _inline __DrvBitBlt(PDev *pdev, UINT32 surface_id, RECTL *dest_rect, CLIPOBJ *clip,
-                        SURFOBJ  *src, RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, 
-                        POINTL *brush_pos, ULONG rop3, SURFOBJ *mask, POINTL *mask_pos,
-                        BOOL invers_mask, ULONG scale_mode)
-{
-    ROP3Info *rop_info = &rops3[rop3];
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    switch (rop_info->method_type) {
-    case ROP3_TYPE_FILL:
-        return DoFill(pdev, surface_id, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
-                      invers_mask);
-    case ROP3_TYPE_OPAQUE:
-        return DoOpaque(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
-                        brush_pos, rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
-    case ROP3_TYPE_COPY:
-        return DoCopy(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans,
-                      rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
-    case ROP3_TYPE_BLEND:
-        return DoBlend(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, rop_info,
-                       mask, mask_pos, invers_mask, scale_mode);
-    case ROP3_TYPE_BLACKNESS:
-        return DoBlackness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
-    case ROP3_TYPE_WHITENESS:
-        return DoWhiteness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
-    case ROP3_TYPE_INVERS:
-        return DoInvers(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
-    case ROP3_TYPE_ROP3:
-        return DoROP3(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
-                      brush_pos, (UINT8)rop_info->method_data, mask, mask_pos, invers_mask,
-                      scale_mode);
-    case ROP3_TYPE_NOP:
-        return TRUE;
-    default:
-        DEBUG_PRINT((pdev, 0, "%s: Error\n", __FUNCTION__));
-        //EngSetError
-        return FALSE;
-    }
-}
-
-#ifdef SUPPORT_BRUSH_AS_MASK
-SURFOBJ *BrushToMask(PDev *pdev, BRUSHOBJ *brush)
-{
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    if (!brush || brush->iSolidColor != ~0) {
-        DEBUG_PRINT((pdev, 8, "%s: no mask, brush 0x%x color 0x%x\n",
-                     __FUNCTION__, brush, brush ? brush->iSolidColor : 0));
-        return NULL;
-    }
-
-    if (!brush->pvRbrush && !BRUSHOBJ_pvGetRbrush(brush)) {
-        DEBUG_PRINT((pdev, 0, "%s: realize failed\n", __FUNCTION__));
-        return NULL;
-    }
-    DEBUG_PRINT((pdev, 7, "%s: done 0x%x\n", __FUNCTION__, brush->pvRbrush));
-    return NULL;
-}
-#endif
-
-
-static _inline BOOL TestSrcBits(PDev *pdev, SURFOBJ *src, XLATEOBJ *color_trans)
-{
-    if (src) {
-        switch (src->iBitmapFormat) {
-        case BMF_32BPP:
-        case BMF_24BPP:
-        case BMF_16BPP: {
-            ULONG bit_fields[3];
-            ULONG ents;
-
-            if (!color_trans || (color_trans->flXlate & XO_TRIVIAL)) {
-                return TRUE;
-            }
-
-            ents = XLATEOBJ_cGetPalette(color_trans, XO_SRCBITFIELDS, 3, bit_fields);
-            ASSERT(pdev, ents == 3);
-            switch (src->iBitmapFormat) {
-            case BMF_32BPP:
-            case BMF_24BPP:
-                if (bit_fields[0] != 0x00ff0000 || bit_fields[1] != 0x0000ff00 ||
-                                                                    bit_fields[2] != 0x000000ff) {
-                    DEBUG_PRINT((pdev, 11, "%s: BMF_32BPP/24BPP r 0x%x g 0x%x b 0x%x\n",
-                                 __FUNCTION__,
-                                 bit_fields[0],
-                                 bit_fields[1],
-                                 bit_fields[2]));
-                    return FALSE;
-                }
-                break;
-            case BMF_16BPP:
-                if (bit_fields[0] != 0x7c00 || bit_fields[1] != 0x03e0 ||
-                                                                        bit_fields[2] != 0x001f) {
-                    DEBUG_PRINT((pdev, 11, "%s: BMF_16BPP r 0x%x g 0x%x b 0x%x\n",
-                                 __FUNCTION__,
-                                 bit_fields[0],
-                                 bit_fields[1],
-                                 bit_fields[2]));
-                    return FALSE;
-                }
-                break;
-            }
-            return TRUE;
-        }
-        case BMF_8BPP:
-        case BMF_4BPP:
-        case BMF_1BPP:
-            return color_trans && (color_trans->flXlate & XO_TABLE);
-        default:
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                              XLATEOBJ *color_trans, RECTL *dest_rect, RECTL *src_rect,
-                              POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4,
-                              ULONG scale_mode, COLORADJUSTMENT *color_adjust)
-{
-    ULONG rop3;
-    ULONG second_rop3;
-#ifdef SUPPORT_BRUSH_AS_MASK
-    SURFOBJ *brush_mask = NULL;
-#endif
-    QXLRESULT res;
-    UINT32 surface_id;
-
-    ASSERT(pdev, dest->iType != STYPE_BITMAP);
-
-    surface_id = GetSurfaceId(dest);
-
-    if (!PrepareBrush(brush)) {
-        return QXL_FAILED;
-    }
-
-    if ((rop3 = rop4 & 0xff) == (second_rop3 = ((rop4 >> 8) & 0xff))) {
-        return __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
-                           brush_pos, rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS :
-                           QXL_FAILED;
-    }
-
-    if (!mask) {
-        DEBUG_PRINT((pdev, 5, "%s: no mask. rop4 is 0x%x\n", __FUNCTION__, rop4));
-        return QXL_UNSUPPORTED;
-#ifdef SUPPORT_BRUSH_AS_MASK
-        brush_mask = BrushToMask(pdev, brush);
-        if (!brush_mask) {
-            DEBUG_PRINT((pdev, 5, "%s: no mask. rop4 is 0x%x\n", __FUNCTION__, rop4));
-            return QXL_UNSUPPORTED;
-        }
-        mask = brush_mask;
-        ASSERT(pdev, mask_pos);
-#endif
-    }
-    DEBUG_PRINT((pdev, 5, "%s: mask, rop4 is 0x%x\n", __FUNCTION__, rop4));
-    ASSERT(pdev, mask_pos);
-    res = (__DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
-                       brush_pos, rop3, mask, mask_pos, FALSE, scale_mode) &&
-          __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
-                      brush_pos, second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS :
-                      QXL_FAILED;
-#ifdef SUPPORT_BRUSH_AS_MASK
-    if (brush_mask) {
-        //free brush_mask;
-    }
-#endif
-
-    return res;
-}
-
-static _inline void FixDestParams(PDev *pdev, SURFOBJ *dest, CLIPOBJ **in_clip,
-                                  RECTL *dest_rect, RECTL *area, POINTL **in_mask_pos,
-                                  POINTL *local_mask_pos)
-{
-    CLIPOBJ *clip;
-
-    area->top = MAX(dest_rect->top, 0);
-    area->left = MAX(dest_rect->left, 0);
-    area->bottom = MIN(dest->sizlBitmap.cy, dest_rect->bottom);
-    area->right = MIN(dest->sizlBitmap.cx, dest_rect->right);
-
-    clip = *in_clip;
-    if (clip) {
-        if (clip->iDComplexity == DC_TRIVIAL) {
-            clip = NULL;
-        } else {
-            SectRect(&clip->rclBounds, area, area);
-            if (clip->iDComplexity == DC_RECT) {
-                clip = NULL;
-            }
-        }
-        *in_clip = clip;
-    }
-
-    if (in_mask_pos && *in_mask_pos) {
-        POINTL *mask_pos;
-        ASSERT(pdev, local_mask_pos);
-        mask_pos = *in_mask_pos;
-        local_mask_pos->x = mask_pos->x + (area->left - dest_rect->left);
-        local_mask_pos->y = mask_pos->y + (area->top - dest_rect->top);
-        *in_mask_pos = local_mask_pos;
-    }
-}
-
-static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                         XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos,
-                         POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
-{
-    RECTL area;
-    POINTL local_mask_pos;
-    RECTL src_rect;
-    RECTL *src_rect_ptr;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    if (!TestSrcBits(pdev, src, color_trans)) {
-        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
-
-        return EngBitBlt(dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos, brush,
-                         brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
-    }
-
-#if 0
-    if (rop4 == 0xccaa) {
-        DEBUG_PRINT((pdev, 7, "%s: rop4 is 0xccaa, call EngBitBlt\n", __FUNCTION__));
-        return QXL_UNSUPPORTED;
-    }
-#endif
-
-    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
-           dest_rect->top < dest_rect->bottom);
-
-    FixDestParams(pdev, dest, &clip, dest_rect, &area, &mask_pos, &local_mask_pos);
-    if (IsEmptyRect(&area)) {
-        DEBUG_PRINT((pdev, 0, "%s: empty rect\n", __FUNCTION__));
-        return QXL_SUCCESS;
-    }
-
-    if (src && src_pos) {
-        POINTL local_pos;
-
-        local_pos.x = src_pos->x + (area.left - dest_rect->left);
-        local_pos.y = src_pos->y + (area.top - dest_rect->top);
-
-        if (dest->iType == STYPE_BITMAP) {
-            return BitBltFromDev(pdev, src, dest, mask, clip, color_trans, &area, local_pos,
-                                 mask_pos, brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
-        }
-
-        if (src->iType != STYPE_BITMAP
-            && GetSurfaceId(src) == GetSurfaceId(dest) && rop4 == 0xcccc) { //SRCCOPY no mask
-            return DoCopyBits(pdev, GetSurfaceId(src), clip, &area, &local_pos) ?
-                              QXL_SUCCESS : QXL_FAILED;
-        }
-
-        src_rect.left = local_pos.x;
-        src_rect.right = src_rect.left + (area.right - area.left);
-        src_rect.top = local_pos.y;
-        src_rect.bottom = src_rect.top + (area.bottom - area.top);
-        src_rect_ptr = &src_rect;
-    } else {
-        src_rect_ptr = NULL;
-    }
-
-    return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect_ptr,
-                        mask_pos, brush, brush_pos, rop4, COLORONCOLOR, NULL);
-}
-
-BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                      XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos,
-                      POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
-{
-    PDev *pdev;
-    QXLRESULT res;
-
-    if (dest->iType == STYPE_BITMAP) {
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        pdev = (PDev *)dest->dhpdev;
-    }
-
-    PUNT_IF_DISABLED(pdev);
-
-    CountCall(pdev, CALL_COUNTER_BIT_BLT);
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-    if ((res = _BitBlt(pdev, dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
-                       brush, brush_pos, rop4))) {
-        if (res == QXL_UNSUPPORTED) {
-            DEBUG_PRINT((pdev, 4, "%s: call EngBitBlt\n", __FUNCTION__));
-            return EngBitBlt(dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
-                             brush, brush_pos, rop4);
-        }
-        return FALSE;
-
-    }
-
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-BOOL APIENTRY DrvCopyBits(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip,
-                          XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos)
-{
-    PDev *pdev;
-
-    if (dest->iType == STYPE_BITMAP) {
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        pdev = (PDev *)dest->dhpdev;
-    }
-
-    PUNT_IF_DISABLED(pdev);
-
-    CountCall(pdev, CALL_COUNTER_BIT_BLT);
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    return _BitBlt(pdev, dest, src, NULL, clip, color_trans, dest_rect, src_pos, NULL, NULL,
-                   NULL, /*SRCCOPY*/ 0xcccc) == QXL_SUCCESS ? TRUE : FALSE;
-}
-
-static _inline BOOL TestStretchCondition(PDev *pdev, SURFOBJ *src, XLATEOBJ *color_trans,
-                                         COLORADJUSTMENT *color_adjust,
-                                         RECTL *dest_rect, RECTL *src_rect)
-{
-    int src_size;
-    int dest_size;
-
-    if (color_adjust && (color_adjust->caFlags & CA_NEGATIVE)) {
-        return FALSE;
-    }
-
-    if (IsCacheableSurf(src, color_trans)) {
-        return TRUE;
-    }
-
-    src_size = (src_rect->right - src_rect->left) * (src_rect->bottom - src_rect->top);
-    dest_size = (dest_rect->right - dest_rect->left) * (dest_rect->bottom - dest_rect->top);
-
-    return dest_size - src_size >= -(src_size >> 2);
-
-}
-
-static _inline unsigned int Scale(unsigned int val, unsigned int base_unit, unsigned int dest_unit)
-{
-    unsigned int div;
-    unsigned int mod;
-
-    div = dest_unit * val / base_unit;
-    mod = dest_unit * val % base_unit;
-    return (mod >= (base_unit >> 1)) ? div + 1: div;
-}
-
-static QXLRESULT _StretchBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                             XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
-                             POINTL *brush_pos, RECTL *dest_rect, RECTL *src_rect,
-                             POINTL *mask_pos, ULONG mode, BRUSHOBJ *brush, DWORD rop4)
-{
-    RECTL area;
-    POINTL local_mask_pos;
-    RECTL local_dest_rect;
-    RECTL local_src_rect;
-
-    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
-
-    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
-           src_rect->top < src_rect->bottom);
-    ASSERT(pdev, dest_rect);
-
-
-    if (dest_rect->left > dest_rect->right) {
-        local_dest_rect.left = dest_rect->right;
-        local_dest_rect.right = dest_rect->left;
-    } else {
-        local_dest_rect.left = dest_rect->left;
-        local_dest_rect.right = dest_rect->right;
-    }
-
-    if (dest_rect->top > dest_rect->bottom) {
-        local_dest_rect.top = dest_rect->bottom;
-        local_dest_rect.bottom = dest_rect->top;
-    } else {
-        local_dest_rect.top = dest_rect->top;
-        local_dest_rect.bottom = dest_rect->bottom;
-    }
-
-    if (!TestSrcBits(pdev, src, color_trans)) {
-        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
-        return QXL_UNSUPPORTED;
-    }
-
-    if (!TestStretchCondition(pdev, src, color_trans, color_adjust, &local_dest_rect, src_rect)) {
-        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
-        return QXL_UNSUPPORTED;
-    }
-
-    FixDestParams(pdev, dest, &clip, &local_dest_rect, &area, &mask_pos, &local_mask_pos);
-    if (IsEmptyRect(&area)) {
-        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
-        return QXL_SUCCESS;
-    }
-    //todo: use FixStreatchSrcArea
-    if (!SameRect(&local_dest_rect, &area)) { // possibly generate incosistent rendering on dest
-                                              // edges
-        unsigned int w_dest;
-        unsigned int h_dest;
-
-        if ((w_dest = local_dest_rect.right - local_dest_rect.left) != area.right - area.left) {
-            unsigned int w_src = src_rect->right - src_rect->left;
-            unsigned int delta;
-
-            if ((delta = area.left - local_dest_rect.left)) {
-                local_src_rect.left = src_rect->left + Scale(delta, w_dest, w_src);
-            } else {
-                local_src_rect.left = src_rect->left;
-            }
-
-            if ((delta = local_dest_rect.right - area.right)) {
-                local_src_rect.right = src_rect->right - Scale(delta, w_dest, w_src);
-            } else {
-                local_src_rect.right = src_rect->right;
-            }
-
-            local_src_rect.left = MIN(local_src_rect.left, src->sizlBitmap.cx - 1);
-            local_src_rect.right = MAX(local_src_rect.right, local_src_rect.left + 1);
-
-        } else {
-            local_src_rect.left = src_rect->left;
-            local_src_rect.right = src_rect->right;
-        }
-
-        if ((h_dest = local_dest_rect.bottom - local_dest_rect.top) != area.bottom - area.top) {
-            unsigned int h_src = src_rect->bottom - src_rect->top;
-            unsigned int delta;
-
-            if ((delta = area.top - local_dest_rect.top)) {
-                local_src_rect.top = src_rect->top + Scale(delta, h_dest, h_src);
-            } else {
-                local_src_rect.top = src_rect->top;
-            }
-
-            if ((delta = local_dest_rect.bottom - area.bottom)) {
-                local_src_rect.bottom = src_rect->bottom - Scale(delta, h_dest, h_src);
-            } else {
-                local_src_rect.bottom = src_rect->bottom;
-            }
-
-            local_src_rect.top = MIN(local_src_rect.top, src->sizlBitmap.cy - 1);
-            local_src_rect.bottom = MAX(local_src_rect.bottom, local_src_rect.top + 1);
-
-        } else {
-            local_src_rect.top = src_rect->top;
-            local_src_rect.bottom = src_rect->bottom;
-        }
-
-        src_rect = &local_src_rect;
-    }
-
-    return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect, mask_pos,
-                        brush, brush_pos, rop4, mode, color_adjust);
-}
-
-BOOL APIENTRY DrvStretchBltROP(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                               XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
-                               POINTL *brush_pos, RECTL *dest_rect, RECTL *src_rect,
-                               POINTL *mask_pos, ULONG mode, BRUSHOBJ *brush, DWORD rop4)
-{
-    PDev *pdev;
-    QXLRESULT res;
-
-    if (src && src->iType != STYPE_BITMAP) {
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        pdev = (PDev *)dest->dhpdev;
-    }
-
-    pdev = (PDev *)dest->dhpdev;
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-    CountCall(pdev, CALL_COUNTER_STRETCH_BLT_ROP);
-
-    PUNT_IF_DISABLED(pdev);
-
-    if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
-                           mode == HALFTONE ? color_adjust: NULL, brush_pos,
-                           dest_rect, src_rect, mask_pos, mode, brush,rop4))) {
-        if (res == QXL_UNSUPPORTED) {
-            goto punt;
-        }
-        return FALSE;
-    }
-    return TRUE;
-
-punt:
-    return EngStretchBltROP(dest, src, mask, clip, color_trans, color_adjust, brush_pos,
-                                dest_rect, src_rect, mask_pos, mode, brush, rop4);
-}
-
-BOOL APIENTRY DrvStretchBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
-                            XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
-                            POINTL *halftone_brush_pos, RECTL *dest_rect, RECTL *src_rect,
-                            POINTL *mask_pos, ULONG mode)
-{
-    PDev *pdev;
-    QXLRESULT res;
-
-    ASSERT(NULL, src);
-    if (src->iType != STYPE_BITMAP) {
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        pdev = (PDev *)dest->dhpdev;
-    }
-    pdev = (PDev *)dest->dhpdev;
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-    CountCall(pdev, CALL_COUNTER_STRETCH_BLT);
-    PUNT_IF_DISABLED(pdev);
-
-    if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
-                           mode == HALFTONE ? color_adjust: NULL, NULL, dest_rect,
-                           src_rect, mask_pos, mode, NULL, (mask) ? 0xccaa:  0xcccc))) {
-        if (res == QXL_UNSUPPORTED) {
-            goto punt;
-        }
-        return FALSE;
-    }
-    return TRUE;
-
-punt:
-    return EngStretchBlt(dest, src, mask, clip, color_trans, color_adjust, halftone_brush_pos,
-                         dest_rect, src_rect, mask_pos, mode);
-}
-
-static BOOL FixStreatchSrcArea(const RECTL *orig_dest, const RECTL *dest, const RECTL *orig_src,
-                               const SIZEL *bitmap_size, RECTL *src)
-{
-    unsigned int w_dest;
-    unsigned int h_dest;
-
-    if (SameRect(orig_dest, dest)) {
-        return FALSE;
-    }
-
-    // possibly generate incosistent rendering on dest edges
-
-    if ((w_dest = orig_dest->right - orig_dest->left) != dest->right - dest->left) {
-        unsigned int w_src = orig_src->right - orig_src->left;
-        unsigned int delta;
-
-        if ((delta = dest->left - orig_dest->left)) {
-            src->left = orig_src->left + Scale(delta, w_dest, w_src);
-        } else {
-            src->left = orig_src->left;
-        }
-
-        if ((delta = orig_dest->right - dest->right)) {
-            src->right = orig_src->right - Scale(delta, w_dest, w_src);
-        } else {
-            src->right = orig_src->right;
-        }
-
-        src->left = MIN(src->left, bitmap_size->cx - 1);
-        src->right = MAX(src->right, src->left + 1);
-
-    } else {
-        src->left = orig_src->left;
-        src->right = orig_src->right;
-    }
-
-    if ((h_dest = orig_dest->bottom - orig_dest->top) != dest->bottom - dest->top) {
-        unsigned int h_src = orig_src->bottom - orig_src->top;
-        unsigned int delta;
-
-        if ((delta = dest->top - orig_dest->top)) {
-            src->top = orig_src->top + Scale(delta, h_dest, h_src);
-        } else {
-            src->top = orig_src->top;
-        }
-
-        if ((delta = orig_dest->bottom - dest->bottom)) {
-            src->bottom = orig_src->bottom - Scale(delta, h_dest, h_src);
-        } else {
-            src->bottom = orig_src->bottom;
-        }
-
-        src->top = MIN(src->top, bitmap_size->cy - 1);
-        src->bottom = MAX(src->bottom, src->top + 1);
-
-    } else {
-        src->top = orig_src->top;
-        src->bottom = orig_src->bottom;
-    }
-
-    return TRUE;
-}
-
-BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ *color_trans,
-                            RECTL *dest_rect, RECTL *src_rect, BLENDOBJ *bland)
-{
-    QXLDrawable *drawable;
-    PDev *pdev;
-    RECTL area;
-    RECTL local_src;
-
-    ASSERT(NULL, src && dest);
-    if (src->iType != STYPE_BITMAP) {
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        pdev = (PDev *)dest->dhpdev;
-    }
-
-    pdev = (PDev *)dest->dhpdev;
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    PUNT_IF_DISABLED(pdev);
-
-    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
-           src_rect->top < src_rect->bottom);
-    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
-           dest_rect->top < dest_rect->bottom);
-
-    CountCall(pdev, CALL_COUNTER_ALPHA_BLEND);
-
-    if (bland->BlendFunction.BlendOp != AC_SRC_OVER) {
-        DEBUG_PRINT((pdev, 0, "%s: unexpected BlendOp\n", __FUNCTION__));
-        goto punt;
-    }
-
-    if (bland->BlendFunction.SourceConstantAlpha == 0) {
-        return TRUE;
-    }
-
-    if (!TestSrcBits(pdev, src, color_trans)) {
-        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
-        goto punt;
-    }
-
-    if (!TestStretchCondition(pdev, src, color_trans, NULL, dest_rect, src_rect)) {
-        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
-        goto punt;
-    }
-
-    FixDestParams(pdev, dest, &clip, dest_rect, &area, NULL, NULL);
-    if (IsEmptyRect(&area)) {
-        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip, GetSurfaceId(dest)))) {
-        DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (FixStreatchSrcArea(dest_rect, &area, src_rect, &src->sizlBitmap, &local_src)) {
-        src_rect = &local_src;
-    }
-
-    CopyRect(&drawable->surfaces_rects[0], src_rect);
-    CopyRect(&drawable->u.alpha_blend.src_area, src_rect);
-    if (bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA) {
-        ASSERT(pdev, src->iBitmapFormat == BMF_32BPP);
-        if (!QXLGetAlphaBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
-                               &drawable->u.alpha_blend.src_area,
-                               &drawable->surfaces_dest[0])) {
-            DEBUG_PRINT((pdev, 0, "%s: QXLGetAlphaBitmap failed\n", __FUNCTION__));
-            ReleaseOutput(pdev, drawable->release_info.id);
-            return FALSE;
-        }
-    } else {
-        if (!QXLGetBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
-                        &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE,
-                        &drawable->surfaces_dest[0])) {
-            DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
-            ReleaseOutput(pdev, drawable->release_info.id);
-            return FALSE;
-        }
-    }
-    drawable->u.alpha_blend.alpha_flags = 0;
-    if (src->iType != STYPE_BITMAP && 
-	bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA)
-      drawable->u.alpha_blend.alpha_flags |= SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA;
-    
-    drawable->u.alpha_blend.alpha = bland->BlendFunction.SourceConstantAlpha;
-    drawable->effect = QXL_EFFECT_BLEND;
-
-    PushDrawable(pdev, drawable);
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-
-    return TRUE;
-
-punt:
-    return EngAlphaBlend(dest, src, clip, color_trans, dest_rect, src_rect, bland);
-}
-
-BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ *color_trans,
-                                RECTL *dest_rect, RECTL *src_rect, ULONG trans_color,
-                                ULONG reserved)
-{
-    QXLDrawable *drawable;
-    PDev *pdev;
-    RECTL area;
-    RECTL local_src;
-
-    ASSERT(NULL, src && dest);
-    if (src->iType != STYPE_BITMAP) {
-        ASSERT(NULL, src->dhpdev);
-        pdev = (PDev *)src->dhpdev;
-    } else {
-        ASSERT(NULL, dest->dhpdev);
-        pdev = (PDev *)dest->dhpdev;
-    }
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-
-    PUNT_IF_DISABLED(pdev);
-
-    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
-           src_rect->top < src_rect->bottom);
-    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
-           dest_rect->top < dest_rect->bottom);
-
-    CountCall(pdev, CALL_COUNTER_TRANSPARENT_BLT);
-
-    if (!TestSrcBits(pdev, src, color_trans)) {
-        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
-        goto punt;
-    }
-
-    if (!TestStretchCondition(pdev, src, color_trans, NULL, dest_rect, src_rect)) {
-        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
-        goto punt;
-    }
-
-    FixDestParams(pdev, dest, &clip, dest_rect, &area, NULL, NULL);
-    if (IsEmptyRect(&area)) {
-        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
-        return TRUE;
-    }
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip, GetSurfaceId(dest)))) {
-        DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (FixStreatchSrcArea(dest_rect, &area, src_rect, &src->sizlBitmap, &local_src)) {
-        src_rect = &local_src;
-    }
-
-    CopyRect(&drawable->u.transparent.src_area, src_rect);
-    CopyRect(&drawable->surfaces_rects[0], src_rect);
-    if (!QXLGetBitmap(pdev, drawable, &drawable->u.transparent.src_bitmap, src,
-                      &drawable->u.transparent.src_area, color_trans, NULL, TRUE,
-                      &drawable->surfaces_dest[0])) {
-        DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
-        ReleaseOutput(pdev, drawable->release_info.id);
-        return FALSE;
-    }
-
-    drawable->u.transparent.src_color = trans_color;
-    switch (src->iBitmapFormat) {
-    case BMF_32BPP:
-    case BMF_24BPP:
-        drawable->u.transparent.true_color = trans_color;
-        break;
-    case BMF_16BPP:
-        drawable->u.transparent.true_color = _16bppTo32bpp(trans_color);
-        break;
-    case BMF_8BPP:
-    case BMF_4BPP:
-    case BMF_1BPP:
-        ASSERT(pdev, trans_color < color_trans->cEntries);
-        if (pdev->bitmap_format == BMF_32BPP) {
-            drawable->u.transparent.true_color = color_trans->pulXlate[trans_color];
-        } else {
-            ASSERT(pdev, pdev->bitmap_format == BMF_16BPP);
-            drawable->u.transparent.true_color = _16bppTo32bpp(color_trans->pulXlate[trans_color]);
-        }
-        break;
-            return color_trans && (color_trans->flXlate & XO_TABLE);
-    }
-
-    drawable->effect = QXL_EFFECT_BLEND;
-    PushDrawable(pdev, drawable);
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-
-    return TRUE;
-
-punt:
-    return EngTransparentBlt(dest, src, clip, color_trans, dest_rect, src_rect, trans_color,
-                             reserved);
-}
-
diff --git a/display/rop.h b/display/rop.h
deleted file mode 100644
index b0c7ef5..0000000
--- a/display/rop.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef _H_ROP
-#define _H_ROP
-
-#define ROP3_DEST (1 << 0)
-#define ROP3_SRC (1 << 1)
-#define ROP3_BRUSH (1 << 2)
-#define ROP3_ALL (ROP3_DEST | ROP3_SRC | ROP3_BRUSH)
-
-typedef struct ROP3Info {
-    UINT8 effect;
-    UINT8 flags;
-    UINT32 method_type;
-    UINT16 method_data;
-} ROP3Info;
-
-extern ROP3Info rops2[];
-
-BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
-                   XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
-                   POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4);
-#endif
diff --git a/display/sources b/display/sources
deleted file mode 100644
index 6c1d5c7..0000000
--- a/display/sources
+++ /dev/null
@@ -1,34 +0,0 @@
-TARGETNAME=qxldd
-TARGETPATH=obj
-TARGETTYPE=GDI_DRIVER
-
-!IFNDEF MSC_WARNING_LEVEL
-MSC_WARNING_LEVEL=/W3
-!ENDIF
-
-MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
-
-INCLUDES=$(DDK_INC_PATH); ..\include; $(SPICE_COMMON_DIR);
-
-# todo: add ntoskrnl.lib for 2008 build
-
-TARGETLIBS = $(DDK_LIB_PATH)\ntstrsafe.lib
-
-!IFNDEF DEBUG
-MSC_OPTIMIZATION = /Ox
-!ENDIF
-
-C_DEFINES = $(C_DEFINES) /DQXLDD
-
-
-SOURCES=driver.c        \
-        rop.c           \
-        res.c           \
-        text.c          \
-        pointer.c       \
-        brush.c         \
-        mspace.c        \
-        quic.c          \
-        surface.c       \
-        driver.rc
-
diff --git a/display/surface.c b/display/surface.c
deleted file mode 100644
index 2cc5895..0000000
--- a/display/surface.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "stddef.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "os_dep.h"
-
-#include "winerror.h"
-#include "windef.h"
-#include "wingdi.h"
-#include "winddi.h"
-#include "devioctl.h"
-#include "ntddvdeo.h"
-
-#include "qxldd.h"
-#include "utils.h"
-#include "mspace.h"
-#include "res.h"
-#include "surface.h"
-
-static BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, ULONG format, UINT32 cx, UINT32 cy,
-                           UINT32 stride, UINT32 surface_id)
-{
-    SIZEL  size;
-    DrawArea *drawarea;
-
-    size.cx = cx;
-    size.cy = cy;
-
-    drawarea = &GetSurfaceInfo(pdev, surface_id)->draw_area;
-
-    if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, format, 0, base_mem))) {
-        DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    if (!EngAssociateSurface(drawarea->bitmap, pdev->eng, 0)) {
-        DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
-        goto error;
-    }
-
-    if (!(drawarea->surf_obj = EngLockSurface(drawarea->bitmap))) {
-        DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__));
-        goto error;
-    }
-
-    drawarea->base_mem = base_mem;
-
-    return TRUE;
-error:
-    EngDeleteSurface(drawarea->bitmap);
-    return FALSE;
-}
-
-static VOID FreeDrawArea(DrawArea *drawarea)
-{
-    if (drawarea->surf_obj) {
-        EngUnlockSurface(drawarea->surf_obj);
-        EngDeleteSurface(drawarea->bitmap);
-        drawarea->surf_obj = NULL;
-    }
-}
-
-static void BitmapFormatToDepthAndSurfaceFormat(ULONG format, UINT32 *depth, UINT32 *surface_format)
-{
-    switch (format) {
-        case BMF_16BPP:
-            *surface_format = SPICE_SURFACE_FMT_16_555;
-            *depth = 16;
-            break;
-        case BMF_24BPP:
-        case BMF_32BPP:
-            *surface_format = SPICE_SURFACE_FMT_32_xRGB;
-            *depth = 32;
-            break;
-        default:
-            *depth = 0;
-            break;
-    };
-}
-
-static UINT8 *CreateSurfaceHelper(PDev *pdev, UINT32 surface_id,
-                                  UINT32 cx, UINT32 cy, ULONG format,
-                                  UINT8 allocation_type,
-                                  INT32 *stride, UINT32 *surface_format,
-                                  QXLPHYSICAL *phys_mem)
-{
-    UINT32 depth;
-    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
-    UINT8 *base_mem;
-    int size;
-
-    BitmapFormatToDepthAndSurfaceFormat(format, &depth, surface_format);
-    ASSERT(pdev, depth != 0);
-    ASSERT(pdev, stride);
-    QXLGetSurface(pdev, phys_mem, cx, cy, depth, stride, &base_mem, allocation_type);
-    DEBUG_PRINT((pdev, 3,
-        "%s: %d, pm %0lX, fmt %d, d %d, s (%d, %d) st %d\n",
-        __FUNCTION__, surface_id, (uint64_t)*phys_mem, *surface_format,
-        depth, cx, cy, *stride));
-    size = abs(*stride) * cy;
-    if (!base_mem) {
-        DEBUG_PRINT((pdev, 0, "%s: %p: %d: QXLGetSurface failed (%d bytes alloc)\n",
-            __FUNCTION__, pdev, surface_id, size));
-        return NULL;
-    }
-    if (!CreateDrawArea(pdev, base_mem, surface_info->bitmap_format, cx, cy, *stride, surface_id)) {
-        DEBUG_PRINT((pdev, 0, "%s: %p: CreateDrawArea failed (%d)\n",
-            __FUNCTION__, pdev, surface_id, size));
-        // TODO: Why did it fail? nothing in the MSDN
-        QXLDelSurface(pdev, base_mem, allocation_type);
-        return NULL;
-    }
-    return base_mem;
-}
-
-static void SendSurfaceCreateCommand(PDev *pdev, UINT32 surface_id, SIZEL size,
-                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem,
-                                     int keep_data)
-{
-    QXLSurfaceCmd *surface;
-
-    surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
-    if (keep_data) {
-        surface->flags |= QXL_SURF_FLAG_KEEP_DATA;
-    }
-    surface->u.surface_create.format = surface_format;
-    surface->u.surface_create.width = size.cx;
-    surface->u.surface_create.height = size.cy;
-    surface->u.surface_create.stride = stride;
-    surface->u.surface_create.data = phys_mem;
-    PushSurfaceCmd(pdev, surface);
-}
-
-HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
-{
-    UINT32 surface_format, depth;
-    HBITMAP hbitmap;
-    INT32 stride;
-    SurfaceInfo *surface_info;
-
-    DEBUG_PRINT((pdev, 9, "%s: %p: %d, (%dx%d), %d\n", __FUNCTION__, pdev, surface_id,
-                size.cx, size.cy, format));
-    surface_info = GetSurfaceInfo(pdev, surface_id);
-
-    if (!(hbitmap = EngCreateDeviceBitmap((DHSURF)surface_info, size, format))) {
-        DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n",
-                    __FUNCTION__, pdev, surface_id));
-        goto out_error1;
-    }
-
-    if (!EngAssociateSurface((HSURF)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) {
-        DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
-        goto out_error2;
-    }
-    surface_info->u.pdev = pdev;
-    surface_info->hbitmap = hbitmap;
-    surface_info->copy = NULL;
-    surface_info->size = size;
-    surface_info->bitmap_format = format;
-    if ((*base_mem = CreateSurfaceHelper(pdev, surface_id, size.cx, size.cy, format,
-                                         allocation_type, &stride, &surface_format,
-                                         phys_mem)) == NULL) {
-        DEBUG_PRINT((pdev, 0, "%s: failed, pdev 0x%lx, surface_id=%d\n",
-                    __FUNCTION__, pdev, surface_id));
-        goto out_error2;
-    }
-    surface_info->stride = stride;
-    if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
-        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem, 0);
-    }
-
-    return hbitmap;
-out_error2:
-    EngDeleteSurface((HSURF)hbitmap);
-out_error1:
-    return 0;
-}
-
-VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
-{
-    DrawArea *drawarea;
-
-    drawarea = &GetSurfaceInfo(pdev,surface_id)->draw_area;
-
-    FreeDrawArea(drawarea);
-
-    if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
-        pdev->surfaces_info[surface_id].draw_area.base_mem != NULL) {
-
-        if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_RAM) {
-            /* server side this surface is already destroyed, just free it here */
-            ASSERT(pdev, pdev->surfaces_info[surface_id].draw_area.base_mem ==
-                         pdev->surfaces_info[surface_id].copy);
-            QXLDelSurface(pdev,
-                          pdev->surfaces_info[surface_id].draw_area.base_mem,
-                          allocation_type);
-            FreeSurfaceInfo(pdev, surface_id);
-        } else {
-            QXLSurfaceCmd *surface_cmd;
-            surface_cmd = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
-            QXLGetDelSurface(pdev, surface_cmd, surface_id, allocation_type);
-            PushSurfaceCmd(pdev, surface_cmd);
-        }
-    }
-}
-
-static void CleanupSurfaceInfo(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
-{
-    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
-
-    FreeDrawArea(&surface_info->draw_area);
-    if (surface_info->draw_area.base_mem != NULL) {
-        QXLDelSurface(pdev, surface_info->draw_area.base_mem, allocation_type);
-    }
-}
-
-BOOL MoveSurfaceToVideoRam(PDev *pdev, UINT32 surface_id)
-{
-    QXLSurfaceCmd *surface;
-    UINT32 surface_format;
-    UINT32 depth;
-    int count_used = 0;
-    int size;
-    INT32 stride = 0;
-    QXLPHYSICAL phys_mem;
-    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
-    UINT32 cx = surface_info->size.cx;
-    UINT32 cy = surface_info->size.cy;
-    UINT8 *base_mem;
-
-    DEBUG_PRINT((pdev, 3, "%s: %d\n", __FUNCTION__, surface_id));
-    if ((base_mem = CreateSurfaceHelper(pdev, surface_id, cx, cy, surface_info->bitmap_format,
-                                        DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
-                                        &stride, &surface_format, &phys_mem)) == NULL) {
-        DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed\n", __FUNCTION__, pdev, surface_id));
-        return FALSE;
-    }
-    size = abs(stride) * cy;
-    if (!EngModifySurface((HSURF)surface_info->hbitmap, pdev->eng, QXL_SURFACE_HOOKS,
-        MS_NOTSYSTEMMEMORY, (DHSURF)surface_info, NULL, 0, NULL)) {
-        DEBUG_PRINT((pdev, 0, "%s: %p: %d: EngModifySurface failed\n",
-            __FUNCTION__, pdev, surface_id));
-        CleanupSurfaceInfo(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
-        return FALSE;
-    }
-    DEBUG_PRINT((pdev, 3, "%s: stride = %d, phys_mem = %0lX, base_mem = %p\n",
-        __FUNCTION__, -stride, (uint64_t)phys_mem, base_mem));
-    DEBUG_PRINT((pdev, 3, "%s: copy %d bytes to %d\n", __FUNCTION__, size, surface_id));
-    // Everything allocated, nothing can fail (API wise) from this point
-    RtlCopyMemory(base_mem, surface_info->copy, size);
-    EngFreeMem(surface_info->copy);
-    surface_info->copy = NULL;
-    SendSurfaceCreateCommand(pdev, surface_id, surface_info->size, surface_format,
-                             -stride, phys_mem, 1);
-    return TRUE;
-}
-
-/* when we return from S3 we need to resend all the surface creation commands.
- * Actually moving the memory vram<->guest is not strictly neccessary since vram
- * is not reset during the suspend, so contents are not lost */
-int MoveAllSurfacesToVideoRam(PDev *pdev)
-{
-    UINT32 surface_id;
-    SurfaceInfo *surface_info;
-
-    /* brute force implementation - alternative is to keep an updated used_surfaces list */
-    DEBUG_PRINT((pdev, 3, "%s %p\n", __FUNCTION__, pdev));
-
-    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
-        surface_info = GetSurfaceInfo(pdev, surface_id);
-        if (!surface_info->draw_area.base_mem) {
-            continue;
-        }
-        if (surface_info->u.pdev != pdev) {
-            DEBUG_PRINT((pdev, 3, "%s: %p: not our pdev (%p)\n", __FUNCTION__, pdev,
-                         surface_info->u.pdev));
-            continue;
-        }
-        if (surface_info->draw_area.surf_obj) {
-            DEBUG_PRINT((pdev, 3, "%s: surface_id = %d, surf_obj not empty\n", __FUNCTION__,
-                         surface_id));
-            continue;
-        }
-        if (surface_info->copy == NULL) {
-            DEBUG_PRINT((pdev, 3, "%s: %p: %d: no copy buffer, ignored\n", __FUNCTION__,
-                         pdev, surface_id));
-            continue;
-        }
-        if (!MoveSurfaceToVideoRam(pdev, surface_id)) {
-            /* Some of the surfaces have not been moved to video ram.
-             * they will remain managed by GDI. */
-            DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed moving to vram\n", __FUNCTION__,
-                         pdev, surface_id));
-        }
-    }
-    return TRUE;
-}
-
-/* to_surface_id is exclusive */
-static void SendSurfaceRangeCreateCommand(PDev *pdev, UINT32 from_surface_id, UINT32 to_surface_id)
-{
-    UINT32 surface_id;
-
-    ASSERT(pdev, from_surface_id < to_surface_id);
-    ASSERT(pdev, to_surface_id <= pdev->n_surfaces);
-
-    for (surface_id = from_surface_id; surface_id < to_surface_id; surface_id++) {
-        SurfaceInfo *surface_info;
-        SURFOBJ *surf_obj;
-        QXLPHYSICAL phys_mem;
-        UINT32 surface_format;
-        UINT32 depth;
-
-        surface_info = GetSurfaceInfo(pdev, surface_id);
-        if (!surface_info->draw_area.base_mem) {
-            continue;
-        }
-
-        surf_obj = surface_info->draw_area.surf_obj;
-
-        if (!surf_obj) {
-            continue;
-        }
-
-        phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
-        BitmapFormatToDepthAndSurfaceFormat(surface_info->bitmap_format, &depth, &surface_format);
-
-        SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
-                                 surface_format, -surface_info->stride, phys_mem,
-                                 /* the surface is still there, tell server not to erase */
-                                 1);
-    }
-}
-
-BOOL MoveAllSurfacesToRam(PDev *pdev)
-{
-    UINT32 surface_id;
-    SurfaceInfo *surface_info;
-    SURFOBJ *surf_obj;
-    UINT8 *copy;
-    UINT8 *line0;
-    int size;
-    QXLPHYSICAL phys_mem;
-
-    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
-        surface_info = GetSurfaceInfo(pdev, surface_id);
-        if (!surface_info->draw_area.base_mem) {
-            continue;
-        }
-        surf_obj = surface_info->draw_area.surf_obj;
-        if (!surf_obj) {
-            DEBUG_PRINT((pdev, 3, "%s: %d: no surfobj, not copying\n", __FUNCTION__, surface_id));
-            continue;
-        }
-        size = surf_obj->sizlBitmap.cy * abs(surf_obj->lDelta);
-        copy = EngAllocMem(0, size, ALLOC_TAG);
-        DEBUG_PRINT((pdev, 3, "%s: %d: copying #%d to %p (%d)\n", __FUNCTION__, surface_id, size,
-            copy, surf_obj->lDelta));
-        RtlCopyMemory(copy, surface_info->draw_area.base_mem, size);
-        surface_info->copy = copy;
-        line0 = surf_obj->lDelta > 0 ? copy : copy + abs(surf_obj->lDelta) *
-                (surf_obj->sizlBitmap.cy - 1);
-        if (!EngModifySurface((HSURF)surface_info->hbitmap,
-                      pdev->eng,
-                      0, /* from the example: used to monitor memory HOOK_COPYBITS | HOOK_BITBLT, */
-                      0,                    /* It's system-memory */
-                      (DHSURF)surface_info,
-                      line0,
-                      surf_obj->lDelta,
-                      NULL)) {
-            /* Send a create messsage for this surface - we previously did a destroy all. */
-            EngFreeMem(surface_info->copy);
-            surface_info->copy = NULL;
-            DEBUG_PRINT((pdev, 0, "%s: %d: EngModifySurface failed, sending create for %d-%d\n",
-                         __FUNCTION__, surface_id, surface_id, pdev->n_surfaces - 1));
-            SendSurfaceRangeCreateCommand(pdev, surface_id, pdev->n_surfaces);
-            return FALSE;
-        }
-        QXLDelSurface(pdev, surface_info->draw_area.base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
-        surface_info->draw_area.base_mem = copy;
-        FreeDrawArea(&surface_info->draw_area);
-    }
-    return TRUE;
-}
diff --git a/display/surface.h b/display/surface.h
deleted file mode 100644
index c3e5a47..0000000
--- a/display/surface.h
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef SURFACE_H
-#define SURFACE_H
-
-#include "qxldd.h"
-
-/* Hooks supported by our surfaces. */
-#ifdef CALL_TEST
-#define QXL_SURFACE_HOOKS_CALL_TEST \
-    (HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |  \
-    HOOK_GRADIENTFILL)
-#else
-#define QXL_SURFACE_HOOKS_CALL_TEST (0)
-#endif
-
-#define QXL_SURFACE_HOOKS \
-    (HOOK_SYNCHRONIZE | HOOK_COPYBITS |                                 \
-    HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH | HOOK_STRETCHBLT |    \
-    HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND | QXL_SURFACE_HOOKS_CALL_TEST)
-
-
-static _inline UINT32 GetSurfaceIdFromInfo(SurfaceInfo *info)
-{
-  PDev *pdev;
-
-  pdev = info->u.pdev;
-  if (info == &pdev->surface0_info) {
-    return 0;
-  }
-  return (UINT32)(info - pdev->surfaces_info);
-}
-
-static _inline SurfaceInfo *GetSurfaceInfo(PDev *pdev, UINT32 id)
-{
-  if (id == 0) {
-    return &pdev->surface0_info;
-  }
-  return &pdev->surfaces_info[id];
-}
-
-static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
-{
-    SurfaceInfo *surface;
-
-    if (!surf || !surf->dhsurf) {
-        return (UINT32)-1;
-    }
-    surface = (SurfaceInfo *)surf->dhsurf;
-    return GetSurfaceIdFromInfo(surface);
-}
-
-static _inline void FreeSurfaceInfo(PDev *pdev, UINT32 surface_id)
-{
-    SurfaceInfo *surface;
-
-    if (surface_id == 0) {
-        return;
-    }
-
-    DEBUG_PRINT((pdev, 9, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
-    surface = &pdev->surfaces_info[surface_id];
-    if (surface->draw_area.base_mem == NULL) {
-        DEBUG_PRINT((pdev, 9, "%s: %p: %d: double free. safely ignored\n", __FUNCTION__,
-                     pdev, surface_id));
-        return;
-    }
-    surface->draw_area.base_mem = NULL; /* Mark as not used */
-    surface->u.next_free = pdev->free_surfaces;
-    pdev->free_surfaces = surface;
-}
-
-static UINT32 GetFreeSurface(PDev *pdev)
-{
-    UINT32 x, id;
-    SurfaceInfo *surface;
-
-    ASSERT(pdev, pdev->enabled);
-    surface = pdev->free_surfaces;
-    if (surface == NULL) {
-        id = 0;
-    } else {
-      pdev->free_surfaces = surface->u.next_free;
-
-      id = (UINT32)(surface - pdev->surfaces_info);
-    }
-
-    return id;
-}
-
-enum {
-    DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
-    DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
-    DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
-    DEVICE_BITMAP_ALLOCATION_TYPE_RAM,
-};
-
-HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
-VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
-
-int MoveAllSurfacesToVideoRam(PDev *pdev);
-BOOL MoveAllSurfacesToRam(PDev *pdev);
-
-#endif
diff --git a/display/text.c b/display/text.c
deleted file mode 100644
index b0a516a..0000000
--- a/display/text.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "os_dep.h"
-#include "qxldd.h"
-#include "utils.h"
-#include "res.h"
-#include "rop.h"
-#include "surface.h"
-
-BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *clip,
-                         RECTL *ignored, RECTL *opaque_rect,
-                         BRUSHOBJ *fore_brush, BRUSHOBJ *back_brash,
-                         POINTL *brushs_origin, MIX mix)
-{
-    QXLDrawable *drawable;
-    ROP3Info *fore_rop;
-    ROP3Info *back_rop;
-    PDev* pdev;
-    RECTL area;
-    UINT32 surface_id;
-
-    if (!(pdev = (PDev *)surf->dhpdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    PUNT_IF_DISABLED(pdev);
-
-    surface_id = GetSurfaceId(surf);
-
-    CountCall(pdev, CALL_COUNTER_TEXT_OUT);
-
-    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
-    ASSERT(pdev, opaque_rect == NULL ||
-           (opaque_rect->left < opaque_rect->right && opaque_rect->top < opaque_rect->bottom));
-    ASSERT(pdev, surf && str && font && clip);
-
-    if (opaque_rect) {
-        CopyRect(&area, opaque_rect);
-    } else {
-        CopyRect(&area, &str->rclBkGround);
-    }
-
-    if (clip) {
-        if (clip->iDComplexity == DC_TRIVIAL) {
-            clip = NULL;
-        } else {
-            SectRect(&clip->rclBounds, &area, &area);
-            if (IsEmptyRect(&area)) {
-                DEBUG_PRINT((pdev, 1, "%s: empty rect after clip\n", __FUNCTION__));
-                return TRUE;
-            }
-        }
-    }
-
-    if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip, surface_id))) {
-        return FALSE;
-    }
-
-    if (opaque_rect) {
-        ASSERT(pdev, back_brash && brushs_origin);
-        if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin,
-                         &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
-            goto error;
-        }
-        CopyRect(&drawable->u.text.back_area, &area);
-        drawable->u.text.back_mode = SPICE_ROPD_OP_PUT;
-        drawable->effect = QXL_EFFECT_OPAQUE;
-    } else {
-        drawable->u.text.back_brush.type = SPICE_BRUSH_TYPE_NONE;
-        RtlZeroMemory(&drawable->u.text.back_area, sizeof(drawable->u.text.back_area));
-        drawable->u.text.back_mode = 0;
-        drawable->effect = QXL_EFFECT_BLEND;
-    }
-
-    fore_rop = &rops2[(mix - 1) & 0x0f];
-    back_rop = &rops2[((mix >> 8) - 1) & 0x0f];
-
-    if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
-        drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
-    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.text.fore_brush, fore_brush,
-                            brushs_origin, &drawable->surfaces_dest[1],
-                            &drawable->surfaces_rects[1])) {
-        DEBUG_PRINT((pdev, 0, "%s: get brush failed\n", __FUNCTION__));
-        goto error;
-    }
-
-    if (fore_rop->method_data != back_rop->method_data && back_rop->method_data) {
-        DEBUG_PRINT((pdev, 0, "%s: ignoring back rop, fore %u back %u\n",
-                     __FUNCTION__,
-                     (UINT32)fore_rop->method_data,
-                     (UINT32)back_rop->method_data));
-    }
-    drawable->u.text.fore_mode = fore_rop->method_data;
-
-    if (!QXLGetStr(pdev, drawable, &drawable->u.text.str, font, str)) {
-        DEBUG_PRINT((pdev, 0, "%s: get str failed\n", __FUNCTION__));
-        goto error;
-    }
-
-    PushDrawable(pdev, drawable);
-    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
-    return TRUE;
-
-error:
-    ReleaseOutput(pdev, drawable->release_info.id);
-    DEBUG_PRINT((pdev, 4, "%s: error\n", __FUNCTION__));
-    return FALSE;
-}
diff --git a/display/utils.h b/display/utils.h
deleted file mode 100644
index a8d0de6..0000000
--- a/display/utils.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef _H_UTILS
-#define _H_UTILS
-
-#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
-#define MAX(x, y) (((x) >= (y)) ? (x) : (y))
-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-
-
-#define OFFSETOF(type, member) ((UINT64)&((type *)0)->member)
-#define CONTAINEROF(ptr, type, member) \
-    ((type *) ((UINT8 *)(ptr) - OFFSETOF(type, member)))
-
-static __inline BOOL IsEmptyRect(RECTL *r)
-{
-    return r->left >= r->right || r->top >= r->bottom;
-}
-
-static __inline void SectRect(RECTL *r1, RECTL *r2, RECTL *dest)
-{
-    dest->top = MAX(r1->top, r2->top);
-    dest->bottom = MAX(MIN(r1->bottom, r2->bottom), dest->top);
-
-    dest->left = MAX(r1->left, r2->left);
-    dest->right = MAX(MIN(r1->right, r2->right), dest->left);
-}
-
-static _inline LONG RectSize(RECTL *rect)
-{
-    return (rect->right - rect->left) * (rect->bottom - rect->top);
-}
-
-#define CopyRectPoint(dest, src, width, height) \
-    (dest)->left = (src)->x; \
-    (dest)->right = (src)->x + width; \
-    (dest)->top = (src)->y; \
-    (dest)->bottom = (src)->y + height; 
-
-#define SameRect(r1, r2) ((r1)->left == (r2)->left && (r1)->right == (r2)->right && \
-                          (r1)->top == (r2)->top && (r1)->bottom == (r2)->bottom)
-
-#define CopyRect(dest, src) \
-    (dest)->top = (src)->top; \
-    (dest)->left = (src)->left; \
-    (dest)->bottom = (src)->bottom; \
-    (dest)->right = (src)->right;
-
-#define CopyPoint(dest, src) \
-    (dest)->x = (src)->x; \
-    (dest)->y = (src)->y;
-
-static __inline void FXToRect(RECTL *dest, RECTFX *src)
-{
-    dest->left = src->xLeft >> 4;
-    dest->top = src->yTop >> 4;
-    dest->right = ALIGN(src->xRight, 16) >> 4;
-    dest->bottom = ALIGN(src->yBottom, 16) >> 4;
-
-}
-
-static _inline int test_bit(void* addr, int bit)
-{
-    return !!(((UINT32 *)addr)[bit >> 5] & (1 << (bit & 0x1f)));
-}
-
-static _inline int test_bit_be(void* addr, int bit)
-{
-    return !!(((UINT8 *)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
-}
-
-static _inline BOOL PrepareBrush(BRUSHOBJ *brush)
-{
-    if (!brush || brush->iSolidColor != ~0 || brush->pvRbrush) {
-        return TRUE;
-    }
-    return BRUSHOBJ_pvGetRbrush(brush) != NULL;
-}
-
-static _inline BOOL IsCacheableSurf(SURFOBJ *surf, XLATEOBJ *color_trans)
-{
-    return surf->iUniq && !(surf->fjBitmap & BMF_DONTCACHE) &&
-                                                               (!color_trans || color_trans->iUniq);
-}
-
-static _inline UINT32 _16bppTo32bpp(UINT32 color)
-{
-    UINT32 ret;
-
-    ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
-    ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
-    ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
-
-    return ret;
-}
-
-static _inline BOOL IsUniqueSurf(SURFOBJ *surf, XLATEOBJ *color_trans)
-{
-    int pallette = color_trans && (color_trans->flXlate & XO_TABLE);
-    return surf->iUniq && (surf->fjBitmap & BMF_DONTCACHE) && (!pallette || color_trans->iUniq);
-}
-
-#endif
-
diff --git a/include/murmur_hash2a.h b/include/murmur_hash2a.h
deleted file mode 100644
index 51da7db..0000000
--- a/include/murmur_hash2a.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-//Some modifications by Red Hat any bug is probably our fault
-
-//-----------------------------------------------------------------------------
-// MurmurHash2A, by Austin Appleby
-
-// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
-// construction. Bulk speed should be identical to Murmur2, small-key speed
-// will be 10%-20% slower due to the added overhead at the end of the hash.
-
-// This variant fixes a minor issue where null keys were more likely to
-// collide with each other than expected, and also makes the algorithm
-// more amenable to incremental implementations. All other caveats from
-// MurmurHash2 still apply.
-
-#ifndef __MURMUR_HASH2A_H
-#define __MURMUR_HASH2A_H
-
-#include <windef.h>
-#include "os_dep.h"
-
-typedef UINT32 uint32_t;
-typedef UINT16 uint16_t;
-typedef UINT8 uint8_t;
-
-#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
-
-_inline uint32_t MurmurHash2A(const void * key, uint32_t len, uint32_t seed )
-{
-    const uint32_t m = 0x5bd1e995;
-    const uint32_t r = 24;
-    uint32_t l = len;
-    uint32_t t = 0;
-
-    const uint8_t * data = (const uint8_t *)key;
-
-    uint32_t h = seed;
-
-    while (len >= 4) {
-        uint32_t k = *(uint32_t*)data;
-
-        mmix(h,k);
-
-        data += 4;
-        len -= 4;
-    }
-
-    switch (len) {
-    case 3: t ^= data[2] << 16;
-    case 2: t ^= data[1] << 8;
-    case 1: t ^= data[0];
-    };
-
-    mmix(h,t);
-    mmix(h,l);
-
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-
-    return h;
-}
-
-_inline uint32_t MurmurHash2AJump3(const uint32_t * key, uint32_t len, uint32_t seed )
-{
-    uint32_t m = 0x5bd1e995;
-    uint32_t r = 24;
-    uint32_t l = len << 2;
-
-    const uint8_t * data = (const uint8_t *)key;
-
-    uint32_t h = seed;
-
-    while (len >= 4) {
-        uint32_t k = *(uint32_t*)data;
-        uint32_t tmp;
-
-        data += 4;
-        tmp = *(uint32_t *)data;
-        k = k << 8;
-        k |= (uint8_t)tmp;
-        mmix(h,k);
-
-        k = tmp << 8;
-        k = k & 0xffff0000;
-        data += 4;
-        tmp = *(uint32_t *)data;
-        k |= (uint16_t)(tmp >> 8);
-        mmix(h,k);
-
-        data += 4;
-        k = *(uint32_t *)data;
-        k = k << 8;
-        k |=  (uint8_t)tmp;
-        mmix(h,k);
-
-        data += 4;
-        len -= 4;
-    }
-
-    while (len >= 1) {
-        uint32_t k = *(uint32_t*)data;
-
-        k = k << 8;
-        mmix(h,k);
-
-        data += 4;
-        len--;
-    }
-
-    h *= m;
-    mmix(h,l);
-
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-
-    return h;
-}
-
-
-_inline uint32_t murmurhash2a(const void *key, size_t length, uint32_t initval)
-{
-    return MurmurHash2A(key, length, initval);
-}
-
-_inline uint32_t murmurhash2ajump3(const uint32_t *key, size_t length, uint32_t initval)
-{
-    return MurmurHash2AJump3(key, length, initval);
-}
-#endif
-
diff --git a/include/os_dep.h b/include/os_dep.h
deleted file mode 100644
index ad229e2..0000000
--- a/include/os_dep.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef OS_DEP_H
-#define OS_DEP_H
-
-#if (WINVER < 0x0501) //Definitions for Win2K
-typedef signed char         INT8, *PINT8;
-typedef signed short        INT16, *PINT16;
-typedef signed int          INT32, *PINT32;
-typedef signed __int64      INT64, *PINT64;
-typedef unsigned char       UINT8, *PUINT8;
-typedef unsigned short      UINT16, *PUINT16;
-typedef unsigned int        UINT32, *PUINT32;
-typedef unsigned __int64    UINT64, *PUINT64;
-
-#define SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA     0x50
-
-#define VideoPortFreePool VideoPortReleaseBuffer
-
-#endif
-
-#endif
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
deleted file mode 100644
index 677ee17..0000000
--- a/include/qxl_driver.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef _H_QXL_DRIVER
-#define _H_QXL_DRIVER
-
-#include <spice\qxl_dev.h>
-#include <spice\qxl_windows.h>
-
-#if (WINVER < 0x0501)
-#include "wdmhelper.h"
-#endif
-
-enum {
-    FIRST_AVIL_IOCTL_FUNC = 0x800,
-    QXL_GET_INFO_FUNC = FIRST_AVIL_IOCTL_FUNC,
-    QXL_SET_CUSTOM_DISPLAY
-};
-
-#define IOCTL_QXL_GET_INFO \
-    CTL_CODE(FILE_DEVICE_VIDEO, QXL_GET_INFO_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_QXL_SET_CUSTOM_DISPLAY \
-    CTL_CODE(FILE_DEVICE_VIDEO, QXL_SET_CUSTOM_DISPLAY, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define QXL_DRIVER_INFO_VERSION 3
-
-typedef struct MemSlot {
-    UINT8 generation;
-    UINT64 start_phys_addr;
-    UINT64 end_phys_addr;
-    UINT64 start_virt_addr;
-    UINT64 end_virt_addr;
-} MemSlot;
-
-typedef struct QXLDriverInfo {
-    UINT32 version;
-    QXLCommandRing *cmd_ring;
-    QXLCursorRing *cursor_ring;
-    QXLReleaseRing *release_ring;
-    PUCHAR notify_cmd_port;
-    PUCHAR notify_cursor_port;
-    PUCHAR notify_oom_port;
-    PUCHAR update_area_async_port;
-    PUCHAR memslot_add_async_port;
-    PUCHAR create_primary_async_port;
-    PUCHAR destroy_primary_async_port;
-    PUCHAR destroy_surface_async_port;
-    PUCHAR destroy_all_surfaces_async_port;
-    PUCHAR flush_surfaces_async_port;
-    PUCHAR flush_release_port;
-    PEVENT display_event;
-    PEVENT cursor_event;
-    PEVENT sleep_event;
-    PEVENT io_cmd_event;
-
-    UINT32 num_pages;
-    void *io_pages_virt;
-    UINT64 io_pages_phys;
-
-    UINT8 *surface0_area;
-    UINT32 surface0_area_size;
-
-    UINT32 *update_id;
-    UINT32 *compression_level;
-
-    PUCHAR update_area_port;
-    QXLRect *update_area;
-    UINT32 *update_surface;
-
-    UINT32 *mm_clock;
-
-    PUCHAR log_port;
-    UINT8 *log_buf;
-    UINT32 *log_level;
-#if (WINVER < 0x0501)
-    PQXLWaitForEvent WaitForEvent;
-#endif
-    UINT8 num_mem_slot;
-    UINT8 main_mem_slot_id;
-    UINT8 slot_id_bits;
-    UINT8 slot_gen_bits;
-    UINT8 *slots_generation;
-    UINT64 *ram_slot_start;
-    UINT64 *ram_slot_end;
-    MemSlot main_mem_slot;
-
-    PUCHAR destroy_surface_wait_port;
-    PUCHAR create_primary_port;
-    PUCHAR destroy_primary_port;
-    PUCHAR memslot_add_port;
-    PUCHAR memslot_del_port;
-    PUCHAR destroy_all_surfaces_port;
-
-    UCHAR  pci_revision;
-
-    UINT32 dev_id;
-
-    QXLSurfaceCreate *primary_surface_create;
-
-    UINT32 n_surfaces;
-
-    UINT64 fb_phys;
-
-    UINT8 create_non_primary_surfaces;
-} QXLDriverInfo;
-
-#endif
-
diff --git a/include/stdint.h b/include/stdint.h
deleted file mode 100644
index f825d4b..0000000
--- a/include/stdint.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/* ISO C9x  7.18  Integer types <stdint.h>
-
- * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
-
- *
-
- *  THIS SOFTWARE IS NOT COPYRIGHTED
-
- *
-
- *  Contributor: Danny Smith <danny_r_smith_2001 at yahoo.co.nz>
-
- *
-
- *  This source code is offered for use in the public domain. You may
-
- *  use, modify or distribute it freely.
-
- *
-
- *  This code is distributed in the hope that it will be useful but
-
- *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
-
- *  DISCLAIMED. This includes but is not limited to warranties of
-
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- *
-
- *  Date: 2000-12-02
-
- */
-
-
-
-
-
-#ifndef _STDINT_H
-
-#define _STDINT_H
-
-#define __need_wint_t
-
-#define __need_wchar_t
-
-#include <stddef.h>
-
-
-
-#ifdef _WIN32_WCE
-
-typedef _int64 int64_t;
-
-typedef unsigned _int64 uint64_t;
-
-#else
-
-typedef long long  int64_t;
-
-typedef unsigned long long   uint64_t;
-
-#endif /* _WIN32_WCE */
-
-
-
-/* 7.18.1.1  Exact-width integer types */
-
-typedef signed char int8_t;
-
-typedef unsigned char   uint8_t;
-
-typedef short  int16_t;
-
-typedef unsigned short  uint16_t;
-
-typedef int  int32_t;
-
-typedef unsigned   uint32_t;
-
-
-
-/* 7.18.1.2  Minimum-width integer types */
-
-typedef signed char int_least8_t;
-
-typedef unsigned char   uint_least8_t;
-
-typedef short  int_least16_t;
-
-typedef unsigned short  uint_least16_t;
-
-typedef int  int_least32_t;
-
-typedef unsigned   uint_least32_t;
-
-#ifndef _WIN32_WCE
-
-typedef long long  int_least64_t;
-
-typedef unsigned long long   uint_least64_t;
-
-#endif
-
-
-
-/*  7.18.1.3  Fastest minimum-width integer types 
-
- *  Not actually guaranteed to be fastest for all purposes
-
- *  Here we use the exact-width types for 8 and 16-bit ints. 
-
- */
-
-typedef char int_fast8_t;
-
-typedef unsigned char uint_fast8_t;
-
-typedef short  int_fast16_t;
-
-typedef unsigned short  uint_fast16_t;
-
-typedef int  int_fast32_t;
-
-typedef unsigned  int  uint_fast32_t;
-
-#ifndef _WIN32_WCE
-
-typedef long long  int_fast64_t;
-
-typedef unsigned long long   uint_fast64_t;
-
-#endif
-
-
-
-/* 7.18.1.4  Integer types capable of holding object pointers */
-
-#ifndef _WIN64
-
-typedef int intptr_t;
-
-typedef unsigned uintptr_t;
-
-#endif
-
-/* 7.18.1.5  Greatest-width integer types */
-
-#ifndef _WIN32_WCE
-
-typedef long long  intmax_t;
-
-typedef unsigned long long   uintmax_t;
-
-#endif
-
-
-
-/* 7.18.2  Limits of specified-width integer types */
-
-#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
-
-
-
-/* 7.18.2.1  Limits of exact-width integer types */
-
-#define INT8_MIN (-128) 
-
-#define INT16_MIN (-32768)
-
-#define INT32_MIN (-2147483647 - 1)
-
-#define INT64_MIN  (-9223372036854775807LL - 1)
-
-
-
-#define INT8_MAX 127
-
-#define INT16_MAX 32767
-
-#define INT32_MAX 2147483647
-
-#define INT64_MAX 9223372036854775807LL
-
-
-
-#define UINT8_MAX 0xff /* 255U */
-
-#define UINT16_MAX 0xffff /* 65535U */
-
-#define UINT32_MAX 0xffffffff  /* 4294967295U */
-
-#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
-
-
-
-/* 7.18.2.2  Limits of minimum-width integer types */
-
-#define INT_LEAST8_MIN INT8_MIN
-
-#define INT_LEAST16_MIN INT16_MIN
-
-#define INT_LEAST32_MIN INT32_MIN
-
-#define INT_LEAST64_MIN INT64_MIN
-
-
-
-#define INT_LEAST8_MAX INT8_MAX
-
-#define INT_LEAST16_MAX INT16_MAX
-
-#define INT_LEAST32_MAX INT32_MAX
-
-#define INT_LEAST64_MAX INT64_MAX
-
-
-
-#define UINT_LEAST8_MAX UINT8_MAX
-
-#define UINT_LEAST16_MAX UINT16_MAX
-
-#define UINT_LEAST32_MAX UINT32_MAX
-
-#define UINT_LEAST64_MAX UINT64_MAX
-
-
-
-/* 7.18.2.3  Limits of fastest minimum-width integer types */
-
-#define INT_FAST8_MIN INT8_MIN
-
-#define INT_FAST16_MIN INT16_MIN
-
-#define INT_FAST32_MIN INT32_MIN
-
-#define INT_FAST64_MIN INT64_MIN
-
-
-
-#define INT_FAST8_MAX INT8_MAX
-
-#define INT_FAST16_MAX INT16_MAX
-
-#define INT_FAST32_MAX INT32_MAX
-
-#define INT_FAST64_MAX INT64_MAX
-
-
-
-#define UINT_FAST8_MAX UINT8_MAX
-
-#define UINT_FAST16_MAX UINT16_MAX
-
-#define UINT_FAST32_MAX UINT32_MAX
-
-#define UINT_FAST64_MAX UINT64_MAX
-
-
-
-/* 7.18.2.4  Limits of integer types capable of holding
-
-    object pointers */ 
-
-#define INTPTR_MIN INT32_MIN
-
-#define INTPTR_MAX INT32_MAX
-
-#define UINTPTR_MAX UINT32_MAX
-
-
-
-/* 7.18.2.5  Limits of greatest-width integer types */
-
-#define INTMAX_MIN INT64_MIN
-
-#define INTMAX_MAX INT64_MAX
-
-#define UINTMAX_MAX UINT64_MAX
-
-
-
-/* 7.18.3  Limits of other integer types */
-
-#define PTRDIFF_MIN INT32_MIN
-
-#define PTRDIFF_MAX INT32_MAX
-
-
-
-#define SIG_ATOMIC_MIN INT32_MIN
-
-#define SIG_ATOMIC_MAX INT32_MAX
-
-
-
-#ifndef SIZE_MAX
-#define SIZE_MAX UINT32_MAX
-#endif
-
-
-#ifndef WCHAR_MIN  /* also in wchar.h */ 
-
-#define WCHAR_MIN 0
-
-#define WCHAR_MAX 0xffff /* UINT16_MAX */
-
-#endif
-
-
-
-/*
-
- * wint_t is unsigned short for compatibility with MS runtime
-
- */
-
-#define WINT_MIN 0
-
-#define WINT_MAX 0xffff /* UINT16_MAX */
-
-
-
-#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
-
-
-
-
-
-/* 7.18.4  Macros for integer constants */
-
-#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
-
-
-
-/* 7.18.4.1  Macros for minimum-width integer constants
-
-
-
-    Accoding to Douglas Gwyn <gwyn at arl.mil>:
-
-	"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
-
-	9899:1999 as initially published, the expansion was required
-
-	to be an integer constant of precisely matching type, which
-
-	is impossible to accomplish for the shorter types on most
-
-	platforms, because C99 provides no standard way to designate
-
-	an integer constant with width less than that of type int.
-
-	TC1 changed this to require just an integer constant
-
-	*expression* with *promoted* type."
-
-*/
-
-
-
-#define INT8_C(val) ((int8_t) + (val))
-
-#define UINT8_C(val) ((uint8_t) + (val##U))
-
-#define INT16_C(val) ((int16_t) + (val))
-
-#define UINT16_C(val) ((uint16_t) + (val##U))
-
-
-
-#define INT32_C(val) val##L
-
-#define UINT32_C(val) val##UL
-
-#define INT64_C(val) val##LL
-
-#define UINT64_C(val) val##ULL
-
-
-
-/* 7.18.4.2  Macros for greatest-width integer constants */
-
-#define INTMAX_C(val)  INT64_C(val)
-
-#define UINTMAX_C(val) UINT64_C(val)
-
-
-
-#endif  /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
-
-
-
-#endif
-
-
-
diff --git a/include/wdmhelper.h b/include/wdmhelper.h
deleted file mode 100644
index 854a4cc..0000000
--- a/include/wdmhelper.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef WDM_HELPER_H
-#define WDM_HELPER_H
-
-#include "os_dep.h"
-
-typedef ULONG (*PQXLWaitForEvent)(PVOID,PLARGE_INTEGER);
-
-LONG QXLInitializeEvent(PVOID * pEvent);
-void QXLSetEvent(PVOID pEvent);
-void QXLDeleteEvent(PVOID pEvent);
-ULONG QXLWaitForEvent(PVOID pEvent,PLARGE_INTEGER Timeout);
-
-#define VideoPortDeleteEvent(dev,pEvent) QXLDeleteEvent(pEvent)
-#define VideoPortCreateEvent(dev,flag,reserved,ppEvent) QXLInitializeEvent(ppEvent)
-#define VideoPortSetEvent(dev,pEvent) QXLSetEvent(pEvent)
-
-#endif
diff --git a/miniport/makefile b/miniport/makefile
deleted file mode 100644
index 53b9a3d..0000000
--- a/miniport/makefile
+++ /dev/null
@@ -1 +0,0 @@
-!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/miniport/minimal_snprintf.c b/miniport/minimal_snprintf.c
deleted file mode 100644
index 40572c1..0000000
--- a/miniport/minimal_snprintf.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/* $Id: snprintf.c,v 1.2 2003/12/10 01:35:10 lukem Exp $ */
-
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell (papowell at astart.com)
- * It may be used for any purpose as long as this notice remains intact
- * on all source code distributions
- */
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (dopr) included.
- * Sigh.  This sort of thing is always nasty do deal with.  Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length.  This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- *
- * More Recently:
- *  Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
- *  This was ugly.  It is still ugly.  I opted out of floating point
- *  numbers, but the formatter understands just about everything
- *  from the normal C string format, at least as far as I can tell from
- *  the Solaris 2.5 printf(3S) man page.
- *
- *  Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
- *    Ok, added some minimal floating point support, which means this
- *    probably requires libm on most operating systems.  Don't yet
- *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
- *    was pretty badly broken, it just wasn't being exercised in ways
- *    which showed it, so that's been fixed.  Also, formated the code
- *    to mutt conventions, and removed dead code left over from the
- *    original.  Also, there is now a builtin-test, just compile with:
- *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
- *    and run snprintf for results.
- *
- *  Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
- *    The PGP code was using unsigned hexadecimal formats.
- *    Unfortunately, unsigned formats simply didn't work.
- *
- *  Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
- *    The original code assumed that both snprintf() and vsnprintf() were
- *    missing.  Some systems only have snprintf() but not vsnprintf(), so
- *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
- *
- *  Andrew Tridgell (tridge at samba.org) Oct 1998
- *    fixed handling of %.0f
- *    added test for HAVE_LONG_DOUBLE
- *
- *  Luke Mewburn <lukem at NetBSD.org>, Thu Sep 30 23:28:21 EST 1999
- *	cleaned up formatting, autoconf tests
- *	added long long support
- *
- **************************************************************/
-
-#include "minimal_snprintf.h"
-
-#define MAX(a,b) ((a)>(b)?(a):(b))
-
-static _inline int isdigit(char c)
-{
-    return c >= '0' && c <= '9';
-}
-
-#if HAVE_LONG_LONG
-#define LLONG long long
-#else
-#define LLONG long
-#endif
-
-static void dopr(char *buffer, size_t maxlen, size_t *retlen,
-		    const char *format, va_list args);
-static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
-		    char *value, int min, int max, int flags);
-static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
-		    LLONG value, int base, int min, int max, int flags);
-#ifdef SUPPORT_FLOAT
-#if HAVE_LONG_DOUBLE
-#define LDOUBLE long double
-#else
-#define LDOUBLE double
-#endif
-
-static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
-		    LDOUBLE fvalue, int min, int max, int flags);
-#endif
-static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, int c);
-
-/*
- * dopr(): poor man's version of doprintf
- */
-
-/* format read states */
-#define DP_S_DEFAULT	0
-#define DP_S_FLAGS	1
-#define DP_S_MIN	2
-#define DP_S_DOT	3
-#define DP_S_MAX	4
-#define DP_S_MOD	5
-#define DP_S_CONV	6
-#define DP_S_DONE	7
-
-/* format flags - Bits */
-#define DP_F_MINUS	(1 << 0)
-#define DP_F_PLUS	(1 << 1)
-#define DP_F_SPACE	(1 << 2)
-#define DP_F_NUM	(1 << 3)
-#define DP_F_ZERO	(1 << 4)
-#define DP_F_UP		(1 << 5)
-#define DP_F_UNSIGNED	(1 << 6)
-
-/* Conversion Flags */
-#define DP_C_SHORT	1
-#define DP_C_LONG	2
-#ifdef SUPPORT_FLOAT
-#define DP_C_LDOUBLE	3
-#endif
-#define DP_C_LLONG	4
-
-#define char_to_int(p) (p - '0')
-
-static void
-dopr(char *buffer, size_t maxlen, size_t *retlen, const char *format,
-	va_list args)
-{
-	char	 ch;
-	LLONG	 value;
-#ifdef SUPPORT_FLOAT
-	LDOUBLE	 fvalue;
-#endif
-	char	*strvalue;
-	int	 min;
-	int	 max;
-	int	 state;
-	int	 flags;
-	int	 cflags;
-	size_t	 currlen;
-
-	state = DP_S_DEFAULT;
-	flags = currlen = cflags = min = 0;
-	max = -1;
-	ch = *format++;
-
-	while (state != DP_S_DONE) {
-		if ((ch == '\0') || (currlen >= maxlen))
-			state = DP_S_DONE;
-
-		switch (state) {
-		case DP_S_DEFAULT:
-			if (ch == '%')
-				state = DP_S_FLAGS;
-			else
-				dopr_outch(buffer, &currlen, maxlen, ch);
-			ch = *format++;
-			break;
-		case DP_S_FLAGS:
-			switch (ch) {
-			case '-':
-				flags |= DP_F_MINUS;
-				ch = *format++;
-				break;
-			case '+':
-				flags |= DP_F_PLUS;
-				ch = *format++;
-				break;
-			case ' ':
-				flags |= DP_F_SPACE;
-				ch = *format++;
-				break;
-			case '#':
-				flags |= DP_F_NUM;
-				ch = *format++;
-				break;
-			case '0':
-				flags |= DP_F_ZERO;
-				ch = *format++;
-				break;
-			default:
-				state = DP_S_MIN;
-				break;
-			}
-			break;
-		case DP_S_MIN:
-			if (isdigit((unsigned char) ch)) {
-				min = 10 * min + char_to_int(ch);
-				ch = *format++;
-			} else if (ch == '*') {
-				min = va_arg(args, int);
-				ch = *format++;
-				state = DP_S_DOT;
-			} else
-				state = DP_S_DOT;
-			break;
-		case DP_S_DOT:
-			if (ch == '.') {
-				state = DP_S_MAX;
-				ch = *format++;
-			} else
-				state = DP_S_MOD;
-			break;
-		case DP_S_MAX:
-			if (isdigit((unsigned char) ch)) {
-				if (max < 0)
-					max = 0;
-				max = 10 * max + char_to_int(ch);
-				ch = *format++;
-			} else if (ch == '*') {
-				max = va_arg(args, int);
-				ch = *format++;
-				state = DP_S_MOD;
-			} else
-				state = DP_S_MOD;
-			break;
-		case DP_S_MOD:
-			switch (ch) {
-			case 'h':
-				cflags = DP_C_SHORT;
-				ch = *format++;
-				break;
-			case 'l':
-				if (*format == 'l') {
-					cflags = DP_C_LLONG;
-					format++;
-				} else
-					cflags = DP_C_LONG;
-				ch = *format++;
-				break;
-			case 'q':
-				cflags = DP_C_LLONG;
-				ch = *format++;
-				break;
-#ifdef SUPPORT_FLOAT
-			case 'L':
-				cflags = DP_C_LDOUBLE;
-				ch = *format++;
-				break;
-#endif
-			default:
-				break;
-			}
-			state = DP_S_CONV;
-			break;
-		case DP_S_CONV:
-			switch (ch) {
-			case 'd':
-			case 'i':
-				switch (cflags) {
-				case DP_C_SHORT:
-					value = va_arg(args, int);
-					break;
-				case DP_C_LONG:
-					value = va_arg(args, long int);
-					break;
-				case DP_C_LLONG:
-					value = va_arg(args, LLONG);
-					break;
-				default:
-					value = va_arg(args, int);
-					break;
-				}
-				fmtint(buffer, &currlen, maxlen, value, 10,
-				    min, max, flags);
-				break;
-			case 'X':
-				flags |= DP_F_UP;
-				/* FALLTHROUGH */
-			case 'x':
-			case 'o':
-			case 'u':
-				flags |= DP_F_UNSIGNED;
-				switch (cflags) {
-				case DP_C_SHORT:
-					value = va_arg(args, unsigned int);
-					break;
-				case DP_C_LONG:
-					value = (LLONG) va_arg(args,
-					    unsigned long int);
-					break;
-				case DP_C_LLONG:
-					value = va_arg(args, unsigned LLONG);
-					break;
-				default:
-					value = (LLONG) va_arg(args,
-					    unsigned int);
-					break;
-				}
-				fmtint(buffer, &currlen, maxlen, value,
-				    ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
-				    min, max, flags);
-				break;
-#ifdef SUPPORT_FLOAT
-			case 'f':
-				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, LDOUBLE);
-				else
-					fvalue = va_arg(args, double);
-				/* um, floating point? */
-				fmtfp(buffer, &currlen, maxlen, fvalue, min,
-				    max, flags);
-				break;
-			case 'E':
-				flags |= DP_F_UP;
-			case 'e':
-				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, LDOUBLE);
-				else
-					fvalue = va_arg(args, double);
-				break;
-			case 'G':
-				flags |= DP_F_UP;
-			case 'g':
-				if (cflags == DP_C_LDOUBLE)
-					fvalue = va_arg(args, LDOUBLE);
-				else
-					fvalue = va_arg(args, double);
-				break;
-#endif // SUPPORT_FLOAT
-			case 'c':
-				dopr_outch(buffer, &currlen, maxlen,
-				    va_arg(args, int));
-				break;
-			case 's':
-				strvalue = va_arg(args, char *);
-				if (max < 0)
-					max = maxlen;	/* ie, no max */
-				fmtstr(buffer, &currlen, maxlen, strvalue,
-				    min, max, flags);
-				break;
-			case 'p':
-				value = (long)va_arg(args, void *);
-				fmtint(buffer, &currlen, maxlen,
-				    value, 16, min, max, flags);
-				break;
-			case 'n':
-/* XXX */
-				if (cflags == DP_C_SHORT) {
-					short int *num;
-					num = va_arg(args, short int *);
-					*num = (short)currlen;
-				} else if (cflags == DP_C_LONG) { /* XXX */
-					long int *num;
-					num = va_arg(args, long int *);
-					*num = (long int) currlen;
-				} else if (cflags == DP_C_LLONG) { /* XXX */
-					LLONG *num;
-					num = va_arg(args, LLONG *);
-					*num = (LLONG) currlen;
-				} else {
-					int    *num;
-					num = va_arg(args, int *);
-					*num = currlen;
-				}
-				break;
-			case '%':
-				dopr_outch(buffer, &currlen, maxlen, ch);
-				break;
-			case 'w':
-				/* not supported yet, treat as next char */
-				ch = *format++;
-				break;
-			default:
-				/* Unknown, skip */
-				break;
-			}
-			ch = *format++;
-			state = DP_S_DEFAULT;
-			flags = cflags = min = 0;
-			max = -1;
-			break;
-		case DP_S_DONE:
-			break;
-		default:
-			/* hmm? */
-			break;	/* some picky compilers need this */
-		}
-	}
-	if (currlen >= maxlen - 1)
-		currlen = maxlen - 1;
-	buffer[currlen] = '\0';
-	*retlen = currlen;
-}
-
-static void
-fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
-	int min, int max, int flags)
-{
-	int	padlen, strln;	/* amount to pad */
-	int	cnt = 0;
-
-	if (value == 0) {
-		value = "<NULL>";
-	}
-	for (strln = 0; value[strln]; ++strln)
-		;	/* strlen */
-	padlen = min - strln;
-	if (padlen < 0)
-		padlen = 0;
-	if (flags & DP_F_MINUS)
-		padlen = -padlen;	/* Left Justify */
-
-	while ((padlen > 0) && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		--padlen;
-		++cnt;
-	}
-	while (*value && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, *value++);
-		++cnt;
-	}
-	while ((padlen < 0) && (cnt < max)) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		++padlen;
-		++cnt;
-	}
-}
-/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
-
-static void
-fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base,
-	int min, int max, int flags)
-{
-	int		signvalue = 0;
-	unsigned LLONG	uvalue;
-	char		convert[20];
-	int		place = 0;
-	int		spadlen = 0;	/* amount to space pad */
-	int		zpadlen = 0;	/* amount to zero pad */
-	int		caps = 0;
-
-	if (max < 0)
-		max = 0;
-
-	uvalue = value;
-
-	if (!(flags & DP_F_UNSIGNED)) {
-		if (value < 0) {
-			signvalue = '-';
-			uvalue = -value;
-		} else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
-			signvalue = '+';
-		else if (flags & DP_F_SPACE)
-			signvalue = ' ';
-	}
-	if (flags & DP_F_UP)
-		caps = 1;	/* Should characters be upper case? */
-
-	do {
-		convert[place++] =
-		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
-		    [uvalue % (unsigned) base];
-		uvalue = (uvalue / (unsigned) base);
-	} while (uvalue && (place < 20));
-	if (place == 20)
-		place--;
-	convert[place] = 0;
-
-	zpadlen = max - place;
-	spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
-	if (zpadlen < 0)
-		zpadlen = 0;
-	if (spadlen < 0)
-		spadlen = 0;
-	if (flags & DP_F_ZERO) {
-		zpadlen = MAX(zpadlen, spadlen);
-		spadlen = 0;
-	}
-	if (flags & DP_F_MINUS)
-		spadlen = -spadlen;	/* Left Justifty */
-
-#ifdef DEBUG_SNPRINTF
-	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
-	    zpadlen, spadlen, min, max, place);
-#endif
-
-	/* Spaces */
-	while (spadlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		--spadlen;
-	}
-
-	/* Sign */
-	if (signvalue)
-		dopr_outch(buffer, currlen, maxlen, signvalue);
-
-	/* Zeros */
-	if (zpadlen > 0) {
-		while (zpadlen > 0) {
-			dopr_outch(buffer, currlen, maxlen, '0');
-			--zpadlen;
-		}
-	}
-	/* Digits */
-	while (place > 0)
-		dopr_outch(buffer, currlen, maxlen, convert[--place]);
-
-	/* Left Justified spaces */
-	while (spadlen < 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		++spadlen;
-	}
-}
-
-#ifdef SUPPORT_FLOAT
-static LDOUBLE
-abs_val(LDOUBLE value)
-{
-	LDOUBLE	result = value;
-
-	if (value < 0)
-		result = -value;
-
-	return result;
-}
-
-static LDOUBLE
-pow10(int exp)
-{
-	LDOUBLE	result = 1;
-
-	while (exp) {
-		result *= 10;
-		exp--;
-	}
-
-	return result;
-}
-
-static long
-round(LDOUBLE value)
-{
-	long	intpart;
-
-	intpart = (long) value;
-	value = value - intpart;
-	if (value >= 0.5)
-		intpart++;
-
-	return intpart;
-}
-
-static void
-fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
-	int min, int max, int flags)
-{
-	int	signvalue = 0;
-	LDOUBLE	ufvalue;
-	char	iconvert[20];
-	char	fconvert[20];
-	int	iplace = 0;
-	int	fplace = 0;
-	int	padlen = 0;	/* amount to pad */
-	int	zpadlen = 0;
-	int	caps = 0;
-	long	intpart;
-	long	fracpart;
-
-	/* AIX manpage says the default is 0, but Solaris says the default is
-	 * 6, and sprintf on AIX defaults to 6 */
-	if (max < 0)
-		max = 6;
-
-	ufvalue = abs_val(fvalue);
-
-	if (fvalue < 0)
-		signvalue = '-';
-	else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
-		signvalue = '+';
-	else if (flags & DP_F_SPACE)
-		signvalue = ' ';
-
-#if 0
-	if (flags & DP_F_UP)
-		caps = 1;	/* Should characters be upper case? */
-#endif
-
-	intpart = (long) ufvalue;
-
-	/* Sorry, we only support 9 digits past the decimal because of our
-	 * conversion method */
-	if (max > 9)
-		max = 9;
-
-	/* We "cheat" by converting the fractional part to integer by
-	 * multiplying by a factor of 10 */
-	fracpart = round((pow10(max)) * (ufvalue - intpart));
-
-	if (fracpart >= pow10(max)) {
-		intpart++;
-		fracpart -= (long)pow10(max);
-	}
-#ifdef DEBUG_SNPRINTF
-	printf("fmtfp: %g %d.%d min=%d max=%d\n",
-	    (double) fvalue, intpart, fracpart, min, max);
-#endif
-
-	/* Convert integer part */
-	do {
-		iconvert[iplace++] =
-		    (caps ? "0123456789ABCDEF"
-			  : "0123456789abcdef")[intpart % 10];
-		intpart = (intpart / 10);
-	} while (intpart && (iplace < 20));
-	if (iplace == 20)
-		iplace--;
-	iconvert[iplace] = 0;
-
-	/* Convert fractional part */
-	do {
-		fconvert[fplace++] =
-		    (caps ? "0123456789ABCDEF"
-			  : "0123456789abcdef")[fracpart % 10];
-		fracpart = (fracpart / 10);
-	} while (fracpart && (fplace < 20));
-	if (fplace == 20)
-		fplace--;
-	fconvert[fplace] = 0;
-
-	/* -1 for decimal point, another -1 if we are printing a sign */
-	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
-	zpadlen = max - fplace;
-	if (zpadlen < 0)
-		zpadlen = 0;
-	if (padlen < 0)
-		padlen = 0;
-	if (flags & DP_F_MINUS)
-		padlen = -padlen;	/* Left Justifty */
-
-	if ((flags & DP_F_ZERO) && (padlen > 0)) {
-		if (signvalue) {
-			dopr_outch(buffer, currlen, maxlen, signvalue);
-			--padlen;
-			signvalue = 0;
-		}
-		while (padlen > 0) {
-			dopr_outch(buffer, currlen, maxlen, '0');
-			--padlen;
-		}
-	}
-	while (padlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		--padlen;
-	}
-	if (signvalue)
-		dopr_outch(buffer, currlen, maxlen, signvalue);
-
-	while (iplace > 0)
-		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
-
-
-#ifdef DEBUG_SNPRINTF
-	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
-#endif
-
-	/*
-         * Decimal point.  This should probably use locale to find the correct
-         * char to print out.
-         */
-	if (max > 0) {
-		dopr_outch(buffer, currlen, maxlen, '.');
-
-		while (fplace > 0)
-			dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
-	}
-	while (zpadlen > 0) {
-		dopr_outch(buffer, currlen, maxlen, '0');
-		--zpadlen;
-	}
-
-	while (padlen < 0) {
-		dopr_outch(buffer, currlen, maxlen, ' ');
-		++padlen;
-	}
-}
-#endif // SUPPORT_FLOAT
-
-static void
-dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
-{
-	if (*currlen < maxlen)
-		buffer[(*currlen)++] = (char)c;
-}
-
-int
-vsnprintf(char *str, size_t count, const char *fmt, va_list args)
-{
-	size_t retlen;
-
-	str[0] = 0;
-	dopr(str, count, &retlen, fmt, args);
-	return (retlen);
-}
-
-/* VARARGS3 */
-int
-snprintf(char *str, size_t count, const char *fmt, ...)
-{
-	va_list	 ap;
-	int	 rv;
-
-	va_start(ap, fmt);
-	rv = vsnprintf(str, count, fmt, ap);
-	va_end(ap);
-	return (rv);
-}
diff --git a/miniport/minimal_snprintf.h b/miniport/minimal_snprintf.h
deleted file mode 100644
index e26f1da..0000000
--- a/miniport/minimal_snprintf.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MINIMAL_SNPRINTF_H
-#define MINIMAL_SNPRINTF_H
-
-#include <stdarg.h>
-
-int snprintf(char *str, size_t count, const char *fmt, ...);
-int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
-
-#endif // MINIMAL_SNPRINTF_H
diff --git a/miniport/qxl.c b/miniport/qxl.c
deleted file mode 100644
index 58ba15e..0000000
--- a/miniport/qxl.c
+++ /dev/null
@@ -1,1311 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "os_dep.h"
-#include "qxl.h"
-#if (WINVER < 0x0501)
-#include "wdmhelper.h"
-#endif
-#include "minimal_snprintf.h"
-
-VP_STATUS FindAdapter(PVOID dev_extension,
-                      PVOID reserved,
-                      PWSTR arg_str,
-                      PVIDEO_PORT_CONFIG_INFO conf_info,
-                      PUCHAR again);
-
-BOOLEAN Initialize(PVOID dev_extension);
-
-VP_STATUS GetPowerState(PVOID dev_extension,
-                        ULONG hw_id,
-                        PVIDEO_POWER_MANAGEMENT state);
-
-VP_STATUS SetPowerState(PVOID dev_extension,
-                        ULONG hw_wId,
-                        PVIDEO_POWER_MANAGEMENT state);
-
-VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
-                             IN PVIDEO_CHILD_ENUM_INFO  enum_info,
-                             OUT PVIDEO_CHILD_TYPE  type,
-                             OUT PUCHAR descriptor,
-                             OUT PULONG uid,
-                             OUT PULONG unused);
-
-BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet);
-
-BOOLEAN Interrupt(PVOID  HwDeviceExtension);
-
-#if defined(ALLOC_PRAGMA)
-#pragma alloc_text(PAGE, DriverEntry)
-#pragma alloc_text(PAGE, FindAdapter)
-#pragma alloc_text(PAGE, Initialize)
-#pragma alloc_text(PAGE, GetPowerState)
-#pragma alloc_text(PAGE, SetPowerState)
-#pragma alloc_text(PAGE, GetChildDescriptor)
-#pragma alloc_text(PAGE, StartIO)
-#endif
-
-typedef struct QXLExtension {
-    PVOID io_base;
-    PUCHAR io_port;
-
-    UCHAR pci_revision;
-
-    QXLRom *rom;
-    ULONG rom_size;
-
-    PHYSICAL_ADDRESS ram_physical;
-    UINT8 *ram_start;
-    QXLRam *ram_header;
-    ULONG ram_size;
-
-    PHYSICAL_ADDRESS vram_physical;
-    ULONG vram_size;
-    UINT8 *vram_start;
-
-    ULONG current_mode;
-    ULONG n_modes;
-    ULONG custom_mode;
-    PVIDEO_MODE_INFORMATION modes;
-
-    PEVENT display_event;
-    PEVENT cursor_event;
-    PEVENT sleep_event;
-    PEVENT io_cmd_event;
-
-    MemSlot *mem_slots;
-
-    char *log_buf;
-    PUCHAR log_port;
-
-    UINT8 create_non_primary_surfaces;
-} QXLExtension;
-
-#define QXL_ALLOC_TAG '_lxq'
-
-#define DBG_LEVEL 10
-
-#define QXL_MINIPORT_DEBUG_PREFIX "qxlmp: "
-
-void DebugPrintV(char *log_buf, PUCHAR log_port, const char *message, const char *func, va_list ap)
-{
-    int n, n_strlen;
-
-    if (log_buf && log_port) {
-        /*
-         * TODO: use a shared semaphore with display code.
-         * In practice this is not a problem, since miniport runs either on ioctls (sync)
-         * or before display is brought up or when it is brought down.
-         * Also the worst that can happen is overwriting a message (not seen in practice).
-         */
-        snprintf(log_buf, QXL_LOG_BUF_SIZE, QXL_MINIPORT_DEBUG_PREFIX);
-        vsnprintf(log_buf + strlen(QXL_MINIPORT_DEBUG_PREFIX),
-                   QXL_LOG_BUF_SIZE - strlen(QXL_MINIPORT_DEBUG_PREFIX),
-                   message, ap);
-        VideoPortWritePortUchar(log_port, 0);
-    } else {
-        VideoDebugPrint((0, (PCHAR)message, ap));
-    }
-}
-
-void DebugPrint(QXLExtension *dev, UINT32 level, const char *message, const char *func, ...)
-{
-    va_list ap;
-
-    if (dev && dev->rom && level > dev->rom->log_level) {
-        return;
-    }
-    va_start(ap, message);
-    DebugPrintV(dev ? dev->log_buf : NULL, dev ? dev->log_port : 0, message, func, ap);
-    va_end(ap);
-}
-
-ULONG DriverEntry(PVOID context1, PVOID context2)
-{
-    VIDEO_HW_INITIALIZATION_DATA init_data;
-    ULONG ret;
-
-    PAGED_CODE();
-
-    DEBUG_PRINT((NULL, 0, "%s: enter\n", __FUNCTION__));
-
-    VideoPortZeroMemory(&init_data, sizeof(VIDEO_HW_INITIALIZATION_DATA));
-    init_data.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
-    init_data.HwDeviceExtensionSize = sizeof(QXLExtension);
-
-    init_data.HwFindAdapter = FindAdapter;
-    init_data.HwInitialize = Initialize;
-    init_data.HwGetPowerState = GetPowerState;
-    init_data.HwSetPowerState = SetPowerState;
-    init_data.HwGetVideoChildDescriptor = GetChildDescriptor;
-    init_data.HwStartIO = StartIO;
-    init_data.HwInterrupt = Interrupt;
-
-    ret = VideoPortInitialize(context1, context2, &init_data, NULL);
-
-    if (ret != NO_ERROR) {
-        DEBUG_PRINT((NULL, 0, "%s: try W2K %u\n", __FUNCTION__, ret));
-        init_data.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
-        ret = VideoPortInitialize(context1, context2, &init_data, NULL);
-    }
-    DEBUG_PRINT((NULL, 0, "%s: exit %u\n", __FUNCTION__, ret));
-    return ret;
-}
-
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
-#pragma alloc_text(PAGE, InitIO)
-#endif
-
-VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
-{
-    PVOID io_base;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-
-    if ((dev->pci_revision == QXL_REVISION_STABLE_V06 &&
-         range->RangeLength < QXL_IO_DESTROY_ALL_SURFACES + 1)
-        || (dev->pci_revision > QXL_REVISION_STABLE_V06 &&
-         range->RangeLength < QXL_IO_FLUSH_RELEASE + 1)
-        || !range->RangeInIoSpace) {
-        DEBUG_PRINT((dev, 0, "%s: bad io range\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-
-    io_base = VideoPortGetDeviceBase(dev, range->RangeStart, range->RangeLength,
-                                     range->RangeInIoSpace);
-
-    if (!io_base) {
-        DEBUG_PRINT((dev, 0, "%s: get io base failed\n", __FUNCTION__));
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-
-    dev->io_base = io_base;
-    dev->io_port = (PUCHAR)range->RangeStart.LowPart;
-    dev->log_port = dev->io_port + QXL_IO_LOG;
-    DEBUG_PRINT((dev, 0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
-                 (ULONG)range->RangeStart.LowPart, range->RangeLength));
-
-    return NO_ERROR;
-}
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
-#pragma alloc_text(PAGE, InitRom)
-#endif
-
-VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
-{
-    PVOID rom = NULL;
-    ULONG rom_size = range->RangeLength;
-    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-
-    if (rom_size < sizeof(QXLRom) || range->RangeInIoSpace) {
-        DEBUG_PRINT((dev, 0, "%s: bad rom range\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-    if ((error = VideoPortMapMemory(dev, range->RangeStart,
-                                    &rom_size, &io_space,
-                                    &rom)) != NO_ERROR ) {
-        DEBUG_PRINT((dev, 0, "%s: map rom filed\n", __FUNCTION__));
-        return error;
-    }
-
-    if (rom_size < range->RangeLength) {
-        DEBUG_PRINT((dev, 0, "%s: short rom map\n", __FUNCTION__));
-        error = ERROR_NOT_ENOUGH_MEMORY;
-        goto err;
-    }
-
-    if (((QXLRom*)rom)->magic != QXL_ROM_MAGIC) {
-        DEBUG_PRINT((dev, 0, "%s: bad rom magic\n", __FUNCTION__));
-        error = ERROR_INVALID_DATA;
-        goto err;
-    }
-
-    dev->rom = rom;
-    dev->rom_size = range->RangeLength;
-    DEBUG_PRINT((dev, 0, "%s OK: rom 0x%lx size %lu\n",
-                 __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
-    return NO_ERROR;
-
-err:
-    VideoPortUnmapMemory(dev, rom, NULL);
-    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
-    return error;
-}
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
-#pragma alloc_text(PAGE, InitRam)
-#endif
-
-VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
-{
-    UINT8 *ram = NULL;
-    QXLRam *ram_header;
-    ULONG ram_size = range->RangeLength;
-    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-
-    if (ram_size < sizeof(QXLRam) + dev->rom->ram_header_offset || range->RangeInIoSpace) {
-        DEBUG_PRINT((dev, 0, "%s: bad ram range\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-
-    if (ram_size < dev->rom->num_pages << PAGE_SHIFT) {
-        DEBUG_PRINT((dev, 0, "%s: bad ram size\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-
-    if ((error = VideoPortMapMemory(dev, range->RangeStart,
-                                    &ram_size, &io_space,
-                                    &ram)) != NO_ERROR ) {
-        DEBUG_PRINT((dev, 0, "%s: map ram filed\n", __FUNCTION__));
-        return error;
-    }
-
-    if (ram_size < range->RangeLength) {
-        DEBUG_PRINT((dev, 0, "%s: short ram map\n", __FUNCTION__));
-        error = ERROR_NOT_ENOUGH_MEMORY;
-        goto err;
-    }
-    ram_header = (QXLRam *)(ram + dev->rom->ram_header_offset);
-    if (ram_header->magic != QXL_RAM_MAGIC) {
-        DEBUG_PRINT((dev, 0, "%s: bad ram magic\n", __FUNCTION__));
-        error = ERROR_INVALID_DATA;
-        goto err;
-    }
-
-    dev->ram_physical = range->RangeStart;
-    dev->ram_start = ram;
-    dev->ram_header = ram_header;
-    dev->ram_size = range->RangeLength;
-    dev->log_buf = dev->ram_header->log_buf;
-    DEBUG_PRINT((dev, 0, "%s OK: ram 0x%lx size %lu\n",
-                 __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
-    return NO_ERROR;
-
-    err:
-    VideoPortUnmapMemory(dev, ram, NULL);
-    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
-    return error;
-}
-
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
-#pragma alloc_text(PAGE, InitVRAM)
-#endif
-
-VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
-{
-    UINT8 *vram_addr = NULL;
-    ULONG vram_mapped_size = range->RangeLength;
-    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-
-    if (range->RangeLength == 0 || range->RangeInIoSpace) {
-        DEBUG_PRINT((dev, 0, "%s: bad mem range\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-
-    if ((error = VideoPortMapMemory(dev, range->RangeStart,
-                                    &vram_mapped_size,
-                                    &io_space,
-                                    &vram_addr))) {
-        DEBUG_PRINT((dev, 0, "%s: map vram failed\n",  __FUNCTION__));
-        return error;
-    }
-
-    if (vram_mapped_size < range->RangeLength) {
-        DEBUG_PRINT((dev, 0, "%s: vram shrinked\n", __FUNCTION__));
-        VideoPortUnmapMemory(dev, vram_addr, NULL);
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-    dev->vram_physical = range->RangeStart;
-    dev->vram_start = vram_addr;
-    dev->vram_size = range->RangeLength;
-    DEBUG_PRINT((dev, 0, "%s: OK, vram 0x%lx size %lu vaddr 0x%lx\n", __FUNCTION__,
-                (ULONG)range->RangeStart.QuadPart, range->RangeLength, dev->vram_start));
-    return NO_ERROR;
-}
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
-               PVIDEO_ACCESS_RANGE ranges, int n_ranges);
-#pragma alloc_text(PAGE, Prob)
-#endif
-
-VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
-               PVIDEO_ACCESS_RANGE ranges, int n_ranges)
-{
-    PCI_COMMON_CONFIG pci_conf;
-    ULONG  bus_data_size;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-
-    bus_data_size = VideoPortGetBusData(dev,
-                                        PCIConfiguration,
-                                        0,
-                                        &pci_conf,
-                                        0,
-                                        sizeof(PCI_COMMON_CONFIG));
-
-    if (bus_data_size != sizeof(PCI_COMMON_CONFIG)) {
-        DEBUG_PRINT((dev, 0,  "%s: GetBusData size %d expectes %d\n",
-                     __FUNCTION__, bus_data_size, sizeof(PCI_COMMON_CONFIG)));
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    if (pci_conf.VendorID != REDHAT_PCI_VENDOR_ID) {
-        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
-                     __FUNCTION__, pci_conf.VendorID, REDHAT_PCI_VENDOR_ID));
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    if (pci_conf.DeviceID != QXL_DEVICE_ID_STABLE) {
-        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
-                     __FUNCTION__, pci_conf.DeviceID, QXL_DEVICE_ID_STABLE));
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    if (pci_conf.RevisionID < QXL_REVISION_STABLE_V06) {
-        DEBUG_PRINT((dev, 0,  "%s: bad revision 0x%x expectes at least 0x%x\n",
-                     __FUNCTION__, pci_conf.RevisionID, QXL_REVISION_STABLE_V06));
-        return ERROR_INVALID_PARAMETER;
-    }
-    dev->pci_revision = pci_conf.RevisionID;
-
-    VideoPortZeroMemory(ranges, sizeof(VIDEO_ACCESS_RANGE) * n_ranges);
-    if ((error = VideoPortGetAccessRanges(dev, 0, NULL, n_ranges,
-                                          ranges, NULL, NULL,
-                                          NULL)) != NO_ERROR ) {
-        DEBUG_PRINT((dev, 0, "%s: get access ranges failed status %u\n", __FUNCTION__, error));
-    }
-
-    if (conf_info->BusInterruptLevel == 0 && conf_info->BusInterruptVector == 0) {
-        DEBUG_PRINT((dev, 0, "%s: no interrupt\n", __FUNCTION__));
-        error = ERROR_INVALID_DATA;
-    }
-
-#ifdef DBG
-    if (error == NO_ERROR) {
-        int i;
-
-        DEBUG_PRINT((dev, 0, "%s: interrupt: vector %lu level %lu mode %s\n",
-                     __FUNCTION__,
-                     conf_info->BusInterruptVector,
-                     conf_info->BusInterruptLevel,
-                     (conf_info->InterruptMode == LevelSensitive) ? "LevelSensitive" : "Latched"));
-
-        for (i = 0; i < n_ranges; i++) {
-            DEBUG_PRINT((dev, 0, "%s: range %d start 0x%lx length %lu space %lu\n", __FUNCTION__, i,
-                         (ULONG)ranges[i].RangeStart.QuadPart,
-                         ranges[i].RangeLength,
-                         (ULONG)ranges[i].RangeInIoSpace));
-        }
-    }
-#endif
-
-    DEBUG_PRINT((dev, 0, "%s exit %lu\n", __FUNCTION__, error));
-    return error;
-}
-
-#if defined(ALLOC_PRAGMA)
-void FillVidModeBPP(VIDEO_MODE_INFORMATION *pMode, ULONG bitsR, ULONG bitsG, ULONG bitsB,
-                    ULONG maskR, ULONG maskG, ULONG maskB);
-#pragma alloc_text(PAGE, FillVidModeBPP)
-#endif
-
-/* Fills given video mode BPP related fields */
-void FillVidModeBPP(VIDEO_MODE_INFORMATION *pMode, ULONG bitsR, ULONG bitsG, ULONG bitsB,
-                    ULONG maskR, ULONG maskG, ULONG maskB)
-{
-    pMode->NumberRedBits   = bitsR;
-    pMode->NumberGreenBits = bitsG;
-    pMode->NumberBlueBits  = bitsB;
-    pMode->RedMask         = maskR;
-    pMode->GreenMask       = maskG;
-    pMode->BlueMask        = maskB;
-}
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS FillVidModeInfo(VIDEO_MODE_INFORMATION *pMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index);
-#pragma alloc_text(PAGE, FillVidModeInfo)
-#endif
-/* Fills given video mode structure */
-VP_STATUS FillVidModeInfo(VIDEO_MODE_INFORMATION *pMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index)
-{
-    unsigned bytes_pp = (bpp + 7) / 8;
-
-    if (xres <= 0 || yres <= 0)
-        return ERROR_INVALID_DATA;
-
-    VideoPortZeroMemory(pMode, sizeof(VIDEO_MODE_INFORMATION));
-
-    /*Common entries*/
-    pMode->Length                       = sizeof(VIDEO_MODE_INFORMATION);
-    pMode->ModeIndex                    = index;
-    pMode->VisScreenWidth               = xres;
-    pMode->VisScreenHeight              = yres;
-    pMode->ScreenStride                 = (xres * bytes_pp + 3) & ~0x3; /* Pixman requirement */
-    pMode->NumberOfPlanes               = 1;
-    pMode->BitsPerPlane                 = bpp;
-    pMode->Frequency                    = 60;
-    pMode->XMillimeter                  = 320;
-    pMode->YMillimeter                  = 240;
-    pMode->VideoMemoryBitmapWidth       = xres;
-    pMode->VideoMemoryBitmapHeight      = yres;
-    pMode->DriverSpecificAttributeFlags = 0;
-    pMode->AttributeFlags               = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR;
-
-    /*BPP related entries*/
-    switch (bpp)
-    {
-        case 16:
-            FillVidModeBPP(pMode, 5, 5, 5, 0x7C00, 0x3E0, 0x1F);
-            break;
-        case 24:
-        case 32:
-            FillVidModeBPP(pMode, 8, 8, 8, 0xFF0000, 0xFF00, 0xFF);
-            break;
-        default:
-            return ERROR_INVALID_DATA;
-    }
-
-    return NO_ERROR;
-}
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode);
-#pragma alloc_text(PAGE, SetVideoModeInfo)
-#endif
-
-VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode)
-{
-    ULONG color_bits;
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 5, "%s: x %u y %u bits %u stride %u orientation %u\n",
-                 __FUNCTION__, qxl_mode->x_res, qxl_mode->y_res,
-                 qxl_mode->bits, qxl_mode->stride, qxl_mode->orientation));
-
-    video_mode->Length = sizeof(VIDEO_MODE_INFORMATION);
-    video_mode->ModeIndex = qxl_mode->id;
-    video_mode->VisScreenWidth = qxl_mode->x_res;
-    video_mode->VisScreenHeight = qxl_mode->y_res;
-    video_mode->ScreenStride = qxl_mode->stride;
-    video_mode->NumberOfPlanes = 1;
-    video_mode->BitsPerPlane = qxl_mode->bits;
-    video_mode->Frequency = 100;
-    video_mode->XMillimeter = qxl_mode->x_mili;
-    video_mode->YMillimeter = qxl_mode->y_mili;
-    color_bits = (qxl_mode->bits == 16) ? 5 : 8;
-    video_mode->NumberRedBits = color_bits;
-    video_mode->NumberGreenBits = color_bits;
-    video_mode->NumberBlueBits = color_bits;
-
-    video_mode->BlueMask = (1 << color_bits) - 1;
-    video_mode->GreenMask = video_mode->BlueMask << color_bits;
-    video_mode->RedMask = video_mode->GreenMask << color_bits;
-
-    video_mode->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS;
-    video_mode->VideoMemoryBitmapWidth = qxl_mode->x_res;
-    video_mode->VideoMemoryBitmapHeight = qxl_mode->y_res;
-    video_mode->DriverSpecificAttributeFlags = qxl_mode->orientation;
-    DEBUG_PRINT((dev, 5, "%s OK\n", __FUNCTION__));
-    return NO_ERROR;
-}
-
-
-#if defined(ALLOC_PRAGMA)
-VP_STATUS InitModes(QXLExtension *dev);
-#pragma alloc_text(PAGE, InitModes)
-#endif
-
-void DestroyMemSlots(QXLExtension *dev)
-{
-    if (dev->mem_slots) {
-        VideoPortFreePool(dev, dev->mem_slots);
-        dev->mem_slots = NULL;
-    }
-}
-
-VP_STATUS InitMemSlots(QXLExtension *dev)
-{
-#if (WINVER < 0x0501) //Win2K
-    error = VideoPortAllocateBuffer(dev, dev->rom->slots_end * sizeof(MemSlot), &dev->mem_slots);
-
-    if(!dev->mem_slots || error != NO_ERROR) {
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#else
-    if (!(dev->mem_slots = VideoPortAllocatePool(dev, VpPagedPool,
-                                                 dev->rom->slots_end * sizeof(MemSlot),
-                                                 QXL_ALLOC_TAG))) {
-        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#endif
-    VideoPortZeroMemory(dev->mem_slots, dev->rom->slots_end * sizeof(MemSlot));
-
-    return NO_ERROR;
-}
-
-VP_STATUS InitModes(QXLExtension *dev)
-{
-    QXLRom *rom;
-    QXLModes *modes;
-    PVIDEO_MODE_INFORMATION modes_info;
-    ULONG n_modes;
-    ULONG i;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
-    rom = dev->rom;
-    modes = (QXLModes *)((UCHAR*)rom + rom->modes_offset);
-    if (dev->rom_size < rom->modes_offset + sizeof(QXLModes) ||
-        (n_modes = modes->n_modes) == 0 || dev->rom_size <
-        rom->modes_offset + sizeof(QXLModes) + n_modes * sizeof(QXLMode)) {
-        DEBUG_PRINT((dev, 0, "%s: bad rom size\n", __FUNCTION__));
-        return ERROR_INVALID_DATA;
-    }
-
-    n_modes += 2;
-#if (WINVER < 0x0501) //Win2K
-    error = VideoPortAllocateBuffer(dev, n_modes * sizeof(VIDEO_MODE_INFORMATION), &modes_info);
-
-    if(!modes_info || error != NO_ERROR) {
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#else
-    if (!(modes_info = VideoPortAllocatePool(dev, VpPagedPool,
-                                             n_modes * sizeof(VIDEO_MODE_INFORMATION),
-                                             QXL_ALLOC_TAG))) {
-        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#endif
-    VideoPortZeroMemory(modes_info, sizeof(VIDEO_MODE_INFORMATION) * n_modes);
-    for (i = 0; i < modes->n_modes; i++) {
-        error = SetVideoModeInfo(dev, &modes_info[i], &modes->modes[i]);
-        if (error != NO_ERROR) {
-            VideoPortFreePool(dev, modes_info);
-            DEBUG_PRINT((dev, 0, "%s: set video mode failed\n", __FUNCTION__));
-            return error;
-        }
-    }
-
-    /* 2 dummy modes for custom display resolution */
-    /* This is necessary to bypass Windows mode index check, that
-       would prevent reusing the same index */
-    dev->custom_mode = modes->n_modes;
-
-    for (i = dev->custom_mode; i <= dev->custom_mode + 1; ++i) {
-        memcpy(&modes_info[i], &modes_info[0], sizeof(VIDEO_MODE_INFORMATION));
-        modes_info[i].ModeIndex = i;
-    }
-
-    dev->n_modes = n_modes;
-    dev->modes = modes_info;
-    DEBUG_PRINT((dev, 0, "%s OK\n", __FUNCTION__));
-    return NO_ERROR;
-}
-
-#if defined(ALLOC_PRAGMA)
-void DevExternsionCleanup(QXLExtension *dev);
-#pragma alloc_text(PAGE, DevExternsionCleanup)
-#endif
-
-void DevExternsionCleanup(QXLExtension *dev)
-{
-    if (dev->sleep_event) {
-        VideoPortDeleteEvent(dev, dev->sleep_event);
-    }
-
-    if (dev->cursor_event) {
-        VideoPortDeleteEvent(dev, dev->cursor_event);
-    }
-
-    if (dev->display_event) {
-        VideoPortDeleteEvent(dev, dev->display_event);
-    }
-
-    if (dev->io_cmd_event) {
-        VideoPortDeleteEvent(dev, dev->io_cmd_event);
-    }
-
-    if (dev->rom) {
-        VideoPortUnmapMemory(dev, dev->rom, NULL);
-    }
-
-    if (dev->ram_start) {
-        VideoPortUnmapMemory(dev, dev->ram_start, NULL);
-    }
-
-    if (dev->vram_start) {
-        VideoPortUnmapMemory(dev, dev->vram_start, NULL);
-    }
-
-    if (dev->modes) {
-        VideoPortFreePool(dev, dev->modes);
-    }
-
-    if (dev->mem_slots) {
-        DestroyMemSlots(dev);
-    }
-
-    VideoPortZeroMemory(dev, sizeof(QXLExtension));
-}
-
-VP_STATUS FindAdapter(PVOID dev_extension,
-                      PVOID reserved,
-                      PWSTR arg_str,
-                      PVIDEO_PORT_CONFIG_INFO conf_info,
-                      PUCHAR again)
-{
-    QXLExtension *dev_ext = dev_extension;
-    VP_STATUS status;
-    VIDEO_ACCESS_RANGE ranges[QXL_PCI_RANGES];
-    PEVENT display_event = NULL;
-    PEVENT cursor_event = NULL;
-    PEVENT sleep_event = NULL;
-    PEVENT io_cmd_event = NULL;
-#if (WINVER >= 0x0501)
-    VPOSVERSIONINFO  sys_info;
-#endif
-
-    PAGED_CODE();
-
-    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
-
-#if (WINVER >= 0x0501)
-    VideoPortZeroMemory(&sys_info, sizeof(VPOSVERSIONINFO));
-    sys_info.Size = sizeof(VPOSVERSIONINFO);
-    if ((status = VideoPortGetVersion(dev_ext, &sys_info)) != NO_ERROR ||
-        sys_info.MajorVersion < 5 || (sys_info.MajorVersion == 5 && sys_info.MinorVersion < 1) ) {
-        DEBUG_PRINT((dev_ext, 0, "%s: err not supported, status %lu major %lu minor %lu\n",
-                     __FUNCTION__, status, sys_info.MajorVersion, sys_info.MinorVersion));
-        return ERROR_NOT_SUPPORTED;
-    }
-#endif
-
-    if (conf_info->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
-        DEBUG_PRINT((dev_ext, 0, "%s: err configInfo size\n", __FUNCTION__));
-        return ERROR_INVALID_PARAMETER;
-    }
-
-    if (conf_info->AdapterInterfaceType != PCIBus) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: not a PCI device %d\n",
-                     __FUNCTION__, conf_info->AdapterInterfaceType));
-        return ERROR_DEV_NOT_EXIST;
-    }
-
-    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &display_event)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: create display event failed %lu\n",
-                     __FUNCTION__, status));
-        return status;
-    }
-
-    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &cursor_event)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: create cursor event failed %lu\n",
-                     __FUNCTION__, status));
-        VideoPortDeleteEvent(dev_ext, display_event);
-        return status;
-    }
-
-    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &sleep_event)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: create sleep event failed %lu\n",
-                     __FUNCTION__, status));
-        VideoPortDeleteEvent(dev_ext, display_event);
-        VideoPortDeleteEvent(dev_ext, cursor_event);
-        return status;
-    }
-
-    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &io_cmd_event)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: create io_cmd event failed %lu\n",
-                     __FUNCTION__, status));
-        VideoPortDeleteEvent(dev_ext, sleep_event);
-        VideoPortDeleteEvent(dev_ext, display_event);
-        VideoPortDeleteEvent(dev_ext, cursor_event);
-        return status;
-    }
-
-    dev_ext->display_event = display_event;
-    dev_ext->cursor_event = cursor_event;
-    dev_ext->sleep_event = sleep_event;
-    dev_ext->io_cmd_event = io_cmd_event;
-
-    if ((status = Prob(dev_ext, conf_info, ranges, QXL_PCI_RANGES)) != NO_ERROR ||
-        (status = InitIO(dev_ext, &ranges[QXL_IO_RANGE_INDEX])) != NO_ERROR ||
-        (status = InitRom(dev_ext, &ranges[QXL_ROM_RANGE_INDEX])) != NO_ERROR ||
-        (status = InitRam(dev_ext, &ranges[QXL_RAM_RANGE_INDEX])) != NO_ERROR ||
-        (status = InitVRAM(dev_ext, &ranges[QXL_VRAM_RANGE_INDEX])) != NO_ERROR ||
-        (status = InitModes(dev_ext)) != NO_ERROR ||
-        (status = InitMemSlots(dev_ext)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0,  "%s: findAdapter failed\n", __FUNCTION__));
-        DevExternsionCleanup(dev_ext);
-    }
-
-    if (VideoPortSetRegistryParameters(dev_extension, L"QxlDeviceID",
-                                       &dev_ext->rom->id, sizeof(UINT32)) != NO_ERROR) {
-        DEBUG_PRINT((dev_ext, 0, "%s: write QXL ID failed\n", __FUNCTION__));
-    }
-
-    DEBUG_PRINT((dev_ext, 0, "%s: exit %lu\n", __FUNCTION__, status));
-    return status;
-}
-
-static BOOLEAN CreateMemSlots(QXLExtension *dev_ext)
-{
-    QXLMemSlot *slot;
-    UINT8 slot_id = dev_ext->rom->slots_start;
-
-    if (slot_id >= dev_ext->rom->slots_end) {
-        DEBUG_PRINT((dev_ext, 0, "%s: start_memslot bigger than nmem_slot\n", __FUNCTION__));
-        return FALSE;
-    }
-
-    dev_ext->mem_slots[slot_id].start_phys_addr = dev_ext->ram_physical.QuadPart;
-    dev_ext->mem_slots[slot_id].end_phys_addr = dev_ext->mem_slots[slot_id].start_phys_addr +
-                                                dev_ext->rom->surface0_area_size +
-                                                dev_ext->rom->num_pages * PAGE_SIZE;
-
-    dev_ext->mem_slots[slot_id].start_virt_addr = (UINT64)dev_ext->ram_start;
-    dev_ext->mem_slots[slot_id].end_virt_addr = dev_ext->mem_slots[slot_id].start_virt_addr +
-                                                dev_ext->rom->surface0_area_size +
-                                                dev_ext->rom->num_pages * PAGE_SIZE;
-
-    dev_ext->ram_header->mem_slot.mem_start = dev_ext->mem_slots[slot_id].start_phys_addr;
-    dev_ext->ram_header->mem_slot.mem_end = dev_ext->mem_slots[slot_id].end_phys_addr;
-
-    VideoPortWritePortUchar((PUCHAR)dev_ext->io_port + QXL_IO_MEMSLOT_ADD, slot_id);
-
-    dev_ext->mem_slots[slot_id].generation = dev_ext->rom->slot_generation;
-
-    return TRUE;
-}
-
-#if defined(ALLOC_PRAGMA)
-void HWReset(QXLExtension *dev_ext);
-#pragma alloc_text(PAGE, HWReset)
-#endif
-
-/* called from HWReset or after returning from sleep from SetPowerState,
- * when returning from sleep we don't want to do a redundant QXL_IO_RESET */
-static void ResetDeviceWithoutIO(QXLExtension *dev_ext)
-{
-    dev_ext->ram_header->int_mask = ~0;
-    CreateMemSlots(dev_ext);
-}
-
-void HWReset(QXLExtension *dev_ext)
-{
-    PAGED_CODE();
-    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
-    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_RESET, 0);
-    ResetDeviceWithoutIO(dev_ext);
-    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
-}
-
-BOOLEAN Initialize(PVOID dev_ext)
-{
-    PAGED_CODE();
-    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
-    HWReset(dev_ext);
-    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
-    return TRUE;
-}
-
-VP_STATUS GetPowerState(PVOID dev_extension,
-                        ULONG hw_id,
-                        PVIDEO_POWER_MANAGEMENT pm_stat)
-{
-    QXLExtension *dev = dev_extension;
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
-
-    switch (hw_id) {
-    case DISPLAY_ADAPTER_HW_ID:
-        switch (pm_stat->PowerState) {
-        case VideoPowerOn:
-        case VideoPowerStandBy:
-        case VideoPowerSuspend:
-        case VideoPowerOff:
-        case VideoPowerShutdown:
-        case VideoPowerHibernate:
-            DEBUG_PRINT((dev, 0, "%s: OK\n", __FUNCTION__));
-            return NO_ERROR;
-        }
-        break;
-    default:
-        DEBUG_PRINT((dev, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
-    }
-    DEBUG_PRINT((dev, 0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
-    return ERROR_DEVICE_REINITIALIZATION_NEEDED;
-}
-
-#ifdef DBG
-static void DebugZeroDeviceMemory(QXLExtension *dev_ext)
-{
-    // don't zero the memory if the ram_start and vram_start are not initialized (a
-    // device has been installed but the monitor is disabled)
-    if (dev_ext->ram_start == 0 || dev_ext->vram_start == 0) {
-        DEBUG_PRINT((dev_ext, 0, "%s: not zeroing memory (addresses not initialized)\n", __FUNCTION__));
-        return;
-    }
-    VideoPortZeroMemory(dev_ext->ram_start, dev_ext->ram_size);
-    VideoPortZeroMemory(dev_ext->vram_start, dev_ext->vram_size);
-}
-#else
-static _inline void DebugZeroDeviceMemory(QXLExtension *dev_ext)
-{
-}
-#endif
-
-VP_STATUS SetPowerState(PVOID dev_extension,
-                        ULONG hw_id,
-                        PVIDEO_POWER_MANAGEMENT pm_stat)
-{
-    QXLExtension *dev_ext = dev_extension;
-    PAGED_CODE();
-    DEBUG_PRINT((dev_ext, 0, "%s (%d): %d: %lu\n", __FUNCTION__, dev_ext->rom->id, hw_id, pm_stat->PowerState));
-
-    switch (hw_id) {
-    case DISPLAY_ADAPTER_HW_ID:
-        switch (pm_stat->PowerState) {
-        case VideoPowerOn:
-            ResetDeviceWithoutIO(dev_ext);
-            break;
-        case VideoPowerStandBy:
-            break;
-        case VideoPowerSuspend:
-            break;
-        case VideoPowerOff:
-            DebugZeroDeviceMemory(dev_ext);
-            break;
-        case VideoPowerShutdown:
-            /* Important: you cannot call out to qxldd.dll here or you get a BSOD. */
-            break;
-        case VideoPowerHibernate:
-            DebugZeroDeviceMemory(dev_ext);
-            break;
-        default:
-            DEBUG_PRINT((dev_ext, 0, "%s: unexpected power state\n", __FUNCTION__));
-            return ERROR_DEVICE_REINITIALIZATION_NEEDED;
-        }
-        break;
-    default:
-        DEBUG_PRINT((dev_ext, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
-        return ERROR_DEVICE_REINITIALIZATION_NEEDED;
-    }
-    return NO_ERROR;
-}
-
-VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
-                             IN PVIDEO_CHILD_ENUM_INFO enum_info,
-                             OUT PVIDEO_CHILD_TYPE type,
-                             OUT PUCHAR descriptor,
-                             OUT PULONG uid,
-                             OUT PULONG unused)
-{
-    QXLExtension *dev = dev_extension;
-    PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s: enter\n", __FUNCTION__));
-
-    switch (enum_info->ChildIndex) {
-    case 0:
-        DEBUG_PRINT((dev, 0, "%s: ACPI id %u\n", __FUNCTION__, enum_info->ACPIHwId));
-        return ERROR_NO_MORE_DEVICES;
-    case 1:
-        DEBUG_PRINT((dev, 0, "%s: Monitor\n", __FUNCTION__));
-        /*
-        *pChildType = Monitor;
-        todo: handle EDID
-        return ERROR_MORE_DATA;
-        */
-        return ERROR_NO_MORE_DEVICES;
-    }
-    DEBUG_PRINT((dev, 0, "%s: ERROR_NO_MORE_DEVICES\n", __FUNCTION__));
-    return ERROR_NO_MORE_DEVICES;
-}
-
-#if defined(ALLOC_PRAGMA)
-PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode);
-#pragma alloc_text(PAGE, FindMode)
-#endif
-
-#define IsValidMode(dev, mode) (FindMode(dev, mode) != NULL)
-
-PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode)
-{
-    VIDEO_MODE_INFORMATION *inf;
-    VIDEO_MODE_INFORMATION *end;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
-
-    inf = dev_ext->modes;
-    end = inf + dev_ext->n_modes;
-    for (; inf < end; inf++) {
-        if (inf->ModeIndex == mode) {
-            DEBUG_PRINT((dev_ext, 0, "%s: OK mode %lu res %lu-%lu orientation %lu\n", __FUNCTION__,
-                         mode, inf->VisScreenWidth, inf->VisScreenHeight,
-                         inf->DriverSpecificAttributeFlags ));
-            return inf;
-        }
-    }
-    DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
-    return NULL;
-}
-
-static VP_STATUS SetCustomDisplay(QXLExtension *dev_ext, QXLEscapeSetCustomDisplay *custom_display)
-{
-    /* alternate custom mode index */
-    if (dev_ext->custom_mode == (dev_ext->n_modes - 1))
-        dev_ext->custom_mode = dev_ext->n_modes - 2;
-    else
-        dev_ext->custom_mode = dev_ext->n_modes - 1;
-
-    return FillVidModeInfo(&dev_ext->modes[dev_ext->custom_mode],
-                           custom_display->xres, custom_display->yres,
-                           custom_display->bpp,
-                           dev_ext->custom_mode);
-}
-
-VP_STATUS QXLRegistryCallback(
-  PVOID HwDeviceExtension,
-  PVOID Context,
-  PWSTR ValueName,
-  PVOID ValueData,
-  ULONG ValueLength
-)
-{
-    QXLExtension *dev_ext = HwDeviceExtension;
-    ULONG *key_ret = (ULONG *)Context;
-
-    DEBUG_PRINT((dev_ext, 60, "%s: length %d, first byte %d\n", __FUNCTION__,
-                ValueLength, (UINT8)ValueData));
-
-    if (key_ret) {
-        *key_ret = *(PULONG)ValueData;
-    }
-    return NO_ERROR;
-}
-
-static UINT8 check_non_primary_surfaces_registry_key(QXLExtension *dev_ext)
-{
-    VP_STATUS ret;
-    ULONG key_ret;
-
-    ret = VideoPortGetRegistryParameters(
-              dev_ext,
-              L"DisableSurfaces",
-              FALSE,
-              QXLRegistryCallback,
-              &key_ret);
-    if (ret == ERROR_INVALID_PARAMETER) {
-        dev_ext->create_non_primary_surfaces = 1;
-        DEBUG_PRINT((dev_ext, 0, "%s: CreateNonPrimarySurfaces key doesn't exist, default to 1\n",
-                    __FUNCTION__));
-    } else {
-        dev_ext->create_non_primary_surfaces = 0;
-    }
-    return dev_ext->create_non_primary_surfaces;
-}
-
-BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
-{
-    QXLExtension *dev_ext = dev_extension;
-    VP_STATUS error;
-
-    PAGED_CODE();
-    DEBUG_PRINT((dev_ext, 0, "%s %d\n", __FUNCTION__, packet->IoControlCode));
-
-    switch (packet->IoControlCode) {
-    case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
-        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n", __FUNCTION__));
-        if (packet->OutputBufferLength < (packet->StatusBlock->Information =
-                                          sizeof(VIDEO_NUM_MODES))) {
-            error = ERROR_INSUFFICIENT_BUFFER;
-            goto err;
-        }
-        ((PVIDEO_NUM_MODES)packet->OutputBuffer)->NumModes = dev_ext->n_modes;
-        ((PVIDEO_NUM_MODES)packet->OutputBuffer)->ModeInformationLength =
-        sizeof(VIDEO_MODE_INFORMATION);
-        break;
-    case IOCTL_VIDEO_QUERY_AVAIL_MODES: {
-            VIDEO_MODE_INFORMATION *inf;
-            VIDEO_MODE_INFORMATION *end;
-            VIDEO_MODE_INFORMATION *out;
-
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_AVAIL_MODES\n", __FUNCTION__));
-            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
-                                              dev_ext->n_modes * sizeof(VIDEO_MODE_INFORMATION))) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-            out = packet->OutputBuffer;
-            inf = dev_ext->modes;
-            end = inf + dev_ext->n_modes;
-            for ( ;inf < end; out++, inf++) {
-                *out = *inf;
-            }
-        }
-        break;
-    case IOCTL_VIDEO_SET_CURRENT_MODE: {
-            ULONG request_mode;
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_SET_CURRENT_MODE\n", __FUNCTION__));
-            if (packet->InputBufferLength < sizeof(VIDEO_MODE)) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-            request_mode = ((PVIDEO_MODE)packet->InputBuffer)->RequestedMode;
-
-            dev_ext->current_mode = request_mode;
-            DEBUG_PRINT((dev_ext, 0, "%s: mode %u\n", __FUNCTION__, request_mode));
-            if (!IsValidMode(dev_ext, request_mode)) {
-                error = ERROR_INVALID_PARAMETER;
-                goto err;
-            }
-        }
-        break;
-    case IOCTL_VIDEO_QUERY_CURRENT_MODE: {
-            PVIDEO_MODE_INFORMATION inf;
-
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_CURRENT_MODE\n", __FUNCTION__));
-
-            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
-                                              sizeof(VIDEO_MODE_INFORMATION))) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-
-            if ((inf = FindMode(dev_ext, dev_ext->current_mode)) == NULL) {
-                DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
-                error = ERROR_INVALID_DATA;
-                goto err;
-            }
-            *(PVIDEO_MODE_INFORMATION)packet->OutputBuffer = *inf;
-        }
-        break;
-    case IOCTL_VIDEO_MAP_VIDEO_MEMORY: {
-            PVIDEO_MEMORY_INFORMATION mem_info;
-
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_MAP_VIDEO_MEMORY\n", __FUNCTION__));
-
-            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
-                                              sizeof(VIDEO_MEMORY_INFORMATION)) ||
-                                            ( packet->InputBufferLength < sizeof(VIDEO_MEMORY) ) ) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-
-            ASSERT(((PVIDEO_MEMORY)(packet->InputBuffer))->RequestedVirtualAddress == NULL);
-            mem_info = packet->OutputBuffer;
-            mem_info->VideoRamBase = mem_info->FrameBufferBase = dev_ext->vram_start;
-            mem_info->VideoRamLength = mem_info->FrameBufferLength = dev_ext->vram_size;
-#if 0
-#ifdef DBG
-            DEBUG_PRINT((dev, 0, "%s: zap\n", __FUNCTION__));
-            VideoPortZeroMemory(mem_info->VideoRamBase, mem_info->VideoRamLength);
-            DEBUG_PRINT((dev, 0, "%s: zap done\n", __FUNCTION__));
-#endif
-#endif
-        }
-        break;
-    case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: {
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY (do nothing) \n", __FUNCTION__));
-        }
-        break;
-    case IOCTL_VIDEO_RESET_DEVICE:
-        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_RESET_DEVICE\n", __FUNCTION__));
-        HWReset(dev_ext);
-        break;
-    case IOCTL_QXL_GET_INFO: {
-            QXLDriverInfo *driver_info;
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_QXL_GET_INFO\n", __FUNCTION__));
-
-            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
-                                              sizeof(QXLDriverInfo))) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-
-            driver_info = packet->OutputBuffer;
-            driver_info->version = QXL_DRIVER_INFO_VERSION;
-            driver_info->pci_revision = dev_ext->pci_revision;
-            driver_info->display_event = dev_ext->display_event;
-            driver_info->cursor_event = dev_ext->cursor_event;
-            driver_info->sleep_event = dev_ext->sleep_event;
-            driver_info->io_cmd_event = dev_ext->io_cmd_event;
-            driver_info->cmd_ring = &dev_ext->ram_header->cmd_ring;
-            driver_info->cursor_ring = &dev_ext->ram_header->cursor_ring;
-            driver_info->release_ring = &dev_ext->ram_header->release_ring;
-            driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
-            driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
-            driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
-            driver_info->update_area_async_port = dev_ext->io_port + QXL_IO_UPDATE_AREA_ASYNC;
-            driver_info->memslot_add_async_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD_ASYNC;
-            driver_info->create_primary_async_port =
-                dev_ext->io_port + QXL_IO_CREATE_PRIMARY_ASYNC;
-            driver_info->destroy_primary_async_port =
-                dev_ext->io_port + QXL_IO_DESTROY_PRIMARY_ASYNC;
-            driver_info->destroy_surface_async_port =
-                dev_ext->io_port + QXL_IO_DESTROY_SURFACE_ASYNC;
-            driver_info->destroy_all_surfaces_async_port =
-                dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES_ASYNC;
-            driver_info->flush_surfaces_async_port = dev_ext->io_port + QXL_IO_FLUSH_SURFACES_ASYNC;
-            driver_info->flush_release_port = dev_ext->io_port + QXL_IO_FLUSH_RELEASE;
-
-            driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
-            driver_info->log_buf = dev_ext->ram_header->log_buf;
-
-            driver_info->surface0_area = dev_ext->ram_start;
-            driver_info->surface0_area_size = dev_ext->rom->surface0_area_size;
-            driver_info->update_id = &dev_ext->rom->update_id;
-            driver_info->mm_clock = &dev_ext->rom->mm_clock;
-            driver_info->compression_level = &dev_ext->rom->compression_level;
-            driver_info->log_level = &dev_ext->rom->log_level;
-            driver_info->update_area_port = dev_ext->io_port + QXL_IO_UPDATE_AREA;
-            driver_info->update_area = &dev_ext->ram_header->update_area;
-            driver_info->update_surface = &dev_ext->ram_header->update_surface;
-
-            driver_info->num_pages = dev_ext->rom->num_pages;
-            driver_info->io_pages_virt = dev_ext->ram_start + driver_info->surface0_area_size;
-            driver_info->io_pages_phys = dev_ext->ram_physical.QuadPart +
-                                                                    driver_info->surface0_area_size;
-
-            driver_info->main_mem_slot_id = dev_ext->rom->slots_start;
-            driver_info->num_mem_slot = dev_ext->rom->slots_end;
-            driver_info->slot_gen_bits = dev_ext->rom->slot_gen_bits;
-            driver_info->slot_id_bits = dev_ext->rom->slot_id_bits;
-            driver_info->slots_generation = &dev_ext->rom->slot_generation;
-            driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
-            driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
-            driver_info->main_mem_slot = dev_ext->mem_slots[driver_info->main_mem_slot_id];
-
-#if (WINVER < 0x0501)
-            driver_info->WaitForEvent = QXLWaitForEvent;
-#endif
-            driver_info->destroy_surface_wait_port = dev_ext->io_port + QXL_IO_DESTROY_SURFACE_WAIT;
-            driver_info->destroy_all_surfaces_port = dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES;
-            driver_info->create_primary_port = dev_ext->io_port + QXL_IO_CREATE_PRIMARY;
-            driver_info->destroy_primary_port = dev_ext->io_port + QXL_IO_DESTROY_PRIMARY;
-            driver_info->memslot_add_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD;
-            driver_info->memslot_del_port = dev_ext->io_port + QXL_IO_MEMSLOT_DEL;
-
-            driver_info->primary_surface_create = &dev_ext->ram_header->create_surface;
-
-            driver_info->n_surfaces = dev_ext->rom->n_surfaces;
-
-            driver_info->fb_phys = dev_ext->vram_physical.QuadPart;
-
-            driver_info->dev_id = dev_ext->rom->id;
-
-            driver_info->create_non_primary_surfaces = check_non_primary_surfaces_registry_key(dev_ext);
-        }
-        break;
-
-    case IOCTL_QXL_SET_CUSTOM_DISPLAY: {
-            QXLEscapeSetCustomDisplay *custom_display;
-            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_QXL_SET_CUSTOM_DISPLAY\n", __FUNCTION__));
-
-            if (packet->InputBufferLength < (packet->StatusBlock->Information =
-                                             sizeof(QXLEscapeSetCustomDisplay))) {
-                error = ERROR_INSUFFICIENT_BUFFER;
-                goto err;
-            }
-
-            custom_display = packet->InputBuffer;
-            DEBUG_PRINT((dev_ext, 0, "%s: %dx%d@%d\n", __FUNCTION__,
-                         custom_display->xres, custom_display->yres,
-                         custom_display->bpp));
-            SetCustomDisplay(dev_ext, custom_display);
-        }
-        break;
-
-    default:
-        DEBUG_PRINT((dev_ext, 0, "%s: invalid command 0x%lx\n", __FUNCTION__, packet->IoControlCode));
-        error = ERROR_INVALID_FUNCTION;
-        goto err;
-    }
-    packet->StatusBlock->Status = NO_ERROR;
-    DEBUG_PRINT((dev_ext, 0, "%s: OK\n", __FUNCTION__));
-    return TRUE;
-err:
-    packet->StatusBlock->Information = 0;
-    packet->StatusBlock->Status = error;
-    DEBUG_PRINT((dev_ext, 0, "%s: ERR\n", __FUNCTION__));
-    return TRUE;
-}
-
-VOID InterruptCallback(PVOID dev_extension, PVOID Context)
-{
-    QXLExtension *dev_ext = dev_extension;
-    UINT32 pending = VideoPortInterlockedExchange(&dev_ext->ram_header->int_pending, 0);
-
-    if (pending & QXL_INTERRUPT_DISPLAY) {
-        VideoPortSetEvent(dev_ext, dev_ext->display_event);
-    }
-    if (pending & QXL_INTERRUPT_CURSOR) {
-        VideoPortSetEvent(dev_ext, dev_ext->cursor_event);
-    }
-    if (pending & QXL_INTERRUPT_IO_CMD) {
-        VideoPortSetEvent(dev_ext, dev_ext->io_cmd_event);
-    }
-
-    dev_ext->ram_header->int_mask = ~0;
-    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
-}
-
-BOOLEAN Interrupt(PVOID dev_extension)
-{
-    QXLExtension *dev_ext = dev_extension;
-
-    if (!(dev_ext->ram_header->int_pending & dev_ext->ram_header->int_mask)) {
-        return FALSE;
-    }
-    dev_ext->ram_header->int_mask = 0;
-    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
-
-    if (!VideoPortQueueDpc(dev_extension, InterruptCallback, NULL)) {
-        VideoPortLogError(dev_extension, NULL, E_UNEXPECTED, QXLERR_INT_DELIVERY);
-        dev_ext->ram_header->int_mask = ~0;
-        VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
-    }
-    return TRUE;
-}
diff --git a/miniport/qxl.h b/miniport/qxl.h
deleted file mode 100644
index c7df4b1..0000000
--- a/miniport/qxl.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#include "winerror.h"
-#include "devioctl.h"
-#include "miniport.h"
-#include "ntddvdeo.h"
-#include "video.h"
-
-#include "qxl_driver.h"
-
-enum {
-    QXLERR_INT_DELIVERY = 1,
-};
-
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1 << PAGE_SHIFT)
-
-#if DBG
-#define DEBUG_PRINT(arg) DebugPrint arg
-#else
-#define DEBUG_PRINT(arg)
-#endif
diff --git a/miniport/qxl.inf b/miniport/qxl.inf
deleted file mode 100644
index 9b17575..0000000
--- a/miniport/qxl.inf
+++ /dev/null
@@ -1,97 +0,0 @@
-
-; Installation inf for qxl driver
-
-[Version]
-Signature = "$CHICAGO$"
-DriverVer = 08/15/2012,1.4.2.3
-Provider = %RHAT%
-CatalogFile = qxl.cat
-Class = Display
-ClassGUID = {4d36e968-e325-11ce-bfc1-08002be10318}
-
-[DestinationDirs]
-DefaultDestDir = 11	; system32
-qxl.Miniport = 12	; drivers
-qxl.Display = 11	; system32
-
-[Manufacturer]
-%RHAT% = q, NTx86, NTamd64, NTx86.6.0, NTamd64.6.0
-
-; WinXP x86 and up
-[q.NTx86]
-%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
-
-; WinXP x64 and up
-[q.NTamd64]
-%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
-
-; Vista x86 and up
-[q.NTx86.6.0]
-%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
-
-; Vista x64 and up
-[q.NTamd64.6.0]
-%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
-
-
-[ControlFlags]
-ExcludeFromSelect = *
-
-[qxl]
-CopyFiles = qxl.Miniport, qxl.Display
-
-[qxl_vista]
-FeatureScore = FC
-CopyFiles = qxl.Miniport, qxl.Display
-
-[qxl.Miniport]
-qxl.sys
-
-[qxl.Display]
-qxldd.dll
-
-[SourceDisksNames]
-1 = %DiskId%
-
-[SourceDisksFiles]
-qxl.sys = 1
-qxldd.dll = 1
-
-[qxl.SoftwareSettings]
-AddReg = qxl_SoftwareDeviceSettings
-
-[qxl_vista.SoftwareSettings]
-AddReg = qxl_SoftwareDeviceSettings
-
-[qxl_SoftwareDeviceSettings]
-HKR,, InstalledDisplayDrivers,        %REG_MULTI_SZ%, qxldd
-HKR,, VgaCompatible,                  %REG_DWORD%,    0
-HKR,, DefaultSettings.BitsPerPel,     %REG_DWORD%,    32
-HKR,, DefaultSettings.XResolution,    %REG_DWORD%,    800
-HKR,, DefaultSettings.YResolution,    %REG_DWORD%,    600
-HKR,, Acceleration.Level,             %REG_DWORD%,    0
-
-[qxl.Services]
-AddService = qxl, 0x00000002, qxl_Service_Inst ; Assign the named service as the PnP function driver
-
-[qxl_vista.Services]
-AddService = qxl, 0x00000002, qxl_Service_Inst ; Assign the named service as the PnP function driver
-
-[qxl_Service_Inst]
-ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
-StartType      = 3                  ; SERVICE_DEMAND_START
-ErrorControl   = 0                  ; SERVICE_ERROR_IGNORE
-LoadOrderGroup = Video
-ServiceBinary  = %12%\qxl.sys
-
-[Strings]
-RHAT = "Red Hat"
-QXL = "QXL GPU"
-DiskId = "Windows 2000 Driver Installation Disk"
-
-REG_SZ         = 0x00000000
-REG_MULTI_SZ   = 0x00010000
-REG_EXPAND_SZ  = 0x00020000
-REG_BINARY     = 0x00000001
-REG_DWORD      = 0x00010001
-FLG_ADDREG_DELVAL = 0x00000004
diff --git a/miniport/qxl.rc b/miniport/qxl.rc
deleted file mode 100644
index 50abefe..0000000
--- a/miniport/qxl.rc
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <windows.h>
-
-#include <ntverp.h>
-
-#define VER_FILETYPE                VFT_DRV
-#define VER_FILESUBTYPE             VFT2_DRV_DISPLAY
-
-#undef  VER_COMPANYNAME_STR
-#undef  VER_FILEVERSION_STR
-#undef  VER_LEGALCOPYRIGHT_STR
-#undef  VER_LEGALCOPYRIGHT_YEARS
-#undef  VER_PRODUCTNAME_STR
-#undef  VER_PRODUCTVERSION_STR
-
-
-#define VER_FILEDESCRIPTION_STR     "Red Hat QXL Display Driver"
-#define VER_INTERNALNAME_STR        "qxl.sys"
-#define VER_ORIGINALFILENAME_STR    VER_INTERNALNAME_STR
-#define VER_FILEVERSION_STR         "1.4.2.3"
-#define VER_PRODUCTNAME_STR         "Spice"
-#define VER_PRODUCTVERSION_STR      "1.4.2.3"
-
-#undef  VER_PRODUCTVERSION
-#define VER_PRODUCTVERSION           1,4,2,3
-
-#define VER_COMPANYNAME_STR         "Red Hat Inc."
-#define VER_LEGALCOPYRIGHT_STR      "© Red Hat Inc. All rights reserved."
-
-#include "common.ver"
diff --git a/miniport/sources b/miniport/sources
deleted file mode 100644
index 8d96e14..0000000
--- a/miniport/sources
+++ /dev/null
@@ -1,29 +0,0 @@
-TARGETNAME=qxl
-TARGETPATH=obj
-TARGETTYPE=MINIPORT
-
-TARGETLIBS=$(DDK_LIB_PATH)\videoprt.lib 
-
-!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K"
-#
-# The driver is built in the Win2K build environment
-#
-TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\ntoskrnl.lib
-!endif
-
-
-AXP64_FLAGS=/QA21164
-
-!IFNDEF MSC_WARNING_LEVEL
-MSC_WARNING_LEVEL=/W3
-!ENDIF
-MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
-
-INCLUDES=$(SPICE_COMMON_DIR); ..\include
-
-SOURCES=qxl.c      \
-		minimal_snprintf.c \
-		wdmhelper.c \
-        qxl.rc
-
-MISCFILES=qxl.inf
diff --git a/miniport/wdmhelper.c b/miniport/wdmhelper.c
deleted file mode 100644
index 5af1909..0000000
--- a/miniport/wdmhelper.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This software is licensed under the GNU General Public License,
-   version 2 (GPLv2) (see COPYING for details), subject to the
-   following clarification.
-
-   With respect to binaries built using the Microsoft(R) Windows
-   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
-   derived from the WDK ("WDK Code").  As to WDK Code, by using or
-   distributing such binaries you agree to be bound by the Microsoft
-   Software License Terms for the WDK.  All WDK Code is considered by
-   the GPLv2 licensors to qualify for the special exception stated in
-   section 3 of GPLv2 (commonly known as the system library
-   exception).
-
-   There is NO WARRANTY for this software, express or implied,
-   including the implied warranties of NON-INFRINGEMENT, TITLE,
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#if (WINVER < 0x0501)
-#include <ntddk.h>
-#include "wdmhelper.h"
-
-void QXLDeleteEvent(PVOID pEvent)
-{
-    if(pEvent) {
-        ExFreePool(pEvent);
-    }
-}
-
-LONG QXLInitializeEvent(PVOID * pEvent)
-{
-    if(pEvent) {
-        *pEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), '_lxq');
-
-        if(*pEvent) {
-            KeInitializeEvent((PRKEVENT)*pEvent, SynchronizationEvent, FALSE);
-        }
-    }
-
-    return 0;
-}
-
-void QXLSetEvent(PVOID pEvent)
-{
-    //Pririty boost can be switched to IO_NO_INCREMENT
-    if(pEvent) {
-        KeSetEvent((PRKEVENT)pEvent, IO_VIDEO_INCREMENT, FALSE);
-    }
-}
-
-ULONG QXLWaitForEvent(PVOID pEvent, PLARGE_INTEGER Timeout)
-{
-    if(pEvent) {
-        return NT_SUCCESS(KeWaitForSingleObject(pEvent, Executive, KernelMode, TRUE, Timeout));
-    }
-
-    return FALSE;
-}
-
-#endif
-
diff --git a/scripts/buildAll.bat b/scripts/buildAll.bat
deleted file mode 100644
index 24c81ea..0000000
--- a/scripts/buildAll.bat
+++ /dev/null
@@ -1,75 +0,0 @@
-REM Copyright Red Hat 2007-2011
-REM Authors: Yan Vugenfirer
-REM          Arnon Gilboa
-REM          Uri Lublin
-:
-: Set global parameters: 
-:
-
-: Use Windows 7 DDK
-if "%DDKVER%"=="" set DDKVER=7600.16385.0
-
-: By default DDK is installed under C:\WINDDK, but it can be installed in different location
-if "%DDKINSTALLROOT%"=="" set DDKINSTALLROOT=C:\WINDDK\
-set BUILDROOT=%DDKINSTALLROOT%%DDKVER%
-set X64ENV=x64
-if "%DDKVER%"=="6000" set X64ENV=amd64
-if "%BUILDCFG%"=="" set BUILDCFG=fre
-
-if not "%1"=="" goto parameters_here
-echo no parameters specified, exiting
-goto :eof
-:parameters_here
-
-:nextparam
-if "%1"=="" goto :eof
-goto %1
-:continue
-shift
-goto nextparam
-
-:fre
-set BUILDCFG=fre
-goto continue
-
-:chk
-set BUILDCFG=chk
-goto continue
-
-:Win7
-set BUILDENV=WIN7
-goto build_it
-
-:Win7_64
-set BUILDENV=%X64ENV% WIN7
-goto build_it
-
-:Vista
-set BUILDENV=Wlh
-goto build_it
-
-:Vista64
-set BUILDENV=%X64ENV% Wlh
-goto build_it
-
-:Win2003
-set BUILDENV=WNET
-goto build_it
-
-:Win200364
-set BUILDENV=%X64ENV% WNET
-goto build_it
-
-:XP
-set BUILDENV=WXP
-goto build_it
-
-:build_it
-set DDKBUILDENV=
-pushd %BUILDROOT%
-call %BUILDROOT%\bin\setenv.bat %BUILDROOT% %BUILDCFG% %BUILDENV%
-popd
-build -cZg
-
-goto continue
-
diff --git a/scripts/clean.bat b/scripts/clean.bat
deleted file mode 100644
index acc3bc3..0000000
--- a/scripts/clean.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-REM Copyright Red Hat 2009-2011
-REM Authors: Arnon Gilboa 
-:rmdir /S /Q Debug
-rmdir /S /Q Release
-for /d %%a in (obj*) do rd /s /q "%%a"
-del /F *.log *.wrn *.err
diff --git a/xddm/COPYING b/xddm/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/xddm/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/xddm/build.bat b/xddm/build.bat
new file mode 100755
index 0000000..1d19875
--- /dev/null
+++ b/xddm/build.bat
@@ -0,0 +1,45 @@
+ at echo off
+
+Rem
+Rem Build and copy to target based on environment variables set by WinDDK\bin\setenv.
+Rem if an argument is supplied the build products are copied there too under a subdirectory.
+Rem
+
+Rem Just use %BUILD_ALT_DIR%, it is equivalent
+Rem set TARGET=%DDK_TARGET_OS%_%_BUILDARCH%_%BUILD_TYPE%
+
+if not DEFINED BUILD_ALT_DIR (
+ echo BUILD_ALT_DIR not defined. Please run in a WinDDK Build Environment.
+ goto exit
+)
+if not DEFINED SPICE_COMMON_DIR (
+ set SPICE_COMMON_DIR=%CD%\..\spice-protocol
+)
+
+set TARGET=install_%BUILD_ALT_DIR%
+echo TARGET=%TARGET%
+if not exist %TARGET% mkdir %TARGET%
+
+if not x%1 == x set DEST=%1
+
+:build
+cd miniport
+build -cZg
+cd ../display
+build -cZg
+cd ../
+
+:copy_local
+copy display\obj%BUILD_ALT_DIR%\i386\qxldd.dll %TARGET%
+copy miniport\obj%BUILD_ALT_DIR%\i386\qxl.sys %TARGET%
+copy miniport\qxl.inf %TARGET%
+copy display\obj%BUILD_ALT_DIR%\i386\qxldd.pdb %TARGET%
+copy miniport\obj%BUILD_ALT_DIR%\i386\qxl.pdb %TARGET%
+if not defined DEST goto exit
+if exist %DEST% (
+ echo copying to %DEST%
+ if not exist %DEST%\%TARGET% ( mkdir "%DEST%\%TARGET%" )
+ xcopy /s /y %TARGET% %DEST%\%TARGET%
+)
+
+:exit
diff --git a/xddm/dirs b/xddm/dirs
new file mode 100644
index 0000000..94db1d0
--- /dev/null
+++ b/xddm/dirs
@@ -0,0 +1,4 @@
+DIRS= \
+     display \
+     miniport
+
diff --git a/xddm/display/brush.c b/xddm/display/brush.c
new file mode 100644
index 0000000..0b9400d
--- /dev/null
+++ b/xddm/display/brush.c
@@ -0,0 +1,400 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "os_dep.h"
+#include "qxldd.h"
+#include "utils.h"
+#include "res.h"
+
+typedef struct InternalBrush {
+    ULONG format;
+    SIZEL size;
+    UINT32 stride;
+    UINT32 key;
+    UINT8 data[0];
+} InternalBrush;
+
+#define COPY1BPP(bits)                                                                  \
+static _inline void realizeBrush##bits##Copy1bpp(PDev *pdev, InternalBrush *internal,   \
+                                                 UINT8 *src, LONG src_stride,           \
+                                                 XLATEOBJ *color_trans)                 \
+{                                                                                       \
+    UINT8 *end = src + src_stride * internal->size.cy;                                  \
+    UINT8 *dest = internal->data;                                                       \
+                                                                                        \
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
+    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
+    for (; src < end; src += src_stride, dest += internal->stride) {                    \
+        UINT##bits *now = (UINT##bits *)dest;                                           \
+        int i;                                                                          \
+                                                                                        \
+        for (i = 0; i < internal->size.cx; i++) {                                       \
+            *(now++) = (UINT##bits)color_trans->pulXlate[test_bit_be(src, i)];          \
+        }                                                                               \
+    }                                                                                   \
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
+}
+
+#define COPY4BPP(bits)                                                                  \
+static _inline void realizeBrush##bits##Copy4bpp(PDev *pdev, InternalBrush *internal,   \
+                                                 UINT8 *src, LONG src_stride,           \
+                                                 XLATEOBJ *color_trans)                 \
+{                                                                                       \
+    UINT8 *dest = internal->data;                                                       \
+    UINT8 *end = dest + internal->stride * internal->size.cy;                           \
+                                                                                        \
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
+    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
+    for (; dest < end; dest += internal->stride, src += src_stride) {                   \
+        UINT8 *src_line = src;                                                          \
+        UINT8 *src_line_end = src_line + (internal->size.cx >> 1);                      \
+        UINT##bits *dest_line = (UINT##bits *)dest;                                     \
+                                                                                        \
+        for (; src_line < src_line_end; src_line++) {                                   \
+            ASSERT(pdev, (*src_line & 0x0fU) < color_trans->cEntries);                  \
+            ASSERT(pdev, ((*src_line >> 4) & 0x0fU) < color_trans->cEntries);           \
+            *(dest_line++) = (UINT##bits)color_trans->pulXlate[(*src_line >> 4) & 0x0f];\
+            *(dest_line++) = (UINT##bits)color_trans->pulXlate[*src_line & 0x0f];       \
+        }                                                                               \
+        if (internal->size.cx & 1) {                                                    \
+            *(dest_line) = (UINT##bits)color_trans->pulXlate[(*src_line >> 4) & 0x0f];  \
+        }                                                                               \
+    }                                                                                   \
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
+}
+
+#define COPY8BPP(bits)                                                                  \
+static _inline void realizeBrush##bits##Copy8bpp(PDev *pdev, InternalBrush *internal,   \
+                                                 UINT8 *src, LONG src_stride,           \
+                                                 XLATEOBJ *color_trans)                 \
+{                                                                                       \
+    UINT8 *dest = internal->data;                                                       \
+    UINT8 *end = dest + internal->stride * internal->size.cy;                           \
+                                                                                        \
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));                                       \
+    ASSERT(pdev, color_trans && color_trans->flXlate & XO_TABLE);                       \
+    for (; dest < end; dest += internal->stride, src += src_stride) {                   \
+        UINT8 *src_line = src;                                                          \
+        UINT8 *src_line_end = src_line + internal->size.cx;                             \
+        UINT##bits *dest_line = (UINT##bits *)dest;                                     \
+                                                                                        \
+        for (; src_line < src_line_end; ++dest_line, src_line++) {                      \
+            ASSERT(pdev, *src_line < color_trans->cEntries);                            \
+            *dest_line = (UINT##bits)color_trans->pulXlate[*src_line];                  \
+        }                                                                               \
+    }                                                                                   \
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));                                 \
+}
+
+COPY1BPP(16);
+COPY1BPP(32);
+COPY4BPP(16);
+COPY4BPP(32);
+COPY8BPP(16);
+COPY8BPP(32);
+
+static _inline void realizeBrush32Copy16bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *dest = internal->data;
+    UINT8 *end = dest + internal->stride * internal->size.cy;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; dest < end; dest += internal->stride, src += src_stride) {
+        UINT32 *dest_line = (UINT32 *)dest;
+        UINT32 *dest_line_end = dest_line + internal->size.cx;
+        UINT16 *src_line = (UINT16 *)src;
+
+        for (; dest_line < dest_line_end; ++dest_line, src_line++) {
+            *dest_line = _16bppTo32bpp(*src_line);
+        }
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+static _inline void realizeBrush32Copy24bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *dest = internal->data;
+    UINT8 *end = dest + internal->stride * internal->size.cy;
+    int line_size = internal->size.cx << 2;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; dest < end; dest += internal->stride, src += src_stride) {
+        UINT8* dest_line = dest;
+        UINT8* dest_line_end = dest_line + line_size;
+        UINT8* src_line = src;
+
+        while (dest_line < dest_line_end) {
+            *(dest_line++) = *(src_line++);
+            *(dest_line++) = *(src_line++);
+            *(dest_line++) = *(src_line++);
+            *(dest_line++) = 0;
+        }
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+static _inline void realizeBrush32Copy32bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *now = internal->data;
+    UINT8 *end = now + internal->stride * internal->size.cy;
+    int line_size = internal->size.cx << 2;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; now < end; now += internal->stride, src += src_stride) {
+        RtlCopyMemory(now, src, line_size);
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+static _inline void realizeBrush16Copy16bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *dest = internal->data;
+    UINT8 *end = dest + internal->stride * internal->size.cy;
+    int line_size = internal->size.cx << 1;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; dest < end; dest += internal->stride, src += src_stride) {
+        RtlCopyMemory(dest, src, line_size);
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+static _inline void realizeBrush16Copy24bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *dest = internal->data;
+    UINT8 *end = dest + internal->stride * internal->size.cy;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; dest < end; dest += internal->stride, src += src_stride) {
+        UINT16 *dest_line = (UINT16 *)dest;
+        UINT16 *dest_line_end = dest_line + internal->size.cx;
+        UINT8 *src_line = src;
+
+        while (dest_line < dest_line_end) {
+            *(dest_line++) = ((UINT16)*(src_line++) >> 3) |
+                             (((UINT16)*(src_line++) & 0xf8) << 2) |
+                             (((UINT16)*(src_line++) & 0xf8) << 7);
+        }
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+UINT16 _32bppTo16bpp(UINT32 color)
+{
+    return ((color & 0xf8) >> 3) | ((color & 0xf800) >> 6) | ((color & 0xf80000) >> 9);
+}
+
+static _inline void realizeBrush16Copy32bpp(PDev *pdev, InternalBrush *internal, UINT8 *src,
+                                          LONG src_stride)
+{
+    UINT8 *now = internal->data;
+    UINT8 *end = now + internal->stride * internal->size.cy;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    for (; now < end; now += internal->stride, src += src_stride) {
+        UINT16 *dest_line = (UINT16 *)now;
+        UINT16 *dest_line_end = dest_line + internal->size.cx;
+        UINT32 *src_line = (UINT32 *)src;
+
+        while (dest_line < dest_line_end) {
+            *(dest_line++) = _32bppTo16bpp(*(src_line++));
+        }
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+}
+
+BOOL APIENTRY DrvRealizeBrush(BRUSHOBJ *brush, SURFOBJ *target, SURFOBJ *pattern, SURFOBJ *mask,
+                              XLATEOBJ *color_trans, ULONG hatch)
+{
+    PDev *pdev;
+    InternalBrush *internal;
+    int stride;
+    int size;
+
+    if (!(pdev = (PDev *)target->dhpdev)) {
+        ASSERT(NULL, 0);
+        return FALSE;
+    }
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    if (mask) {
+        DEBUG_PRINT((pdev, 0, "%s: ignoring mask\n", __FUNCTION__));
+    }
+
+    switch (pattern->iBitmapFormat) {
+    case BMF_1BPP:
+    case BMF_32BPP:
+    case BMF_24BPP:
+    case BMF_16BPP:
+    case BMF_8BPP:
+    case BMF_4BPP:
+        break;
+    default:
+        DEBUG_PRINT((pdev, 0, "%s: bad format\n", __FUNCTION__));
+        return FALSE;
+    }
+    stride = (pdev->bitmap_format == BMF_32BPP) ? pattern->sizlBitmap.cx << 2 :
+                                                 ALIGN(pattern->sizlBitmap.cx << 1, 4);
+    size = stride * pattern->sizlBitmap.cy;
+    size += sizeof(InternalBrush);
+
+    if (!(internal = (InternalBrush *)BRUSHOBJ_pvAllocRbrush(brush, size))) {
+        DEBUG_PRINT((pdev, 0, "%s: alloc failed\n", __FUNCTION__));
+        return FALSE;
+    }
+    internal->size = pattern->sizlBitmap;
+    internal->key = 0;
+    internal->stride = stride;
+    if ((internal->format = pdev->bitmap_format) == BMF_32BPP) {
+        switch (pattern->iBitmapFormat) {
+        case BMF_1BPP:
+            realizeBrush32Copy1bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        case BMF_32BPP:
+            realizeBrush32Copy32bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_24BPP:
+            realizeBrush32Copy24bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_16BPP:
+            realizeBrush32Copy16bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_8BPP:
+            realizeBrush32Copy8bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        case BMF_4BPP:
+            realizeBrush32Copy4bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        }
+    } else {
+        ASSERT(pdev, pdev->bitmap_format == BMF_16BPP);
+        switch (pattern->iBitmapFormat) {
+        case BMF_1BPP:
+            realizeBrush16Copy1bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        case BMF_32BPP:
+            realizeBrush16Copy32bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_24BPP:
+            realizeBrush16Copy24bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_16BPP:
+            realizeBrush16Copy16bpp(pdev, internal, pattern->pvScan0, pattern->lDelta);
+            break;
+        case BMF_8BPP:
+            realizeBrush16Copy8bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        case BMF_4BPP:
+            realizeBrush16Copy4bpp(pdev, internal, pattern->pvScan0, pattern->lDelta, color_trans);
+            break;
+        }
+    }
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+
+static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *pattern,
+                               InternalBrush *brush, INT32 *surface_dest,
+                               QXLRect *surface_rect)
+{
+    HSURF hsurf;
+    SURFOBJ *surf_obj;
+    QXLRect area;
+    UINT32 key;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    if (brush->key && QXLGetBitsFromCache(pdev, drawable, brush->key, pattern)) {
+        DEBUG_PRINT((pdev, 13, "%s: from cache\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    if (!(hsurf = (HSURF)EngCreateBitmap(brush->size, brush->stride, brush->format, BMF_TOPDOWN,
+                                         brush->data))) {
+        DEBUG_PRINT((pdev, 0, "%s: create bitmap failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (!(surf_obj = EngLockSurface(hsurf))) {
+        DEBUG_PRINT((pdev, 0, "%s: lock surf failed\n", __FUNCTION__));
+        goto error_1;
+    }
+    area.left = area.top = 0;
+    area.right = brush->size.cx;
+    area.bottom = brush->size.cy;
+
+    CopyRect(surface_rect, &area);
+
+    if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE, surface_dest)) {
+        goto error_2;
+    }
+
+    brush->key = key;
+    EngUnlockSurface(surf_obj);
+    EngDeleteSurface(hsurf);
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+    return TRUE;
+
+error_2:
+    EngUnlockSurface(surf_obj);
+error_1:
+    EngDeleteSurface(hsurf);
+    return FALSE;
+}
+
+
+BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, QXLBrush *qxl_brush,
+                 BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+                 QXLRect *surface_rect)
+{
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    ASSERT(pdev, brush);
+
+    if (brush->iSolidColor == ~0) {
+        ASSERT(pdev, brush_pos);
+
+        DEBUG_PRINT((pdev, 11, "%s: pattern\n", __FUNCTION__));
+        if (!brush->pvRbrush && !BRUSHOBJ_pvGetRbrush(brush)) {
+            DEBUG_PRINT((pdev, 0, "%s: brush realize failed\n", __FUNCTION__));
+            return FALSE;
+        }
+        qxl_brush->type = SPICE_BRUSH_TYPE_PATTERN;
+        qxl_brush->u.pattern.pos.x = brush_pos->x;
+        qxl_brush->u.pattern.pos.y = brush_pos->y;
+        if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush,
+                        surface_dest, surface_rect)) {
+            return FALSE;
+        }
+    } else {
+        qxl_brush->type = SPICE_BRUSH_TYPE_SOLID;
+        qxl_brush->u.color = brush->iSolidColor;
+        DEBUG_PRINT((pdev, 11, "%s: color 0x%x\n", __FUNCTION__, qxl_brush->u.color));
+    }
+    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
diff --git a/xddm/display/driver.c b/xddm/display/driver.c
new file mode 100644
index 0000000..d7fdbf7
--- /dev/null
+++ b/xddm/display/driver.c
@@ -0,0 +1,1590 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "os_dep.h"
+
+#include "winerror.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+#include "qxldd.h"
+#include "utils.h"
+#include "mspace.h"
+#include "res.h"
+#include "surface.h"
+
+#define DEVICE_NAME L"qxldd"
+
+#define QXLDD_DEBUG_PREFIX "qxldd: "
+
+static DRVFN drv_calls[] = {
+    {INDEX_DrvDisableDriver, (PFN)DrvDisableDriver},
+    {INDEX_DrvEscape, (PFN)DrvEscape},
+    {INDEX_DrvEnablePDEV, (PFN)DrvEnablePDEV},
+    {INDEX_DrvDisablePDEV, (PFN)DrvDisablePDEV},
+    {INDEX_DrvCompletePDEV, (PFN)DrvCompletePDEV},
+    {INDEX_DrvEnableSurface, (PFN)DrvEnableSurface},
+    {INDEX_DrvDisableSurface, (PFN)DrvDisableSurface},
+    {INDEX_DrvAssertMode, (PFN)DrvAssertMode},
+    {INDEX_DrvGetModes, (PFN)DrvGetModes},
+    {INDEX_DrvSynchronize, (PFN)DrvSynchronize},
+    {INDEX_DrvCopyBits, (PFN)DrvCopyBits},
+    {INDEX_DrvBitBlt, (PFN)DrvBitBlt},
+    {INDEX_DrvTextOut, (PFN)DrvTextOut},
+    {INDEX_DrvStrokePath, (PFN)DrvStrokePath},
+    {INDEX_DrvRealizeBrush, (PFN)DrvRealizeBrush},
+    {INDEX_DrvSetPointerShape, (PFN)DrvSetPointerShape},
+    {INDEX_DrvMovePointer, (PFN)DrvMovePointer},
+    {INDEX_DrvStretchBlt, (PFN)DrvStretchBlt},
+    {INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
+    {INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
+    {INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
+    {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
+    {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
+
+#ifdef CALL_TEST
+    {INDEX_DrvFillPath, (PFN)DrvFillPath},
+    {INDEX_DrvGradientFill, (PFN)DrvGradientFill},
+    {INDEX_DrvLineTo, (PFN)DrvLineTo},
+    {INDEX_DrvPlgBlt, (PFN)DrvPlgBlt},
+    {INDEX_DrvStrokeAndFillPath, (PFN)DrvStrokeAndFillPath},
+#endif
+};
+
+#ifdef CALL_TEST
+
+typedef struct CallCounter {
+    const char *name;
+    BOOL effective;
+} CallCounterInfo;
+
+static CallCounterInfo counters_info[NUM_CALL_COUNTERS] = {
+    { "DrvCopyBits", FALSE},
+    { "DrvBitBlt", TRUE},
+    { "DrvTextOut", TRUE},
+    { "DrvStrokePath", TRUE},
+    { "DrvStretchBlt", FALSE},
+    { "DrvStretchBltROP", TRUE},
+    { "TransparentBlt", FALSE},
+    { "DrvAlphaBlend", FALSE},
+
+    { "DrvFillPath", FALSE},
+    { "DrvGradientFill", FALSE},
+    { "DrvLineTo", FALSE},
+    { "DrvPlgBlt", FALSE},
+    { "DrvStrokeAndFillPath", FALSE},
+};
+
+#endif
+
+#define DBG_LEVEL 0
+
+void DebugPrintV(PDev *pdev, const char *message, va_list ap)
+{
+    if (pdev && pdev->log_buf) {
+        EngAcquireSemaphore(pdev->print_sem);
+        _snprintf(pdev->log_buf, QXL_LOG_BUF_SIZE, QXLDD_DEBUG_PREFIX);
+        _vsnprintf(pdev->log_buf + strlen(QXLDD_DEBUG_PREFIX),
+                   QXL_LOG_BUF_SIZE - strlen(QXLDD_DEBUG_PREFIX), message, ap);
+        sync_io(pdev, pdev->log_port, 0);
+        EngReleaseSemaphore(pdev->print_sem);
+    } else {
+        EngDebugPrint(QXLDD_DEBUG_PREFIX, (PCHAR)message, ap);
+    }
+}
+
+void DebugPrint(PDev *pdev, int level, const char *message, ...)
+{
+    va_list ap;
+
+    if (level > (pdev && pdev->log_level ? (int)*pdev->log_level : DBG_LEVEL)) {
+        return;
+    }
+    va_start(ap, message);
+    DebugPrintV(pdev, message, ap);
+    va_end(ap);
+}
+
+#define DRIVER_VERSION 1
+#define OS_VERSION_MAJOR 5
+#define OS_VERSION_MINOR 0
+#define MK_GDIINFO_VERSION(os_major, os_minor, drv_vers) \
+    ((drv_vers) | ((os_minor) << 8) | ((os_major) << 12))
+
+
+GDIINFO gdi_default = {
+    MK_GDIINFO_VERSION(OS_VERSION_MAJOR, OS_VERSION_MINOR, DRIVER_VERSION),
+    DT_RASDISPLAY,
+    0,                      //ulHorzSize
+    0,                      //ulVertSize
+    0,                      //ulHorzRes
+    0,                      //ulVertRes
+    0,                      //cBitsPixel
+    0,                      //cPlanes
+    0,                      //ulNumColors
+    0,                      //flRaster
+    0,                      //ulLogPixelsX
+    0,                      //ulLogPixelsY
+    TC_RA_ABLE,             //flTextCaps
+    0,                      //ulDACRed
+    0,                      //ulDACGreen
+    0,                      //ulDACBlue
+    0x0024,                 //ulAspectX
+    0x0024,                 //ulAspectY
+    0x0033,                 //ulAspectXY
+    1,                      //xStyleStep
+    1,                      //yStyleSte;
+    3,                      //denStyleStep
+    { 0, 0},               //ptlPhysOffset
+    { 0, 0},               //szlPhysSize
+    0,                      //ulNumPalReg
+
+    {                       //ciDevice
+        { 6700, 3300, 0},  //Red
+        { 2100, 7100, 0},  //Green
+        { 1400,  800, 0},  //Blue
+        { 1750, 3950, 0},  //Cyan
+        { 4050, 2050, 0},  //Magenta
+        { 4400, 5200, 0},  //Yellow
+        { 3127, 3290, 0},  //AlignmentWhite
+        20000,              //RedGamma
+        20000,              //GreenGamma
+        20000,              //BlueGamma
+        0, 0, 0, 0, 0, 0    //No dye correction for raster displays
+    },
+
+    0,                      //ulDevicePelsDPI
+    PRIMARY_ORDER_CBA,      //ulPrimaryOrder
+    HT_PATSIZE_4x4_M,       //ulHTPatternSize
+    HT_FORMAT_8BPP,         //ulHTOutputFormat
+    HT_FLAG_ADDITIVE_PRIMS, //flHTFlags
+    0,                      //ulVRefresh
+    0,                      //ulPanningHorzRes
+    0,                      //ulPanningVertRes
+    0,                      //ulBltAlignment
+    //more
+};
+
+#define SYSTM_LOGFONT {16, 7, 0, 0, 700, 0, 0, 0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
+                       CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\
+                       VARIABLE_PITCH | FF_DONTCARE, L"System"}
+#define HELVE_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
+                       CLIP_STROKE_PRECIS, PROOF_QUALITY,\
+                       VARIABLE_PITCH | FF_DONTCARE, L"MS Sans Serif"}
+#define COURI_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
+                       CLIP_STROKE_PRECIS,PROOF_QUALITY,\
+                       FIXED_PITCH | FF_DONTCARE, L"Courier"}
+
+DEVINFO dev_default = {
+    GCAPS_ARBRUSHOPAQUE | GCAPS_ARBRUSHTEXT | GCAPS_ASYNCMOVE | /* GCAPS_BEZIERS | */
+    GCAPS_GRAY16 | GCAPS_OPAQUERECT |
+    GCAPS_WINDINGFILL /*| GCAPS_LAYERED*/,
+    SYSTM_LOGFONT,      //lfDefaultFont
+    HELVE_LOGFONT,      //lfAnsiVarFont
+    COURI_LOGFONT,      //lfAnsiFixFont
+    0,                  //cFonts
+    0,                  //iDitherFormat
+    0,                  //cxDither
+    0,                  //cyDither
+    0,                  //hpalDefault
+#if (WINVER >= 0x0501)
+    GCAPS2_MOUSETRAILS |
+#endif
+    GCAPS2_ALPHACURSOR,
+};
+
+static BOOL PrepareHardware(PDev *pdev);
+
+static void mspace_print(void *user_data, char *format, ...)
+{
+    PDev *pdev = (PDev *)user_data;
+    va_list ap;
+
+    va_start(ap, format);
+    DebugPrintV(pdev, format, ap);
+    va_end(ap);
+}
+
+static void mspace_abort(void *user_data)
+{
+    mspace_print(user_data, "mspace abort");
+    EngDebugBreak();
+}
+
+BOOL DrvEnableDriver(ULONG engine_version, ULONG enable_data_size, PDRVENABLEDATA enable_data)
+{
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+    enable_data->iDriverVersion = DDI_DRIVER_VERSION_NT5;
+    enable_data->c = sizeof(drv_calls) / sizeof(DRVFN);
+    enable_data->pdrvfn = drv_calls;
+    mspace_set_abort_func(mspace_abort);
+    mspace_set_print_func(mspace_print);
+    ResInitGlobals();
+#ifndef _WIN64
+    CheckAndSetSSE2();
+#endif
+    DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
+    return TRUE;
+}
+
+ULONG DrvEscape(SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn,
+                ULONG cjOut, PVOID pvOut)
+{
+    PDev* pdev = pso ? (PDev*)pso->dhpdev : NULL;
+    int RetVal = -1;
+
+    switch (iEsc) {
+    case QXL_ESCAPE_SET_CUSTOM_DISPLAY: {
+        ULONG length;
+
+        DEBUG_PRINT((pdev, 1, "set custom display %p\n", pdev));
+        if (pdev == NULL)
+            break;
+
+        if (EngDeviceIoControl(pdev->driver, IOCTL_QXL_SET_CUSTOM_DISPLAY,
+                               pvIn, cjIn, NULL, 0, &length)) {
+            DEBUG_PRINT((pdev, 0, "%s: IOCTL_QXL_SET_CUSTOM_DISPLAY failed\n", __FUNCTION__));
+            break;
+        }
+        RetVal = 1;
+        break;
+    }
+    default:
+        DEBUG_PRINT((NULL, 1, "%s: unhandled escape code %d\n", __FUNCTION__, iEsc));
+        RetVal = 0;
+    }
+
+    DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
+    return RetVal;
+}
+
+VOID DrvDisableDriver(VOID)
+{
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+    ResDestroyGlobals();
+}
+
+DWORD GetAvailableModes(HANDLE driver, PVIDEO_MODE_INFORMATION *mode_info,
+                        DWORD *mode_info_size)
+{
+    ULONG n;
+    VIDEO_NUM_MODES modes;
+    PVIDEO_MODE_INFORMATION info;
+
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+    if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL, 0,
+                           &modes, sizeof(VIDEO_NUM_MODES), &n)) {
+        DEBUG_PRINT((NULL, 0, "%s: query num modes failed\n", __FUNCTION__));
+        return 0;
+    }
+
+    info = (PVIDEO_MODE_INFORMATION)EngAllocMem(FL_ZERO_MEMORY,
+                                                modes.NumModes * modes.ModeInformationLength,
+                                                ALLOC_TAG);
+    if (!info) {
+        DEBUG_PRINT((NULL, 0, "%s: memory allocation failed\n", __FUNCTION__));
+        return 0;
+    }
+
+    if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0, info,
+                           modes.NumModes * modes.ModeInformationLength, &n)) {
+        DEBUG_PRINT((NULL, 0, "%s: query modes failed\n", __FUNCTION__));
+        EngFreeMem(info);
+        return 0;
+    }
+
+    *mode_info = info;
+    *mode_info_size = modes.ModeInformationLength;
+
+    n = modes.NumModes;
+    while ( n-- ) {
+        if ( (info->NumberOfPlanes != 1 ) ||!(info->AttributeFlags & VIDEO_MODE_GRAPHICS)
+             ||((info->BitsPerPlane != 16) && (info->BitsPerPlane != 32))) {
+
+            DEBUG_PRINT((NULL, 1, "%s: unsuported mode rejecting miniport mode\n",  __FUNCTION__));
+            DEBUG_PRINT((NULL, 1, "                   width = %li height = %li\n",
+                         info->VisScreenWidth, info->VisScreenHeight));
+            DEBUG_PRINT((NULL, 1, "                   bpp = %li freq = %li\n",
+                         info->BitsPerPlane * info->NumberOfPlanes, info->Frequency));
+            info->Length = 0;
+        }
+
+        info = (PVIDEO_MODE_INFORMATION) (((PUCHAR)info) + modes.ModeInformationLength);
+    }
+    DEBUG_PRINT((NULL, 1, "%s: OK num modes %lu\n", __FUNCTION__, modes.NumModes));
+    return modes.NumModes;
+}
+
+BOOL InitializeModeFields(PDev *pdev, GDIINFO *gdi_info, DEVINFO *dev_info,
+                          DEVMODEW *dev_mode)
+{
+    ULONG n_modes;
+    PVIDEO_MODE_INFORMATION video_buff;
+    PVIDEO_MODE_INFORMATION selected_mode;
+    PVIDEO_MODE_INFORMATION video_mode;
+    VIDEO_MODE_INFORMATION vmi;
+    ULONG video_mode_size;
+
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+    n_modes = GetAvailableModes(pdev->driver, &video_buff, &video_mode_size);
+    if ( n_modes == 0 ) {
+        DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
+#if (WINVER < 0x0501)
+    DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u\n",
+                 __FUNCTION__,
+                 dev_mode->dmFields,
+                 dev_mode->dmBitsPerPel,
+                 dev_mode->dmPelsWidth,
+                 dev_mode->dmPelsHeight,
+                 dev_mode->dmDisplayFrequency));
+#else
+    DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u orientation %u\n",
+                 __FUNCTION__,
+                 dev_mode->dmFields,
+                 dev_mode->dmBitsPerPel,
+                 dev_mode->dmPelsWidth,
+                 dev_mode->dmPelsHeight,
+                 dev_mode->dmDisplayFrequency,
+                 dev_mode->dmDisplayOrientation));
+#endif
+
+
+    selected_mode = NULL;
+    video_mode = video_buff;
+
+    while (n_modes--) {
+        if ( video_mode->Length != 0 ) {
+            DEBUG_PRINT((NULL, 1, "%s: check width = %li height = %li\n",
+                         __FUNCTION__,
+                         video_mode->VisScreenWidth,
+                         video_mode->VisScreenHeight));
+            DEBUG_PRINT((NULL, 1, "                             bpp = %li freq = %li\n",
+                         video_mode->BitsPerPlane * video_mode->NumberOfPlanes,
+                         video_mode->Frequency));
+
+            if ( (video_mode->VisScreenWidth  == dev_mode->dmPelsWidth)
+                 && (video_mode->VisScreenHeight == dev_mode->dmPelsHeight)
+                 && (video_mode->BitsPerPlane * video_mode->NumberOfPlanes
+                     == dev_mode->dmBitsPerPel)
+                 && (video_mode->Frequency == dev_mode->dmDisplayFrequency)
+#if (WINVER >= 0x0501)
+                 && (video_mode->DriverSpecificAttributeFlags
+                     == dev_mode->dmDisplayOrientation)
+#endif
+            ) {
+                selected_mode = video_mode;
+                DEBUG_PRINT((NULL, 1, "%s: found\n", __FUNCTION__));
+                break;
+            }
+        }
+        video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)video_mode) + video_mode_size);
+    }
+
+    if (!selected_mode) {
+        DEBUG_PRINT((NULL, 0, "%s: not found\n"));
+        EngFreeMem(video_buff);
+        return FALSE;
+    }
+
+    vmi = *selected_mode;
+    EngFreeMem(video_buff);
+
+    pdev->video_mode_index = vmi.ModeIndex;
+    pdev->resolution.cx = vmi.VisScreenWidth;
+    pdev->resolution.cy = vmi.VisScreenHeight;
+    pdev->max_bitmap_size = pdev->resolution.cx * pdev->resolution.cy;
+    pdev->max_bitmap_size += pdev->max_bitmap_size / 2;
+    pdev->stride = vmi.ScreenStride;
+
+    *gdi_info = gdi_default;
+
+    gdi_info->ulHorzSize = vmi.XMillimeter;
+    gdi_info->ulVertSize = vmi.YMillimeter;
+    gdi_info->ulHorzRes = vmi.VisScreenWidth;
+    gdi_info->ulVertRes = vmi.VisScreenHeight;
+    gdi_info->cBitsPixel = vmi.BitsPerPlane;
+    gdi_info->cPlanes = vmi.NumberOfPlanes;
+    gdi_info->ulVRefresh = vmi.Frequency;
+    gdi_info->ulDACRed = vmi.NumberRedBits;
+    gdi_info->ulDACGreen = vmi.NumberGreenBits;
+    gdi_info->ulDACBlue = vmi.NumberBlueBits;
+    gdi_info->ulLogPixelsX = dev_mode->dmLogPixels;
+    gdi_info->ulLogPixelsY = dev_mode->dmLogPixels;
+
+    *dev_info = dev_default;
+
+    switch ( vmi.BitsPerPlane ) {
+    case 16:
+        pdev->bitmap_format = BMF_16BPP;
+        pdev->red_mask = vmi.RedMask;
+        pdev->green_mask = vmi.GreenMask;
+        pdev->blue_mask = vmi.BlueMask;
+
+        gdi_info->ulNumColors = (ULONG)-1;
+        gdi_info->ulNumPalReg = 0;
+        gdi_info->ulHTOutputFormat = HT_FORMAT_16BPP;
+
+        dev_info->iDitherFormat = BMF_16BPP;
+        break;
+    case 32:
+        pdev->bitmap_format = BMF_32BPP;
+        pdev->red_mask = vmi.RedMask;
+        pdev->green_mask = vmi.GreenMask;
+        pdev->blue_mask = vmi.BlueMask;
+
+        gdi_info->ulNumColors = (ULONG)-1;
+        gdi_info->ulNumPalReg = 0;
+        gdi_info->ulHTOutputFormat = HT_FORMAT_32BPP;
+
+        dev_info->iDitherFormat = BMF_32BPP;
+        break;
+    default:
+        DEBUG_PRINT((NULL, 0, "%s: bit depth not supported\n", __FUNCTION__));
+        return FALSE;
+    }
+    DEBUG_PRINT((NULL, 1, "%s: exit\n", __FUNCTION__));
+    return TRUE;
+}
+
+void DestroyPalette(PDev *pdev)
+{
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    if (pdev->palette) {
+        EngDeletePalette(pdev->palette);
+        pdev->palette = NULL;
+    }
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+BOOL InitPalette(PDev *pdev, DEVINFO *dev_info)
+{
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    if ((pdev->palette = EngCreatePalette(PAL_BITFIELDS, 0, NULL,
+                                          pdev->red_mask,
+                                          pdev->green_mask,
+                                          pdev->blue_mask)) == NULL) {
+        DEBUG_PRINT((NULL, 0, "%s: create palette failed\n", __FUNCTION__));
+        return FALSE;
+    }
+    dev_info->hpalDefault = pdev->palette;
+
+    DEBUG_PRINT((NULL, 1, "%s: OK\n", __FUNCTION__));
+    return TRUE;
+}
+
+DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ignore3,
+                     ULONG dev_caps_size, ULONG *dev_caps, ULONG dev_inf_size,
+                     DEVINFO *in_dev_info, HDEV gdi_dev, PWSTR device_name, HANDLE driver)
+{
+    PDev *pdev;
+    GDIINFO gdi_info;
+    DEVINFO dev_info;
+
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+    if (!(pdev = (PDev*)EngAllocMem(FL_ZERO_MEMORY, sizeof(PDev), ALLOC_TAG))) {
+        DEBUG_PRINT((NULL, 0, "%s: pdev alloc failed\n", __FUNCTION__));
+        return NULL;
+    }
+
+    RtlZeroMemory(&gdi_info, sizeof(GDIINFO));
+    RtlCopyMemory(&gdi_info, dev_caps, MIN(dev_caps_size, sizeof(GDIINFO)));
+
+    RtlZeroMemory(&dev_info, sizeof(DEVINFO));
+    RtlCopyMemory(&dev_info, in_dev_info, MIN(dev_inf_size, sizeof(DEVINFO)));
+
+    pdev->driver = driver;
+
+    if (!InitializeModeFields(pdev, &gdi_info, &dev_info, dev_mode)) {
+        DEBUG_PRINT((NULL, 0, "%s: init mode failed\n", __FUNCTION__));
+        goto err1;
+    }
+
+    if (!InitPalette(pdev, &dev_info)) {
+        DEBUG_PRINT((NULL, 0, "%s: init palet failed\n", __FUNCTION__));
+        goto err1;
+    }
+
+    if (!ResInit(pdev)) {
+        DEBUG_PRINT((NULL, 0, "%s: init res failed\n", __FUNCTION__));
+        goto err2;
+    }
+
+    RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
+    RtlCopyMemory(in_dev_info, &dev_info, dev_inf_size);
+
+    pdev->enabled = TRUE; /* assume no operations before a DrvEnablePDEV. */
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    return(DHPDEV)pdev;
+
+err2:
+    DestroyPalette(pdev);
+
+err1:
+    EngFreeMem(pdev);
+
+    return NULL;
+}
+
+#ifdef DBG
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+    UINT32 i;
+    SurfaceInfo *surface_info;
+    int total = 0;
+    int of_pdev = 0;
+    int no_surf_obj = 0;
+
+    for (i = 0 ; i < pdev->n_surfaces; ++i) {
+        surface_info = GetSurfaceInfo(pdev, i);
+        if (surface_info->draw_area.base_mem != NULL) {
+            total++;
+            // all should belong to the same pdev
+            if (surface_info->u.pdev == pdev) {
+                of_pdev++;
+                if (surface_info->draw_area.surf_obj == NULL) {
+                    no_surf_obj++;
+                }
+            }
+        }
+    }
+    DEBUG_PRINT((pdev, 1, "%s: %p: %d / %d / %d (total,pdev,no_surf_obj)\n", __FUNCTION__, pdev,
+                total, of_pdev, no_surf_obj));
+}
+#else
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+}
+#endif
+
+VOID DrvDisablePDEV(DHPDEV in_pdev)
+{
+    PDev* pdev = (PDev*)in_pdev;
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    ResDestroy(pdev);
+    DestroyPalette(pdev);
+    EngFreeMem(pdev);
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+VOID DrvCompletePDEV(DHPDEV in_pdev, HDEV gdi_dev)
+{
+    PDev* pdev = (PDev*)in_pdev;
+
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    pdev->eng = gdi_dev;
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+static VOID HideMouse(PDev *pdev)
+{
+    QXLCursorCmd *cursor_cmd;
+
+    cursor_cmd = CursorCmd(pdev);
+    cursor_cmd->type = QXL_CURSOR_HIDE;
+
+    PushCursorCmd(pdev, cursor_cmd);
+}
+
+static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
+                                 UINT32 width, UINT32 height, INT32 stride,
+                                 QXLPHYSICAL phys_mem)
+{
+    pdev->primary_surface_create->format = format;
+    pdev->primary_surface_create->width = width;
+    pdev->primary_surface_create->height = height;
+    pdev->primary_surface_create->stride = -stride;
+    pdev->primary_surface_create->mem = phys_mem;
+
+    pdev->primary_surface_create->flags = 0;
+    pdev->primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
+
+    async_io(pdev, ASYNCABLE_CREATE_PRIMARY, 0);
+}
+
+static void DestroyPrimarySurface(PDev *pdev, int hide_mouse)
+{
+    if (hide_mouse) {
+        HideMouse(pdev);
+    }
+    async_io(pdev, ASYNCABLE_DESTROY_PRIMARY, 0);
+}
+
+static void DestroyAllSurfaces(PDev *pdev)
+{
+    HideMouse(pdev);
+    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
+}
+
+BOOL SetHardwareMode(PDev *pdev)
+{
+    VIDEO_MODE_INFORMATION video_info;
+    DWORD length;
+
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx mode %lu\n", __FUNCTION__, pdev, pdev->video_mode_index));
+
+    if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_SET_CURRENT_MODE,
+                           &pdev->video_mode_index, sizeof(DWORD),
+                           NULL, 0, &length)) {
+        DEBUG_PRINT((NULL, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx OK\n", __FUNCTION__, pdev));
+    return TRUE;
+}
+
+static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
+{
+    QXLPHYSICAL high_bits;
+
+
+    pdev->mem_slots[pdev->main_mem_slot].slot = *slot;
+
+    high_bits = pdev->main_mem_slot << pdev->slot_gen_bits;
+    high_bits |= slot->generation;
+    high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+    pdev->mem_slots[pdev->main_mem_slot].high_bits = high_bits;
+
+    pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+}
+
+static void RemoveVRamSlot(PDev *pdev)
+{
+    sync_io(pdev, pdev->memslot_del_port, pdev->vram_mem_slot);
+    pdev->vram_slot_initialized = FALSE;
+}
+
+static BOOLEAN CreateVRamSlot(PDev *pdev)
+{
+    QXLMemSlot *slot;
+    UINT64 high_bits;
+    UINT8 slot_id = pdev->main_mem_slot + 1;
+
+    if (slot_id >= pdev->num_mem_slot) {
+        return FALSE;
+    }
+
+    pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+
+
+    *pdev->ram_slot_start = pdev->fb_phys;
+    *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
+
+    async_io(pdev, ASYNCABLE_MEMSLOT_ADD, slot_id);
+
+    pdev->vram_mem_slot = slot_id;
+
+    pdev->mem_slots[slot_id].slot.generation = *pdev->slots_generation;
+    pdev->mem_slots[slot_id].slot.start_phys_addr = pdev->fb_phys;
+    pdev->mem_slots[slot_id].slot.end_phys_addr = pdev->fb_phys + pdev->fb_size;
+    pdev->mem_slots[slot_id].slot.start_virt_addr = (UINT64)pdev->fb;
+    pdev->mem_slots[slot_id].slot.end_virt_addr = (UINT64)pdev->fb + pdev->fb_size;
+
+    high_bits = slot_id << pdev->slot_gen_bits;
+    high_bits |= pdev->mem_slots[slot_id].slot.generation;
+    high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+    pdev->mem_slots[slot_id].high_bits = high_bits;
+
+    pdev->vram_slot_initialized = TRUE;
+
+    return TRUE;
+}
+
+static BOOL PrepareHardware(PDev *pdev)
+{
+    VIDEO_MEMORY video_mem;
+    VIDEO_MEMORY_INFORMATION video_mem_Info;
+    DWORD length;
+    QXLDriverInfo dev_info;
+    QXLPHYSICAL high_bits;
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    if (!SetHardwareMode(pdev)) {
+        DEBUG_PRINT((pdev, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+
+    if (EngDeviceIoControl( pdev->driver, IOCTL_QXL_GET_INFO, NULL,
+                            0, &dev_info, sizeof(QXLDriverInfo), &length) ) {
+        DEBUG_PRINT((pdev, 0, "%s: get qxl info failed, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+
+    if (dev_info.version != QXL_DRIVER_INFO_VERSION) {
+        DEBUG_PRINT((pdev, 0, "%s: get qxl info mismatch, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+
+    pdev->pci_revision = dev_info.pci_revision;
+    pdev->use_async = (pdev->pci_revision >= QXL_REVISION_STABLE_V10);
+    pdev->cmd_ring = dev_info.cmd_ring;
+    pdev->cursor_ring = dev_info.cursor_ring;
+    pdev->release_ring = dev_info.release_ring;
+    pdev->notify_cmd_port = dev_info.notify_cmd_port;
+    pdev->notify_cursor_port = dev_info.notify_cursor_port;
+    pdev->notify_oom_port = dev_info.notify_oom_port;
+
+    pdev->asyncable[ASYNCABLE_UPDATE_AREA][ASYNC] = dev_info.update_area_async_port;
+    pdev->asyncable[ASYNCABLE_UPDATE_AREA][SYNC] = dev_info.update_area_port;
+    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][ASYNC] = dev_info.memslot_add_async_port;
+    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][SYNC] = dev_info.memslot_add_port;
+    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][ASYNC] = dev_info.create_primary_async_port;
+    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][SYNC] = dev_info.create_primary_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][ASYNC] = dev_info.destroy_primary_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][SYNC] = dev_info.destroy_primary_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][ASYNC] = dev_info.destroy_surface_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][SYNC] = dev_info.destroy_surface_wait_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][ASYNC] = dev_info.destroy_all_surfaces_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][SYNC] = dev_info.destroy_all_surfaces_port;
+    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][ASYNC] = dev_info.flush_surfaces_async_port;
+    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][SYNC] = NULL;
+
+    pdev->display_event = dev_info.display_event;
+    pdev->cursor_event = dev_info.cursor_event;
+    pdev->sleep_event = dev_info.sleep_event;
+    pdev->io_cmd_event = dev_info.io_cmd_event;
+#if (WINVER < 0x0501)
+    pdev->WaitForEvent = dev_info.WaitForEvent;
+#endif
+
+    pdev->num_io_pages = dev_info.num_pages;
+    pdev->io_pages_virt = dev_info.io_pages_virt;
+    pdev->io_pages_phys = dev_info.io_pages_phys;
+
+    pdev->dev_update_id = dev_info.update_id;
+
+    pdev->update_area = dev_info.update_area;
+    pdev->update_surface = dev_info.update_surface;
+
+    pdev->mm_clock = dev_info.mm_clock;
+
+    pdev->compression_level = dev_info.compression_level;
+
+    pdev->log_port = dev_info.log_port;
+    pdev->log_buf = dev_info.log_buf;
+    pdev->log_level = dev_info.log_level;
+
+    pdev->n_surfaces = dev_info.n_surfaces;
+
+    pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
+                                  ALLOC_TAG);
+    if (!pdev->mem_slots) {
+        DEBUG_PRINT((pdev, 0, "%s: mem slots alloc failed, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+
+    pdev->slots_generation = dev_info.slots_generation;
+    pdev->ram_slot_start = dev_info.ram_slot_start;
+    pdev->ram_slot_end = dev_info.ram_slot_end;
+    pdev->slot_id_bits = dev_info.slot_id_bits;
+    pdev->slot_gen_bits = dev_info.slot_gen_bits;
+    pdev->main_mem_slot = dev_info.main_mem_slot_id;
+    pdev->num_mem_slot = dev_info.num_mem_slot;
+
+    UpdateMainSlot(pdev, &dev_info.main_mem_slot);
+
+    video_mem.RequestedVirtualAddress = NULL;
+
+    if (EngDeviceIoControl( pdev->driver, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &video_mem,
+                            sizeof(VIDEO_MEMORY), &video_mem_Info,
+                            sizeof(video_mem_Info), &length) ) {
+        DEBUG_PRINT((pdev, 0, "%s: mapping failed, 0x%lx\n", __FUNCTION__, pdev));
+        return FALSE;
+    }
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx vals 0x%lx %ul\n", __FUNCTION__, pdev,
+                 video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
+    pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
+    pdev->fb_size = video_mem_Info.FrameBufferLength;
+    pdev->fb_phys = dev_info.fb_phys;
+
+    pdev->memslot_del_port = dev_info.memslot_del_port;
+
+    pdev->flush_release_port = dev_info.flush_release_port;
+
+    pdev->primary_memory_start = dev_info.surface0_area;
+    pdev->primary_memory_size = dev_info.surface0_area_size;
+
+    pdev->primary_surface_create = dev_info.primary_surface_create;
+
+    pdev->dev_id = dev_info.dev_id;
+
+    pdev->create_non_primary_surfaces = dev_info.create_non_primary_surfaces;
+    DEBUG_PRINT((pdev, 1, "%s: create_non_primary_surfaces = %d\n", __FUNCTION__,
+                 pdev->create_non_primary_surfaces));
+
+    CreateVRamSlot(pdev);
+
+    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit: 0x%lx %ul\n", __FUNCTION__, pdev,
+                 pdev->fb, pdev->fb_size));
+    return TRUE;
+}
+
+static VOID UnmapFB(PDev *pdev)
+{
+    VIDEO_MEMORY video_mem;
+    DWORD length;
+
+    if (!pdev->fb) {
+        return;
+    }
+
+    video_mem.RequestedVirtualAddress = pdev->fb;
+    pdev->fb = 0;
+    pdev->fb_size = 0;
+    if (EngDeviceIoControl(pdev->driver,
+                           IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
+                           &video_mem,
+                           sizeof(video_mem),
+                           NULL,
+                           0,
+                           &length)) {
+        DEBUG_PRINT((NULL, 0, "%s: unmpap failed, 0x%lx\n", __FUNCTION__, pdev));
+    }
+}
+
+VOID EnableQXLPrimarySurface(PDev *pdev)
+{
+    UINT32 depth, format;
+
+    switch (pdev->bitmap_format) {
+        case BMF_8BPP:
+            PANIC(pdev, "bad formart type 8bpp\n");
+        case BMF_16BPP:
+            depth = 16;
+            format = SPICE_SURFACE_FMT_16_555;
+            break;
+        case BMF_24BPP:
+        case BMF_32BPP:
+            depth = 32;
+            format = SPICE_SURFACE_FMT_32_xRGB;
+            break;
+        default:
+            PANIC(pdev, "bad formart type\n");
+    };
+
+    CreatePrimarySurface(pdev, depth, format,
+                         pdev->resolution.cx, pdev->resolution.cy,
+                         pdev->stride, pdev->surf_phys);
+    pdev->surf_enable = TRUE;
+}
+
+HSURF DrvEnableSurface(DHPDEV in_pdev)
+{
+    PDev *pdev;
+    HSURF surf;
+    DWORD length;
+    QXLPHYSICAL phys_mem;
+    UINT8 *base_mem;
+
+    pdev = (PDev*)in_pdev;
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
+
+    if (!PrepareHardware(pdev)) {
+        return FALSE;
+    }
+    InitResources(pdev);
+
+    if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
+                                           &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
+        DEBUG_PRINT((pdev, 0, "%s: create device surface failed, 0x%lx\n",
+                     __FUNCTION__, pdev));
+        goto err;
+    }
+
+    DEBUG_PRINT((pdev, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
+                 "0x%lx, 0x%lx, %lu, NULL)\n",
+                 __FUNCTION__,
+                 surf,
+                 pdev->eng,
+                 pdev,
+                 pdev->fb,
+                 pdev->stride));
+
+    pdev->surf = surf;
+    pdev->surf_phys = phys_mem;
+    pdev->surf_base = base_mem;
+
+    EnableQXLPrimarySurface(pdev);
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+    return surf;
+
+err:
+    DrvDisableSurface((DHPDEV)pdev);
+    DEBUG_PRINT((pdev, 0, "%s: 0x%lx err\n", __FUNCTION__, pdev));
+    return NULL;
+}
+
+VOID DisableQXLPrimarySurface(PDev *pdev, int hide_mouse)
+{
+    DrawArea drawarea;
+
+    if (pdev->surf_enable) {
+        DestroyPrimarySurface(pdev, hide_mouse);
+        pdev->surf_enable = FALSE;
+    }
+}
+
+VOID DisableQXLAllSurfaces(PDev *pdev)
+{
+    DestroyAllSurfaces(pdev);
+}
+
+VOID DrvDisableSurface(DHPDEV in_pdev)
+{
+    PDev *pdev = (PDev*)in_pdev;
+    DrawArea drawarea;
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    // Don't destroy the primary - it's destroyed by destroy_all_surfaces
+    // at AssertModeDisable. Also, msdn specifically mentions DrvDisableSurface
+    // should not touch the hardware, that should be done just via DrvAssertMode
+    // (http://msdn.microsoft.com/en-us/library/ff556200%28VS.85%29.aspx)
+    pdev->surf_enable = FALSE;
+    UnmapFB(pdev);
+
+    if (pdev->surf) {
+        DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
+        EngDeleteSurface(pdev->surf);
+        pdev->surf = NULL;
+    }
+
+    if (pdev->mem_slots) {
+        EngFreeMem(pdev->mem_slots);
+        pdev->mem_slots = NULL;
+    }
+
+    DebugCountAliveSurfaces(pdev);
+    ClearResources(pdev);
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+static void FlushSurfaces(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+    SURFOBJ *surf_obj;
+    RECTL area = {0, 0, 0, 0};
+
+    if (pdev->pci_revision < QXL_REVISION_STABLE_V10) {
+        DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_SURFACES\n", __FUNCTION__));
+        for (surface_id = pdev->n_surfaces - 1; surface_id >  0 ; --surface_id) {
+            surface_info = GetSurfaceInfo(pdev, surface_id);
+
+            if (!surface_info->draw_area.base_mem) {
+                continue;
+            }
+            surf_obj = surface_info->draw_area.surf_obj;
+            if (!surf_obj) {
+                continue;
+            }
+            area.right = surf_obj->sizlBitmap.cx;
+            area.bottom = surf_obj->sizlBitmap.cy;
+            UpdateArea(pdev,&area, surface_id);
+        }
+    } else {
+        async_io(pdev, ASYNCABLE_FLUSH_SURFACES, 0);
+    }
+}
+
+static BOOL FlushRelease(PDev *pdev)
+{
+    if (pdev->pci_revision<  QXL_REVISION_STABLE_V10) {
+        DWORD length;
+
+        DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_RELEASE\n", __FUNCTION__));
+        if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_RESET_DEVICE,
+                               NULL, 0, NULL, 0, &length)) {
+            DEBUG_PRINT((NULL, 0, "%s: reset failed 0x%lx\n", __FUNCTION__, pdev));
+            return FALSE;
+        }
+    } else {
+        /* Free release ring contents */
+        ReleaseCacheDeviceMemoryResources(pdev);
+        EmptyReleaseRing(pdev);
+        /* Get the last free list onto the release ring */
+        sync_io(pdev, pdev->flush_release_port, 0);
+        DEBUG_PRINT((pdev, 4, "%s after FLUSH_RELEASE\n", __FUNCTION__));
+        /* And release that. mspace allocators should be clean after. */
+        EmptyReleaseRing(pdev);
+    }
+    return TRUE;
+}
+
+static BOOL AssertModeDisable(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 3, "%s entry\n", __FUNCTION__));
+    /* flush command ring and update all surfaces */
+    FlushSurfaces(pdev);
+    DebugCountAliveSurfaces(pdev);
+    /*
+     * this call is redundant for
+     * pci_revision <  QXL_REVISION_STABLE_V10, due to the
+     * IOCTL_VIDEO_RESET_DEVICE in FlushRelease. However,
+     * MoveAllSurfacesToRam depends on destroy_all_surfaces
+     * in case of failure.
+     * TODO: make MoveAllSurfacesToRam send destroy_surface
+     * commands instead of create_surface commands in case
+     * of failure
+     */
+    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
+    /* move all surfaces from device to system memory */
+    if (!MoveAllSurfacesToRam(pdev)) {
+        EnableQXLPrimarySurface(pdev);
+        return FALSE;
+    }
+    if (!FlushRelease(pdev)) {
+        return FALSE;
+    }
+    RemoveVRamSlot(pdev);
+    DebugCountAliveSurfaces(pdev);
+    DEBUG_PRINT((pdev, 4, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+        pdev->release_ring->prod, pdev->release_ring->cons,
+        pdev->free_outputs));
+    DEBUG_PRINT((pdev, 3, "%s exit\n", __FUNCTION__));
+    return TRUE;
+}
+
+static void AssertModeEnable(PDev *pdev)
+{
+    InitDeviceMemoryResources(pdev);
+    DEBUG_PRINT((pdev, 3, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+        pdev->release_ring->prod, pdev->release_ring->cons,
+        pdev->free_outputs));
+    EnableQXLPrimarySurface(pdev);
+    CreateVRamSlot(pdev);
+    DebugCountAliveSurfaces(pdev);
+    MoveAllSurfacesToVideoRam(pdev);
+    DebugCountAliveSurfaces(pdev);
+}
+
+BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
+{
+    PDev* pdev = (PDev*)in_pdev;
+    BOOL ret = TRUE;
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx revision %d enable %d\n", __FUNCTION__, pdev, pdev->pci_revision, enable));
+    if (pdev->enabled == enable) {
+        DEBUG_PRINT((pdev, 1, "%s: called twice with same argument (%d)\n", __FUNCTION__,
+            enable));
+        return TRUE;
+    }
+    pdev->enabled = enable;
+    if (enable) {
+        AssertModeEnable(pdev);
+    } else {
+        ret = AssertModeDisable(pdev);
+        if (!ret) {
+            pdev->enabled = !enable;
+        }
+    }
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
+    return ret;
+}
+
+ULONG DrvGetModes(HANDLE driver, ULONG dev_modes_size, DEVMODEW *dev_modes)
+{
+    PVIDEO_MODE_INFORMATION video_modes;
+    PVIDEO_MODE_INFORMATION curr_video_mode;
+    DWORD mode_size;
+    DWORD output_size;
+    DWORD n_modes;
+
+    DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+    n_modes = GetAvailableModes(driver, &video_modes, &mode_size);
+
+    if (!n_modes) {
+        DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
+        return 0;
+    }
+
+    if (!dev_modes) {
+        DEBUG_PRINT((NULL, 1, "%s: query size\n", __FUNCTION__));
+        output_size = n_modes * sizeof(DEVMODEW);
+        goto out;
+    }
+
+    if (dev_modes_size < n_modes * sizeof(DEVMODEW)) {
+        DEBUG_PRINT((NULL, 0, "%s: buf to small\n", __FUNCTION__));
+        output_size = 0;
+        goto out;
+    }
+
+    output_size = 0;
+    curr_video_mode = video_modes;
+    do {
+        if (curr_video_mode->Length != 0) {
+            RtlZeroMemory(dev_modes, sizeof(DEVMODEW));
+            ASSERT(NULL, sizeof(DEVICE_NAME) < sizeof(dev_modes->dmDeviceName));
+            RtlCopyMemory(dev_modes->dmDeviceName, DEVICE_NAME, sizeof(DEVICE_NAME));
+            dev_modes->dmSpecVersion = DM_SPECVERSION;
+            dev_modes->dmDriverVersion = DM_SPECVERSION;
+            dev_modes->dmSize = sizeof(DEVMODEW);
+            dev_modes->dmBitsPerPel =   curr_video_mode->NumberOfPlanes *
+                                        curr_video_mode->BitsPerPlane;
+            dev_modes->dmPelsWidth = curr_video_mode->VisScreenWidth;
+            dev_modes->dmPelsHeight = curr_video_mode->VisScreenHeight;
+            dev_modes->dmDisplayFrequency = curr_video_mode->Frequency;
+            dev_modes->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+                                  DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
+#if (WINVER >= 0x0501)
+            dev_modes->dmDisplayOrientation = curr_video_mode->DriverSpecificAttributeFlags;
+            dev_modes->dmFields |= DM_DISPLAYORIENTATION;
+#endif
+
+            DEBUG_PRINT((NULL, 1, "%s: mode: w %u h %u bits %u frequency %u\n",
+                         __FUNCTION__,
+                         dev_modes->dmPelsWidth,
+                         dev_modes->dmPelsHeight,
+                         dev_modes->dmBitsPerPel,
+                         dev_modes->dmDisplayFrequency));
+#if (WINVER >= 0x0501)
+            DEBUG_PRINT((NULL, 1, "             orientation %u\n",
+                         dev_modes->dmDisplayOrientation));
+#endif
+            output_size += sizeof(DEVMODEW);
+            dev_modes++;
+        }
+        curr_video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)curr_video_mode) + mode_size);
+    } while (--n_modes);
+
+    out:
+
+    EngFreeMem(video_modes);
+    DEBUG_PRINT((NULL, 1, "%s: exit %u\n", __FUNCTION__, output_size));
+    return output_size;
+}
+
+VOID DrvSynchronize(DHPDEV in_pdev, RECTL *ignored)
+{
+    PDev* pdev = (PDev*)in_pdev;
+    int notify;
+
+    DEBUG_PRINT((pdev, 3, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    DEBUG_PRINT((pdev, 4, "%s: 0x%lx done\n", __FUNCTION__, pdev));
+}
+
+char *BitmapFormatToStr(int format)
+{
+    switch (format) {
+    case BMF_1BPP:
+        return  "BMF_1BPP";
+    case BMF_4BPP:
+        return "BMF_4BPP";
+    case BMF_8BPP:
+        return "BMF_8BPP";
+    case BMF_16BPP:
+        return "BMF_16BPP";
+    case BMF_24BPP:
+        return "BMF_24BPP";
+    case BMF_32BPP:
+        return "BMF_32BPP";
+    case BMF_4RLE:
+        return "BMF_4RLE";
+    case BMF_8RLE:
+        return "BMF_8RLE";
+    case BMF_JPEG:
+        return "BMF_JPEG";
+    case BMF_PNG:
+        return "BMF_PNG";
+    default:
+        return "?";
+    }
+}
+
+char *BitmapTypeToStr(int type)
+{
+    switch (type) {
+    case STYPE_BITMAP:
+        return  "STYPE_BITMAP";
+    case STYPE_DEVICE:
+        return "STYPE_DEVICE";
+    case STYPE_DEVBITMAP:
+        return "STYPE_DEVBITMAP";
+    default:
+        return "?";
+    }
+}
+
+#include "rop.h"
+#include "utils.h"
+#include "res.h"
+
+FIX FlotaToFixed(FLOATL val, FLOATL scale)
+{
+    FLOATOBJ float_obj;
+    FIX ret;
+
+    FLOATOBJ_SetFloat(&float_obj, val);
+    FLOATOBJ_MulFloat(&float_obj, scale);
+
+    ret = FLOATOBJ_GetLong(&float_obj) << 4;
+    FLOATOBJ_MulLong(&float_obj, 16);
+    ret |= (0x0f & FLOATOBJ_GetLong(&float_obj));
+    return ret;
+}
+
+static BOOL GetCosmeticAttr(PDev *pdev, QXLDrawable *drawable, QXLLineAttr *q_line_attr,
+                            LINEATTRS *line_attr)
+{
+    q_line_attr->join_style = JOIN_MITER;
+    q_line_attr->end_style = ENDCAP_BUTT;
+    q_line_attr->width = 1 << 4;
+    q_line_attr->miter_limit = 0;
+
+    if (line_attr->fl & LA_STYLED) {
+        PFLOAT_LONG src_style = line_attr->pstyle;
+        FIX *style;
+        FIX *end;
+        UINT32 nseg;
+
+        q_line_attr->flags = (UINT8)(line_attr->fl & (LA_STYLED | LA_STARTGAP));
+        nseg = (line_attr->fl & LA_ALTERNATE) ? 2 : line_attr->cstyle;
+        if ( nseg > 100) {
+            return FALSE;
+        }
+
+        if (!(style = (FIX *)QXLGetBuf(pdev, drawable, &q_line_attr->style,
+                                       nseg * sizeof(UINT32)))) {
+            return FALSE;
+        }
+
+        if (line_attr->fl & LA_ALTERNATE) {
+            style[0] = style[1] = 1 << 4;
+        } else {
+            for ( end = style + nseg;  style < end; style++, src_style++) {
+                *style = (*src_style).l << 4;
+            }
+        }
+        q_line_attr->style_nseg = (UINT8)nseg;
+    } else {
+        q_line_attr->flags = 0;
+        q_line_attr->style_nseg = 0;
+        q_line_attr->style = 0;
+    }
+    return TRUE;
+}
+
+BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOBJ *width_transform,
+                            BRUSHOBJ *brush, POINTL *brush_pos, LINEATTRS *line_attr,
+                            MIX mix /*rop*/)
+{
+    QXLDrawable *drawable;
+    RECTFX fx_area;
+    RECTL area;
+    PDev *pdev;
+    ROP3Info *fore_rop;
+    ROP3Info *back_rop;
+    BOOL h_or_v_line;
+
+    if (!(pdev = (PDev *)surf->dhpdev)) {
+        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    PUNT_IF_DISABLED(pdev);
+
+    CountCall(pdev, CALL_COUNTER_STROKE_PATH);
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+    ASSERT(pdev, surf && path && line_attr && clip);
+
+
+    if (line_attr->fl & (LA_STYLED | LA_ALTERNATE | LA_GEOMETRIC)) { //for now
+        // punt back to GDI result in infinite recursion
+        //return EngStrokePath(surf, path, clip, width_transform, brush, brush_pos, line_attr, mix);
+    }
+
+    ASSERT(pdev, (line_attr->fl & LA_GEOMETRIC) == 0); /* We should not get these */
+
+    PATHOBJ_vGetBounds(path, &fx_area);
+    FXToRect(&area, &fx_area);
+
+    h_or_v_line = area.bottom == area.top + 1  || area.right == area.left + 1;
+
+    if (clip) {
+        if (clip->iDComplexity == DC_TRIVIAL) {
+            clip = NULL;
+        } else {
+            SectRect(&clip->rclBounds, &area, &area);
+            if (IsEmptyRect(&area)) {
+                DEBUG_PRINT((pdev, 1, "%s: empty rect after clip\n", __FUNCTION__));
+                return TRUE;
+            }
+        }
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip, GetSurfaceId(surf)))) {
+        return FALSE;
+    }
+
+    fore_rop = &rops2[(mix - 1) & 0x0f];
+    back_rop = &rops2[((mix >> 8) - 1) & 0x0f];
+
+    if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
+        drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
+    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos,
+                            &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
+        goto err;
+    }
+
+    if (!QXLGetPath(pdev, drawable, &drawable->u.stroke.path, path)) {
+        goto err;
+    }
+    // DrvStrokePath only draws foreground pixels, unless you support dotted
+    // lines, so you only care about the low-order byte.
+    drawable->u.stroke.fore_mode = fore_rop->method_data;
+    drawable->u.stroke.back_mode = back_rop->method_data;
+
+    drawable->effect = (h_or_v_line) ? QXL_EFFECT_OPAQUE: QXL_EFFECT_BLEND;
+
+    if (!GetCosmeticAttr(pdev, drawable, &drawable->u.stroke.attr, line_attr)) {
+        goto err;
+    }
+
+    if (drawable->u.stroke.attr.flags & LA_STYLED) {
+        drawable->effect = (fore_rop->effect == back_rop->effect) ? fore_rop->effect :
+                                                                                   QXL_EFFECT_BLEND;
+    } else {
+        drawable->effect = fore_rop->effect;
+    }
+
+    if (drawable->effect == QXL_EFFECT_OPAQUE && !h_or_v_line) {
+        drawable->effect = QXL_EFFECT_OPAQUE_BRUSH;
+    }
+
+    PushDrawable(pdev, drawable);
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+    return TRUE;
+
+err:
+    ReleaseOutput(pdev, drawable->release_info.id);
+    return FALSE;
+}
+
+HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
+{
+    PDev *pdev;
+    UINT8 *base_mem;
+    UINT32 surface_id;
+    QXLPHYSICAL phys_mem;
+    HBITMAP hbitmap;
+
+    pdev = (PDev *)dhpdev;
+
+    if (!pdev->create_non_primary_surfaces) {
+        return FALSE;
+    }
+
+    if (!pdev->vram_slot_initialized || pdev->bitmap_format != format || pdev->fb == 0) {
+        DEBUG_PRINT((pdev, 3, "%s failed: %p: slot_initialized %d, format(%d,%d), fb %p\n",
+                    __FUNCTION__, pdev, pdev->vram_slot_initialized,
+                    pdev->bitmap_format, format, pdev->fb));
+        return 0;
+    }
+
+    PUNT_IF_DISABLED(pdev);
+
+    surface_id = GetFreeSurface(pdev);
+    if (!surface_id) {
+        DEBUG_PRINT((pdev, 3, "%s:%p GetFreeSurface failed\n", __FUNCTION__, pdev));
+        goto out_error;
+    }
+    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+
+    hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
+                                 DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+    if (!hbitmap) {
+         DEBUG_PRINT((pdev, 3, "%s:%p CreateDeviceBitmap failed\n", __FUNCTION__, pdev));
+        goto out_error2;
+    }
+
+    return hbitmap;
+
+    // to optimize the failure case
+out_error2:
+    FreeSurfaceInfo(pdev, surface_id);
+out_error:
+    return 0;
+}
+
+VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface;
+    PDev *pdev;
+
+    surface = (SurfaceInfo *)dhsurf;
+    surface_id = GetSurfaceIdFromInfo(surface);
+    pdev = surface->u.pdev;
+
+    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+
+    ASSERT(pdev, surface_id < pdev->n_surfaces);
+
+    DeleteDeviceBitmap(surface->u.pdev, surface_id,
+                       surface->copy ? DEVICE_BITMAP_ALLOCATION_TYPE_RAM
+                                     : DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+}
+
+#ifdef CALL_TEST
+
+void CountCall(PDev *pdev, int counter)
+{
+    if (pdev->count_calls) {
+        int i;
+
+        pdev->call_counters[counter]++;
+        if((++pdev->total_calls % 500) == 0) {
+            DEBUG_PRINT((pdev, 0, "total eng calls is %u\n", pdev->total_calls));
+            for (i = 0; i < NUM_CALL_COUNTERS; i++) {
+                DEBUG_PRINT((pdev, 0, "%s count is %u\n",
+                             counters_info[i].name, pdev->call_counters[i]));
+            }
+        }
+        pdev->count_calls = FALSE;
+    } else if (counters_info[counter].effective) {
+        pdev->count_calls = TRUE;
+    }
+}
+
+BOOL APIENTRY DrvFillPath(
+    SURFOBJ  *pso,
+    PATHOBJ  *ppo,
+    CLIPOBJ  *pco,
+    BRUSHOBJ *pbo,
+    POINTL   *pptlBrushOrg,
+    MIX       mix,
+    FLONG     flOptions)
+{
+    PDev *pdev;
+
+    pdev = (PDev *)pso->dhpdev;
+    CountCall(pdev, CALL_COUNTER_FILL_PATH);
+
+    return EngFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
+}
+
+BOOL APIENTRY DrvGradientFill(
+    SURFOBJ         *psoDest,
+    CLIPOBJ         *pco,
+    XLATEOBJ        *pxlo,
+    TRIVERTEX       *pVertex,
+    ULONG            nVertex,
+    PVOID            pMesh,
+    ULONG            nMesh,
+    RECTL           *prclExtents,
+    POINTL          *pptlDitherOrg,
+    ULONG            ulMode)
+{
+    PDev *pdev;
+
+    pdev = (PDev *)psoDest->dhpdev;
+    CountCall(pdev, CALL_COUNTER_GRADIENT_FILL);
+    return EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
+                           pptlDitherOrg, ulMode);
+}
+
+BOOL APIENTRY DrvLineTo(
+    SURFOBJ   *pso,
+    CLIPOBJ   *pco,
+    BRUSHOBJ  *pbo,
+    LONG       x1,
+    LONG       y1,
+    LONG       x2,
+    LONG       y2,
+    RECTL     *prclBounds,
+    MIX        mix)
+{
+    PDev *pdev;
+
+    pdev = (PDev *)pso->dhpdev;
+    CountCall(pdev, CALL_COUNTER_LINE_TO);
+    return EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
+}
+
+BOOL APIENTRY DrvPlgBlt(
+    SURFOBJ         *psoTrg,
+    SURFOBJ         *psoSrc,
+    SURFOBJ         *psoMsk,
+    CLIPOBJ         *pco,
+    XLATEOBJ        *pxlo,
+    COLORADJUSTMENT *pca,
+    POINTL          *pptlBrushOrg,
+    POINTFIX        *pptfx,
+    RECTL           *prcl,
+    POINTL          *pptl,
+    ULONG            iMode)
+{
+    if (psoSrc->iType == STYPE_BITMAP) {
+        PDev *pdev;
+
+        ASSERT(NULL, psoTrg && psoTrg->iType != STYPE_BITMAP && psoTrg->dhpdev);
+        pdev = (PDev *)psoTrg->dhpdev;
+        CountCall(pdev, CALL_COUNTER_PLG_BLT);
+    }
+    return EngPlgBlt(psoTrg, psoSrc, psoMsk, pco, pxlo, pca, pptlBrushOrg, pptfx, prcl, pptl,
+                     iMode);
+}
+
+BOOL APIENTRY DrvStrokeAndFillPath(
+    SURFOBJ   *pso,
+    PATHOBJ   *ppo,
+    CLIPOBJ   *pco,
+    XFORMOBJ  *pxo,
+    BRUSHOBJ  *pboStroke,
+    LINEATTRS *plineattrs,
+    BRUSHOBJ  *pboFill,
+    POINTL    *pptlBrushOrg,
+    MIX        mixFill,
+    FLONG      flOptions)
+{
+    PDev *pdev = (PDev *)pso->dhpdev;
+    CountCall(pdev, CALL_COUNTER_STROKE_AND_FILL_PATH);
+    return EngStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, plineattrs, pboFill, pptlBrushOrg,
+                                mixFill, flOptions);
+}
+
+#endif
diff --git a/xddm/display/driver.rc b/xddm/display/driver.rc
new file mode 100644
index 0000000..f11c9db
--- /dev/null
+++ b/xddm/display/driver.rc
@@ -0,0 +1,29 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE                VFT_DRV
+#define VER_FILESUBTYPE             VFT2_DRV_DISPLAY
+
+#undef  VER_COMPANYNAME_STR
+#undef  VER_FILEVERSION_STR
+#undef  VER_LEGALCOPYRIGHT_STR
+#undef  VER_LEGALCOPYRIGHT_YEARS
+#undef  VER_PRODUCTNAME_STR
+#undef  VER_PRODUCTVERSION_STR
+
+
+#define VER_FILEDESCRIPTION_STR     "Red Hat QXL Display Driver"
+#define VER_INTERNALNAME_STR        "qxldd.dll"
+#define VER_ORIGINALFILENAME_STR    VER_INTERNALNAME_STR
+#define VER_FILEVERSION_STR         "1.4.2.3"
+#define VER_PRODUCTNAME_STR         "Spice"
+#define VER_PRODUCTVERSION_STR      VER_FILEVERSION_STR
+
+#undef  VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION           1,4,2,3
+
+#define VER_COMPANYNAME_STR         "Red Hat Inc."
+#define VER_LEGALCOPYRIGHT_STR      "© Red Hat Inc. All rights reserved."
+
+#include "common.ver"
diff --git a/xddm/display/makefile b/xddm/display/makefile
new file mode 100644
index 0000000..53b9a3d
--- /dev/null
+++ b/xddm/display/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/xddm/display/mspace.c b/xddm/display/mspace.c
new file mode 100644
index 0000000..d0ba123
--- /dev/null
+++ b/xddm/display/mspace.c
@@ -0,0 +1,2437 @@
+// based on dlmalloc from Doug Lea
+
+
+// quote from the Doug Lea original file
+    /*
+      This is a version (aka dlmalloc) of malloc/free/realloc written by
+      Doug Lea and released to the public domain, as explained at
+      http://creativecommons.org/licenses/publicdomain.  Send questions,
+      comments, complaints, performance data, etc to dl at cs.oswego.edu
+
+    * Version 2.8.3 Thu Sep 22 11:16:15 2005  Doug Lea  (dl at gee)
+
+       Note: There may be an updated version of this malloc obtainable at
+               ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+             Check before installing!
+    */
+
+
+#include <ntddk.h>
+
+#include "mspace.h"
+
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#define USE_LOCKS 0
+#define malloc_getpagesize ((size_t)4096U)
+#define DEFAULT_GRANULARITY malloc_getpagesize
+#define MAX_SIZE_T (~(size_t)0)
+#define MALLOC_FAILURE_ACTION
+#define MALLINFO_FIELD_TYPE size_t
+#define FOOTERS 0
+#define INSECURE 0
+#define PROCEED_ON_ERROR 0
+#define DEBUG 0
+#define ABORT_ON_ASSERT_FAILURE 1
+#define ABORT(user_data) abort_func(user_data)
+#define USE_BUILTIN_FFS 0
+#define USE_DEV_RANDOM 0
+#define PRINT(params) print_func params
+
+
+#define MEMCPY(dest, src, n) RtlCopyMemory(dest, src, n)
+#define MEMCLEAR(dest, n) RtlZeroMemory(dest, n)
+
+
+#define M_GRANULARITY        (-1)
+
+void default_abort_func(void *user_data)
+{
+    for (;;);
+}
+
+void default_print_func(void *user_data, char *format, ...)
+{
+}
+
+static mspace_abort_t abort_func = default_abort_func;
+static mspace_print_t print_func = default_print_func;
+
+void mspace_set_abort_func(mspace_abort_t f)
+{
+    abort_func = f;
+}
+
+void mspace_set_print_func(mspace_print_t f)
+{
+    print_func = f;
+}
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any system that has a
+  /usr/include/malloc.h defining struct mallinfo.  The main
+  declaration needed is the mallinfo struct that is returned (by-copy)
+  by mallinfo().  The malloinfo struct contains a bunch of fields that
+  are not even meaningful in this version of malloc.  These fields are
+  are instead filled by mallinfo() with other numbers that might be of
+  interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else a compliant version is
+  declared below.  These must be precisely the same for mallinfo() to
+  work.  The original SVID version of this struct, defined on most
+  systems with mallinfo, declares all fields as ints. But some others
+  define as unsigned long. If your system defines the fields using a
+  type of different width than listed here, you MUST #include your
+  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+
+struct mallinfo {
+  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
+  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
+  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
+  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
+  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
+  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
+  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
+  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+  MALLINFO_FIELD_TYPE fordblks; /* total free space */
+  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+
+#endif /* NO_MALLINFO */
+
+
+
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#define assert(user_data, x) if(!(x)) ABORT(user_data)
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else  /* DEBUG */
+#define assert(user_data, x)
+#endif /* DEBUG */
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE         (sizeof(size_t))
+#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some plaftorms */
+#define SIZE_T_ZERO         ((size_t)0)
+#define SIZE_T_ONE          ((size_t)1)
+#define SIZE_T_TWO          ((size_t)2)
+#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+#if USE_LOCKS
+
+/*
+  When locks are defined, there are up to two global locks:
+
+  * If HAVE_MORECORE, morecore_mutex protects sequences of calls to
+    MORECORE.  In many cases sys_alloc requires two calls, that should
+    not be interleaved with calls by other threads.  This does not
+    protect against direct calls to MORECORE by other threads not
+    using this lock, so there is still code to cope the best we can on
+    interference.
+
+  * magic_init_mutex ensures that mparams.magic and other
+    unique mparams values are initialized only once.
+*/
+
+
+#define USE_LOCK_BIT               (2U)
+#else  /* USE_LOCKS */
+#define USE_LOCK_BIT               (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS
+#define ACQUIRE_MAGIC_INIT_LOCK()  ACQUIRE_LOCK(&magic_init_mutex);
+#define RELEASE_MAGIC_INIT_LOCK()  RELEASE_LOCK(&magic_init_mutex);
+#else  /* USE_LOCKS */
+#define ACQUIRE_MAGIC_INIT_LOCK()
+#define RELEASE_MAGIC_INIT_LOCK()
+#endif /* USE_LOCKS */
+
+
+
+/* -----------------------  Chunk representations ------------------------ */
+
+/*
+  (The following includes lightly edited explanations by Colin Plumb.)
+
+  The malloc_chunk declaration below is misleading (but accurate and
+  necessary).  It declares a "view" into memory allowing access to
+  necessary fields at known offsets from a given base.
+
+  Chunks of memory are maintained using a `boundary tag' method as
+  originally described by Knuth.  (See the paper by Paul Wilson
+  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+  techniques.)  Sizes of free chunks are stored both in the front of
+  each chunk and at the end.  This makes consolidating fragmented
+  chunks into bigger chunks fast.  The head fields also hold bits
+  representing whether chunks are free or in use.
+
+  Here are some pictures to make it clearer.  They are "exploded" to
+  show that the state of a chunk can be thought of as extending from
+  the high 31 bits of the head field of its header through the
+  prev_foot and PINUSE_BIT bit of the following chunk header.
+
+  A chunk that's in use looks like:
+
+   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           | Size of previous chunk (if P = 1)                             |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         1| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               |
+         +-                                                             -+
+         |                                                               |
+         +-                                                             -+
+         |                                                               :
+         +-      size - sizeof(size_t) available payload bytes          -+
+         :                                                               |
+ chunk-> +-                                                             -+
+         |                                                               |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+       | Size of next chunk (may or may not be in use)               | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    And if it's free, it looks like this:
+
+   chunk-> +-                                                             -+
+           | User payload (must be in use, or we would have merged!)       |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         0| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Next pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Prev pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               :
+         +-      size - sizeof(struct chunk) unused bytes               -+
+         :                                                               |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Size of this chunk                                            |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+       | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                                                               :
+       +- User payload                                                -+
+       :                                                               |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                                                     |0|
+                                                                     +-+
+  Note that since we always merge adjacent free chunks, the chunks
+  adjacent to a free chunk must be in use.
+
+  Given a pointer to a chunk (which can be derived trivially from the
+  payload pointer) we can, in O(1) time, find out whether the adjacent
+  chunks are free, and if so, unlink them from the lists that they
+  are on and merge them with the current chunk.
+
+  Chunks always begin on even word boundaries, so the mem portion
+  (which is returned to the user) is also on an even word boundary, and
+  thus at least double-word aligned.
+
+  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+  chunk size (which is always a multiple of two words), is an in-use
+  bit for the *previous* chunk.  If that bit is *clear*, then the
+  word before the current chunk size contains the previous chunk
+  size, and can be used to find the front of the previous chunk.
+  The very first chunk allocated always has this bit set, preventing
+  access to non-existent (or non-owned) memory. If pinuse is set for
+  any given chunk, then you CANNOT determine the size of the
+  previous chunk, and might even get a memory addressing fault when
+  trying to do so.
+
+  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+  the chunk size redundantly records whether the current chunk is
+  inuse. This redundancy enables usage checks within free and realloc,
+  and reduces indirection when freeing and consolidating chunks.
+
+  Each freshly allocated chunk must have both cinuse and pinuse set.
+  That is, each allocated chunk borders either a previously allocated
+  and still in-use chunk, or the base of its memory arena. This is
+  ensured by making all allocations from the the `lowest' part of any
+  found chunk.  Further, no free chunk physically borders another one,
+  so each free chunk is known to be preceded and followed by either
+  inuse chunks or the ends of memory.
+
+  Note that the `foot' of the current chunk is actually represented
+  as the prev_foot of the NEXT chunk. This makes it easier to
+  deal with alignments etc but can be very confusing when trying
+  to extend or adapt this code.
+
+  The exceptions to all this are
+
+     1. The special chunk `top' is the top-most available chunk (i.e.,
+        the one bordering the end of available memory). It is treated
+        specially.  Top is never included in any bin, is used only if
+        no other chunk is available, and is released back to the
+        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
+        the top chunk is treated as larger (and thus less well
+        fitting) than any other available chunk.  The top chunk
+        doesn't update its trailing size field since there is no next
+        contiguous chunk that would have to index off it. However,
+        space is still allocated for it (TOP_FOOT_SIZE) to enable
+        separation or merging when space is extended.
+
+     3. Chunks allocated via mmap, which have the lowest-order bit
+        (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
+        PINUSE_BIT in their head fields.  Because they are allocated
+        one-by-one, each must carry its own prev_foot field, which is
+        also used to hold the offset this chunk has within its mmapped
+        region, which is needed to preserve alignment. Each mmapped
+        chunk is trailed by the first two fields of a fake next-chunk
+        for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+  size_t               prev_foot;  /* Size of previous chunk (if free).  */
+  size_t               head;       /* Size and inuse bits. */
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk  mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
+typedef unsigned int bindex_t;         /* Described below */
+typedef unsigned int binmap_t;         /* Described below */
+typedef unsigned int flag_t;           /* The type of various bit flag sets */
+
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE         (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+  The head field of a chunk is or'ed with PINUSE_BIT when previous
+  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+  use. If the chunk was obtained with mmap, the prev_foot field has
+  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
+  mmapped region to the base of the chunk.
+*/
+
+#define PINUSE_BIT          (SIZE_T_ONE)
+#define CINUSE_BIT          (SIZE_T_TWO)
+#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p)           ((p)->head & CINUSE_BIT)
+#define pinuse(p)           ((p)->head & PINUSE_BIT)
+#define chunksize(p)        ((p)->head & ~(INUSE_BITS))
+
+#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
+#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p) CHUNK_OVERHEAD
+
+/* Return true if malloced space is not necessarily cleared */
+#define calloc_must_clear(p) (1)
+
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+  When chunks are not in use, they are treated as nodes of either
+  lists or trees.
+
+  "Small"  chunks are stored in circular doubly-linked lists, and look
+  like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Larger chunks are kept in a form of bitwise digital trees (aka
+  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
+  free chunks greater than 256 bytes, their size doesn't impose any
+  constraints on user chunk sizes.  Each node looks like:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk of same size        |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk of same size       |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to left child (child[0])                  |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to right child (child[1])                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to parent                                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             bin index of this chunk                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space                                      .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
+  of the same size are arranged in a circularly-linked list, with only
+  the oldest chunk (the next to be used, in our FIFO ordering)
+  actually in the tree.  (Tree members are distinguished by a non-null
+  parent pointer.)  If a chunk with the same size an an existing node
+  is inserted, it is linked off the existing node using pointers that
+  work in the same way as fd/bk pointers of small chunks.
+
+  Each tree contains a power of 2 sized range of chunk sizes (the
+  smallest is 0x100 <= x < 0x180), which is is divided in half at each
+  tree level, with the chunks in the smaller half of the range (0x100
+  <= x < 0x140 for the top nose) in the left subtree and the larger
+  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
+  done by inspecting individual bits.
+
+  Using these rules, each node's left subtree contains all smaller
+  sizes than its right subtree.  However, the node at the root of each
+  subtree has no particular ordering relationship to either.  (The
+  dividing line between the subtree sizes is based on trie relation.)
+  If we remove the last chunk of a given size from the interior of the
+  tree, we need to replace it with a leaf node.  The tree ordering
+  rules permit a node to be replaced by any leaf below it.
+
+  The smallest chunk in a tree (a common operation in a best-fit
+  allocator) can be found by walking a path to the leftmost leaf in
+  the tree.  Unlike a usual binary tree, where we follow left child
+  pointers until we reach a null, here we follow the right child
+  pointer any time the left one is null, until we reach a leaf with
+  both child pointers null. The smallest chunk in the tree will be
+  somewhere along that path.
+
+  The worst case number of steps to add, find, or remove a node is
+  bounded by the number of bits differentiating chunks within
+  bins. Under current bin calculations, this ranges from 6 up to 21
+  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+  is of course much better.
+*/
+
+struct malloc_tree_chunk {
+  /* The first four fields must be compatible with malloc_chunk */
+  size_t                    prev_foot;
+  size_t                    head;
+  struct malloc_tree_chunk* fd;
+  struct malloc_tree_chunk* bk;
+
+  struct malloc_tree_chunk* child[2];
+  struct malloc_tree_chunk* parent;
+  bindex_t                  index;
+};
+
+typedef struct malloc_tree_chunk  tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+  Each malloc space may include non-contiguous segments, held in a
+  list headed by an embedded malloc_segment record representing the
+  top-most space. Segments also include flags holding properties of
+  the space. Large chunks that are directly allocated by mmap are not
+  included in this list. They are instead independently created and
+  destroyed without otherwise keeping track of them.
+
+  Segment management mainly comes into play for spaces allocated by
+  MMAP.  Any call to MMAP might or might not return memory that is
+  adjacent to an existing segment.  MORECORE normally contiguously
+  extends the current space, so this space is almost always adjacent,
+  which is simpler and faster to deal with. (This is why MORECORE is
+  used preferentially to MMAP when both are available -- see
+  sys_alloc.)  When allocating using MMAP, we don't use any of the
+  hinting mechanisms (inconsistently) supported in various
+  implementations of unix mmap, or distinguish reserving from
+  committing memory. Instead, we just ask for space, and exploit
+  contiguity when we get it.  It is probably possible to do
+  better than this on some systems, but no general scheme seems
+  to be significantly better.
+
+  Management entails a simpler variant of the consolidation scheme
+  used for chunks to reduce fragmentation -- new adjacent memory is
+  normally prepended or appended to an existing segment. However,
+  there are limitations compared to chunk consolidation that mostly
+  reflect the fact that segment processing is relatively infrequent
+  (occurring only when getting memory from system) and that we
+  don't expect to have huge numbers of segments:
+
+  * Segments are not indexed, so traversal requires linear scans.  (It
+    would be possible to index these, but is not worth the extra
+    overhead and complexity for most programs on most platforms.)
+  * New segments are only appended to old ones when holding top-most
+    memory; if they cannot be prepended to others, they are held in
+    different segments.
+
+  Except for the top-most segment of an mstate, each segment record
+  is kept at the tail of its segment. Segments are added by pushing
+  segment records onto the list headed by &mstate.seg for the
+  containing mstate.
+
+  Segment flags control allocation/merge/deallocation policies:
+  * If EXTERN_BIT set, then we did not allocate this segment,
+    and so should not try to deallocate or merge with others.
+    (This currently holds only for the initial segment passed
+    into create_mspace_with_base.)
+  * If IS_MMAPPED_BIT set, the segment may be merged with
+    other surrounding mmapped segments and trimmed/de-allocated
+    using munmap.
+  * If neither bit is set, then the segment was obtained using
+    MORECORE so can be merged with surrounding MORECORE'd segments
+    and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+  char*        base;             /* base address */
+  size_t       size;             /* allocated size */
+  struct malloc_segment* next;   /* ptr to next segment */
+};
+
+typedef struct malloc_segment  msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+   A malloc_state holds all of the bookkeeping for a space.
+   The main fields are:
+
+  Top
+    The topmost chunk of the currently active segment. Its size is
+    cached in topsize.  The actual size of topmost space is
+    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+    fenceposts and segment records if necessary when getting more
+    space from the system.  The size at which to autotrim top is
+    cached from mparams in trim_check, except that it is disabled if
+    an autotrim fails.
+
+  Designated victim (dv)
+    This is the preferred chunk for servicing small requests that
+    don't have exact fits.  It is normally the chunk split off most
+    recently to service another small request.  Its size is cached in
+    dvsize. The link fields of this chunk are not maintained since it
+    is not kept in a bin.
+
+  SmallBins
+    An array of bin headers for free chunks.  These bins hold chunks
+    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+    chunks of all the same size, spaced 8 bytes apart.  To simplify
+    use in double-linked lists, each bin header acts as a malloc_chunk
+    pointing to the real first node, if it exists (else pointing to
+    itself).  This avoids special-casing for headers.  But to avoid
+    waste, we allocate only the fd/bk pointers of bins, and then use
+    repositioning tricks to treat these as the fields of a chunk.
+
+  TreeBins
+    Treebins are pointers to the roots of trees holding a range of
+    sizes. There are 2 equally spaced treebins for each power of two
+    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+    larger.
+
+  Bin maps
+    There is one bit map for small bins ("smallmap") and one for
+    treebins ("treemap).  Each bin sets its bit when non-empty, and
+    clears the bit when empty.  Bit operations are then used to avoid
+    bin-by-bin searching -- nearly all "search" is done without ever
+    looking at bins that won't be selected.  The bit maps
+    conservatively use 32 bits per map word, even if on 64bit system.
+    For a good description of some of the bit-based techniques used
+    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+    supplement at http://hackersdelight.org/). Many of these are
+    intended to reduce the branchiness of paths through malloc etc, as
+    well as to reduce the number of memory locations read or written.
+
+  Segments
+    A list of segments headed by an embedded malloc_segment record
+    representing the initial space.
+
+  Address check support
+    The least_addr field is the least address ever obtained from
+    MORECORE or MMAP. Attempted frees and reallocs of any address less
+    than this are trapped (unless INSECURE is defined).
+
+  Magic tag
+    A cross-check field that should always hold same value as mparams.magic.
+
+  Flags
+    Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+  Statistics
+    Each space keeps track of current and maximum system memory
+    obtained via MORECORE or MMAP.
+
+  Locking
+    If USE_LOCKS is defined, the "mutex" lock is acquired and released
+    around every public call using this mspace.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS        (32U)
+#define NTREEBINS         (32U)
+#define SMALLBIN_SHIFT    (3U)
+#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT     (8U)
+#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+  binmap_t   smallmap;
+  binmap_t   treemap;
+  size_t     dvsize;
+  size_t     topsize;
+  char*      least_addr;
+  mchunkptr  dv;
+  mchunkptr  top;
+  size_t     magic;
+  mchunkptr  smallbins[(NSMALLBINS+1)*2];
+  tbinptr    treebins[NTREEBINS];
+  size_t     footprint;
+  size_t     max_footprint;
+  flag_t     mflags;
+  void      *user_data;
+#if USE_LOCKS
+  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+  msegment   seg;
+};
+
+typedef struct malloc_state*    mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+  malloc_params holds global properties, including those that can be
+  dynamically set using mallopt. There is a single instance, mparams,
+  initialized in init_mparams.
+*/
+
+struct malloc_params {
+  size_t magic;
+  size_t page_size;
+  size_t granularity;
+  flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* The global malloc_state used for all non-"mspace" calls */
+//static struct malloc_state _gm_;
+//#define gm                 (&_gm_)
+//#define is_global(M)       ((M) == &_gm_)
+#define is_initialized(M)  ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
+#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
+#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+  ((M)->mflags | USE_LOCK_BIT) :\
+  ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+  (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))
+
+#define is_page_aligned(S)\
+   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/*  True if segment S holds address A */
+#define segment_holds(S, A)\
+  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= sp->base && addr < sp->base + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+      return 1;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+
+
+/*
+  TOP_FOOT_SIZE is padding at the end of a segment, including space
+  that may be needed to place segment records and fenceposts when new
+  noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* -------------------------------  Hooks -------------------------------- */
+
+/*
+  PREACTION should be defined to return 0 on success, and nonzero on
+  failure. If you are not using locking, you can redefine these to do
+  anything you like.
+*/
+
+#if USE_LOCKS
+
+/* Ensure locks are initialized */
+#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())
+
+#define PREACTION(M)  ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif  /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif  /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+  USAGE_ERROR_ACTION is triggered on detected bad frees and
+  reallocs. The argument p is an address that might have triggered the
+  fault. It is ignored by the two predefined actions, but might be
+  useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT(m->user_data)
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT(m->user_data)
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_malloc_state(M)       do_check_malloc_state(M)
+
+static void   do_check_any_chunk(mstate m, mchunkptr p);
+static void   do_check_top_chunk(mstate m, mchunkptr p);
+static void   do_check_inuse_chunk(mstate m, mchunkptr p);
+static void   do_check_free_chunk(mstate m, mchunkptr p);
+static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void   do_check_tree(mstate m, tchunkptr t);
+static void   do_check_treebin(mstate m, bindex_t i);
+static void   do_check_smallbin(mstate m, bindex_t i);
+static void   do_check_malloc_state(mstate m);
+static int    bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i)     (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I */
+#if defined(__GNUC__) && defined(i386)
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K;\
+    __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm"  (X));\
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int Y = (unsigned int)X;\
+    unsigned int N = ((Y - 0x100) >> 16) & 8;\
+    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+    N += K;\
+    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+    K = 14 - N + ((Y <<= K) >> 15);\
+    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+  }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+   ((i == NTREEBINS-1)? 0 : \
+    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
+   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i)              ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
+#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
+
+#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
+#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
+#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
+
+/* index corresponding to given bit */
+
+#if defined(__GNUC__) && defined(i386)
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\
+  I = (bindex_t)J;\
+}
+
+#else /* GNUC */
+#if  USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else /* USE_BUILTIN_FFS */
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int Y = X - 1;\
+  unsigned int K = Y >> (16-4) & 16;\
+  unsigned int N = K;        Y >>= K;\
+  N += K = Y >> (8-3) &  8;  Y >>= K;\
+  N += K = Y >> (4-2) &  4;  Y >>= K;\
+  N += K = Y >> (2-1) &  2;  Y >>= K;\
+  N += K = Y >> (1-0) &  1;  Y >>= K;\
+  I = (bindex_t)(N + Y);\
+}
+#endif /* USE_BUILTIN_FFS */
+#endif /* GNUC */
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x)         ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x)         ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+  For security, the main invariant is that malloc/free/etc never
+  writes to a static address other than malloc_state, unless static
+  malloc_state itself has been corrupted, which cannot occur via
+  malloc (because of these checks). In essence this means that we
+  believe all pointers, sizes, maps etc held in malloc_state, but
+  check all of those linked or offsetted from other embedded data
+  structures.  These checks are interspersed with main code in a way
+  that tends to minimize their run-time cost.
+
+  When FOOTERS is defined, in addition to range checking, we also
+  verify footer fields of inuse chunks, which can be used guarantee
+  that the mstate controlling malloc/free is intact.  This is a
+  streamlined version of the approach described by William Robertson
+  et al in "Run-time Detection of Heap-based Overflows" LISA'03
+  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+  of an inuse chunk holds the xor of its mstate and a random seed,
+  that is checked upon calls to free() and realloc().  This is
+  (probablistically) unguessable from outside the program, but can be
+  computed by any code successfully malloc'ing any chunk, so does not
+  itself provide protection against code that has already broken
+  security through some other means.  Unlike Robertson et al, we
+  always dynamically check addresses of all offset chunks (previous,
+  next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n)    ((char*)(p) < (char*)(n))
+/* Check if p has its cinuse bit on */
+#define ok_cinuse(p)     cinuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p)     pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n)    (1)
+#define ok_cinuse(p)     (1)
+#define ok_pinuse(p)     (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M)      ((M)->magic == mparams.magic)
+#else  /* (FOOTERS && !INSECURE) */
+#define ok_magic(M)      (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e)  __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e)  (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e)  (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+  ((mstate)(((mchunkptr)((char*)(p) +\
+    (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+  mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+  if (mparams.page_size == 0) {
+    size_t s;
+
+    mparams.default_mflags = USE_LOCK_BIT;
+
+#if (FOOTERS && !INSECURE)
+    {
+#if USE_DEV_RANDOM
+      int fd;
+      unsigned char buf[sizeof(size_t)];
+      /* Try to use /dev/urandom, else fall back on using time */
+      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+        s = *((size_t *) buf);
+        close(fd);
+      }
+      else
+#endif /* USE_DEV_RANDOM */
+        s = (size_t)(time(0) ^ (size_t)0x55555555U);
+
+      s |= (size_t)8U;    /* ensure nonzero */
+      s &= ~(size_t)7U;   /* improve chances of fault for bad values */
+
+    }
+#else /* (FOOTERS && !INSECURE) */
+    s = (size_t)0x58585858U;
+#endif /* (FOOTERS && !INSECURE) */
+    ACQUIRE_MAGIC_INIT_LOCK();
+    if (mparams.magic == 0) {
+      mparams.magic = s;
+      /* Set up lock for main malloc area */
+      //INITIAL_LOCK(&gm->mutex);
+      //gm->mflags = mparams.default_mflags;
+    }
+    RELEASE_MAGIC_INIT_LOCK();
+
+
+    mparams.page_size = malloc_getpagesize;
+    mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
+                           DEFAULT_GRANULARITY : mparams.page_size);
+
+    /* Sanity-check configuration:
+       size_t must be unsigned and as wide as pointer type.
+       ints must be at least 4 bytes.
+       alignment must be at least 8.
+       Alignment, min chunk size, and page size must all be powers of 2.
+    */
+    if ((sizeof(size_t) != sizeof(char*)) ||
+        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
+        (sizeof(int) < 4)  ||
+        (MALLOC_ALIGNMENT < (size_t)8U) ||
+        ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||
+        ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||
+        ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
+        ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))
+      ABORT(NULL);
+  }
+  return 0;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+  size_t val = (size_t)value;
+  init_mparams();
+  switch(param_number) {
+  case M_GRANULARITY:
+    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+      mparams.granularity = val;
+      return 1;
+    }
+    else
+      return 0;
+  default:
+    return 0;
+  }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc  */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+  assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(m->user_data, ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+  msegmentptr sp = segment_holding(m, (char*)p);
+  size_t  sz = chunksize(p);
+  assert(m->user_data, sp != 0);
+  assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(m->user_data, ok_address(m, p));
+  assert(m->user_data, sz == m->topsize);
+  assert(m->user_data, sz > 0);
+  assert(m->user_data, sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+  assert(m->user_data, pinuse(p));
+  assert(m->user_data, !next_pinuse(p));
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+  do_check_any_chunk(m, p);
+  assert(m->user_data, cinuse(p));
+  assert(m->user_data, next_pinuse(p));
+  /* If not pinuse, previous chunk has OK offset */
+  assert(m->user_data, pinuse(p) || next_chunk(prev_chunk(p)) == p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+  size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+  mchunkptr next = chunk_plus_offset(p, sz);
+  do_check_any_chunk(m, p);
+  assert(m->user_data, !cinuse(p));
+  assert(m->user_data, !next_pinuse(p));
+  if (p != m->dv && p != m->top) {
+    if (sz >= MIN_CHUNK_SIZE) {
+      assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
+      assert(m->user_data, is_aligned(chunk2mem(p)));
+      assert(m->user_data, next->prev_foot == sz);
+      assert(m->user_data, pinuse(p));
+      assert(m->user_data, next == m->top || cinuse(next));
+      assert(m->user_data, p->fd->bk == p);
+      assert(m->user_data, p->bk->fd == p);
+    }
+    else  /* markers are always of size SIZE_T_SIZE */
+      assert(m->user_data, sz == SIZE_T_SIZE);
+  }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+    do_check_inuse_chunk(m, p);
+    assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
+    assert(m->user_data, sz >= MIN_CHUNK_SIZE);
+    assert(m->user_data, sz >= s);
+    /* size is less than MIN_CHUNK_SIZE more than request */
+    assert(m->user_data, sz < (s + MIN_CHUNK_SIZE));
+  }
+}
+
+/* Check a tree and its subtrees.  */
+static void do_check_tree(mstate m, tchunkptr t) {
+  tchunkptr head = 0;
+  tchunkptr u = t;
+  bindex_t tindex = t->index;
+  size_t tsize = chunksize(t);
+  bindex_t idx;
+  compute_tree_index(tsize, idx);
+  assert(m->user_data, tindex == idx);
+  assert(m->user_data, tsize >= MIN_LARGE_SIZE);
+  assert(m->user_data, tsize >= minsize_for_tree_index(idx));
+  assert(m->user_data, (idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+  do { /* traverse through chain of same-sized nodes */
+    do_check_any_chunk(m, ((mchunkptr)u));
+    assert(m->user_data, u->index == tindex);
+    assert(m->user_data, chunksize(u) == tsize);
+    assert(m->user_data, !cinuse(u));
+    assert(m->user_data, !next_pinuse(u));
+    assert(m->user_data, u->fd->bk == u);
+    assert(m->user_data, u->bk->fd == u);
+    if (u->parent == 0) {
+      assert(m->user_data, u->child[0] == 0);
+      assert(m->user_data, u->child[1] == 0);
+    }
+    else {
+      assert(m->user_data, head == 0); /* only one node on chain has parent */
+      head = u;
+      assert(m->user_data, u->parent != u);
+      assert(m->user_data, u->parent->child[0] == u ||
+             u->parent->child[1] == u ||
+             *((tbinptr*)(u->parent)) == u);
+      if (u->child[0] != 0) {
+        assert(m->user_data, u->child[0]->parent == u);
+        assert(m->user_data, u->child[0] != u);
+        do_check_tree(m, u->child[0]);
+      }
+      if (u->child[1] != 0) {
+        assert(m->user_data, u->child[1]->parent == u);
+        assert(m->user_data, u->child[1] != u);
+        do_check_tree(m, u->child[1]);
+      }
+      if (u->child[0] != 0 && u->child[1] != 0) {
+        assert(m->user_data, chunksize(u->child[0]) < chunksize(u->child[1]));
+      }
+    }
+    u = u->fd;
+  } while (u != t);
+  assert(m->user_data, head != 0);
+}
+
+/*  Check all the chunks in a treebin.  */
+static void do_check_treebin(mstate m, bindex_t i) {
+  tbinptr* tb = treebin_at(m, i);
+  tchunkptr t = *tb;
+  int empty = (m->treemap & (1U << i)) == 0;
+  if (t == 0)
+    assert(m->user_data, empty);
+  if (!empty)
+    do_check_tree(m, t);
+}
+
+/*  Check all the chunks in a smallbin.  */
+static void do_check_smallbin(mstate m, bindex_t i) {
+  sbinptr b = smallbin_at(m, i);
+  mchunkptr p = b->bk;
+  unsigned int empty = (m->smallmap & (1U << i)) == 0;
+  if (p == b)
+    assert(m->user_data, empty);
+  if (!empty) {
+    for (; p != b; p = p->bk) {
+      size_t size = chunksize(p);
+      mchunkptr q;
+      /* each chunk claims to be free */
+      do_check_free_chunk(m, p);
+      /* chunk belongs in bin */
+      assert(m->user_data, small_index(size) == i);
+      assert(m->user_data, p->bk == b || chunksize(p->bk) == chunksize(p));
+      /* chunk is followed by an inuse chunk */
+      q = next_chunk(p);
+      if (q->head != FENCEPOST_HEAD)
+        do_check_inuse_chunk(m, q);
+    }
+  }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+  size_t size = chunksize(x);
+  if (is_small(size)) {
+    bindex_t sidx = small_index(size);
+    sbinptr b = smallbin_at(m, sidx);
+    if (smallmap_is_marked(m, sidx)) {
+      mchunkptr p = b;
+      do {
+        if (p == x)
+          return 1;
+      } while ((p = p->fd) != b);
+    }
+  }
+  else {
+    bindex_t tidx;
+    compute_tree_index(size, tidx);
+    if (treemap_is_marked(m, tidx)) {
+      tchunkptr t = *treebin_at(m, tidx);
+      size_t sizebits = size << leftshift_for_tree_index(tidx);
+      while (t != 0 && chunksize(t) != size) {
+        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+        sizebits <<= 1;
+      }
+      if (t != 0) {
+        tchunkptr u = t;
+        do {
+          if (u == (tchunkptr)x)
+            return 1;
+        } while ((u = u->fd) != t);
+      }
+    }
+  }
+  return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+  size_t sum = 0;
+  if (is_initialized(m)) {
+    msegmentptr s = &m->seg;
+    sum += m->topsize + TOP_FOOT_SIZE;
+    while (s != 0) {
+      mchunkptr q = align_as_chunk(s->base);
+      mchunkptr lastq = 0;
+      assert(m->user_data, pinuse(q));
+      while (segment_holds(s, q) &&
+             q != m->top && q->head != FENCEPOST_HEAD) {
+        sum += chunksize(q);
+        if (cinuse(q)) {
+          assert(m->user_data, !bin_find(m, q));
+          do_check_inuse_chunk(m, q);
+        }
+        else {
+          assert(m->user_data, q == m->dv || bin_find(m, q));
+          assert(m->user_data, lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
+          do_check_free_chunk(m, q);
+        }
+        lastq = q;
+        q = next_chunk(q);
+      }
+      s = s->next;
+    }
+  }
+  return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+  bindex_t i;
+  size_t total;
+  /* check bins */
+  for (i = 0; i < NSMALLBINS; ++i)
+    do_check_smallbin(m, i);
+  for (i = 0; i < NTREEBINS; ++i)
+    do_check_treebin(m, i);
+
+  if (m->dvsize != 0) { /* check dv chunk */
+    do_check_any_chunk(m, m->dv);
+    assert(m->user_data, m->dvsize == chunksize(m->dv));
+    assert(m->user_data, m->dvsize >= MIN_CHUNK_SIZE);
+    assert(m->user_data, bin_find(m, m->dv) == 0);
+  }
+
+  if (m->top != 0) {   /* check top chunk */
+    do_check_top_chunk(m, m->top);
+    assert(m->user_data, m->topsize == chunksize(m->top));
+    assert(m->user_data, m->topsize > 0);
+    assert(m->user_data, bin_find(m, m->top) == 0);
+  }
+
+  total = traverse_and_check(m);
+  assert(m->user_data, total <= m->footprint);
+  assert(m->user_data, m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  if (!PREACTION(m)) {
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      size_t nfree = SIZE_T_ONE; /* top always free */
+      size_t mfree = m->topsize + TOP_FOOT_SIZE;
+      size_t sum = mfree;
+      msegmentptr s = &m->seg;
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          size_t sz = chunksize(q);
+          sum += sz;
+          if (!cinuse(q)) {
+            mfree += sz;
+            ++nfree;
+          }
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+
+      nm.arena    = sum;
+      nm.ordblks  = nfree;
+      nm.hblkhd   = m->footprint - sum;
+      nm.usmblks  = m->max_footprint;
+      nm.uordblks = m->footprint - mfree;
+      nm.fordblks = mfree;
+      nm.keepcost = m->topsize;
+    }
+
+    POSTACTION(m);
+  }
+  return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+  if (!PREACTION(m)) {
+    size_t maxfp = 0;
+    size_t fp = 0;
+    size_t used = 0;
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      msegmentptr s = &m->seg;
+      maxfp = m->max_footprint;
+      fp = m->footprint;
+      used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          if (!cinuse(q))
+            used -= chunksize(q);
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+    }
+
+    PRINT((m->user_data, "max system bytes = %10lu\n", (unsigned long)(maxfp)));
+    PRINT((m->user_data, "system bytes     = %10lu\n", (unsigned long)(fp)));
+    PRINT((m->user_data, "in use bytes     = %10lu\n", (unsigned long)(used)));
+
+    POSTACTION(m);
+  }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+  Various forms of linking and unlinking are defined as macros.  Even
+  the ones for trees, which are very long but have very short typical
+  paths.  This is ugly but reduces reliance on inlining support of
+  compilers.
+*/
+
+/* Link a free chunk into a smallbin  */
+#define insert_small_chunk(M, P, S) {\
+  bindex_t I  = small_index(S);\
+  mchunkptr B = smallbin_at(M, I);\
+  mchunkptr F = B;\
+  assert((M)->user_data, S >= MIN_CHUNK_SIZE);\
+  if (!smallmap_is_marked(M, I))\
+    mark_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, B->fd)))\
+    F = B->fd;\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+  B->fd = P;\
+  F->bk = P;\
+  P->fd = F;\
+  P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin  */
+#define unlink_small_chunk(M, P, S) {\
+  mchunkptr F = P->fd;\
+  mchunkptr B = P->bk;\
+  bindex_t I = small_index(S);\
+  assert((M)->user_data, P != B);\
+  assert((M)->user_data, P != F);\
+  assert((M)->user_data, chunksize(P) == small_index2size(I));\
+  if (F == B)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+                   (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+    F->bk = B;\
+    B->fd = F;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+  mchunkptr F = P->fd;\
+  assert((M)->user_data, P != B);\
+  assert((M)->user_data, P != F);\
+  assert((M)->user_data, chunksize(P) == small_index2size(I));\
+  if (B == F)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, F))) {\
+    B->fd = F;\
+    F->bk = B;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+  size_t DVS = M->dvsize;\
+  if (DVS != 0) {\
+    mchunkptr DV = M->dv;\
+    assert((M)->user_data, is_small(DVS));\
+    insert_small_chunk(M, DV, DVS);\
+  }\
+  M->dvsize = S;\
+  M->dv = P;\
+}
+
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+  tbinptr* H;\
+  bindex_t I;\
+  compute_tree_index(S, I);\
+  H = treebin_at(M, I);\
+  X->index = I;\
+  X->child[0] = X->child[1] = 0;\
+  if (!treemap_is_marked(M, I)) {\
+    mark_treemap(M, I);\
+    *H = X;\
+    X->parent = (tchunkptr)H;\
+    X->fd = X->bk = X;\
+  }\
+  else {\
+    tchunkptr T = *H;\
+    size_t K = S << leftshift_for_tree_index(I);\
+    for (;;) {\
+      if (chunksize(T) != S) {\
+        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+        K <<= 1;\
+        if (*C != 0)\
+          T = *C;\
+        else if (RTCHECK(ok_address(M, C))) {\
+          *C = X;\
+          X->parent = T;\
+          X->fd = X->bk = X;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+      else {\
+        tchunkptr F = T->fd;\
+        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+          T->fd = F->bk = X;\
+          X->fd = F;\
+          X->bk = T;\
+          X->parent = 0;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+    }\
+  }\
+}
+
+/*
+  Unlink steps:
+
+  1. If x is a chained node, unlink it from its same-sized fd/bk links
+     and choose its bk node as its replacement.
+  2. If x was the last node of its size, but not a leaf node, it must
+     be replaced with a leaf node (not merely one with an open left or
+     right), to make sure that lefts and rights of descendents
+     correspond properly to bit masks.  We use the rightmost descendent
+     of x.  We could use any other leaf, but this is easy to locate and
+     tends to counteract removal of leftmosts elsewhere, and so keeps
+     paths shorter than minimally guaranteed.  This doesn't loop much
+     because on average a node in a tree is near the bottom.
+  3. If x is the base of a chain (i.e., has parent links) relink
+     x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+  tchunkptr XP = X->parent;\
+  tchunkptr R;\
+  if (X->bk != X) {\
+    tchunkptr F = X->fd;\
+    R = X->bk;\
+    if (RTCHECK(ok_address(M, F))) {\
+      F->bk = R;\
+      R->fd = F;\
+    }\
+    else {\
+      CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+  else {\
+    tchunkptr* RP;\
+    if (((R = *(RP = &(X->child[1]))) != 0) ||\
+        ((R = *(RP = &(X->child[0]))) != 0)) {\
+      tchunkptr* CP;\
+      while ((*(CP = &(R->child[1])) != 0) ||\
+             (*(CP = &(R->child[0])) != 0)) {\
+        R = *(RP = CP);\
+      }\
+      if (RTCHECK(ok_address(M, RP)))\
+        *RP = 0;\
+      else {\
+        CORRUPTION_ERROR_ACTION(M);\
+      }\
+    }\
+  }\
+  if (XP != 0) {\
+    tbinptr* H = treebin_at(M, X->index);\
+    if (X == *H) {\
+      if ((*H = R) == 0) \
+        clear_treemap(M, X->index);\
+    }\
+    else if (RTCHECK(ok_address(M, XP))) {\
+      if (XP->child[0] == X) \
+        XP->child[0] = R;\
+      else \
+        XP->child[1] = R;\
+    }\
+    else\
+      CORRUPTION_ERROR_ACTION(M);\
+    if (R != 0) {\
+      if (RTCHECK(ok_address(M, R))) {\
+        tchunkptr C0, C1;\
+        R->parent = XP;\
+        if ((C0 = X->child[0]) != 0) {\
+          if (RTCHECK(ok_address(M, C0))) {\
+            R->child[0] = C0;\
+            C0->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+        if ((C1 = X->child[1]) != 0) {\
+          if (RTCHECK(ok_address(M, C1))) {\
+            R->child[1] = C1;\
+            C1->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+      }\
+      else\
+        CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+  if (is_small(S)) insert_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+  if (is_small(S)) unlink_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+  /* Ensure alignment */
+  size_t offset = align_offset(chunk2mem(p));
+  p = (mchunkptr)((char*)p + offset);
+  psize -= offset;
+
+  m->top = p;
+  m->topsize = psize;
+  p->head = psize | PINUSE_BIT;
+  /* set size of fake trailing chunk holding overhead space only once */
+  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+  /* Establish circular links for smallbins */
+  bindex_t i;
+  for (i = 0; i < NSMALLBINS; ++i) {
+    sbinptr bin = smallbin_at(m,i);
+    bin->fd = bin->bk = bin;
+  }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+  int i;
+  ++malloc_corruption_error_count;
+  /* Reinitialize fields to forget about all memory */
+  m->smallbins = m->treebins = 0;
+  m->dvsize = m->topsize = 0;
+  m->seg.base = 0;
+  m->seg.size = 0;
+  m->seg.next = 0;
+  m->top = m->dv = 0;
+  for (i = 0; i < NTREEBINS; ++i)
+    *treebin_at(m, i) = 0;
+  init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+                           size_t nb) {
+  mchunkptr p = align_as_chunk(newbase);
+  mchunkptr oldfirst = align_as_chunk(oldbase);
+  size_t psize = (char*)oldfirst - (char*)p;
+  mchunkptr q = chunk_plus_offset(p, nb);
+  size_t qsize = psize - nb;
+  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+  assert(m->user_data, (char*)oldfirst > (char*)q);
+  assert(m->user_data, pinuse(oldfirst));
+  assert(m->user_data, qsize >= MIN_CHUNK_SIZE);
+
+  /* consolidate remainder with first chunk of old base */
+  if (oldfirst == m->top) {
+    size_t tsize = m->topsize += qsize;
+    m->top = q;
+    q->head = tsize | PINUSE_BIT;
+    check_top_chunk(m, q);
+  }
+  else if (oldfirst == m->dv) {
+    size_t dsize = m->dvsize += qsize;
+    m->dv = q;
+    set_size_and_pinuse_of_free_chunk(q, dsize);
+  }
+  else {
+    if (!cinuse(oldfirst)) {
+      size_t nsize = chunksize(oldfirst);
+      unlink_chunk(m, oldfirst, nsize);
+      oldfirst = chunk_plus_offset(oldfirst, nsize);
+      qsize += nsize;
+    }
+    set_free_with_pinuse(q, qsize, oldfirst);
+    insert_chunk(m, q, qsize);
+    check_free_chunk(m, q);
+  }
+
+  check_malloced_chunk(m, chunk2mem(p), nb);
+  return chunk2mem(p);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+  MALLOC_FAILURE_ACTION;
+  return 0;
+}
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+  tchunkptr v = 0;
+  size_t rsize = -nb; /* Unsigned negation */
+  tchunkptr t;
+  bindex_t idx;
+  compute_tree_index(nb, idx);
+
+  if ((t = *treebin_at(m, idx)) != 0) {
+    /* Traverse tree for this bin looking for node with size == nb */
+    size_t sizebits = nb << leftshift_for_tree_index(idx);
+    tchunkptr rst = 0;  /* The deepest untaken right subtree */
+    for (;;) {
+      tchunkptr rt;
+      size_t trem = chunksize(t) - nb;
+      if (trem < rsize) {
+        v = t;
+        if ((rsize = trem) == 0)
+          break;
+      }
+      rt = t->child[1];
+      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+      if (rt != 0 && rt != t)
+        rst = rt;
+      if (t == 0) {
+        t = rst; /* set t to least subtree holding sizes > nb */
+        break;
+      }
+      sizebits <<= 1;
+    }
+  }
+
+  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+    if (leftbits != 0) {
+      bindex_t i;
+      binmap_t leastbit = least_bit(leftbits);
+      compute_bit2idx(leastbit, i);
+      t = *treebin_at(m, i);
+    }
+  }
+
+  while (t != 0) { /* find smallest of tree or subtree */
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+    t = leftmost_child(t);
+  }
+
+  /*  If dv is a better fit, return 0 so malloc will use it */
+  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+    if (RTCHECK(ok_address(m, v))) { /* split */
+      mchunkptr r = chunk_plus_offset(v, nb);
+      assert(m->user_data, chunksize(v) == rsize + nb);
+      if (RTCHECK(ok_next(v, r))) {
+        unlink_large_chunk(m, v);
+        if (rsize < MIN_CHUNK_SIZE)
+          set_inuse_and_pinuse(m, v, (rsize + nb));
+        else {
+          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+          set_size_and_pinuse_of_free_chunk(r, rsize);
+          insert_chunk(m, r, rsize);
+        }
+        return chunk2mem(v);
+      }
+    }
+    CORRUPTION_ERROR_ACTION(m);
+  }
+  return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+  tchunkptr t, v;
+  size_t rsize;
+  bindex_t i;
+  binmap_t leastbit = least_bit(m->treemap);
+  compute_bit2idx(leastbit, i);
+
+  v = t = *treebin_at(m, i);
+  rsize = chunksize(t) - nb;
+
+  while ((t = leftmost_child(t)) != 0) {
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+  }
+
+  if (RTCHECK(ok_address(m, v))) {
+    mchunkptr r = chunk_plus_offset(v, nb);
+    assert(m->user_data, chunksize(v) == rsize + nb);
+    if (RTCHECK(ok_next(v, r))) {
+      unlink_large_chunk(m, v);
+      if (rsize < MIN_CHUNK_SIZE)
+        set_inuse_and_pinuse(m, v, (rsize + nb));
+      else {
+        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        replace_dv(m, r, rsize);
+      }
+      return chunk2mem(v);
+    }
+  }
+
+  CORRUPTION_ERROR_ACTION(m);
+  return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+  if (bytes >= MAX_REQUEST) {
+    MALLOC_FAILURE_ACTION;
+    return 0;
+  }
+  if (!PREACTION(m)) {
+    mchunkptr oldp = mem2chunk(oldmem);
+    size_t oldsize = chunksize(oldp);
+    mchunkptr next = chunk_plus_offset(oldp, oldsize);
+    mchunkptr newp = 0;
+    void* extra = 0;
+
+    /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
+                ok_next(oldp, next) && ok_pinuse(next))) {
+      size_t nb = request2size(bytes);
+      if (oldsize >= nb) { /* already big enough */
+        size_t rsize = oldsize - nb;
+        newp = oldp;
+        if (rsize >= MIN_CHUNK_SIZE) {
+          mchunkptr remainder = chunk_plus_offset(newp, nb);
+          set_inuse(m, newp, nb);
+          set_inuse(m, remainder, rsize);
+          extra = chunk2mem(remainder);
+        }
+      }
+      else if (next == m->top && oldsize + m->topsize > nb) {
+        /* Expand into top */
+        size_t newsize = oldsize + m->topsize;
+        size_t newtopsize = newsize - nb;
+        mchunkptr newtop = chunk_plus_offset(oldp, nb);
+        set_inuse(m, oldp, nb);
+        newtop->head = newtopsize |PINUSE_BIT;
+        m->top = newtop;
+        m->topsize = newtopsize;
+        newp = oldp;
+      }
+    }
+    else {
+      USAGE_ERROR_ACTION(m, oldmem);
+      POSTACTION(m);
+      return 0;
+    }
+
+    POSTACTION(m);
+
+    if (newp != 0) {
+      if (extra != 0) {
+        internal_free(m, extra);
+      }
+      check_inuse_chunk(m, newp);
+      return chunk2mem(newp);
+    }
+    else {
+      void* newmem = internal_malloc(m, bytes);
+      if (newmem != 0) {
+        size_t oc = oldsize - overhead_for(oldp);
+        MEMCPY(newmem, oldmem, (oc < bytes)? oc : bytes);
+        internal_free(m, oldmem);
+      }
+      return newmem;
+    }
+  }
+  return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */
+    return internal_malloc(m, bytes);
+  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+    alignment = MIN_CHUNK_SIZE;
+  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+    size_t a = MALLOC_ALIGNMENT << 1;
+    while (a < alignment) a <<= 1;
+    alignment = a;
+  }
+
+  if (bytes >= MAX_REQUEST - alignment) {
+    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
+      MALLOC_FAILURE_ACTION;
+    }
+  }
+  else {
+    size_t nb = request2size(bytes);
+    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+    char* mem = (char*)internal_malloc(m, req);
+    if (mem != 0) {
+      void* leader = 0;
+      void* trailer = 0;
+      mchunkptr p = mem2chunk(mem);
+
+      if (PREACTION(m)) return 0;
+      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+        /*
+          Find an aligned spot inside chunk.  Since we need to give
+          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+          the first calculation places us at a spot with less than
+          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+          We've allocated enough total room so that this is always
+          possible.
+        */
+        char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+                                                       alignment -
+                                                       SIZE_T_ONE)) &
+                                             -alignment));
+        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+          br : br+alignment;
+        mchunkptr newp = (mchunkptr)pos;
+        size_t leadsize = pos - (char*)(p);
+        size_t newsize = chunksize(p) - leadsize;
+
+        /* Otherwise, give back leader, use the rest */
+        set_inuse(m, newp, newsize);
+        set_inuse(m, p, leadsize);
+        leader = chunk2mem(p);
+
+        p = newp;
+      }
+
+      assert(m->user_data, chunksize(p) >= nb);
+      assert(m->user_data, (((size_t)(chunk2mem(p))) % alignment) == 0);
+      check_inuse_chunk(m, p);
+      POSTACTION(m);
+      if (leader != 0) {
+        internal_free(m, leader);
+      }
+      if (trailer != 0) {
+        internal_free(m, trailer);
+      }
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+static mstate init_user_mstate(char* tbase, size_t tsize, void *user_data) {
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  mchunkptr mn;
+  mchunkptr msp = align_as_chunk(tbase);
+  mstate m = (mstate)(chunk2mem(msp));
+  MEMCLEAR(m, msize);
+  INITIAL_LOCK(&m->mutex);
+  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
+  m->seg.base = m->least_addr = tbase;
+  m->seg.size = m->footprint = m->max_footprint = tsize;
+  m->magic = mparams.magic;
+  m->mflags = mparams.default_mflags;
+  m->user_data = user_data;
+  init_bins(m);
+  mn = next_chunk(mem2chunk(m));
+  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+  check_top_chunk(m, m->top);
+  return m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data) {
+  mstate m = 0;
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  init_mparams(); /* Ensure pagesize etc initialized */
+
+  if (capacity > msize + TOP_FOOT_SIZE &&
+      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    m = init_user_mstate((char*)base, capacity, user_data);
+    set_lock(m, locked);
+  }
+  return (mspace)m;
+}
+
+/*
+  mspace versions of routines are near-clones of the global
+  versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (!PREACTION(ms)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = ms->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+        mchunkptr b, p;
+        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+        b = smallbin_at(ms, idx);
+        p = b->fd;
+        assert(ms->user_data, chunksize(p) == small_index2size(idx));
+        unlink_first_small_chunk(ms, b, p, idx);
+        set_inuse_and_pinuse(ms, p, small_index2size(idx));
+        mem = chunk2mem(p);
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+
+      else if (nb > ms->dvsize) {
+        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+          mchunkptr b, p, r;
+          size_t rsize;
+          bindex_t i;
+          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+          binmap_t leastbit = least_bit(leftbits);
+          compute_bit2idx(leastbit, i);
+          b = smallbin_at(ms, i);
+          p = b->fd;
+          assert(ms->user_data, chunksize(p) == small_index2size(i));
+          unlink_first_small_chunk(ms, b, p, i);
+          rsize = small_index2size(i) - nb;
+          /* Fit here cannot be remainderless if 4byte sizes */
+          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+            set_inuse_and_pinuse(ms, p, small_index2size(i));
+          else {
+            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+            r = chunk_plus_offset(p, nb);
+            set_size_and_pinuse_of_free_chunk(r, rsize);
+            replace_dv(ms, r, rsize);
+          }
+          mem = chunk2mem(p);
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+
+        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+    }
+
+    if (nb <= ms->dvsize) {
+      size_t rsize = ms->dvsize - nb;
+      mchunkptr p = ms->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+        ms->dvsize = rsize;
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      }
+      else { /* exhaust dv */
+        size_t dvs = ms->dvsize;
+        ms->dvsize = 0;
+        ms->dv = 0;
+        set_inuse_and_pinuse(ms, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < ms->topsize) { /* Split top */
+      size_t rsize = ms->topsize -= nb;
+      mchunkptr p = ms->top;
+      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(ms, ms->top);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(ms, nb);
+
+  postaction:
+    POSTACTION(ms);
+    return mem;
+  }
+
+  return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+        size_t psize = chunksize(p);
+        mchunkptr next = chunk_plus_offset(p, psize);
+        if (!pinuse(p)) {
+          size_t prevsize = p->prev_foot;
+
+          mchunkptr prev = chunk_minus_offset(p, prevsize);
+          psize += prevsize;
+          p = prev;
+          if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+            if (p != fm->dv) {
+              unlink_chunk(fm, p, prevsize);
+            }
+            else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+              fm->dvsize = psize;
+              set_free_with_pinuse(p, psize, next);
+              goto postaction;
+            }
+          }
+          else
+            goto erroraction;
+        }
+
+        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+          if (!cinuse(next)) {  /* consolidate forward */
+            if (next == fm->top) {
+              size_t tsize = fm->topsize += psize;
+              fm->top = p;
+              p->head = tsize | PINUSE_BIT;
+              if (p == fm->dv) {
+                fm->dv = 0;
+                fm->dvsize = 0;
+              }
+              goto postaction;
+            }
+            else if (next == fm->dv) {
+              size_t dsize = fm->dvsize += psize;
+              fm->dv = p;
+              set_size_and_pinuse_of_free_chunk(p, dsize);
+              goto postaction;
+            }
+            else {
+              size_t nsize = chunksize(next);
+              psize += nsize;
+              unlink_chunk(fm, next, nsize);
+              set_size_and_pinuse_of_free_chunk(p, psize);
+              if (p == fm->dv) {
+                fm->dvsize = psize;
+                goto postaction;
+              }
+            }
+          }
+          else
+            set_free_with_pinuse(p, psize, next);
+          insert_chunk(fm, p, psize);
+          check_free_chunk(fm, p);
+          goto postaction;
+        }
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+        (req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = internal_malloc(ms, req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    MEMCLEAR(mem, req);
+  return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    mspace_free(msp, oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if FOOTERS
+    mchunkptr p  = mem2chunk(oldmem);
+    mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(ms)) {
+      USAGE_ERROR_ACTION(ms,ms);
+      return 0;
+    }
+    return internal_realloc(ms, oldmem, bytes);
+  }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return internal_memalign(ms, alignment, bytes);
+}
+
+void mspace_malloc_stats(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    internal_malloc_stats(ms);
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+}
+
+size_t mspace_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->footprint;
+  } else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->max_footprint;
+  } else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+int mspace_mallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
diff --git a/xddm/display/mspace.h b/xddm/display/mspace.h
new file mode 100644
index 0000000..96b0593
--- /dev/null
+++ b/xddm/display/mspace.h
@@ -0,0 +1,150 @@
+#ifndef _H_MSPACE
+#define _H_MSPACE
+
+#define NO_MALLINFO 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+//typedef unsigned long size_t;
+typedef void (*mspace_abort_t)(void *user_data);
+typedef void (*mspace_print_t)(void *user_data, char *format, ...);
+
+void mspace_set_abort_func(mspace_abort_t f);
+void mspace_set_print_func(mspace_print_t f);
+
+/*
+  mspace is an opaque type representing an independent
+  region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+  create_mspace creates and returns a new independent space with the
+  given initial capacity, or, if 0, the default granularity size.  It
+  returns null if there is no system memory available to create the
+  space.  If argument locked is non-zero, the space uses a separate
+  lock to control access. The capacity of the space will grow
+  dynamically as needed to service mspace_malloc requests.  You can
+  control the sizes of incremental increases of this space by
+  compiling with a different DEFAULT_GRANULARITY or dynamically
+  setting with mallopt(M_GRANULARITY, value).
+*/
+//mspace create_mspace(size_t capacity, int locked);
+
+/*
+  destroy_mspace destroys the given space, and attempts to return all
+  of its memory back to the system, returning the total number of
+  bytes freed. After destruction, the results of access to all memory
+  used by the space become undefined.
+*/
+//size_t destroy_mspace(mspace msp);
+
+/*
+  create_mspace_with_base uses the memory supplied as the initial base
+  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+  space is used for bookkeeping, so the capacity must be at least this
+  large. (Otherwise 0 is returned.) When this initial space is
+  exhausted, additional memory will be obtained from the system.
+  Destroying this space will deallocate all additionally allocated
+  space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data);
+
+/*
+  mspace_malloc behaves as malloc, but operates within
+  the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+  mspace_free behaves as free, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_free is not actually needed.
+  free may be called instead of mspace_free because freed chunks from
+  any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+  mspace_realloc behaves as realloc, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_realloc is not actually
+  needed.  realloc may be called instead of mspace_realloc because
+  realloced chunks from any space are handled by their originating
+  spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+  mspace_calloc behaves as calloc, but operates within
+  the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+  mspace_memalign behaves as memalign, but operates within
+  the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+  mspace_independent_calloc behaves as independent_calloc, but
+  operates within the given space.
+*/
+//void** mspace_independent_calloc(mspace msp, size_t n_elements,
+//                                 size_t elem_size, void* chunks[]);
+
+/*
+  mspace_independent_comalloc behaves as independent_comalloc, but
+  operates within the given space.
+*/
+//void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+//                                   size_t sizes[], void* chunks[]);
+
+/*
+  mspace_footprint() returns the number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+  mspace_max_footprint() returns the peak number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+  mspace_mallinfo behaves as mallinfo, but reports properties of
+  the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+  mspace_malloc_stats behaves as malloc_stats, but reports
+  properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+  mspace_trim behaves as malloc_trim, but
+  operates within the given space.
+*/
+//int mspace_trim(mspace msp, size_t pad);
+
+/*
+  An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif
diff --git a/xddm/display/pointer.c b/xddm/display/pointer.c
new file mode 100644
index 0000000..d38a207
--- /dev/null
+++ b/xddm/display/pointer.c
@@ -0,0 +1,144 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "os_dep.h"
+#include "qxldd.h"
+#include "utils.h"
+#include "res.h"
+
+/* DDK quote
+
+Calls to the pointer functions are serialized by GDI. This means two different threads in the
+driver cannot execute the pointer functions simultaneously.
+
+*/
+
+ULONG APIENTRY DrvSetPointerShape(SURFOBJ *surf, SURFOBJ *mask, SURFOBJ *color_pointer,
+                                  XLATEOBJ *color_trans, LONG hot_x, LONG hot_y,
+                                  LONG pos_x, LONG pos_y, RECTL *prcl, FLONG flags)
+{
+    QXLCursorCmd *cursor_cmd;
+    PDev *pdev;
+
+    if (!(pdev = (PDev *)surf->dhpdev)) {
+        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
+        return SPS_ERROR;
+    }
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    if (flags & SPS_CHANGE) {
+        BOOL ok;
+        cursor_cmd = CursorCmd(pdev);
+        cursor_cmd->type = QXL_CURSOR_SET;
+        if (flags & SPS_ALPHA) {
+            if (mask) {
+                DEBUG_PRINT((pdev, 0, "%s: SPS_ALPHA and mask \n", __FUNCTION__));
+            }
+            ASSERT(pdev, color_pointer);
+            ok = GetAlphaCursor(pdev, cursor_cmd, hot_x, hot_y, color_pointer);
+        } else if (!mask) {
+            ok = GetTransparentCursor(pdev, cursor_cmd);
+        } else if (color_pointer && color_pointer->iBitmapFormat != BMF_1BPP) {
+            ASSERT(pdev, mask);
+            ok = GetColorCursor(pdev, cursor_cmd, hot_x, hot_y, color_pointer, mask, color_trans);
+        } else {
+            ok = GetMonoCursor(pdev, cursor_cmd, hot_x, hot_y, mask);
+        }
+
+        if (!ok) {
+            DEBUG_PRINT((pdev, 0, "%s: get cursor failed\n", __FUNCTION__));
+            ReleaseOutput(pdev, cursor_cmd->release_info.id);
+            return SPS_ERROR;
+        }
+        if (pos_x < 0) {
+            cursor_cmd->u.set.visible = FALSE;
+            cursor_cmd->u.set.position.x = cursor_cmd->u.set.position.y = 0;
+        } else {
+            cursor_cmd->u.set.visible = TRUE;
+            cursor_cmd->u.set.position.x = (INT16)pos_x;
+            cursor_cmd->u.set.position.y = (INT16)pos_y;
+        }
+
+        PushCursorCmd(pdev, cursor_cmd);
+
+    } else {
+        cursor_cmd = CursorCmd(pdev);
+        if (pos_x < 0) {
+#ifdef DBG
+            DEBUG_PRINT((pdev, 0, "%s: no SPS_CHANGE and pos_x < 0\n", __FUNCTION__));
+#endif
+            cursor_cmd->type = QXL_CURSOR_HIDE;
+        } else {
+#ifdef DBG
+            DEBUG_PRINT((pdev, 0, "%s: no SPS_CHANGE\n", __FUNCTION__));
+#endif
+            cursor_cmd->type = QXL_CURSOR_MOVE;
+            cursor_cmd->u.position.x = (INT16)pos_x;
+            cursor_cmd->u.position.y = (INT16)pos_y;
+        }
+        PushCursorCmd(pdev, cursor_cmd);
+    }
+#if (WINVER >= 0x0501)
+    if ((flags & (SPS_LENGTHMASK | SPS_FREQMASK)) != pdev->cursor_trail){
+        pdev->cursor_trail = (flags & (SPS_LENGTHMASK | SPS_FREQMASK));
+        cursor_cmd = CursorCmd(pdev);
+        cursor_cmd->type = QXL_CURSOR_TRAIL;
+        cursor_cmd->u.trail.length = (UINT16)((flags & SPS_LENGTHMASK) >> 8);
+        cursor_cmd->u.trail.frequency = (UINT16)((flags & SPS_FREQMASK) >> 12);
+        PushCursorCmd(pdev, cursor_cmd);
+    }
+#endif
+
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+    return SPS_ACCEPT_NOEXCLUDE;
+}
+
+VOID APIENTRY DrvMovePointer(SURFOBJ *surf, LONG pos_x, LONG pos_y, RECTL *area)
+{
+    QXLCursorCmd *cursor_cmd;
+    PDev *pdev;
+
+    if (!(pdev = (PDev *)surf->dhpdev)) {
+        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
+        return;
+    }
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    if (pos_y < 0 && pos_x >= 0) {
+        DEBUG_PRINT((pdev, 0, "%s: unexpected negative y pos\n", __FUNCTION__));
+        return;
+    }
+
+    cursor_cmd = CursorCmd(pdev);
+    if (pos_x < 0) {
+        cursor_cmd->type = QXL_CURSOR_HIDE;
+    } else {
+        cursor_cmd->type = QXL_CURSOR_MOVE;
+        cursor_cmd->u.position.x = (INT16)pos_x;
+        cursor_cmd->u.position.y = (INT16)pos_y;
+    }
+    PushCursorCmd(pdev, cursor_cmd);
+
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+}
+
diff --git a/xddm/display/quic.c b/xddm/display/quic.c
new file mode 100644
index 0000000..ee12fab
--- /dev/null
+++ b/xddm/display/quic.c
@@ -0,0 +1,1738 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+// Red Hat image compression based on SFALIC by Roman Starosolski
+// http://sun.iinf.polsl.gliwice.pl/~rstaros/sfalic/index.html
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "os_dep.h"
+
+#include "winerror.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+#include "qxldd.h"
+#include "utils.h"
+#include "mspace.h"
+#include "res.h"
+#include "surface.h"
+
+
+#include "quic.h"
+
+//#define DEBUG
+
+#define RLE
+#define RLE_STAT
+#define PRED_1
+//#define RLE_PRED_1
+#define RLE_PRED_2
+//#define RLE_PRED_3
+#define QUIC_RGB
+
+#define QUIC_MAGIC (*(uint32_t *)"QUIC")
+#define QUIC_VERSION_MAJOR 0U
+#define QUIC_VERSION_MINOR 1U
+#define QUIC_VERSION ((QUIC_VERSION_MAJOR << 16) | (QUIC_VERSION_MAJOR & 0xffff))
+
+#define ABS(a) ((a) >= 0 ? (a) : -(a))
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef DEBUG
+
+#define ASSERT(usr, x) \
+    if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
+
+#else
+
+#define ASSERT(usr, x)
+
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+typedef uint8_t BYTE;
+
+/* maximum number of codes in family */
+#define MAXNUMCODES 8
+
+/* model evolution, warning: only 1,3 and 5 allowed */
+#define DEFevol 3
+#define MINevol 0
+#define MAXevol 5
+
+/* starting wait mask index */
+#define DEFwmistart 0
+#define MINwmistart 0
+
+/* codeword length limit */
+#define DEFmaxclen 26
+
+/* target wait mask index */
+#define DEFwmimax 6
+
+/* number of symbols to encode before increasing wait mask index */
+#define DEFwminext 2048
+#define MINwminext 1
+#define MAXwminext 100000000
+
+typedef struct QuicFamily {
+    unsigned int nGRcodewords[MAXNUMCODES];      /* indexed by code number, contains number of
+                                                    unmodofied GR codewords in the code */
+    unsigned int notGRcwlen[MAXNUMCODES];        /* indexed by code number, contains codeword
+                                                    length of the not-GR codeword */
+    unsigned int notGRprefixmask[MAXNUMCODES];   /* indexed by code number, contains mask to
+                                                    determine if the codeword is GR or not-GR */
+    unsigned int notGRsuffixlen[MAXNUMCODES];    /* indexed by code number, contains suffix
+                                                    length of the not-GR codeword */
+
+    /* array for translating distribution U to L for depths up to 8 bpp,
+    initialized by decorelateinit() */
+    BYTE xlatU2L[256];
+
+    /* array for translating distribution L to U for depths up to 8 bpp,
+       initialized by corelateinit() */
+    unsigned int xlatL2U[256];
+} QuicFamily;
+
+static QuicFamily family_8bpc;
+static QuicFamily family_5bpc;
+
+typedef unsigned COUNTER;   /* counter in the array of counters in bucket of the data model */
+
+typedef struct s_bucket {
+    COUNTER *pcounters;     /* pointer to array of counters */
+    unsigned int bestcode;  /* best code so far */
+} s_bucket;
+
+typedef struct Encoder Encoder;
+
+typedef struct CommonState {
+    Encoder *encoder;
+
+    unsigned int waitcnt;
+    unsigned int tabrand_seed;
+    unsigned int wm_trigger;
+    unsigned int wmidx;
+    unsigned int wmileft;
+
+#ifdef RLE_STAT
+    int melcstate; /* index to the state array */
+
+    int melclen;  /* contents of the state array location
+                     indexed by melcstate: the "expected"
+                     run length is 2^melclen, shorter runs are
+                     encoded by a 1 followed by the run length
+                     in binary representation, wit a fixed length
+                     of melclen bits */
+
+    unsigned long melcorder;  /* 2^ melclen */
+#endif
+} CommonState;
+
+
+#define MAX_CHANNELS 4
+
+typedef struct FamilyStat {
+    s_bucket **buckets_ptrs;
+    s_bucket *buckets_buf;
+    COUNTER *counters;
+} FamilyStat;
+
+typedef struct Channel {
+    Encoder *encoder;
+
+    int correlate_row_width;
+    BYTE *correlate_row;
+
+    s_bucket **_buckets_ptrs;
+
+    FamilyStat family_stat_8bpc;
+    FamilyStat family_stat_5bpc;
+
+    CommonState state;
+} Channel;
+
+struct Encoder {
+    QuicUsrContext *usr;
+    QuicImageType type;
+    unsigned int width;
+    unsigned int height;
+    unsigned int num_channels;
+
+    unsigned int n_buckets_8bpc;
+    unsigned int n_buckets_5bpc;
+
+    unsigned int io_available_bits;
+    uint32_t io_word;
+    uint32_t io_next_word;
+    uint32_t *io_now;
+    uint32_t *io_end;
+    uint32_t io_words_count;
+
+    int rows_completed;
+
+    Channel channels[MAX_CHANNELS];
+
+    CommonState rgb_state;
+};
+
+/* target wait mask index */
+static int wmimax = DEFwmimax;
+
+/* number of symbols to encode before increasing wait mask index */
+static int wminext = DEFwminext;
+
+/* model evolution mode */
+static int evol = DEFevol;
+
+/* bppmask[i] contains i ones as lsb-s */
+static const unsigned long int bppmask[33] = {
+    0x00000000, /* [0] */
+    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff /* [32] */
+};
+
+static const unsigned int bitat[32] = {
+    0x00000001, 0x00000002, 0x00000004, 0x00000008,
+    0x00000010, 0x00000020, 0x00000040, 0x00000080,
+    0x00000100, 0x00000200, 0x00000400, 0x00000800,
+    0x00001000, 0x00002000, 0x00004000, 0x00008000,
+    0x00010000, 0x00020000, 0x00040000, 0x00080000,
+    0x00100000, 0x00200000, 0x00400000, 0x00800000,
+    0x01000000, 0x02000000, 0x04000000, 0x08000000,
+    0x10000000, 0x20000000, 0x40000000, 0x80000000 /* [31]*/
+};
+
+
+#define TABRAND_TABSIZE 256
+#define TABRAND_SEEDMASK 0x0ff
+
+static const unsigned int tabrand_chaos[TABRAND_TABSIZE] = {
+    0x02c57542, 0x35427717, 0x2f5a2153, 0x9244f155, 0x7bd26d07, 0x354c6052, 0x57329b28, 0x2993868e,
+    0x6cd8808c, 0x147b46e0, 0x99db66af, 0xe32b4cac, 0x1b671264, 0x9d433486, 0x62a4c192, 0x06089a4b,
+    0x9e3dce44, 0xdaabee13, 0x222425ea, 0xa46f331d, 0xcd589250, 0x8bb81d7f, 0xc8b736b9, 0x35948d33,
+    0xd7ac7fd0, 0x5fbe2803, 0x2cfbc105, 0x013dbc4e, 0x7a37820f, 0x39f88e9e, 0xedd58794, 0xc5076689,
+    0xfcada5a4, 0x64c2f46d, 0xb3ba3243, 0x8974b4f9, 0x5a05aebd, 0x20afcd00, 0x39e2b008, 0x88a18a45,
+    0x600bde29, 0xf3971ace, 0xf37b0a6b, 0x7041495b, 0x70b707ab, 0x06beffbb, 0x4206051f, 0xe13c4ee3,
+    0xc1a78327, 0x91aa067c, 0x8295f72a, 0x732917a6, 0x1d871b4d, 0x4048f136, 0xf1840e7e, 0x6a6048c1,
+    0x696cb71a, 0x7ff501c3, 0x0fc6310b, 0x57e0f83d, 0x8cc26e74, 0x11a525a2, 0x946934c7, 0x7cd888f0,
+    0x8f9d8604, 0x4f86e73b, 0x04520316, 0xdeeea20c, 0xf1def496, 0x67687288, 0xf540c5b2, 0x22401484,
+    0x3478658a, 0xc2385746, 0x01979c2c, 0x5dad73c8, 0x0321f58b, 0xf0fedbee, 0x92826ddf, 0x284bec73,
+    0x5b1a1975, 0x03df1e11, 0x20963e01, 0xa17cf12b, 0x740d776e, 0xa7a6bf3c, 0x01b5cce4, 0x1118aa76,
+    0xfc6fac0a, 0xce927e9b, 0x00bf2567, 0x806f216c, 0xbca69056, 0x795bd3e9, 0xc9dc4557, 0x8929b6c2,
+    0x789d52ec, 0x3f3fbf40, 0xb9197368, 0xa38c15b5, 0xc3b44fa8, 0xca8333b0, 0xb7e8d590, 0xbe807feb,
+    0xbf5f8360, 0xd99e2f5c, 0x372928e1, 0x7c757c4c, 0x0db5b154, 0xc01ede02, 0x1fc86e78, 0x1f3985be,
+    0xb4805c77, 0x00c880fa, 0x974c1b12, 0x35ab0214, 0xb2dc840d, 0x5b00ae37, 0xd313b026, 0xb260969d,
+    0x7f4c8879, 0x1734c4d3, 0x49068631, 0xb9f6a021, 0x6b863e6f, 0xcee5debf, 0x29f8c9fb, 0x53dd6880,
+    0x72b61223, 0x1f67a9fd, 0x0a0f6993, 0x13e59119, 0x11cca12e, 0xfe6b6766, 0x16b6effc, 0x97918fc4,
+    0xc2b8a563, 0x94f2f741, 0x0bfa8c9a, 0xd1537ae8, 0xc1da349c, 0x873c60ca, 0x95005b85, 0x9b5c080e,
+    0xbc8abbd9, 0xe1eab1d2, 0x6dac9070, 0x4ea9ebf1, 0xe0cf30d4, 0x1ef5bd7b, 0xd161043e, 0x5d2fa2e2,
+    0xff5d3cae, 0x86ed9f87, 0x2aa1daa1, 0xbd731a34, 0x9e8f4b22, 0xb1c2c67a, 0xc21758c9, 0xa182215d,
+    0xccb01948, 0x8d168df7, 0x04238cfe, 0x368c3dbc, 0x0aeadca5, 0xbad21c24, 0x0a71fee5, 0x9fc5d872,
+    0x54c152c6, 0xfc329483, 0x6783384a, 0xeddb3e1c, 0x65f90e30, 0x884ad098, 0xce81675a, 0x4b372f7d,
+    0x68bf9a39, 0x43445f1e, 0x40f8d8cb, 0x90d5acb6, 0x4cd07282, 0x349eeb06, 0x0c9d5332, 0x520b24ef,
+    0x80020447, 0x67976491, 0x2f931ca3, 0xfe9b0535, 0xfcd30220, 0x61a9e6cc, 0xa487d8d7, 0x3f7c5dd1,
+    0x7d0127c5, 0x48f51d15, 0x60dea871, 0xc9a91cb7, 0x58b53bb3, 0x9d5e0b2d, 0x624a78b4, 0x30dbee1b,
+    0x9bdf22e7, 0x1df5c299, 0x2d5643a7, 0xf4dd35ff, 0x03ca8fd6, 0x53b47ed8, 0x6f2c19aa, 0xfeb0c1f4,
+    0x49e54438, 0x2f2577e6, 0xbf876969, 0x72440ea9, 0xfa0bafb8, 0x74f5b3a0, 0x7dd357cd, 0x89ce1358,
+    0x6ef2cdda, 0x1e7767f3, 0xa6be9fdb, 0x4f5f88f8, 0xba994a3a, 0x08ca6b65, 0xe0893818, 0x9e00a16a,
+    0xf42bfc8f, 0x9972eedc, 0x749c8b51, 0x32c05f5e, 0xd706805f, 0x6bfbb7cf, 0xd9210a10, 0x31a1db97,
+    0x923a9559, 0x37a7a1f6, 0x059f8861, 0xca493e62, 0x65157e81, 0x8f6467dd, 0xab85ff9f, 0x9331aff2,
+    0x8616b9f5, 0xedbd5695, 0xee7e29b1, 0x313ac44f, 0xb903112f, 0x432ef649, 0xdc0a36c0, 0x61cf2bba,
+    0x81474925, 0xa8b6c7ad, 0xee5931de, 0xb2f8158d, 0x59fb7409, 0x2e3dfaed, 0x9af25a3f, 0xe1fed4d5,
+};
+
+static unsigned int stabrand()
+{
+    //ASSERT( !(TABRAND_SEEDMASK & TABRAND_TABSIZE));
+    //ASSERT( TABRAND_SEEDMASK + 1 == TABRAND_TABSIZE );
+
+    return TABRAND_SEEDMASK;
+}
+
+static unsigned int tabrand(unsigned int *tabrand_seed)
+{
+    return tabrand_chaos[++*tabrand_seed & TABRAND_SEEDMASK];
+}
+
+static const unsigned short besttrigtab[3][11] = { /* array of wm_trigger for waitmask and evol,
+                                                    used by set_wm_trigger() */
+    /* 1 */ { 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160},
+    /* 3 */ { 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140},
+    /* 5 */ { 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160}
+};
+
+/* set wm_trigger knowing waitmask (param) and evol (glob)*/
+static void set_wm_trigger(CommonState *state)
+{
+    unsigned int wm = state->wmidx;
+    if (wm > 10) {
+        wm = 10;
+    }
+
+    ASSERT(state->encoder->usr, evol < 6);
+
+    state->wm_trigger = besttrigtab[evol / 2][wm];
+
+    ASSERT(state->encoder->usr, state->wm_trigger <= 2000);
+    ASSERT(state->encoder->usr, state->wm_trigger >= 1);
+}
+
+static int ceil_log_2(int val) /* ceil(log_2(val)) */
+{
+    int result;
+
+    //ASSERT(val>0);
+
+    if (val == 1) {
+        return 0;
+    }
+
+    result = 1;
+    val -= 1;
+    while (val >>= 1) {
+        result++;
+    }
+
+    return result;
+}
+
+/* number of leading zeroes in the byte, used by cntlzeroes(uint)*/
+static const BYTE lzeroes[256] = {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* count leading zeroes */
+static unsigned int cnt_l_zeroes(const unsigned int bits)
+{
+    if (bits & 0xff800000) {
+        return lzeroes[bits >> 24];
+    } else if (bits & 0xffff8000) {
+        return 8 + lzeroes[(bits >> 16) & 0x000000ff];
+    } else if (bits & 0xffffff80) {
+        return 16 + lzeroes[(bits >> 8) & 0x000000ff];
+    } else {
+        return 24 + lzeroes[bits & 0x000000ff];
+    }
+}
+
+#define QUIC_FAMILY_8BPC
+#include "quic_family_tmpl.c"
+
+#ifdef QUIC_RGB
+#define QUIC_FAMILY_5BPC
+#include "quic_family_tmpl.c"
+#endif
+
+static void decorelate_init(QuicFamily *family, int bpc)
+{
+    const unsigned int pixelbitmask = bppmask[bpc];
+    const unsigned int pixelbitmaskshr = pixelbitmask >> 1;
+    unsigned int s;
+
+    //ASSERT(bpc <= 8);
+
+    for (s = 0; s <= pixelbitmask; s++) {
+        if (s <= pixelbitmaskshr) {
+            family->xlatU2L[s] = s << 1;
+        } else {
+            family->xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
+        }
+    }
+}
+
+static void corelate_init(QuicFamily *family, int bpc)
+{
+    const unsigned long int pixelbitmask = bppmask[bpc];
+    unsigned long int s;
+
+    //ASSERT(bpc <= 8);
+
+    for (s = 0; s <= pixelbitmask; s++) {
+        if (s & 0x01) {
+            family->xlatL2U[s] = pixelbitmask - (s >> 1);
+        } else {
+            family->xlatL2U[s] = (s >> 1);
+        }
+    }
+}
+
+static void family_init(QuicFamily *family, int bpc, int limit)
+{
+    int l;
+
+    for (l = 0; l < bpc; l++) { /* fill arrays indexed by code number */
+        int altprefixlen, altcodewords;
+
+        altprefixlen = limit - bpc;
+        if (altprefixlen > (int)(bppmask[bpc - l])) {
+            altprefixlen = bppmask[bpc - l];
+        }
+
+        altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);
+
+        family->nGRcodewords[l] = (altprefixlen << l);
+        family->notGRcwlen[l] = altprefixlen + ceil_log_2(altcodewords);
+        family->notGRprefixmask[l] = bppmask[32 - altprefixlen]; /* needed for decoding only */
+        family->notGRsuffixlen[l] = ceil_log_2(altcodewords); /* needed for decoding only */
+    }
+
+    decorelate_init(family, bpc);
+    corelate_init(family, bpc);
+}
+
+static void more_io_words(Encoder *encoder)
+{
+    uint32_t *io_ptr;
+    int num_io_words = encoder->usr->more_space(encoder->usr, &io_ptr, encoder->rows_completed);
+    if (num_io_words <= 0) {
+        encoder->usr->error(encoder->usr, "%s: no more words\n", __FUNCTION__);
+    }
+    ASSERT(encoder->usr, io_ptr);
+    encoder->io_words_count += num_io_words;
+    encoder->io_now = io_ptr;
+    encoder->io_end = encoder->io_now + num_io_words;
+}
+
+static void __write_io_word(Encoder *encoder)
+{
+    more_io_words(encoder);
+    *(encoder->io_now++) = encoder->io_word;
+}
+
+static void (*__write_io_word_ptr)(Encoder *encoder) = __write_io_word;
+
+static INLINE void write_io_word(Encoder *encoder)
+{
+    if (encoder->io_now == encoder->io_end) {
+        __write_io_word_ptr(encoder); //disable inline optimizations
+        return;
+    }
+    *(encoder->io_now++) = encoder->io_word;
+}
+
+static INLINE void encode(Encoder *encoder, unsigned int word, unsigned int len)
+{
+    int delta;
+
+    ASSERT(encoder->usr, len > 0 && len < 32);
+    ASSERT(encoder->usr, !(word & ~bppmask[len]));
+    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
+        encoder->io_available_bits = delta;
+        encoder->io_word |= word << encoder->io_available_bits;
+        return;
+    }
+    delta = -delta;
+    encoder->io_word |= word >> delta;
+    write_io_word(encoder);
+    encoder->io_available_bits = 32 - delta;
+    encoder->io_word = word << encoder->io_available_bits;
+
+    ASSERT(encoder->usr, encoder->io_available_bits < 32);
+    ASSERT(encoder->usr, (encoder->io_word & bppmask[encoder->io_available_bits]) == 0);
+}
+
+static INLINE void encode_32(Encoder *encoder, unsigned int word)
+{
+    encode(encoder, word >> 16, 16);
+    encode(encoder, word & 0x0000ffff, 16);
+}
+
+static INLINE void flush(Encoder *encoder)
+{
+    if (encoder->io_available_bits > 0 && encoder->io_available_bits != 32) {
+        encode(encoder, 0, encoder->io_available_bits);
+    }
+    encode_32(encoder, 0);
+    encode(encoder, 0, 1);
+}
+
+static void __read_io_word(Encoder *encoder)
+{
+    more_io_words(encoder);
+    encoder->io_next_word = *(encoder->io_now++);
+}
+
+static void (*__read_io_word_ptr)(Encoder *encoder) = __read_io_word;
+
+
+static INLINE void read_io_word(Encoder *encoder)
+{
+    if (encoder->io_now == encoder->io_end) {
+        __read_io_word_ptr(encoder); //disable inline optimizations
+        return;
+    }
+    ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
+    encoder->io_next_word = *(encoder->io_now++);
+}
+
+static INLINE void decode_eatbits(Encoder *encoder, int len)
+{
+    int delta;
+
+    ASSERT(encoder->usr, len > 0 && len < 32);
+    encoder->io_word <<= len;
+
+    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
+        encoder->io_available_bits = delta;
+        encoder->io_word |= encoder->io_next_word >> encoder->io_available_bits;
+        return;
+    }
+
+    delta = -delta;
+    encoder->io_word |= encoder->io_next_word << delta;
+    read_io_word(encoder);
+    encoder->io_available_bits = 32 - delta;
+    encoder->io_word |= (encoder->io_next_word >> encoder->io_available_bits);
+}
+
+static INLINE void decode_eat32bits(Encoder *encoder)
+{
+    decode_eatbits(encoder, 16);
+    decode_eatbits(encoder, 16);
+}
+
+#ifdef RLE
+
+#ifdef RLE_STAT
+
+static INLINE void encode_ones(Encoder *encoder, unsigned int n)
+{
+    unsigned int count;
+
+    for (count = n >> 5; count; count--) {
+        encode(encoder, ~0U, 32);
+    }
+
+    if ((n &= 0x1f)) {
+        encode(encoder, (1U << n) - 1, n);
+    }
+}
+
+#define MELCSTATES 32 /* number of melcode states */
+
+static int zeroLUT[256]; /* table to find out number of leading zeros */
+
+static int J[MELCSTATES] = {
+    0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7,
+    7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+/* creates the bit counting look-up table. */
+static void init_zeroLUT()
+{
+    int i, j, k, l;
+
+    j = k = 1;
+    l = 8;
+    for (i = 0; i < 256; ++i) {
+        zeroLUT[i] = l;
+        --k;
+        if (k == 0) {
+            k = j;
+            --l;
+            j *= 2;
+        }
+    }
+}
+
+static void encoder_init_rle(CommonState *state)
+{
+    state->melcstate = 0;
+    state->melclen = J[0];
+    state->melcorder = 1 << state->melclen;
+}
+
+#ifdef QUIC_RGB
+
+static void encode_run(Encoder *encoder, unsigned int runlen) //todo: try use end of line
+{
+    int hits = 0;
+
+    while (runlen >= encoder->rgb_state.melcorder) {
+        hits++;
+        runlen -= encoder->rgb_state.melcorder;
+        if (encoder->rgb_state.melcstate < MELCSTATES) {
+            encoder->rgb_state.melclen = J[++encoder->rgb_state.melcstate];
+            encoder->rgb_state.melcorder = (1L << encoder->rgb_state.melclen);
+        }
+    }
+
+    /* send the required number of "hit" bits (one per occurrence
+       of a run of length melcorder). This number is never too big:
+       after 31 such "hit" bits, each "hit" would represent a run of 32K
+       pixels.
+    */
+    encode_ones(encoder, hits);
+
+    encode(encoder, runlen, encoder->rgb_state.melclen + 1);
+
+    /* adjust melcoder parameters */
+    if (encoder->rgb_state.melcstate) {
+        encoder->rgb_state.melclen = J[--encoder->rgb_state.melcstate];
+        encoder->rgb_state.melcorder = (1L << encoder->rgb_state.melclen);
+    }
+}
+
+#endif
+
+static void encode_channel_run(Encoder *encoder, Channel *channel, unsigned int runlen)
+{
+    //todo: try use end of line
+    int hits = 0;
+
+    while (runlen >= channel->state.melcorder) {
+        hits++;
+        runlen -= channel->state.melcorder;
+        if (channel->state.melcstate < MELCSTATES) {
+            channel->state.melclen = J[++channel->state.melcstate];
+            channel->state.melcorder = (1L << channel->state.melclen);
+        }
+    }
+
+    /* send the required number of "hit" bits (one per occurrence
+       of a run of length melcorder). This number is never too big:
+       after 31 such "hit" bits, each "hit" would represent a run of 32K
+       pixels.
+    */
+    encode_ones(encoder, hits);
+
+    encode(encoder, runlen, channel->state.melclen + 1);
+
+    /* adjust melcoder parameters */
+    if (channel->state.melcstate) {
+        channel->state.melclen = J[--channel->state.melcstate];
+        channel->state.melcorder = (1L << channel->state.melclen);
+    }
+}
+
+/* decoding routine: reads bits from the input and returns a run length. */
+/* argument is the number of pixels left to end-of-line (bound on run length) */
+
+#ifdef QUIC_RGB
+static int decode_run(Encoder *encoder)
+{
+    int runlen = 0;
+
+    do {
+        register int temp, hits;
+        temp = zeroLUT[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
+                                                                      input stream, up to 8 */
+        for (hits = 1; hits <= temp; hits++) {
+            runlen += encoder->rgb_state.melcorder;
+
+            if (encoder->rgb_state.melcstate < MELCSTATES) {
+                encoder->rgb_state.melclen = J[++encoder->rgb_state.melcstate];
+                encoder->rgb_state.melcorder = (1U << encoder->rgb_state.melclen);
+            }
+        }
+        if (temp != 8) {
+            decode_eatbits(encoder, temp + 1);  /* consume the leading
+                                                            0 of the remainder encoding */
+            break;
+        }
+        decode_eatbits(encoder, 8);
+    } while (1);
+
+    /* read the length of the remainder */
+    if (encoder->rgb_state.melclen) {
+        runlen += encoder->io_word >> (32 - encoder->rgb_state.melclen);
+        decode_eatbits(encoder, encoder->rgb_state.melclen);
+    }
+
+    /* adjust melcoder parameters */
+    if (encoder->rgb_state.melcstate) {
+        encoder->rgb_state.melclen = J[--encoder->rgb_state.melcstate];
+        encoder->rgb_state.melcorder = (1U << encoder->rgb_state.melclen);
+    }
+
+    return runlen;
+}
+
+#endif
+
+static int decode_channel_run(Encoder *encoder, Channel *channel)
+{
+    int runlen = 0;
+
+    do {
+        register int temp, hits;
+        temp = zeroLUT[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
+                                                                      input stream, up to 8 */
+        for (hits = 1; hits <= temp; hits++) {
+            runlen += channel->state.melcorder;
+
+            if (channel->state.melcstate < MELCSTATES) {
+                channel->state.melclen = J[++channel->state.melcstate];
+                channel->state.melcorder = (1U << channel->state.melclen);
+            }
+        }
+        if (temp != 8) {
+            decode_eatbits(encoder, temp + 1);  /* consume the leading
+                                                            0 of the remainder encoding */
+            break;
+        }
+        decode_eatbits(encoder, 8);
+    } while (1);
+
+    /* read the length of the remainder */
+    if (channel->state.melclen) {
+        runlen += encoder->io_word >> (32 - channel->state.melclen);
+        decode_eatbits(encoder, channel->state.melclen);
+    }
+
+    /* adjust melcoder parameters */
+    if (channel->state.melcstate) {
+        channel->state.melclen = J[--channel->state.melcstate];
+        channel->state.melcorder = (1U << channel->state.melclen);
+    }
+
+    return runlen;
+}
+
+#else
+
+static INLINE int find_msb(int x)
+{
+    int r;
+
+    __asm__("bsrl %1,%0\n\t"
+            "jnz 1f\n\t"
+            "movl $-1,%0\n"
+            "1:" : "=r" (r) : "rm" (x));
+    return r + 1;
+}
+
+static INLINE void encode_run(Encoder *encoder, unsigned int len)
+{
+    int odd = len & 1U;
+    int msb;
+
+    len &= ~1U;
+
+    while ((msb = find_msb(len))) {
+        len &= ~(1 << (msb - 1));
+        ASSERT(encoder->usr, msb < 32);
+        encode(encoder, (1 << (msb)) - 1, msb);
+        encode(encoder, 0, 1);
+    }
+
+    if (odd) {
+        encode(encoder, 2, 2);
+    } else {
+        encode(encoder, 0, 1);
+    }
+}
+
+static INLINE unsigned int decode_run(Encoder *encoder)
+{
+    unsigned int len = 0;
+    int count;
+
+    do {
+        count = 0;
+        while (encoder->io_word & (1U << 31)) {
+            decode_eatbits(encoder, 1);
+            count++;
+            ASSERT(encoder->usr, count < 32);
+        }
+        decode_eatbits(encoder, 1);
+        len += (1U << count) >> 1;
+    } while (count > 1);
+
+    return len;
+}
+
+#endif
+#endif
+
+static INLINE void init_decode_io(Encoder *encoder)
+{
+    encoder->io_next_word = encoder->io_word = *(encoder->io_now++);
+    encoder->io_available_bits = 0;
+}
+
+#ifdef __GNUC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#define ATTR_PACKED
+#pragma pack(push)
+#pragma pack(1)
+#endif
+
+typedef struct ATTR_PACKED one_byte_pixel_t {
+    BYTE a;
+} one_byte_t;
+
+typedef struct ATTR_PACKED three_bytes_pixel_t {
+    BYTE a;
+    BYTE b;
+    BYTE c;
+} three_bytes_t;
+
+typedef struct ATTR_PACKED four_bytes_pixel_t {
+    BYTE a;
+    BYTE b;
+    BYTE c;
+    BYTE d;
+} four_bytes_t;
+
+typedef struct ATTR_PACKED rgb32_pixel_t {
+    BYTE b;
+    BYTE g;
+    BYTE r;
+    BYTE pad;
+} rgb32_pixel_t;
+
+typedef struct ATTR_PACKED rgb24_pixel_t {
+    BYTE b;
+    BYTE g;
+    BYTE r;
+} rgb24_pixel_t;
+
+typedef uint16_t rgb16_pixel_t;
+
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
+
+#undef ATTR_PACKED
+
+#define ONE_BYTE
+#include "quic_tmpl.c"
+
+#define FOUR_BYTE
+#include "quic_tmpl.c"
+
+#ifdef QUIC_RGB
+
+#define QUIC_RGB32
+#include "quic_rgb_tmpl.c"
+
+#define QUIC_RGB24
+#include "quic_rgb_tmpl.c"
+
+#define QUIC_RGB16
+#include "quic_rgb_tmpl.c"
+
+#define QUIC_RGB16_TO_32
+#include "quic_rgb_tmpl.c"
+
+#else
+
+#define THREE_BYTE
+#include "quic_tmpl.c"
+
+#endif
+
+static void fill_model_structures(Encoder *encoder, FamilyStat *family_stat,
+                                  unsigned int rep_first, unsigned int first_size,
+                                  unsigned int rep_next, unsigned int mul_size,
+                                  unsigned int levels, unsigned int ncounters,
+                                  unsigned int nbuckets, unsigned int n_buckets_ptrs)
+{
+    unsigned int
+    bsize,
+    bstart,
+    bend = 0,
+    repcntr,
+    bnumber;
+
+    COUNTER * free_counter = family_stat->counters;/* first free location in the array of
+                                                      counters */
+
+    bnumber = 0;
+
+    repcntr = rep_first + 1;    /* first bucket */
+    bsize = first_size;
+
+    do { /* others */
+        if (bnumber) {
+            bstart = bend + 1;
+        } else {
+            bstart = 0;
+        }
+
+        if (!--repcntr) {
+            repcntr = rep_next;
+            bsize *= mul_size;
+        }
+
+        bend = bstart + bsize - 1;
+        if (bend + bsize >= levels) {
+            bend = levels - 1;
+        }
+
+        family_stat->buckets_buf[bnumber].pcounters = free_counter;
+        free_counter += ncounters;
+
+        ASSERT(encoder->usr, bstart < n_buckets_ptrs);
+        {
+            unsigned int i;
+            ASSERT(encoder->usr, bend < n_buckets_ptrs);
+            for (i = bstart; i <= bend; i++) {
+                family_stat->buckets_ptrs[i] = family_stat->buckets_buf + bnumber;
+            }
+        }
+
+        bnumber++;
+    } while (bend < levels - 1);
+
+    ASSERT(encoder->usr, free_counter - family_stat->counters == nbuckets * ncounters);
+}
+
+static void find_model_params(Encoder *encoder,
+                              const int bpc,
+                              unsigned int *ncounters,
+                              unsigned int *levels,
+                              unsigned int *n_buckets_ptrs,
+                              unsigned int *repfirst,
+                              unsigned int *firstsize,
+                              unsigned int *repnext,
+                              unsigned int *mulsize,
+                              unsigned int *nbuckets)
+{
+    unsigned int bsize;              /* bucket size */
+    unsigned int bstart, bend = 0;   /* bucket start and end, range : 0 to levels-1*/
+    unsigned int repcntr;            /* helper */
+
+    ASSERT(encoder->usr, bpc <= 8 && bpc > 0);
+
+
+    *ncounters = 8;
+
+    *levels = 0x1 << bpc;
+
+    *n_buckets_ptrs = 0;  /* ==0 means: not set yet */
+
+    switch (evol) {   /* set repfirst firstsize repnext mulsize */
+    case 1: /* buckets contain following numbers of contexts: 1 1 1 2 2 4 4 8 8 ... */
+        *repfirst = 3;
+        *firstsize = 1;
+        *repnext = 2;
+        *mulsize = 2;
+        break;
+    case 3: /* 1 2 4 8 16 32 64 ... */
+        *repfirst = 1;
+        *firstsize = 1;
+        *repnext = 1;
+        *mulsize = 2;
+        break;
+    case 5:                     /* 1 4 16 64 256 1024 4096 16384 65536 */
+        *repfirst = 1;
+        *firstsize = 1;
+        *repnext = 1;
+        *mulsize = 4;
+        break;
+    case 0: /* obsolete */
+    case 2: /* obsolete */
+    case 4: /* obsolete */
+        encoder->usr->error(encoder->usr, "findmodelparams(): evol value obsolete!!!\n");
+    default:
+        encoder->usr->error(encoder->usr, "findmodelparams(): evol out of range!!!\n");
+    }
+
+    *nbuckets = 0;
+    repcntr = *repfirst + 1;    /* first bucket */
+    bsize = *firstsize;
+
+    do { /* other buckets */
+        if (nbuckets) {         /* bucket start */
+            bstart = bend + 1;
+        } else {
+            bstart = 0;
+        }
+
+        if (!--repcntr) {         /* bucket size */
+            repcntr = *repnext;
+            bsize *= *mulsize;
+        }
+
+        bend = bstart + bsize - 1;  /* bucket end */
+        if (bend + bsize >= *levels) {  /* if following bucked was bigger than current one */
+            bend = *levels - 1;     /* concatenate them */
+        }
+
+        if (!*n_buckets_ptrs) {           /* array size not set yet? */
+            *n_buckets_ptrs = *levels;
+ #if 0
+            if (bend == *levels - 1) {   /* this bucket is last - all in the first array */
+                *n_buckets_ptrs = *levels;
+            } else if (bsize >= 256) { /* this bucket is allowed to reside in the 2nd table */
+                b_lo_ptrs = bstart;
+                assert(bstart);     /* previous bucket exists */
+            }
+ #endif
+        }
+
+        (*nbuckets)++;
+    } while (bend < *levels - 1);
+}
+
+static int init_model_structures(Encoder *encoder, FamilyStat *family_stat,
+                                 unsigned int rep_first, unsigned int first_size,
+                                 unsigned int rep_next, unsigned int mul_size,
+                                 unsigned int levels, unsigned int ncounters,
+                                 unsigned int n_buckets_ptrs, unsigned int n_buckets)
+{
+    family_stat->buckets_ptrs = (s_bucket **)encoder->usr->malloc(encoder->usr,
+                                                                  n_buckets_ptrs *
+                                                                  sizeof(s_bucket *));
+    if (!family_stat->buckets_ptrs) {
+        return FALSE;
+    }
+
+    family_stat->counters = (COUNTER *)encoder->usr->malloc(encoder->usr,
+                                                            n_buckets * sizeof(COUNTER) *
+                                                            MAXNUMCODES);
+    if (!family_stat->counters) {
+        goto error_1;
+    }
+
+    family_stat->buckets_buf = (s_bucket *)encoder->usr->malloc(encoder->usr,
+                                                                n_buckets * sizeof(s_bucket));
+    if (!family_stat->buckets_buf) {
+        goto error_2;
+    }
+
+    fill_model_structures(encoder, family_stat, rep_first, first_size, rep_next, mul_size, levels,
+                          ncounters, n_buckets, n_buckets_ptrs);
+
+    return TRUE;
+
+error_2:
+    encoder->usr->free(encoder->usr, family_stat->counters);
+
+error_1:
+    encoder->usr->free(encoder->usr, family_stat->buckets_ptrs);
+
+    return FALSE;
+}
+
+static void free_family_stat(QuicUsrContext *usr, FamilyStat *family_stat)
+{
+    usr->free(usr, family_stat->buckets_ptrs);
+    usr->free(usr, family_stat->counters);
+    usr->free(usr, family_stat->buckets_buf);
+}
+
+static int init_channel(Encoder *encoder, Channel *channel)
+{
+    unsigned int ncounters;
+    unsigned int levels;
+    unsigned int rep_first;
+    unsigned int first_size;
+    unsigned int rep_next;
+    unsigned int mul_size;
+    unsigned int n_buckets;
+    unsigned int n_buckets_ptrs;
+
+    channel->encoder = encoder;
+    channel->state.encoder = encoder;
+    channel->correlate_row_width = 0;
+    channel->correlate_row = NULL;
+
+    find_model_params(encoder, 8, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
+                      &first_size, &rep_next, &mul_size, &n_buckets);
+    encoder->n_buckets_8bpc = n_buckets;
+    if (!init_model_structures(encoder, &channel->family_stat_8bpc, rep_first, first_size,
+                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
+                               n_buckets)) {
+        return FALSE;
+    }
+
+    find_model_params(encoder, 5, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
+                      &first_size, &rep_next, &mul_size, &n_buckets);
+    encoder->n_buckets_5bpc = n_buckets;
+    if (!init_model_structures(encoder, &channel->family_stat_5bpc, rep_first, first_size,
+                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
+                               n_buckets)) {
+        free_family_stat(encoder->usr, &channel->family_stat_8bpc);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void destroy_channel(Channel *channel)
+{
+    QuicUsrContext *usr = channel->encoder->usr;
+    if (channel->correlate_row) {
+        usr->free(usr, channel->correlate_row - 1);
+    }
+    free_family_stat(usr, &channel->family_stat_8bpc);
+    free_family_stat(usr, &channel->family_stat_5bpc);
+}
+
+static int init_encoder(Encoder *encoder, QuicUsrContext *usr)
+{
+    int i;
+
+    encoder->usr = usr;
+    encoder->rgb_state.encoder = encoder;
+
+    for (i = 0; i < MAX_CHANNELS; i++) {
+        if (!init_channel(encoder, &encoder->channels[i])) {
+            for (--i; i >= 0; i--) {
+                destroy_channel(&encoder->channels[i]);
+            }
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static int encoder_reste(Encoder *encoder, uint32_t *io_ptr, uint32_t *io_ptr_end)
+{
+    ASSERT(encoder->usr, ((unsigned long)io_ptr % 4) == ((unsigned long)io_ptr_end % 4));
+    ASSERT(encoder->usr, io_ptr <= io_ptr_end);
+
+    encoder->rgb_state.waitcnt = 0;
+    encoder->rgb_state.tabrand_seed = stabrand();
+    encoder->rgb_state.wmidx = DEFwmistart;
+    encoder->rgb_state.wmileft = wminext;
+    set_wm_trigger(&encoder->rgb_state);
+
+#if defined(RLE) && defined(RLE_STAT)
+    encoder_init_rle(&encoder->rgb_state);
+#endif
+
+    encoder->io_words_count = (uint32_t)(io_ptr_end - io_ptr);
+    encoder->io_now = io_ptr;
+    encoder->io_end = io_ptr_end;
+    encoder->rows_completed = 0;
+
+    return TRUE;
+}
+
+static int encoder_reste_channels(Encoder *encoder, int channels, int width, int bpc)
+{
+    int i;
+
+    encoder->num_channels = channels;
+
+    for (i = 0; i < channels; i++) {
+        s_bucket *bucket;
+        s_bucket *end_bucket;
+
+        if (encoder->channels[i].correlate_row_width < width) {
+            encoder->channels[i].correlate_row_width = 0;
+            if (encoder->channels[i].correlate_row) {
+                encoder->usr->free(encoder->usr, encoder->channels[i].correlate_row - 1);
+            }
+            if (!(encoder->channels[i].correlate_row = (BYTE *)encoder->usr->malloc(encoder->usr,
+                                                                                    width + 1))) {
+                return FALSE;
+            }
+            encoder->channels[i].correlate_row++;
+            encoder->channels[i].correlate_row_width = width;
+        }
+
+        if (bpc == 8) {
+            MEMCLEAR(encoder->channels[i].family_stat_8bpc.counters,
+                     encoder->n_buckets_8bpc * sizeof(COUNTER) * MAXNUMCODES);
+            bucket = encoder->channels[i].family_stat_8bpc.buckets_buf;
+            end_bucket = bucket + encoder->n_buckets_8bpc;
+            for (; bucket < end_bucket; bucket++) {
+                bucket->bestcode = /*BPC*/ 8 - 1;
+            }
+            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_8bpc.buckets_ptrs;
+        } else if (bpc == 5) {
+            MEMCLEAR(encoder->channels[i].family_stat_5bpc.counters,
+                     encoder->n_buckets_5bpc * sizeof(COUNTER) * MAXNUMCODES);
+            bucket = encoder->channels[i].family_stat_5bpc.buckets_buf;
+            end_bucket = bucket + encoder->n_buckets_5bpc;
+            for (; bucket < end_bucket; bucket++) {
+                bucket->bestcode = /*BPC*/ 5 - 1;
+            }
+            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_5bpc.buckets_ptrs;
+        } else {
+            encoder->usr->warn(encoder->usr, "%s: bad bpc %d\n", __FUNCTION__, bpc);
+            return FALSE;
+        }
+
+        encoder->channels[i].state.waitcnt = 0;
+        encoder->channels[i].state.tabrand_seed = stabrand();
+        encoder->channels[i].state.wmidx = DEFwmistart;
+        encoder->channels[i].state.wmileft = wminext;
+        set_wm_trigger(&encoder->channels[i].state);
+
+#if defined(RLE) && defined(RLE_STAT)
+        encoder_init_rle(&encoder->channels[i].state);
+#endif
+    }
+    return TRUE;
+}
+
+static void quic_image_params(Encoder *encoder, QuicImageType type, int *channels, int *bpc)
+{
+    ASSERT(encoder->usr, channels && bpc);
+    switch (type) {
+    case QUIC_IMAGE_TYPE_GRAY:
+        *channels = 1;
+        *bpc = 8;
+        break;
+    case QUIC_IMAGE_TYPE_RGB16:
+        *channels = 3;
+        *bpc = 5;
+#ifndef QUIC_RGB
+        encoder->usr->error(encoder->usr, "not implemented\n");
+#endif
+        break;
+    case QUIC_IMAGE_TYPE_RGB24:
+        *channels = 3;
+        *bpc = 8;
+        break;
+    case QUIC_IMAGE_TYPE_RGB32:
+        *channels = 3;
+        *bpc = 8;
+        break;
+    case QUIC_IMAGE_TYPE_RGBA:
+        *channels = 4;
+        *bpc = 8;
+        break;
+    case QUIC_IMAGE_TYPE_INVALID:
+    default:
+        *channels = 0;
+        *bpc = 0;
+        encoder->usr->error(encoder->usr, "bad image type\n");
+    }
+}
+
+#define FILL_LINES() {                                                  \
+    if (line == lines_end) {                                            \
+        int n = encoder->usr->more_lines(encoder->usr, &line);          \
+        if (n <= 0) {                                                   \
+            encoder->usr->error(encoder->usr, "more lines failed\n");   \
+        }                                                               \
+        lines_end = line + n * stride;                                  \
+    }                                                                   \
+}
+
+#define NEXT_LINE() {       \
+    line += stride;         \
+    FILL_LINES();           \
+}
+
+#define QUIC_COMPRESS_RGB(bits)                                                                 \
+        encoder->channels[0].correlate_row[-1] = 0;                                             \
+        encoder->channels[1].correlate_row[-1] = 0;                                             \
+        encoder->channels[2].correlate_row[-1] = 0;                                             \
+        quic_rgb##bits##_compress_row0(encoder, (rgb##bits##_pixel_t *)(line), width);          \
+        encoder->rows_completed++;                                                              \
+        for (row = 1; row < height; row++) {                                                    \
+            prev = line;                                                                        \
+            NEXT_LINE();                                                                        \
+            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];     \
+            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];     \
+            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];     \
+            quic_rgb##bits##_compress_row(encoder, (rgb##bits##_pixel_t *)prev,                 \
+                                          (rgb##bits##_pixel_t *)line, width);                  \
+            encoder->rows_completed++;                                                          \
+        }
+
+int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
+                uint8_t *line, unsigned int num_lines, int stride,
+                uint32_t *io_ptr, unsigned int num_io_words)
+{
+    Encoder *encoder = (Encoder *)quic;
+    uint32_t *io_ptr_end = io_ptr + num_io_words;
+    uint8_t *lines_end;
+    int row;
+    uint8_t *prev;
+    int channels;
+    int bpc;
+#ifndef QUIC_RGB
+    int i;
+#endif
+
+    ASSERT(encoder->usr, line);
+    lines_end = line + num_lines * stride;
+
+    quic_image_params(encoder, type, &channels, &bpc);
+
+    if (!encoder_reste(encoder, io_ptr, io_ptr_end) ||
+        !encoder_reste_channels(encoder, channels, width, bpc)) {
+        return QUIC_ERROR;
+    }
+
+    encoder->io_word = 0;
+    encoder->io_available_bits = 32;
+
+    encode_32(encoder, QUIC_MAGIC);
+    encode_32(encoder, QUIC_VERSION);
+    encode_32(encoder, type);
+    encode_32(encoder, width);
+    encode_32(encoder, height);
+
+    FILL_LINES();
+
+    switch (type) {
+#ifdef QUIC_RGB
+    case QUIC_IMAGE_TYPE_RGB32:
+        ASSERT(encoder->usr, ABS(stride) >= width * 4);
+        QUIC_COMPRESS_RGB(32);
+        break;
+    case QUIC_IMAGE_TYPE_RGB24:
+        ASSERT(encoder->usr, ABS(stride) >= width * 3);
+        QUIC_COMPRESS_RGB(24);
+        break;
+    case QUIC_IMAGE_TYPE_RGB16:
+        ASSERT(encoder->usr, ABS(stride) >= width * 2);
+        QUIC_COMPRESS_RGB(16);
+        break;
+    case QUIC_IMAGE_TYPE_RGBA:
+        ASSERT(encoder->usr, ABS(stride) >= width * 4);
+
+        encoder->channels[0].correlate_row[-1] = 0;
+        encoder->channels[1].correlate_row[-1] = 0;
+        encoder->channels[2].correlate_row[-1] = 0;
+        quic_rgb32_compress_row0(encoder, (rgb32_pixel_t *)(line), width);
+
+        encoder->channels[3].correlate_row[-1] = 0;
+        quic_four_compress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(line + 3), width);
+
+        encoder->rows_completed++;
+
+        for (row = 1; row < height; row++) {
+            prev = line;
+            NEXT_LINE();
+            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
+            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
+            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
+            quic_rgb32_compress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)line, width);
+
+            encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
+            quic_four_compress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
+                                   (four_bytes_t *)(line + 3), width);
+            encoder->rows_completed++;
+        }
+        break;
+#else
+    case QUIC_IMAGE_TYPE_RGB24:
+        ASSERT(encoder->usr, ABS(stride) >= width * 3);
+        for (i = 0; i < 3; i++) {
+            encoder->channels[i].correlate_row[-1] = 0;
+            quic_three_compress_row0(encoder, &encoder->channels[i], (three_bytes_t *)(line + i),
+                                     width);
+        }
+        encoder->rows_completed++;
+        for (row = 1; row < height; row++) {
+            prev = line;
+            NEXT_LINE();
+            for (i = 0; i < 3; i++) {
+                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
+                quic_three_compress_row(encoder, &encoder->channels[i], (three_bytes_t *)(prev + i),
+                                        (three_bytes_t *)(line + i), width);
+            }
+            encoder->rows_completed++;
+        }
+        break;
+    case QUIC_IMAGE_TYPE_RGB32:
+    case QUIC_IMAGE_TYPE_RGBA:
+        ASSERT(encoder->usr, ABS(stride) >= width * 4);
+        for (i = 0; i < channels; i++) {
+            encoder->channels[i].correlate_row[-1] = 0;
+            quic_four_compress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(line + i),
+                                    width);
+        }
+        encoder->rows_completed++;
+        for (row = 1; row < height; row++) {
+            prev = line;
+            NEXT_LINE();
+            for (i = 0; i < channels; i++) {
+                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
+                quic_four_compress_row(encoder, &encoder->channels[i], (four_bytes_t *)(prev + i),
+                                       (four_bytes_t *)(line + i), width);
+            }
+            encoder->rows_completed++;
+        }
+        break;
+#endif
+    case QUIC_IMAGE_TYPE_GRAY:
+        ASSERT(encoder->usr, ABS(stride) >= width);
+        encoder->channels[0].correlate_row[-1] = 0;
+        quic_one_compress_row0(encoder, &encoder->channels[0], (one_byte_t *)line, width);
+        encoder->rows_completed++;
+        for (row = 1; row < height; row++) {
+            prev = line;
+            NEXT_LINE();
+            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
+            quic_one_compress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
+                                  (one_byte_t *)line, width);
+            encoder->rows_completed++;
+        }
+        break;
+    case QUIC_IMAGE_TYPE_INVALID:
+    default:
+        encoder->usr->error(encoder->usr, "bad image type\n");
+    }
+
+    flush(encoder);
+    encoder->io_words_count -= (uint32_t)(encoder->io_end - encoder->io_now);
+
+    return encoder->io_words_count;
+}
+
+int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
+                      QuicImageType *out_type, int *out_width, int *out_height)
+{
+    Encoder *encoder = (Encoder *)quic;
+    uint32_t *io_ptr_end = io_ptr + num_io_words;
+    QuicImageType type;
+    int width;
+    int height;
+    uint32_t magic;
+    uint32_t version;
+    int channels;
+    int bpc;
+
+    if (!encoder_reste(encoder, io_ptr, io_ptr_end)) {
+        return QUIC_ERROR;
+    }
+
+    init_decode_io(encoder);
+
+    magic = encoder->io_word;
+    decode_eat32bits(encoder);
+    if (magic != QUIC_MAGIC) {
+        encoder->usr->warn(encoder->usr, "bad magic\n");
+        return QUIC_ERROR;
+    }
+
+    version = encoder->io_word;
+    decode_eat32bits(encoder);
+    if (version != QUIC_VERSION) {
+        encoder->usr->warn(encoder->usr, "bad version\n");
+        return QUIC_ERROR;
+    }
+
+    type = (QuicImageType)encoder->io_word;
+    decode_eat32bits(encoder);
+
+    width = encoder->io_word;
+    decode_eat32bits(encoder);
+
+    height = encoder->io_word;
+    decode_eat32bits(encoder);
+
+    quic_image_params(encoder, type, &channels, &bpc);
+
+    if (!encoder_reste_channels(encoder, channels, width, bpc)) {
+        return QUIC_ERROR;
+    }
+
+    *out_width = encoder->width = width;
+    *out_height = encoder->height = height;
+    *out_type = encoder->type = type;
+    return QUIC_OK;
+}
+
+#ifndef QUIC_RGB
+static void clear_row(four_bytes_t *row, int width)
+{
+    four_bytes_t *end;
+    for (end = row + width; row < end; row++) {
+        row->a = 0;
+    }
+}
+
+#endif
+
+#ifdef QUIC_RGB
+
+static void uncompress_rgba(Encoder *encoder, uint8_t *buf, int stride)
+{
+    unsigned int row;
+    uint8_t *prev;
+
+    encoder->channels[0].correlate_row[-1] = 0;
+    encoder->channels[1].correlate_row[-1] = 0;
+    encoder->channels[2].correlate_row[-1] = 0;
+    quic_rgb32_uncompress_row0(encoder, (rgb32_pixel_t *)buf, encoder->width);
+
+    encoder->channels[3].correlate_row[-1] = 0;
+    quic_four_uncompress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(buf + 3),
+                              encoder->width);
+
+    encoder->rows_completed++;
+    for (row = 1; row < encoder->height; row++) {
+        prev = buf;
+        buf += stride;
+
+        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
+        encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
+        encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
+        quic_rgb32_uncompress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)buf,
+                                  encoder->width);
+
+        encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
+        quic_four_uncompress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
+                                 (four_bytes_t *)(buf + 3), encoder->width);
+
+        encoder->rows_completed++;
+    }
+}
+
+#endif
+
+static void uncompress_gray(Encoder *encoder, uint8_t *buf, int stride)
+{
+    unsigned int row;
+    uint8_t *prev;
+
+    encoder->channels[0].correlate_row[-1] = 0;
+    quic_one_uncompress_row0(encoder, &encoder->channels[0], (one_byte_t *)buf, encoder->width);
+    encoder->rows_completed++;
+    for (row = 1; row < encoder->height; row++) {
+        prev = buf;
+        buf += stride;
+        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
+        quic_one_uncompress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
+                                (one_byte_t *)buf, encoder->width);
+        encoder->rows_completed++;
+    }
+}
+
+#define QUIC_UNCOMPRESS_RGB(prefix, type)                                                       \
+        encoder->channels[0].correlate_row[-1] = 0;                                             \
+        encoder->channels[1].correlate_row[-1] = 0;                                             \
+        encoder->channels[2].correlate_row[-1] = 0;                                             \
+        quic_rgb##prefix##_uncompress_row0(encoder, (type *)buf, encoder->width);  \
+        encoder->rows_completed++;                                                              \
+        for (row = 1; row < encoder->height; row++) {                                           \
+            prev = buf;                                                                         \
+            buf += stride;                                                                      \
+            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];     \
+            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];     \
+            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];     \
+            quic_rgb##prefix##_uncompress_row(encoder, (type *)prev, (type *)buf,               \
+                                              encoder->width);                                  \
+            encoder->rows_completed++;                                                          \
+        }
+        
+int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
+{
+    Encoder *encoder = (Encoder *)quic;
+    unsigned int row;
+    uint8_t *prev;
+#ifndef QUIC_RGB
+    int i;
+#endif
+
+    ASSERT(encoder->usr, buf);
+
+    switch (encoder->type) {
+#ifdef QUIC_RGB
+    case QUIC_IMAGE_TYPE_RGB32:
+    case QUIC_IMAGE_TYPE_RGB24:
+        if (type == QUIC_IMAGE_TYPE_RGB32) {
+            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
+            QUIC_UNCOMPRESS_RGB(32, rgb32_pixel_t);
+            break;
+        } else if (type == QUIC_IMAGE_TYPE_RGB24) {
+            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 3);
+            QUIC_UNCOMPRESS_RGB(24, rgb24_pixel_t);
+            break;
+        }
+        encoder->usr->warn(encoder->usr, "unsupported output format\n");
+        return QUIC_ERROR;
+    case QUIC_IMAGE_TYPE_RGB16:
+        if (type == QUIC_IMAGE_TYPE_RGB16) {
+            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 2);
+            QUIC_UNCOMPRESS_RGB(16, rgb16_pixel_t);
+        } else if (type == QUIC_IMAGE_TYPE_RGB32) {
+            ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
+            QUIC_UNCOMPRESS_RGB(16_to_32, rgb32_pixel_t);
+        } else {
+            encoder->usr->warn(encoder->usr, "unsupported output format\n");
+            return QUIC_ERROR;
+        }
+
+        break;
+    case QUIC_IMAGE_TYPE_RGBA:
+
+        if (type != QUIC_IMAGE_TYPE_RGBA) {
+            encoder->usr->warn(encoder->usr, "unsupported output format\n");
+            return QUIC_ERROR;
+        }
+        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 4);
+        uncompress_rgba(encoder, buf, stride);
+        break;
+#else
+    case QUIC_IMAGE_TYPE_RGB24:
+        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width * 3);
+        for (i = 0; i < 3; i++) {
+            encoder->channels[i].correlate_row[-1] = 0;
+            quic_three_uncompress_row0(encoder, &encoder->channels[i], (three_bytes_t *)(buf + i),
+                                       encoder->width);
+        }
+        encoder->rows_completed++;
+        for (row = 1; row < encoder->height; row++) {
+            prev = buf;
+            buf += stride;
+            for (i = 0; i < 3; i++) {
+                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
+                quic_three_uncompress_row(encoder, &encoder->channels[i],
+                                          (three_bytes_t *)(prev + i),
+                                          (three_bytes_t *)(buf + i),
+                                          encoder->width);
+            }
+            encoder->rows_completed++;
+        }
+        break;
+    case QUIC_IMAGE_TYPE_RGB32:
+        ASSERT(encoder->usr, ABS(stride) >= encoder->width * 4);
+        for (i = 0; i < 3; i++) {
+            encoder->channels[i].correlate_row[-1] = 0;
+            quic_four_uncompress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(buf + i),
+                                      encoder->width);
+        }
+        clear_row((four_bytes_t *)(buf + 3), encoder->width);
+        encoder->rows_completed++;
+        for (row = 1; row < encoder->height; row++) {
+            prev = buf;
+            buf += stride;
+            for (i = 0; i < 3; i++) {
+                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
+                quic_four_uncompress_row(encoder, &encoder->channels[i],
+                                         (four_bytes_t *)(prev + i),
+                                         (four_bytes_t *)(buf + i),
+                                         encoder->width);
+            }
+            clear_row((four_bytes_t *)(buf + 3), encoder->width);
+            encoder->rows_completed++;
+        }
+        break;
+    case QUIC_IMAGE_TYPE_RGBA:
+        ASSERT(encoder->usr, ABS(stride) >= encoder->width * 4);
+        for (i = 0; i < 4; i++) {
+            encoder->channels[i].correlate_row[-1] = 0;
+            quic_four_uncompress_row0(encoder, &encoder->channels[i], (four_bytes_t *)(buf + i),
+                                      encoder->width);
+        }
+        encoder->rows_completed++;
+        for (row = 1; row < encoder->height; row++) {
+            prev = buf;
+            buf += stride;
+            for (i = 0; i < 4; i++) {
+                encoder->channels[i].correlate_row[-1] = encoder->channels[i].correlate_row[0];
+                quic_four_uncompress_row(encoder, &encoder->channels[i],
+                                         (four_bytes_t *)(prev + i),
+                                         (four_bytes_t *)(buf + i),
+                                         encoder->width);
+            }
+            encoder->rows_completed++;
+        }
+        break;
+#endif
+    case QUIC_IMAGE_TYPE_GRAY:
+
+        if (type != QUIC_IMAGE_TYPE_GRAY) {
+            encoder->usr->warn(encoder->usr, "unsupported output format\n");
+            return QUIC_ERROR;
+        }
+        ASSERT(encoder->usr, ABS(stride) >= (int)encoder->width);
+        uncompress_gray(encoder, buf, stride);
+        break;
+    case QUIC_IMAGE_TYPE_INVALID:
+    default:
+        encoder->usr->error(encoder->usr, "bad image type\n");
+    }
+    return QUIC_OK;
+}
+
+static int need_init = TRUE;
+
+QuicContext *quic_create(QuicUsrContext *usr)
+{
+    Encoder *encoder;
+
+    if (!usr || need_init || !usr->error || !usr->warn || !usr->info || !usr->malloc ||
+        !usr->free || !usr->more_space || !usr->more_lines) {
+        return NULL;
+    }
+
+    if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) {
+        return NULL;
+    }
+
+    if (!init_encoder(encoder, usr)) {
+        usr->free(usr, encoder);
+        return NULL;
+    }
+    return (QuicContext *)encoder;
+}
+
+void quic_destroy(QuicContext *quic)
+{
+    Encoder *encoder = (Encoder *)quic;
+    int i;
+
+    if (!quic) {
+        return;
+    }
+
+    for (i = 0; i < MAX_CHANNELS; i++) {
+        destroy_channel(&encoder->channels[i]);
+    }
+    encoder->usr->free(encoder->usr, encoder);
+}
+
+void quic_init()
+{
+    if (!need_init) {
+        return;
+    }
+    need_init = FALSE;
+
+    family_init(&family_8bpc, 8, DEFmaxclen);
+    family_init(&family_5bpc, 5, DEFmaxclen);
+#if defined(RLE) && defined(RLE_STAT)
+    init_zeroLUT();
+#endif
+}
+
diff --git a/xddm/display/quic.h b/xddm/display/quic.h
new file mode 100644
index 0000000..9463760
--- /dev/null
+++ b/xddm/display/quic.h
@@ -0,0 +1,68 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef __QUIC_H
+#define __QUIC_H
+
+#include "quic_config.h"
+
+typedef enum {
+    QUIC_IMAGE_TYPE_INVALID,
+    QUIC_IMAGE_TYPE_GRAY,
+    QUIC_IMAGE_TYPE_RGB16,
+    QUIC_IMAGE_TYPE_RGB24,
+    QUIC_IMAGE_TYPE_RGB32,
+    QUIC_IMAGE_TYPE_RGBA
+} QuicImageType;
+
+#define QUIC_ERROR -1
+#define QUIC_OK 0
+
+typedef void *QuicContext;
+
+typedef struct QuicUsrContext QuicUsrContext;
+struct QuicUsrContext {
+    void (*error)(QuicUsrContext *usr, const char *fmt, ...);
+    void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
+    void (*info)(QuicUsrContext *usr, const char *fmt, ...);
+    void *(*malloc)(QuicUsrContext *usr, int size);
+    void (*free)(QuicUsrContext *usr, void *ptr);
+    int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
+    int (*more_lines)(QuicUsrContext *usr, uint8_t **lines); // on return the last line of previous
+                                                             // lines bunch must stil be valid
+};
+
+int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
+                uint8_t *lines, unsigned int num_lines, int stride,
+                uint32_t *io_ptr, unsigned int num_io_words);
+
+int quic_decode_begin(QuicContext *quic, uint32_t *io_ptr, unsigned int num_io_words,
+                      QuicImageType *type, int *width, int *height);
+int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride);
+
+
+QuicContext *quic_create(QuicUsrContext *usr);
+void quic_destroy(QuicContext *quic);
+
+void quic_init();
+
+#endif
+
diff --git a/xddm/display/quic_config.h b/xddm/display/quic_config.h
new file mode 100644
index 0000000..2c41ecb
--- /dev/null
+++ b/xddm/display/quic_config.h
@@ -0,0 +1,54 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef __QUIC_CONFIG_H
+#define __QUIC_CONFIG_H
+
+#include <spice/types.h>
+
+#ifdef __GNUC__
+
+#include <string.h>
+
+#define INLINE inline
+
+#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
+
+#else
+
+#ifdef QXLDD
+#include <windef.h>
+#include "os_dep.h"
+#define INLINE _inline
+#define MEMCLEAR(ptr, size) RtlZeroMemory(ptr, size)
+#else
+#include <stddef.h>
+#include <string.h>
+
+#define INLINE inline
+#define MEMCLEAR(ptr, size) memset(ptr, 0, size)
+#endif
+
+
+#endif
+
+#endif
+
diff --git a/xddm/display/quic_family_tmpl.c b/xddm/display/quic_family_tmpl.c
new file mode 100644
index 0000000..695c482
--- /dev/null
+++ b/xddm/display/quic_family_tmpl.c
@@ -0,0 +1,118 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifdef QUIC_FAMILY_8BPC
+#undef QUIC_FAMILY_8BPC
+#define FNAME(name) name##_8bpc
+#define VNAME(name) name##_8bpc
+#define BPC 8
+#endif
+
+
+#ifdef QUIC_FAMILY_5BPC
+#undef QUIC_FAMILY_5BPC
+#define FNAME(name) name##_5bpc
+#define VNAME(name) name##_5bpc
+#define BPC 5
+#endif
+
+
+static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
+{
+    if (n < VNAME(family).nGRcodewords[l]) {
+        return (n >> l) + 1 + l;
+    } else {
+        return VNAME(family).notGRcwlen[l];
+    }
+}
+
+static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
+                                 unsigned int * const codewordlen)
+{
+    if (n < VNAME(family).nGRcodewords[l]) {
+        (*codeword) = bitat[l] | (n & bppmask[l]);
+        (*codewordlen) = (n >> l) + l + 1;
+    } else {
+        (*codeword) = n - VNAME(family).nGRcodewords[l];
+        (*codewordlen) = VNAME(family).notGRcwlen[l];
+    }
+}
+
+unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
+                                    unsigned int * const codewordlen)
+{
+    if (bits > VNAME(family).notGRprefixmask[l]) { /*GR*/
+        const unsigned int zeroprefix = cnt_l_zeroes(bits);       /* leading zeroes in codeword */
+        const unsigned int cwlen = zeroprefix + 1 + l;            /* codeword length */
+        (*codewordlen) = cwlen;
+        return (zeroprefix << l) | ((bits >> (32 - cwlen)) & bppmask[l]);
+    } else { /* not-GR */
+        const unsigned int cwlen = VNAME(family).notGRcwlen[l];
+        (*codewordlen) = cwlen;
+        return VNAME(family).nGRcodewords[l] + ((bits) >> (32 - cwlen) &
+                                                bppmask[VNAME(family).notGRsuffixlen[l]]);
+    }
+}
+
+/* update the bucket using just encoded curval */
+static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
+                                const BYTE curval, unsigned int bpp)
+{
+    COUNTER * const pcounters = bucket->pcounters;
+    unsigned int i;
+    unsigned int bestcode;
+    unsigned int bestcodelen;
+    //unsigned int bpp = encoder->bpp;
+
+    /* update counters, find minimum */
+
+    bestcode = bpp - 1;
+    bestcodelen = (pcounters[bestcode] += FNAME(golomb_code_len)(curval, bestcode));
+
+    for (i = bpp - 2; i < bpp; i--) { /* NOTE: expression i<bpp for signed int i would be: i>=0 */
+        const unsigned int ithcodelen = (pcounters[i] += FNAME(golomb_code_len)(curval, i));
+
+        if (ithcodelen < bestcodelen) {
+            bestcode = i;
+            bestcodelen = ithcodelen;
+        }
+    }
+
+    bucket->bestcode = bestcode; /* store the found minimum */
+
+    if (bestcodelen > state->wm_trigger) { /* halving counters? */
+        for (i = 0; i < bpp; i++) {
+            pcounters[i] >>= 1;
+        }
+    }
+}
+
+static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
+{
+    ASSERT(channel->encoder->usr, val < (0x1U << BPC));
+
+    return channel->_buckets_ptrs[val];
+}
+
+#undef FNAME
+#undef VNAME
+#undef BPC
+
diff --git a/xddm/display/quic_rgb_tmpl.c b/xddm/display/quic_rgb_tmpl.c
new file mode 100644
index 0000000..b256d18
--- /dev/null
+++ b/xddm/display/quic_rgb_tmpl.c
@@ -0,0 +1,766 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifdef QUIC_RGB32
+#undef QUIC_RGB32
+#define PIXEL rgb32_pixel_t
+#define FNAME(name) quic_rgb32_##name
+#define golomb_coding golomb_coding_8bpc
+#define golomb_decoding golomb_decoding_8bpc
+#define update_model update_model_8bpc
+#define find_bucket find_bucket_8bpc
+#define family family_8bpc
+#define BPC 8
+#define BPC_MASK 0xffU
+#define COMPRESS_IMP
+#define SET_r(pix, val) ((pix)->r = val)
+#define GET_r(pix) ((pix)->r)
+#define SET_g(pix, val) ((pix)->g = val)
+#define GET_g(pix) ((pix)->g)
+#define SET_b(pix, val) ((pix)->b = val)
+#define GET_b(pix) ((pix)->b)
+#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
+#endif
+
+#ifdef QUIC_RGB24
+#undef QUIC_RGB24
+#define PIXEL rgb24_pixel_t
+#define FNAME(name) quic_rgb24_##name
+#define golomb_coding golomb_coding_8bpc
+#define golomb_decoding golomb_decoding_8bpc
+#define update_model update_model_8bpc
+#define find_bucket find_bucket_8bpc
+#define family family_8bpc
+#define BPC 8
+#define BPC_MASK 0xffU
+#define COMPRESS_IMP
+#define SET_r(pix, val) ((pix)->r = val)
+#define GET_r(pix) ((pix)->r)
+#define SET_g(pix, val) ((pix)->g = val)
+#define GET_g(pix) ((pix)->g)
+#define SET_b(pix, val) ((pix)->b = val)
+#define GET_b(pix) ((pix)->b)
+#define UNCOMPRESS_PIX_START(pix)
+#endif
+
+#ifdef QUIC_RGB16
+#undef QUIC_RGB16
+#define PIXEL rgb16_pixel_t
+#define FNAME(name) quic_rgb16_##name
+#define golomb_coding golomb_coding_5bpc
+#define golomb_decoding golomb_decoding_5bpc
+#define update_model update_model_5bpc
+#define find_bucket find_bucket_5bpc
+#define family family_5bpc
+#define BPC 5
+#define BPC_MASK 0x1fU
+#define COMPRESS_IMP
+#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
+#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
+#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
+#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
+#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
+#define GET_b(pix) (*(pix) & 0x1f)
+#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
+#endif
+
+#ifdef QUIC_RGB16_TO_32
+#undef QUIC_RGB16_TO_32
+#define PIXEL rgb32_pixel_t
+#define FNAME(name) quic_rgb16_to_32_##name
+#define golomb_coding golomb_coding_5bpc
+#define golomb_decoding golomb_decoding_5bpc
+#define update_model update_model_5bpc
+#define find_bucket find_bucket_5bpc
+#define family family_5bpc
+#define BPC 5
+#define BPC_MASK 0x1fU
+
+#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
+#define GET_r(pix) ((pix)->r >> 3)
+#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
+#define GET_g(pix) ((pix)->g >> 3)
+#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
+#define GET_b(pix) ((pix)->b >> 3)
+#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
+#endif
+
+#define SAME_PIXEL(p1, p2)                                 \
+    (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) &&   \
+     GET_b(p1) == GET_b(p2))
+
+
+#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
+#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
+#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
+
+/*  a  */
+
+#define DECORELATE_0(channel, curr, bpc_mask)\
+    family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
+
+#define CORELATE_0(channel, curr, correlate, bpc_mask)\
+    ((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
+
+#ifdef PRED_1
+
+/*  (a+b)/2  */
+#define DECORELATE(channel, prev, curr, bpc_mask, r)                                            \
+    r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) +   \
+                        _PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
+
+#define CORELATE(channel, prev, curr, correlate, bpc_mask, r)                                   \
+    SET_##channel(r, ((family.xlatL2U[correlate] +                                              \
+          (int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
+#endif
+
+#ifdef PRED_2
+
+/*  .75a+.75b-.5c  */
+#define DECORELATE(channel, prev, curr, bpc_mask, r) {                          \
+    int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) -   \
+                        (int)(_PIXEL_C(channel, prev) << 1)) >> 2;              \
+    if (p < 0) {                                                                \
+        p = 0;                                                                  \
+    } else if ((unsigned)p > bpc_mask) {                                        \
+        p = bpc_mask;                                                           \
+    }                                                                           \
+    r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask];    \
+}
+
+#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) {                         \
+    const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) -     \
+                        (int)(_PIXEL_C(channel, prev) << 1) ) >> 2;                     \
+    const unsigned int s = family.xlatL2U[correlate];                                   \
+    if (!(p & ~bpc_mask)) {                                                             \
+        SET_##channel(r, (s + (unsigned)p) & bpc_mask);                                 \
+    } else if (p < 0) {                                                                 \
+        SET_##channel(r, s);                                                            \
+    } else {                                                                            \
+        SET_##channel(r, (s + bpc_mask) & bpc_mask);                                    \
+    }                                                                                   \
+}
+
+#endif
+
+
+#define COMPRESS_ONE_ROW0_0(channel)                                                \
+    correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)];            \
+    golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel,        \
+                  correlate_row_##channel[-1])->bestcode,                           \
+                  &codeword, &codewordlen);                                         \
+    encode(encoder, codeword, codewordlen);
+
+#define COMPRESS_ONE_ROW0(channel, index)                                               \
+    correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask);  \
+    golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel,        \
+                  correlate_row_##channel[index -1])->bestcode,                         \
+                  &codeword, &codewordlen);                                             \
+    encode(encoder, codeword, codewordlen);
+
+#define UPDATE_MODEL(index)                                                                 \
+    update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]),   \
+                correlate_row_r[index], bpc);                                               \
+    update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]),   \
+                correlate_row_g[index], bpc);                                               \
+    update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]),   \
+                correlate_row_b[index], bpc);
+
+
+#ifdef RLE_PRED_1
+#define RLE_PRED_1_IMP                                                                          \
+if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) {                                                \
+    if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) &&                         \
+                                i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) {    \
+        goto do_run;                                                                            \
+    }                                                                                           \
+}
+#else
+#define RLE_PRED_1_IMP
+#endif
+
+#ifdef RLE_PRED_2
+#define RLE_PRED_2_IMP                                                              \
+if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) {                                   \
+    if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) {  \
+        goto do_run;                                                                \
+    }                                                                               \
+}
+#else
+#define RLE_PRED_2_IMP
+#endif
+
+#ifdef RLE_PRED_3
+#define RLE_PRED_3_IMP                                                              \
+if (i > 1 &&  SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) {     \
+    goto do_run;                                                                    \
+}
+#else
+#define RLE_PRED_3_IMP
+#endif
+
+#ifdef COMPRESS_IMP
+
+static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
+                                     const PIXEL * const cur_row,
+                                     const int end,
+                                     const unsigned int waitmask,
+                                     const unsigned int bpc,
+                                     const unsigned int bpc_mask)
+{
+    Channel * const channel_r = encoder->channels;
+    Channel * const channel_g = channel_r + 1;
+    Channel * const channel_b = channel_g + 1;
+
+    BYTE * const correlate_row_r = channel_r->correlate_row;
+    BYTE * const correlate_row_g = channel_g->correlate_row;
+    BYTE * const correlate_row_b = channel_b->correlate_row;
+    int stopidx;
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (!i) {
+        unsigned int codeword, codewordlen;
+
+        COMPRESS_ONE_ROW0_0(r);
+        COMPRESS_ONE_ROW0_0(g);
+        COMPRESS_ONE_ROW0_0(b);
+
+        if (encoder->rgb_state.waitcnt) {
+            encoder->rgb_state.waitcnt--;
+        } else {
+            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+            UPDATE_MODEL(0);
+        }
+        stopidx = ++i + encoder->rgb_state.waitcnt;
+    } else {
+        stopidx = i + encoder->rgb_state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        for (; i <= stopidx; i++) {
+            unsigned int codeword, codewordlen;
+            COMPRESS_ONE_ROW0(r, i);
+            COMPRESS_ONE_ROW0(g, i);
+            COMPRESS_ONE_ROW0(b, i);
+        }
+
+        UPDATE_MODEL(stopidx);
+        stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+    }
+
+    for (; i < end; i++) {
+        unsigned int codeword, codewordlen;
+
+        COMPRESS_ONE_ROW0(r, i);
+        COMPRESS_ONE_ROW0(g, i);
+        COMPRESS_ONE_ROW0(b, i);
+    }
+    encoder->rgb_state.waitcnt = stopidx - end;
+}
+
+static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
+                                 unsigned int width)
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    int pos = 0;
+
+    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
+        if (encoder->rgb_state.wmileft) {
+            FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
+                                     bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
+            width -= encoder->rgb_state.wmileft;
+            pos += encoder->rgb_state.wmileft;
+        }
+
+        encoder->rgb_state.wmidx++;
+        set_wm_trigger(&encoder->rgb_state);
+        encoder->rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
+                                 bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)encoder->rgb_state.wmidx) {
+            encoder->rgb_state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
+    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+#define COMPRESS_ONE_0(channel) \
+    correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) -    \
+                                                (int)GET_##channel(prev_row) ) & bpc_mask]; \
+    golomb_coding(correlate_row_##channel[0],                                               \
+                  find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode,    \
+                  &codeword, &codewordlen);                                                 \
+    encode(encoder, codeword, codewordlen);
+
+#define COMPRESS_ONE(channel, index)                                                            \
+    DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask,                             \
+               correlate_row_##channel[index]);                                                 \
+    golomb_coding(correlate_row_##channel[index],                                               \
+                 find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode,  \
+                 &codeword, &codewordlen);                                                      \
+    encode(encoder, codeword, codewordlen);
+
+static void FNAME(compress_row_seg)(Encoder *encoder, int i,
+                                    const PIXEL * const prev_row,
+                                    const PIXEL * const cur_row,
+                                    const int end,
+                                    const unsigned int waitmask,
+                                    const unsigned int bpc,
+                                    const unsigned int bpc_mask)
+{
+    Channel * const channel_r = encoder->channels;
+    Channel * const channel_g = channel_r + 1;
+    Channel * const channel_b = channel_g + 1;
+
+    BYTE * const correlate_row_r = channel_r->correlate_row;
+    BYTE * const correlate_row_g = channel_g->correlate_row;
+    BYTE * const correlate_row_b = channel_b->correlate_row;
+    int stopidx;
+#ifdef RLE
+    int run_index = 0;
+    int run_size;
+#endif
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (!i) {
+        unsigned int codeword, codewordlen;
+
+        COMPRESS_ONE_0(r);
+        COMPRESS_ONE_0(g);
+        COMPRESS_ONE_0(b);
+
+        if (encoder->rgb_state.waitcnt) {
+            encoder->rgb_state.waitcnt--;
+        } else {
+            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+            UPDATE_MODEL(0);
+        }
+        stopidx = ++i + encoder->rgb_state.waitcnt;
+    } else {
+        stopidx = i + encoder->rgb_state.waitcnt;
+    }
+    for (;;) {
+        while (stopidx < end) {
+            for (; i <= stopidx; i++) {
+                unsigned int codeword, codewordlen;
+#ifdef RLE
+                RLE_PRED_1_IMP;
+                RLE_PRED_2_IMP;
+                RLE_PRED_3_IMP;
+#endif
+                COMPRESS_ONE(r, i);
+                COMPRESS_ONE(g, i);
+                COMPRESS_ONE(b, i);
+            }
+
+            UPDATE_MODEL(stopidx);
+            stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+        }
+
+        for (; i < end; i++) {
+            unsigned int codeword, codewordlen;
+#ifdef RLE
+            RLE_PRED_1_IMP;
+            RLE_PRED_2_IMP;
+            RLE_PRED_3_IMP;
+#endif
+            COMPRESS_ONE(r, i);
+            COMPRESS_ONE(g, i);
+            COMPRESS_ONE(b, i);
+        }
+        encoder->rgb_state.waitcnt = stopidx - end;
+
+        return;
+
+#ifdef RLE
+do_run:
+        run_index = i;
+        encoder->rgb_state.waitcnt = stopidx - i;
+        run_size = 0;
+
+        while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
+            run_size++;
+            if (++i == end) {
+                encode_run(encoder, run_size);
+                return;
+            }
+        }
+        encode_run(encoder, run_size);
+        stopidx = i + encoder->rgb_state.waitcnt;
+#endif
+    }
+}
+
+static void FNAME(compress_row)(Encoder *encoder,
+                                const PIXEL * const prev_row,
+                                const PIXEL * const cur_row,
+                                unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
+        if (encoder->rgb_state.wmileft) {
+            FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
+                                    pos + encoder->rgb_state.wmileft,
+                                    bppmask[encoder->rgb_state.wmidx],
+                                    bpc, bpc_mask);
+            width -= encoder->rgb_state.wmileft;
+            pos += encoder->rgb_state.wmileft;
+        }
+
+        encoder->rgb_state.wmidx++;
+        set_wm_trigger(&encoder->rgb_state);
+        encoder->rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
+                                bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)encoder->rgb_state.wmidx) {
+            encoder->rgb_state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
+    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+#endif
+
+#define UNCOMPRESS_ONE_ROW0_0(channel)                                                          \
+    correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel,           \
+                                                       correlate_row_##channel[-1])->bestcode,  \
+                                                       encoder->io_word, &codewordlen);         \
+    SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]);               \
+    decode_eatbits(encoder, codewordlen);
+
+#define UNCOMPRESS_ONE_ROW0(channel)                                                              \
+    correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel,             \
+                                                       correlate_row_##channel[i - 1])->bestcode, \
+                                                       encoder->io_word,                          \
+                                                       &codewordlen);                             \
+    SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i],       \
+                  bpc_mask));                                                                     \
+    decode_eatbits(encoder, codewordlen);
+
+static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
+                                       PIXEL * const cur_row,
+                                       const int end,
+                                       const unsigned int waitmask,
+                                       const unsigned int bpc,
+                                       const unsigned int bpc_mask)
+{
+    Channel * const channel_r = encoder->channels;
+    Channel * const channel_g = channel_r + 1;
+    Channel * const channel_b = channel_g + 1;
+
+    BYTE * const correlate_row_r = channel_r->correlate_row;
+    BYTE * const correlate_row_g = channel_g->correlate_row;
+    BYTE * const correlate_row_b = channel_b->correlate_row;
+    int stopidx;
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (!i) {
+        unsigned int codewordlen;
+
+        UNCOMPRESS_PIX_START(&cur_row[i]);
+        UNCOMPRESS_ONE_ROW0_0(r);
+        UNCOMPRESS_ONE_ROW0_0(g);
+        UNCOMPRESS_ONE_ROW0_0(b);
+
+        if (encoder->rgb_state.waitcnt) {
+            --encoder->rgb_state.waitcnt;
+        } else {
+            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+            UPDATE_MODEL(0);
+        }
+        stopidx = ++i + encoder->rgb_state.waitcnt;
+    } else {
+        stopidx = i + encoder->rgb_state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        for (; i <= stopidx; i++) {
+            unsigned int codewordlen;
+
+            UNCOMPRESS_PIX_START(&cur_row[i]);
+            UNCOMPRESS_ONE_ROW0(r);
+            UNCOMPRESS_ONE_ROW0(g);
+            UNCOMPRESS_ONE_ROW0(b);
+        }
+        UPDATE_MODEL(stopidx);
+        stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+    }
+
+    for (; i < end; i++) {
+        unsigned int codewordlen;
+
+        UNCOMPRESS_PIX_START(&cur_row[i]);
+        UNCOMPRESS_ONE_ROW0(r);
+        UNCOMPRESS_ONE_ROW0(g);
+        UNCOMPRESS_ONE_ROW0(b);
+    }
+    encoder->rgb_state.waitcnt = stopidx - end;
+}
+
+static void FNAME(uncompress_row0)(Encoder *encoder,
+                                   PIXEL * const cur_row,
+                                   unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
+        if (encoder->rgb_state.wmileft) {
+            FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
+                                       pos + encoder->rgb_state.wmileft,
+                                       bppmask[encoder->rgb_state.wmidx],
+                                       bpc, bpc_mask);
+            pos += encoder->rgb_state.wmileft;
+            width -= encoder->rgb_state.wmileft;
+        }
+
+        encoder->rgb_state.wmidx++;
+        set_wm_trigger(&encoder->rgb_state);
+        encoder->rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
+                                   bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)encoder->rgb_state.wmidx) {
+            encoder->rgb_state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
+    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+#define UNCOMPRESS_ONE_0(channel) \
+    correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel,           \
+                                                       correlate_row_##channel[-1])->bestcode,  \
+                                                       encoder->io_word, &codewordlen);         \
+    SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] +                    \
+                          GET_##channel(prev_row)) & bpc_mask);                                 \
+    decode_eatbits(encoder, codewordlen);
+
+#define UNCOMPRESS_ONE(channel)                                                                   \
+    correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel,             \
+                                                       correlate_row_##channel[i - 1])->bestcode, \
+                                                       encoder->io_word,                          \
+                                                       &codewordlen);                             \
+    CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask,            \
+             &cur_row[i]);                                                                        \
+    decode_eatbits(encoder, codewordlen);
+
+static void FNAME(uncompress_row_seg)(Encoder *encoder,
+                                      const PIXEL * const prev_row,
+                                      PIXEL * const cur_row,
+                                      int i,
+                                      const int end,
+                                      const unsigned int bpc,
+                                      const unsigned int bpc_mask)
+{
+    Channel * const channel_r = encoder->channels;
+    Channel * const channel_g = channel_r + 1;
+    Channel * const channel_b = channel_g + 1;
+
+    BYTE * const correlate_row_r = channel_r->correlate_row;
+    BYTE * const correlate_row_g = channel_g->correlate_row;
+    BYTE * const correlate_row_b = channel_b->correlate_row;
+    const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
+    int stopidx;
+#ifdef RLE
+    int run_index = 0;
+    int run_end;
+#endif
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (!i) {
+        unsigned int codewordlen;
+
+        UNCOMPRESS_PIX_START(&cur_row[i]);
+        UNCOMPRESS_ONE_0(r);
+        UNCOMPRESS_ONE_0(g);
+        UNCOMPRESS_ONE_0(b);
+
+        if (encoder->rgb_state.waitcnt) {
+            --encoder->rgb_state.waitcnt;
+        } else {
+            encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+            UPDATE_MODEL(0);
+        }
+        stopidx = ++i + encoder->rgb_state.waitcnt;
+    } else {
+        stopidx = i + encoder->rgb_state.waitcnt;
+    }
+    for (;;) {
+        while (stopidx < end) {
+            for (; i <= stopidx; i++) {
+                unsigned int codewordlen;
+#ifdef RLE
+                RLE_PRED_1_IMP;
+                RLE_PRED_2_IMP;
+                RLE_PRED_3_IMP;
+#endif
+                UNCOMPRESS_PIX_START(&cur_row[i]);
+                UNCOMPRESS_ONE(r);
+                UNCOMPRESS_ONE(g);
+                UNCOMPRESS_ONE(b);
+            }
+
+            UPDATE_MODEL(stopidx);
+
+            stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
+        }
+
+        for (; i < end; i++) {
+            unsigned int codewordlen;
+#ifdef RLE
+            RLE_PRED_1_IMP;
+            RLE_PRED_2_IMP;
+            RLE_PRED_3_IMP;
+#endif
+            UNCOMPRESS_PIX_START(&cur_row[i]);
+            UNCOMPRESS_ONE(r);
+            UNCOMPRESS_ONE(g);
+            UNCOMPRESS_ONE(b);
+        }
+
+        encoder->rgb_state.waitcnt = stopidx - end;
+
+        return;
+
+#ifdef RLE
+do_run:
+        encoder->rgb_state.waitcnt = stopidx - i;
+        run_index = i;
+        run_end = i + decode_run(encoder);
+
+        for (; i < run_end; i++) {
+            UNCOMPRESS_PIX_START(&cur_row[i]);
+            SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
+            SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
+            SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
+        }
+
+        if (i == end) {
+            return;
+        }
+
+        stopidx = i + encoder->rgb_state.waitcnt;
+#endif
+    }
+}
+
+static void FNAME(uncompress_row)(Encoder *encoder,
+                                  const PIXEL * const prev_row,
+                                  PIXEL * const cur_row,
+                                  unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
+        if (encoder->rgb_state.wmileft) {
+            FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
+                                      pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
+            pos += encoder->rgb_state.wmileft;
+            width -= encoder->rgb_state.wmileft;
+        }
+
+        encoder->rgb_state.wmidx++;
+        set_wm_trigger(&encoder->rgb_state);
+        encoder->rgb_state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
+                                  pos + width, bpc, bpc_mask);
+        if (wmimax > (int)encoder->rgb_state.wmidx) {
+            encoder->rgb_state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
+    ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+#undef PIXEL
+#undef FNAME
+#undef _PIXEL_A
+#undef _PIXEL_B
+#undef _PIXEL_C
+#undef SAME_PIXEL
+#undef RLE_PRED_1_IMP
+#undef RLE_PRED_2_IMP
+#undef RLE_PRED_3_IMP
+#undef UPDATE_MODEL
+#undef DECORELATE_0
+#undef DECORELATE
+#undef COMPRESS_ONE_ROW0_0
+#undef COMPRESS_ONE_ROW0
+#undef COMPRESS_ONE_0
+#undef COMPRESS_ONE
+#undef CORELATE_0
+#undef CORELATE
+#undef UNCOMPRESS_ONE_ROW0_0
+#undef UNCOMPRESS_ONE_ROW0
+#undef UNCOMPRESS_ONE_0
+#undef UNCOMPRESS_ONE
+#undef golomb_coding
+#undef golomb_decoding
+#undef update_model
+#undef find_bucket
+#undef family
+#undef BPC
+#undef BPC_MASK
+#undef COMPRESS_IMP
+#undef SET_r
+#undef GET_r
+#undef SET_g
+#undef GET_g
+#undef SET_b
+#undef GET_b
+#undef UNCOMPRESS_PIX_START
+
diff --git a/xddm/display/quic_tmpl.c b/xddm/display/quic_tmpl.c
new file mode 100644
index 0000000..6591d02
--- /dev/null
+++ b/xddm/display/quic_tmpl.c
@@ -0,0 +1,636 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifdef ONE_BYTE
+#undef ONE_BYTE
+#define FNAME(name) quic_one_##name
+#define PIXEL one_byte_t
+#endif
+
+#ifdef THREE_BYTE
+#undef THREE_BYTE
+#define FNAME(name) quic_three_##name
+#define PIXEL three_bytes_t
+#endif
+
+#ifdef FOUR_BYTE
+#undef FOUR_BYTE
+#define FNAME(name) quic_four_##name
+#define PIXEL four_bytes_t
+#endif
+
+#define golomb_coding golomb_coding_8bpc
+#define golomb_decoding golomb_decoding_8bpc
+#define update_model update_model_8bpc
+#define find_bucket find_bucket_8bpc
+#define family family_8bpc
+
+#define BPC 8
+#define BPC_MASK 0xffU
+
+#define _PIXEL_A ((unsigned int)curr[-1].a)
+#define _PIXEL_B ((unsigned int)prev[0].a)
+#define _PIXEL_C ((unsigned int)prev[-1].a)
+
+#ifdef RLE_PRED_1
+#define RLE_PRED_1_IMP                                                              \
+if (cur_row[i - 1].a == prev_row[i].a) {                                            \
+    if (run_index != i && prev_row[i - 1].a == prev_row[i].a &&                     \
+                        i + 1 < end && prev_row[i].a == prev_row[i + 1].a) {        \
+        goto do_run;                                                                \
+    }                                                                               \
+}
+#else
+#define RLE_PRED_1_IMP
+#endif
+
+#ifdef RLE_PRED_2
+#define RLE_PRED_2_IMP                                                     \
+if (prev_row[i - 1].a == prev_row[i].a) {                                  \
+    if (run_index != i && i > 2 && cur_row[i - 1].a == cur_row[i - 2].a) { \
+        goto do_run;                                                       \
+    }                                                                      \
+}
+#else
+#define RLE_PRED_2_IMP
+#endif
+
+#ifdef RLE_PRED_3
+#define RLE_PRED_3_IMP                                                  \
+if (i > 1 && cur_row[i - 1].a == cur_row[i - 2].a && i != run_index) {  \
+    goto do_run;                                                        \
+}
+#else
+#define RLE_PRED_3_IMP
+#endif
+
+/*  a  */
+static INLINE BYTE FNAME(decorelate_0)(const PIXEL * const curr, const unsigned int bpc_mask)
+{
+    return family.xlatU2L[(unsigned)((int)curr[0].a - (int)_PIXEL_A) & bpc_mask];
+}
+
+static INLINE void FNAME(corelate_0)(PIXEL *curr, const BYTE corelate,
+                                     const unsigned int bpc_mask)
+{
+    curr->a = (family.xlatL2U[corelate] + _PIXEL_A) & bpc_mask;
+}
+
+#ifdef PRED_1
+
+/*  (a+b)/2  */
+static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
+                                     const unsigned int bpc_mask)
+{
+    return family.xlatU2L[(unsigned)((int)curr->a - (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask];
+}
+
+
+static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
+                                   const unsigned int bpc_mask)
+{
+    curr->a = (family.xlatL2U[corelate] + (int)((_PIXEL_A + _PIXEL_B) >> 1)) & bpc_mask;
+}
+
+#endif
+
+#ifdef PRED_2
+
+/*  .75a+.75b-.5c  */
+static INLINE BYTE FNAME(decorelate)(const PIXEL *const prev, const PIXEL * const curr,
+                                     const unsigned int bpc_mask)
+{
+    int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
+
+    if (p < 0) {
+        p = 0;
+    } else if ((unsigned)p > bpc_mask) {
+        p = bpc_mask;
+    }
+
+    {
+        return family.xlatU2L[(unsigned)((int)curr->a - p) & bpc_mask];
+    }
+}
+
+static INLINE void FNAME(corelate)(const PIXEL *prev, PIXEL *curr, const BYTE corelate,
+                                   const unsigned int bpc_mask)
+{
+    const int p = ((int)(3 * (_PIXEL_A + _PIXEL_B)) - (int)(_PIXEL_C << 1)) >> 2;
+    const unsigned int s = family.xlatL2U[corelate];
+
+    if (!(p & ~bpc_mask)) {
+        curr->a = (s + (unsigned)p) & bpc_mask;
+    } else if (p < 0) {
+        curr->a = s;
+    } else {
+        curr->a = (s + bpc_mask) & bpc_mask;
+    }
+}
+
+#endif
+
+static void FNAME(compress_row0_seg)(Encoder *encoder, Channel *channel, int i,
+                                     const PIXEL * const cur_row,
+                                     const int end,
+                                     const unsigned int waitmask,
+                                     const unsigned int bpc,
+                                     const unsigned int bpc_mask)
+{
+    BYTE * const decorelate_drow = channel->correlate_row;
+    int stopidx;
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (i == 0) {
+        unsigned int codeword, codewordlen;
+
+        decorelate_drow[0] = family.xlatU2L[cur_row->a];
+        golomb_coding(decorelate_drow[0], find_bucket(channel, decorelate_drow[-1])->bestcode,
+                      &codeword, &codewordlen);
+        encode(encoder, codeword, codewordlen);
+
+        if (channel->state.waitcnt) {
+            channel->state.waitcnt--;
+        } else {
+            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
+            update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
+                         decorelate_drow[i], bpc);
+        }
+        stopidx = ++i + channel->state.waitcnt;
+    } else {
+        stopidx = i + channel->state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        for (; i <= stopidx; i++) {
+            unsigned int codeword, codewordlen;
+            decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
+            golomb_coding(decorelate_drow[i],
+                          find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
+                          &codewordlen);
+            encode(encoder, codeword, codewordlen);
+        }
+
+        update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
+                     decorelate_drow[stopidx], bpc);
+        stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
+    }
+
+    for (; i < end; i++) {
+        unsigned int codeword, codewordlen;
+        decorelate_drow[i] = FNAME(decorelate_0)(&cur_row[i], bpc_mask);
+        golomb_coding(decorelate_drow[i], find_bucket(channel, decorelate_drow[i - 1])->bestcode,
+                      &codeword, &codewordlen);
+        encode(encoder, codeword, codewordlen);
+    }
+    channel->state.waitcnt = stopidx - end;
+}
+
+static void FNAME(compress_row0)(Encoder *encoder, Channel *channel, const PIXEL *cur_row,
+                                 unsigned int width)
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    int pos = 0;
+
+    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
+        if (channel->state.wmileft) {
+            FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + channel->state.wmileft,
+                                     bppmask[channel->state.wmidx], bpc, bpc_mask);
+            width -= channel->state.wmileft;
+            pos += channel->state.wmileft;
+        }
+
+        channel->state.wmidx++;
+        set_wm_trigger(&channel->state);
+        channel->state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(compress_row0_seg)(encoder, channel, pos, cur_row, pos + width,
+                                 bppmask[channel->state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)channel->state.wmidx) {
+            channel->state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
+    ASSERT(encoder->usr, channel->state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+static void FNAME(compress_row_seg)(Encoder *encoder, Channel *channel, int i,
+                                    const PIXEL * const prev_row,
+                                    const PIXEL * const cur_row,
+                                    const int end,
+                                    const unsigned int waitmask,
+                                    const unsigned int bpc,
+                                    const unsigned int bpc_mask)
+{
+    BYTE * const decorelate_drow = channel->correlate_row;
+    int stopidx;
+#ifdef RLE
+    int run_index = 0;
+    int run_size;
+#endif
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (!i) {
+        unsigned int codeword, codewordlen;
+
+        decorelate_drow[0] = family.xlatU2L[(unsigned)((int)cur_row->a -
+                                                       (int)prev_row->a) & bpc_mask];
+
+        golomb_coding(decorelate_drow[0],
+                      find_bucket(channel, decorelate_drow[-1])->bestcode,
+                      &codeword,
+                      &codewordlen);
+        encode(encoder, codeword, codewordlen);
+
+        if (channel->state.waitcnt) {
+            channel->state.waitcnt--;
+        } else {
+            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
+            update_model(&channel->state, find_bucket(channel, decorelate_drow[-1]),
+                         decorelate_drow[0], bpc);
+        }
+        stopidx = ++i + channel->state.waitcnt;
+    } else {
+        stopidx = i + channel->state.waitcnt;
+    }
+    for (;;) {
+        while (stopidx < end) {
+            for (; i <= stopidx; i++) {
+                unsigned int codeword, codewordlen;
+#ifdef RLE
+                RLE_PRED_1_IMP;
+                RLE_PRED_2_IMP;
+                RLE_PRED_3_IMP;
+#endif
+                decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
+                golomb_coding(decorelate_drow[i],
+                              find_bucket(channel, decorelate_drow[i - 1])->bestcode, &codeword,
+                              &codewordlen);
+                encode(encoder, codeword, codewordlen);
+            }
+
+            update_model(&channel->state, find_bucket(channel, decorelate_drow[stopidx - 1]),
+                         decorelate_drow[stopidx], bpc);
+            stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
+        }
+
+        for (; i < end; i++) {
+            unsigned int codeword, codewordlen;
+#ifdef RLE
+            RLE_PRED_1_IMP;
+            RLE_PRED_2_IMP;
+            RLE_PRED_3_IMP;
+#endif
+            decorelate_drow[i] = FNAME(decorelate)(&prev_row[i], &cur_row[i], bpc_mask);
+            golomb_coding(decorelate_drow[i], find_bucket(channel,
+                                                          decorelate_drow[i - 1])->bestcode,
+                          &codeword, &codewordlen);
+            encode(encoder, codeword, codewordlen);
+        }
+        channel->state.waitcnt = stopidx - end;
+
+        return;
+
+#ifdef RLE
+do_run:
+        run_index = i;
+        channel->state.waitcnt = stopidx - i;
+        run_size = 0;
+
+        while (cur_row[i].a == cur_row[i - 1].a) {
+            run_size++;
+            if (++i == end) {
+#ifdef RLE_STAT
+                encode_channel_run(encoder, channel, run_size);
+#else
+                encode_run(encoder, run_size);
+#endif
+                return;
+            }
+        }
+#ifdef RLE_STAT
+        encode_channel_run(encoder, channel, run_size);
+#else
+        encode_run(encoder, run_size);
+#endif
+        stopidx = i + channel->state.waitcnt;
+#endif
+    }
+}
+
+static void FNAME(compress_row)(Encoder *encoder, Channel *channel,
+                                const PIXEL * const prev_row,
+                                const PIXEL * const cur_row,
+                                unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
+        if (channel->state.wmileft) {
+            FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row,
+                                    pos + channel->state.wmileft, bppmask[channel->state.wmidx],
+                                    bpc, bpc_mask);
+            width -= channel->state.wmileft;
+            pos += channel->state.wmileft;
+        }
+
+        channel->state.wmidx++;
+        set_wm_trigger(&channel->state);
+        channel->state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(compress_row_seg)(encoder, channel, pos, prev_row, cur_row, pos + width,
+                                bppmask[channel->state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)channel->state.wmidx) {
+            channel->state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
+    ASSERT(encoder->usr, channel->state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+static void FNAME(uncompress_row0_seg)(Encoder *encoder, Channel *channel, int i,
+                                       BYTE * const correlate_row,
+                                       PIXEL * const cur_row,
+                                       const int end,
+                                       const unsigned int waitmask,
+                                       const unsigned int bpc,
+                                       const unsigned int bpc_mask)
+{
+    int stopidx;
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (i == 0) {
+        unsigned int codewordlen;
+
+        correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel,
+                                                             correlate_row[-1])->bestcode,
+                                                 encoder->io_word, &codewordlen);
+        cur_row[0].a = (BYTE)family.xlatL2U[correlate_row[0]];
+        decode_eatbits(encoder, codewordlen);
+
+        if (channel->state.waitcnt) {
+            --channel->state.waitcnt;
+        } else {
+            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
+            update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
+                         correlate_row[0], bpc);
+        }
+        stopidx = ++i + channel->state.waitcnt;
+    } else {
+        stopidx = i + channel->state.waitcnt;
+    }
+
+    while (stopidx < end) {
+        struct s_bucket * pbucket = NULL;
+
+        for (; i <= stopidx; i++) {
+            unsigned int codewordlen;
+
+            pbucket = find_bucket(channel, correlate_row[i - 1]);
+            correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
+                                                     &codewordlen);
+            FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
+            decode_eatbits(encoder, codewordlen);
+        }
+
+        update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
+
+        stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
+    }
+
+    for (; i < end; i++) {
+        unsigned int codewordlen;
+
+        correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
+                                                             correlate_row[i - 1])->bestcode,
+                                                 encoder->io_word, &codewordlen);
+        FNAME(corelate_0)(&cur_row[i], correlate_row[i], bpc_mask);
+        decode_eatbits(encoder, codewordlen);
+    }
+    channel->state.waitcnt = stopidx - end;
+}
+
+static void FNAME(uncompress_row0)(Encoder *encoder, Channel *channel,
+                                   PIXEL * const cur_row,
+                                   unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    BYTE * const correlate_row = channel->correlate_row;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
+        if (channel->state.wmileft) {
+            FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row,
+                                       pos + channel->state.wmileft, bppmask[channel->state.wmidx],
+                                       bpc, bpc_mask);
+            pos += channel->state.wmileft;
+            width -= channel->state.wmileft;
+        }
+
+        channel->state.wmidx++;
+        set_wm_trigger(&channel->state);
+        channel->state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(uncompress_row0_seg)(encoder, channel, pos, correlate_row, cur_row, pos + width,
+                                   bppmask[channel->state.wmidx], bpc, bpc_mask);
+        if (wmimax > (int)channel->state.wmidx) {
+            channel->state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
+    ASSERT(encoder->usr, channel->state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+static void FNAME(uncompress_row_seg)(Encoder *encoder, Channel *channel,
+                                      BYTE *correlate_row,
+                                      const PIXEL * const prev_row,
+                                      PIXEL * const cur_row,
+                                      int i,
+                                      const int end,
+                                      const unsigned int bpc,
+                                      const unsigned int bpc_mask)
+{
+    const unsigned int waitmask = bppmask[channel->state.wmidx];
+    int stopidx;
+#ifdef RLE
+    int run_index = 0;
+    int run_end;
+#endif
+
+    ASSERT(encoder->usr, end - i > 0);
+
+    if (i == 0) {
+        unsigned int codewordlen;
+
+        correlate_row[0] = (BYTE)golomb_decoding(find_bucket(channel, correlate_row[-1])->bestcode,
+                                                             encoder->io_word, &codewordlen);
+        cur_row[0].a = (family.xlatL2U[correlate_row[0]] + prev_row[0].a) & bpc_mask;
+        decode_eatbits(encoder, codewordlen);
+
+        if (channel->state.waitcnt) {
+            --channel->state.waitcnt;
+        } else {
+            channel->state.waitcnt = (tabrand(&channel->state.tabrand_seed) & waitmask);
+            update_model(&channel->state, find_bucket(channel, correlate_row[-1]),
+                         correlate_row[0], bpc);
+        }
+        stopidx = ++i + channel->state.waitcnt;
+    } else {
+        stopidx = i + channel->state.waitcnt;
+    }
+    for (;;) {
+        while (stopidx < end) {
+            struct s_bucket * pbucket = NULL;
+
+            for (; i <= stopidx; i++) {
+                unsigned int codewordlen;
+#ifdef RLE
+                RLE_PRED_1_IMP;
+                RLE_PRED_2_IMP;
+                RLE_PRED_3_IMP;
+#endif
+                pbucket = find_bucket(channel, correlate_row[i - 1]);
+                correlate_row[i] = (BYTE)golomb_decoding(pbucket->bestcode, encoder->io_word,
+                                                         &codewordlen);
+                FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
+                decode_eatbits(encoder, codewordlen);
+            }
+
+            update_model(&channel->state, pbucket, correlate_row[stopidx], bpc);
+
+            stopidx = i + (tabrand(&channel->state.tabrand_seed) & waitmask);
+        }
+
+        for (; i < end; i++) {
+            unsigned int codewordlen;
+#ifdef RLE
+            RLE_PRED_1_IMP;
+            RLE_PRED_2_IMP;
+            RLE_PRED_3_IMP;
+#endif
+            correlate_row[i] = (BYTE)golomb_decoding(find_bucket(channel,
+                                                                 correlate_row[i - 1])->bestcode,
+                                                     encoder->io_word, &codewordlen);
+            FNAME(corelate)(&prev_row[i], &cur_row[i], correlate_row[i], bpc_mask);
+            decode_eatbits(encoder, codewordlen);
+        }
+
+        channel->state.waitcnt = stopidx - end;
+
+        return;
+
+#ifdef RLE
+do_run:
+        channel->state.waitcnt = stopidx - i;
+        run_index = i;
+#ifdef RLE_STAT
+        run_end = i + decode_channel_run(encoder, channel);
+#else
+        run_end = i + decode_run(encoder);
+#endif
+
+        for (; i < run_end; i++) {
+            cur_row[i].a = cur_row[i - 1].a;
+        }
+
+        if (i == end) {
+            return;
+        }
+
+        stopidx = i + channel->state.waitcnt;
+#endif
+    }
+}
+
+static void FNAME(uncompress_row)(Encoder *encoder, Channel *channel,
+                                  const PIXEL * const prev_row,
+                                  PIXEL * const cur_row,
+                                  unsigned int width)
+
+{
+    const unsigned int bpc = BPC;
+    const unsigned int bpc_mask = BPC_MASK;
+    BYTE * const correlate_row = channel->correlate_row;
+    unsigned int pos = 0;
+
+    while ((wmimax > (int)channel->state.wmidx) && (channel->state.wmileft <= width)) {
+        if (channel->state.wmileft) {
+            FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
+                                      pos + channel->state.wmileft, bpc, bpc_mask);
+            pos += channel->state.wmileft;
+            width -= channel->state.wmileft;
+        }
+
+        channel->state.wmidx++;
+        set_wm_trigger(&channel->state);
+        channel->state.wmileft = wminext;
+    }
+
+    if (width) {
+        FNAME(uncompress_row_seg)(encoder, channel, correlate_row, prev_row, cur_row, pos,
+                                  pos + width, bpc, bpc_mask);
+        if (wmimax > (int)channel->state.wmidx) {
+            channel->state.wmileft -= width;
+        }
+    }
+
+    ASSERT(encoder->usr, (int)channel->state.wmidx <= wmimax);
+    ASSERT(encoder->usr, channel->state.wmidx <= 32);
+    ASSERT(encoder->usr, wminext > 0);
+}
+
+#undef PIXEL
+#undef FNAME
+#undef _PIXEL_A
+#undef _PIXEL_B
+#undef _PIXEL_C
+#undef RLE_PRED_1_IMP
+#undef RLE_PRED_2_IMP
+#undef RLE_PRED_3_IMP
+#undef golomb_coding
+#undef golomb_deoding
+#undef update_model
+#undef find_bucket
+#undef family
+#undef BPC
+#undef BPC_MASK
+
diff --git a/xddm/display/qxldd.h b/xddm/display/qxldd.h
new file mode 100644
index 0000000..1a1b5d5
--- /dev/null
+++ b/xddm/display/qxldd.h
@@ -0,0 +1,548 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _H_QXLDD
+#define _H_QXLDD
+
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "ioaccess.h"
+#include "qxl_driver.h"
+#include "mspace.h"
+#if (WINVER < 0x0501)
+#include "wdmhelper.h"
+#endif
+
+#define ALLOC_TAG 'dlxq'
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+#define DEBUG_PRINT(arg) DebugPrint arg
+
+#ifdef DBG
+#define ASSERT(pdev, x) if (!(x)) { \
+    DebugPrint(pdev, 0, "ASSERT(%s) failed @ %s\n", #x, __FUNCTION__); \
+    EngDebugBreak();\
+}
+#define ONDBG(x) x
+#else
+#define ASSERT(pdev, x)
+#define ONDBG(x)
+#endif
+
+#define PANIC(pdev, str) {                                      \
+    DebugPrint(pdev, 0, "PANIC: %s @ %s\n", str, __FUNCTION__); \
+    EngDebugBreak();                                            \
+}
+
+#define PUNT_IF_DISABLED(pdev) \
+    do { \
+        if (!pdev->enabled) { \
+            DEBUG_PRINT((pdev, 0, "%s: punting\n", __FUNCTION__)); \
+            return FALSE; \
+        } \
+    } while (0)
+
+typedef enum {
+    QXL_SUCCESS,
+    QXL_FAILED,
+    QXL_UNSUPPORTED,
+} QXLRESULT;
+
+typedef struct Ring RingItem;
+typedef struct Ring {
+    RingItem *prev;
+    RingItem *next;
+} Ring;
+
+#define IMAGE_HASH_SHIFT 15
+#define IMAGE_HASH_SIZE (1 << IMAGE_HASH_SHIFT)
+#define IMAGE_HASH_MASK (IMAGE_HASH_SIZE - 1)
+
+#define IMAGE_POOL_SIZE (1 << 15)
+
+#define CURSOR_CACHE_SIZE (1 << 6)
+#define CURSOR_HASH_SIZE (CURSOR_CACHE_SIZE << 1)
+#define CURSOR_HASH_NASKE (CURSOR_HASH_SIZE - 1)
+
+#define PALETTE_CACHE_SIZE (1 << 6)
+#define PALETTE_HASH_SIZE (PALETTE_CACHE_SIZE << 1)
+#define PALETTE_HASH_NASKE (PALETTE_HASH_SIZE - 1)
+
+//#define CALL_TEST
+
+#ifdef CALL_TEST
+enum {
+    CALL_COUNTER_COPY_BITS,
+    CALL_COUNTER_BIT_BLT,
+    CALL_COUNTER_TEXT_OUT,
+    CALL_COUNTER_STROKE_PATH,
+    CALL_COUNTER_STRETCH_BLT,
+    CALL_COUNTER_STRETCH_BLT_ROP,
+    CALL_COUNTER_TRANSPARENT_BLT,
+    CALL_COUNTER_ALPHA_BLEND,
+
+    CALL_COUNTER_FILL_PATH,
+    CALL_COUNTER_GRADIENT_FILL,
+    CALL_COUNTER_LINE_TO,
+    CALL_COUNTER_PLG_BLT,
+    CALL_COUNTER_STROKE_AND_FILL_PATH,
+
+    NUM_CALL_COUNTERS,
+};
+#endif
+
+typedef struct QuicData QuicData;
+
+#define IMAGE_KEY_HASH_SIZE (1 << 15)
+#define IMAGE_KEY_HASH_MASK (IMAGE_KEY_HASH_SIZE - 1)
+
+typedef struct ImageKey {
+    HSURF hsurf;
+    UINT64 unique;
+    UINT32 key;
+} ImageKey;
+
+typedef struct CacheImage {
+    struct CacheImage *next;
+    RingItem lru_link;
+    UINT32 key;
+    UINT32 hits;
+    UINT8 format;
+    UINT32 width;
+    UINT32 height;
+    struct InternalImage *image;
+} CacheImage;
+
+#define NUM_UPDATE_TRACE_ITEMS 10
+typedef struct UpdateTrace {
+    RingItem link;
+    UINT32 last_time;
+    RECTL area;
+    HSURF hsurf;
+    UINT8 count;
+} UpdateTrace;
+
+typedef struct PMemSlot {
+    MemSlot slot;
+    QXLPHYSICAL high_bits;
+} PMemSlot;
+
+typedef struct MspaceInfo {
+    mspace _mspace;
+    UINT8 *mspace_start;
+    UINT8 *mspace_end;
+} MspaceInfo;
+
+enum {
+    MSPACE_TYPE_DEVRAM,
+    MSPACE_TYPE_VRAM,
+
+    NUM_MSPACES,
+};
+
+enum {
+    SYNC = 0,
+    ASYNC = 1
+};
+
+typedef enum {
+    ASYNCABLE_UPDATE_AREA = 0,
+    ASYNCABLE_MEMSLOT_ADD,
+    ASYNCABLE_CREATE_PRIMARY,
+    ASYNCABLE_DESTROY_PRIMARY,
+    ASYNCABLE_DESTROY_SURFACE,
+    ASYNCABLE_DESTROY_ALL_SURFACES,
+    ASYNCABLE_FLUSH_SURFACES,
+
+    ASYNCABLE_COUNT
+} asyncable_t;
+
+
+typedef struct PDev PDev;
+
+typedef struct DrawArea {
+   HSURF bitmap;
+   SURFOBJ* surf_obj;
+   UINT8 *base_mem;
+} DrawArea;
+
+typedef struct SurfaceInfo SurfaceInfo;
+struct SurfaceInfo {
+    DrawArea    draw_area;
+    HBITMAP     hbitmap;
+    SIZEL       size;
+    UINT8      *copy;
+    ULONG       bitmap_format;
+    INT32       stride;
+    union {
+        PDev *pdev;
+        SurfaceInfo *next_free;
+    } u;
+};
+
+#define SSE_MASK 15
+#define SSE_ALIGN 16
+
+typedef struct PDev {
+    HANDLE driver;
+    HDEV eng;
+    HPALETTE palette;
+    HSURF surf;
+    UINT8 surf_enable;
+    DWORD video_mode_index;
+    SIZEL resolution;
+    UINT32 max_bitmap_size;
+    ULONG bitmap_format;
+    UINT8 create_non_primary_surfaces;
+
+    ULONG fb_size;
+    BYTE* fb;
+    UINT64 fb_phys;
+    UINT8 vram_slot_initialized;
+    UINT8 vram_mem_slot;
+
+    ULONG stride;
+    FLONG red_mask;
+    FLONG green_mask;
+    FLONG blue_mask;
+    ULONG fp_state_size;
+
+    QXLPHYSICAL surf_phys;
+    UINT8 *surf_base;
+
+    QuicData *quic_data;
+    HSEMAPHORE quic_data_sem;
+
+    QXLCommandRing *cmd_ring;
+    QXLCursorRing *cursor_ring;
+    QXLReleaseRing *release_ring;
+    PUCHAR notify_cmd_port;
+    PUCHAR notify_cursor_port;
+    PUCHAR notify_oom_port;
+    PEVENT display_event;
+    PEVENT cursor_event;
+    PEVENT sleep_event;
+    PEVENT io_cmd_event;
+
+    PUCHAR log_port;
+    UINT8 *log_buf;
+    UINT32 *log_level;
+
+    PMemSlot *mem_slots;
+    UINT8 num_mem_slot;
+    UINT8 main_mem_slot;
+    UINT8 slot_id_bits;
+    UINT8 slot_gen_bits;
+    UINT8 *slots_generation;
+    UINT64 *ram_slot_start;
+    UINT64 *ram_slot_end;
+    QXLPHYSICAL va_slot_mask;
+
+    UINT32 num_io_pages;
+    UINT8 *io_pages_virt;
+    UINT64 io_pages_phys;
+
+    UINT32 *dev_update_id;
+
+    QXLRect *update_area;
+    UINT32 *update_surface;
+
+    UINT32 *mm_clock;
+
+    UINT32 *compression_level;
+
+    FLONG cursor_trail;
+
+#if (WINVER < 0x0501)
+    PQXLWaitForEvent WaitForEvent;
+#endif
+
+    PUCHAR asyncable[ASYNCABLE_COUNT][2];
+    HSEMAPHORE io_sem;
+    PUCHAR memslot_del_port;
+    PUCHAR flush_release_port;
+    UINT32 use_async;
+
+    UINT8* primary_memory_start;
+    UINT32 primary_memory_size;
+
+    QXLSurfaceCreate *primary_surface_create;
+
+    UINT32 dev_id;
+
+    Ring update_trace;
+    UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
+
+    UINT64 free_outputs;
+
+    MspaceInfo mspaces[NUM_MSPACES];
+
+    /*
+     * TODO: reconsider semaphores according to
+     * http://msdn.microsoft.com/en-us/library/ff568281%28v=vs.85%29.aspx
+     * 1) In order to protect the device log buffer,
+     *     the print_sem must be shared between different pdevs and
+     *     different display sessions.
+     * 2) malloc_sem: not sure what it protects. Maybe globals in mspace?
+     *    since only the enabled pdev is allocating memory, I don't
+     *    think it is required (unless it is possible to have
+     *    AssertMode(x, enable) before AssertMode(y, disable).
+     * 3) cmd_sem, cursor_sem: again, since only the enabled pdev touches the cmd rings
+     *    I don't think it is required.
+     * 4) io_sem - same as print sem. Note that we should prevent starvation between
+     *    print_sem and io_sem in DebugPrintV.
+     *
+     */
+    HSEMAPHORE malloc_sem; /* Also protects release ring */
+    HSEMAPHORE print_sem;
+    HSEMAPHORE cmd_sem;
+    HSEMAPHORE cursor_sem; /* Protects cursor_ring */
+
+    CacheImage cache_image_pool[IMAGE_POOL_SIZE];
+    Ring cache_image_lru;
+    Ring cursors_lru;
+    Ring palette_lru;
+    ImageKey image_key_lookup[IMAGE_KEY_HASH_SIZE];
+    struct CacheImage *image_cache[IMAGE_HASH_SIZE];
+    struct InternalCursor *cursor_cache[CURSOR_HASH_SIZE];
+    UINT32 num_cursors;
+    UINT32 last_cursor_id;
+    struct InternalPalette *palette_cache[PALETTE_HASH_SIZE];
+    UINT32 num_palettes;
+
+    UINT32 n_surfaces;
+    SurfaceInfo surface0_info;
+    SurfaceInfo *surfaces_info;
+    SurfaceInfo *free_surfaces;
+
+    UINT32 update_id;
+
+    UINT32 enabled; /* 1 between DrvAssertMode(TRUE) and DrvAssertMode(FALSE) */
+
+
+    UCHAR  pci_revision;
+
+#ifdef DBG
+    int num_free_pages;
+    int num_outputs;
+    int num_path_pages;
+    int num_rects_pages;
+    int num_bits_pages;
+    int num_buf_pages;
+    int num_glyphs_pages;
+    int num_cursor_pages;
+#endif
+
+#ifdef CALL_TEST
+    BOOL count_calls;
+    UINT32 total_calls;
+    UINT32 call_counters[NUM_CALL_COUNTERS];
+#endif
+} PDev;
+
+
+void DebugPrintV(PDev *pdev, const char *message, va_list ap);
+void DebugPrint(PDev *pdev, int level, const char *message, ...);
+
+void InitResources(PDev *pdev);
+void ClearResources(PDev *pdev);
+
+#ifdef CALL_TEST
+void CountCall(PDev *pdev, int counter);
+#else
+#define CountCall(a, b)
+#endif
+
+char *BitmapFormatToStr(int format);
+char *BitmapTypeToStr(int type);
+
+static _inline void RingInit(Ring *ring)
+{
+    ring->next = ring->prev = ring;
+}
+
+static _inline void RingItemInit(RingItem *item)
+{
+    item->next = item->prev = NULL;
+}
+
+static _inline BOOL RingItemIsLinked(RingItem *item)
+{
+    return !!item->next;
+}
+
+static _inline BOOL RingIsEmpty(PDev *pdev, Ring *ring)
+{
+    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
+    return ring == ring->next;
+}
+
+static _inline void RingAdd(PDev *pdev, Ring *ring, RingItem *item)
+{
+    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
+    ASSERT(pdev, item->next == NULL && item->prev == NULL);
+
+    item->next = ring->next;
+    item->prev = ring;
+    ring->next = item->next->prev = item;
+}
+
+static _inline void RingRemove(PDev *pdev, RingItem *item)
+{
+    ASSERT(pdev, item->next != NULL && item->prev != NULL);
+    ASSERT(pdev, item->next != item);
+
+    item->next->prev = item->prev;
+    item->prev->next = item->next;
+    item->prev = item->next = 0;
+}
+
+static _inline RingItem *RingGetTail(PDev *pdev, Ring *ring)
+{
+    RingItem *ret;
+
+    ASSERT(pdev, ring->next != NULL && ring->prev != NULL);
+
+    if (RingIsEmpty(pdev, ring)) {
+        return NULL;
+    }
+    ret = ring->prev;
+    return ret;
+}
+
+#if (WINVER < 0x0501)
+#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
+#else
+#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
+#endif
+
+/* Helpers for dealing with ENG_TIME_FIELDS */
+static _inline ULONG64 eng_time_diff_ms(ENG_TIME_FIELDS *b, ENG_TIME_FIELDS *a)
+{
+    ULONG64 ret = 0;
+
+    ret += b->usMilliseconds - a->usMilliseconds;
+    ret += 1000 * (b->usSecond - a->usSecond);
+    ret += 60000 * (b->usMinute - a->usMinute);
+    ret += 3600000L * (b->usHour - a->usHour);
+    // don't get into gregorian calendar, just ignore more then a single day difference
+    if (b->usDay != a->usDay) {
+        ret += (3600L * 24L * 1000L);
+    }
+    return ret;
+}
+
+#define INTERRUPT_NOT_PRESENT_TIMEOUT_MS 60000L
+#define INTERRUPT_NOT_PRESENT_TIMEOUT_100NS (INTERRUPT_NOT_PRESENT_TIMEOUT_MS * 10000L)
+
+/* Write to an ioport. For some operations we support a new port that returns
+ * immediatly, and completion is signaled by an interrupt that sets io_cmd_event.
+ * If the pci_revision is >= QXL_REVISION_STABLE_V10, we support it, else do
+ * a regular ioport write.
+ */
+static _inline void async_io(PDev *pdev, asyncable_t op, UCHAR val)
+{
+    ENG_TIME_FIELDS start, finish;
+    LARGE_INTEGER timeout;                      // 1 => 100 nanoseconds
+    ULONG64 millis;
+
+    if (pdev->use_async) {
+        EngAcquireSemaphore(pdev->io_sem);
+        WRITE_PORT_UCHAR(pdev->asyncable[op][ASYNC], val);
+        /* Our Interrupt may be taken from us unexpectedly, by a surprise removal.
+         * in which case this event will never be set. This happens only during WHQL
+         * tests (pnpdtest /surprise). So instead: Wait on a timer, if we fail, stop waiting, until
+         * we get reset. We use EngQueryLocalTime because there is no way to differentiate a return on
+         * timeout from a return on event set otherwise. */
+        timeout.QuadPart = -INTERRUPT_NOT_PRESENT_TIMEOUT_100NS; // negative  => relative
+        DEBUG_PRINT((pdev, 15, "WAIT_FOR_EVENT %d\n", (int)op));
+        EngQueryLocalTime(&start);
+        WAIT_FOR_EVENT(pdev, pdev->io_cmd_event, &timeout);
+        EngQueryLocalTime(&finish);
+        millis = eng_time_diff_ms(&finish, &start);
+        if (millis >= INTERRUPT_NOT_PRESENT_TIMEOUT_MS) {
+            pdev->use_async = 0;
+            DEBUG_PRINT((pdev, 0, "%s: timeout reached, disabling async io!\n", __FUNCTION__));
+        }
+        EngReleaseSemaphore(pdev->io_sem);
+        DEBUG_PRINT((pdev, 3, "finished async %d\n", (int)op));
+    } else {
+        if (pdev->asyncable[op][SYNC] == NULL) {
+            DEBUG_PRINT((pdev, 0, "ERROR: trying calling sync io on NULL port %d\n", op));
+        } else {
+            EngAcquireSemaphore(pdev->io_sem);
+            WRITE_PORT_UCHAR(pdev->asyncable[op][SYNC], val);
+            EngReleaseSemaphore(pdev->io_sem);
+        }
+    }
+}
+
+/*
+ * Before the introduction of QXL_IO_*_ASYNC all io writes would return
+ * only when their function was complete. Since qemu would only allow
+ * a single outstanding io operation between all vcpu threads, they were
+ * also protected from simultaneous calls between different vcpus.
+ *
+ * With the introduction of _ASYNC we need to explicitly lock between different
+ * threads running on different vcpus, this is what this helper accomplishes.
+ */
+static _inline void sync_io(PDev *pdev, PUCHAR port, UCHAR val)
+{
+    EngAcquireSemaphore(pdev->io_sem);
+    WRITE_PORT_UCHAR(port, val);
+    EngReleaseSemaphore(pdev->io_sem);
+}
+
+#ifdef DBG
+#define DUMP_VRAM_MSPACE(pdev) \
+    do { \
+        DEBUG_PRINT((pdev, 0, "%s: dumping mspace vram (%p)\n", __FUNCTION__, pdev)); \
+        if (pdev) {  \
+            mspace_malloc_stats(pdev->mspaces[MSPACE_TYPE_VRAM]._mspace); \
+        } else { \
+            DEBUG_PRINT((pdev, 0, "nothing\n")); \
+        }\
+    } while (0)
+
+#define DUMP_DEVRAM_MSPACE(pdev) \
+    do { \
+        DEBUG_PRINT((pdev, 0, "%s: dumping mspace devram (%p)\n", __FUNCTION__, pdev)); \
+        if (pdev) {  \
+            mspace_malloc_stats(pdev->mspaces[MSPACE_TYPE_DEVRAM]._mspace); \
+        } else { \
+            DEBUG_PRINT((pdev, 0, "nothing\n")); \
+        }\
+    } while (0)
+#else
+#define DUMP_VRAM_MSPACE
+#define DUMP_DEVRAM_MSPACE
+#endif
+
+#endif
diff --git a/xddm/display/res.c b/xddm/display/res.c
new file mode 100644
index 0000000..e494271
--- /dev/null
+++ b/xddm/display/res.c
@@ -0,0 +1,3387 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifdef DBG
+#include <stdio.h>
+#endif
+#include <ddraw.h>
+#include <dxmini.h>
+#include "qxldd.h"
+#include "os_dep.h"
+#include "res.h"
+#include "utils.h"
+#include "mspace.h"
+#include "quic.h"
+#include "murmur_hash2a.h"
+#include "surface.h"
+#include "rop.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+static _inline QXLPHYSICAL PA(PDev *pdev, PVOID virt, UINT8 slot_id)
+{
+    PMemSlot *p_slot = &pdev->mem_slots[slot_id];
+
+    return p_slot->high_bits | ((UINT64)virt - p_slot->slot.start_virt_addr);
+}
+
+static _inline UINT64 VA(PDev *pdev, QXLPHYSICAL paddr, UINT8 slot_id)
+{
+    UINT64 virt;
+    PMemSlot *p_slot = &pdev->mem_slots[slot_id];
+
+    ASSERT(pdev, (paddr >> (64 - pdev->slot_id_bits)) == slot_id);
+    ASSERT(pdev, ((paddr << pdev->slot_id_bits) >> (64 - pdev->slot_gen_bits)) ==
+           p_slot->slot.generation);
+
+    virt = paddr & pdev->va_slot_mask;
+    virt += p_slot->slot.start_virt_addr;;
+
+    return virt;
+}
+
+#define RELEASE_RES(pdev, res) if (!--(res)->refs) (res)->free(pdev, res);
+#define GET_RES(res) (++(res)->refs)
+
+/* Debug helpers - tag each resource with this enum */
+enum {
+    RESOURCE_TYPE_DRAWABLE = 1,
+    RESOURCE_TYPE_SURFACE,
+    RESOURCE_TYPE_PATH,
+    RESOURCE_TYPE_CLIP_RECTS,
+    RESOURCE_TYPE_QUIC_IMAGE,
+    RESOURCE_TYPE_BITMAP_IMAGE,
+    RESOURCE_TYPE_SURFACE_IMAGE,
+    RESOURCE_TYPE_SRING,
+    RESOURCE_TYPE_CURSOR,
+    RESOURCE_TYPE_BUF,
+    RESOURCE_TYPE_UPDATE,
+};
+
+#ifdef DBG
+#define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
+#else
+#define RESOURCE_TYPE(res, val)
+#endif
+
+typedef struct Resource Resource;
+struct Resource {
+    UINT32 refs;
+#ifdef DBG
+    UINT32 type;
+#endif
+    void (*free)(PDev *pdev, Resource *res);
+    UINT8 res[0];
+};
+
+static void FreeMem(PDev* pdev, UINT32 mspace_type, void *ptr);
+static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
+
+
+#define PUSH_CMD(pdev) do {                             \
+    int notify;                                         \
+    SPICE_RING_PUSH(pdev->cmd_ring, notify);            \
+    if (notify) {                                       \
+        sync_io(pdev, pdev->notify_cmd_port, 0);     \
+    }                                                   \
+} while (0);
+
+#define PUSH_CURSOR_CMD(pdev) do {                      \
+    int notify;                                         \
+    SPICE_RING_PUSH(pdev->cursor_ring, notify);         \
+    if (notify) {                                       \
+        sync_io(pdev, pdev->notify_cursor_port, 0);  \
+    }                                                   \
+} while (0);
+
+
+#define MAX_OUTPUT_RES 6
+
+typedef struct QXLOutput {
+    UINT32 num_res;
+#ifdef DBG
+    UINT32 type;
+#endif
+    Resource *resources[MAX_OUTPUT_RES];
+    UINT8 data[0];
+} QXLOutput;
+
+static int have_sse2 = FALSE;
+
+#ifndef DBG
+static _inline void DebugShowOutput(PDev *pdev, QXLOutput* output)
+{
+}
+#else
+const char* resource_type_to_string(QXLOutput *output, UINT32 type)
+{
+    static char buf[1024];
+
+    switch (type) {
+    case 0: return "UNSET";
+    case RESOURCE_TYPE_DRAWABLE: return "drawable";
+    case RESOURCE_TYPE_SURFACE: {
+        QXLSurfaceCmd *surface_cmd = (QXLSurfaceCmd*)output->data;
+        _snprintf(buf, sizeof(buf) - 1, "surface %u", surface_cmd->surface_id);
+        return buf;
+    }
+    case RESOURCE_TYPE_PATH: return "path";
+    case RESOURCE_TYPE_CLIP_RECTS: return "clip_rects";
+    case RESOURCE_TYPE_QUIC_IMAGE: return "quic_image";
+    case RESOURCE_TYPE_BITMAP_IMAGE: return "bitmap_image";
+    case RESOURCE_TYPE_SURFACE_IMAGE: return "surface_image";
+    case RESOURCE_TYPE_SRING: return "sring";
+    case RESOURCE_TYPE_CURSOR: return "cursor";
+    case RESOURCE_TYPE_BUF: return "buf";
+    case RESOURCE_TYPE_UPDATE: return "update";
+    }
+    return "UNDEFINED";
+}
+
+static void DebugShowOutput(PDev *pdev, QXLOutput* output)
+{
+    UINT32 i;
+
+    DEBUG_PRINT((pdev, 11, "output: %s res %d\n", resource_type_to_string(output, output->type),
+                output->num_res));
+    for (i = 0 ; i < output->num_res ; ++i) {
+        DEBUG_PRINT((pdev, 11, "type %s\n", resource_type_to_string(output,
+            output->resources[i]->type)));
+    }
+}
+#endif
+
+UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id)
+{
+    QXLOutput *output = (QXLOutput *)output_id;
+    Resource **now;
+    Resource **end;
+    UINT64 next;
+
+    ASSERT(pdev, output_id);
+    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+    DebugShowOutput(pdev, output);
+
+    for (now = output->resources, end = now + output->num_res; now < end; now++) {
+        RELEASE_RES(pdev, *now);
+    }
+    next = *(UINT64*)output->data;
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, output);
+    DEBUG_PRINT((pdev, 10, "%s done\n", __FUNCTION__));
+    ONDBG(pdev->num_outputs--); //todo: atomic
+    return next;
+}
+
+static void AddRes(PDev *pdev, QXLOutput *output, Resource *res)
+{
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    ASSERT(pdev, output->num_res < MAX_OUTPUT_RES);
+    res->refs++;
+    output->resources[output->num_res++] = res;
+    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
+}
+
+static _inline void DrawableAddRes(PDev *pdev, QXLDrawable *drawable, Resource *res)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)((UINT8 *)drawable - sizeof(QXLOutput));
+    AddRes(pdev, output, res);
+}
+
+ 
+static _inline void SurfaceAddRes(PDev *pdev, QXLSurfaceCmd *surface, Resource *res)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)((UINT8 *)surface - sizeof(QXLOutput));
+    AddRes(pdev, output, res);
+}
+
+static _inline void CursorCmdAddRes(PDev *pdev, QXLCursorCmd *cmd, Resource *res)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)((UINT8 *)cmd - sizeof(QXLOutput));
+    AddRes(pdev, output, res);
+}
+
+#define SUPPORT_SURPRISE_REMOVE
+
+
+/* Called with cursor_sem held */
+static void WaitForCursorRing(PDev* pdev)
+{
+    int wait;
+
+    DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    for (;;) {
+        SPICE_RING_PROD_WAIT(pdev->cursor_ring, wait);
+
+        if (!wait) {
+            break;
+        }
+#ifdef SUPPORT_SURPRISE_REMOVE
+        {
+            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
+            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
+            WAIT_FOR_EVENT(pdev, pdev->cursor_event, &timeout);
+            if (SPICE_RING_IS_FULL(pdev->cursor_ring)) {
+                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
+            }
+        }
+#else
+        WAIT_FOR_EVENT(pdev, pdev->cursor_event, NULL);
+#endif //SUPPORT_SURPRISE_REMOVE
+    }
+}
+
+/* Called with cmd_sem held */
+static void WaitForCmdRing(PDev* pdev)
+{
+    int wait;
+
+    DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    for (;;) {
+        SPICE_RING_PROD_WAIT(pdev->cmd_ring, wait);
+
+        if (!wait) {
+            break;
+        }
+        DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+#ifdef SUPPORT_SURPRISE_REMOVE
+        {
+            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
+            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
+            WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
+            if (SPICE_RING_IS_FULL(pdev->cmd_ring)) {
+                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
+            }
+        }
+#else
+        WAIT_FOR_EVENT(pdev, pdev->display_event, NULL);
+#endif //SUPPORT_SURPRISE_REMOVE
+    }
+}
+
+static void QXLSleep(PDev* pdev, int msec)
+{
+    LARGE_INTEGER timeout;
+
+    DEBUG_PRINT((pdev, 18, "%s: 0x%lx msec %u\n", __FUNCTION__, pdev, msec));
+    timeout.QuadPart = -msec * 1000 * 10;
+    WAIT_FOR_EVENT(pdev, pdev->sleep_event, &timeout);
+    DEBUG_PRINT((pdev, 19, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+/* Called with malloc_sem held */
+static void WaitForReleaseRing(PDev* pdev)
+{
+    int wait;
+
+    DEBUG_PRINT((pdev, 15, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+    for (;;) {
+        LARGE_INTEGER timeout;
+
+        if (SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+            QXLSleep(pdev, 10);
+            if (!SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+                break;
+            }
+            sync_io(pdev, pdev->notify_oom_port, 0);
+        }
+        SPICE_RING_CONS_WAIT(pdev->release_ring, wait);
+
+        if (!wait) {
+            break;
+        }
+
+        timeout.QuadPart = -30 * 1000 * 10; //30ms
+        WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
+
+        if (SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+#ifdef DBG
+            DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
+            DEBUG_PRINT((pdev, 0,
+                "\tfree %d out %d path %d rect %d bits %d buf %d glyph %d cursor %d\n",
+                         pdev->num_free_pages,
+                         pdev->num_outputs,
+                         pdev->num_path_pages,
+                         pdev->num_rects_pages,
+                         pdev->num_bits_pages,
+                         pdev->num_buf_pages,
+                         pdev->num_glyphs_pages,
+                         pdev->num_cursor_pages));
+#endif
+            //oom
+            sync_io(pdev, pdev->notify_oom_port, 0);
+        }
+    }
+    DEBUG_PRINT((pdev, 16, "%s: 0x%lx, done\n", __FUNCTION__, pdev));
+}
+
+/* Called with malloc_sem held */
+static void FlushReleaseRing(PDev *pdev)
+{
+    UINT64 output;
+    int notify;
+    int num_to_release = 50;
+
+    output = pdev->free_outputs;
+
+    while (1) {
+        while (output != 0) {
+            output = ReleaseOutput(pdev, output);
+            if (--num_to_release == 0) {
+                break;
+            }
+        }
+
+        if (output != 0 ||
+            SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+            break;
+        }
+
+        output = *SPICE_RING_CONS_ITEM(pdev->release_ring);
+        SPICE_RING_POP(pdev->release_ring, notify);
+    }
+
+    pdev->free_outputs = output;
+}
+
+void EmptyReleaseRing(PDev *pdev)
+{
+    int count = 0;
+
+    EngAcquireSemaphore(pdev->malloc_sem);
+    while (pdev->free_outputs || !SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+        FlushReleaseRing(pdev);
+        count++;
+    }
+    EngReleaseSemaphore(pdev->malloc_sem);
+    DEBUG_PRINT((pdev, 3, "%s: complete after %d rounds\n", __FUNCTION__, count));
+}
+
+// todo: separate VRAM releases from DEVRAM releases
+#define AllocMem(pdev, mspace_type, size) __AllocMem(pdev, mspace_type, size, TRUE)
+static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, BOOL force)
+{
+    UINT8 *ptr;
+
+    ASSERT(pdev, pdev && pdev->mspaces[mspace_type]._mspace);
+    DEBUG_PRINT((pdev, 12, "%s: 0x%lx %p(%d) size %u\n", __FUNCTION__, pdev,
+        pdev->mspaces[mspace_type]._mspace,
+        mspace_footprint(pdev->mspaces[mspace_type]._mspace),
+        size));
+#ifdef DBG
+    if (pdev && pdev->log_level && *pdev->log_level > 11) {
+        mspace_malloc_stats(pdev->mspaces[mspace_type]._mspace);
+    }
+#endif
+    EngAcquireSemaphore(pdev->malloc_sem);
+
+    while (1) {
+        /* Release lots of queued resources, before allocating, as we
+           want to release early to minimize fragmentation risks. */
+        FlushReleaseRing(pdev);
+
+        ptr = mspace_malloc(pdev->mspaces[mspace_type]._mspace, size);
+        if (ptr) {
+            break;
+        }
+
+        if (pdev->free_outputs != 0 ||
+            !SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+            /* We have more things to free, try that */
+            continue;
+        }
+
+        if (force) {
+            /* Ask spice to free some stuff */
+            WaitForReleaseRing(pdev);
+        } else {
+            /* Fail */
+            break;
+        }
+    }
+
+    EngReleaseSemaphore(pdev->malloc_sem);
+    ASSERT(pdev, (!ptr && !force) || (ptr >= pdev->mspaces[mspace_type].mspace_start &&
+                                      ptr < pdev->mspaces[mspace_type].mspace_end));
+    DEBUG_PRINT((pdev, 13, "%s: 0x%lx done 0x%x\n", __FUNCTION__, pdev, ptr));
+    return ptr;
+}
+
+static void FreeMem(PDev* pdev, UINT32 mspace_type, void *ptr)
+{
+    ASSERT(pdev, pdev && pdev->mspaces[mspace_type]._mspace);
+#ifdef DBG
+    if (!((UINT8 *)ptr >= pdev->mspaces[mspace_type].mspace_start &&
+                 (UINT8 *)ptr < pdev->mspaces[mspace_type].mspace_end)) {
+        DebugPrint(pdev, 0, "ASSERT failed @ %s, %p not in [%p, %p) (%d)\n", __FUNCTION__,
+            ptr, pdev->mspaces[mspace_type].mspace_start,
+            pdev->mspaces[mspace_type].mspace_end, mspace_type);
+        EngDebugBreak();
+    }
+#endif
+    EngAcquireSemaphore(pdev->malloc_sem);
+    mspace_free(pdev->mspaces[mspace_type]._mspace, ptr);
+    EngReleaseSemaphore(pdev->malloc_sem);
+}
+
+static void InitMspace(PDev *pdev, UINT32 mspace_type, UINT8 *start, size_t capacity)
+{
+    pdev->mspaces[mspace_type]._mspace = create_mspace_with_base(start, capacity, 0, pdev);
+    pdev->mspaces[mspace_type].mspace_start = start;
+    pdev->mspaces[mspace_type].mspace_end = start + capacity;
+}
+
+static void ResetCache(PDev *pdev)
+{
+    int i;
+
+    RtlZeroMemory(pdev->image_key_lookup,
+                  sizeof(pdev->image_key_lookup));
+    RtlZeroMemory(pdev->cache_image_pool,
+                  sizeof(pdev->cache_image_pool));
+    RingInit(&pdev->cache_image_lru);
+    for (i = 0; i < IMAGE_POOL_SIZE; i++) {
+        RingAdd(pdev, &pdev->cache_image_lru,
+                &pdev->cache_image_pool[i].lru_link);
+    }
+
+    RtlZeroMemory(pdev->image_cache, sizeof(pdev->image_cache));
+    RtlZeroMemory(pdev->cursor_cache, sizeof(pdev->cursor_cache));
+    RingInit(&pdev->cursors_lru);
+    pdev->num_cursors = 0;
+    pdev->last_cursor_id = 0;
+
+    RtlZeroMemory(pdev->palette_cache, sizeof(pdev->palette_cache));
+    RingInit(&pdev->palette_lru);
+    pdev->num_palettes = 0;
+}
+
+/* Init anything that resides on the device memory (pci vram and devram bars).
+ * NOTE: TODO better documentation of what is on the guest ram (saved during sleep)
+ * and what is on the pci device bars (bar 0 and 1, devram and vram)
+ */
+void InitDeviceMemoryResources(PDev *pdev)
+{
+    UINT32 i;
+
+    DEBUG_PRINT((pdev, 0, "%s: %d, %d\n", __FUNCTION__, pdev->num_io_pages * PAGE_SIZE,
+                pdev->fb_size));
+    RtlZeroMemory(pdev->update_trace_items, sizeof(pdev->update_trace_items));
+    RingInit(&pdev->update_trace);
+    for (i = 0; i < NUM_UPDATE_TRACE_ITEMS; i++) {
+         RingAdd(pdev, &pdev->update_trace, &pdev->update_trace_items[i].link);
+    }
+    InitMspace(pdev, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
+    InitMspace(pdev, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
+    ResetCache(pdev);
+    pdev->free_outputs = 0;
+}
+
+void InitSurfaces(PDev *pdev)
+{
+    UINT32 i;
+    pdev->surfaces_info = (SurfaceInfo *)EngAllocMem(FL_ZERO_MEMORY,
+                                                     sizeof(SurfaceInfo) * pdev->n_surfaces,
+                                                     ALLOC_TAG);
+    if (!pdev->surfaces_info) {
+        PANIC(pdev, "surfaces_info allocation failed\n");
+    }
+
+    pdev->free_surfaces = &pdev->surfaces_info[1];
+    for (i = 0; i < pdev->n_surfaces - 1; i++) {
+        pdev->surfaces_info[i].u.next_free = &pdev->surfaces_info[i+1];
+    }
+}
+
+void ClearResources(PDev *pdev)
+{
+    if (pdev->surfaces_info) {
+        EngFreeMem(pdev->surfaces_info);
+        pdev->surfaces_info = NULL;
+    }
+
+    if (pdev->malloc_sem) {
+        EngDeleteSemaphore(pdev->malloc_sem);
+        pdev->malloc_sem = NULL;
+    }
+
+    if (pdev->cmd_sem) {
+        EngDeleteSemaphore(pdev->cmd_sem);
+        pdev->cmd_sem = NULL;
+    }
+
+    if (pdev->cursor_sem) {
+        EngDeleteSemaphore(pdev->cursor_sem);
+        pdev->cursor_sem = NULL;
+    }
+
+    if (pdev->print_sem) {
+        EngDeleteSemaphore(pdev->print_sem);
+        pdev->print_sem = NULL;
+    }
+}
+
+void InitResources(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 3, "%s: entry\n", __FUNCTION__));
+
+    InitSurfaces(pdev);
+    InitDeviceMemoryResources(pdev);
+
+    pdev->update_id = *pdev->dev_update_id;
+
+    pdev->malloc_sem = EngCreateSemaphore();
+    if (!pdev->malloc_sem) {
+        PANIC(pdev, "malloc sem creation failed\n");
+    }
+    pdev->cmd_sem = EngCreateSemaphore();
+    if (!pdev->cmd_sem) {
+        PANIC(pdev, "cmd sem creation failed\n");
+    }
+    pdev->cursor_sem = EngCreateSemaphore();
+    if (!pdev->cursor_sem) {
+        PANIC(pdev, "cursor sem creation failed\n");
+    }
+    pdev->print_sem = EngCreateSemaphore();
+    if (!pdev->print_sem) {
+        PANIC(pdev, "print sem creation failed\n");
+    }
+
+    ONDBG(pdev->num_outputs = 0);
+    ONDBG(pdev->num_path_pages = 0);
+    ONDBG(pdev->num_rects_pages = 0);
+    ONDBG(pdev->num_bits_pages = 0);
+    ONDBG(pdev->num_buf_pages = 0);
+    ONDBG(pdev->num_glyphs_pages = 0);
+    ONDBG(pdev->num_cursor_pages = 0);
+
+#ifdef CALL_TEST
+    pdev->count_calls = TRUE;
+    pdev->total_calls = 0;
+    for (i = 0; i < NUM_CALL_COUNTERS; i++) {
+        pdev->call_counters[i] = 0;
+    }
+#endif
+    DEBUG_PRINT((pdev, 1, "%s: exit\n", __FUNCTION__));
+}
+
+static QXLDrawable *GetDrawable(PDev *pdev)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLDrawable));
+    output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_DRAWABLE);
+    ((QXLDrawable *)output->data)->release_info.id = (UINT64)output;
+    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+    ONDBG(pdev->num_outputs++); //todo: atomic
+    return(QXLDrawable *)output->data;
+}
+
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id)
+{
+    QXLDrawable *drawable;
+
+    ASSERT(pdev, pdev && area);
+
+    drawable = GetDrawable(pdev);
+    drawable->surface_id = surface_id;
+    drawable->type = type;
+    drawable->effect = QXL_EFFECT_BLEND;
+    drawable->self_bitmap = 0;
+    drawable->mm_time = *pdev->mm_clock;
+    drawable->surfaces_dest[0] = -1;
+    drawable->surfaces_dest[1] = - 1;
+    drawable->surfaces_dest[2] = -1;
+    CopyRect(&drawable->bbox, area);
+
+    if (!SetClip(pdev, clip, drawable)) {
+        DEBUG_PRINT((pdev, 0, "%s: set clip failed\n", __FUNCTION__));
+        ReleaseOutput(pdev, drawable->release_info.id);
+        drawable = NULL;
+    }
+    return drawable;
+}
+
+void PushDrawable(PDev *pdev, QXLDrawable *drawable)
+{
+    QXLCommand *cmd;
+
+    EngAcquireSemaphore(pdev->cmd_sem);
+    WaitForCmdRing(pdev);
+    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
+    cmd->type = QXL_CMD_DRAW;
+    cmd->data = PA(pdev, drawable, pdev->main_mem_slot);
+    PUSH_CMD(pdev);
+    EngReleaseSemaphore(pdev->cmd_sem);
+}
+
+static QXLSurfaceCmd *GetSurfaceCmd(PDev *pdev)
+{
+    QXLOutput *output;
+
+    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLSurfaceCmd));
+    output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_SURFACE);
+    ((QXLSurfaceCmd *)output->data)->release_info.id = (UINT64)output;
+    DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+    ONDBG(pdev->num_outputs++); //todo: atomic
+    return(QXLSurfaceCmd *)output->data;
+}
+
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id)
+{
+    QXLSurfaceCmd *surface_cmd;
+
+    ASSERT(pdev, pdev);
+
+    surface_cmd = GetSurfaceCmd(pdev);
+    surface_cmd->surface_id = surface_id;
+    surface_cmd->type = type;
+    surface_cmd->flags = 0;
+
+    return surface_cmd;
+}
+
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
+{
+    QXLCommand *cmd;
+
+    EngAcquireSemaphore(pdev->cmd_sem);
+    WaitForCmdRing(pdev);
+    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
+    cmd->type = QXL_CMD_SURFACE;
+    cmd->data = PA(pdev, surface_cmd, pdev->main_mem_slot);
+    PUSH_CMD(pdev);
+    EngReleaseSemaphore(pdev->cmd_sem);
+}
+
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem)
+{
+    return PA(pdev, base_mem, pdev->vram_mem_slot);
+}
+
+_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, INT32 *stride,
+                              UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
+{
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    switch (allocation_type) {
+    case DEVICE_BITMAP_ALLOCATION_TYPE_SURF0:
+        ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
+        *base_mem = pdev->primary_memory_start;
+        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+        *stride = (x * depth / 8 + 3) & ~0x3; /* Pixman requires 4 byte aligned stride */
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+        *stride = x * depth / 8;
+        *stride = ALIGN(*stride, 4);
+        *base_mem = AllocMem(pdev, MSPACE_TYPE_DEVRAM, (*stride) * y);
+        *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
+        *stride = x * depth / 8;
+        *stride = ALIGN(*stride, 4);
+        *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE);
+        *phys_mem = SurfaceToPhysical(pdev, *base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
+        /* used only before suspend to sleep (DrvAssertMode(FALSE)) and then released
+         * and copied back to VRAM */
+        *stride = x * depth / 8;
+        *stride = ALIGN(*stride, 4);
+        *base_mem = EngAllocMem(0 /* don't zero memory, will be copied over in a bit */,
+                                (*stride) * y, ALLOC_TAG);
+        *phys_mem = (QXLPHYSICAL)NULL; /* make sure no one uses it */
+        break;
+    default:
+        PANIC(pdev, "No allocation type");
+    }
+}
+
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
+{
+    GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
+}
+
+void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type)
+{
+    switch (allocation_type) {
+    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
+        FreeMem(pdev, MSPACE_TYPE_VRAM, base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
+        EngFreeMem(base_mem);
+        break;
+    default:
+        PANIC(pdev, "bad allocation type");
+    }
+}
+
+typedef struct InternalDelSurface {
+    UINT32 surface_id;
+    UINT8 allocation_type;
+} InternalDelSurface;
+
+
+static void FreeDelSurface(PDev *pdev, Resource *res)
+{
+    InternalDelSurface *internal;
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    internal = (InternalDelSurface *)res->res;
+    QXLDelSurface(pdev, GetSurfaceInfo(pdev, internal->surface_id)->draw_area.base_mem,
+        internal->allocation_type);
+    FreeSurfaceInfo(pdev, internal->surface_id);
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#define SURFACEDEL_ALLOC_BASE (sizeof(Resource) + sizeof(InternalDelSurface))
+
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type)
+{
+    Resource *surface_res;
+    InternalDelSurface *internal;
+    size_t alloc_size;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    alloc_size = SURFACEDEL_ALLOC_BASE;
+    surface_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
+    
+    surface_res->refs = 1;
+    surface_res->free = FreeDelSurface;
+    RESOURCE_TYPE(surface_res, RESOURCE_TYPE_SURFACE);
+
+    internal = (InternalDelSurface *)surface_res->res;
+    internal->surface_id = surface_id;
+    internal->allocation_type = allocation_type;
+
+    SurfaceAddRes(pdev, surface, surface_res);
+    RELEASE_RES(pdev, surface_res);
+}
+
+static void FreePath(PDev *pdev, Resource *res)
+{
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    chunk_phys = ((QXLPath *)res->res)->chunk.next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_path_pages--);
+    }
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_path_pages--);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#define NEW_DATA_CHUNK(page_counter, size) {                                    \
+    void *ptr = AllocMem(pdev, MSPACE_TYPE_DEVRAM, size + sizeof(QXLDataChunk));                    \
+    ONDBG((*(page_counter))++);                                                 \
+    chunk->next_chunk = PA(pdev, ptr, pdev->main_mem_slot);                     \
+    ((QXLDataChunk *)ptr)->prev_chunk = PA(pdev, chunk, pdev->main_mem_slot);   \
+    chunk = (QXLDataChunk *)ptr;                                                \
+    chunk->data_size = 0;                                                       \
+    chunk->next_chunk = 0;                                                      \
+    now = chunk->data;                                                          \
+    end = now + size;                                                           \
+}
+
+#ifdef DBG
+    #define GetPathCommon __GetPathCommon
+#else
+    #define GetPathCommon(pdev, path, chunk_ptr, now_ptr, end_ptr, data_size, page_counter)\
+        __GetPathCommon(pdev, path, chunk_ptr, now_ptr, end_ptr, data_size, NULL)
+#endif
+
+#define PATH_PREALLOC_PONTS 20
+#define PATH_MAX_ALLOC_PONTS 128
+#define PATH_ALLOC_SIZE (sizeof(Resource) + sizeof(QXLPath) + sizeof(QXLPathSeg) +\
+                         sizeof(POINTFIX) * PATH_PREALLOC_PONTS)
+
+
+static void __GetPathCommon(PDev *pdev, PATHOBJ *path, QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
+                            UINT8 **end_ptr, UINT32 *data_size, int *page_counter)
+{
+    QXLDataChunk *chunk = *chunk_ptr;
+    UINT8 *now = *now_ptr;
+    UINT8 *end = *end_ptr;
+    PATHDATA data;
+    int more;
+
+    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
+    PATHOBJ_vEnumStart(path);
+
+    do {
+        int pt_buf_size;
+        UINT8 *pt_buf;
+        QXLPathSeg *seg;
+
+        more = PATHOBJ_bEnum(path, &data);
+        if (data.count == 0) {
+            break;
+        }
+
+        if (end - now < sizeof(QXLPathSeg)) {
+            size_t alloc_size = MIN(data.count << 3, sizeof(POINTFIX) * PATH_MAX_ALLOC_PONTS);
+            alloc_size += sizeof(QXLPathSeg);
+            NEW_DATA_CHUNK(page_counter, alloc_size);
+        }
+        seg = (QXLPathSeg*)now;
+        seg->flags = data.flags;
+        seg->count = data.count;
+        now = (UINT8 *)seg->points;
+        chunk->data_size += sizeof(*seg);
+        *data_size +=  sizeof(*seg);
+        pt_buf_size = data.count << 3;
+        pt_buf = (UINT8 *)data.pptfx;
+
+        do {
+            int cp_size;
+            if (end == now ) {
+                size_t alloc_size = MIN(pt_buf_size, sizeof(POINTFIX) * PATH_MAX_ALLOC_PONTS);
+                NEW_DATA_CHUNK(page_counter, alloc_size);
+            }
+
+            cp_size = (int)MIN(end - now, pt_buf_size);
+            memcpy(now, pt_buf, cp_size);
+            chunk->data_size += cp_size;
+            *data_size += cp_size;
+            now += cp_size;
+            pt_buf += cp_size;
+            pt_buf_size -= cp_size;
+        } while (pt_buf_size);
+    } while (more);
+
+    *chunk_ptr = chunk;
+    *now_ptr = now;
+    *end_ptr = end;
+    DEBUG_PRINT((pdev, 17, "%s: done\n", __FUNCTION__));
+}
+
+static Resource *__GetPath(PDev *pdev, PATHOBJ *path)
+{
+    Resource *res;
+    QXLPath *qxl_path;
+    QXLDataChunk *chunk;
+    PATHDATA data;
+    UINT8 *now;
+    UINT8 *end;
+    int more;
+
+    ASSERT(pdev, QXL_PATH_BEGIN == PD_BEGINSUBPATH && QXL_PATH_END == PD_ENDSUBPATH &&
+           QXL_PATH_CLOSE == PD_CLOSEFIGURE && QXL_PATH_BEZIER == PD_BEZIERS);
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, PATH_ALLOC_SIZE);
+    ONDBG(pdev->num_path_pages++);
+    res->refs = 1;
+    res->free = FreePath;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_PATH);
+
+    qxl_path = (QXLPath *)res->res;
+    qxl_path->data_size = 0;
+    chunk = &qxl_path->chunk;
+    chunk->data_size = 0;
+    chunk->prev_chunk = 0;
+    chunk->next_chunk = 0;
+
+    now = chunk->data;
+    end = (UINT8 *)res + PATH_ALLOC_SIZE;
+    GetPathCommon(pdev, path, &chunk, &now, &end, &qxl_path->data_size,
+                  &pdev->num_path_pages);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+    return res;
+}
+
+BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path)
+{
+    Resource *path_res;
+    ASSERT(pdev, pdev && drawable && path_phys && path);
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+
+    path_res = __GetPath(pdev, path);
+    *path_phys = PA(pdev, path_res->res, pdev->main_mem_slot);
+    DrawableAddRes(pdev, drawable, path_res);
+    RELEASE_RES(pdev, path_res);
+    return TRUE;
+}
+
+
+static void FreeClipRects(PDev *pdev, Resource *res)
+{
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    chunk_phys = ((QXLClipRects *)res->res)->chunk.next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_rects_pages--);
+    }
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_rects_pages--);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+
+#define RECTS_NUM_PREALLOC 8
+#define RECTS_ALLOC_SIZE (sizeof(Resource) + sizeof(QXLClipRects) + \
+                          sizeof(QXLRect) * RECTS_NUM_PREALLOC)
+#define RECTS_NUM_ALLOC 20
+#define RECTS_CHUNK_ALLOC_SIZE (sizeof(QXLDataChunk) + sizeof(QXLRect) * RECTS_NUM_ALLOC)
+
+static Resource *GetClipRects(PDev *pdev, CLIPOBJ *clip)
+{
+    Resource *res;
+    QXLClipRects *rects;
+    QXLDataChunk *chunk;
+    QXLRect *dest;
+    QXLRect *dest_end;
+    int more;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, RECTS_ALLOC_SIZE);
+    ONDBG(pdev->num_rects_pages++);
+    res->refs = 1;
+    res->free = FreeClipRects;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CLIP_RECTS);
+    rects = (QXLClipRects *)res->res;
+    rects->num_rects = 0;
+
+    chunk = &rects->chunk;
+    chunk->data_size = 0;
+    chunk->prev_chunk = 0;
+    chunk->next_chunk = 0;
+
+    dest = (QXLRect *)chunk->data;
+    dest_end = dest + ((RECTS_ALLOC_SIZE - sizeof(Resource) - sizeof(QXLClipRects)) >> 4);
+
+    CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
+    do {
+        RECTL *now;
+        RECTL *end;
+        struct {
+            ULONG  count;
+            RECTL  rects[20];
+        } buf;
+
+        more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
+        rects->num_rects += buf.count;
+        for (now = buf.rects, end = now + buf.count; now < end; now++, dest++) {
+            if (dest == dest_end) {
+                void *page = AllocMem(pdev, MSPACE_TYPE_DEVRAM, RECTS_CHUNK_ALLOC_SIZE);
+                ONDBG(pdev->num_rects_pages++);
+                chunk->next_chunk = PA(pdev, page, pdev->main_mem_slot);
+                ((QXLDataChunk *)page)->prev_chunk = PA(pdev, chunk, pdev->main_mem_slot);
+                chunk = (QXLDataChunk *)page;
+                chunk->data_size = 0;
+                chunk->next_chunk = 0;
+                dest = (QXLRect *)chunk->data;
+                dest_end = dest + RECTS_NUM_ALLOC;
+            }
+            CopyRect(dest, now);
+            chunk->data_size += sizeof(QXLRect);
+        }
+    } while (more);
+    DEBUG_PRINT((pdev, 13, "%s: done, num_rects %d\n", __FUNCTION__, rects->num_rects));
+    return res;
+}
+
+static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable)
+{
+    Resource *rects_res;
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+
+    if (clip == NULL) {
+        drawable->clip.type = SPICE_CLIP_TYPE_NONE;
+        DEBUG_PRINT((pdev, 10, "%s: QXL_CLIP_TYPE_NONE\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    if (clip->iDComplexity == DC_RECT) {
+        QXLClipRects *rects;
+        rects_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + sizeof(QXLClipRects) +
+                                         sizeof(QXLRect));
+        rects_res->refs = 1;
+        rects_res->free = FreeClipRects;
+        RESOURCE_TYPE(rects_res, RESOURCE_TYPE_CLIP_RECTS);
+        rects = (QXLClipRects *)rects_res->res;
+        rects->num_rects = 1;
+        rects->chunk.data_size = sizeof(QXLRect);
+        rects->chunk.prev_chunk = 0;
+        rects->chunk.next_chunk = 0;
+        CopyRect((QXLRect *)rects->chunk.data, &clip->rclBounds);
+    } else {
+      rects_res = GetClipRects(pdev, clip);
+    }
+
+    DrawableAddRes(pdev, drawable, rects_res);
+    RELEASE_RES(pdev, rects_res);
+    drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
+    drawable->clip.data = PA(pdev, rects_res->res, pdev->main_mem_slot);
+    DEBUG_PRINT((pdev, 10, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+#ifndef _WIN64
+
+static _inline void fast_memcpy_aligment(void *dest, const void *src, size_t len)
+{
+    _asm
+    {
+        mov ecx, len
+        mov esi, src
+        mov edi, dest
+
+        cmp ecx, 128
+        jb try_to_copy64
+ 
+        prefetchnta [esi]
+        copy_128:
+            prefetchnta [esi + 64]
+
+            movdqa xmm0, [esi]
+            movdqa xmm1, [esi + 16]
+            movdqa xmm2, [esi + 32]
+            movdqa xmm3, [esi + 48]
+
+            prefetchnta [esi + 128]
+
+            movntdq [edi], xmm0
+            movntdq [edi + 16], xmm1
+            movntdq [edi + 32], xmm2
+            movntdq [edi + 48], xmm3
+
+            movdqa xmm0, [esi + 64]
+            movdqa xmm1, [esi + 80]
+            movdqa xmm2, [esi + 96]
+            movdqa xmm3, [esi + 112]
+
+            movntdq [edi + 64], xmm0
+            movntdq [edi + 80], xmm1
+            movntdq [edi + 96], xmm2
+            movntdq [edi + 112], xmm3
+
+            add edi, 128
+            add esi, 128
+            sub ecx, 128
+            cmp ecx, 128
+            jae copy_128
+ 
+       try_to_copy64:
+            cmp ecx, 64
+            jb try_to_copy32
+
+             movdqa xmm0, [esi]
+             movdqa xmm1, [esi + 16]
+             movdqa xmm2, [esi + 32]
+             movdqa xmm3, [esi + 48]
+
+             movntdq [edi], xmm0
+             movntdq [edi + 16], xmm1
+             movntdq [edi + 32], xmm2
+             movntdq [edi + 48], xmm3
+             
+             add edi, 64
+             add esi, 64
+             sub ecx, 64
+             prefetchnta [esi]
+
+        try_to_copy32:
+             cmp ecx, 32
+             jb try_to_copy16
+
+             movdqa xmm0, [esi]
+             movdqa xmm1, [esi + 16] 
+             movntdq [edi], xmm0
+             movntdq [edi + 16], xmm1
+
+             add edi, 32 
+             add esi, 32 
+             sub ecx, 32
+
+        try_to_copy16:
+             cmp ecx, 16
+             jb try_to_copy4
+
+             movdqa xmm0, [esi]
+             movntdq [edi], xmm0
+
+             add edi, 16
+             add esi, 16
+             sub ecx, 16
+
+
+        try_to_copy4:
+            cmp ecx, 4
+            jb try_to_copy_1 
+            movsd
+            sub ecx, 4
+            jmp try_to_copy4
+
+        try_to_copy_1:     
+            rep movsb
+
+        sfence
+    }
+}
+
+static _inline void fast_memcpy_unaligment(void *dest, const void *src, size_t len)
+{
+    _asm
+    {
+        mov ecx, len
+        mov esi, src
+        mov edi, dest
+
+        cmp ecx, 128
+        jb try_to_copy64
+ 
+        prefetchnta [esi]
+        copy_128:
+            prefetchnta [esi + 64]
+
+            movdqu xmm0, [esi]
+            movdqu xmm1, [esi + 16]
+            movdqu xmm2, [esi + 32]
+            movdqu xmm3, [esi + 48]
+
+            prefetchnta [esi + 128]
+
+            movntdq [edi], xmm0
+            movntdq [edi + 16], xmm1
+            movntdq [edi + 32], xmm2
+            movntdq [edi + 48], xmm3
+
+            movdqu xmm0, [esi + 64]
+            movdqu xmm1, [esi + 80]
+            movdqu xmm2, [esi + 96]
+            movdqu xmm3, [esi + 112]
+
+            movntdq [edi + 64], xmm0
+            movntdq [edi + 80], xmm1
+            movntdq [edi + 96], xmm2
+            movntdq [edi + 112], xmm3
+
+            add edi, 128
+            add esi, 128
+            sub ecx, 128
+            cmp ecx, 128
+            jae copy_128
+ 
+       try_to_copy64:
+            cmp ecx, 64
+            jb try_to_copy32
+
+             movdqu xmm0, [esi]
+             movdqu xmm1, [esi + 16]
+             movdqu xmm2, [esi + 32]
+             movdqu xmm3, [esi + 48]
+
+             movntdq [edi], xmm0
+             movntdq [edi + 16], xmm1
+             movntdq [edi + 32], xmm2
+             movntdq [edi + 48], xmm3
+             
+             add edi, 64
+             add esi, 64
+             sub ecx, 64
+             prefetchnta [esi]
+
+        try_to_copy32:
+             cmp ecx, 32
+             jb try_to_copy16
+
+             movdqu xmm0, [esi]
+             movdqu xmm1, [esi + 16] 
+             movntdq [edi], xmm0
+             movntdq [edi + 16], xmm1
+
+             add edi, 32 
+             add esi, 32 
+             sub ecx, 32
+
+        try_to_copy16:
+             cmp ecx, 16
+             jb try_to_copy4
+
+             movdqu xmm0, [esi]
+             movntdq [edi], xmm0
+
+             add edi, 16
+             add esi, 16
+             sub ecx, 16
+
+
+        try_to_copy4:
+            cmp ecx, 4
+            jb try_to_copy_1 
+            movsd
+            sub ecx, 4
+            jmp try_to_copy4
+
+        try_to_copy_1:     
+            rep movsb
+
+        sfence
+    }
+}
+
+#endif
+
+#ifdef DBG
+    #define PutBytesAlign __PutBytesAlign
+#define PutBytes(pdev, chunk, now, end, src, size, page_counter, alloc_size, use_sse)\
+    __PutBytesAlign(pdev, chunk, now, end, src, size, page_counter, alloc_size, 1, use_sse)
+#else
+#define  PutBytesAlign(pdev, chunk, now, end, src, size, page_counter, alloc_size, alignment, use_sse)\
+    __PutBytesAlign(pdev, chunk, now, end, src, size, NULL, alloc_size, alignment, use_sse)
+#define  PutBytes(pdev, chunk, now, end, src, size, page_counter, alloc_size, use_sse)\
+    __PutBytesAlign(pdev, chunk, now, end, src, size, NULL, alloc_size, 1, use_sse)
+#endif
+
+#define BITS_BUF_MAX (64 * 1024)
+
+static void __PutBytesAlign(PDev *pdev, QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
+                            UINT8 **end_ptr, UINT8 *src, int size, int *page_counter,
+                            size_t alloc_size, uint32_t alignment, BOOL use_sse)
+{
+    QXLDataChunk *chunk = *chunk_ptr;
+    UINT8 *now = *now_ptr;
+    UINT8 *end = *end_ptr;
+    int offset;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    while (size) {
+        int cp_size = (int)MIN(end - now, size);
+        if (!cp_size) {
+            size_t aligned_size;
+            ASSERT(pdev, alloc_size > 0);
+            ASSERT(pdev, BITS_BUF_MAX > alignment);
+            aligned_size = (int)MIN(alloc_size + alignment - 1, BITS_BUF_MAX);
+            aligned_size -=  aligned_size % alignment;
+            NEW_DATA_CHUNK(page_counter, aligned_size);
+            cp_size = (int)MIN(end - now, size);
+        }
+#ifndef _WIN64
+        if (use_sse) {
+            offset = (size_t)now & SSE_MASK;
+            if (offset) {
+                offset = SSE_ALIGN - offset;
+                if (offset >= cp_size) {
+                    RtlCopyMemory(now, src, cp_size);
+                    src += cp_size;
+                    now += cp_size;
+                    chunk->data_size += cp_size;
+                    size -= cp_size;
+                    continue;
+                }
+                RtlCopyMemory(now, src,  offset);
+                now += offset;
+                src += offset;
+                size -= offset;
+                cp_size -= offset;
+                chunk->data_size += offset;
+            }
+    
+            if (((size_t)src & SSE_MASK) == 0) {
+                fast_memcpy_aligment(now, src, cp_size);
+            } else {
+                fast_memcpy_unaligment(now, src, cp_size);
+            }
+        } else {
+            RtlCopyMemory(now, src, cp_size);
+        }
+#else
+        RtlCopyMemory(now, src, cp_size);
+#endif
+        src += cp_size;
+        now += cp_size;
+        chunk->data_size += cp_size;
+        size -= cp_size;
+    }
+    *chunk_ptr = chunk;
+    *now_ptr = now;
+    *end_ptr = end;
+    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
+}
+
+typedef struct InternalImage {
+    CacheImage *cache;
+    QXLImage image;
+} InternalImage;
+
+#define HSURF_HASH_VAL(h) (((unsigned long)h >> 4) ^ ((unsigned long)(h) >> 8) ^ \
+                           ((unsigned long)(h) >> 16) ^ ((unsigned long)(h) >> 24))
+
+#define IMAGE_KEY_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & IMAGE_KEY_HASH_MASK)
+
+static void ImageKeyPut(PDev *pdev, HSURF hsurf, UINT64 unique, UINT32 key)
+{
+    ImageKey *image_key;
+
+    if (!unique) {
+        return;
+    }
+    image_key = &pdev->image_key_lookup[IMAGE_KEY_HASH_VAL(hsurf)];
+    image_key->hsurf = hsurf;
+    image_key->unique = unique;
+    image_key->key = key;
+}
+
+static BOOL ImageKeyGet(PDev *pdev, HSURF hsurf, UINT64 unique, UINT32 *key)
+{
+    ImageKey *image_key;
+    BOOL res = FALSE;
+
+    if (!unique) {
+        return FALSE;
+    }
+    image_key = &pdev->image_key_lookup[IMAGE_KEY_HASH_VAL(hsurf)];
+    if (image_key->hsurf == hsurf && image_key->unique == unique) {
+        *key = image_key->key;
+        res = TRUE;
+    }
+    return res;
+}
+
+#define IMAGE_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & IMAGE_HASH_MASK)
+
+static CacheImage *ImageCacheGetByKey(PDev *pdev, UINT32 key, BOOL check_rest,
+                                      UINT8 format, UINT32 width, UINT32 height)
+{
+    CacheImage *cache_image;
+
+    cache_image = pdev->image_cache[IMAGE_HASH_VAL(key)];
+    while (cache_image) {
+        if (cache_image->key == key && (!check_rest || (cache_image->format == format &&
+            cache_image->width == width && cache_image->height == height))) {
+            break;
+        }
+        cache_image = cache_image->next;
+    }
+    return cache_image;
+}
+
+static void ImageCacheAdd(PDev *pdev, CacheImage *cache_image)
+{
+    int key;
+
+    key = IMAGE_HASH_VAL(cache_image->key);
+    cache_image->next = pdev->image_cache[key];
+    cache_image->hits = 1;
+    pdev->image_cache[key] = cache_image;
+}
+
+static void ImageCacheRemove(PDev *pdev, CacheImage *cache_image)
+{
+    CacheImage **cache_img;
+
+    if (!cache_image->hits) {
+        return;
+    }
+    cache_img = &pdev->image_cache[IMAGE_HASH_VAL(cache_image->key)];
+    while (*cache_img) {
+        if ((*cache_img)->key == cache_image->key) {
+            *cache_img = cache_image->next;
+            break;
+        }
+        cache_img = &(*cache_img)->next;
+    }
+}
+
+static CacheImage *AllocCacheImage(PDev* pdev)
+{
+    RingItem *item;
+    while (!(item = RingGetTail(pdev, &pdev->cache_image_lru))) {
+        /* malloc_sem protects release_ring too */
+        EngAcquireSemaphore(pdev->malloc_sem);
+        if (pdev->free_outputs == 0 &&
+            SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+            WaitForReleaseRing(pdev);
+        }
+        FlushReleaseRing(pdev);
+        EngReleaseSemaphore(pdev->malloc_sem);
+    }
+    RingRemove(pdev, item);
+    return CONTAINEROF(item, CacheImage, lru_link);
+}
+
+#define IMAGE_HASH_INIT_VAL(width, height, format) \
+    ((UINT32)((width) & 0x1FFF) | ((UINT32)((height) & 0x1FFF) << 13) |\
+     ((UINT32)(format) << 26))
+
+static _inline void SetImageId(InternalImage *internal, BOOL cache_me, LONG width, LONG height,
+                               UINT8 format, UINT32 key)
+{
+    UINT32 image_info = IMAGE_HASH_INIT_VAL(width, height, format);
+
+    if (cache_me) {
+        QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER << 30) |
+                         image_info, key);
+        internal->image.descriptor.flags = QXL_IMAGE_CACHE;
+    } else {
+        QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER_DONT_CACHE  << 30) |
+                         image_info, key);
+        internal->image.descriptor.flags = 0;
+    }
+}
+
+typedef struct InternalPalette {
+    UINT32 refs;
+    struct InternalPalette *next;
+    RingItem lru_link;
+    QXLPalette palette;
+} InternalPalette;
+
+#define PALETTE_HASH_VAL(unique) ((int)(unique) & PALETTE_HASH_NASKE)
+
+static _inline void ReleasePalette(PDev *pdev, InternalPalette *palette)
+{
+    ASSERT(pdev, palette);
+    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
+    if (--palette->refs == 0) {
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, palette);
+    }
+}
+
+static _inline void PaletteCacheRemove(PDev *pdev, InternalPalette *palette)
+{
+    InternalPalette **internal;
+    BOOL found = FALSE;
+
+    DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
+
+    ASSERT(pdev, palette->palette.unique);
+    internal = &pdev->palette_cache[PALETTE_HASH_VAL(palette->palette.unique)];
+
+    while (*internal) {
+        if ((*internal)->palette.unique == palette->palette.unique) {
+            *internal = palette->next;
+            found = TRUE;
+            break;
+        }
+        internal = &(*internal)->next;
+    }
+
+    RingRemove(pdev, &palette->lru_link);
+    ReleasePalette(pdev, palette);
+    pdev->num_palettes--;
+
+    if (!found) {
+        DEBUG_PRINT((pdev, 0, "%s: Error: palette 0x%x isn't in cache \n", __FUNCTION__, palette));
+        ASSERT(pdev, FALSE);
+    } else {
+        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
+    }
+}
+
+static _inline InternalPalette *PaletteCacheGet(PDev *pdev, UINT32 unique)
+{
+    InternalPalette *now;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    if (!unique) {
+        return NULL;
+    }
+
+    now = pdev->palette_cache[PALETTE_HASH_VAL(unique)];
+    while (now) {
+        if (now->palette.unique == unique) {
+            RingRemove(pdev, &now->lru_link);
+            RingAdd(pdev, &pdev->palette_lru, &now->lru_link);
+            now->refs++;
+            DEBUG_PRINT((pdev, 13, "%s: found\n", __FUNCTION__));
+            return now;
+        }
+        now = now->next;
+    }
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+    return NULL;
+}
+
+static void PaletteCacheClear(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
+    while(pdev->num_palettes) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->palette_lru));
+        PaletteCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->palette_lru),
+                                             InternalPalette, lru_link));
+    }
+}
+
+static _inline void PaletteCacheAdd(PDev *pdev, InternalPalette *palette)
+{
+    int key;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    if (!palette->palette.unique) {
+        DEBUG_PRINT((pdev, 13, "%s: not unique\n", __FUNCTION__));
+        return;
+    }
+
+    if (pdev->num_palettes == PALETTE_CACHE_SIZE) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->palette_lru));
+        PaletteCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->palette_lru),
+                                             InternalPalette, lru_link));
+    }
+
+    key = PALETTE_HASH_VAL(palette->palette.unique);
+    palette->next = pdev->palette_cache[key];
+    pdev->palette_cache[key] = palette;
+
+    RingAdd(pdev, &pdev->palette_lru, &palette->lru_link);
+    palette->refs++;
+    pdev->num_palettes++;
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+
+static _inline void GetPallette(PDev *pdev, QXLBitmap *bitmap, XLATEOBJ *color_trans)
+{
+    InternalPalette *internal;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    if (!color_trans || !(color_trans->flXlate & XO_TABLE)) {
+        bitmap->palette = 0;
+        return;
+    }
+
+    if ((internal = PaletteCacheGet(pdev, color_trans->iUniq))) {
+        DEBUG_PRINT((pdev, 12, "%s: from cache\n", __FUNCTION__));
+        bitmap->palette = PA(pdev, &internal->palette, pdev->main_mem_slot);
+        return;
+    }
+
+    internal = (InternalPalette *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(InternalPalette) +
+                                           (color_trans->cEntries << 2));
+    internal->refs = 1;
+    RingItemInit(&internal->lru_link);
+    bitmap->palette = PA(pdev, &internal->palette, pdev->main_mem_slot);
+    internal->palette.unique = color_trans->iUniq;
+    internal->palette.num_ents = (UINT16)color_trans->cEntries;
+
+    RtlCopyMemory(internal->palette.ents, color_trans->pulXlate, color_trans->cEntries << 2);
+    PaletteCacheAdd(pdev, internal);
+    DEBUG_PRINT((pdev, 12, "%s: done\n", __FUNCTION__));
+}
+
+static void FreeQuicImage(PDev *pdev, Resource *res) // todo: defer
+{
+    InternalImage *internal;
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    internal = (InternalImage *)res->res;
+    if (internal->cache) {
+        RingAdd(pdev, &pdev->cache_image_lru, &internal->cache->lru_link);
+        internal->cache->image = NULL;
+    }
+
+    chunk_phys = ((QXLDataChunk *)internal->image.quic.data)->next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_bits_pages--);
+
+    }
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_bits_pages--);
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+static _inline QuicImageType GetQuicImageType(UINT8 format)
+{
+    switch (format) {
+    case SPICE_BITMAP_FMT_32BIT:
+        return QUIC_IMAGE_TYPE_RGB32;
+    case SPICE_BITMAP_FMT_16BIT:
+        return QUIC_IMAGE_TYPE_RGB16;
+    case SPICE_BITMAP_FMT_RGBA:
+        return QUIC_IMAGE_TYPE_RGBA;
+    case SPICE_BITMAP_FMT_24BIT:
+        return QUIC_IMAGE_TYPE_RGB24;
+    default:
+        return QUIC_IMAGE_TYPE_INVALID;
+    };
+}
+
+#define QUIC_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
+#define QUIC_BUF_MAX (64 * 1024)
+#define QUIC_BUF_MIN 1024
+
+struct QuicData {
+    QuicUsrContext user;
+    PDev *pdev;
+    QuicContext *quic;
+    QXLDataChunk *chunk;
+    int chunk_io_words;
+    int prev_chunks_io_words;
+    int rows;
+    int raw_row_size;
+};
+
+static int quic_usr_more_space(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed)
+{
+    QuicData *usr_data = (QuicData *)usr;
+    PDev *pdev = usr_data->pdev;
+    QXLDataChunk *new_chank;
+    int alloc_size;
+    int more;
+
+    ASSERT(pdev, usr_data->rows >= rows_completed);
+    more =  (rows_completed - usr_data->rows) * usr_data->raw_row_size;
+
+    alloc_size = MIN(MAX(more >> 4, QUIC_BUF_MIN), QUIC_BUF_MAX);
+    new_chank = AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLDataChunk) + alloc_size);
+    new_chank->data_size = 0;
+    new_chank->prev_chunk = PA(pdev, usr_data->chunk, pdev->main_mem_slot);
+    new_chank->next_chunk = 0;
+
+    usr_data->prev_chunks_io_words += usr_data->chunk_io_words;
+    usr_data->chunk->data_size = usr_data->chunk_io_words << 2;
+    usr_data->chunk->next_chunk = PA(pdev, new_chank, pdev->main_mem_slot);
+    usr_data->chunk = new_chank;
+
+    usr_data->chunk_io_words = alloc_size >> 2;
+
+    ONDBG(pdev->num_bits_pages++);
+
+    *io_ptr = (UINT32 *)new_chank->data;
+    return usr_data->chunk_io_words;
+}
+
+static int quic_usr_more_lines(QuicUsrContext *usr, uint8_t **lines)
+{
+    return 0;
+}
+
+static _inline Resource *GetQuicImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
+                                      BOOL cache_me, LONG width, LONG height, UINT8 format,
+                                      UINT8 *src, UINT32 line_size, UINT32 key)
+{
+    Resource *image_res;
+    InternalImage *internal;
+    QuicImageType type;
+    size_t alloc_size;
+    int data_size;
+    QuicData *quic_data;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev->quic_data);
+
+    if (!*pdev->compression_level) {
+        return NULL;
+    }
+
+    if ((type = GetQuicImageType(format)) == QUIC_IMAGE_TYPE_INVALID) {
+        DEBUG_PRINT((pdev, 13, "%s: unsupported\n", __FUNCTION__));
+        return NULL;
+    }
+
+    EngAcquireSemaphore(pdev->quic_data_sem);
+
+    quic_data = pdev->quic_data;
+
+    alloc_size = MIN(QUIC_ALLOC_BASE + (height * line_size >> 4), QUIC_ALLOC_BASE + QUIC_BUF_MAX);
+    alloc_size = MAX(alloc_size, QUIC_ALLOC_BASE + QUIC_BUF_MIN);
+
+    image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
+    ONDBG(pdev->num_bits_pages++);
+    image_res->refs = 1;
+    image_res->free = FreeQuicImage;
+    RESOURCE_TYPE(image_res, RESOURCE_TYPE_QUIC_IMAGE);
+
+    internal = (InternalImage *)image_res->res;
+    SetImageId(internal, cache_me, width, height, format, key);
+    internal->image.descriptor.type = SPICE_IMAGE_TYPE_QUIC;
+    internal->image.descriptor.width = width;
+    internal->image.descriptor.height = height;
+
+    quic_data->chunk = (QXLDataChunk *)internal->image.quic.data;
+    quic_data->chunk->data_size = 0;
+    quic_data->chunk->prev_chunk = 0;
+    quic_data->chunk->next_chunk = 0;
+    quic_data->prev_chunks_io_words = 0;
+    quic_data->chunk_io_words = (int)(((UINT8 *)image_res + alloc_size - quic_data->chunk->data) >> 2);
+    quic_data->rows = height;
+    quic_data->raw_row_size = line_size;
+
+    ASSERT(pdev, quic_data->chunk_io_words > 0);
+    data_size = quic_encode(quic_data->quic, type, width, height, src, height, surf->lDelta,
+                            (UINT32 *)quic_data->chunk->data, quic_data->chunk_io_words);
+    if (data_size == QUIC_ERROR) {
+        FreeQuicImage(pdev, image_res);
+        DEBUG_PRINT((pdev, 13, "%s: error\n", __FUNCTION__));
+        image_res = NULL;
+        goto out;
+    }
+
+    quic_data->chunk->data_size = (data_size - quic_data->prev_chunks_io_words) << 2;
+    internal->image.quic.data_size = data_size << 2;
+    DEBUG_PRINT((pdev, 13, "%s: done. row size %u quic size %u \n", __FUNCTION__,
+                 line_size * height, data_size << 2));
+
+ out:
+    EngReleaseSemaphore(pdev->quic_data_sem);
+
+    return image_res;
+}
+
+static void FreeBitmapImage(PDev *pdev, Resource *res) // todo: defer
+{
+    InternalImage *internal;
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    internal = (InternalImage *)res->res;
+    if (internal->cache) {
+        RingAdd(pdev, &pdev->cache_image_lru, &internal->cache->lru_link);
+        internal->cache->image = NULL;
+    }
+
+    if (internal->image.bitmap.palette) {
+        QXLPalette *palette = (QXLPalette *)VA(pdev, internal->image.bitmap.palette,
+					       pdev->main_mem_slot);
+        ReleasePalette(pdev, CONTAINEROF(palette, InternalPalette, palette));
+    }
+
+    chunk_phys = ((QXLDataChunk *)(&internal->image.bitmap + 1))->next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_bits_pages--);
+
+    }
+
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_bits_pages--);
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#ifndef _WIN64
+
+static _inline void RestoreFPU(PDev *pdev, UINT8 FPUSave[])
+{
+    void *align_addr =  (void *)ALIGN((size_t)(FPUSave), SSE_ALIGN);
+
+    _asm
+    {
+        mov esi, align_addr
+
+        movdqa xmm0, [esi]
+        movdqa xmm1, [esi + 16]
+        movdqa xmm2, [esi + 32]
+        movdqa xmm3, [esi + 48]
+    }
+}
+
+static _inline void SaveFPU(PDev *pdev, UINT8 FPUSave[])
+{
+    void *align_addr =  (void *)ALIGN((size_t)(FPUSave), SSE_ALIGN);
+
+    _asm
+    {
+        mov edi, align_addr
+    
+        movdqa [edi], xmm0
+        movdqa [edi + 16], xmm1
+        movdqa [edi + 32], xmm2
+        movdqa [edi + 48], xmm3
+    }
+}
+
+#endif
+
+static void FreeSurfaceImage(PDev *pdev, Resource *res)
+{
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#define BITMAP_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
+
+static _inline Resource *GetBitmapImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
+                                        BOOL cache_me, LONG width, LONG height, UINT8 format,
+                                        UINT8 *src, UINT32 line_size, UINT32 key)
+{
+    Resource *image_res;
+    InternalImage *internal;
+    size_t alloc_size;
+    QXLDataChunk *chunk;
+    UINT8 *src_end;
+    UINT8 *dest;
+    UINT8 *dest_end;
+    UINT8 FPUSave[16 * 4 + 15];
+    BOOL use_sse = FALSE;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    ASSERT(pdev, width > 0 && height > 0);
+
+    ASSERT(pdev, BITS_BUF_MAX > line_size);
+    alloc_size = BITMAP_ALLOC_BASE + BITS_BUF_MAX - BITS_BUF_MAX % line_size;
+    alloc_size = MIN(BITMAP_ALLOC_BASE + height * line_size, alloc_size);
+    image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
+    ONDBG(pdev->num_bits_pages++);
+
+    image_res->refs = 1;
+    image_res->free = FreeBitmapImage;
+    RESOURCE_TYPE(image_res, RESOURCE_TYPE_BITMAP_IMAGE);
+
+    internal = (InternalImage *)image_res->res;
+    SetImageId(internal, cache_me, width, height, format, key);
+    internal->image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+    chunk = (QXLDataChunk *)(&internal->image.bitmap + 1);
+    chunk->data_size = 0;
+    chunk->prev_chunk = 0;
+    chunk->next_chunk = 0;
+    internal->image.bitmap.data = PA(pdev, chunk, pdev->main_mem_slot);
+    internal->image.bitmap.flags = 0;
+    internal->image.descriptor.width = internal->image.bitmap.x = width;
+    internal->image.descriptor.height = internal->image.bitmap.y = height;
+    internal->image.bitmap.format = format;
+    internal->image.bitmap.stride = line_size;
+    src_end = src - surf->lDelta;
+    src += surf->lDelta * (height - 1);
+    dest = chunk->data;
+    dest_end = (UINT8 *)image_res + alloc_size;
+    alloc_size = height * line_size;
+
+#ifndef _WIN64
+    if (have_sse2 && alloc_size >= 1024) {
+        use_sse = TRUE;
+        SaveFPU(pdev, FPUSave);
+    }
+#endif
+    for (; src != src_end; src -= surf->lDelta, alloc_size -= line_size) {
+        PutBytesAlign(pdev, &chunk, &dest, &dest_end, src, line_size,
+                      &pdev->num_bits_pages, alloc_size, line_size, use_sse);
+    }
+#ifndef _WIN64
+    if (use_sse) {
+        RestoreFPU(pdev, FPUSave);
+    }
+#endif
+
+    GetPallette(pdev, &internal->image.bitmap, color_trans);
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+    return image_res;
+}
+
+#define ADAPTIVE_HASH
+
+static _inline UINT32 GetHash(UINT8 *src, INT32 width, INT32 height, UINT8 format, int high_bits_set,
+                              UINT32 line_size, LONG stride, XLATEOBJ *color_trans)
+{
+    UINT32 hash_value = IMAGE_HASH_INIT_VAL(width, height, format);
+    UINT8 *row_buf = src;
+    UINT8 last_byte = 0;
+    UINT8 reminder;
+    UINT32 i;
+    int row;
+
+    if (color_trans && color_trans->flXlate == XO_TABLE) {
+        hash_value = murmurhash2a(color_trans->pulXlate,
+                                  sizeof(*color_trans->pulXlate) * color_trans->cEntries,
+                                  hash_value);
+    }
+
+    if (format == SPICE_BITMAP_FMT_32BIT && stride == line_size) {
+        hash_value = murmurhash2ajump3((UINT32 *)row_buf, width * height, hash_value);
+    } else {
+        for (row = 0; row < height; row++) {
+    #ifdef ADAPTIVE_HASH
+            if (format ==  SPICE_BITMAP_FMT_32BIT) {
+                hash_value = murmurhash2ajump3((UINT32 *)row_buf, width, hash_value);
+            } else {
+                if (format == SPICE_BITMAP_FMT_4BIT_BE && (width & 0x1)) {
+                    last_byte = row_buf[line_size - 1] & 0xF0;
+                } else if (format == SPICE_BITMAP_FMT_1BIT_BE && (reminder = width & 0x7)) {
+                    last_byte = row_buf[line_size - 1] & ~((1 << (8 - reminder)) - 1);
+                }
+                if (last_byte) {
+                    hash_value = murmurhash2a(row_buf, line_size - 1, hash_value);
+                    hash_value = murmurhash2a(&last_byte, 1, hash_value);
+                } else {
+                    hash_value = murmurhash2a(row_buf, line_size, hash_value);
+                }
+            }
+    #else
+            hash_value = murmurhash2a(row_buf, line_size, hash_value);
+    #endif
+            row_buf += stride;
+        }
+    }
+    if (high_bits_set) {
+        hash_value ^= 1;
+    }
+    return hash_value;
+}
+
+static _inline UINT32 GetFormatLineSize(INT32 width, ULONG bitmap_format, UINT8 *format)
+{
+    switch (bitmap_format) {
+    case BMF_32BPP:
+        *format = SPICE_BITMAP_FMT_32BIT;
+        return width << 2;
+    case BMF_24BPP:
+        *format = SPICE_BITMAP_FMT_24BIT;
+        return width * 3;
+    case BMF_16BPP:
+        *format = SPICE_BITMAP_FMT_16BIT;
+        return width << 1;
+    case BMF_8BPP:
+        *format = SPICE_BITMAP_FMT_8BIT;
+        return width;
+    case BMF_4BPP:
+        *format = SPICE_BITMAP_FMT_4BIT_BE;
+        return ALIGN(width, 2) >> 1;
+    case BMF_1BPP:
+        *format = SPICE_BITMAP_FMT_1BIT_BE;
+        return ALIGN(width, 8) >> 3;
+    default:
+        return 0;
+    }
+}
+
+static BOOL CacheSizeTest(PDev *pdev, SURFOBJ *surf)
+{
+    BOOL ret = (UINT32)surf->sizlBitmap.cx * surf->sizlBitmap.cy <= pdev->max_bitmap_size;
+    if (!ret) {
+        DEBUG_PRINT((pdev, 1, "%s: cache size test failed x %d y %d max\n",
+                     __FUNCTION__,
+                     surf->sizlBitmap.cx,
+                     surf->sizlBitmap.cy,
+                     pdev->max_bitmap_size));
+    }
+    return ret;
+}
+
+static _inline UINT64 get_unique(SURFOBJ *surf, XLATEOBJ *color_trans)
+{
+    ULONG pallette_unique = color_trans ? color_trans->iUniq : 0;
+
+    // NOTE: GDI sometimes gives many instances of the exactly same SURFOBJ (hsurf & iUniq),
+    // but with (fjBitmap & BMF_DONTCACHE). This opposed to what documented in the MSDN.
+    if (!surf->iUniq || (surf->fjBitmap & BMF_DONTCACHE) || !pallette_unique) {
+        return 0;
+    } else {
+        return (surf->iUniq | ((UINT64)pallette_unique << 32));
+    }
+}
+
+BOOL QXLCheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans)
+{
+    CacheImage *cache_image;
+    UINT64 gdi_unique;
+    UINT32 key;
+    UINT8 format;
+
+    gdi_unique = get_unique(surf, color_trans);
+
+    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
+        return FALSE;
+    }
+
+    switch (surf->iBitmapFormat) {
+    case BMF_32BPP:
+        format = SPICE_BITMAP_FMT_32BIT;
+        break;
+    case BMF_24BPP:
+        format = SPICE_BITMAP_FMT_24BIT;
+        break;
+    case BMF_16BPP:
+        format = SPICE_BITMAP_FMT_16BIT;
+        break;
+    case BMF_8BPP:
+        format = SPICE_BITMAP_FMT_8BIT;
+        break;
+    case BMF_4BPP:
+        format = SPICE_BITMAP_FMT_4BIT_BE;
+        break;
+    case BMF_1BPP:
+        format = SPICE_BITMAP_FMT_1BIT_BE;
+    }
+
+
+    if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
+                                          surf->sizlBitmap.cx,
+                                          surf->sizlBitmap.cy))) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static CacheImage *GetCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans, int high_bits_set, UINT32 *hash_key)
+{
+    CacheImage *cache_image;
+    UINT64 gdi_unique;
+    UINT32 key;
+    UINT8 format;
+    UINT32 line_size;
+
+    gdi_unique = get_unique(surf, color_trans);
+
+    if (!(line_size = GetFormatLineSize(surf->sizlBitmap.cx, surf->iBitmapFormat, &format))) {
+        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
+        key = GetHash(surf->pvScan0, surf->sizlBitmap.cx, surf->sizlBitmap.cy, format,
+                      high_bits_set, line_size, surf->lDelta, color_trans);
+        ImageKeyPut(pdev, surf->hsurf, gdi_unique, key);
+        DEBUG_PRINT((pdev, 11, "%s: ImageKeyPut %u\n", __FUNCTION__, key));
+    } else {
+        DEBUG_PRINT((pdev, 11, "%s: ImageKeyGet %u\n", __FUNCTION__, key));
+    }
+
+    if (hash_key) {
+        *hash_key = key;
+    }
+
+    if ((cache_image = ImageCacheGetByKey(pdev, key, TRUE, format,
+                                          surf->sizlBitmap.cx,
+                                          surf->sizlBitmap.cy))) {
+        cache_image->hits++;
+        DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
+                     key, cache_image->hits));
+        return cache_image;
+    }
+
+    if (CacheSizeTest(pdev, surf)) {
+        CacheImage *cache_image;
+        cache_image = AllocCacheImage(pdev);
+        ImageCacheRemove(pdev, cache_image);
+        cache_image->key = key;
+        cache_image->image = NULL;
+        cache_image->format = format;
+        cache_image->width = surf->sizlBitmap.cx;
+        cache_image->height = surf->sizlBitmap.cy;
+        ImageCacheAdd(pdev, cache_image);
+        RingAdd(pdev, &pdev->cache_image_lru, &cache_image->lru_link);
+        DEBUG_PRINT((pdev, 11, "%s: ImageCacheAdd %u\n", __FUNCTION__, key));
+    }
+    return NULL;
+}
+
+// TODO: reconsider
+static HSEMAPHORE image_id_sem = NULL;
+
+static _inline UINT32 get_image_serial()
+{
+    static UINT32 image_id = 0; // move to dev mem and use InterlockedIncrement
+    UINT32 ret = 0;
+
+    EngAcquireSemaphore(image_id_sem);
+    ret = ++image_id;
+    EngReleaseSemaphore(image_id_sem);
+    return ret;
+}
+
+static int rgb32_data_has_alpha(int width, int height, int stride,
+                                UINT8 *data, int *all_set_out)
+{
+    UINT32 *line, *end, alpha;
+    int has_alpha;
+
+    has_alpha = FALSE;
+    while (height-- > 0) {
+        line = (UINT32 *)data;
+        end = line + width;
+        data += stride;
+        while (line != end) {
+            alpha = *line & 0xff000000U;
+            if (alpha != 0) {
+                has_alpha = TRUE;
+                if (alpha != 0xff000000U) {
+                    *all_set_out = FALSE;
+                    return TRUE;
+                }
+            }
+            line++;
+        }
+    }
+
+    *all_set_out = has_alpha;
+    return has_alpha;
+}
+
+BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
+                  QXLRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+                  INT32 *surface_dest)
+{
+    Resource *image_res;
+    InternalImage *internal;
+    CacheImage *cache_image;
+    UINT32 key;
+    UINT8 format;
+    UINT32 line_size;
+    UINT8 *src;
+    int high_bits_set;
+    INT32 width = area->right - area->left;
+    INT32 height = area->bottom - area->top;
+
+    ASSERT(pdev, !hash_key || use_cache);
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    if (surf->iType != STYPE_BITMAP) {
+        UINT32 alloc_size;
+
+        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+        alloc_size = sizeof(Resource) + sizeof(InternalImage);
+        image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
+
+        ONDBG(pdev->num_bits_pages++);
+        image_res->refs = 1;
+        image_res->free = FreeSurfaceImage;
+        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
+
+        internal = (InternalImage *)image_res->res;
+
+        SetImageId(internal, FALSE, 0, 0, 0, 0);
+        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+        internal->image.descriptor.width = 0;
+        internal->image.descriptor.height = 0;
+        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+
+        DrawableAddRes(pdev, drawable, image_res);
+
+        RELEASE_RES(pdev, image_res);
+
+        return TRUE;
+    }
+
+    if (area->left < 0 || area->right > surf->sizlBitmap.cx ||
+        area->top < 0 || area->bottom > surf->sizlBitmap.cy) {
+        DEBUG_PRINT((pdev, 0, "%s: bad dimensions\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    high_bits_set = FALSE;
+    if (surf->iBitmapFormat == BMF_32BPP) {
+        if (rgb32_data_has_alpha(width, height, surf->lDelta,
+                                 (UINT8 *)surf->pvScan0 + area->left * 4,
+                                 &high_bits_set) &&
+            !high_bits_set) {
+            return QXLGetAlphaBitmap(pdev, drawable, image_phys,
+                                     surf, area, surface_dest);
+        }
+    }
+
+    DEBUG_PRINT((pdev, 11, "%s: iUniq=%x DONTCACHE=%x w=%d h=%d cx=%d cy=%d "
+                 "hsurf=%x ctiUniq=%x XO_TABLE=%u format=%u\n", __FUNCTION__,
+                 surf->iUniq, surf->fjBitmap & BMF_DONTCACHE, width, height,
+                 surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
+                 color_trans ? color_trans->iUniq : 0,
+                 color_trans ? !!(color_trans->flXlate & XO_TABLE) : 0,
+                 surf->iBitmapFormat));
+
+    if (use_cache) {
+        cache_image = GetCacheImage(pdev, surf, color_trans, high_bits_set, hash_key);
+        if (cache_image && cache_image->image) {
+            DEBUG_PRINT((pdev, 11, "%s: cached image found %u\n", __FUNCTION__, cache_image->key));
+            internal = cache_image->image;
+            *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+            image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
+            DrawableAddRes(pdev, drawable, image_res);
+            return TRUE;
+        }
+    } else {
+        cache_image = NULL;
+    }
+
+    if (cache_image) {
+        key = cache_image->key;
+        width = surf->sizlBitmap.cx;
+        height = surf->sizlBitmap.cy;
+        src = surf->pvScan0;
+    } else {
+        int scan0_offset;
+        int dx;
+
+        key = get_image_serial();
+        switch (surf->iBitmapFormat) {
+        case BMF_32BPP:
+            dx = 0;
+            scan0_offset = area->left << 2;
+            break;
+        case BMF_24BPP:
+            dx = 0;
+            scan0_offset = area->left * 3;
+            break;
+        case BMF_16BPP:
+            dx = 0;
+            scan0_offset = area->left << 1;
+            break;
+        case BMF_8BPP:
+            dx = 0;
+            scan0_offset = area->left;
+            break;
+        case BMF_4BPP:
+            dx = area->left & 0x01;
+            scan0_offset = (area->left & ~0x01) >> 1;
+            break;
+        case BMF_1BPP:
+            dx = area->left & 0x07;
+            scan0_offset = (area->left & ~0x07) >> 3;
+            break;
+        default:
+            DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
+            return FALSE;
+        }
+        width = width + dx;
+        src = (UINT8 *)surf->pvScan0 + area->top * surf->lDelta + scan0_offset;
+
+        area->left = dx;
+        area->right = width;
+
+        area->top = 0;
+        area->bottom = height;
+    }
+
+    if (!(line_size = GetFormatLineSize(width, surf->iBitmapFormat, &format))) {
+        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (!(image_res = GetQuicImage(pdev, surf, color_trans, !!cache_image, width, height, format,
+                                   src, line_size, key))) {
+        image_res = GetBitmapImage(pdev, surf, color_trans, !!cache_image, width, height, format,
+                                   src, line_size, key);
+    }
+    internal = (InternalImage *)image_res->res;
+    if (high_bits_set) {
+        internal->image.descriptor.flags |= QXL_IMAGE_HIGH_BITS_SET;
+    }
+    if ((internal->cache = cache_image)) {
+        DEBUG_PRINT((pdev, 11, "%s: cache_me %u\n", __FUNCTION__, key));
+        cache_image->image = internal;
+        if (RingItemIsLinked(&cache_image->lru_link)) {
+            RingRemove(pdev, &cache_image->lru_link);
+        }
+    }
+    *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+    DrawableAddRes(pdev, drawable, image_res);
+    RELEASE_RES(pdev, image_res);
+    return TRUE;
+}
+
+BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys,
+                       SURFOBJ *surf, QXLRect *area, INT32 *surface_dest)
+{
+    Resource *image_res;
+    InternalImage *internal;
+    CacheImage *cache_image;
+    UINT64 gdi_unique;
+    UINT32 key;
+    UINT8 *src;
+    INT32 width = area->right - area->left;
+    INT32 height = area->bottom - area->top;
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    ASSERT(pdev, area->left >= 0 && area->right <= surf->sizlBitmap.cx &&
+           area->top >= 0 && area->bottom <= surf->sizlBitmap.cy);
+
+    DEBUG_PRINT((pdev, 11, "%s: iUniq=%x DONTCACHE=%x w=%d h=%d cx=%d cy=%d "
+                 "hsurf=%x format=%u\n", __FUNCTION__, surf->iUniq,
+                 surf->fjBitmap & BMF_DONTCACHE, width, height,
+                 surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
+                 surf->iBitmapFormat));
+
+    if (surf->iType != STYPE_BITMAP) {
+        UINT32 alloc_size;
+
+        DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+        alloc_size = sizeof(Resource) + sizeof(InternalImage);
+        image_res = AllocMem(pdev, MSPACE_TYPE_DEVRAM, alloc_size);
+
+        ONDBG(pdev->num_bits_pages++);
+        image_res->refs = 1;
+        image_res->free = FreeSurfaceImage;
+        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
+
+        internal = (InternalImage *)image_res->res;
+
+        SetImageId(internal, FALSE, 0, 0, 0, 0);
+        internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+        internal->image.descriptor.width = 0;
+        internal->image.descriptor.height = 0;
+        *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+        DrawableAddRes(pdev, drawable, image_res);
+        RELEASE_RES(pdev, image_res);
+
+        return TRUE;
+    }
+
+    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
+
+    //todo: use GetCacheImage
+
+    // NOTE: Same BMF_DONTCACHE issue as in QXLGetBitmap
+    if (!surf->iUniq || (surf->fjBitmap & BMF_DONTCACHE)) {
+        gdi_unique = 0;
+    } else {
+        gdi_unique = surf->iUniq;
+    }
+
+    if (!ImageKeyGet(pdev, surf->hsurf, gdi_unique, &key)) {
+        key = GetHash(surf->pvScan0, surf->sizlBitmap.cx, surf->sizlBitmap.cy, SPICE_BITMAP_FMT_RGBA,
+                      FALSE, surf->sizlBitmap.cx << 2, surf->lDelta, NULL);
+        ImageKeyPut(pdev, surf->hsurf, gdi_unique, key);
+        DEBUG_PRINT((pdev, 11, "%s: ImageKeyPut %u\n", __FUNCTION__, key));
+    } else {
+        DEBUG_PRINT((pdev, 11, "%s: ImageKeyGet %u\n", __FUNCTION__, key));
+    }
+
+    if (cache_image = ImageCacheGetByKey(pdev, key, TRUE, SPICE_BITMAP_FMT_RGBA,
+                                         surf->sizlBitmap.cx, surf->sizlBitmap.cy)) {
+        DEBUG_PRINT((pdev, 11, "%s: ImageCacheGetByKey %u hits %u\n", __FUNCTION__,
+                     key, cache_image->hits));
+        cache_image->hits++;
+        if (internal = cache_image->image) {
+            DEBUG_PRINT((pdev, 11, "%s: cached image found %u\n", __FUNCTION__, key));
+            *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+            image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
+            DrawableAddRes(pdev, drawable, image_res);
+            return TRUE;
+        }
+    } else if (CacheSizeTest(pdev, surf)) {
+        CacheImage *cache_image;
+        cache_image = AllocCacheImage(pdev);
+        ImageCacheRemove(pdev, cache_image);
+        cache_image->key = key;
+        cache_image->image = NULL;
+        cache_image->format = SPICE_BITMAP_FMT_RGBA;
+        cache_image->width = surf->sizlBitmap.cx;
+        cache_image->height = surf->sizlBitmap.cy;
+        ImageCacheAdd(pdev, cache_image);
+        RingAdd(pdev, &pdev->cache_image_lru, &cache_image->lru_link);
+        DEBUG_PRINT((pdev, 11, "%s: ImageCacheAdd %u\n", __FUNCTION__, key));
+    }
+
+    if (cache_image) {
+        width = surf->sizlBitmap.cx;
+        height = surf->sizlBitmap.cy;
+        src = surf->pvScan0;
+    } else {
+        src = (UINT8 *)surf->pvScan0 + area->top * surf->lDelta + (area->left << 2);
+        area->left = 0;
+        area->right = width;
+        area->top = 0;
+        area->bottom = height;
+    }
+
+    if (!(image_res = GetQuicImage(pdev, surf, NULL, !!cache_image, width, height,
+                                   SPICE_BITMAP_FMT_RGBA, src, width << 2, key))) {
+        image_res = GetBitmapImage(pdev, surf, NULL, !!cache_image, width, height,
+                                   SPICE_BITMAP_FMT_RGBA, src, width << 2, key);
+    }
+    internal = (InternalImage *)image_res->res;
+    if ((internal->cache = cache_image)) {
+        DEBUG_PRINT((pdev, 11, "%s: cache_me %u\n", __FUNCTION__, key));
+        cache_image->image = internal;
+        if (RingItemIsLinked(&cache_image->lru_link)) {
+            RingRemove(pdev, &cache_image->lru_link);
+        }
+    }
+    *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+    DrawableAddRes(pdev, drawable, image_res);
+    RELEASE_RES(pdev, image_res);
+    return TRUE;
+}
+
+BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys)
+{
+    InternalImage *internal;
+    CacheImage *cache_image;
+    Resource *image_res;
+
+    if ((cache_image = ImageCacheGetByKey(pdev, hash_key, FALSE, 0, 0, 0)) &&
+        (internal = cache_image->image)) {
+        cache_image->hits++;
+        *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+        image_res = (Resource *)((UINT8 *)internal - sizeof(Resource));
+        DrawableAddRes(pdev, drawable, image_res);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, QXLQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
+                BOOL invers, LONG width, LONG height, INT32 *surface_dest)
+{
+    QXLRect area;
+
+    if (!mask) {
+        qxl_mask->bitmap = 0;
+        return TRUE;
+    }
+
+    ASSERT(pdev, pos && qxl_mask && drawable);
+    if (mask->iBitmapFormat != BMF_1BPP) {
+        DEBUG_PRINT((pdev, 0, "%s: bitmap format err\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    qxl_mask->flags = invers ? SPICE_MASK_FLAGS_INVERS : 0;
+
+    area.left = pos->x;
+    area.right = area.left + width;
+    area.top = pos->y;
+    area.bottom = area.top + height;
+
+    if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE,
+                     surface_dest)) {
+        qxl_mask->pos.x = area.left;
+        qxl_mask->pos.y = area.top;
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void FreeBuf(PDev *pdev, Resource *res)
+{
+    ONDBG(pdev->num_buf_pages--);
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+}
+
+UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size)
+{
+    Resource *buf_res;
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    if (size > PAGE_SIZE - sizeof(Resource)) {
+        DEBUG_PRINT((pdev, 0, "%s: size err\n", __FUNCTION__));
+        return NULL;
+    }
+
+    buf_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + size);
+    ONDBG(pdev->num_buf_pages++);
+    buf_res->refs = 1;
+    buf_res->free = FreeBuf;
+    RESOURCE_TYPE(buf_res, RESOURCE_TYPE_BUF);
+
+    *buf_phys = PA(pdev, buf_res->res, pdev->main_mem_slot);
+    DrawableAddRes(pdev, drawable, buf_res);
+    RELEASE_RES(pdev, buf_res);
+    return buf_res->res;
+}
+
+#ifdef UPDATE_CMD
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
+{
+    QXLCommand *cmd;
+    QXLOutput *output;
+    QXLUpdateCmd *updat_cmd;
+
+    DEBUG_PRINT((pdev, 12, "%s UPDATE_CMD\n", __FUNCTION__));
+
+    output = (QXLOutput *)AllocMem(pdev, sizeof(QXLOutput) + sizeof(QXLUpdateCmd));
+    RESOURCE_TYPE(output, RESOURCE_TYPE_UPDATE);
+    output->num_res = 0;
+    updat_cmd = (QXLUpdateCmd *)output->data;
+    updat_cmd->release_info.id = (UINT64)output;
+    ONDBG(pdev->num_outputs++); //todo: atomic
+
+    CopyRect(&updat_cmd->area, area);
+    updat_cmd->update_id = ++pdev->update_id;
+    updat_cmd->surface_id = surface_id;
+
+    EngAcquireSemaphore(pdev->cmd_sem);
+    WaitForCmdRing(pdev);
+    cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
+    cmd->type = QXL_CMD_UPDATE;
+    cmd->data = PA(pdev, updat_cmd, pdev->main_mem_slot);
+    PUSH_CMD(pdev);
+    EngReleaseSemaphore(pdev->cmd_sem);
+    do {
+#ifdef DBG
+        {
+            LARGE_INTEGER timeout; // 1 => 100 nanoseconds
+            timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
+            WAIT_FOR_EVENT(pdev, pdev->display_event, &timeout);
+            if (*pdev->dev_update_id != pdev->update_id) {
+                DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
+            }
+        }
+#else
+        WAIT_FOR_EVENT(pdev, pdev->display_event, NULL);
+#endif // DEBUG
+        mb();
+    } while (*pdev->dev_update_id != pdev->update_id);
+}
+
+#else
+
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
+{
+    DEBUG_PRINT((pdev, 12, "%s IO\n", __FUNCTION__));
+    CopyRect(pdev->update_area, area);
+    *pdev->update_surface = surface_id;
+    async_io(pdev, ASYNCABLE_UPDATE_AREA, 0);
+}
+
+#endif
+
+static _inline void add_rast_glyphs(PDev *pdev, QXLString *str, ULONG count, GLYPHPOS *glyps,
+                                    QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
+                                    UINT8 **end_ptr, int bpp, POINTL *delta, QXLPoint **str_pos)
+{
+    GLYPHPOS *glyps_end = glyps + count;
+    QXLDataChunk *chunk = *chunk_ptr;
+    UINT8 *now = *now_ptr;
+    UINT8 *end = *end_ptr;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    for (; glyps < glyps_end; glyps++) {
+        QXLRasterGlyph *glyph;
+        UINT8 *line;
+        UINT8 *end_line;
+        UINT32 stride;
+
+        if (end - now < sizeof(*glyph)) {
+            NEW_DATA_CHUNK(&pdev->num_glyphs_pages, PAGE_SIZE);
+        }
+
+        glyph = (QXLRasterGlyph *)now;
+        if (delta) {
+            if (*str_pos) {
+                glyph->render_pos.x = (*str_pos)->x + delta->x;
+                glyph->render_pos.y = (*str_pos)->y + delta->y;
+            } else {
+                glyph->render_pos.x = glyps->ptl.x;
+                glyph->render_pos.y = glyps->ptl.y;
+            }
+            *str_pos = (QXLPoint *)&glyph->render_pos;
+        } else {
+            glyph->render_pos.x = glyps->ptl.x;
+            glyph->render_pos.y = glyps->ptl.y;
+        }
+        glyph->glyph_origin.x = glyps->pgdf->pgb->ptlOrigin.x;
+        glyph->glyph_origin.y = glyps->pgdf->pgb->ptlOrigin.y;
+        glyph->width = (UINT16)glyps->pgdf->pgb->sizlBitmap.cx;
+        glyph->height = (UINT16)glyps->pgdf->pgb->sizlBitmap.cy;
+        now += sizeof(*glyph);
+        chunk->data_size += sizeof(*glyph);
+        str->data_size += sizeof(*glyph);
+        if (!glyph->height) {
+            continue;
+        }
+
+        stride = ALIGN(glyph->width * bpp, 8) >> 3;
+        end_line = (UINT8 *)glyps->pgdf->pgb->aj - stride;
+        line = (UINT8 *)glyps->pgdf->pgb->aj + stride * (glyph->height - 1);
+
+        for (; line != end_line; line -= stride) {
+            UINT8 *bits_pos = line;
+            UINT8 *bits_end = bits_pos + stride;
+
+            for (; bits_pos != bits_end; bits_pos++) {
+                UINT8 val;
+                int i;
+                if (end - now < sizeof(*bits_pos)) {
+                    NEW_DATA_CHUNK(&pdev->num_glyphs_pages, PAGE_SIZE);
+                }
+                *(UINT8 *)now = *bits_pos;
+                now += sizeof(*bits_pos);
+                chunk->data_size += sizeof(*bits_pos);
+                str->data_size += sizeof(*bits_pos);
+            }
+        }
+    }
+    *chunk_ptr = chunk;
+    *now_ptr = now;
+    *end_ptr = end;
+    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
+}
+static _inline BOOL add_glyphs(PDev *pdev, QXLString *str, ULONG count, GLYPHPOS *glyps,
+                               QXLDataChunk **chunk, UINT8 **now, UINT8 **end, POINTL *delta,
+                               QXLPoint  **str_pos)
+{
+    if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
+        add_rast_glyphs(pdev, str, count, glyps, chunk, now, end, 1, delta, str_pos);
+    } else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
+        add_rast_glyphs(pdev, str, count, glyps, chunk, now, end, 4, delta, str_pos);
+    }
+    return TRUE;
+}
+
+static void FreeSring(PDev *pdev, Resource *res)
+{
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    chunk_phys = ((QXLString *)res->res)->chunk.next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_glyphs_pages--);
+    }
+
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_glyphs_pages--);
+
+    DEBUG_PRINT((pdev, 14, "%s: done\n", __FUNCTION__));
+}
+
+
+#define TEXT_ALLOC_SIZE sizeof(Resource) + sizeof(QXLString) + 512
+
+BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str)
+{
+    Resource *str_res;
+    QXLString *qxl_str;
+    QXLDataChunk *chunk;
+    UINT8 *now;
+    UINT8 *end;
+    BOOL more;
+    static int id_QXLGetStr = 0;
+    POINTL  delta;
+    POINTL  *delta_ptr;
+    QXLPoint  *str_pos;
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+
+    str_res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, TEXT_ALLOC_SIZE);
+    ONDBG(pdev->num_glyphs_pages++);
+    str_res->refs = 1;
+    str_res->free = FreeSring;
+    RESOURCE_TYPE(str_res, RESOURCE_TYPE_SRING);
+
+    qxl_str = (QXLString *)str_res->res;
+    qxl_str->data_size = 0;
+    qxl_str->length = (UINT16)str->cGlyphs;
+    qxl_str->flags = 0;
+
+    if (font->flFontType & FO_TYPE_RASTER) {
+        qxl_str->flags = (font->flFontType & FO_GRAY16) ?   SPICE_STRING_FLAGS_RASTER_A4 :
+                         SPICE_STRING_FLAGS_RASTER_A1;
+    }
+
+    chunk = &qxl_str->chunk;
+    chunk->data_size = 0;
+    chunk->prev_chunk = 0;
+    chunk->next_chunk = 0;
+
+    now = chunk->data;
+    end = (UINT8 *)str_res + TEXT_ALLOC_SIZE;
+
+    if (str->ulCharInc) {
+        str_pos = NULL;
+        if (str->flAccel & SO_VERTICAL) {
+            delta.x = 0;
+            delta.y = (str->flAccel & SO_REVERSED) ? -(LONG)str->ulCharInc : str->ulCharInc;
+        } else {
+            delta.x = (str->flAccel & SO_REVERSED) ? -(LONG)str->ulCharInc : str->ulCharInc;
+            delta.y = 0;
+        }
+        delta_ptr = δ
+    } else {
+        delta_ptr = NULL;
+    }
+
+    STROBJ_vEnumStart(str);
+
+    do {
+        ULONG count;
+        GLYPHPOS *glyps;
+
+        if (str->pgp) {
+            count = str->cGlyphs;
+            glyps = str->pgp;
+            more = FALSE;
+        } else {
+            more = STROBJ_bEnum(str, &count, &glyps);
+
+            if (more == DDI_ERROR) {
+                goto error;
+            }
+        }
+        if (!add_glyphs(pdev, qxl_str, count, glyps, &chunk, &now, &end, delta_ptr, &str_pos)) {
+            goto error;
+        }
+
+    } while (more);
+
+    *str_phys = PA(pdev, str_res->res, pdev->main_mem_slot);
+    DrawableAddRes(pdev, drawable, str_res);
+    RELEASE_RES(pdev, str_res);
+
+    DEBUG_PRINT((pdev, 10, "%s: done size %u\n", __FUNCTION__, qxl_str->data_size));
+    return TRUE;
+
+    error:
+    FreeSring(pdev, str_res);
+    DEBUG_PRINT((pdev, 10, "%s: error\n", __FUNCTION__));
+    return FALSE;
+}
+
+QXLCursorCmd *CursorCmd(PDev *pdev)
+{
+    QXLCursorCmd *cursor_cmd;
+    QXLOutput *output;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLCursorCmd));
+    output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_CURSOR);
+    cursor_cmd = (QXLCursorCmd *)output->data;
+    cursor_cmd->release_info.id = (UINT64)output;
+    ONDBG(pdev->num_outputs++); //todo: atomic
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+    return cursor_cmd;
+}
+
+void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd)
+{
+    QXLCommand *cmd;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    EngAcquireSemaphore(pdev->cursor_sem);
+    WaitForCursorRing(pdev);
+    cmd = SPICE_RING_PROD_ITEM(pdev->cursor_ring);
+    cmd->type = QXL_CMD_CURSOR;
+    cmd->data = PA(pdev, cursor_cmd, pdev->main_mem_slot);
+    PUSH_CURSOR_CMD(pdev);
+    EngReleaseSemaphore(pdev->cursor_sem);
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+}
+
+typedef struct InternalCursor {
+    struct InternalCursor *next;
+    RingItem lru_link;
+    HSURF   hsurf;
+    ULONG   unique;
+    QXLCursor cursor;
+} InternalCursor;
+
+
+#define CURSOR_HASH_VAL(hsurf) (HSURF_HASH_VAL(hsurf) & CURSOR_HASH_NASKE)
+
+static void CursorCacheRemove(PDev *pdev, InternalCursor *cursor)
+{
+    InternalCursor **internal;
+    BOOL found = FALSE;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    ASSERT(pdev, cursor->unique);
+    internal = &pdev->cursor_cache[CURSOR_HASH_VAL(cursor->hsurf)];
+
+    while (*internal) {
+        if ((*internal)->hsurf == cursor->hsurf) {
+            if ((*internal) == cursor) {
+                *internal = cursor->next;
+                found = TRUE;
+                break;
+            }
+            DEBUG_PRINT((pdev, 0, "%s: unexpected\n", __FUNCTION__));
+        }
+        internal = &(*internal)->next;
+    }
+
+    RingRemove(pdev, &cursor->lru_link);
+    RELEASE_RES(pdev, (Resource *)((UINT8 *)cursor - sizeof(Resource)));
+    pdev->num_cursors--;
+
+    if (!found) {
+        DEBUG_PRINT((pdev, 0, "%s: Error: cursor 0x%x isn't in cache \n", __FUNCTION__, cursor));
+        ASSERT(pdev, FALSE);
+    } else {
+        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
+    }
+
+}
+
+static void CursorCacheClear(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
+    while (pdev->num_cursors) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->cursors_lru));
+        CursorCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->cursors_lru),
+                                            InternalCursor, lru_link));
+    }
+}
+
+static void CursorCacheAdd(PDev *pdev, InternalCursor *cursor)
+{
+    int key;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+    if (!cursor->unique) {
+        return;
+    }
+
+    if (pdev->num_cursors == CURSOR_CACHE_SIZE) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->cursors_lru));
+        CursorCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->cursors_lru),
+                                            InternalCursor, lru_link));
+    }
+
+    key = CURSOR_HASH_VAL(cursor->hsurf);
+    cursor->next = pdev->cursor_cache[key];
+    pdev->cursor_cache[key] = cursor;
+
+    RingAdd(pdev, &pdev->cursors_lru, &cursor->lru_link);
+    GET_RES((Resource *)((UINT8 *)cursor - sizeof(Resource)));
+    pdev->num_cursors++;
+}
+
+static InternalCursor *CursorCacheGet(PDev *pdev, HSURF hsurf, UINT32 unique)
+{
+    InternalCursor **internal;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    if (!unique) {
+        return NULL;
+    }
+
+    internal = &pdev->cursor_cache[CURSOR_HASH_VAL(hsurf)];
+    while (*internal) {
+        InternalCursor *now = *internal;
+        if (now->hsurf == hsurf) {
+            if (now->unique == unique) {
+                RingRemove(pdev, &now->lru_link);
+                RingAdd(pdev, &pdev->cursors_lru, &now->lru_link);
+                return now;
+            }
+            CursorCacheRemove(pdev, now);
+            break;
+        }
+        internal = &now->next;
+    }
+    return NULL;
+}
+
+static void FreeCursor(PDev *pdev, Resource *res)
+{
+    QXLPHYSICAL chunk_phys;
+
+    DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+    chunk_phys = ((InternalCursor *)res->res)->cursor.chunk.next_chunk;
+    while (chunk_phys) {
+        QXLDataChunk *chunk = (QXLDataChunk *)VA(pdev, chunk_phys, pdev->main_mem_slot);
+        chunk_phys = chunk->next_chunk;
+        FreeMem(pdev, MSPACE_TYPE_DEVRAM, chunk);
+        ONDBG(pdev->num_cursor_pages--);
+    }
+
+    FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
+    ONDBG(pdev->num_cursor_pages--);
+
+    DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+
+typedef struct NewCursorInfo {
+    QXLCursor *cursor;
+    QXLDataChunk *chunk;
+    UINT8 *now;
+    UINT8 *end;
+} NewCursorInfo;
+
+#define CURSOR_ALLOC_SIZE (PAGE_SIZE << 1)
+
+static BOOL GetCursorCommon(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
+                            UINT16 type, NewCursorInfo *info, BOOL *in_cach)
+{
+    InternalCursor *internal;
+    QXLCursor *cursor;
+    Resource *res;
+    ULONG unique;
+    UINT8 *src;
+    UINT8 *src_end;
+    int line_size;
+    HSURF bitmap = 0;
+    SURFOBJ *local_surf = surf;
+
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    *in_cach = FALSE;
+    unique = (surf->fjBitmap & BMF_DONTCACHE) ? 0 : surf->iUniq;
+
+    if ((internal = CursorCacheGet(pdev, surf->hsurf, unique))) {
+        res = (Resource *)((UINT8 *)internal - sizeof(Resource));
+        CursorCmdAddRes(pdev, cmd, res);
+        cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
+        *in_cach = TRUE;
+        return TRUE;
+    }
+
+    if (surf->iType != STYPE_BITMAP) {
+        RECTL dest_rect;
+        POINTL src_pos;
+        ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP || surf->iBitmapFormat == BMF_16BPP);
+
+        /* copying the surface to a bitmap */
+
+        bitmap = (HSURF)EngCreateBitmap(surf->sizlBitmap, surf->lDelta, surf->iBitmapFormat,
+                                        0, NULL);
+        if (!bitmap) {
+            DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
+            return FALSE;
+        }
+
+        if (!EngAssociateSurface(bitmap, pdev->eng, 0)) {
+            DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
+            goto error;
+        }
+
+        if (!(local_surf = EngLockSurface(bitmap))) {
+            DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__));
+            goto error;
+        }
+
+        dest_rect.top = 0;
+        dest_rect.left = 0;
+        dest_rect.bottom = surf->sizlBitmap.cy;
+        dest_rect.right = surf->sizlBitmap.cx;
+
+        src_pos.x = 0;
+        src_pos.y = 0;
+            
+        if (!BitBltFromDev(pdev, surf, local_surf, NULL, NULL, NULL, &dest_rect, src_pos,
+                           NULL, NULL, NULL, 0xcccc)) {
+            goto error;
+        }
+    }
+
+    ASSERT(pdev, sizeof(Resource) + sizeof(InternalCursor) < CURSOR_ALLOC_SIZE);
+    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, CURSOR_ALLOC_SIZE);
+    ONDBG(pdev->num_cursor_pages++);
+    res->refs = 1;
+    res->free = FreeCursor;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
+
+    internal = (InternalCursor *)res->res;
+    internal->hsurf = surf->hsurf;
+    internal->unique = unique;
+    RingItemInit(&internal->lru_link);
+
+    cursor = info->cursor = &internal->cursor;
+    cursor->header.type = type;
+    cursor->header.unique = unique ? ++pdev->last_cursor_id : 0;
+    cursor->header.width = (UINT16)local_surf->sizlBitmap.cx;
+    cursor->header.height = (type == SPICE_CURSOR_TYPE_MONO) ? (UINT16)local_surf->sizlBitmap.cy >> 1 :
+                            (UINT16)local_surf->sizlBitmap.cy;
+    cursor->header.hot_spot_x = (UINT16)hot_x;
+    cursor->header.hot_spot_y = (UINT16)hot_y;
+
+    cursor->data_size = 0;
+
+    info->chunk = &cursor->chunk;
+    info->chunk->data_size = 0;
+    info->chunk->prev_chunk = 0;
+    info->chunk->next_chunk = 0;
+
+    info->now = info->chunk->data;
+    info->end = (UINT8 *)res + CURSOR_ALLOC_SIZE;
+
+    switch (type) {
+    case SPICE_CURSOR_TYPE_ALPHA:
+    case SPICE_CURSOR_TYPE_COLOR32:
+        line_size = cursor->header.width << 2;
+        break;
+    case SPICE_CURSOR_TYPE_MONO:
+        line_size = ALIGN(cursor->header.width, 8) >> 3;
+        break;
+    case SPICE_CURSOR_TYPE_COLOR4:
+        line_size = ALIGN(cursor->header.width, 2) >> 1;
+        break;
+    case SPICE_CURSOR_TYPE_COLOR8:
+        line_size = cursor->header.width;
+        break;
+    case SPICE_CURSOR_TYPE_COLOR16:
+        line_size = cursor->header.width << 1;
+        break;
+    case SPICE_CURSOR_TYPE_COLOR24:
+        line_size = cursor->header.width * 3;
+        break;
+    }
+
+    cursor->data_size = line_size * local_surf->sizlBitmap.cy;
+    src = local_surf->pvScan0;
+    src_end = src + (local_surf->lDelta * local_surf->sizlBitmap.cy);
+    for (; src != src_end; src += local_surf->lDelta) {
+        PutBytes(pdev, &info->chunk, &info->now, &info->end, src, line_size,
+                 &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+    }
+
+    CursorCacheAdd(pdev, internal);
+    CursorCmdAddRes(pdev, cmd, res);
+    RELEASE_RES(pdev, res);
+    cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
+    DEBUG_PRINT((pdev, 11, "%s: done, data_size %u\n", __FUNCTION__, cursor->data_size));
+
+    if (local_surf != surf) {
+        EngUnlockSurface(local_surf);
+        EngDeleteSurface(bitmap);
+    }
+
+    return TRUE;
+error:
+    if (bitmap) {
+        ASSERT(pdev, local_surf != surf);
+        EngDeleteSurface(bitmap);
+    }
+
+    return FALSE;
+}
+
+BOOL GetAlphaCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf)
+{
+    NewCursorInfo info;
+    BOOL ret;
+    BOOL in_cache;
+
+    ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP);
+    ASSERT(pdev, surf->sizlBitmap.cx > 0 && surf->sizlBitmap.cy > 0);
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ret = GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, SPICE_CURSOR_TYPE_ALPHA, &info, &in_cache);
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+    return ret;
+}
+
+BOOL GetMonoCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf)
+{
+    NewCursorInfo info;
+    BOOL ret;
+    BOOL in_cache;
+
+    ASSERT(pdev, surf->iBitmapFormat == BMF_1BPP);
+    ASSERT(pdev, surf->sizlBitmap.cy > 0 && (surf->sizlBitmap.cy & 1) == 0);
+    ASSERT(pdev, surf->sizlBitmap.cx > 0);
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    ret = GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, SPICE_CURSOR_TYPE_MONO, &info, &in_cache);
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+    return ret;
+}
+
+BOOL GetColorCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
+                    SURFOBJ *mask, XLATEOBJ *color_trans)
+{
+    NewCursorInfo info;
+    UINT16 type;
+    BOOL in_cache;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    ASSERT(pdev, surf && mask);
+    ASSERT(pdev, surf->sizlBitmap.cx > 0 && surf->sizlBitmap.cy);
+
+    if ( mask->sizlBitmap.cx != surf->sizlBitmap.cx ||
+         mask->sizlBitmap.cy != surf->sizlBitmap.cy * 2 ) {
+        DEBUG_PRINT((pdev, 0, "%s: err mask size, surf(%d, %d) mask(%d, %d)\n",
+                     __FUNCTION__,
+                     surf->sizlBitmap.cx,
+                     surf->sizlBitmap.cy,
+                     mask->sizlBitmap.cx,
+                     mask->sizlBitmap.cy));
+        return FALSE;
+    }
+
+    switch (surf->iBitmapFormat) {
+    case BMF_32BPP:
+        type = SPICE_CURSOR_TYPE_COLOR32;
+        break;
+    case BMF_24BPP:
+        type = SPICE_CURSOR_TYPE_COLOR24;
+        break;
+    case BMF_16BPP:
+        type = SPICE_CURSOR_TYPE_COLOR16;
+        break;
+    case BMF_8BPP:
+        type = SPICE_CURSOR_TYPE_COLOR8;
+        break;
+    case BMF_4BPP:
+        type = SPICE_CURSOR_TYPE_COLOR4;
+        break;
+    default:
+        DEBUG_PRINT((pdev, 0, "%s: unexpected format\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (!GetCursorCommon(pdev, cmd, hot_x, hot_y, surf, type, &info, &in_cache)) {
+        return FALSE;
+    }
+
+    if (!in_cache) {
+        int line_size;
+        UINT8 *src;
+        UINT8 *src_end;
+
+        if (type == SPICE_CURSOR_TYPE_COLOR8) {
+
+            DEBUG_PRINT((pdev, 8, "%s: SPICE_CURSOR_TYPE_COLOR8\n", __FUNCTION__));
+            ASSERT(pdev, color_trans);
+            ASSERT(pdev, color_trans->pulXlate);
+            ASSERT(pdev, color_trans->flXlate & XO_TABLE);
+            ASSERT(pdev, color_trans->cEntries == 256);
+
+            if (pdev->bitmap_format == BMF_32BPP) {
+                PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)color_trans->pulXlate,
+                         256 << 2, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+            } else {
+                int i;
+
+                for (i = 0; i < 256; i++) {
+                    UINT32 ent = _16bppTo32bpp(color_trans->pulXlate[i]);
+                    PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)&ent,
+                             4, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+                }
+            }
+            info.cursor->data_size += 256 << 2;
+        } else if (type == SPICE_CURSOR_TYPE_COLOR4) {
+
+            ASSERT(pdev, color_trans);
+            ASSERT(pdev, color_trans->pulXlate);
+            ASSERT(pdev, color_trans->flXlate & XO_TABLE);
+            ASSERT(pdev, color_trans->cEntries == 16);
+
+            if (pdev->bitmap_format == BMF_32BPP) {
+                PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)color_trans->pulXlate,
+                         16 << 2, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+            } else {
+                int i;
+
+                for (i = 0; i < 16; i++) {
+                    UINT32 ent = _16bppTo32bpp(color_trans->pulXlate[i]);
+                    PutBytes(pdev, &info.chunk, &info.now, &info.end, (UINT8 *)&ent,
+                             4, &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+                }
+            }
+            info.cursor->data_size += 16 << 2;
+        }
+
+        ASSERT(pdev, mask->iBitmapFormat == BMF_1BPP);
+        ASSERT(pdev, mask->iType == STYPE_BITMAP);
+
+        line_size = ALIGN(mask->sizlBitmap.cx, 8) >> 3;
+        info.cursor->data_size += line_size * surf->sizlBitmap.cy;
+        src = mask->pvScan0;
+        src_end = src + (mask->lDelta * surf->sizlBitmap.cy);
+
+        for (; src != src_end; src += mask->lDelta) {
+            PutBytes(pdev, &info.chunk, &info.now, &info.end, src, line_size,
+                     &pdev->num_cursor_pages, PAGE_SIZE, FALSE);
+        }
+    }
+
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd)
+{
+    Resource *res;
+    InternalCursor *internal;
+    QXLCursor *cursor;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, sizeof(Resource) + sizeof(InternalCursor) < PAGE_SIZE);
+
+    res = (Resource *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(Resource) + sizeof(InternalCursor));
+    ONDBG(pdev->num_cursor_pages++);
+    res->refs = 1;
+    res->free = FreeCursor;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
+
+    internal = (InternalCursor *)res->res;
+    internal->hsurf = NULL;
+    internal->unique = 0;
+    RingItemInit(&internal->lru_link);
+
+    cursor = &internal->cursor;
+    cursor->header.type = SPICE_CURSOR_TYPE_MONO;
+    cursor->header.unique = 0;
+    cursor->header.width = 0;
+    cursor->header.height = 0;
+    cursor->header.hot_spot_x = 0;
+    cursor->header.hot_spot_y = 0;
+    cursor->data_size = 0;
+    cursor->chunk.data_size = 0;
+
+    CursorCmdAddRes(pdev, cmd, res);
+    RELEASE_RES(pdev, res);
+    cmd->u.set.shape = PA(pdev, &internal->cursor, pdev->main_mem_slot);
+
+    DEBUG_PRINT((pdev, 8, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+void ReleaseCacheDeviceMemoryResources(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 0, "%s \n", __FUNCTION__));
+    PaletteCacheClear(pdev);
+    CursorCacheClear(pdev);
+}
+
+static void quic_usr_error(QuicUsrContext *usr, const char *format, ...)
+{
+    QuicData *quic_data = (QuicData *)usr;
+    va_list ap;
+
+    va_start(ap, format);
+    DebugPrintV(quic_data->pdev, format, ap);
+    va_end(ap);
+    EngDebugBreak();
+}
+
+static void quic_usr_warn(QuicUsrContext *usr, const char *format, ...)
+{
+    QuicData *quic_data = (QuicData *)usr;
+    va_list ap;
+
+    va_start(ap, format);
+    DebugPrintV(quic_data->pdev, format, ap);
+    va_end(ap);
+}
+
+static void *quic_usr_malloc(QuicUsrContext *usr, int size)
+{
+    return EngAllocMem(0, size, ALLOC_TAG);
+}
+
+static void quic_usr_free(QuicUsrContext *usr, void *ptr)
+{
+    EngFreeMem(ptr);
+}
+
+BOOL ResInit(PDev *pdev)
+{
+    QuicData *usr_data;
+
+    if (!(usr_data = EngAllocMem(FL_ZERO_MEMORY, sizeof(QuicData), ALLOC_TAG))) {
+        return FALSE;
+    }
+    usr_data->user.error = quic_usr_error;
+    usr_data->user.warn = quic_usr_warn;
+    usr_data->user.info = quic_usr_warn;
+    usr_data->user.malloc = quic_usr_malloc;
+    usr_data->user.free = quic_usr_free;
+    usr_data->user.more_space = quic_usr_more_space;
+    usr_data->user.more_lines = quic_usr_more_lines;
+    usr_data->pdev = pdev;
+    if (!(usr_data->quic = quic_create(&usr_data->user))) {
+        EngFreeMem(usr_data);
+        return FALSE;
+    }
+    pdev->quic_data = usr_data;
+    pdev->quic_data_sem = EngCreateSemaphore();
+    if (!pdev->quic_data_sem) {
+        PANIC(pdev, "quic_data_sem creation failed\n");
+    }
+    pdev->io_sem = EngCreateSemaphore();
+    if (!pdev->io_sem) {
+        PANIC(pdev, "io_sem creation failed\n");
+    }
+
+    return TRUE;
+}
+
+void ResDestroy(PDev *pdev)
+{
+    QuicData *usr_data = pdev->quic_data;
+    quic_destroy(usr_data->quic);
+    EngDeleteSemaphore(pdev->quic_data_sem);
+    EngFreeMem(usr_data);
+}
+
+void ResInitGlobals()
+{
+    image_id_sem = EngCreateSemaphore();
+    if (!image_id_sem) {
+        EngDebugBreak();
+    }
+    quic_init();
+}
+
+void ResDestroyGlobals()
+{
+    EngDeleteSemaphore(image_id_sem);
+    image_id_sem = NULL;
+}
+
+#ifndef _WIN64
+
+void CheckAndSetSSE2()
+{
+    _asm
+    {
+        mov eax, 0x0000001
+        cpuid
+        and edx, 0x4000000
+        mov have_sse2, edx
+    }
+
+    if (have_sse2) {
+        have_sse2 = TRUE;
+    }
+}
+
+#endif
diff --git a/xddm/display/res.h b/xddm/display/res.h
new file mode 100644
index 0000000..d69986e
--- /dev/null
+++ b/xddm/display/res.h
@@ -0,0 +1,77 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _H_RES
+#define _H_RES
+
+#include "qxldd.h"
+
+UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id);
+
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id);
+void PushDrawable(PDev *pdev, QXLDrawable *drawable);
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
+
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type);
+void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type);
+BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path);
+BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, QXLQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
+                BOOL invers, LONG width, LONG height, INT32 *surface_dest);
+BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, QXLBrush *qxl_brush,
+                            BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+                            QXLRect *surface_rect);
+BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
+                  QXLRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+                  INT32 *surface_dest);
+BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys);
+BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
+                       QXLRect *area, INT32 *surface_dest);
+BOOL QXLCheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans);
+UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size);
+BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str);
+
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id);
+
+QXLCursorCmd *CursorCmd(PDev *pdev);
+void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd);
+
+BOOL GetAlphaCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf);
+BOOL GetColorCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf,
+                    SURFOBJ *mask, XLATEOBJ *color_trans);
+BOOL GetMonoCursor(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_y, SURFOBJ *surf);
+BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd);
+
+BOOL ResInit(PDev *pdev);
+void ResDestroy(PDev *pdev);
+void ResInitGlobals();
+void ResDestroyGlobals();
+#ifndef _WIN64
+void CheckAndSetSSE2();
+#endif
+void EmptyReleaseRing(PDev *pdev);
+void InitDeviceMemoryResources(PDev *pdev);
+void ReleaseCacheDeviceMemoryResources(PDev *pdev);
+
+#endif
diff --git a/xddm/display/rop.c b/xddm/display/rop.c
new file mode 100644
index 0000000..9fb3527
--- /dev/null
+++ b/xddm/display/rop.c
@@ -0,0 +1,1778 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "os_dep.h"
+#include "qxldd.h"
+#include "utils.h"
+#include "res.h"
+#include "rop.h"
+#include "surface.h"
+
+
+enum ROP3type {
+    ROP3_TYPE_ERR,
+    ROP3_TYPE_FILL,
+    ROP3_TYPE_OPAQUE,
+    ROP3_TYPE_COPY,
+    ROP3_TYPE_BLEND,
+    ROP3_TYPE_BLACKNESS,
+    ROP3_TYPE_WHITENESS,
+    ROP3_TYPE_INVERS,
+    ROP3_TYPE_ROP3,
+    ROP3_TYPE_NOP,
+};
+
+
+ROP3Info rops2[] = {
+    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_BLACKNESS, SPICE_ROPD_OP_BLACKNESS},                     //0
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR |
+                                                               SPICE_ROPD_INVERS_RES},        //DPon
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                               SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_AND},  //DPna
+    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_BRUSH |
+                                                    SPICE_ROPD_OP_PUT},                       //Pn
+    {QXL_EFFECT_BLACKNESS_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                              SPICE_ROPD_INVERS_DEST | SPICE_ROPD_OP_AND},    //PDna
+    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST, ROP3_TYPE_INVERS, SPICE_ROPD_OP_INVERS},            //Dn
+    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR},    //DPx
+    {QXL_EFFECT_BLACKNESS_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                              SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES},     //DPan
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_AND},       //DPa
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR |
+                                               SPICE_ROPD_INVERS_RES},                        //DPxn
+    {QXL_EFFECT_NOP, ROP3_DEST, ROP3_TYPE_NOP, 0},                                            //D
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                            SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_OR},      //DPno
+    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_PUT},                       //P
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_DEST |
+                                               SPICE_ROPD_OP_OR},                             //PDno
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR},        //DPo
+    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_WHITENESS, SPICE_ROPD_OP_WHITENESS},                     //1
+};
+
+
+ROP3Info rops3[] = {
+
+    //todo: update rop3 effect
+
+    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_BLACKNESS, 0},                                 //0
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x01},                             //DPSoon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x02},                             //DPSona
+                                                                                    //PSon
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_OR |
+                                               SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x04},                             //SDPona
+                                                                                    //DPon
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_OR |
+                                               SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x06},                             //PDSxnon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x07},                             //PDSaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x08},                             //SDPnaa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x09},                             //PDSxon
+                                                                                    //DPna
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                                                   SPICE_ROPD_INVERS_BRUSH |
+                                                                   SPICE_ROPD_OP_AND},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0b},                             //PSDnaon
+                                                                                    //SPna
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_INVERS_BRUSH |
+                                                                 SPICE_ROPD_OP_AND },
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0d},                             //PDSnaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x0e},                             //PDSonon
+                                                                                    //Pn
+    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_PUT},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x10},                             //PDSona
+                                                                                    //DSon
+    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_OR |
+                                             SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x12},                             //SDPxnon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x13},                             //SDPaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x14},                             //DPSxnon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x15},                             //DPSaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x16},                             //PSDPSanaxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x17},                             //SSPxDSxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x18},                             //SPxPDxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x19},                             //SDPSanaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1a},                             //PDSPaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1b},                             //SDPSxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1c},                             //PSDPaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1d},                             //DSPDxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1e},                             //PDSox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x1f},                             //PDSoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x20},                             //DPSnaa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x21},                             //SDPxon
+                                                                                    //DSna
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_INVERS_SRC |
+                                                                   SPICE_ROPD_OP_AND},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x23},                             //SPDnaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x24},                             //SPxDSxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x25},                             //PDSPanaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x26},                             //SDPSaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x27},                             //SDPSxnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x28},                             //DPSxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x29},                             //PSDPSaoxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2a},                             //DPSana
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2b},                             //SSPxPDxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2c},                             //SPDSoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2d},                             //PSDnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2e},                             //PSDPxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x2f},                             //PSDnoan
+                                                                                    //PSna
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_INVERS_SRC |
+                                                                 SPICE_ROPD_OP_AND},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x31},                             //SDPnaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x32},                             //SDPSoox
+    {QXL_EFFECT_OPAQUE, ROP3_SRC, ROP3_TYPE_COPY, SPICE_ROPD_INVERS_SRC |
+                                                  SPICE_ROPD_OP_PUT},               //Sn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x34},                             //SPDSaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x35},                             //SPDSxnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x36},                             //SDPox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x37},                             //SDPoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x38},                             //PSDPoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x39},                             //SPDnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3a},                             //SPDSxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3b},                             //SPDnoan
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_XOR},//PSx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3d},                             //SPDSonox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x3e},                             //SPDSnaox
+                                                                                    //PSan
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_AND |
+                                                                 SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x40},                             //PSDnaa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x41},                             //DPSxon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x42},                             //SDxPDxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x43},                             //SPDSanaxn
+                                                                                    //SDna
+    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_INVERS_DEST |
+                                                              SPICE_ROPD_OP_AND},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x45},                             //DPSnaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x46},                             //DSPDaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x47},                             //PSDPxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x48},                             //SDPxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x49},                             //PDSPDaoxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4a},                             //DPSDoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4b},                             //PDSnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4c},                             //SDPana
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4d},                             //SSPxDSxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4e},                             //PDSPxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x4f},                             //PDSnoan
+                                                                                    //PDna
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_INVERS_DEST |
+                                                               SPICE_ROPD_OP_AND},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x51},                             //DSPnaon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x52},                             //DPSDaox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x53},                             //SPDSxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x54},                             //DPSonon
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST, ROP3_TYPE_INVERS, 0},                        //Dn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x56},                             //DPSox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x57},                             //DPSoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x58},                             //PDSPoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x59},                             //DPSnox
+    {QXL_EFFECT_REVERT_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR},
+                                                                                    //DPx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5b},                             //DPSDonox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5c},                             //DPSDxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5d},                             //DPSnoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x5e},                             //DPSDnaox
+                                                                                    //DPan
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_AND |
+                                                               SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x60},                             //PDSxa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x61},                             //DSPDSaoxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x62},                             //DSPDoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x63},                             //SDPnox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x64},                             //SDPSoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x65},                             //DSPnox
+    {QXL_EFFECT_REVERT_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
+                                                     SPICE_ROPD_OP_XOR},            //DSx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x67},                             //SDPSonox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x68},                             //DSPDSonoxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x69},                             //PDSxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6a},                             //DPSax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6b},                             //PSDPSoaxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6c},                             //SDPax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6d},                             //PDSPDoaxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6e},                             //SDPSnoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x6f},                             //PDSxnan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x70},                             //PDSana
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x71},                             //SSDxPDxaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x72},                             //SDPSxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x73},                             //SDPnoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x74},                             //DSPDxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x75},                             //DSPnoan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x76},                             //SDPSnaox
+                                                                                    //DSan
+    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_AND |
+                                                              SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x78},                             //PDSax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x79},                             //DSPDSoaxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7a},                             //DPSDnoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7b},                             //SDPxnan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7c},                             //SPDSnoax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7d},                             //DPSxnan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7e},                             //SPxDSxo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x7f},                             //DPSaan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x80},                             //DPSaa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x81},                             //SPxDSxon
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x82},                             //DPSxna
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x83},                             //SPDSnoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x84},                             //SDPxna
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x85},                             //PDSPnoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x86},                             //DSPDSoaxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x87},                             //PDSaxn
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
+                                                  SPICE_ROPD_OP_AND},               //DSa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x89},                             //SDPSnaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8a},                             //DSPnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8b},                             //DSPDxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8c},                             //SDPnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8d},                             //SDPSxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8e},                             //SSDxPDxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x8f},                             //PDSanan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x90},                             //PDSxna
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x91},                             //SDPSnoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x92},                             //DPSDPoaxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x93},                             //SPDaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x94},                             //PSDPSoaxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x95},                             //DPSaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x96},                             //DPSxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x97},                             //PSDPSonoxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x98},                             //SDPSonoxn
+                                                                                    //DSxn
+    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND, SPICE_ROPD_OP_XOR |
+                                                              SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9a},                             //DPSnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9b},                             //SDPSoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9c},                             //SPDnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9d},                             //DSPDoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9e},                             //DSPDSaoxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0x9f},                             //PDSxan
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                                    SPICE_ROPD_OP_AND},             //DPa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa1},                             //PDSPnaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa2},                             //DPSnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa3},                             //DPSDxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa4},                             //PDSPonoxn
+                                                                                    //PDxn
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_XOR |
+                                                               SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa6},                             //DSPnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa7},                             //PDSPoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa8},                             //DPSoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xa9},                             //DPSoxn
+    {QXL_EFFECT_NOP, ROP3_DEST, ROP3_TYPE_NOP, 0},                                  //D
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xab},                             //DPSono
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xac},                             //SPDSxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xad},                             //DPSDaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xae},                             //DSPnao
+                                                                                    //DPno
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                                    SPICE_ROPD_INVERS_BRUSH | SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb0},                             //PDSnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb1},                             //PDSPxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb2},                             //SSPxDSxox
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb3},                             //SDPanan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb4},                             //PSDnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb5},                             //DPSDoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb6},                             //DPSDPaoxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb7},                             //SDPxan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb8},                             //PSDPxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xb9},                             //DSPDaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xba},                             //DPSnao
+                                                                                    //DSno
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
+                                                       SPICE_ROPD_INVERS_SRC | SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbc},                             //SPDSanax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbd},                             //SDxPDxan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbe},                             //DPSxo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xbf},                             //DPSano
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_AND},//PSa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc1},                             //SPDSnaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc2},                             //SPDSonoxn
+                                                                                    //PSxn
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_XOR |
+                                                                 SPICE_ROPD_INVERS_RES},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc4},                             //SPDnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc5},                             //SPDSxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc6},                             //SDPnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc7},                             //PSDPoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc8},                             //SDPoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xc9},                             //SPDoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xca},                             //DPSDxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xcb},                             //SPDSaoxn
+    {QXL_EFFECT_OPAQUE, ROP3_SRC, ROP3_TYPE_COPY, SPICE_ROPD_OP_PUT},                     //S
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xcd},                             //SDPono
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xce},                             //SDPnao
+                                                                                    //SPno
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE,
+                                               SPICE_ROPD_INVERS_BRUSH |
+                                               SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd0},                             //PSDnoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd1},                             //PSDPxoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd2},                             //PDSnax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd3},                             //SPDSoaxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd4},                             //SSPxPDxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd5},                             //DPSanan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd6},                             //PSDPSaoxx
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd7},                             //DPSxan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd8},                             //PDSPxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xd9},                             //SDPSaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xda},                             //DPSDanax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdb},                             //SPxDSxan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdc},                             //SPDnao
+                                                                                    //SDno
+    {QXL_EFFECT_BLEND, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
+                                             SPICE_ROPD_INVERS_DEST |
+                                             SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xde},                             //SDPxo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xdf},                             //SDPano
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe0},                             //PDSoa
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe1},                             //PDSoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe2},                             //DSPDxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe3},                             //PSDPaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe4},                             //SDPSxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe5},                             //PDSPaoxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe6},                             //SDPSanax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe7},                             //SPxPDxan
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe8},                             //SSPxDSxax
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xe9},                             //DSPDSanaxxn
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xea},                             //DPSao
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xeb},                             //DPSxno
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xec},                             //SDPao
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xed},                             //SDPxno
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_SRC | ROP3_DEST, ROP3_TYPE_BLEND,
+                                                  SPICE_ROPD_OP_OR},                //DSo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xef},                             //SDPnoo
+    {QXL_EFFECT_OPAQUE, ROP3_BRUSH, ROP3_TYPE_FILL, SPICE_ROPD_OP_PUT},                   //P
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf1},                             //PDSono
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf2},                             //PDSnao
+                                                                                    //PSno
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE,
+                                               SPICE_ROPD_INVERS_SRC |
+                                               SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf4},                             //PSDnao
+                                                                                    //PDno
+    {QXL_EFFECT_BLEND, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                               SPICE_ROPD_INVERS_DEST |
+                                               SPICE_ROPD_OP_OR},
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf6},                             //PDSxo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf7},                             //PDSano
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf8},                             //PDSao
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xf9},                             //PDSxno
+    {QXL_EFFECT_NOP_ON_DUP, ROP3_DEST | ROP3_BRUSH, ROP3_TYPE_FILL,
+                                                    SPICE_ROPD_OP_OR},              //DPo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfb},                             //DPSnoo
+    {QXL_EFFECT_OPAQUE, ROP3_SRC | ROP3_BRUSH, ROP3_TYPE_OPAQUE, SPICE_ROPD_OP_OR}, //PSo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfd},                             //PSDnoo
+    {QXL_EFFECT_BLEND, ROP3_ALL, ROP3_TYPE_ROP3, 0xfe},                             //DPSoo
+    {QXL_EFFECT_OPAQUE, 0, ROP3_TYPE_WHITENESS, 1},                                 //1
+};
+
+
+static BOOL DoFill(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush,
+                   POINTL *brush_pos, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
+                   BOOL invers_mask)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area && brush);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
+        !QXLGetMask(pdev, drawable, &drawable->u.fill.mask, mask, mask_pos, invers_mask,
+                     width, height, &drawable->surfaces_dest[1])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    drawable->u.fill.rop_descriptor = rop_info->method_data;
+
+    drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL GetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *bitmap_phys, SURFOBJ *surf,
+                      QXLRect *area, XLATEOBJ *color_trans, BOOL use_cache, INT32 *surface_dest)
+{
+    DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
+    if (surf->iType != STYPE_BITMAP) {
+        UINT32 surface_id;
+
+        ASSERT(pdev, (PDev *)surf->dhpdev == pdev);
+        surface_id =  GetSurfaceId(surf);
+        if (surface_id == drawable->surface_id) {
+            DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
+            *bitmap_phys = 0;
+            drawable->self_bitmap = TRUE;
+            drawable->self_bitmap_area = *area;
+            area->right = area->right - area->left;
+            area->left = 0;
+            area->bottom = area->bottom - area->top;
+            area->top = 0;
+            return TRUE;
+        }
+    }
+    return QXLGetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, surf,
+                        area, color_trans, NULL, use_cache, surface_dest);
+}
+
+static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
+{
+    return (scale_mode == HALFTONE) ? SPICE_IMAGE_SCALE_MODE_INTERPOLATE :
+                                      SPICE_IMAGE_SCALE_MODE_NEAREST;
+}
+
+static BOOL DoOpaque(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                     RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+                     UINT16 rop_descriptor, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask,
+                     ULONG scale_mode)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area && brush && src_rect && src);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    drawable->u.opaque.scale_mode = GdiScaleModeToQxl(scale_mode);
+    CopyRect(&drawable->u.opaque.src_area, src_rect);
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
+        !QXLGetMask(pdev, drawable, &drawable->u.opaque.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[1]) ||
+        !GetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, src,
+                   &drawable->u.opaque.src_area, color_trans, TRUE,
+                   &drawable->surfaces_dest[2])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[2], src_rect);
+
+    drawable->u.opaque.rop_descriptor = rop_descriptor;
+    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL StreamTest(PDev *pdev, UINT32 surface_id, SURFOBJ *src_surf, 
+		       XLATEOBJ *color_trans, RECTL *src_rect, RECTL *dest)
+{
+    Ring *ring = &pdev->update_trace;
+    UpdateTrace *trace = (UpdateTrace *)ring->next;
+    LONG src_pixmap_pixels = src_surf->sizlBitmap.cx * src_surf->sizlBitmap.cy;
+
+    if (src_pixmap_pixels <= 128 * 128 || 
+	/* Only handle streams on primary surface */
+	surface_id != 0) {
+        return TRUE;
+    }
+
+    for (;;) {
+        if (SameRect(dest, &trace->area) || (trace->hsurf == src_surf->hsurf &&
+                                              src_pixmap_pixels / RectSize(src_rect) > 100)) {
+            UINT32 now = *pdev->mm_clock;
+            BOOL ret;
+
+            if (now != trace->last_time && now - trace->last_time < 1000 / 5) {
+                trace->last_time = now - 1; // asumong mm clock is active so delta t == 0 is
+                                            // imposibole. frocing delata t to be at least 1.
+                if (trace->count < 20) {
+                    trace->count++;
+                    ret = TRUE;
+                } else {
+                    ret = FALSE;
+                }
+            } else {
+                trace->last_time = now;
+                trace->count = 0;
+                ret = TRUE;
+            }
+            RingRemove(pdev, (RingItem *)trace);
+            RingAdd(pdev, ring, (RingItem *)trace);
+            return ret;
+        }
+        if (trace->link.next == ring) {
+            break;
+        }
+        trace = (UpdateTrace *)trace->link.next;
+    }
+    RingRemove(pdev, (RingItem *)trace);
+    trace->area = *dest;
+    trace->last_time = *pdev->mm_clock;
+
+    if (IsUniqueSurf(src_surf, color_trans)) {
+        trace->hsurf = src_surf->hsurf;
+    } else {
+        trace->hsurf = NULL;
+    }
+    trace->count = 0;
+    RingAdd(pdev, ring, (RingItem *)trace);
+
+    return TRUE;
+}
+
+static BOOL TestSplitClips(PDev *pdev, SURFOBJ *src, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *mask)
+{
+    UINT32 width;
+    UINT32 height;
+    UINT32 src_space;
+    UINT32 clip_space = 0;
+    int more;
+
+    if (!clip || mask) {
+        return FALSE;
+    }
+
+    if (src->iType != STYPE_BITMAP) {
+        return FALSE;
+    }
+
+    width = src_rect->right - src_rect->left;
+    height = src_rect->bottom - src_rect->top;
+    src_space = width * height;
+
+    if (clip->iDComplexity == DC_RECT) {
+        width = clip->rclBounds.right - clip->rclBounds.left;
+        height = clip->rclBounds.bottom - clip->rclBounds.top;
+        clip_space = width * height;
+
+        if ((src_space / clip_space) > 1) {
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    if (clip->iMode == TC_RECTANGLES) {
+        CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
+        do {
+            RECTL *now;
+            RECTL *end;
+
+            struct {
+                ULONG  count;
+                RECTL  rects[20];
+            } buf;
+
+            more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
+            for(now = buf.rects, end = now + buf.count; now < end; now++) {
+                width = now->right - now->left;
+                height = now->bottom - now->top;
+                clip_space += width * height;
+            }
+        } while (more);
+
+        if ((src_space / clip_space) > 1) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static _inline BOOL DoPartialCopy(PDev *pdev, UINT32 surface_id, SURFOBJ *src, RECTL *src_rect,
+                                  RECTL *area_rect, RECTL *clip_rect, XLATEOBJ *color_trans,
+                                  ULONG scale_mode, UINT16 rop_descriptor)
+{
+    QXLDrawable *drawable;
+    RECTL clip_area;
+    UINT32 width;
+    UINT32 height;
+
+    SectRect(area_rect, clip_rect, &clip_area);
+    if (IsEmptyRect(&clip_area)) {
+        return TRUE;
+    }
+
+    width = clip_area.right - clip_area.left;
+    height = clip_area.bottom - clip_area.top;
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL, surface_id))) {
+        return FALSE;
+    }
+
+    drawable->effect = QXL_EFFECT_OPAQUE;
+    drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
+    drawable->u.copy.mask.bitmap = 0;
+    drawable->u.copy.rop_descriptor = rop_descriptor;
+
+    drawable->u.copy.src_area.top = src_rect->top + (clip_area.top - area_rect->top);
+    drawable->u.copy.src_area.bottom = drawable->u.copy.src_area.top + clip_area.bottom -
+                                       clip_area.top;
+    drawable->u.copy.src_area.left = src_rect->left + (clip_area.left - area_rect->left);
+    drawable->u.copy.src_area.right = drawable->u.copy.src_area.left + clip_area.right -
+                                      clip_area.left;
+
+    if(!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
+                  color_trans, FALSE, &drawable->surfaces_dest[0])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoCopy(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                   RECTL *src_rect, XLATEOBJ *color_trans, UINT16 rop_descriptor, SURFOBJ *mask,
+                   POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+{
+    QXLDrawable *drawable;
+    BOOL use_cache;
+    UINT32 width;
+    UINT32 height;
+
+    ASSERT(pdev, pdev && area && src_rect && src);
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (mask) {
+        use_cache = TRUE;
+    } else {
+        use_cache = StreamTest(pdev, surface_id, src, color_trans, src_rect, area);
+    }
+
+    if (use_cache && TestSplitClips(pdev, src, src_rect, clip, mask) &&
+        !QXLCheckIfCacheImage(pdev, src, color_trans)) {
+        if (clip->iDComplexity == DC_RECT) {
+            if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, &clip->rclBounds, color_trans,
+                               scale_mode, rop_descriptor)) {
+                return FALSE;
+            }
+        } else {
+            int more;
+            ASSERT(pdev, clip->iMode == TC_RECTANGLES);
+            CLIPOBJ_cEnumStart(clip, TRUE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
+            do {
+                RECTL *now;
+                RECTL *end;
+
+                struct {
+                    ULONG  count;
+                    RECTL  rects[20];
+                } buf;
+                more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
+                for(now = buf.rects, end = now + buf.count; now < end; now++) {
+                    if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, now, color_trans,
+                                       scale_mode, rop_descriptor)) {
+                        return FALSE;
+                    }
+                }
+            } while (more);
+        }
+        return TRUE;
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    if (mask) {
+        drawable->effect = QXL_EFFECT_BLEND;
+    } else {
+        drawable->effect = QXL_EFFECT_OPAQUE;
+    }
+
+    drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
+    CopyRect(&drawable->u.copy.src_area, src_rect);
+    if (!QXLGetMask(pdev, drawable, &drawable->u.copy.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[0]) ||
+        !GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
+                   color_trans, use_cache, &drawable->surfaces_dest[1])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[1], src_rect);
+
+    drawable->u.copy.rop_descriptor = rop_descriptor;
+    PushDrawable(pdev, drawable);
+    DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+static BOOL DoCopyBits(PDev *pdev, UINT32 surface_id, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height; 
+
+    ASSERT(pdev, pdev && area && src_pos);
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    if (area->left == src_pos->x && area->top == src_pos->y) {
+        DEBUG_PRINT((pdev, 6, "%s: NOP\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    drawable->surfaces_dest[0] = surface_id;
+    CopyRectPoint(&drawable->surfaces_rects[0], src_pos, width, height);
+
+    CopyPoint(&drawable->u.copy_bits.src_pos, src_pos);
+    drawable->effect = QXL_EFFECT_OPAQUE;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoBlend(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                    RECTL *src_rect, XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask,
+                    POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height; 
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area && src_rect && src);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    drawable->u.blend.scale_mode = GdiScaleModeToQxl(scale_mode);
+    CopyRect(&drawable->u.blend.src_area, src_rect);
+    if (!QXLGetMask(pdev, drawable, &drawable->u.blend.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[0]) ||
+        !GetBitmap(pdev, drawable, &drawable->u.blend.src_bitmap, src, &drawable->u.blend.src_area,
+                   color_trans, TRUE, &drawable->surfaces_dest[1])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[1], src_rect);
+
+    drawable->u.blend.rop_descriptor = rop_info->method_data;
+    drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoBlackness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
+                        POINTL *mask_pos, BOOL invers_mask)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetMask(pdev, drawable, &drawable->u.blackness.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[0])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+ if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+
+    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoWhiteness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
+                        POINTL *mask_pos, BOOL invers_mask)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetMask(pdev, drawable, &drawable->u.whiteness.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[0])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+
+    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoInvers(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, 
+                     POINTL *mask_pos, BOOL invers_mask)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    if (!QXLGetMask(pdev, drawable, &drawable->u.invers.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[0])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+    }
+
+    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_REVERT_ON_DUP;
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+static BOOL DoROP3(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+                   RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+                   UINT8 rop3, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+{
+    QXLDrawable *drawable;
+    UINT32 width;
+    UINT32 height;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+    ASSERT(pdev, pdev && area && brush && src_rect && src);
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    width = area->right - area->left;
+    height = area->bottom - area->top;
+
+    drawable->u.rop3.scale_mode = GdiScaleModeToQxl(scale_mode);
+    CopyRect(&drawable->u.rop3.src_area, src_rect);
+    if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos,
+                     &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
+        !QXLGetMask(pdev, drawable, &drawable->u.rop3.mask, mask, mask_pos, invers_mask,
+                    width, height, &drawable->surfaces_dest[1]) ||
+        !GetBitmap(pdev, drawable, &drawable->u.rop3.src_bitmap, src, &drawable->u.rop3.src_area,
+                   color_trans, TRUE, &drawable->surfaces_dest[2])) {
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    if (mask_pos) {
+        CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+    }
+    CopyRect(&drawable->surfaces_rects[2], src_rect);
+
+    drawable->u.rop3.rop3 = rop3;
+    drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_BLEND; //for now
+    PushDrawable(pdev, drawable);
+    return TRUE;
+}
+
+BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
+                   XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
+                   POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
+{
+    RECTL area;
+    SURFOBJ* surf_obj;
+    BOOL ret;
+    UINT32 surface_id;
+    SurfaceInfo *surface;
+
+    surface = (SurfaceInfo *)src->dhsurf;
+    surface_id = GetSurfaceId(src);
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    area.top = MAX(0, src_pos.y);
+    area.bottom = MIN(src_pos.y + dest_rect->bottom - dest_rect->top,
+                      surface->draw_area.surf_obj->sizlBitmap.cy);
+    area.left = MAX(0, src_pos.x);
+    area.right = MIN(src_pos.x + dest_rect->right - dest_rect->left,
+                     surface->draw_area.surf_obj->sizlBitmap.cx);
+
+    UpdateArea(pdev, &area, surface_id);
+
+    surf_obj = surface->draw_area.surf_obj;
+
+    if (rop4 == 0xcccc) {
+        ret = EngCopyBits(dest, surf_obj, clip, color_trans, dest_rect, &src_pos);
+    } else {
+        ret = EngBitBlt(dest, surf_obj, mask, clip, color_trans, dest_rect, &src_pos,
+                        mask_pos, brush, brush_pos, rop4);
+    }
+
+    return ret;
+}
+
+BOOL _inline __DrvBitBlt(PDev *pdev, UINT32 surface_id, RECTL *dest_rect, CLIPOBJ *clip,
+                        SURFOBJ  *src, RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, 
+                        POINTL *brush_pos, ULONG rop3, SURFOBJ *mask, POINTL *mask_pos,
+                        BOOL invers_mask, ULONG scale_mode)
+{
+    ROP3Info *rop_info = &rops3[rop3];
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    switch (rop_info->method_type) {
+    case ROP3_TYPE_FILL:
+        return DoFill(pdev, surface_id, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
+                      invers_mask);
+    case ROP3_TYPE_OPAQUE:
+        return DoOpaque(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                        brush_pos, rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+    case ROP3_TYPE_COPY:
+        return DoCopy(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans,
+                      rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+    case ROP3_TYPE_BLEND:
+        return DoBlend(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, rop_info,
+                       mask, mask_pos, invers_mask, scale_mode);
+    case ROP3_TYPE_BLACKNESS:
+        return DoBlackness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
+    case ROP3_TYPE_WHITENESS:
+        return DoWhiteness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
+    case ROP3_TYPE_INVERS:
+        return DoInvers(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
+    case ROP3_TYPE_ROP3:
+        return DoROP3(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                      brush_pos, (UINT8)rop_info->method_data, mask, mask_pos, invers_mask,
+                      scale_mode);
+    case ROP3_TYPE_NOP:
+        return TRUE;
+    default:
+        DEBUG_PRINT((pdev, 0, "%s: Error\n", __FUNCTION__));
+        //EngSetError
+        return FALSE;
+    }
+}
+
+#ifdef SUPPORT_BRUSH_AS_MASK
+SURFOBJ *BrushToMask(PDev *pdev, BRUSHOBJ *brush)
+{
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    if (!brush || brush->iSolidColor != ~0) {
+        DEBUG_PRINT((pdev, 8, "%s: no mask, brush 0x%x color 0x%x\n",
+                     __FUNCTION__, brush, brush ? brush->iSolidColor : 0));
+        return NULL;
+    }
+
+    if (!brush->pvRbrush && !BRUSHOBJ_pvGetRbrush(brush)) {
+        DEBUG_PRINT((pdev, 0, "%s: realize failed\n", __FUNCTION__));
+        return NULL;
+    }
+    DEBUG_PRINT((pdev, 7, "%s: done 0x%x\n", __FUNCTION__, brush->pvRbrush));
+    return NULL;
+}
+#endif
+
+
+static _inline BOOL TestSrcBits(PDev *pdev, SURFOBJ *src, XLATEOBJ *color_trans)
+{
+    if (src) {
+        switch (src->iBitmapFormat) {
+        case BMF_32BPP:
+        case BMF_24BPP:
+        case BMF_16BPP: {
+            ULONG bit_fields[3];
+            ULONG ents;
+
+            if (!color_trans || (color_trans->flXlate & XO_TRIVIAL)) {
+                return TRUE;
+            }
+
+            ents = XLATEOBJ_cGetPalette(color_trans, XO_SRCBITFIELDS, 3, bit_fields);
+            ASSERT(pdev, ents == 3);
+            switch (src->iBitmapFormat) {
+            case BMF_32BPP:
+            case BMF_24BPP:
+                if (bit_fields[0] != 0x00ff0000 || bit_fields[1] != 0x0000ff00 ||
+                                                                    bit_fields[2] != 0x000000ff) {
+                    DEBUG_PRINT((pdev, 11, "%s: BMF_32BPP/24BPP r 0x%x g 0x%x b 0x%x\n",
+                                 __FUNCTION__,
+                                 bit_fields[0],
+                                 bit_fields[1],
+                                 bit_fields[2]));
+                    return FALSE;
+                }
+                break;
+            case BMF_16BPP:
+                if (bit_fields[0] != 0x7c00 || bit_fields[1] != 0x03e0 ||
+                                                                        bit_fields[2] != 0x001f) {
+                    DEBUG_PRINT((pdev, 11, "%s: BMF_16BPP r 0x%x g 0x%x b 0x%x\n",
+                                 __FUNCTION__,
+                                 bit_fields[0],
+                                 bit_fields[1],
+                                 bit_fields[2]));
+                    return FALSE;
+                }
+                break;
+            }
+            return TRUE;
+        }
+        case BMF_8BPP:
+        case BMF_4BPP:
+        case BMF_1BPP:
+            return color_trans && (color_trans->flXlate & XO_TABLE);
+        default:
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                              XLATEOBJ *color_trans, RECTL *dest_rect, RECTL *src_rect,
+                              POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4,
+                              ULONG scale_mode, COLORADJUSTMENT *color_adjust)
+{
+    ULONG rop3;
+    ULONG second_rop3;
+#ifdef SUPPORT_BRUSH_AS_MASK
+    SURFOBJ *brush_mask = NULL;
+#endif
+    QXLRESULT res;
+    UINT32 surface_id;
+
+    ASSERT(pdev, dest->iType != STYPE_BITMAP);
+
+    surface_id = GetSurfaceId(dest);
+
+    if (!PrepareBrush(brush)) {
+        return QXL_FAILED;
+    }
+
+    if ((rop3 = rop4 & 0xff) == (second_rop3 = ((rop4 >> 8) & 0xff))) {
+        return __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                           brush_pos, rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS :
+                           QXL_FAILED;
+    }
+
+    if (!mask) {
+        DEBUG_PRINT((pdev, 5, "%s: no mask. rop4 is 0x%x\n", __FUNCTION__, rop4));
+        return QXL_UNSUPPORTED;
+#ifdef SUPPORT_BRUSH_AS_MASK
+        brush_mask = BrushToMask(pdev, brush);
+        if (!brush_mask) {
+            DEBUG_PRINT((pdev, 5, "%s: no mask. rop4 is 0x%x\n", __FUNCTION__, rop4));
+            return QXL_UNSUPPORTED;
+        }
+        mask = brush_mask;
+        ASSERT(pdev, mask_pos);
+#endif
+    }
+    DEBUG_PRINT((pdev, 5, "%s: mask, rop4 is 0x%x\n", __FUNCTION__, rop4));
+    ASSERT(pdev, mask_pos);
+    res = (__DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                       brush_pos, rop3, mask, mask_pos, FALSE, scale_mode) &&
+          __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+                      brush_pos, second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS :
+                      QXL_FAILED;
+#ifdef SUPPORT_BRUSH_AS_MASK
+    if (brush_mask) {
+        //free brush_mask;
+    }
+#endif
+
+    return res;
+}
+
+static _inline void FixDestParams(PDev *pdev, SURFOBJ *dest, CLIPOBJ **in_clip,
+                                  RECTL *dest_rect, RECTL *area, POINTL **in_mask_pos,
+                                  POINTL *local_mask_pos)
+{
+    CLIPOBJ *clip;
+
+    area->top = MAX(dest_rect->top, 0);
+    area->left = MAX(dest_rect->left, 0);
+    area->bottom = MIN(dest->sizlBitmap.cy, dest_rect->bottom);
+    area->right = MIN(dest->sizlBitmap.cx, dest_rect->right);
+
+    clip = *in_clip;
+    if (clip) {
+        if (clip->iDComplexity == DC_TRIVIAL) {
+            clip = NULL;
+        } else {
+            SectRect(&clip->rclBounds, area, area);
+            if (clip->iDComplexity == DC_RECT) {
+                clip = NULL;
+            }
+        }
+        *in_clip = clip;
+    }
+
+    if (in_mask_pos && *in_mask_pos) {
+        POINTL *mask_pos;
+        ASSERT(pdev, local_mask_pos);
+        mask_pos = *in_mask_pos;
+        local_mask_pos->x = mask_pos->x + (area->left - dest_rect->left);
+        local_mask_pos->y = mask_pos->y + (area->top - dest_rect->top);
+        *in_mask_pos = local_mask_pos;
+    }
+}
+
+static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                         XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos,
+                         POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
+{
+    RECTL area;
+    POINTL local_mask_pos;
+    RECTL src_rect;
+    RECTL *src_rect_ptr;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    if (!TestSrcBits(pdev, src, color_trans)) {
+        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
+
+        return EngBitBlt(dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos, brush,
+                         brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
+    }
+
+#if 0
+    if (rop4 == 0xccaa) {
+        DEBUG_PRINT((pdev, 7, "%s: rop4 is 0xccaa, call EngBitBlt\n", __FUNCTION__));
+        return QXL_UNSUPPORTED;
+    }
+#endif
+
+    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
+           dest_rect->top < dest_rect->bottom);
+
+    FixDestParams(pdev, dest, &clip, dest_rect, &area, &mask_pos, &local_mask_pos);
+    if (IsEmptyRect(&area)) {
+        DEBUG_PRINT((pdev, 0, "%s: empty rect\n", __FUNCTION__));
+        return QXL_SUCCESS;
+    }
+
+    if (src && src_pos) {
+        POINTL local_pos;
+
+        local_pos.x = src_pos->x + (area.left - dest_rect->left);
+        local_pos.y = src_pos->y + (area.top - dest_rect->top);
+
+        if (dest->iType == STYPE_BITMAP) {
+            return BitBltFromDev(pdev, src, dest, mask, clip, color_trans, &area, local_pos,
+                                 mask_pos, brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
+        }
+
+        if (src->iType != STYPE_BITMAP
+            && GetSurfaceId(src) == GetSurfaceId(dest) && rop4 == 0xcccc) { //SRCCOPY no mask
+            return DoCopyBits(pdev, GetSurfaceId(src), clip, &area, &local_pos) ?
+                              QXL_SUCCESS : QXL_FAILED;
+        }
+
+        src_rect.left = local_pos.x;
+        src_rect.right = src_rect.left + (area.right - area.left);
+        src_rect.top = local_pos.y;
+        src_rect.bottom = src_rect.top + (area.bottom - area.top);
+        src_rect_ptr = &src_rect;
+    } else {
+        src_rect_ptr = NULL;
+    }
+
+    return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect_ptr,
+                        mask_pos, brush, brush_pos, rop4, COLORONCOLOR, NULL);
+}
+
+BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                      XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos,
+                      POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
+{
+    PDev *pdev;
+    QXLRESULT res;
+
+    if (dest->iType == STYPE_BITMAP) {
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
+    }
+
+    PUNT_IF_DISABLED(pdev);
+
+    CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+    if ((res = _BitBlt(pdev, dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
+                       brush, brush_pos, rop4))) {
+        if (res == QXL_UNSUPPORTED) {
+            DEBUG_PRINT((pdev, 4, "%s: call EngBitBlt\n", __FUNCTION__));
+            return EngBitBlt(dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
+                             brush, brush_pos, rop4);
+        }
+        return FALSE;
+
+    }
+
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+BOOL APIENTRY DrvCopyBits(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip,
+                          XLATEOBJ *color_trans, RECTL *dest_rect, POINTL *src_pos)
+{
+    PDev *pdev;
+
+    if (dest->iType == STYPE_BITMAP) {
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
+    }
+
+    PUNT_IF_DISABLED(pdev);
+
+    CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    return _BitBlt(pdev, dest, src, NULL, clip, color_trans, dest_rect, src_pos, NULL, NULL,
+                   NULL, /*SRCCOPY*/ 0xcccc) == QXL_SUCCESS ? TRUE : FALSE;
+}
+
+static _inline BOOL TestStretchCondition(PDev *pdev, SURFOBJ *src, XLATEOBJ *color_trans,
+                                         COLORADJUSTMENT *color_adjust,
+                                         RECTL *dest_rect, RECTL *src_rect)
+{
+    int src_size;
+    int dest_size;
+
+    if (color_adjust && (color_adjust->caFlags & CA_NEGATIVE)) {
+        return FALSE;
+    }
+
+    if (IsCacheableSurf(src, color_trans)) {
+        return TRUE;
+    }
+
+    src_size = (src_rect->right - src_rect->left) * (src_rect->bottom - src_rect->top);
+    dest_size = (dest_rect->right - dest_rect->left) * (dest_rect->bottom - dest_rect->top);
+
+    return dest_size - src_size >= -(src_size >> 2);
+
+}
+
+static _inline unsigned int Scale(unsigned int val, unsigned int base_unit, unsigned int dest_unit)
+{
+    unsigned int div;
+    unsigned int mod;
+
+    div = dest_unit * val / base_unit;
+    mod = dest_unit * val % base_unit;
+    return (mod >= (base_unit >> 1)) ? div + 1: div;
+}
+
+static QXLRESULT _StretchBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                             XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
+                             POINTL *brush_pos, RECTL *dest_rect, RECTL *src_rect,
+                             POINTL *mask_pos, ULONG mode, BRUSHOBJ *brush, DWORD rop4)
+{
+    RECTL area;
+    POINTL local_mask_pos;
+    RECTL local_dest_rect;
+    RECTL local_src_rect;
+
+    DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+
+    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
+           src_rect->top < src_rect->bottom);
+    ASSERT(pdev, dest_rect);
+
+
+    if (dest_rect->left > dest_rect->right) {
+        local_dest_rect.left = dest_rect->right;
+        local_dest_rect.right = dest_rect->left;
+    } else {
+        local_dest_rect.left = dest_rect->left;
+        local_dest_rect.right = dest_rect->right;
+    }
+
+    if (dest_rect->top > dest_rect->bottom) {
+        local_dest_rect.top = dest_rect->bottom;
+        local_dest_rect.bottom = dest_rect->top;
+    } else {
+        local_dest_rect.top = dest_rect->top;
+        local_dest_rect.bottom = dest_rect->bottom;
+    }
+
+    if (!TestSrcBits(pdev, src, color_trans)) {
+        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
+        return QXL_UNSUPPORTED;
+    }
+
+    if (!TestStretchCondition(pdev, src, color_trans, color_adjust, &local_dest_rect, src_rect)) {
+        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
+        return QXL_UNSUPPORTED;
+    }
+
+    FixDestParams(pdev, dest, &clip, &local_dest_rect, &area, &mask_pos, &local_mask_pos);
+    if (IsEmptyRect(&area)) {
+        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
+        return QXL_SUCCESS;
+    }
+    //todo: use FixStreatchSrcArea
+    if (!SameRect(&local_dest_rect, &area)) { // possibly generate incosistent rendering on dest
+                                              // edges
+        unsigned int w_dest;
+        unsigned int h_dest;
+
+        if ((w_dest = local_dest_rect.right - local_dest_rect.left) != area.right - area.left) {
+            unsigned int w_src = src_rect->right - src_rect->left;
+            unsigned int delta;
+
+            if ((delta = area.left - local_dest_rect.left)) {
+                local_src_rect.left = src_rect->left + Scale(delta, w_dest, w_src);
+            } else {
+                local_src_rect.left = src_rect->left;
+            }
+
+            if ((delta = local_dest_rect.right - area.right)) {
+                local_src_rect.right = src_rect->right - Scale(delta, w_dest, w_src);
+            } else {
+                local_src_rect.right = src_rect->right;
+            }
+
+            local_src_rect.left = MIN(local_src_rect.left, src->sizlBitmap.cx - 1);
+            local_src_rect.right = MAX(local_src_rect.right, local_src_rect.left + 1);
+
+        } else {
+            local_src_rect.left = src_rect->left;
+            local_src_rect.right = src_rect->right;
+        }
+
+        if ((h_dest = local_dest_rect.bottom - local_dest_rect.top) != area.bottom - area.top) {
+            unsigned int h_src = src_rect->bottom - src_rect->top;
+            unsigned int delta;
+
+            if ((delta = area.top - local_dest_rect.top)) {
+                local_src_rect.top = src_rect->top + Scale(delta, h_dest, h_src);
+            } else {
+                local_src_rect.top = src_rect->top;
+            }
+
+            if ((delta = local_dest_rect.bottom - area.bottom)) {
+                local_src_rect.bottom = src_rect->bottom - Scale(delta, h_dest, h_src);
+            } else {
+                local_src_rect.bottom = src_rect->bottom;
+            }
+
+            local_src_rect.top = MIN(local_src_rect.top, src->sizlBitmap.cy - 1);
+            local_src_rect.bottom = MAX(local_src_rect.bottom, local_src_rect.top + 1);
+
+        } else {
+            local_src_rect.top = src_rect->top;
+            local_src_rect.bottom = src_rect->bottom;
+        }
+
+        src_rect = &local_src_rect;
+    }
+
+    return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect, mask_pos,
+                        brush, brush_pos, rop4, mode, color_adjust);
+}
+
+BOOL APIENTRY DrvStretchBltROP(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                               XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
+                               POINTL *brush_pos, RECTL *dest_rect, RECTL *src_rect,
+                               POINTL *mask_pos, ULONG mode, BRUSHOBJ *brush, DWORD rop4)
+{
+    PDev *pdev;
+    QXLRESULT res;
+
+    if (src && src->iType != STYPE_BITMAP) {
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
+    }
+
+    pdev = (PDev *)dest->dhpdev;
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+    CountCall(pdev, CALL_COUNTER_STRETCH_BLT_ROP);
+
+    PUNT_IF_DISABLED(pdev);
+
+    if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
+                           mode == HALFTONE ? color_adjust: NULL, brush_pos,
+                           dest_rect, src_rect, mask_pos, mode, brush,rop4))) {
+        if (res == QXL_UNSUPPORTED) {
+            goto punt;
+        }
+        return FALSE;
+    }
+    return TRUE;
+
+punt:
+    return EngStretchBltROP(dest, src, mask, clip, color_trans, color_adjust, brush_pos,
+                                dest_rect, src_rect, mask_pos, mode, brush, rop4);
+}
+
+BOOL APIENTRY DrvStretchBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *clip,
+                            XLATEOBJ *color_trans, COLORADJUSTMENT *color_adjust,
+                            POINTL *halftone_brush_pos, RECTL *dest_rect, RECTL *src_rect,
+                            POINTL *mask_pos, ULONG mode)
+{
+    PDev *pdev;
+    QXLRESULT res;
+
+    ASSERT(NULL, src);
+    if (src->iType != STYPE_BITMAP) {
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
+    }
+    pdev = (PDev *)dest->dhpdev;
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+    CountCall(pdev, CALL_COUNTER_STRETCH_BLT);
+    PUNT_IF_DISABLED(pdev);
+
+    if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
+                           mode == HALFTONE ? color_adjust: NULL, NULL, dest_rect,
+                           src_rect, mask_pos, mode, NULL, (mask) ? 0xccaa:  0xcccc))) {
+        if (res == QXL_UNSUPPORTED) {
+            goto punt;
+        }
+        return FALSE;
+    }
+    return TRUE;
+
+punt:
+    return EngStretchBlt(dest, src, mask, clip, color_trans, color_adjust, halftone_brush_pos,
+                         dest_rect, src_rect, mask_pos, mode);
+}
+
+static BOOL FixStreatchSrcArea(const RECTL *orig_dest, const RECTL *dest, const RECTL *orig_src,
+                               const SIZEL *bitmap_size, RECTL *src)
+{
+    unsigned int w_dest;
+    unsigned int h_dest;
+
+    if (SameRect(orig_dest, dest)) {
+        return FALSE;
+    }
+
+    // possibly generate incosistent rendering on dest edges
+
+    if ((w_dest = orig_dest->right - orig_dest->left) != dest->right - dest->left) {
+        unsigned int w_src = orig_src->right - orig_src->left;
+        unsigned int delta;
+
+        if ((delta = dest->left - orig_dest->left)) {
+            src->left = orig_src->left + Scale(delta, w_dest, w_src);
+        } else {
+            src->left = orig_src->left;
+        }
+
+        if ((delta = orig_dest->right - dest->right)) {
+            src->right = orig_src->right - Scale(delta, w_dest, w_src);
+        } else {
+            src->right = orig_src->right;
+        }
+
+        src->left = MIN(src->left, bitmap_size->cx - 1);
+        src->right = MAX(src->right, src->left + 1);
+
+    } else {
+        src->left = orig_src->left;
+        src->right = orig_src->right;
+    }
+
+    if ((h_dest = orig_dest->bottom - orig_dest->top) != dest->bottom - dest->top) {
+        unsigned int h_src = orig_src->bottom - orig_src->top;
+        unsigned int delta;
+
+        if ((delta = dest->top - orig_dest->top)) {
+            src->top = orig_src->top + Scale(delta, h_dest, h_src);
+        } else {
+            src->top = orig_src->top;
+        }
+
+        if ((delta = orig_dest->bottom - dest->bottom)) {
+            src->bottom = orig_src->bottom - Scale(delta, h_dest, h_src);
+        } else {
+            src->bottom = orig_src->bottom;
+        }
+
+        src->top = MIN(src->top, bitmap_size->cy - 1);
+        src->bottom = MAX(src->bottom, src->top + 1);
+
+    } else {
+        src->top = orig_src->top;
+        src->bottom = orig_src->bottom;
+    }
+
+    return TRUE;
+}
+
+BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ *color_trans,
+                            RECTL *dest_rect, RECTL *src_rect, BLENDOBJ *bland)
+{
+    QXLDrawable *drawable;
+    PDev *pdev;
+    RECTL area;
+    RECTL local_src;
+
+    ASSERT(NULL, src && dest);
+    if (src->iType != STYPE_BITMAP) {
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        pdev = (PDev *)dest->dhpdev;
+    }
+
+    pdev = (PDev *)dest->dhpdev;
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    PUNT_IF_DISABLED(pdev);
+
+    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
+           src_rect->top < src_rect->bottom);
+    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
+           dest_rect->top < dest_rect->bottom);
+
+    CountCall(pdev, CALL_COUNTER_ALPHA_BLEND);
+
+    if (bland->BlendFunction.BlendOp != AC_SRC_OVER) {
+        DEBUG_PRINT((pdev, 0, "%s: unexpected BlendOp\n", __FUNCTION__));
+        goto punt;
+    }
+
+    if (bland->BlendFunction.SourceConstantAlpha == 0) {
+        return TRUE;
+    }
+
+    if (!TestSrcBits(pdev, src, color_trans)) {
+        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
+        goto punt;
+    }
+
+    if (!TestStretchCondition(pdev, src, color_trans, NULL, dest_rect, src_rect)) {
+        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
+        goto punt;
+    }
+
+    FixDestParams(pdev, dest, &clip, dest_rect, &area, NULL, NULL);
+    if (IsEmptyRect(&area)) {
+        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip, GetSurfaceId(dest)))) {
+        DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (FixStreatchSrcArea(dest_rect, &area, src_rect, &src->sizlBitmap, &local_src)) {
+        src_rect = &local_src;
+    }
+
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
+    CopyRect(&drawable->u.alpha_blend.src_area, src_rect);
+    if (bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA) {
+        ASSERT(pdev, src->iBitmapFormat == BMF_32BPP);
+        if (!QXLGetAlphaBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
+                               &drawable->u.alpha_blend.src_area,
+                               &drawable->surfaces_dest[0])) {
+            DEBUG_PRINT((pdev, 0, "%s: QXLGetAlphaBitmap failed\n", __FUNCTION__));
+            ReleaseOutput(pdev, drawable->release_info.id);
+            return FALSE;
+        }
+    } else {
+        if (!QXLGetBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
+                        &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE,
+                        &drawable->surfaces_dest[0])) {
+            DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
+            ReleaseOutput(pdev, drawable->release_info.id);
+            return FALSE;
+        }
+    }
+    drawable->u.alpha_blend.alpha_flags = 0;
+    if (src->iType != STYPE_BITMAP && 
+	bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA)
+      drawable->u.alpha_blend.alpha_flags |= SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA;
+    
+    drawable->u.alpha_blend.alpha = bland->BlendFunction.SourceConstantAlpha;
+    drawable->effect = QXL_EFFECT_BLEND;
+
+    PushDrawable(pdev, drawable);
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+
+    return TRUE;
+
+punt:
+    return EngAlphaBlend(dest, src, clip, color_trans, dest_rect, src_rect, bland);
+}
+
+BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ *color_trans,
+                                RECTL *dest_rect, RECTL *src_rect, ULONG trans_color,
+                                ULONG reserved)
+{
+    QXLDrawable *drawable;
+    PDev *pdev;
+    RECTL area;
+    RECTL local_src;
+
+    ASSERT(NULL, src && dest);
+    if (src->iType != STYPE_BITMAP) {
+        ASSERT(NULL, src->dhpdev);
+        pdev = (PDev *)src->dhpdev;
+    } else {
+        ASSERT(NULL, dest->dhpdev);
+        pdev = (PDev *)dest->dhpdev;
+    }
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    PUNT_IF_DISABLED(pdev);
+
+    ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
+           src_rect->top < src_rect->bottom);
+    ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
+           dest_rect->top < dest_rect->bottom);
+
+    CountCall(pdev, CALL_COUNTER_TRANSPARENT_BLT);
+
+    if (!TestSrcBits(pdev, src, color_trans)) {
+        DEBUG_PRINT((pdev, 1, "%s: test src failed\n", __FUNCTION__));
+        goto punt;
+    }
+
+    if (!TestStretchCondition(pdev, src, color_trans, NULL, dest_rect, src_rect)) {
+        DEBUG_PRINT((pdev, 1, "%s: stretch test failed\n", __FUNCTION__));
+        goto punt;
+    }
+
+    FixDestParams(pdev, dest, &clip, dest_rect, &area, NULL, NULL);
+    if (IsEmptyRect(&area)) {
+        DEBUG_PRINT((pdev, 0, "%s: empty dest\n", __FUNCTION__));
+        return TRUE;
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip, GetSurfaceId(dest)))) {
+        DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (FixStreatchSrcArea(dest_rect, &area, src_rect, &src->sizlBitmap, &local_src)) {
+        src_rect = &local_src;
+    }
+
+    CopyRect(&drawable->u.transparent.src_area, src_rect);
+    CopyRect(&drawable->surfaces_rects[0], src_rect);
+    if (!QXLGetBitmap(pdev, drawable, &drawable->u.transparent.src_bitmap, src,
+                      &drawable->u.transparent.src_area, color_trans, NULL, TRUE,
+                      &drawable->surfaces_dest[0])) {
+        DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
+        ReleaseOutput(pdev, drawable->release_info.id);
+        return FALSE;
+    }
+
+    drawable->u.transparent.src_color = trans_color;
+    switch (src->iBitmapFormat) {
+    case BMF_32BPP:
+    case BMF_24BPP:
+        drawable->u.transparent.true_color = trans_color;
+        break;
+    case BMF_16BPP:
+        drawable->u.transparent.true_color = _16bppTo32bpp(trans_color);
+        break;
+    case BMF_8BPP:
+    case BMF_4BPP:
+    case BMF_1BPP:
+        ASSERT(pdev, trans_color < color_trans->cEntries);
+        if (pdev->bitmap_format == BMF_32BPP) {
+            drawable->u.transparent.true_color = color_trans->pulXlate[trans_color];
+        } else {
+            ASSERT(pdev, pdev->bitmap_format == BMF_16BPP);
+            drawable->u.transparent.true_color = _16bppTo32bpp(color_trans->pulXlate[trans_color]);
+        }
+        break;
+            return color_trans && (color_trans->flXlate & XO_TABLE);
+    }
+
+    drawable->effect = QXL_EFFECT_BLEND;
+    PushDrawable(pdev, drawable);
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+
+    return TRUE;
+
+punt:
+    return EngTransparentBlt(dest, src, clip, color_trans, dest_rect, src_rect, trans_color,
+                             reserved);
+}
+
diff --git a/xddm/display/rop.h b/xddm/display/rop.h
new file mode 100644
index 0000000..b0c7ef5
--- /dev/null
+++ b/xddm/display/rop.h
@@ -0,0 +1,42 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _H_ROP
+#define _H_ROP
+
+#define ROP3_DEST (1 << 0)
+#define ROP3_SRC (1 << 1)
+#define ROP3_BRUSH (1 << 2)
+#define ROP3_ALL (ROP3_DEST | ROP3_SRC | ROP3_BRUSH)
+
+typedef struct ROP3Info {
+    UINT8 effect;
+    UINT8 flags;
+    UINT32 method_type;
+    UINT16 method_data;
+} ROP3Info;
+
+extern ROP3Info rops2[];
+
+BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
+                   XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
+                   POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4);
+#endif
diff --git a/xddm/display/sources b/xddm/display/sources
new file mode 100644
index 0000000..6c1d5c7
--- /dev/null
+++ b/xddm/display/sources
@@ -0,0 +1,34 @@
+TARGETNAME=qxldd
+TARGETPATH=obj
+TARGETTYPE=GDI_DRIVER
+
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+
+MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
+
+INCLUDES=$(DDK_INC_PATH); ..\include; $(SPICE_COMMON_DIR);
+
+# todo: add ntoskrnl.lib for 2008 build
+
+TARGETLIBS = $(DDK_LIB_PATH)\ntstrsafe.lib
+
+!IFNDEF DEBUG
+MSC_OPTIMIZATION = /Ox
+!ENDIF
+
+C_DEFINES = $(C_DEFINES) /DQXLDD
+
+
+SOURCES=driver.c        \
+        rop.c           \
+        res.c           \
+        text.c          \
+        pointer.c       \
+        brush.c         \
+        mspace.c        \
+        quic.c          \
+        surface.c       \
+        driver.rc
+
diff --git a/xddm/display/surface.c b/xddm/display/surface.c
new file mode 100644
index 0000000..2cc5895
--- /dev/null
+++ b/xddm/display/surface.c
@@ -0,0 +1,407 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "os_dep.h"
+
+#include "winerror.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+#include "qxldd.h"
+#include "utils.h"
+#include "mspace.h"
+#include "res.h"
+#include "surface.h"
+
+static BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, ULONG format, UINT32 cx, UINT32 cy,
+                           UINT32 stride, UINT32 surface_id)
+{
+    SIZEL  size;
+    DrawArea *drawarea;
+
+    size.cx = cx;
+    size.cy = cy;
+
+    drawarea = &GetSurfaceInfo(pdev, surface_id)->draw_area;
+
+    if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, format, 0, base_mem))) {
+        DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    if (!EngAssociateSurface(drawarea->bitmap, pdev->eng, 0)) {
+        DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
+        goto error;
+    }
+
+    if (!(drawarea->surf_obj = EngLockSurface(drawarea->bitmap))) {
+        DEBUG_PRINT((pdev, 0, "%s: EngLockSurface failed\n", __FUNCTION__));
+        goto error;
+    }
+
+    drawarea->base_mem = base_mem;
+
+    return TRUE;
+error:
+    EngDeleteSurface(drawarea->bitmap);
+    return FALSE;
+}
+
+static VOID FreeDrawArea(DrawArea *drawarea)
+{
+    if (drawarea->surf_obj) {
+        EngUnlockSurface(drawarea->surf_obj);
+        EngDeleteSurface(drawarea->bitmap);
+        drawarea->surf_obj = NULL;
+    }
+}
+
+static void BitmapFormatToDepthAndSurfaceFormat(ULONG format, UINT32 *depth, UINT32 *surface_format)
+{
+    switch (format) {
+        case BMF_16BPP:
+            *surface_format = SPICE_SURFACE_FMT_16_555;
+            *depth = 16;
+            break;
+        case BMF_24BPP:
+        case BMF_32BPP:
+            *surface_format = SPICE_SURFACE_FMT_32_xRGB;
+            *depth = 32;
+            break;
+        default:
+            *depth = 0;
+            break;
+    };
+}
+
+static UINT8 *CreateSurfaceHelper(PDev *pdev, UINT32 surface_id,
+                                  UINT32 cx, UINT32 cy, ULONG format,
+                                  UINT8 allocation_type,
+                                  INT32 *stride, UINT32 *surface_format,
+                                  QXLPHYSICAL *phys_mem)
+{
+    UINT32 depth;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT8 *base_mem;
+    int size;
+
+    BitmapFormatToDepthAndSurfaceFormat(format, &depth, surface_format);
+    ASSERT(pdev, depth != 0);
+    ASSERT(pdev, stride);
+    QXLGetSurface(pdev, phys_mem, cx, cy, depth, stride, &base_mem, allocation_type);
+    DEBUG_PRINT((pdev, 3,
+        "%s: %d, pm %0lX, fmt %d, d %d, s (%d, %d) st %d\n",
+        __FUNCTION__, surface_id, (uint64_t)*phys_mem, *surface_format,
+        depth, cx, cy, *stride));
+    size = abs(*stride) * cy;
+    if (!base_mem) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: QXLGetSurface failed (%d bytes alloc)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        return NULL;
+    }
+    if (!CreateDrawArea(pdev, base_mem, surface_info->bitmap_format, cx, cy, *stride, surface_id)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: CreateDrawArea failed (%d)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        // TODO: Why did it fail? nothing in the MSDN
+        QXLDelSurface(pdev, base_mem, allocation_type);
+        return NULL;
+    }
+    return base_mem;
+}
+
+static void SendSurfaceCreateCommand(PDev *pdev, UINT32 surface_id, SIZEL size,
+                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem,
+                                     int keep_data)
+{
+    QXLSurfaceCmd *surface;
+
+    surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+    if (keep_data) {
+        surface->flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
+    surface->u.surface_create.format = surface_format;
+    surface->u.surface_create.width = size.cx;
+    surface->u.surface_create.height = size.cy;
+    surface->u.surface_create.stride = stride;
+    surface->u.surface_create.data = phys_mem;
+    PushSurfaceCmd(pdev, surface);
+}
+
+HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
+{
+    UINT32 surface_format, depth;
+    HBITMAP hbitmap;
+    INT32 stride;
+    SurfaceInfo *surface_info;
+
+    DEBUG_PRINT((pdev, 9, "%s: %p: %d, (%dx%d), %d\n", __FUNCTION__, pdev, surface_id,
+                size.cx, size.cy, format));
+    surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    if (!(hbitmap = EngCreateDeviceBitmap((DHSURF)surface_info, size, format))) {
+        DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n",
+                    __FUNCTION__, pdev, surface_id));
+        goto out_error1;
+    }
+
+    if (!EngAssociateSurface((HSURF)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) {
+        DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
+        goto out_error2;
+    }
+    surface_info->u.pdev = pdev;
+    surface_info->hbitmap = hbitmap;
+    surface_info->copy = NULL;
+    surface_info->size = size;
+    surface_info->bitmap_format = format;
+    if ((*base_mem = CreateSurfaceHelper(pdev, surface_id, size.cx, size.cy, format,
+                                         allocation_type, &stride, &surface_format,
+                                         phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: failed, pdev 0x%lx, surface_id=%d\n",
+                    __FUNCTION__, pdev, surface_id));
+        goto out_error2;
+    }
+    surface_info->stride = stride;
+    if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
+        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem, 0);
+    }
+
+    return hbitmap;
+out_error2:
+    EngDeleteSurface((HSURF)hbitmap);
+out_error1:
+    return 0;
+}
+
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
+{
+    DrawArea *drawarea;
+
+    drawarea = &GetSurfaceInfo(pdev,surface_id)->draw_area;
+
+    FreeDrawArea(drawarea);
+
+    if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
+        pdev->surfaces_info[surface_id].draw_area.base_mem != NULL) {
+
+        if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_RAM) {
+            /* server side this surface is already destroyed, just free it here */
+            ASSERT(pdev, pdev->surfaces_info[surface_id].draw_area.base_mem ==
+                         pdev->surfaces_info[surface_id].copy);
+            QXLDelSurface(pdev,
+                          pdev->surfaces_info[surface_id].draw_area.base_mem,
+                          allocation_type);
+            FreeSurfaceInfo(pdev, surface_id);
+        } else {
+            QXLSurfaceCmd *surface_cmd;
+            surface_cmd = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+            QXLGetDelSurface(pdev, surface_cmd, surface_id, allocation_type);
+            PushSurfaceCmd(pdev, surface_cmd);
+        }
+    }
+}
+
+static void CleanupSurfaceInfo(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
+{
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    FreeDrawArea(&surface_info->draw_area);
+    if (surface_info->draw_area.base_mem != NULL) {
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, allocation_type);
+    }
+}
+
+BOOL MoveSurfaceToVideoRam(PDev *pdev, UINT32 surface_id)
+{
+    QXLSurfaceCmd *surface;
+    UINT32 surface_format;
+    UINT32 depth;
+    int count_used = 0;
+    int size;
+    INT32 stride = 0;
+    QXLPHYSICAL phys_mem;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT32 cx = surface_info->size.cx;
+    UINT32 cy = surface_info->size.cy;
+    UINT8 *base_mem;
+
+    DEBUG_PRINT((pdev, 3, "%s: %d\n", __FUNCTION__, surface_id));
+    if ((base_mem = CreateSurfaceHelper(pdev, surface_id, cx, cy, surface_info->bitmap_format,
+                                        DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
+                                        &stride, &surface_format, &phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed\n", __FUNCTION__, pdev, surface_id));
+        return FALSE;
+    }
+    size = abs(stride) * cy;
+    if (!EngModifySurface((HSURF)surface_info->hbitmap, pdev->eng, QXL_SURFACE_HOOKS,
+        MS_NOTSYSTEMMEMORY, (DHSURF)surface_info, NULL, 0, NULL)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: EngModifySurface failed\n",
+            __FUNCTION__, pdev, surface_id));
+        CleanupSurfaceInfo(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        return FALSE;
+    }
+    DEBUG_PRINT((pdev, 3, "%s: stride = %d, phys_mem = %0lX, base_mem = %p\n",
+        __FUNCTION__, -stride, (uint64_t)phys_mem, base_mem));
+    DEBUG_PRINT((pdev, 3, "%s: copy %d bytes to %d\n", __FUNCTION__, size, surface_id));
+    // Everything allocated, nothing can fail (API wise) from this point
+    RtlCopyMemory(base_mem, surface_info->copy, size);
+    EngFreeMem(surface_info->copy);
+    surface_info->copy = NULL;
+    SendSurfaceCreateCommand(pdev, surface_id, surface_info->size, surface_format,
+                             -stride, phys_mem, 1);
+    return TRUE;
+}
+
+/* when we return from S3 we need to resend all the surface creation commands.
+ * Actually moving the memory vram<->guest is not strictly neccessary since vram
+ * is not reset during the suspend, so contents are not lost */
+int MoveAllSurfacesToVideoRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+
+    /* brute force implementation - alternative is to keep an updated used_surfaces list */
+    DEBUG_PRINT((pdev, 3, "%s %p\n", __FUNCTION__, pdev));
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        if (surface_info->u.pdev != pdev) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: not our pdev (%p)\n", __FUNCTION__, pdev,
+                         surface_info->u.pdev));
+            continue;
+        }
+        if (surface_info->draw_area.surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: surface_id = %d, surf_obj not empty\n", __FUNCTION__,
+                         surface_id));
+            continue;
+        }
+        if (surface_info->copy == NULL) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: %d: no copy buffer, ignored\n", __FUNCTION__,
+                         pdev, surface_id));
+            continue;
+        }
+        if (!MoveSurfaceToVideoRam(pdev, surface_id)) {
+            /* Some of the surfaces have not been moved to video ram.
+             * they will remain managed by GDI. */
+            DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed moving to vram\n", __FUNCTION__,
+                         pdev, surface_id));
+        }
+    }
+    return TRUE;
+}
+
+/* to_surface_id is exclusive */
+static void SendSurfaceRangeCreateCommand(PDev *pdev, UINT32 from_surface_id, UINT32 to_surface_id)
+{
+    UINT32 surface_id;
+
+    ASSERT(pdev, from_surface_id < to_surface_id);
+    ASSERT(pdev, to_surface_id <= pdev->n_surfaces);
+
+    for (surface_id = from_surface_id; surface_id < to_surface_id; surface_id++) {
+        SurfaceInfo *surface_info;
+        SURFOBJ *surf_obj;
+        QXLPHYSICAL phys_mem;
+        UINT32 surface_format;
+        UINT32 depth;
+
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+
+        surf_obj = surface_info->draw_area.surf_obj;
+
+        if (!surf_obj) {
+            continue;
+        }
+
+        phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
+        BitmapFormatToDepthAndSurfaceFormat(surface_info->bitmap_format, &depth, &surface_format);
+
+        SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
+                                 surface_format, -surface_info->stride, phys_mem,
+                                 /* the surface is still there, tell server not to erase */
+                                 1);
+    }
+}
+
+BOOL MoveAllSurfacesToRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+    SURFOBJ *surf_obj;
+    UINT8 *copy;
+    UINT8 *line0;
+    int size;
+    QXLPHYSICAL phys_mem;
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        surf_obj = surface_info->draw_area.surf_obj;
+        if (!surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: %d: no surfobj, not copying\n", __FUNCTION__, surface_id));
+            continue;
+        }
+        size = surf_obj->sizlBitmap.cy * abs(surf_obj->lDelta);
+        copy = EngAllocMem(0, size, ALLOC_TAG);
+        DEBUG_PRINT((pdev, 3, "%s: %d: copying #%d to %p (%d)\n", __FUNCTION__, surface_id, size,
+            copy, surf_obj->lDelta));
+        RtlCopyMemory(copy, surface_info->draw_area.base_mem, size);
+        surface_info->copy = copy;
+        line0 = surf_obj->lDelta > 0 ? copy : copy + abs(surf_obj->lDelta) *
+                (surf_obj->sizlBitmap.cy - 1);
+        if (!EngModifySurface((HSURF)surface_info->hbitmap,
+                      pdev->eng,
+                      0, /* from the example: used to monitor memory HOOK_COPYBITS | HOOK_BITBLT, */
+                      0,                    /* It's system-memory */
+                      (DHSURF)surface_info,
+                      line0,
+                      surf_obj->lDelta,
+                      NULL)) {
+            /* Send a create messsage for this surface - we previously did a destroy all. */
+            EngFreeMem(surface_info->copy);
+            surface_info->copy = NULL;
+            DEBUG_PRINT((pdev, 0, "%s: %d: EngModifySurface failed, sending create for %d-%d\n",
+                         __FUNCTION__, surface_id, surface_id, pdev->n_surfaces - 1));
+            SendSurfaceRangeCreateCommand(pdev, surface_id, pdev->n_surfaces);
+            return FALSE;
+        }
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        surface_info->draw_area.base_mem = copy;
+        FreeDrawArea(&surface_info->draw_area);
+    }
+    return TRUE;
+}
diff --git a/xddm/display/surface.h b/xddm/display/surface.h
new file mode 100644
index 0000000..c3e5a47
--- /dev/null
+++ b/xddm/display/surface.h
@@ -0,0 +1,103 @@
+#ifndef SURFACE_H
+#define SURFACE_H
+
+#include "qxldd.h"
+
+/* Hooks supported by our surfaces. */
+#ifdef CALL_TEST
+#define QXL_SURFACE_HOOKS_CALL_TEST \
+    (HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |  \
+    HOOK_GRADIENTFILL)
+#else
+#define QXL_SURFACE_HOOKS_CALL_TEST (0)
+#endif
+
+#define QXL_SURFACE_HOOKS \
+    (HOOK_SYNCHRONIZE | HOOK_COPYBITS |                                 \
+    HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH | HOOK_STRETCHBLT |    \
+    HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND | QXL_SURFACE_HOOKS_CALL_TEST)
+
+
+static _inline UINT32 GetSurfaceIdFromInfo(SurfaceInfo *info)
+{
+  PDev *pdev;
+
+  pdev = info->u.pdev;
+  if (info == &pdev->surface0_info) {
+    return 0;
+  }
+  return (UINT32)(info - pdev->surfaces_info);
+}
+
+static _inline SurfaceInfo *GetSurfaceInfo(PDev *pdev, UINT32 id)
+{
+  if (id == 0) {
+    return &pdev->surface0_info;
+  }
+  return &pdev->surfaces_info[id];
+}
+
+static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
+{
+    SurfaceInfo *surface;
+
+    if (!surf || !surf->dhsurf) {
+        return (UINT32)-1;
+    }
+    surface = (SurfaceInfo *)surf->dhsurf;
+    return GetSurfaceIdFromInfo(surface);
+}
+
+static _inline void FreeSurfaceInfo(PDev *pdev, UINT32 surface_id)
+{
+    SurfaceInfo *surface;
+
+    if (surface_id == 0) {
+        return;
+    }
+
+    DEBUG_PRINT((pdev, 9, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+    surface = &pdev->surfaces_info[surface_id];
+    if (surface->draw_area.base_mem == NULL) {
+        DEBUG_PRINT((pdev, 9, "%s: %p: %d: double free. safely ignored\n", __FUNCTION__,
+                     pdev, surface_id));
+        return;
+    }
+    surface->draw_area.base_mem = NULL; /* Mark as not used */
+    surface->u.next_free = pdev->free_surfaces;
+    pdev->free_surfaces = surface;
+}
+
+static UINT32 GetFreeSurface(PDev *pdev)
+{
+    UINT32 x, id;
+    SurfaceInfo *surface;
+
+    ASSERT(pdev, pdev->enabled);
+    surface = pdev->free_surfaces;
+    if (surface == NULL) {
+        id = 0;
+    } else {
+      pdev->free_surfaces = surface->u.next_free;
+
+      id = (UINT32)(surface - pdev->surfaces_info);
+    }
+
+    return id;
+}
+
+enum {
+    DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
+    DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
+    DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
+    DEVICE_BITMAP_ALLOCATION_TYPE_RAM,
+};
+
+HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
+
+int MoveAllSurfacesToVideoRam(PDev *pdev);
+BOOL MoveAllSurfacesToRam(PDev *pdev);
+
+#endif
diff --git a/xddm/display/text.c b/xddm/display/text.c
new file mode 100644
index 0000000..b0a516a
--- /dev/null
+++ b/xddm/display/text.c
@@ -0,0 +1,128 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "os_dep.h"
+#include "qxldd.h"
+#include "utils.h"
+#include "res.h"
+#include "rop.h"
+#include "surface.h"
+
+BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *clip,
+                         RECTL *ignored, RECTL *opaque_rect,
+                         BRUSHOBJ *fore_brush, BRUSHOBJ *back_brash,
+                         POINTL *brushs_origin, MIX mix)
+{
+    QXLDrawable *drawable;
+    ROP3Info *fore_rop;
+    ROP3Info *back_rop;
+    PDev* pdev;
+    RECTL area;
+    UINT32 surface_id;
+
+    if (!(pdev = (PDev *)surf->dhpdev)) {
+        DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    PUNT_IF_DISABLED(pdev);
+
+    surface_id = GetSurfaceId(surf);
+
+    CountCall(pdev, CALL_COUNTER_TEXT_OUT);
+
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+    ASSERT(pdev, opaque_rect == NULL ||
+           (opaque_rect->left < opaque_rect->right && opaque_rect->top < opaque_rect->bottom));
+    ASSERT(pdev, surf && str && font && clip);
+
+    if (opaque_rect) {
+        CopyRect(&area, opaque_rect);
+    } else {
+        CopyRect(&area, &str->rclBkGround);
+    }
+
+    if (clip) {
+        if (clip->iDComplexity == DC_TRIVIAL) {
+            clip = NULL;
+        } else {
+            SectRect(&clip->rclBounds, &area, &area);
+            if (IsEmptyRect(&area)) {
+                DEBUG_PRINT((pdev, 1, "%s: empty rect after clip\n", __FUNCTION__));
+                return TRUE;
+            }
+        }
+    }
+
+    if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip, surface_id))) {
+        return FALSE;
+    }
+
+    if (opaque_rect) {
+        ASSERT(pdev, back_brash && brushs_origin);
+        if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin,
+                         &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
+            goto error;
+        }
+        CopyRect(&drawable->u.text.back_area, &area);
+        drawable->u.text.back_mode = SPICE_ROPD_OP_PUT;
+        drawable->effect = QXL_EFFECT_OPAQUE;
+    } else {
+        drawable->u.text.back_brush.type = SPICE_BRUSH_TYPE_NONE;
+        RtlZeroMemory(&drawable->u.text.back_area, sizeof(drawable->u.text.back_area));
+        drawable->u.text.back_mode = 0;
+        drawable->effect = QXL_EFFECT_BLEND;
+    }
+
+    fore_rop = &rops2[(mix - 1) & 0x0f];
+    back_rop = &rops2[((mix >> 8) - 1) & 0x0f];
+
+    if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
+        drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
+    } else if (!QXLGetBrush(pdev, drawable, &drawable->u.text.fore_brush, fore_brush,
+                            brushs_origin, &drawable->surfaces_dest[1],
+                            &drawable->surfaces_rects[1])) {
+        DEBUG_PRINT((pdev, 0, "%s: get brush failed\n", __FUNCTION__));
+        goto error;
+    }
+
+    if (fore_rop->method_data != back_rop->method_data && back_rop->method_data) {
+        DEBUG_PRINT((pdev, 0, "%s: ignoring back rop, fore %u back %u\n",
+                     __FUNCTION__,
+                     (UINT32)fore_rop->method_data,
+                     (UINT32)back_rop->method_data));
+    }
+    drawable->u.text.fore_mode = fore_rop->method_data;
+
+    if (!QXLGetStr(pdev, drawable, &drawable->u.text.str, font, str)) {
+        DEBUG_PRINT((pdev, 0, "%s: get str failed\n", __FUNCTION__));
+        goto error;
+    }
+
+    PushDrawable(pdev, drawable);
+    DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+    return TRUE;
+
+error:
+    ReleaseOutput(pdev, drawable->release_info.id);
+    DEBUG_PRINT((pdev, 4, "%s: error\n", __FUNCTION__));
+    return FALSE;
+}
diff --git a/xddm/display/utils.h b/xddm/display/utils.h
new file mode 100644
index 0000000..a8d0de6
--- /dev/null
+++ b/xddm/display/utils.h
@@ -0,0 +1,123 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _H_UTILS
+#define _H_UTILS
+
+#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
+#define MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+
+#define OFFSETOF(type, member) ((UINT64)&((type *)0)->member)
+#define CONTAINEROF(ptr, type, member) \
+    ((type *) ((UINT8 *)(ptr) - OFFSETOF(type, member)))
+
+static __inline BOOL IsEmptyRect(RECTL *r)
+{
+    return r->left >= r->right || r->top >= r->bottom;
+}
+
+static __inline void SectRect(RECTL *r1, RECTL *r2, RECTL *dest)
+{
+    dest->top = MAX(r1->top, r2->top);
+    dest->bottom = MAX(MIN(r1->bottom, r2->bottom), dest->top);
+
+    dest->left = MAX(r1->left, r2->left);
+    dest->right = MAX(MIN(r1->right, r2->right), dest->left);
+}
+
+static _inline LONG RectSize(RECTL *rect)
+{
+    return (rect->right - rect->left) * (rect->bottom - rect->top);
+}
+
+#define CopyRectPoint(dest, src, width, height) \
+    (dest)->left = (src)->x; \
+    (dest)->right = (src)->x + width; \
+    (dest)->top = (src)->y; \
+    (dest)->bottom = (src)->y + height; 
+
+#define SameRect(r1, r2) ((r1)->left == (r2)->left && (r1)->right == (r2)->right && \
+                          (r1)->top == (r2)->top && (r1)->bottom == (r2)->bottom)
+
+#define CopyRect(dest, src) \
+    (dest)->top = (src)->top; \
+    (dest)->left = (src)->left; \
+    (dest)->bottom = (src)->bottom; \
+    (dest)->right = (src)->right;
+
+#define CopyPoint(dest, src) \
+    (dest)->x = (src)->x; \
+    (dest)->y = (src)->y;
+
+static __inline void FXToRect(RECTL *dest, RECTFX *src)
+{
+    dest->left = src->xLeft >> 4;
+    dest->top = src->yTop >> 4;
+    dest->right = ALIGN(src->xRight, 16) >> 4;
+    dest->bottom = ALIGN(src->yBottom, 16) >> 4;
+
+}
+
+static _inline int test_bit(void* addr, int bit)
+{
+    return !!(((UINT32 *)addr)[bit >> 5] & (1 << (bit & 0x1f)));
+}
+
+static _inline int test_bit_be(void* addr, int bit)
+{
+    return !!(((UINT8 *)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
+}
+
+static _inline BOOL PrepareBrush(BRUSHOBJ *brush)
+{
+    if (!brush || brush->iSolidColor != ~0 || brush->pvRbrush) {
+        return TRUE;
+    }
+    return BRUSHOBJ_pvGetRbrush(brush) != NULL;
+}
+
+static _inline BOOL IsCacheableSurf(SURFOBJ *surf, XLATEOBJ *color_trans)
+{
+    return surf->iUniq && !(surf->fjBitmap & BMF_DONTCACHE) &&
+                                                               (!color_trans || color_trans->iUniq);
+}
+
+static _inline UINT32 _16bppTo32bpp(UINT32 color)
+{
+    UINT32 ret;
+
+    ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
+    ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
+    ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
+
+    return ret;
+}
+
+static _inline BOOL IsUniqueSurf(SURFOBJ *surf, XLATEOBJ *color_trans)
+{
+    int pallette = color_trans && (color_trans->flXlate & XO_TABLE);
+    return surf->iUniq && (surf->fjBitmap & BMF_DONTCACHE) && (!pallette || color_trans->iUniq);
+}
+
+#endif
+
diff --git a/xddm/include/murmur_hash2a.h b/xddm/include/murmur_hash2a.h
new file mode 100644
index 0000000..51da7db
--- /dev/null
+++ b/xddm/include/murmur_hash2a.h
@@ -0,0 +1,152 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+//Some modifications by Red Hat any bug is probably our fault
+
+//-----------------------------------------------------------------------------
+// MurmurHash2A, by Austin Appleby
+
+// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
+// construction. Bulk speed should be identical to Murmur2, small-key speed
+// will be 10%-20% slower due to the added overhead at the end of the hash.
+
+// This variant fixes a minor issue where null keys were more likely to
+// collide with each other than expected, and also makes the algorithm
+// more amenable to incremental implementations. All other caveats from
+// MurmurHash2 still apply.
+
+#ifndef __MURMUR_HASH2A_H
+#define __MURMUR_HASH2A_H
+
+#include <windef.h>
+#include "os_dep.h"
+
+typedef UINT32 uint32_t;
+typedef UINT16 uint16_t;
+typedef UINT8 uint8_t;
+
+#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+_inline uint32_t MurmurHash2A(const void * key, uint32_t len, uint32_t seed )
+{
+    const uint32_t m = 0x5bd1e995;
+    const uint32_t r = 24;
+    uint32_t l = len;
+    uint32_t t = 0;
+
+    const uint8_t * data = (const uint8_t *)key;
+
+    uint32_t h = seed;
+
+    while (len >= 4) {
+        uint32_t k = *(uint32_t*)data;
+
+        mmix(h,k);
+
+        data += 4;
+        len -= 4;
+    }
+
+    switch (len) {
+    case 3: t ^= data[2] << 16;
+    case 2: t ^= data[1] << 8;
+    case 1: t ^= data[0];
+    };
+
+    mmix(h,t);
+    mmix(h,l);
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+}
+
+_inline uint32_t MurmurHash2AJump3(const uint32_t * key, uint32_t len, uint32_t seed )
+{
+    uint32_t m = 0x5bd1e995;
+    uint32_t r = 24;
+    uint32_t l = len << 2;
+
+    const uint8_t * data = (const uint8_t *)key;
+
+    uint32_t h = seed;
+
+    while (len >= 4) {
+        uint32_t k = *(uint32_t*)data;
+        uint32_t tmp;
+
+        data += 4;
+        tmp = *(uint32_t *)data;
+        k = k << 8;
+        k |= (uint8_t)tmp;
+        mmix(h,k);
+
+        k = tmp << 8;
+        k = k & 0xffff0000;
+        data += 4;
+        tmp = *(uint32_t *)data;
+        k |= (uint16_t)(tmp >> 8);
+        mmix(h,k);
+
+        data += 4;
+        k = *(uint32_t *)data;
+        k = k << 8;
+        k |=  (uint8_t)tmp;
+        mmix(h,k);
+
+        data += 4;
+        len -= 4;
+    }
+
+    while (len >= 1) {
+        uint32_t k = *(uint32_t*)data;
+
+        k = k << 8;
+        mmix(h,k);
+
+        data += 4;
+        len--;
+    }
+
+    h *= m;
+    mmix(h,l);
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+}
+
+
+_inline uint32_t murmurhash2a(const void *key, size_t length, uint32_t initval)
+{
+    return MurmurHash2A(key, length, initval);
+}
+
+_inline uint32_t murmurhash2ajump3(const uint32_t *key, size_t length, uint32_t initval)
+{
+    return MurmurHash2AJump3(key, length, initval);
+}
+#endif
+
diff --git a/xddm/include/os_dep.h b/xddm/include/os_dep.h
new file mode 100644
index 0000000..ad229e2
--- /dev/null
+++ b/xddm/include/os_dep.h
@@ -0,0 +1,41 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef OS_DEP_H
+#define OS_DEP_H
+
+#if (WINVER < 0x0501) //Definitions for Win2K
+typedef signed char         INT8, *PINT8;
+typedef signed short        INT16, *PINT16;
+typedef signed int          INT32, *PINT32;
+typedef signed __int64      INT64, *PINT64;
+typedef unsigned char       UINT8, *PUINT8;
+typedef unsigned short      UINT16, *PUINT16;
+typedef unsigned int        UINT32, *PUINT32;
+typedef unsigned __int64    UINT64, *PUINT64;
+
+#define SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA     0x50
+
+#define VideoPortFreePool VideoPortReleaseBuffer
+
+#endif
+
+#endif
diff --git a/xddm/include/qxl_driver.h b/xddm/include/qxl_driver.h
new file mode 100644
index 0000000..677ee17
--- /dev/null
+++ b/xddm/include/qxl_driver.h
@@ -0,0 +1,127 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _H_QXL_DRIVER
+#define _H_QXL_DRIVER
+
+#include <spice\qxl_dev.h>
+#include <spice\qxl_windows.h>
+
+#if (WINVER < 0x0501)
+#include "wdmhelper.h"
+#endif
+
+enum {
+    FIRST_AVIL_IOCTL_FUNC = 0x800,
+    QXL_GET_INFO_FUNC = FIRST_AVIL_IOCTL_FUNC,
+    QXL_SET_CUSTOM_DISPLAY
+};
+
+#define IOCTL_QXL_GET_INFO \
+    CTL_CODE(FILE_DEVICE_VIDEO, QXL_GET_INFO_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_QXL_SET_CUSTOM_DISPLAY \
+    CTL_CODE(FILE_DEVICE_VIDEO, QXL_SET_CUSTOM_DISPLAY, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define QXL_DRIVER_INFO_VERSION 3
+
+typedef struct MemSlot {
+    UINT8 generation;
+    UINT64 start_phys_addr;
+    UINT64 end_phys_addr;
+    UINT64 start_virt_addr;
+    UINT64 end_virt_addr;
+} MemSlot;
+
+typedef struct QXLDriverInfo {
+    UINT32 version;
+    QXLCommandRing *cmd_ring;
+    QXLCursorRing *cursor_ring;
+    QXLReleaseRing *release_ring;
+    PUCHAR notify_cmd_port;
+    PUCHAR notify_cursor_port;
+    PUCHAR notify_oom_port;
+    PUCHAR update_area_async_port;
+    PUCHAR memslot_add_async_port;
+    PUCHAR create_primary_async_port;
+    PUCHAR destroy_primary_async_port;
+    PUCHAR destroy_surface_async_port;
+    PUCHAR destroy_all_surfaces_async_port;
+    PUCHAR flush_surfaces_async_port;
+    PUCHAR flush_release_port;
+    PEVENT display_event;
+    PEVENT cursor_event;
+    PEVENT sleep_event;
+    PEVENT io_cmd_event;
+
+    UINT32 num_pages;
+    void *io_pages_virt;
+    UINT64 io_pages_phys;
+
+    UINT8 *surface0_area;
+    UINT32 surface0_area_size;
+
+    UINT32 *update_id;
+    UINT32 *compression_level;
+
+    PUCHAR update_area_port;
+    QXLRect *update_area;
+    UINT32 *update_surface;
+
+    UINT32 *mm_clock;
+
+    PUCHAR log_port;
+    UINT8 *log_buf;
+    UINT32 *log_level;
+#if (WINVER < 0x0501)
+    PQXLWaitForEvent WaitForEvent;
+#endif
+    UINT8 num_mem_slot;
+    UINT8 main_mem_slot_id;
+    UINT8 slot_id_bits;
+    UINT8 slot_gen_bits;
+    UINT8 *slots_generation;
+    UINT64 *ram_slot_start;
+    UINT64 *ram_slot_end;
+    MemSlot main_mem_slot;
+
+    PUCHAR destroy_surface_wait_port;
+    PUCHAR create_primary_port;
+    PUCHAR destroy_primary_port;
+    PUCHAR memslot_add_port;
+    PUCHAR memslot_del_port;
+    PUCHAR destroy_all_surfaces_port;
+
+    UCHAR  pci_revision;
+
+    UINT32 dev_id;
+
+    QXLSurfaceCreate *primary_surface_create;
+
+    UINT32 n_surfaces;
+
+    UINT64 fb_phys;
+
+    UINT8 create_non_primary_surfaces;
+} QXLDriverInfo;
+
+#endif
+
diff --git a/xddm/include/stdint.h b/xddm/include/stdint.h
new file mode 100644
index 0000000..f825d4b
--- /dev/null
+++ b/xddm/include/stdint.h
@@ -0,0 +1,397 @@
+/* ISO C9x  7.18  Integer types <stdint.h>
+
+ * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
+
+ *
+
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+
+ *
+
+ *  Contributor: Danny Smith <danny_r_smith_2001 at yahoo.co.nz>
+
+ *
+
+ *  This source code is offered for use in the public domain. You may
+
+ *  use, modify or distribute it freely.
+
+ *
+
+ *  This code is distributed in the hope that it will be useful but
+
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+
+ *  DISCLAIMED. This includes but is not limited to warranties of
+
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ *
+
+ *  Date: 2000-12-02
+
+ */
+
+
+
+
+
+#ifndef _STDINT_H
+
+#define _STDINT_H
+
+#define __need_wint_t
+
+#define __need_wchar_t
+
+#include <stddef.h>
+
+
+
+#ifdef _WIN32_WCE
+
+typedef _int64 int64_t;
+
+typedef unsigned _int64 uint64_t;
+
+#else
+
+typedef long long  int64_t;
+
+typedef unsigned long long   uint64_t;
+
+#endif /* _WIN32_WCE */
+
+
+
+/* 7.18.1.1  Exact-width integer types */
+
+typedef signed char int8_t;
+
+typedef unsigned char   uint8_t;
+
+typedef short  int16_t;
+
+typedef unsigned short  uint16_t;
+
+typedef int  int32_t;
+
+typedef unsigned   uint32_t;
+
+
+
+/* 7.18.1.2  Minimum-width integer types */
+
+typedef signed char int_least8_t;
+
+typedef unsigned char   uint_least8_t;
+
+typedef short  int_least16_t;
+
+typedef unsigned short  uint_least16_t;
+
+typedef int  int_least32_t;
+
+typedef unsigned   uint_least32_t;
+
+#ifndef _WIN32_WCE
+
+typedef long long  int_least64_t;
+
+typedef unsigned long long   uint_least64_t;
+
+#endif
+
+
+
+/*  7.18.1.3  Fastest minimum-width integer types 
+
+ *  Not actually guaranteed to be fastest for all purposes
+
+ *  Here we use the exact-width types for 8 and 16-bit ints. 
+
+ */
+
+typedef char int_fast8_t;
+
+typedef unsigned char uint_fast8_t;
+
+typedef short  int_fast16_t;
+
+typedef unsigned short  uint_fast16_t;
+
+typedef int  int_fast32_t;
+
+typedef unsigned  int  uint_fast32_t;
+
+#ifndef _WIN32_WCE
+
+typedef long long  int_fast64_t;
+
+typedef unsigned long long   uint_fast64_t;
+
+#endif
+
+
+
+/* 7.18.1.4  Integer types capable of holding object pointers */
+
+#ifndef _WIN64
+
+typedef int intptr_t;
+
+typedef unsigned uintptr_t;
+
+#endif
+
+/* 7.18.1.5  Greatest-width integer types */
+
+#ifndef _WIN32_WCE
+
+typedef long long  intmax_t;
+
+typedef unsigned long long   uintmax_t;
+
+#endif
+
+
+
+/* 7.18.2  Limits of specified-width integer types */
+
+#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
+
+
+
+/* 7.18.2.1  Limits of exact-width integer types */
+
+#define INT8_MIN (-128) 
+
+#define INT16_MIN (-32768)
+
+#define INT32_MIN (-2147483647 - 1)
+
+#define INT64_MIN  (-9223372036854775807LL - 1)
+
+
+
+#define INT8_MAX 127
+
+#define INT16_MAX 32767
+
+#define INT32_MAX 2147483647
+
+#define INT64_MAX 9223372036854775807LL
+
+
+
+#define UINT8_MAX 0xff /* 255U */
+
+#define UINT16_MAX 0xffff /* 65535U */
+
+#define UINT32_MAX 0xffffffff  /* 4294967295U */
+
+#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+
+
+
+/* 7.18.2.2  Limits of minimum-width integer types */
+
+#define INT_LEAST8_MIN INT8_MIN
+
+#define INT_LEAST16_MIN INT16_MIN
+
+#define INT_LEAST32_MIN INT32_MIN
+
+#define INT_LEAST64_MIN INT64_MIN
+
+
+
+#define INT_LEAST8_MAX INT8_MAX
+
+#define INT_LEAST16_MAX INT16_MAX
+
+#define INT_LEAST32_MAX INT32_MAX
+
+#define INT_LEAST64_MAX INT64_MAX
+
+
+
+#define UINT_LEAST8_MAX UINT8_MAX
+
+#define UINT_LEAST16_MAX UINT16_MAX
+
+#define UINT_LEAST32_MAX UINT32_MAX
+
+#define UINT_LEAST64_MAX UINT64_MAX
+
+
+
+/* 7.18.2.3  Limits of fastest minimum-width integer types */
+
+#define INT_FAST8_MIN INT8_MIN
+
+#define INT_FAST16_MIN INT16_MIN
+
+#define INT_FAST32_MIN INT32_MIN
+
+#define INT_FAST64_MIN INT64_MIN
+
+
+
+#define INT_FAST8_MAX INT8_MAX
+
+#define INT_FAST16_MAX INT16_MAX
+
+#define INT_FAST32_MAX INT32_MAX
+
+#define INT_FAST64_MAX INT64_MAX
+
+
+
+#define UINT_FAST8_MAX UINT8_MAX
+
+#define UINT_FAST16_MAX UINT16_MAX
+
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define UINT_FAST64_MAX UINT64_MAX
+
+
+
+/* 7.18.2.4  Limits of integer types capable of holding
+
+    object pointers */ 
+
+#define INTPTR_MIN INT32_MIN
+
+#define INTPTR_MAX INT32_MAX
+
+#define UINTPTR_MAX UINT32_MAX
+
+
+
+/* 7.18.2.5  Limits of greatest-width integer types */
+
+#define INTMAX_MIN INT64_MIN
+
+#define INTMAX_MAX INT64_MAX
+
+#define UINTMAX_MAX UINT64_MAX
+
+
+
+/* 7.18.3  Limits of other integer types */
+
+#define PTRDIFF_MIN INT32_MIN
+
+#define PTRDIFF_MAX INT32_MAX
+
+
+
+#define SIG_ATOMIC_MIN INT32_MIN
+
+#define SIG_ATOMIC_MAX INT32_MAX
+
+
+
+#ifndef SIZE_MAX
+#define SIZE_MAX UINT32_MAX
+#endif
+
+
+#ifndef WCHAR_MIN  /* also in wchar.h */ 
+
+#define WCHAR_MIN 0
+
+#define WCHAR_MAX 0xffff /* UINT16_MAX */
+
+#endif
+
+
+
+/*
+
+ * wint_t is unsigned short for compatibility with MS runtime
+
+ */
+
+#define WINT_MIN 0
+
+#define WINT_MAX 0xffff /* UINT16_MAX */
+
+
+
+#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
+
+
+
+
+
+/* 7.18.4  Macros for integer constants */
+
+#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
+
+
+
+/* 7.18.4.1  Macros for minimum-width integer constants
+
+
+
+    Accoding to Douglas Gwyn <gwyn at arl.mil>:
+
+	"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
+
+	9899:1999 as initially published, the expansion was required
+
+	to be an integer constant of precisely matching type, which
+
+	is impossible to accomplish for the shorter types on most
+
+	platforms, because C99 provides no standard way to designate
+
+	an integer constant with width less than that of type int.
+
+	TC1 changed this to require just an integer constant
+
+	*expression* with *promoted* type."
+
+*/
+
+
+
+#define INT8_C(val) ((int8_t) + (val))
+
+#define UINT8_C(val) ((uint8_t) + (val##U))
+
+#define INT16_C(val) ((int16_t) + (val))
+
+#define UINT16_C(val) ((uint16_t) + (val##U))
+
+
+
+#define INT32_C(val) val##L
+
+#define UINT32_C(val) val##UL
+
+#define INT64_C(val) val##LL
+
+#define UINT64_C(val) val##ULL
+
+
+
+/* 7.18.4.2  Macros for greatest-width integer constants */
+
+#define INTMAX_C(val)  INT64_C(val)
+
+#define UINTMAX_C(val) UINT64_C(val)
+
+
+
+#endif  /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
+
+
+
+#endif
+
+
+
diff --git a/xddm/include/wdmhelper.h b/xddm/include/wdmhelper.h
new file mode 100644
index 0000000..854a4cc
--- /dev/null
+++ b/xddm/include/wdmhelper.h
@@ -0,0 +1,38 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef WDM_HELPER_H
+#define WDM_HELPER_H
+
+#include "os_dep.h"
+
+typedef ULONG (*PQXLWaitForEvent)(PVOID,PLARGE_INTEGER);
+
+LONG QXLInitializeEvent(PVOID * pEvent);
+void QXLSetEvent(PVOID pEvent);
+void QXLDeleteEvent(PVOID pEvent);
+ULONG QXLWaitForEvent(PVOID pEvent,PLARGE_INTEGER Timeout);
+
+#define VideoPortDeleteEvent(dev,pEvent) QXLDeleteEvent(pEvent)
+#define VideoPortCreateEvent(dev,flag,reserved,ppEvent) QXLInitializeEvent(ppEvent)
+#define VideoPortSetEvent(dev,pEvent) QXLSetEvent(pEvent)
+
+#endif
diff --git a/xddm/miniport/makefile b/xddm/miniport/makefile
new file mode 100644
index 0000000..53b9a3d
--- /dev/null
+++ b/xddm/miniport/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/xddm/miniport/minimal_snprintf.c b/xddm/miniport/minimal_snprintf.c
new file mode 100644
index 0000000..40572c1
--- /dev/null
+++ b/xddm/miniport/minimal_snprintf.c
@@ -0,0 +1,708 @@
+/* $Id: snprintf.c,v 1.2 2003/12/10 01:35:10 lukem Exp $ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ *
+ *  Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats.
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge at samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ *  Luke Mewburn <lukem at NetBSD.org>, Thu Sep 30 23:28:21 EST 1999
+ *	cleaned up formatting, autoconf tests
+ *	added long long support
+ *
+ **************************************************************/
+
+#include "minimal_snprintf.h"
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+static _inline int isdigit(char c)
+{
+    return c >= '0' && c <= '9';
+}
+
+#if HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+static void dopr(char *buffer, size_t maxlen, size_t *retlen,
+		    const char *format, va_list args);
+static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
+		    char *value, int min, int max, int flags);
+static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
+		    LLONG value, int base, int min, int max, int flags);
+#ifdef SUPPORT_FLOAT
+#if HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
+		    LDOUBLE fvalue, int min, int max, int flags);
+#endif
+static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, int c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT	0
+#define DP_S_FLAGS	1
+#define DP_S_MIN	2
+#define DP_S_DOT	3
+#define DP_S_MAX	4
+#define DP_S_MOD	5
+#define DP_S_CONV	6
+#define DP_S_DONE	7
+
+/* format flags - Bits */
+#define DP_F_MINUS	(1 << 0)
+#define DP_F_PLUS	(1 << 1)
+#define DP_F_SPACE	(1 << 2)
+#define DP_F_NUM	(1 << 3)
+#define DP_F_ZERO	(1 << 4)
+#define DP_F_UP		(1 << 5)
+#define DP_F_UNSIGNED	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT	1
+#define DP_C_LONG	2
+#ifdef SUPPORT_FLOAT
+#define DP_C_LDOUBLE	3
+#endif
+#define DP_C_LLONG	4
+
+#define char_to_int(p) (p - '0')
+
+static void
+dopr(char *buffer, size_t maxlen, size_t *retlen, const char *format,
+	va_list args)
+{
+	char	 ch;
+	LLONG	 value;
+#ifdef SUPPORT_FLOAT
+	LDOUBLE	 fvalue;
+#endif
+	char	*strvalue;
+	int	 min;
+	int	 max;
+	int	 state;
+	int	 flags;
+	int	 cflags;
+	size_t	 currlen;
+
+	state = DP_S_DEFAULT;
+	flags = currlen = cflags = min = 0;
+	max = -1;
+	ch = *format++;
+
+	while (state != DP_S_DONE) {
+		if ((ch == '\0') || (currlen >= maxlen))
+			state = DP_S_DONE;
+
+		switch (state) {
+		case DP_S_DEFAULT:
+			if (ch == '%')
+				state = DP_S_FLAGS;
+			else
+				dopr_outch(buffer, &currlen, maxlen, ch);
+			ch = *format++;
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char) ch)) {
+				min = 10 * min + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				min = va_arg(args, int);
+				ch = *format++;
+				state = DP_S_DOT;
+			} else
+				state = DP_S_DOT;
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else
+				state = DP_S_MOD;
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char) ch)) {
+				if (max < 0)
+					max = 0;
+				max = 10 * max + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				max = va_arg(args, int);
+				ch = *format++;
+				state = DP_S_MOD;
+			} else
+				state = DP_S_MOD;
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cflags = DP_C_SHORT;
+				ch = *format++;
+				break;
+			case 'l':
+				if (*format == 'l') {
+					cflags = DP_C_LLONG;
+					format++;
+				} else
+					cflags = DP_C_LONG;
+				ch = *format++;
+				break;
+			case 'q':
+				cflags = DP_C_LLONG;
+				ch = *format++;
+				break;
+#ifdef SUPPORT_FLOAT
+			case 'L':
+				cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+#endif
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			switch (ch) {
+			case 'd':
+			case 'i':
+				switch (cflags) {
+				case DP_C_SHORT:
+					value = va_arg(args, int);
+					break;
+				case DP_C_LONG:
+					value = va_arg(args, long int);
+					break;
+				case DP_C_LLONG:
+					value = va_arg(args, LLONG);
+					break;
+				default:
+					value = va_arg(args, int);
+					break;
+				}
+				fmtint(buffer, &currlen, maxlen, value, 10,
+				    min, max, flags);
+				break;
+			case 'X':
+				flags |= DP_F_UP;
+				/* FALLTHROUGH */
+			case 'x':
+			case 'o':
+			case 'u':
+				flags |= DP_F_UNSIGNED;
+				switch (cflags) {
+				case DP_C_SHORT:
+					value = va_arg(args, unsigned int);
+					break;
+				case DP_C_LONG:
+					value = (LLONG) va_arg(args,
+					    unsigned long int);
+					break;
+				case DP_C_LLONG:
+					value = va_arg(args, unsigned LLONG);
+					break;
+				default:
+					value = (LLONG) va_arg(args,
+					    unsigned int);
+					break;
+				}
+				fmtint(buffer, &currlen, maxlen, value,
+				    ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
+				    min, max, flags);
+				break;
+#ifdef SUPPORT_FLOAT
+			case 'f':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				/* um, floating point? */
+				fmtfp(buffer, &currlen, maxlen, fvalue, min,
+				    max, flags);
+				break;
+			case 'E':
+				flags |= DP_F_UP;
+			case 'e':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'G':
+				flags |= DP_F_UP;
+			case 'g':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				break;
+#endif // SUPPORT_FLOAT
+			case 'c':
+				dopr_outch(buffer, &currlen, maxlen,
+				    va_arg(args, int));
+				break;
+			case 's':
+				strvalue = va_arg(args, char *);
+				if (max < 0)
+					max = maxlen;	/* ie, no max */
+				fmtstr(buffer, &currlen, maxlen, strvalue,
+				    min, max, flags);
+				break;
+			case 'p':
+				value = (long)va_arg(args, void *);
+				fmtint(buffer, &currlen, maxlen,
+				    value, 16, min, max, flags);
+				break;
+			case 'n':
+/* XXX */
+				if (cflags == DP_C_SHORT) {
+					short int *num;
+					num = va_arg(args, short int *);
+					*num = (short)currlen;
+				} else if (cflags == DP_C_LONG) { /* XXX */
+					long int *num;
+					num = va_arg(args, long int *);
+					*num = (long int) currlen;
+				} else if (cflags == DP_C_LLONG) { /* XXX */
+					LLONG *num;
+					num = va_arg(args, LLONG *);
+					*num = (LLONG) currlen;
+				} else {
+					int    *num;
+					num = va_arg(args, int *);
+					*num = currlen;
+				}
+				break;
+			case '%':
+				dopr_outch(buffer, &currlen, maxlen, ch);
+				break;
+			case 'w':
+				/* not supported yet, treat as next char */
+				ch = *format++;
+				break;
+			default:
+				/* Unknown, skip */
+				break;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			flags = cflags = min = 0;
+			max = -1;
+			break;
+		case DP_S_DONE:
+			break;
+		default:
+			/* hmm? */
+			break;	/* some picky compilers need this */
+		}
+	}
+	if (currlen >= maxlen - 1)
+		currlen = maxlen - 1;
+	buffer[currlen] = '\0';
+	*retlen = currlen;
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
+	int min, int max, int flags)
+{
+	int	padlen, strln;	/* amount to pad */
+	int	cnt = 0;
+
+	if (value == 0) {
+		value = "<NULL>";
+	}
+	for (strln = 0; value[strln]; ++strln)
+		;	/* strlen */
+	padlen = min - strln;
+	if (padlen < 0)
+		padlen = 0;
+	if (flags & DP_F_MINUS)
+		padlen = -padlen;	/* Left Justify */
+
+	while ((padlen > 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+		++cnt;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while ((padlen < 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+		++cnt;
+	}
+}
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void
+fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base,
+	int min, int max, int flags)
+{
+	int		signvalue = 0;
+	unsigned LLONG	uvalue;
+	char		convert[20];
+	int		place = 0;
+	int		spadlen = 0;	/* amount to space pad */
+	int		zpadlen = 0;	/* amount to zero pad */
+	int		caps = 0;
+
+	if (max < 0)
+		max = 0;
+
+	uvalue = value;
+
+	if (!(flags & DP_F_UNSIGNED)) {
+		if (value < 0) {
+			signvalue = '-';
+			uvalue = -value;
+		} else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
+			signvalue = '+';
+		else if (flags & DP_F_SPACE)
+			signvalue = ' ';
+	}
+	if (flags & DP_F_UP)
+		caps = 1;	/* Should characters be upper case? */
+
+	do {
+		convert[place++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [uvalue % (unsigned) base];
+		uvalue = (uvalue / (unsigned) base);
+	} while (uvalue && (place < 20));
+	if (place == 20)
+		place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (spadlen < 0)
+		spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = MAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS)
+		spadlen = -spadlen;	/* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+	    zpadlen, spadlen, min, max, place);
+#endif
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue)
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+	/* Digits */
+	while (place > 0)
+		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+#ifdef SUPPORT_FLOAT
+static LDOUBLE
+abs_val(LDOUBLE value)
+{
+	LDOUBLE	result = value;
+
+	if (value < 0)
+		result = -value;
+
+	return result;
+}
+
+static LDOUBLE
+pow10(int exp)
+{
+	LDOUBLE	result = 1;
+
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+
+	return result;
+}
+
+static long
+round(LDOUBLE value)
+{
+	long	intpart;
+
+	intpart = (long) value;
+	value = value - intpart;
+	if (value >= 0.5)
+		intpart++;
+
+	return intpart;
+}
+
+static void
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
+	int min, int max, int flags)
+{
+	int	signvalue = 0;
+	LDOUBLE	ufvalue;
+	char	iconvert[20];
+	char	fconvert[20];
+	int	iplace = 0;
+	int	fplace = 0;
+	int	padlen = 0;	/* amount to pad */
+	int	zpadlen = 0;
+	int	caps = 0;
+	long	intpart;
+	long	fracpart;
+
+	/* AIX manpage says the default is 0, but Solaris says the default is
+	 * 6, and sprintf on AIX defaults to 6 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val(fvalue);
+
+	if (fvalue < 0)
+		signvalue = '-';
+	else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
+		signvalue = '+';
+	else if (flags & DP_F_SPACE)
+		signvalue = ' ';
+
+#if 0
+	if (flags & DP_F_UP)
+		caps = 1;	/* Should characters be upper case? */
+#endif
+
+	intpart = (long) ufvalue;
+
+	/* Sorry, we only support 9 digits past the decimal because of our
+	 * conversion method */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10 */
+	fracpart = round((pow10(max)) * (ufvalue - intpart));
+
+	if (fracpart >= pow10(max)) {
+		intpart++;
+		fracpart -= (long)pow10(max);
+	}
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: %g %d.%d min=%d max=%d\n",
+	    (double) fvalue, intpart, fracpart, min, max);
+#endif
+
+	/* Convert integer part */
+	do {
+		iconvert[iplace++] =
+		    (caps ? "0123456789ABCDEF"
+			  : "0123456789abcdef")[intpart % 10];
+		intpart = (intpart / 10);
+	} while (intpart && (iplace < 20));
+	if (iplace == 20)
+		iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	do {
+		fconvert[fplace++] =
+		    (caps ? "0123456789ABCDEF"
+			  : "0123456789abcdef")[fracpart % 10];
+		fracpart = (fracpart / 10);
+	} while (fracpart && (fplace < 20));
+	if (fplace == 20)
+		fplace--;
+	fconvert[fplace] = 0;
+
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+	zpadlen = max - fplace;
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (padlen < 0)
+		padlen = 0;
+	if (flags & DP_F_MINUS)
+		padlen = -padlen;	/* Left Justifty */
+
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch(buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue)
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	while (iplace > 0)
+		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+	/*
+         * Decimal point.  This should probably use locale to find the correct
+         * char to print out.
+         */
+	if (max > 0) {
+		dopr_outch(buffer, currlen, maxlen, '.');
+
+		while (fplace > 0)
+			dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+	}
+	while (zpadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, '0');
+		--zpadlen;
+	}
+
+	while (padlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+#endif // SUPPORT_FLOAT
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
+{
+	if (*currlen < maxlen)
+		buffer[(*currlen)++] = (char)c;
+}
+
+int
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+	size_t retlen;
+
+	str[0] = 0;
+	dopr(str, count, &retlen, fmt, args);
+	return (retlen);
+}
+
+/* VARARGS3 */
+int
+snprintf(char *str, size_t count, const char *fmt, ...)
+{
+	va_list	 ap;
+	int	 rv;
+
+	va_start(ap, fmt);
+	rv = vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+	return (rv);
+}
diff --git a/xddm/miniport/minimal_snprintf.h b/xddm/miniport/minimal_snprintf.h
new file mode 100644
index 0000000..e26f1da
--- /dev/null
+++ b/xddm/miniport/minimal_snprintf.h
@@ -0,0 +1,9 @@
+#ifndef MINIMAL_SNPRINTF_H
+#define MINIMAL_SNPRINTF_H
+
+#include <stdarg.h>
+
+int snprintf(char *str, size_t count, const char *fmt, ...);
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+
+#endif // MINIMAL_SNPRINTF_H
diff --git a/xddm/miniport/qxl.c b/xddm/miniport/qxl.c
new file mode 100644
index 0000000..58ba15e
--- /dev/null
+++ b/xddm/miniport/qxl.c
@@ -0,0 +1,1311 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "os_dep.h"
+#include "qxl.h"
+#if (WINVER < 0x0501)
+#include "wdmhelper.h"
+#endif
+#include "minimal_snprintf.h"
+
+VP_STATUS FindAdapter(PVOID dev_extension,
+                      PVOID reserved,
+                      PWSTR arg_str,
+                      PVIDEO_PORT_CONFIG_INFO conf_info,
+                      PUCHAR again);
+
+BOOLEAN Initialize(PVOID dev_extension);
+
+VP_STATUS GetPowerState(PVOID dev_extension,
+                        ULONG hw_id,
+                        PVIDEO_POWER_MANAGEMENT state);
+
+VP_STATUS SetPowerState(PVOID dev_extension,
+                        ULONG hw_wId,
+                        PVIDEO_POWER_MANAGEMENT state);
+
+VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
+                             IN PVIDEO_CHILD_ENUM_INFO  enum_info,
+                             OUT PVIDEO_CHILD_TYPE  type,
+                             OUT PUCHAR descriptor,
+                             OUT PULONG uid,
+                             OUT PULONG unused);
+
+BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet);
+
+BOOLEAN Interrupt(PVOID  HwDeviceExtension);
+
+#if defined(ALLOC_PRAGMA)
+#pragma alloc_text(PAGE, DriverEntry)
+#pragma alloc_text(PAGE, FindAdapter)
+#pragma alloc_text(PAGE, Initialize)
+#pragma alloc_text(PAGE, GetPowerState)
+#pragma alloc_text(PAGE, SetPowerState)
+#pragma alloc_text(PAGE, GetChildDescriptor)
+#pragma alloc_text(PAGE, StartIO)
+#endif
+
+typedef struct QXLExtension {
+    PVOID io_base;
+    PUCHAR io_port;
+
+    UCHAR pci_revision;
+
+    QXLRom *rom;
+    ULONG rom_size;
+
+    PHYSICAL_ADDRESS ram_physical;
+    UINT8 *ram_start;
+    QXLRam *ram_header;
+    ULONG ram_size;
+
+    PHYSICAL_ADDRESS vram_physical;
+    ULONG vram_size;
+    UINT8 *vram_start;
+
+    ULONG current_mode;
+    ULONG n_modes;
+    ULONG custom_mode;
+    PVIDEO_MODE_INFORMATION modes;
+
+    PEVENT display_event;
+    PEVENT cursor_event;
+    PEVENT sleep_event;
+    PEVENT io_cmd_event;
+
+    MemSlot *mem_slots;
+
+    char *log_buf;
+    PUCHAR log_port;
+
+    UINT8 create_non_primary_surfaces;
+} QXLExtension;
+
+#define QXL_ALLOC_TAG '_lxq'
+
+#define DBG_LEVEL 10
+
+#define QXL_MINIPORT_DEBUG_PREFIX "qxlmp: "
+
+void DebugPrintV(char *log_buf, PUCHAR log_port, const char *message, const char *func, va_list ap)
+{
+    int n, n_strlen;
+
+    if (log_buf && log_port) {
+        /*
+         * TODO: use a shared semaphore with display code.
+         * In practice this is not a problem, since miniport runs either on ioctls (sync)
+         * or before display is brought up or when it is brought down.
+         * Also the worst that can happen is overwriting a message (not seen in practice).
+         */
+        snprintf(log_buf, QXL_LOG_BUF_SIZE, QXL_MINIPORT_DEBUG_PREFIX);
+        vsnprintf(log_buf + strlen(QXL_MINIPORT_DEBUG_PREFIX),
+                   QXL_LOG_BUF_SIZE - strlen(QXL_MINIPORT_DEBUG_PREFIX),
+                   message, ap);
+        VideoPortWritePortUchar(log_port, 0);
+    } else {
+        VideoDebugPrint((0, (PCHAR)message, ap));
+    }
+}
+
+void DebugPrint(QXLExtension *dev, UINT32 level, const char *message, const char *func, ...)
+{
+    va_list ap;
+
+    if (dev && dev->rom && level > dev->rom->log_level) {
+        return;
+    }
+    va_start(ap, message);
+    DebugPrintV(dev ? dev->log_buf : NULL, dev ? dev->log_port : 0, message, func, ap);
+    va_end(ap);
+}
+
+ULONG DriverEntry(PVOID context1, PVOID context2)
+{
+    VIDEO_HW_INITIALIZATION_DATA init_data;
+    ULONG ret;
+
+    PAGED_CODE();
+
+    DEBUG_PRINT((NULL, 0, "%s: enter\n", __FUNCTION__));
+
+    VideoPortZeroMemory(&init_data, sizeof(VIDEO_HW_INITIALIZATION_DATA));
+    init_data.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
+    init_data.HwDeviceExtensionSize = sizeof(QXLExtension);
+
+    init_data.HwFindAdapter = FindAdapter;
+    init_data.HwInitialize = Initialize;
+    init_data.HwGetPowerState = GetPowerState;
+    init_data.HwSetPowerState = SetPowerState;
+    init_data.HwGetVideoChildDescriptor = GetChildDescriptor;
+    init_data.HwStartIO = StartIO;
+    init_data.HwInterrupt = Interrupt;
+
+    ret = VideoPortInitialize(context1, context2, &init_data, NULL);
+
+    if (ret != NO_ERROR) {
+        DEBUG_PRINT((NULL, 0, "%s: try W2K %u\n", __FUNCTION__, ret));
+        init_data.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
+        ret = VideoPortInitialize(context1, context2, &init_data, NULL);
+    }
+    DEBUG_PRINT((NULL, 0, "%s: exit %u\n", __FUNCTION__, ret));
+    return ret;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitIO)
+#endif
+
+VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+    PVOID io_base;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+
+    if ((dev->pci_revision == QXL_REVISION_STABLE_V06 &&
+         range->RangeLength < QXL_IO_DESTROY_ALL_SURFACES + 1)
+        || (dev->pci_revision > QXL_REVISION_STABLE_V06 &&
+         range->RangeLength < QXL_IO_FLUSH_RELEASE + 1)
+        || !range->RangeInIoSpace) {
+        DEBUG_PRINT((dev, 0, "%s: bad io range\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+
+    io_base = VideoPortGetDeviceBase(dev, range->RangeStart, range->RangeLength,
+                                     range->RangeInIoSpace);
+
+    if (!io_base) {
+        DEBUG_PRINT((dev, 0, "%s: get io base failed\n", __FUNCTION__));
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    dev->io_base = io_base;
+    dev->io_port = (PUCHAR)range->RangeStart.LowPart;
+    dev->log_port = dev->io_port + QXL_IO_LOG;
+    DEBUG_PRINT((dev, 0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
+                 (ULONG)range->RangeStart.LowPart, range->RangeLength));
+
+    return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitRom)
+#endif
+
+VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+    PVOID rom = NULL;
+    ULONG rom_size = range->RangeLength;
+    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+
+    if (rom_size < sizeof(QXLRom) || range->RangeInIoSpace) {
+        DEBUG_PRINT((dev, 0, "%s: bad rom range\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+    if ((error = VideoPortMapMemory(dev, range->RangeStart,
+                                    &rom_size, &io_space,
+                                    &rom)) != NO_ERROR ) {
+        DEBUG_PRINT((dev, 0, "%s: map rom filed\n", __FUNCTION__));
+        return error;
+    }
+
+    if (rom_size < range->RangeLength) {
+        DEBUG_PRINT((dev, 0, "%s: short rom map\n", __FUNCTION__));
+        error = ERROR_NOT_ENOUGH_MEMORY;
+        goto err;
+    }
+
+    if (((QXLRom*)rom)->magic != QXL_ROM_MAGIC) {
+        DEBUG_PRINT((dev, 0, "%s: bad rom magic\n", __FUNCTION__));
+        error = ERROR_INVALID_DATA;
+        goto err;
+    }
+
+    dev->rom = rom;
+    dev->rom_size = range->RangeLength;
+    DEBUG_PRINT((dev, 0, "%s OK: rom 0x%lx size %lu\n",
+                 __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
+    return NO_ERROR;
+
+err:
+    VideoPortUnmapMemory(dev, rom, NULL);
+    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
+    return error;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitRam)
+#endif
+
+VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+    UINT8 *ram = NULL;
+    QXLRam *ram_header;
+    ULONG ram_size = range->RangeLength;
+    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+
+    if (ram_size < sizeof(QXLRam) + dev->rom->ram_header_offset || range->RangeInIoSpace) {
+        DEBUG_PRINT((dev, 0, "%s: bad ram range\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+
+    if (ram_size < dev->rom->num_pages << PAGE_SHIFT) {
+        DEBUG_PRINT((dev, 0, "%s: bad ram size\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+
+    if ((error = VideoPortMapMemory(dev, range->RangeStart,
+                                    &ram_size, &io_space,
+                                    &ram)) != NO_ERROR ) {
+        DEBUG_PRINT((dev, 0, "%s: map ram filed\n", __FUNCTION__));
+        return error;
+    }
+
+    if (ram_size < range->RangeLength) {
+        DEBUG_PRINT((dev, 0, "%s: short ram map\n", __FUNCTION__));
+        error = ERROR_NOT_ENOUGH_MEMORY;
+        goto err;
+    }
+    ram_header = (QXLRam *)(ram + dev->rom->ram_header_offset);
+    if (ram_header->magic != QXL_RAM_MAGIC) {
+        DEBUG_PRINT((dev, 0, "%s: bad ram magic\n", __FUNCTION__));
+        error = ERROR_INVALID_DATA;
+        goto err;
+    }
+
+    dev->ram_physical = range->RangeStart;
+    dev->ram_start = ram;
+    dev->ram_header = ram_header;
+    dev->ram_size = range->RangeLength;
+    dev->log_buf = dev->ram_header->log_buf;
+    DEBUG_PRINT((dev, 0, "%s OK: ram 0x%lx size %lu\n",
+                 __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
+    return NO_ERROR;
+
+    err:
+    VideoPortUnmapMemory(dev, ram, NULL);
+    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
+    return error;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitVRAM)
+#endif
+
+VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+    UINT8 *vram_addr = NULL;
+    ULONG vram_mapped_size = range->RangeLength;
+    ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+
+    if (range->RangeLength == 0 || range->RangeInIoSpace) {
+        DEBUG_PRINT((dev, 0, "%s: bad mem range\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+
+    if ((error = VideoPortMapMemory(dev, range->RangeStart,
+                                    &vram_mapped_size,
+                                    &io_space,
+                                    &vram_addr))) {
+        DEBUG_PRINT((dev, 0, "%s: map vram failed\n",  __FUNCTION__));
+        return error;
+    }
+
+    if (vram_mapped_size < range->RangeLength) {
+        DEBUG_PRINT((dev, 0, "%s: vram shrinked\n", __FUNCTION__));
+        VideoPortUnmapMemory(dev, vram_addr, NULL);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    dev->vram_physical = range->RangeStart;
+    dev->vram_start = vram_addr;
+    dev->vram_size = range->RangeLength;
+    DEBUG_PRINT((dev, 0, "%s: OK, vram 0x%lx size %lu vaddr 0x%lx\n", __FUNCTION__,
+                (ULONG)range->RangeStart.QuadPart, range->RangeLength, dev->vram_start));
+    return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
+               PVIDEO_ACCESS_RANGE ranges, int n_ranges);
+#pragma alloc_text(PAGE, Prob)
+#endif
+
+VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
+               PVIDEO_ACCESS_RANGE ranges, int n_ranges)
+{
+    PCI_COMMON_CONFIG pci_conf;
+    ULONG  bus_data_size;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+
+    bus_data_size = VideoPortGetBusData(dev,
+                                        PCIConfiguration,
+                                        0,
+                                        &pci_conf,
+                                        0,
+                                        sizeof(PCI_COMMON_CONFIG));
+
+    if (bus_data_size != sizeof(PCI_COMMON_CONFIG)) {
+        DEBUG_PRINT((dev, 0,  "%s: GetBusData size %d expectes %d\n",
+                     __FUNCTION__, bus_data_size, sizeof(PCI_COMMON_CONFIG)));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if (pci_conf.VendorID != REDHAT_PCI_VENDOR_ID) {
+        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
+                     __FUNCTION__, pci_conf.VendorID, REDHAT_PCI_VENDOR_ID));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if (pci_conf.DeviceID != QXL_DEVICE_ID_STABLE) {
+        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
+                     __FUNCTION__, pci_conf.DeviceID, QXL_DEVICE_ID_STABLE));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if (pci_conf.RevisionID < QXL_REVISION_STABLE_V06) {
+        DEBUG_PRINT((dev, 0,  "%s: bad revision 0x%x expectes at least 0x%x\n",
+                     __FUNCTION__, pci_conf.RevisionID, QXL_REVISION_STABLE_V06));
+        return ERROR_INVALID_PARAMETER;
+    }
+    dev->pci_revision = pci_conf.RevisionID;
+
+    VideoPortZeroMemory(ranges, sizeof(VIDEO_ACCESS_RANGE) * n_ranges);
+    if ((error = VideoPortGetAccessRanges(dev, 0, NULL, n_ranges,
+                                          ranges, NULL, NULL,
+                                          NULL)) != NO_ERROR ) {
+        DEBUG_PRINT((dev, 0, "%s: get access ranges failed status %u\n", __FUNCTION__, error));
+    }
+
+    if (conf_info->BusInterruptLevel == 0 && conf_info->BusInterruptVector == 0) {
+        DEBUG_PRINT((dev, 0, "%s: no interrupt\n", __FUNCTION__));
+        error = ERROR_INVALID_DATA;
+    }
+
+#ifdef DBG
+    if (error == NO_ERROR) {
+        int i;
+
+        DEBUG_PRINT((dev, 0, "%s: interrupt: vector %lu level %lu mode %s\n",
+                     __FUNCTION__,
+                     conf_info->BusInterruptVector,
+                     conf_info->BusInterruptLevel,
+                     (conf_info->InterruptMode == LevelSensitive) ? "LevelSensitive" : "Latched"));
+
+        for (i = 0; i < n_ranges; i++) {
+            DEBUG_PRINT((dev, 0, "%s: range %d start 0x%lx length %lu space %lu\n", __FUNCTION__, i,
+                         (ULONG)ranges[i].RangeStart.QuadPart,
+                         ranges[i].RangeLength,
+                         (ULONG)ranges[i].RangeInIoSpace));
+        }
+    }
+#endif
+
+    DEBUG_PRINT((dev, 0, "%s exit %lu\n", __FUNCTION__, error));
+    return error;
+}
+
+#if defined(ALLOC_PRAGMA)
+void FillVidModeBPP(VIDEO_MODE_INFORMATION *pMode, ULONG bitsR, ULONG bitsG, ULONG bitsB,
+                    ULONG maskR, ULONG maskG, ULONG maskB);
+#pragma alloc_text(PAGE, FillVidModeBPP)
+#endif
+
+/* Fills given video mode BPP related fields */
+void FillVidModeBPP(VIDEO_MODE_INFORMATION *pMode, ULONG bitsR, ULONG bitsG, ULONG bitsB,
+                    ULONG maskR, ULONG maskG, ULONG maskB)
+{
+    pMode->NumberRedBits   = bitsR;
+    pMode->NumberGreenBits = bitsG;
+    pMode->NumberBlueBits  = bitsB;
+    pMode->RedMask         = maskR;
+    pMode->GreenMask       = maskG;
+    pMode->BlueMask        = maskB;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS FillVidModeInfo(VIDEO_MODE_INFORMATION *pMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index);
+#pragma alloc_text(PAGE, FillVidModeInfo)
+#endif
+/* Fills given video mode structure */
+VP_STATUS FillVidModeInfo(VIDEO_MODE_INFORMATION *pMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index)
+{
+    unsigned bytes_pp = (bpp + 7) / 8;
+
+    if (xres <= 0 || yres <= 0)
+        return ERROR_INVALID_DATA;
+
+    VideoPortZeroMemory(pMode, sizeof(VIDEO_MODE_INFORMATION));
+
+    /*Common entries*/
+    pMode->Length                       = sizeof(VIDEO_MODE_INFORMATION);
+    pMode->ModeIndex                    = index;
+    pMode->VisScreenWidth               = xres;
+    pMode->VisScreenHeight              = yres;
+    pMode->ScreenStride                 = (xres * bytes_pp + 3) & ~0x3; /* Pixman requirement */
+    pMode->NumberOfPlanes               = 1;
+    pMode->BitsPerPlane                 = bpp;
+    pMode->Frequency                    = 60;
+    pMode->XMillimeter                  = 320;
+    pMode->YMillimeter                  = 240;
+    pMode->VideoMemoryBitmapWidth       = xres;
+    pMode->VideoMemoryBitmapHeight      = yres;
+    pMode->DriverSpecificAttributeFlags = 0;
+    pMode->AttributeFlags               = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR;
+
+    /*BPP related entries*/
+    switch (bpp)
+    {
+        case 16:
+            FillVidModeBPP(pMode, 5, 5, 5, 0x7C00, 0x3E0, 0x1F);
+            break;
+        case 24:
+        case 32:
+            FillVidModeBPP(pMode, 8, 8, 8, 0xFF0000, 0xFF00, 0xFF);
+            break;
+        default:
+            return ERROR_INVALID_DATA;
+    }
+
+    return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode);
+#pragma alloc_text(PAGE, SetVideoModeInfo)
+#endif
+
+VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode)
+{
+    ULONG color_bits;
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 5, "%s: x %u y %u bits %u stride %u orientation %u\n",
+                 __FUNCTION__, qxl_mode->x_res, qxl_mode->y_res,
+                 qxl_mode->bits, qxl_mode->stride, qxl_mode->orientation));
+
+    video_mode->Length = sizeof(VIDEO_MODE_INFORMATION);
+    video_mode->ModeIndex = qxl_mode->id;
+    video_mode->VisScreenWidth = qxl_mode->x_res;
+    video_mode->VisScreenHeight = qxl_mode->y_res;
+    video_mode->ScreenStride = qxl_mode->stride;
+    video_mode->NumberOfPlanes = 1;
+    video_mode->BitsPerPlane = qxl_mode->bits;
+    video_mode->Frequency = 100;
+    video_mode->XMillimeter = qxl_mode->x_mili;
+    video_mode->YMillimeter = qxl_mode->y_mili;
+    color_bits = (qxl_mode->bits == 16) ? 5 : 8;
+    video_mode->NumberRedBits = color_bits;
+    video_mode->NumberGreenBits = color_bits;
+    video_mode->NumberBlueBits = color_bits;
+
+    video_mode->BlueMask = (1 << color_bits) - 1;
+    video_mode->GreenMask = video_mode->BlueMask << color_bits;
+    video_mode->RedMask = video_mode->GreenMask << color_bits;
+
+    video_mode->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS;
+    video_mode->VideoMemoryBitmapWidth = qxl_mode->x_res;
+    video_mode->VideoMemoryBitmapHeight = qxl_mode->y_res;
+    video_mode->DriverSpecificAttributeFlags = qxl_mode->orientation;
+    DEBUG_PRINT((dev, 5, "%s OK\n", __FUNCTION__));
+    return NO_ERROR;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitModes(QXLExtension *dev);
+#pragma alloc_text(PAGE, InitModes)
+#endif
+
+void DestroyMemSlots(QXLExtension *dev)
+{
+    if (dev->mem_slots) {
+        VideoPortFreePool(dev, dev->mem_slots);
+        dev->mem_slots = NULL;
+    }
+}
+
+VP_STATUS InitMemSlots(QXLExtension *dev)
+{
+#if (WINVER < 0x0501) //Win2K
+    error = VideoPortAllocateBuffer(dev, dev->rom->slots_end * sizeof(MemSlot), &dev->mem_slots);
+
+    if(!dev->mem_slots || error != NO_ERROR) {
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#else
+    if (!(dev->mem_slots = VideoPortAllocatePool(dev, VpPagedPool,
+                                                 dev->rom->slots_end * sizeof(MemSlot),
+                                                 QXL_ALLOC_TAG))) {
+        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#endif
+    VideoPortZeroMemory(dev->mem_slots, dev->rom->slots_end * sizeof(MemSlot));
+
+    return NO_ERROR;
+}
+
+VP_STATUS InitModes(QXLExtension *dev)
+{
+    QXLRom *rom;
+    QXLModes *modes;
+    PVIDEO_MODE_INFORMATION modes_info;
+    ULONG n_modes;
+    ULONG i;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
+    rom = dev->rom;
+    modes = (QXLModes *)((UCHAR*)rom + rom->modes_offset);
+    if (dev->rom_size < rom->modes_offset + sizeof(QXLModes) ||
+        (n_modes = modes->n_modes) == 0 || dev->rom_size <
+        rom->modes_offset + sizeof(QXLModes) + n_modes * sizeof(QXLMode)) {
+        DEBUG_PRINT((dev, 0, "%s: bad rom size\n", __FUNCTION__));
+        return ERROR_INVALID_DATA;
+    }
+
+    n_modes += 2;
+#if (WINVER < 0x0501) //Win2K
+    error = VideoPortAllocateBuffer(dev, n_modes * sizeof(VIDEO_MODE_INFORMATION), &modes_info);
+
+    if(!modes_info || error != NO_ERROR) {
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#else
+    if (!(modes_info = VideoPortAllocatePool(dev, VpPagedPool,
+                                             n_modes * sizeof(VIDEO_MODE_INFORMATION),
+                                             QXL_ALLOC_TAG))) {
+        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#endif
+    VideoPortZeroMemory(modes_info, sizeof(VIDEO_MODE_INFORMATION) * n_modes);
+    for (i = 0; i < modes->n_modes; i++) {
+        error = SetVideoModeInfo(dev, &modes_info[i], &modes->modes[i]);
+        if (error != NO_ERROR) {
+            VideoPortFreePool(dev, modes_info);
+            DEBUG_PRINT((dev, 0, "%s: set video mode failed\n", __FUNCTION__));
+            return error;
+        }
+    }
+
+    /* 2 dummy modes for custom display resolution */
+    /* This is necessary to bypass Windows mode index check, that
+       would prevent reusing the same index */
+    dev->custom_mode = modes->n_modes;
+
+    for (i = dev->custom_mode; i <= dev->custom_mode + 1; ++i) {
+        memcpy(&modes_info[i], &modes_info[0], sizeof(VIDEO_MODE_INFORMATION));
+        modes_info[i].ModeIndex = i;
+    }
+
+    dev->n_modes = n_modes;
+    dev->modes = modes_info;
+    DEBUG_PRINT((dev, 0, "%s OK\n", __FUNCTION__));
+    return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+void DevExternsionCleanup(QXLExtension *dev);
+#pragma alloc_text(PAGE, DevExternsionCleanup)
+#endif
+
+void DevExternsionCleanup(QXLExtension *dev)
+{
+    if (dev->sleep_event) {
+        VideoPortDeleteEvent(dev, dev->sleep_event);
+    }
+
+    if (dev->cursor_event) {
+        VideoPortDeleteEvent(dev, dev->cursor_event);
+    }
+
+    if (dev->display_event) {
+        VideoPortDeleteEvent(dev, dev->display_event);
+    }
+
+    if (dev->io_cmd_event) {
+        VideoPortDeleteEvent(dev, dev->io_cmd_event);
+    }
+
+    if (dev->rom) {
+        VideoPortUnmapMemory(dev, dev->rom, NULL);
+    }
+
+    if (dev->ram_start) {
+        VideoPortUnmapMemory(dev, dev->ram_start, NULL);
+    }
+
+    if (dev->vram_start) {
+        VideoPortUnmapMemory(dev, dev->vram_start, NULL);
+    }
+
+    if (dev->modes) {
+        VideoPortFreePool(dev, dev->modes);
+    }
+
+    if (dev->mem_slots) {
+        DestroyMemSlots(dev);
+    }
+
+    VideoPortZeroMemory(dev, sizeof(QXLExtension));
+}
+
+VP_STATUS FindAdapter(PVOID dev_extension,
+                      PVOID reserved,
+                      PWSTR arg_str,
+                      PVIDEO_PORT_CONFIG_INFO conf_info,
+                      PUCHAR again)
+{
+    QXLExtension *dev_ext = dev_extension;
+    VP_STATUS status;
+    VIDEO_ACCESS_RANGE ranges[QXL_PCI_RANGES];
+    PEVENT display_event = NULL;
+    PEVENT cursor_event = NULL;
+    PEVENT sleep_event = NULL;
+    PEVENT io_cmd_event = NULL;
+#if (WINVER >= 0x0501)
+    VPOSVERSIONINFO  sys_info;
+#endif
+
+    PAGED_CODE();
+
+    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
+
+#if (WINVER >= 0x0501)
+    VideoPortZeroMemory(&sys_info, sizeof(VPOSVERSIONINFO));
+    sys_info.Size = sizeof(VPOSVERSIONINFO);
+    if ((status = VideoPortGetVersion(dev_ext, &sys_info)) != NO_ERROR ||
+        sys_info.MajorVersion < 5 || (sys_info.MajorVersion == 5 && sys_info.MinorVersion < 1) ) {
+        DEBUG_PRINT((dev_ext, 0, "%s: err not supported, status %lu major %lu minor %lu\n",
+                     __FUNCTION__, status, sys_info.MajorVersion, sys_info.MinorVersion));
+        return ERROR_NOT_SUPPORTED;
+    }
+#endif
+
+    if (conf_info->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
+        DEBUG_PRINT((dev_ext, 0, "%s: err configInfo size\n", __FUNCTION__));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if (conf_info->AdapterInterfaceType != PCIBus) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: not a PCI device %d\n",
+                     __FUNCTION__, conf_info->AdapterInterfaceType));
+        return ERROR_DEV_NOT_EXIST;
+    }
+
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &display_event)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: create display event failed %lu\n",
+                     __FUNCTION__, status));
+        return status;
+    }
+
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &cursor_event)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: create cursor event failed %lu\n",
+                     __FUNCTION__, status));
+        VideoPortDeleteEvent(dev_ext, display_event);
+        return status;
+    }
+
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &sleep_event)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: create sleep event failed %lu\n",
+                     __FUNCTION__, status));
+        VideoPortDeleteEvent(dev_ext, display_event);
+        VideoPortDeleteEvent(dev_ext, cursor_event);
+        return status;
+    }
+
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &io_cmd_event)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: create io_cmd event failed %lu\n",
+                     __FUNCTION__, status));
+        VideoPortDeleteEvent(dev_ext, sleep_event);
+        VideoPortDeleteEvent(dev_ext, display_event);
+        VideoPortDeleteEvent(dev_ext, cursor_event);
+        return status;
+    }
+
+    dev_ext->display_event = display_event;
+    dev_ext->cursor_event = cursor_event;
+    dev_ext->sleep_event = sleep_event;
+    dev_ext->io_cmd_event = io_cmd_event;
+
+    if ((status = Prob(dev_ext, conf_info, ranges, QXL_PCI_RANGES)) != NO_ERROR ||
+        (status = InitIO(dev_ext, &ranges[QXL_IO_RANGE_INDEX])) != NO_ERROR ||
+        (status = InitRom(dev_ext, &ranges[QXL_ROM_RANGE_INDEX])) != NO_ERROR ||
+        (status = InitRam(dev_ext, &ranges[QXL_RAM_RANGE_INDEX])) != NO_ERROR ||
+        (status = InitVRAM(dev_ext, &ranges[QXL_VRAM_RANGE_INDEX])) != NO_ERROR ||
+        (status = InitModes(dev_ext)) != NO_ERROR ||
+        (status = InitMemSlots(dev_ext)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0,  "%s: findAdapter failed\n", __FUNCTION__));
+        DevExternsionCleanup(dev_ext);
+    }
+
+    if (VideoPortSetRegistryParameters(dev_extension, L"QxlDeviceID",
+                                       &dev_ext->rom->id, sizeof(UINT32)) != NO_ERROR) {
+        DEBUG_PRINT((dev_ext, 0, "%s: write QXL ID failed\n", __FUNCTION__));
+    }
+
+    DEBUG_PRINT((dev_ext, 0, "%s: exit %lu\n", __FUNCTION__, status));
+    return status;
+}
+
+static BOOLEAN CreateMemSlots(QXLExtension *dev_ext)
+{
+    QXLMemSlot *slot;
+    UINT8 slot_id = dev_ext->rom->slots_start;
+
+    if (slot_id >= dev_ext->rom->slots_end) {
+        DEBUG_PRINT((dev_ext, 0, "%s: start_memslot bigger than nmem_slot\n", __FUNCTION__));
+        return FALSE;
+    }
+
+    dev_ext->mem_slots[slot_id].start_phys_addr = dev_ext->ram_physical.QuadPart;
+    dev_ext->mem_slots[slot_id].end_phys_addr = dev_ext->mem_slots[slot_id].start_phys_addr +
+                                                dev_ext->rom->surface0_area_size +
+                                                dev_ext->rom->num_pages * PAGE_SIZE;
+
+    dev_ext->mem_slots[slot_id].start_virt_addr = (UINT64)dev_ext->ram_start;
+    dev_ext->mem_slots[slot_id].end_virt_addr = dev_ext->mem_slots[slot_id].start_virt_addr +
+                                                dev_ext->rom->surface0_area_size +
+                                                dev_ext->rom->num_pages * PAGE_SIZE;
+
+    dev_ext->ram_header->mem_slot.mem_start = dev_ext->mem_slots[slot_id].start_phys_addr;
+    dev_ext->ram_header->mem_slot.mem_end = dev_ext->mem_slots[slot_id].end_phys_addr;
+
+    VideoPortWritePortUchar((PUCHAR)dev_ext->io_port + QXL_IO_MEMSLOT_ADD, slot_id);
+
+    dev_ext->mem_slots[slot_id].generation = dev_ext->rom->slot_generation;
+
+    return TRUE;
+}
+
+#if defined(ALLOC_PRAGMA)
+void HWReset(QXLExtension *dev_ext);
+#pragma alloc_text(PAGE, HWReset)
+#endif
+
+/* called from HWReset or after returning from sleep from SetPowerState,
+ * when returning from sleep we don't want to do a redundant QXL_IO_RESET */
+static void ResetDeviceWithoutIO(QXLExtension *dev_ext)
+{
+    dev_ext->ram_header->int_mask = ~0;
+    CreateMemSlots(dev_ext);
+}
+
+void HWReset(QXLExtension *dev_ext)
+{
+    PAGED_CODE();
+    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
+    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_RESET, 0);
+    ResetDeviceWithoutIO(dev_ext);
+    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
+}
+
+BOOLEAN Initialize(PVOID dev_ext)
+{
+    PAGED_CODE();
+    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
+    HWReset(dev_ext);
+    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
+    return TRUE;
+}
+
+VP_STATUS GetPowerState(PVOID dev_extension,
+                        ULONG hw_id,
+                        PVIDEO_POWER_MANAGEMENT pm_stat)
+{
+    QXLExtension *dev = dev_extension;
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
+
+    switch (hw_id) {
+    case DISPLAY_ADAPTER_HW_ID:
+        switch (pm_stat->PowerState) {
+        case VideoPowerOn:
+        case VideoPowerStandBy:
+        case VideoPowerSuspend:
+        case VideoPowerOff:
+        case VideoPowerShutdown:
+        case VideoPowerHibernate:
+            DEBUG_PRINT((dev, 0, "%s: OK\n", __FUNCTION__));
+            return NO_ERROR;
+        }
+        break;
+    default:
+        DEBUG_PRINT((dev, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+    }
+    DEBUG_PRINT((dev, 0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
+    return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+}
+
+#ifdef DBG
+static void DebugZeroDeviceMemory(QXLExtension *dev_ext)
+{
+    // don't zero the memory if the ram_start and vram_start are not initialized (a
+    // device has been installed but the monitor is disabled)
+    if (dev_ext->ram_start == 0 || dev_ext->vram_start == 0) {
+        DEBUG_PRINT((dev_ext, 0, "%s: not zeroing memory (addresses not initialized)\n", __FUNCTION__));
+        return;
+    }
+    VideoPortZeroMemory(dev_ext->ram_start, dev_ext->ram_size);
+    VideoPortZeroMemory(dev_ext->vram_start, dev_ext->vram_size);
+}
+#else
+static _inline void DebugZeroDeviceMemory(QXLExtension *dev_ext)
+{
+}
+#endif
+
+VP_STATUS SetPowerState(PVOID dev_extension,
+                        ULONG hw_id,
+                        PVIDEO_POWER_MANAGEMENT pm_stat)
+{
+    QXLExtension *dev_ext = dev_extension;
+    PAGED_CODE();
+    DEBUG_PRINT((dev_ext, 0, "%s (%d): %d: %lu\n", __FUNCTION__, dev_ext->rom->id, hw_id, pm_stat->PowerState));
+
+    switch (hw_id) {
+    case DISPLAY_ADAPTER_HW_ID:
+        switch (pm_stat->PowerState) {
+        case VideoPowerOn:
+            ResetDeviceWithoutIO(dev_ext);
+            break;
+        case VideoPowerStandBy:
+            break;
+        case VideoPowerSuspend:
+            break;
+        case VideoPowerOff:
+            DebugZeroDeviceMemory(dev_ext);
+            break;
+        case VideoPowerShutdown:
+            /* Important: you cannot call out to qxldd.dll here or you get a BSOD. */
+            break;
+        case VideoPowerHibernate:
+            DebugZeroDeviceMemory(dev_ext);
+            break;
+        default:
+            DEBUG_PRINT((dev_ext, 0, "%s: unexpected power state\n", __FUNCTION__));
+            return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+        }
+        break;
+    default:
+        DEBUG_PRINT((dev_ext, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+        return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+    }
+    return NO_ERROR;
+}
+
+VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
+                             IN PVIDEO_CHILD_ENUM_INFO enum_info,
+                             OUT PVIDEO_CHILD_TYPE type,
+                             OUT PUCHAR descriptor,
+                             OUT PULONG uid,
+                             OUT PULONG unused)
+{
+    QXLExtension *dev = dev_extension;
+    PAGED_CODE();
+    DEBUG_PRINT((dev, 0, "%s: enter\n", __FUNCTION__));
+
+    switch (enum_info->ChildIndex) {
+    case 0:
+        DEBUG_PRINT((dev, 0, "%s: ACPI id %u\n", __FUNCTION__, enum_info->ACPIHwId));
+        return ERROR_NO_MORE_DEVICES;
+    case 1:
+        DEBUG_PRINT((dev, 0, "%s: Monitor\n", __FUNCTION__));
+        /*
+        *pChildType = Monitor;
+        todo: handle EDID
+        return ERROR_MORE_DATA;
+        */
+        return ERROR_NO_MORE_DEVICES;
+    }
+    DEBUG_PRINT((dev, 0, "%s: ERROR_NO_MORE_DEVICES\n", __FUNCTION__));
+    return ERROR_NO_MORE_DEVICES;
+}
+
+#if defined(ALLOC_PRAGMA)
+PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode);
+#pragma alloc_text(PAGE, FindMode)
+#endif
+
+#define IsValidMode(dev, mode) (FindMode(dev, mode) != NULL)
+
+PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode)
+{
+    VIDEO_MODE_INFORMATION *inf;
+    VIDEO_MODE_INFORMATION *end;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
+
+    inf = dev_ext->modes;
+    end = inf + dev_ext->n_modes;
+    for (; inf < end; inf++) {
+        if (inf->ModeIndex == mode) {
+            DEBUG_PRINT((dev_ext, 0, "%s: OK mode %lu res %lu-%lu orientation %lu\n", __FUNCTION__,
+                         mode, inf->VisScreenWidth, inf->VisScreenHeight,
+                         inf->DriverSpecificAttributeFlags ));
+            return inf;
+        }
+    }
+    DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
+    return NULL;
+}
+
+static VP_STATUS SetCustomDisplay(QXLExtension *dev_ext, QXLEscapeSetCustomDisplay *custom_display)
+{
+    /* alternate custom mode index */
+    if (dev_ext->custom_mode == (dev_ext->n_modes - 1))
+        dev_ext->custom_mode = dev_ext->n_modes - 2;
+    else
+        dev_ext->custom_mode = dev_ext->n_modes - 1;
+
+    return FillVidModeInfo(&dev_ext->modes[dev_ext->custom_mode],
+                           custom_display->xres, custom_display->yres,
+                           custom_display->bpp,
+                           dev_ext->custom_mode);
+}
+
+VP_STATUS QXLRegistryCallback(
+  PVOID HwDeviceExtension,
+  PVOID Context,
+  PWSTR ValueName,
+  PVOID ValueData,
+  ULONG ValueLength
+)
+{
+    QXLExtension *dev_ext = HwDeviceExtension;
+    ULONG *key_ret = (ULONG *)Context;
+
+    DEBUG_PRINT((dev_ext, 60, "%s: length %d, first byte %d\n", __FUNCTION__,
+                ValueLength, (UINT8)ValueData));
+
+    if (key_ret) {
+        *key_ret = *(PULONG)ValueData;
+    }
+    return NO_ERROR;
+}
+
+static UINT8 check_non_primary_surfaces_registry_key(QXLExtension *dev_ext)
+{
+    VP_STATUS ret;
+    ULONG key_ret;
+
+    ret = VideoPortGetRegistryParameters(
+              dev_ext,
+              L"DisableSurfaces",
+              FALSE,
+              QXLRegistryCallback,
+              &key_ret);
+    if (ret == ERROR_INVALID_PARAMETER) {
+        dev_ext->create_non_primary_surfaces = 1;
+        DEBUG_PRINT((dev_ext, 0, "%s: CreateNonPrimarySurfaces key doesn't exist, default to 1\n",
+                    __FUNCTION__));
+    } else {
+        dev_ext->create_non_primary_surfaces = 0;
+    }
+    return dev_ext->create_non_primary_surfaces;
+}
+
+BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
+{
+    QXLExtension *dev_ext = dev_extension;
+    VP_STATUS error;
+
+    PAGED_CODE();
+    DEBUG_PRINT((dev_ext, 0, "%s %d\n", __FUNCTION__, packet->IoControlCode));
+
+    switch (packet->IoControlCode) {
+    case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
+        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n", __FUNCTION__));
+        if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+                                          sizeof(VIDEO_NUM_MODES))) {
+            error = ERROR_INSUFFICIENT_BUFFER;
+            goto err;
+        }
+        ((PVIDEO_NUM_MODES)packet->OutputBuffer)->NumModes = dev_ext->n_modes;
+        ((PVIDEO_NUM_MODES)packet->OutputBuffer)->ModeInformationLength =
+        sizeof(VIDEO_MODE_INFORMATION);
+        break;
+    case IOCTL_VIDEO_QUERY_AVAIL_MODES: {
+            VIDEO_MODE_INFORMATION *inf;
+            VIDEO_MODE_INFORMATION *end;
+            VIDEO_MODE_INFORMATION *out;
+
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_AVAIL_MODES\n", __FUNCTION__));
+            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+                                              dev_ext->n_modes * sizeof(VIDEO_MODE_INFORMATION))) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+            out = packet->OutputBuffer;
+            inf = dev_ext->modes;
+            end = inf + dev_ext->n_modes;
+            for ( ;inf < end; out++, inf++) {
+                *out = *inf;
+            }
+        }
+        break;
+    case IOCTL_VIDEO_SET_CURRENT_MODE: {
+            ULONG request_mode;
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_SET_CURRENT_MODE\n", __FUNCTION__));
+            if (packet->InputBufferLength < sizeof(VIDEO_MODE)) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+            request_mode = ((PVIDEO_MODE)packet->InputBuffer)->RequestedMode;
+
+            dev_ext->current_mode = request_mode;
+            DEBUG_PRINT((dev_ext, 0, "%s: mode %u\n", __FUNCTION__, request_mode));
+            if (!IsValidMode(dev_ext, request_mode)) {
+                error = ERROR_INVALID_PARAMETER;
+                goto err;
+            }
+        }
+        break;
+    case IOCTL_VIDEO_QUERY_CURRENT_MODE: {
+            PVIDEO_MODE_INFORMATION inf;
+
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_CURRENT_MODE\n", __FUNCTION__));
+
+            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+                                              sizeof(VIDEO_MODE_INFORMATION))) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+
+            if ((inf = FindMode(dev_ext, dev_ext->current_mode)) == NULL) {
+                DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
+                error = ERROR_INVALID_DATA;
+                goto err;
+            }
+            *(PVIDEO_MODE_INFORMATION)packet->OutputBuffer = *inf;
+        }
+        break;
+    case IOCTL_VIDEO_MAP_VIDEO_MEMORY: {
+            PVIDEO_MEMORY_INFORMATION mem_info;
+
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_MAP_VIDEO_MEMORY\n", __FUNCTION__));
+
+            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+                                              sizeof(VIDEO_MEMORY_INFORMATION)) ||
+                                            ( packet->InputBufferLength < sizeof(VIDEO_MEMORY) ) ) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+
+            ASSERT(((PVIDEO_MEMORY)(packet->InputBuffer))->RequestedVirtualAddress == NULL);
+            mem_info = packet->OutputBuffer;
+            mem_info->VideoRamBase = mem_info->FrameBufferBase = dev_ext->vram_start;
+            mem_info->VideoRamLength = mem_info->FrameBufferLength = dev_ext->vram_size;
+#if 0
+#ifdef DBG
+            DEBUG_PRINT((dev, 0, "%s: zap\n", __FUNCTION__));
+            VideoPortZeroMemory(mem_info->VideoRamBase, mem_info->VideoRamLength);
+            DEBUG_PRINT((dev, 0, "%s: zap done\n", __FUNCTION__));
+#endif
+#endif
+        }
+        break;
+    case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: {
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY (do nothing) \n", __FUNCTION__));
+        }
+        break;
+    case IOCTL_VIDEO_RESET_DEVICE:
+        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_RESET_DEVICE\n", __FUNCTION__));
+        HWReset(dev_ext);
+        break;
+    case IOCTL_QXL_GET_INFO: {
+            QXLDriverInfo *driver_info;
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_QXL_GET_INFO\n", __FUNCTION__));
+
+            if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+                                              sizeof(QXLDriverInfo))) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+
+            driver_info = packet->OutputBuffer;
+            driver_info->version = QXL_DRIVER_INFO_VERSION;
+            driver_info->pci_revision = dev_ext->pci_revision;
+            driver_info->display_event = dev_ext->display_event;
+            driver_info->cursor_event = dev_ext->cursor_event;
+            driver_info->sleep_event = dev_ext->sleep_event;
+            driver_info->io_cmd_event = dev_ext->io_cmd_event;
+            driver_info->cmd_ring = &dev_ext->ram_header->cmd_ring;
+            driver_info->cursor_ring = &dev_ext->ram_header->cursor_ring;
+            driver_info->release_ring = &dev_ext->ram_header->release_ring;
+            driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
+            driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
+            driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+            driver_info->update_area_async_port = dev_ext->io_port + QXL_IO_UPDATE_AREA_ASYNC;
+            driver_info->memslot_add_async_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD_ASYNC;
+            driver_info->create_primary_async_port =
+                dev_ext->io_port + QXL_IO_CREATE_PRIMARY_ASYNC;
+            driver_info->destroy_primary_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_PRIMARY_ASYNC;
+            driver_info->destroy_surface_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_SURFACE_ASYNC;
+            driver_info->destroy_all_surfaces_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES_ASYNC;
+            driver_info->flush_surfaces_async_port = dev_ext->io_port + QXL_IO_FLUSH_SURFACES_ASYNC;
+            driver_info->flush_release_port = dev_ext->io_port + QXL_IO_FLUSH_RELEASE;
+
+            driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
+            driver_info->log_buf = dev_ext->ram_header->log_buf;
+
+            driver_info->surface0_area = dev_ext->ram_start;
+            driver_info->surface0_area_size = dev_ext->rom->surface0_area_size;
+            driver_info->update_id = &dev_ext->rom->update_id;
+            driver_info->mm_clock = &dev_ext->rom->mm_clock;
+            driver_info->compression_level = &dev_ext->rom->compression_level;
+            driver_info->log_level = &dev_ext->rom->log_level;
+            driver_info->update_area_port = dev_ext->io_port + QXL_IO_UPDATE_AREA;
+            driver_info->update_area = &dev_ext->ram_header->update_area;
+            driver_info->update_surface = &dev_ext->ram_header->update_surface;
+
+            driver_info->num_pages = dev_ext->rom->num_pages;
+            driver_info->io_pages_virt = dev_ext->ram_start + driver_info->surface0_area_size;
+            driver_info->io_pages_phys = dev_ext->ram_physical.QuadPart +
+                                                                    driver_info->surface0_area_size;
+
+            driver_info->main_mem_slot_id = dev_ext->rom->slots_start;
+            driver_info->num_mem_slot = dev_ext->rom->slots_end;
+            driver_info->slot_gen_bits = dev_ext->rom->slot_gen_bits;
+            driver_info->slot_id_bits = dev_ext->rom->slot_id_bits;
+            driver_info->slots_generation = &dev_ext->rom->slot_generation;
+            driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
+            driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
+            driver_info->main_mem_slot = dev_ext->mem_slots[driver_info->main_mem_slot_id];
+
+#if (WINVER < 0x0501)
+            driver_info->WaitForEvent = QXLWaitForEvent;
+#endif
+            driver_info->destroy_surface_wait_port = dev_ext->io_port + QXL_IO_DESTROY_SURFACE_WAIT;
+            driver_info->destroy_all_surfaces_port = dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES;
+            driver_info->create_primary_port = dev_ext->io_port + QXL_IO_CREATE_PRIMARY;
+            driver_info->destroy_primary_port = dev_ext->io_port + QXL_IO_DESTROY_PRIMARY;
+            driver_info->memslot_add_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD;
+            driver_info->memslot_del_port = dev_ext->io_port + QXL_IO_MEMSLOT_DEL;
+
+            driver_info->primary_surface_create = &dev_ext->ram_header->create_surface;
+
+            driver_info->n_surfaces = dev_ext->rom->n_surfaces;
+
+            driver_info->fb_phys = dev_ext->vram_physical.QuadPart;
+
+            driver_info->dev_id = dev_ext->rom->id;
+
+            driver_info->create_non_primary_surfaces = check_non_primary_surfaces_registry_key(dev_ext);
+        }
+        break;
+
+    case IOCTL_QXL_SET_CUSTOM_DISPLAY: {
+            QXLEscapeSetCustomDisplay *custom_display;
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_QXL_SET_CUSTOM_DISPLAY\n", __FUNCTION__));
+
+            if (packet->InputBufferLength < (packet->StatusBlock->Information =
+                                             sizeof(QXLEscapeSetCustomDisplay))) {
+                error = ERROR_INSUFFICIENT_BUFFER;
+                goto err;
+            }
+
+            custom_display = packet->InputBuffer;
+            DEBUG_PRINT((dev_ext, 0, "%s: %dx%d@%d\n", __FUNCTION__,
+                         custom_display->xres, custom_display->yres,
+                         custom_display->bpp));
+            SetCustomDisplay(dev_ext, custom_display);
+        }
+        break;
+
+    default:
+        DEBUG_PRINT((dev_ext, 0, "%s: invalid command 0x%lx\n", __FUNCTION__, packet->IoControlCode));
+        error = ERROR_INVALID_FUNCTION;
+        goto err;
+    }
+    packet->StatusBlock->Status = NO_ERROR;
+    DEBUG_PRINT((dev_ext, 0, "%s: OK\n", __FUNCTION__));
+    return TRUE;
+err:
+    packet->StatusBlock->Information = 0;
+    packet->StatusBlock->Status = error;
+    DEBUG_PRINT((dev_ext, 0, "%s: ERR\n", __FUNCTION__));
+    return TRUE;
+}
+
+VOID InterruptCallback(PVOID dev_extension, PVOID Context)
+{
+    QXLExtension *dev_ext = dev_extension;
+    UINT32 pending = VideoPortInterlockedExchange(&dev_ext->ram_header->int_pending, 0);
+
+    if (pending & QXL_INTERRUPT_DISPLAY) {
+        VideoPortSetEvent(dev_ext, dev_ext->display_event);
+    }
+    if (pending & QXL_INTERRUPT_CURSOR) {
+        VideoPortSetEvent(dev_ext, dev_ext->cursor_event);
+    }
+    if (pending & QXL_INTERRUPT_IO_CMD) {
+        VideoPortSetEvent(dev_ext, dev_ext->io_cmd_event);
+    }
+
+    dev_ext->ram_header->int_mask = ~0;
+    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+}
+
+BOOLEAN Interrupt(PVOID dev_extension)
+{
+    QXLExtension *dev_ext = dev_extension;
+
+    if (!(dev_ext->ram_header->int_pending & dev_ext->ram_header->int_mask)) {
+        return FALSE;
+    }
+    dev_ext->ram_header->int_mask = 0;
+    VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+
+    if (!VideoPortQueueDpc(dev_extension, InterruptCallback, NULL)) {
+        VideoPortLogError(dev_extension, NULL, E_UNEXPECTED, QXLERR_INT_DELIVERY);
+        dev_ext->ram_header->int_mask = ~0;
+        VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+    }
+    return TRUE;
+}
diff --git a/xddm/miniport/qxl.h b/xddm/miniport/qxl.h
new file mode 100644
index 0000000..c7df4b1
--- /dev/null
+++ b/xddm/miniport/qxl.h
@@ -0,0 +1,41 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "winerror.h"
+#include "devioctl.h"
+#include "miniport.h"
+#include "ntddvdeo.h"
+#include "video.h"
+
+#include "qxl_driver.h"
+
+enum {
+    QXLERR_INT_DELIVERY = 1,
+};
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+
+#if DBG
+#define DEBUG_PRINT(arg) DebugPrint arg
+#else
+#define DEBUG_PRINT(arg)
+#endif
diff --git a/xddm/miniport/qxl.inf b/xddm/miniport/qxl.inf
new file mode 100644
index 0000000..9b17575
--- /dev/null
+++ b/xddm/miniport/qxl.inf
@@ -0,0 +1,97 @@
+
+; Installation inf for qxl driver
+
+[Version]
+Signature = "$CHICAGO$"
+DriverVer = 08/15/2012,1.4.2.3
+Provider = %RHAT%
+CatalogFile = qxl.cat
+Class = Display
+ClassGUID = {4d36e968-e325-11ce-bfc1-08002be10318}
+
+[DestinationDirs]
+DefaultDestDir = 11	; system32
+qxl.Miniport = 12	; drivers
+qxl.Display = 11	; system32
+
+[Manufacturer]
+%RHAT% = q, NTx86, NTamd64, NTx86.6.0, NTamd64.6.0
+
+; WinXP x86 and up
+[q.NTx86]
+%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
+
+; WinXP x64 and up
+[q.NTamd64]
+%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
+
+; Vista x86 and up
+[q.NTx86.6.0]
+%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
+
+; Vista x64 and up
+[q.NTamd64.6.0]
+%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
+
+
+[ControlFlags]
+ExcludeFromSelect = *
+
+[qxl]
+CopyFiles = qxl.Miniport, qxl.Display
+
+[qxl_vista]
+FeatureScore = FC
+CopyFiles = qxl.Miniport, qxl.Display
+
+[qxl.Miniport]
+qxl.sys
+
+[qxl.Display]
+qxldd.dll
+
+[SourceDisksNames]
+1 = %DiskId%
+
+[SourceDisksFiles]
+qxl.sys = 1
+qxldd.dll = 1
+
+[qxl.SoftwareSettings]
+AddReg = qxl_SoftwareDeviceSettings
+
+[qxl_vista.SoftwareSettings]
+AddReg = qxl_SoftwareDeviceSettings
+
+[qxl_SoftwareDeviceSettings]
+HKR,, InstalledDisplayDrivers,        %REG_MULTI_SZ%, qxldd
+HKR,, VgaCompatible,                  %REG_DWORD%,    0
+HKR,, DefaultSettings.BitsPerPel,     %REG_DWORD%,    32
+HKR,, DefaultSettings.XResolution,    %REG_DWORD%,    800
+HKR,, DefaultSettings.YResolution,    %REG_DWORD%,    600
+HKR,, Acceleration.Level,             %REG_DWORD%,    0
+
+[qxl.Services]
+AddService = qxl, 0x00000002, qxl_Service_Inst ; Assign the named service as the PnP function driver
+
+[qxl_vista.Services]
+AddService = qxl, 0x00000002, qxl_Service_Inst ; Assign the named service as the PnP function driver
+
+[qxl_Service_Inst]
+ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
+StartType      = 3                  ; SERVICE_DEMAND_START
+ErrorControl   = 0                  ; SERVICE_ERROR_IGNORE
+LoadOrderGroup = Video
+ServiceBinary  = %12%\qxl.sys
+
+[Strings]
+RHAT = "Red Hat"
+QXL = "QXL GPU"
+DiskId = "Windows 2000 Driver Installation Disk"
+
+REG_SZ         = 0x00000000
+REG_MULTI_SZ   = 0x00010000
+REG_EXPAND_SZ  = 0x00020000
+REG_BINARY     = 0x00000001
+REG_DWORD      = 0x00010001
+FLG_ADDREG_DELVAL = 0x00000004
diff --git a/xddm/miniport/qxl.rc b/xddm/miniport/qxl.rc
new file mode 100644
index 0000000..50abefe
--- /dev/null
+++ b/xddm/miniport/qxl.rc
@@ -0,0 +1,29 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE                VFT_DRV
+#define VER_FILESUBTYPE             VFT2_DRV_DISPLAY
+
+#undef  VER_COMPANYNAME_STR
+#undef  VER_FILEVERSION_STR
+#undef  VER_LEGALCOPYRIGHT_STR
+#undef  VER_LEGALCOPYRIGHT_YEARS
+#undef  VER_PRODUCTNAME_STR
+#undef  VER_PRODUCTVERSION_STR
+
+
+#define VER_FILEDESCRIPTION_STR     "Red Hat QXL Display Driver"
+#define VER_INTERNALNAME_STR        "qxl.sys"
+#define VER_ORIGINALFILENAME_STR    VER_INTERNALNAME_STR
+#define VER_FILEVERSION_STR         "1.4.2.3"
+#define VER_PRODUCTNAME_STR         "Spice"
+#define VER_PRODUCTVERSION_STR      "1.4.2.3"
+
+#undef  VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION           1,4,2,3
+
+#define VER_COMPANYNAME_STR         "Red Hat Inc."
+#define VER_LEGALCOPYRIGHT_STR      "© Red Hat Inc. All rights reserved."
+
+#include "common.ver"
diff --git a/xddm/miniport/sources b/xddm/miniport/sources
new file mode 100644
index 0000000..8d96e14
--- /dev/null
+++ b/xddm/miniport/sources
@@ -0,0 +1,29 @@
+TARGETNAME=qxl
+TARGETPATH=obj
+TARGETTYPE=MINIPORT
+
+TARGETLIBS=$(DDK_LIB_PATH)\videoprt.lib 
+
+!if !defined(DDK_TARGET_OS) || "$(DDK_TARGET_OS)"=="Win2K"
+#
+# The driver is built in the Win2K build environment
+#
+TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\ntoskrnl.lib
+!endif
+
+
+AXP64_FLAGS=/QA21164
+
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
+
+INCLUDES=$(SPICE_COMMON_DIR); ..\include
+
+SOURCES=qxl.c      \
+		minimal_snprintf.c \
+		wdmhelper.c \
+        qxl.rc
+
+MISCFILES=qxl.inf
diff --git a/xddm/miniport/wdmhelper.c b/xddm/miniport/wdmhelper.c
new file mode 100644
index 0000000..5af1909
--- /dev/null
+++ b/xddm/miniport/wdmhelper.c
@@ -0,0 +1,64 @@
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This software is licensed under the GNU General Public License,
+   version 2 (GPLv2) (see COPYING for details), subject to the
+   following clarification.
+
+   With respect to binaries built using the Microsoft(R) Windows
+   Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+   derived from the WDK ("WDK Code").  As to WDK Code, by using or
+   distributing such binaries you agree to be bound by the Microsoft
+   Software License Terms for the WDK.  All WDK Code is considered by
+   the GPLv2 licensors to qualify for the special exception stated in
+   section 3 of GPLv2 (commonly known as the system library
+   exception).
+
+   There is NO WARRANTY for this software, express or implied,
+   including the implied warranties of NON-INFRINGEMENT, TITLE,
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#if (WINVER < 0x0501)
+#include <ntddk.h>
+#include "wdmhelper.h"
+
+void QXLDeleteEvent(PVOID pEvent)
+{
+    if(pEvent) {
+        ExFreePool(pEvent);
+    }
+}
+
+LONG QXLInitializeEvent(PVOID * pEvent)
+{
+    if(pEvent) {
+        *pEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), '_lxq');
+
+        if(*pEvent) {
+            KeInitializeEvent((PRKEVENT)*pEvent, SynchronizationEvent, FALSE);
+        }
+    }
+
+    return 0;
+}
+
+void QXLSetEvent(PVOID pEvent)
+{
+    //Pririty boost can be switched to IO_NO_INCREMENT
+    if(pEvent) {
+        KeSetEvent((PRKEVENT)pEvent, IO_VIDEO_INCREMENT, FALSE);
+    }
+}
+
+ULONG QXLWaitForEvent(PVOID pEvent, PLARGE_INTEGER Timeout)
+{
+    if(pEvent) {
+        return NT_SUCCESS(KeWaitForSingleObject(pEvent, Executive, KernelMode, TRUE, Timeout));
+    }
+
+    return FALSE;
+}
+
+#endif
+
diff --git a/xddm/scripts/buildAll.bat b/xddm/scripts/buildAll.bat
new file mode 100644
index 0000000..24c81ea
--- /dev/null
+++ b/xddm/scripts/buildAll.bat
@@ -0,0 +1,75 @@
+REM Copyright Red Hat 2007-2011
+REM Authors: Yan Vugenfirer
+REM          Arnon Gilboa
+REM          Uri Lublin
+:
+: Set global parameters: 
+:
+
+: Use Windows 7 DDK
+if "%DDKVER%"=="" set DDKVER=7600.16385.0
+
+: By default DDK is installed under C:\WINDDK, but it can be installed in different location
+if "%DDKINSTALLROOT%"=="" set DDKINSTALLROOT=C:\WINDDK\
+set BUILDROOT=%DDKINSTALLROOT%%DDKVER%
+set X64ENV=x64
+if "%DDKVER%"=="6000" set X64ENV=amd64
+if "%BUILDCFG%"=="" set BUILDCFG=fre
+
+if not "%1"=="" goto parameters_here
+echo no parameters specified, exiting
+goto :eof
+:parameters_here
+
+:nextparam
+if "%1"=="" goto :eof
+goto %1
+:continue
+shift
+goto nextparam
+
+:fre
+set BUILDCFG=fre
+goto continue
+
+:chk
+set BUILDCFG=chk
+goto continue
+
+:Win7
+set BUILDENV=WIN7
+goto build_it
+
+:Win7_64
+set BUILDENV=%X64ENV% WIN7
+goto build_it
+
+:Vista
+set BUILDENV=Wlh
+goto build_it
+
+:Vista64
+set BUILDENV=%X64ENV% Wlh
+goto build_it
+
+:Win2003
+set BUILDENV=WNET
+goto build_it
+
+:Win200364
+set BUILDENV=%X64ENV% WNET
+goto build_it
+
+:XP
+set BUILDENV=WXP
+goto build_it
+
+:build_it
+set DDKBUILDENV=
+pushd %BUILDROOT%
+call %BUILDROOT%\bin\setenv.bat %BUILDROOT% %BUILDCFG% %BUILDENV%
+popd
+build -cZg
+
+goto continue
+
diff --git a/xddm/scripts/clean.bat b/xddm/scripts/clean.bat
new file mode 100644
index 0000000..acc3bc3
--- /dev/null
+++ b/xddm/scripts/clean.bat
@@ -0,0 +1,6 @@
+REM Copyright Red Hat 2009-2011
+REM Authors: Arnon Gilboa 
+:rmdir /S /Q Debug
+rmdir /S /Q Release
+for /d %%a in (obj*) do rd /s /q "%%a"
+del /F *.log *.wrn *.err


More information about the Spice-commits mailing list