From 03a2959e46c8729b41168bf71b985ec41c5e6845 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Thu, 25 Oct 2012 15:54:46 +0200 Subject: move xddm driver to xddm subdir --- 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 - 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 + 84 files changed, 18271 insertions(+), 18271 deletions(-) delete mode 100644 COPYING delete mode 100755 build.bat delete mode 100644 dirs delete mode 100644 display/brush.c delete mode 100644 display/driver.c delete mode 100644 display/driver.rc delete mode 100644 display/makefile delete mode 100644 display/mspace.c delete mode 100644 display/mspace.h delete mode 100644 display/pointer.c delete mode 100644 display/quic.c delete mode 100644 display/quic.h delete mode 100644 display/quic_config.h delete mode 100644 display/quic_family_tmpl.c delete mode 100644 display/quic_rgb_tmpl.c delete mode 100644 display/quic_tmpl.c delete mode 100644 display/qxldd.h delete mode 100644 display/res.c delete mode 100644 display/res.h delete mode 100644 display/rop.c delete mode 100644 display/rop.h delete mode 100644 display/sources delete mode 100644 display/surface.c delete mode 100644 display/surface.h delete mode 100644 display/text.c delete mode 100644 display/utils.h delete mode 100644 include/murmur_hash2a.h delete mode 100644 include/os_dep.h delete mode 100644 include/qxl_driver.h delete mode 100644 include/stdint.h delete mode 100644 include/wdmhelper.h delete mode 100644 miniport/makefile delete mode 100644 miniport/minimal_snprintf.c delete mode 100644 miniport/minimal_snprintf.h delete mode 100644 miniport/qxl.c delete mode 100644 miniport/qxl.h delete mode 100644 miniport/qxl.inf delete mode 100644 miniport/qxl.rc delete mode 100644 miniport/sources delete mode 100644 miniport/wdmhelper.c delete mode 100644 scripts/buildAll.bat delete mode 100644 scripts/clean.bat create mode 100644 xddm/COPYING create mode 100755 xddm/build.bat create mode 100644 xddm/dirs create mode 100644 xddm/display/brush.c create mode 100644 xddm/display/driver.c create mode 100644 xddm/display/driver.rc create mode 100644 xddm/display/makefile create mode 100644 xddm/display/mspace.c create mode 100644 xddm/display/mspace.h create mode 100644 xddm/display/pointer.c create mode 100644 xddm/display/quic.c create mode 100644 xddm/display/quic.h create mode 100644 xddm/display/quic_config.h create mode 100644 xddm/display/quic_family_tmpl.c create mode 100644 xddm/display/quic_rgb_tmpl.c create mode 100644 xddm/display/quic_tmpl.c create mode 100644 xddm/display/qxldd.h create mode 100644 xddm/display/res.c create mode 100644 xddm/display/res.h create mode 100644 xddm/display/rop.c create mode 100644 xddm/display/rop.h create mode 100644 xddm/display/sources create mode 100644 xddm/display/surface.c create mode 100644 xddm/display/surface.h create mode 100644 xddm/display/text.c create mode 100644 xddm/display/utils.h create mode 100644 xddm/include/murmur_hash2a.h create mode 100644 xddm/include/os_dep.h create mode 100644 xddm/include/qxl_driver.h create mode 100644 xddm/include/stdint.h create mode 100644 xddm/include/wdmhelper.h create mode 100644 xddm/miniport/makefile create mode 100644 xddm/miniport/minimal_snprintf.c create mode 100644 xddm/miniport/minimal_snprintf.h create mode 100644 xddm/miniport/qxl.c create mode 100644 xddm/miniport/qxl.h create mode 100644 xddm/miniport/qxl.inf create mode 100644 xddm/miniport/qxl.rc create mode 100644 xddm/miniport/sources create mode 100644 xddm/miniport/wdmhelper.c create mode 100644 xddm/scripts/buildAll.bat create mode 100644 xddm/scripts/clean.bat 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. - - - Copyright (C) - - 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. - - , 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 @@ -@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 -#include -#include -#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 - -#include - -#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@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 - -#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 -#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 -#include -#include -#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 - -#ifdef __GNUC__ - -#include - -#define INLINE inline - -#define MEMCLEAR(ptr, size) memset(ptr, 0, size) - -#else - -#ifdef QXLDD -#include -#include "os_dep.h" -#define INLINE _inline -#define MEMCLEAR(ptr, size) RtlZeroMemory(ptr, size) -#else -#include -#include - -#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=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 -#include -#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 -#endif -#include -#include -#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 -#include -#include -#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 -#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 -#include - -#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 - - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - - * - - * THIS SOFTWARE IS NOT COPYRIGHTED - - * - - * Contributor: Danny Smith - - * - - * 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 - - - -#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 : - - "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@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 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 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 01/27/98 for mutt 0.89i - * The PGP code was using unsigned hexadecimal formats. - * Unfortunately, unsigned formats simply didn't work. - * - * Michael Elkins 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@samba.org) Oct 1998 - * fixed handling of %.0f - * added test for HAVE_LONG_DOUBLE - * - * Luke Mewburn , 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 = ""; - } - 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 - -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 - -#include - -#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 -#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. + + + Copyright (C) + + 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. + + , 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 @@ +@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 +#include +#include +#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 + +#include + +#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@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 + +#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 +#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 +#include +#include +#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 + +#ifdef __GNUC__ + +#include + +#define INLINE inline + +#define MEMCLEAR(ptr, size) memset(ptr, 0, size) + +#else + +#ifdef QXLDD +#include +#include "os_dep.h" +#define INLINE _inline +#define MEMCLEAR(ptr, size) RtlZeroMemory(ptr, size) +#else +#include +#include + +#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=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 +#include +#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 +#endif +#include +#include +#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 +#include +#include +#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 +#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 +#include + +#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 + + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + + * + + * THIS SOFTWARE IS NOT COPYRIGHTED + + * + + * Contributor: Danny Smith + + * + + * 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 + + + +#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 : + + "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@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 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 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 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 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@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * Luke Mewburn , 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 = ""; + } + 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 + +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 + +#include + +#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 +#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 -- cgit v1.2.3