summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--COPYING339
-rw-r--r--Makefile.am57
-rw-r--r--NEWS201
-rw-r--r--README32
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac326
-rw-r--r--debian.upstream/Makefile.am27
-rw-r--r--debian.upstream/changelog.in5
-rw-r--r--debian.upstream/compat1
-rw-r--r--debian.upstream/control.in27
-rw-r--r--debian.upstream/copyright24
-rwxr-xr-xdebian.upstream/rules18
-rw-r--r--debian.upstream/xvba-video.install1
-rw-r--r--src/Makefile.am82
-rw-r--r--src/color_matrix.c469
-rw-r--r--src/color_matrix.h79
-rw-r--r--src/debug.c158
-rw-r--r--src/debug.h52
-rw-r--r--src/fglrxinfo.c221
-rw-r--r--src/fglrxinfo.h46
-rw-r--r--src/object_heap.c210
-rw-r--r--src/object_heap.h116
-rw-r--r--src/shaders/Bicubic.cg179
-rw-r--r--src/shaders/Bicubic.pso74
-rw-r--r--src/shaders/Bicubic_FLOAT.pso53
-rw-r--r--src/shaders/Evergreen.cg65
-rw-r--r--src/shaders/Evergreen_mix_1.cg22
-rw-r--r--src/shaders/Evergreen_mix_1.pso35
-rw-r--r--src/shaders/Evergreen_mix_2.cg22
-rw-r--r--src/shaders/Evergreen_mix_2.pso45
-rw-r--r--src/shaders/Evergreen_mix_3.cg22
-rw-r--r--src/shaders/Evergreen_mix_3.pso55
-rw-r--r--src/shaders/Evergreen_mix_4.cg22
-rw-r--r--src/shaders/Evergreen_mix_4.pso65
-rw-r--r--src/shaders/Makefile.am46
-rw-r--r--src/shaders/NV12.cg46
-rw-r--r--src/shaders/NV12.pso31
-rw-r--r--src/shaders/ProcAmp.cg49
-rw-r--r--src/shaders/ProcAmp.pso23
-rw-r--r--src/shaders/YV12.cg76
-rw-r--r--src/shaders/YV12.pso33
-rwxr-xr-xsrc/shaders/pso2h.py128
-rw-r--r--src/sysdeps.h68
-rw-r--r--src/uarray.c144
-rw-r--r--src/uarray.h59
-rw-r--r--src/uasyncqueue.c333
-rw-r--r--src/uasyncqueue.h44
-rw-r--r--src/ulist.c166
-rw-r--r--src/ulist.h63
-rw-r--r--src/uqueue.c107
-rw-r--r--src/uqueue.h41
-rw-r--r--src/utils.c221
-rw-r--r--src/utils.h50
-rw-r--r--src/utils_glx.c1231
-rw-r--r--src/utils_glx.h233
-rw-r--r--src/utils_x11.c184
-rw-r--r--src/utils_x11.h59
-rw-r--r--src/vaapi_compat.h64
-rw-r--r--src/xvba_buffer.c946
-rw-r--r--src/xvba_buffer.h129
-rw-r--r--src/xvba_decode.c716
-rw-r--r--src/xvba_decode.h130
-rw-r--r--src/xvba_driver.c282
-rw-r--r--src/xvba_driver.h110
-rw-r--r--src/xvba_driver_template.h676
-rw-r--r--src/xvba_dump.c705
-rw-r--r--src/xvba_dump.h145
-rw-r--r--src/xvba_gate.c956
-rw-r--r--src/xvba_gate.h218
-rw-r--r--src/xvba_image.c822
-rw-r--r--src/xvba_image.h234
-rw-r--r--src/xvba_subpic.c585
-rw-r--r--src/xvba_subpic.h175
-rw-r--r--src/xvba_video.c1131
-rw-r--r--src/xvba_video.h329
-rw-r--r--src/xvba_video_glx.c2349
-rw-r--r--src/xvba_video_glx.h166
-rw-r--r--src/xvba_video_x11.c223
-rw-r--r--src/xvba_video_x11.h92
80 files changed, 17772 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..4558581
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Gwenole Beauchesne <gbeauchesne@splitted-desktop.com> - Primary author
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..cd643f9
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,57 @@
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = debian.upstream src
+
+DOCS = \
+ AUTHORS \
+ COPYING \
+ NEWS \
+ README
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = \
+ aclocal.m4 compile config.guess config.sub \
+ configure depcomp install-sh ltmain.sh \
+ Makefile.in missing
+
+DEB_BUILDDIR = debian.build
+
+deb:
+ @[ -d debian ] || ln -s debian.upstream debian
+ dpkg-buildpackage -rfakeroot -uc -us
+
+deb.upstream: dist
+ -mkdir -p $(DEB_BUILDDIR)
+ cd $(DEB_BUILDDIR) && \
+ rm -rf $(PACKAGE)-$(VERSION) && \
+ tar zxvf ../$(PACKAGE)-$(VERSION).tar.gz && \
+ cd $(PACKAGE)-$(VERSION) && \
+ $(MAKE) deb -f Makefile.am
+
+bindistdir = $(distdir).$(TARGET_ARCH)
+
+bindist: bindist-gzip
+
+bindist_conf_flags =
+bindist_conf_flags += --enable-debug
+bindist_conf_flags += --enable-tracer
+
+bindistdir: dist-gzip
+ -rm -rf bindist-build; mkdir bindist-build
+ -cd bindist-build && tar zxf ../$(distdir).tar.gz
+ -cd bindist-build/$(distdir) && \
+ ./configure --prefix=/usr $(bindist_conf_flags) && \
+ $(MAKE)
+
+ -rm -rf $(bindistdir); mkdir $(bindistdir)
+ $(MAKE) install-strip \
+ DESTDIR=$(PWD)/$(bindistdir) \
+ -C bindist-build/$(distdir)
+ find $(bindistdir)/ -name "*.la" -exec rm -f {} \;
+ -rm -rf bindist-build
+
+ cp $(DOCS) $(bindistdir)/
+
+bindist-gzip: bindistdir
+ tar zcvf $(bindistdir).tar.gz $(bindistdir)
+ rm -rf $(bindistdir)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..2a7e247
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,201 @@
+xvba-video NEWS -- summary of changes. 2011-06-14
+Copyright (C) 2009-2011 Splitted-Desktop Systems
+
+Version 0.8.0 - 14.Jun.2011
+* Relicense code to GPLv2
+* Require fglrx >= 8.80.5 (Catalyst 10.12)
+
+Version 0.7.8 - 24.Feb.2011
+* Add compatibility glue with upstream libva >= 1.0.8
+
+Version 0.7.7 - 15.Dec.2010
+* Fix Evergreen workaround for newer fglrx versions
+* Fix vaQueryConfigProfiles() & vaQueryConfigEntrypoints() duplicates
+
+Version 0.7.6 - 04.Nov.2010
+* Fix Evergreen workaround for fglrx >= 8.79.4
+* Add vaPutSurface() high-quality scaling flag (VA_FILTER_SCALING_HQ)
+
+Version 0.7.5 - 05.Oct.2010
+* Add support for GL_TEXTURE_RECTANGLE_ARB textures
+* Add workaround for GLX rendering on Evergreen chips
+* Add vaPutSurface() low-quality scaling flag (VA_FILTER_SCALING_FAST)
+
+Version 0.7.4 - 21.Sep.2010
+* Check UVD is really enabled prior to using it
+* Add debug info through XVBA_VIDEO_DEBUG=<level>
+* Fix regression when decoding multiple slices per frame
+* Fix system crash with H.264 videos encoded over HP @ L4.1
+
+Version 0.7.3 - 05.Aug.2010
+* Add compatibility glue with original VA-API 0.31.1
+* Fix vaCopySurfaceGLX() to a GLX texture of different size
+
+Version 0.7.2 - 13.Jul.2010
+* Require fglrx >= 8.73.2 (Catalyst 10.5)
+* Fix vaInitialize() return status if an error occurred
+* Fix regression when rendering subpictures in VA/GLX mode
+* Set VADisplayAttribDirectSurface to 1 in VA/GLX mode too
+
+Version 0.7.1 - 09.Jul.2010
+* Drop explicit link against libva
+* Add compatibility glue with original VA-API 0.31.0
+* Fix regression when rendering to a GL_RGBA texture
+* Fix rendering of subpictures with size mod 16 != 0
+
+Version 0.7.0 - 08.Jul.2010
+* Add support for VA-API 0.31.1-sds1
+* Requires fglrx driver version >= 8.69.2
+* Fix VA/GLX to preserve caller's GL context
+* Fix vaCopySurfaceGLX() to handle GL_RGBA8 textures
+* Fix output surface creation code to detect errors
+
+Version 0.6.11 - 18.Apr.2010
+* Fix VA context destruction
+* Fix rendering of empty surfaces
+* Fix vaGetImage() in I420 format
+* Fix vaCreateConfig() to validate profile & entrypoint
+
+Version 0.6.10 - 18.Mar.2010
+* Add I420 image format
+* Add support for VA-API 0.31.0-sds6
+* Fix destruction of child windows used by vaPutSurface()
+
+Version 0.6.9 - 26.Feb.2010
+* Build against VA-API 0.31.0-sds5
+* Optimize rendering of VA images
+* Fix detection of window size changes
+* Fix rendering of multiple surfaces per window
+* Add support for VA_CLEAR_DRAWABLE to vaPutSurface()
+
+Version 0.6.8 - 22.Feb.2010
+* Fix rendering of VA images not a multiple of 16
+* Add support for GL_RGBA textures in vaCreateSurfaceGLX()
+* Optimize rendering of multiple subpictures from a single image
+
+Version 0.6.7 - 18.Feb.2010
+* Use fail-safe values for H.264 videos encoded over HP@L4.1
+* Fix hue rotation to preserve luminance
+* Fix internal contrast range to [ 0.0f .. 10.0f ]
+* Fix rendering of multiple subpictures per surface
+* Fix vaCopySurfaceGLX() for surfaces with dimensions not a multiple of 16
+
+Version 0.6.6 - 11.Feb.2010
+* Fix XvBA objects destruction for fglrx >= 8.70.3
+* Fix vaPutImage() to a surface used for decoding
+* Fix vaGetImage()/vaPutSurface() with surface dimensions not a multiple of 16
+* Fix rendering of VA subpictures that were previously deassociated
+
+Version 0.6.5 - 08.Feb.2010
+* Add brightness/contrast/hue/saturation display attributes
+* Fix vaPutSurface() window resize. e.g. when switching to full-screen mode
+* Allow vaPutSurface() to render to multiple drawables from a single surface
+
+Version 0.6.4 - 20.Jan.2010
+* Fix vaGetImage() with YV12 format
+* Fix vaPutSurface() to only draw the requested source region
+* Fix rendering of subpictures with size different from parent surface's
+
+Version 0.6.3 - 18.Jan.2010
+* Add background-color display attribute
+* Fix output surface allocation logic
+* Fix subwindow stacking order in vaPutSurface()
+* Fix vaGetImage() to wait for decoding to complete
+
+Version 0.6.2 - 14.Jan.2010
+* Fix VA buffer leaks when decoded surfaces are not used
+* Add support for RGBA, NV12 and YV12 image formats for vaPutImage()
+* Don't capture keyboard and mouse events in windowed rendering mode with OpenGL
+
+Version 0.6.1 - 11.Jan.2010
+* Add support for surfaces not bound to any VA context for plain rendering
+* Avoid flickering in windowed rendering mode with OpenGL (vaPutSurface())
+* Fix windowed rendering with OpenGL for clips larger than the visible area
+
+Version 0.6.0 - 30.Dec.2009
+* Add vaPutSurface() implementation with OpenGL, if PCOM is disabled
+* Add support for bob deinterlacing (PCOM only)
+
+Version 0.5.4 - 04.Dec.2009
+* Fix check for RGB subpicture format
+* Fix support for VA_SUBPICTURE_GLOBAL_ALPHA flag
+* Add YUY2 subpicture format (PCOM only)
+* Add RGBA subpicture format (OpenGL only)
+
+Version 0.5.3 - 28.Nov.2009
+* Handle up to 16 subpictures in OpenGL rendering mode too
+
+Version 0.5.2 - 27.Nov.2009
+* Add ARGB subpictures to OpenGL renderer
+* Fix rendering and destruction of subpictures
+* Drop create/destroy context workarounds for fglrx >= 8.69.2
+
+Version 0.5.1 - 12.Oct.2009
+* Fix ARGB image format
+* Fix H.264 level_idc reconstruction
+* Fix vaCreateImage() when output VAImage points to stack
+* Add vaPutImage() for full BGRA and NV12 image uploads
+
+Version 0.5.0 - 06.Oct.2009
+* Fix vaGetImage() with YV12 pixels
+* Add support for subpictures (PCOM only)
+
+Version 0.4.4 - 24.Sep.2009
+* Fix vaQueryConfigProfiles()
+* Fix vaQueryConfigEntrypoints()
+
+Version 0.4.3 - 22.Sep.2009
+* Fix vaQuerySurfaceStatus()
+* Fix various bugs in vaGetImage()
+* Fix support for multiple VA/GLX surfaces per context
+
+Version 0.4.2 - 10.Sep.2009
+* Add VADisplayAttributes
+* Add support for VA-API 0.31
+* Fix one minor memory leak in vaDestroySurfaces()
+* Make vaInitialize() fail if PCOM is disabled and fglrx < 8.66
+
+Version 0.4.1 - 01.Sep.2009
+* Fix vaQueryImageFormats()
+* Add support for OpenGL extensions (v3) to VA-API
+* Disable support for PCOM rendering in public releases
+
+Version 0.4.0 - 21.Aug.2009
+* Add support for OpenGL extensions to VA-API
+* Fix VAImageID pool memory leak in vaTerminate()
+
+Version 0.3.0 - 12.Aug.2009
+* Add support for XvBA 0.74
+* Add support for VAImage related functions:
+ - vaCreateImage(), vaDestroyImage()
+ - vaGetImage() for full surface readback only (i.e. no partial reads)
+
+Version 0.2.3 - 04.Aug.2009
+* Add support for VA-API 0.30
+* Add support for vaSyncSurface() and vaQuerySurfaceStatus()
+* Add debugging tools (XVBA_VIDEO_TRACE environment variable)
+* Fix vaPutSurface() in asynchronous mode under some rare conditions
+
+Version 0.2.2 - 17.Jun.2009
+* Use asynchronous present model by default
+* Fix video playback when window size changes
+* Fix memory leak in presence of multiple slices per frame
+
+Version 0.2.1 - 16.Jun.2009
+* Add make bindist rule
+* Fix fullscreen mode with some video clips
+* Fix windowed mode to use the requested display bounds
+* Fix unimplemented hooks to return an error (VA_STATUS_ERROR_OPERATION_FAILED)
+
+Version 0.2.0 - 11.Jun.2009
+* Fix memory leaks
+* Fix VC-1 decoding
+* Fix minor H.264 bugs
+
+Version 0.1.1 - 10.Jun.2009
+* Allow window size changes
+* Fix VC-1 LEVEL reconstruction
+* Fix H.264 level_idc reconstruction
+
+Version 0.1.0 - 09.Jun.2009
+* Initial public (binary) release
diff --git a/README b/README
new file mode 100644
index 0000000..0b6da21
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+
+ xvba-video
+ An XvBA-based backend for VA-API
+
+ Copyright (C) 2009-2011 Splitted-Desktop Systems
+
+
+License
+-------
+
+xvba-video is available under the terms of the GNU General Public
+License.
+
+
+Overview
+--------
+
+xvba-video consists in an XvBA-based backend for VA-API.
+
+
+Requirements
+------------
+
+libVA API version (not package) GLX support
+0.29-branch >= 0.29.0-sds8 No
+0.30-branch >= 0.30.0-sds1 No
+0.30-branch >= 0.30.4-sds5 Yes
+upstream 0.31-branch No
+0.31-branch >= 0.31.0-sds1 Yes
+
+mplayer-vaapi >= 20090320 patchset is also needed if you intend to use
+MPlayer.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..9c2f4f6
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install
+./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..72c6a4f
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,326 @@
+# xvba_video package version number
+m4_define([xvba_video_major_version], [0])
+m4_define([xvba_video_minor_version], [8])
+m4_define([xvba_video_micro_version], [0])
+m4_define([xvba_video_pre_version], [0])
+m4_define([xvba_video_version],
+ [xvba_video_major_version.xvba_video_minor_version.xvba_video_micro_version])
+m4_if(xvba_video_pre_version, [0], [], [
+m4_append([xvba_video_version], xvba_video_pre_version, [.pre])
+])
+
+# libva package version number
+m4_define([libva_sds_version_0_29], [8])
+m4_define([libva_sds_package_version_0_29], [0.29-2+sds11])
+m4_define([libva_sds_version_0_30], [1])
+m4_define([libva_sds_package_version_0_30], [0.30-1+sds1])
+m4_define([libva_glx_sds_version_0_30], [5])
+m4_define([libva_glx_sds_package_version_0_30], [0.30.4-1+sds6])
+m4_define([libva_glx_sds_version_0_31], [1])
+m4_define([libva_glx_sds_package_version_0_31], [0.31.0-1+sds1])
+m4_define([libva_sds_version], [libva_glx_sds_version_0_31])
+m4_define([libva_sds_package_version], [libva_glx_sds_package_version_0_31])
+
+AC_PREREQ([2.57])
+AC_INIT([xvba_video], [xvba_video_version], [gbeauchesne@splitted-desktop.com], [xvba-video])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CANONICAL_TARGET
+AM_INIT_AUTOMAKE
+AM_CONFIG_HEADER([src/config.h])
+
+LIBVA_SDS_VERSION_0_29=libva_sds_version_0_29
+LIBVA_SDS_VERSION_0_30=libva_sds_version_0_30
+LIBVA_GLX_SDS_VERSION_0_30=libva_glx_sds_version_0_30
+LIBVA_GLX_SDS_VERSION_0_31=libva_glx_sds_version_0_31
+LIBVA_SDS_VERSION=libva_sds_version
+LIBVA_SDS_PACKAGE_VERSION=libva_sds_package_version
+AC_SUBST(LIBVA_SDS_PACKAGE_VERSION)
+
+XVBA_VIDEO_MAJOR_VERSION=xvba_video_major_version
+XVBA_VIDEO_MINOR_VERSION=xvba_video_minor_version
+XVBA_VIDEO_MICRO_VERSION=xvba_video_micro_version
+AC_DEFINE([XVBA_VIDEO_MAJOR_VERSION], [xvba_video_major_version], [Major version of the driver])
+AC_DEFINE([XVBA_VIDEO_MINOR_VERSION], [xvba_video_minor_version], [Minor version of the driver])
+AC_DEFINE([XVBA_VIDEO_MICRO_VERSION], [xvba_video_micro_version], [Micro version of the driver])
+AC_DEFINE([XVBA_VIDEO_PRE_VERSION], [xvba_video_pre_version], [Preversion of the driver])
+
+XVBA_VIDEO_LT_LDFLAGS="-avoid-version"
+AC_SUBST(XVBA_VIDEO_LT_LDFLAGS)
+
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_PROG_CC
+
+AC_CHECK_LIB(m, sqrt)
+
+AC_HEADER_STDC
+AC_SYS_LARGEFILE
+
+dnl We want pthreads. Try libpthread first, then libc_r (FreeBSD), then PTL.
+HAVE_PTHREADS=yes
+AC_CHECK_LIB(pthread, pthread_create, , [
+ AC_CHECK_LIB(c_r, pthread_create, , [
+ AC_CHECK_LIB(PTL, pthread_create, , [
+ HAVE_PTHREADS=no
+ ])
+ ])
+])
+if test "x$HAVE_PTHREADS" = "xyes"; then
+ AC_DEFINE(HAVE_PTHREADS, 1, [Defined if pthreads are available])
+fi
+
+dnl Checks for libraries.
+AC_CHECK_LIB(rt, timer_create)
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(clock_gettime)
+
+dnl Check for Cg compiler
+AC_CHECK_PROG(CGC, [cgc], [cgc], [no])
+have_cgc="no"
+if test "x$CGC" != "xno"; then
+ have_cgc="yes"
+fi
+AM_CONDITIONAL(HAVE_CGC, [test "x$have_cgc" = "xyes"])
+
+dnl Check for python (pso2h.py needs it)
+AC_CHECK_PROG(PYTHON, [python], [python], [no])
+have_python="no"
+if test "x$PYTHON" != "xno"; then
+ have_python="yes"
+fi
+AM_CONDITIONAL(HAVE_PYTHON, [test "x$have_python" = "xyes"])
+
+TARGET_ARCH="$target_cpu"
+AC_SUBST(TARGET_ARCH)
+
+AC_DEFUN([AC_DEFINE_01], [
+ if test "$2" = "yes" -o "$2" = "guessing yes"; then
+ AC_DEFINE($1, 1, $3)
+ else
+ AC_DEFINE($1, 0, $3)
+ fi
+])
+
+AC_ARG_ENABLE(glx,
+ AC_HELP_STRING([--enable-glx],
+ [enable OpenGL/X11 @<:@default=yes@:>@]),
+ [], [enable_glx="yes"])
+
+AC_ARG_ENABLE(libxvba-dlopen,
+ AC_HELP_STRING([--enable-libxvba-dlopen],
+ [enable libXvBAW.so.1 to be dlopen()'ed]),
+ [], [enable_libxvba_dlopen="yes"])
+
+AC_DEFINE_01(USE_DLOPEN, "$enable_libxvba_dlopen",
+ [Define to enable libXvBAW.so.1 to be dlopen()'ed])
+
+AC_ARG_ENABLE(valgrind,
+ AC_HELP_STRING([--enable-valgrind],
+ [enable runtime detection of valgrind]),
+ [], [PKG_CHECK_EXISTS(valgrind, [enable_valgrind="yes"], [enable_valgrind="no"])])
+
+AC_DEFINE_01(USE_VALGRIND, "$enable_valgrind",
+ [Define to enable run-time detection of Valgrind])
+
+AC_ARG_ENABLE(debug,
+ AC_HELP_STRING([--enable-debug],
+ [enable debugging information]),
+ [], [enable_debug="yes"])
+
+AC_DEFINE_01(USE_DEBUG, "$enable_debug",
+ [Enable debugging information])
+
+AC_ARG_ENABLE(tracer,
+ AC_HELP_STRING([--enable-tracer],
+ [enable XvBA tracer]),
+ [], [enable_tracer="yes"])
+
+AC_DEFINE_01(USE_TRACER, "$enable_tracer",
+ [Enable XvBA tracer])
+
+dnl Check for __attribute__((visibility()))
+AC_CACHE_CHECK([whether __attribute__((visibility())) is supported],
+ xvba_cv_visibility_attribute,
+ [cat > conftest.c <<EOF
+int foo __attribute__ ((visibility ("hidden"))) = 1;
+int bar __attribute__ ((visibility ("protected"))) = 1;
+EOF
+ xvba_cv_visibility_attribute=no
+ if ${CC-cc} -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
+ if grep '\.hidden.*foo' conftest.s >/dev/null; then
+ if grep '\.protected.*bar' conftest.s >/dev/null; then
+ xvba_cv_visibility_attribute=yes
+ fi
+ fi
+ fi
+ rm -f conftest.[cs]
+])
+if test $xvba_cv_visibility_attribute = yes; then
+ AC_DEFINE([HAVE_VISIBILITY_ATTRIBUTE], 1, [Define to use the __attribute__((visibility())) extension])
+fi
+
+dnl Check for OpenGL
+USE_GLX=1
+if test "$enable_glx" != "yes"; then
+ USE_GLX=0
+fi
+GL_DEPS_CFLAGS=""
+GL_DEPS_LIBS=""
+AC_CHECK_HEADERS([GL/gl.h GL/glext.h GL/glx.h], [], [USE_GLX=0], [
+#ifdef HAVE_GL_GL_H
+# include <GL/gl.h>
+#endif
+])
+AC_CHECK_LIB(GL, glXCreateContext, [GL_DEPS_LIBS="-lGL -ldl"], [USE_GLX=0])
+AC_SUBST(GL_DEPS_CFLAGS)
+AC_SUBST(GL_DEPS_LIBS)
+
+dnl Check for VA-API
+PKG_CHECK_MODULES(LIBVA_DEPS, [libva])
+PKG_CHECK_MODULES(LIBVA_X11_DEPS, [libva-x11])
+PKG_CHECK_MODULES(LIBVA_GLX_DEPS, [libva-glx], [], [USE_GLX=0])
+
+dnl Check for SDS extensions to VA-API
+AC_CACHE_CHECK([for VA-API],
+ ac_cv_libva_sds_extensions, [
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $LIBVA_DEPS_CFLAGS"
+ AC_TRY_COMPILE([
+ #include <va/va_version.h>
+ #if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 29
+ # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_SDS_VERSION_0_29)
+ # error "VA-API version >= 0.29.0-sds$LIBVA_SDS_VERSION_0_29 is required"
+ # endif
+ #elif VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 30
+ # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_SDS_VERSION_0_30)
+ # error "VA-API version >= 0.30.0-sds$LIBVA_SDS_VERSION_0_30 is required"
+ # endif
+ #elif !VA_CHECK_VERSION(0,31,0)
+ # error "VA-API version >= 0.31 is required"
+ #endif
+ ], [],
+ [ac_cv_libva_sds_extensions="yes"],
+ [ac_cv_libva_sds_extensions="no"])
+ CFLAGS="$saved_CFLAGS"
+])
+VA_VERSION=`$PKG_CONFIG --modversion libva`
+VA_MAJOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f1`
+VA_MINOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f2`
+VA_MICRO_VERSION=`echo "$VA_VERSION" | cut -d'.' -f3`
+VA_SDS_VERSION=`$PKG_CONFIG libva --variable sdsversion`
+
+VA_VERSION_STR="$VA_VERSION"
+if test -n "$VA_SDS_VERSION"; then
+ VA_VERSION_STR="$VA_VERSION_STR-sds$VA_SDS_VERSION"
+fi
+
+va_full_version_int=`expr ${VA_MAJOR_VERSION:-0} "*" 1000000 + \
+ ${VA_MINOR_VERSION:-0} "*" 10000 + \
+ ${VA_MICRO_VERSION:-0} "*" 100 + \
+ ${VA_SDS_VERSION:-0}`
+VA_DRIVER_INIT_FUNC="__vaDriverInit_${VA_MAJOR_VERSION}_${VA_MINOR_VERSION}"
+if test $va_full_version_int -ge 00310005; then
+ VA_DRIVER_INIT_FUNC="${VA_DRIVER_INIT_FUNC}_${VA_MICRO_VERSION}_sds${VA_SDS_VERSION}"
+else
+ VA_DRIVER_INIT_FUNC="${VA_DRIVER_INIT_FUNC}_sds"
+fi
+if test "$ac_cv_libva_sds_extensions" = "yes"; then
+ AC_DEFINE_UNQUOTED([VA_DRIVER_INIT_FUNC], [$VA_DRIVER_INIT_FUNC], [Define driver entry-point])
+else
+ AC_MSG_ERROR([Your VA-API SDK does not include SDS extensions])
+fi
+
+dnl Check for OpenGL rendering extensions to VA-API
+AC_CACHE_CHECK([for VA-API (GLX extensions)],
+ ac_cv_libva_glx_extensions, [
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $LIBVA_DEPS_CFLAGS"
+ AC_TRY_COMPILE([
+ #include <va/va_version.h>
+ #if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 30
+ # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_GLX_SDS_VERSION_0_30)
+ # error "VA-API version >= 0.30.0-sds$LIBVA_GLX_SDS_VERSION_0_30 is required"
+ # endif
+ #elif VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 31
+ # if !defined(VA_SDS_VERSION) || (VA_SDS_VERSION < $LIBVA_GLX_SDS_VERSION_0_31)
+ # error "VA-API version >= 0.31.0-sds$LIBVA_GLX_SDS_VERSION_0_31 is required"
+ # endif
+ #elif VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION >= 32
+ #else
+ # error "This version of VA-API is not supported for OpenGL rendering"
+ #endif
+ ], [],
+ [ac_cv_libva_glx_extensions="yes"],
+ [ac_cv_libva_glx_extensions="no" USE_GLX=0])
+ CFLAGS="$saved_CFLAGS"
+])
+
+dnl Check for VA-API drivers path
+AC_MSG_CHECKING([for VA drivers path])
+LIBVA_DRIVERS_PATH=`$PKG_CONFIG libva --variable driverdir`
+if test -z "$LIBVA_DRIVERS_PATH"; then
+ LIBVA_DRIVERS_PATH="/usr/lib/xorg/modules/drivers"
+fi
+AC_MSG_RESULT([$LIBVA_DRIVERS_PATH])
+AC_SUBST(LIBVA_DRIVERS_PATH)
+
+dnl Check for XvBA
+AC_CACHE_CHECK([for XvBA],
+ ac_cv_have_xvba, [
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS -lXvBAW"
+ LIBS="$LIBS -lX11 -lXext -lGL -ldl" # XXX: help broken XvBA libraries...
+ AC_TRY_LINK(
+ [
+#include <X11/Xlib.h>
+#include <amdxvba.h>
+ ],
+ [XVBAQueryExtension(0,0)],
+ [ac_cv_have_xvba="yes" HAVE_XVBA=1],
+ [ac_cv_have_xvba="no" HAVE_XVBA=0])
+ LIBS="$saved_LIBS"
+])
+if test "$ac_cv_have_xvba" = "no"; then
+ AC_MSG_ERROR([you need XvBA to build this package])
+fi
+
+AC_DEFINE_UNQUOTED(USE_GLX, $USE_GLX, [Defined to 1 if GLX is enabled])
+AM_CONDITIONAL(USE_GLX, test $USE_GLX -eq 1)
+
+PKG_CHECK_MODULES(DRM_DEPS, [libdrm])
+
+XVBA_VIDEO_CFLAGS="$LIBVA_DEPS_CFLAGS $DRM_DEPS_CFLAGS"
+XVBA_VIDEO_LIBS=""
+if test "$enable_libxvba_dlopen" = "yes"; then
+ XVBA_VIDEO_LIBS="$XVBA_VIDEO_LIBS -ldl"
+else
+ XVBA_VIDEO_LIBS="$XVBA_VIDEO_LIBS -lXvBAW -lXext -lGL"
+fi
+if test $USE_GLX -eq 1; then
+ XVBA_VIDEO_CFLAGS="$XVBA_VIDEO_CFLAGS $GL_DEPS_CFLAGS"
+ XVBA_VIDEO_LIBS="$XVBA_VIDEO_LIBS $GL_DEPS_LIBS"
+fi
+if test "$enable_valgrind" = "yes"; then
+ PKG_CHECK_MODULES(VALGRIND_DEPS, [valgrind])
+ XVBA_VIDEO_CFLAGS="$XVBA_VIDEO_CFLAGS $VALGRIND_DEPS_CFLAGS"
+fi
+AC_SUBST(XVBA_VIDEO_CFLAGS)
+AC_SUBST(XVBA_VIDEO_LIBS)
+
+AC_OUTPUT([
+ Makefile
+ debian.upstream/Makefile
+ src/Makefile
+ src/shaders/Makefile
+])
+
+dnl Print summary
+echo
+echo xvba-video configuration summary:
+echo
+echo VA-API version ................... : $VA_VERSION_STR
+echo GLX support ...................... : $(test $USE_GLX -eq 1 && echo yes || echo no)
+echo Cg compiler ...................... : $CGC
+echo Enable debugging information ..... : $enable_debug
+echo Enable XvBA tracer ............... : $enable_tracer
diff --git a/debian.upstream/Makefile.am b/debian.upstream/Makefile.am
new file mode 100644
index 0000000..0816444
--- /dev/null
+++ b/debian.upstream/Makefile.am
@@ -0,0 +1,27 @@
+DEBIANFILES = \
+ changelog.in \
+ compat \
+ control.in \
+ copyright \
+ rules \
+ xvba-video.install \
+ $(NULL)
+
+DEBIANGENFILES = \
+ changelog \
+ control \
+ $(NULL)
+
+EXTRA_DIST = $(DEBIANFILES)
+
+dist_noinst_DATA = $(DEBIANGENFILES)
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = Makefile.in $(DEBIANGENFILES)
+
+$(DEBIANGENFILES): %: %.in Makefile
+ -sed \
+ -e 's|\@PACKAGE_VERSION\@|$(PACKAGE_VERSION)|' \
+ -e 's|\@LIBVA_SDS_PACKAGE_VERSION\@|$(LIBVA_SDS_PACKAGE_VERSION)|' \
+ -e 's|\@DATE\@|'"`LC_ALL=C date +'%a, %d %b %Y %X %z'`"'|' \
+ $< > $@
diff --git a/debian.upstream/changelog.in b/debian.upstream/changelog.in
new file mode 100644
index 0000000..c2b20f3
--- /dev/null
+++ b/debian.upstream/changelog.in
@@ -0,0 +1,5 @@
+xvba-video (@PACKAGE_VERSION@-1) unstable; urgency=low
+
+ * Autogenerated package, see NEWS file for ChangeLog.
+
+ -- Gwenole Beauchesne <gbeauchesne@splitted-desktop.com> @DATE@
diff --git a/debian.upstream/compat b/debian.upstream/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian.upstream/compat
@@ -0,0 +1 @@
+5
diff --git a/debian.upstream/control.in b/debian.upstream/control.in
new file mode 100644
index 0000000..2e6db32
--- /dev/null
+++ b/debian.upstream/control.in
@@ -0,0 +1,27 @@
+Source: xvba-video
+Section: libs
+Priority: optional
+Maintainer: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
+Build-Depends: debhelper (>= 5),
+ cdbs,
+ libdrm-dev,
+ libva-dev (>= @LIBVA_SDS_PACKAGE_VERSION@),
+ python
+Standards-Version: 3.7.2
+
+Package: xvba-video
+Section: libs
+Architecture: any
+Depends: libva1 (>= @LIBVA_SDS_PACKAGE_VERSION@),
+ ${shlibs:Depends}, ${misc:Depends}
+Description: XvBA-based backend for VA-API
+ Video decode driver for ATI/AMD chipsets (XvBA implementation).
+
+Package: xvba-video-dbg
+Section: libdevel
+Architecture: any
+Depends: xvba-video (= ${Source-Version})
+Description: XvBA-based backend for VA-API
+ Video decode driver for ATI/AMD chipsets (XvBA implementation).
+ .
+ This package contains the debug files.
diff --git a/debian.upstream/copyright b/debian.upstream/copyright
new file mode 100644
index 0000000..63b3d55
--- /dev/null
+++ b/debian.upstream/copyright
@@ -0,0 +1,24 @@
+This package is maintained by:
+Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
+
+
+License:
+
+ Copyright (C) 2009-2011 Splitted-Desktop Systems
+
+ 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.
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License is in `/usr/share/common-licenses/GPL'.
diff --git a/debian.upstream/rules b/debian.upstream/rules
new file mode 100755
index 0000000..a6286f6
--- /dev/null
+++ b/debian.upstream/rules
@@ -0,0 +1,18 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/simple-patchsys.mk
+include /usr/share/cdbs/1/rules/utils.mk
+
+# Allow SMP build
+ifeq ($(DEBIAN_BUILD_NCPUS),)
+ DEBIAN_BUILD_NCPUS = $(shell /usr/bin/getconf _NPROCESSORS_ONLN)
+endif
+ifneq ($(DEBIAN_BUILD_NCPUS),)
+ EXTRA_MAKE_FLAGS += -j$(DEBIAN_BUILD_NCPUS)
+endif
+MAKE += $(EXTRA_MAKE_FLAGS)
+
+DEB_CONFIGURE_USER_FLAGS += --enable-debug
+DEB_CONFIGURE_USER_FLAGS += --enable-tracer
diff --git a/debian.upstream/xvba-video.install b/debian.upstream/xvba-video.install
new file mode 100644
index 0000000..8fbbd2b
--- /dev/null
+++ b/debian.upstream/xvba-video.install
@@ -0,0 +1 @@
+debian/tmp/usr/lib/va/drivers/*.so
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..02b9430
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,82 @@
+DRIVERS = fglrx
+
+SUBDIRS = shaders
+
+INCLUDES = \
+ $(XVBA_VIDEO_CFLAGS)
+
+LDADD = \
+ $(XVBA_VIDEO_LT_LDFLAGS) -module \
+ -no-undefined -module -Wl,--no-undefined
+
+if USE_GLX
+source_glx_h = xvba_video_glx.h utils_glx.h
+source_glx_c = xvba_video_glx.c utils_glx.c
+endif
+
+source_x11_h = xvba_video_x11.h utils_x11.h
+source_x11_c = xvba_video_x11.c utils_x11.c
+
+source_h = \
+ color_matrix.h \
+ debug.h \
+ fglrxinfo.h \
+ object_heap.h \
+ sysdeps.h \
+ utils.h \
+ uarray.h \
+ uasyncqueue.h \
+ ulist.h \
+ uqueue.h \
+ vaapi_compat.h \
+ xvba_buffer.h \
+ xvba_decode.h \
+ xvba_driver.h \
+ xvba_driver_template.h \
+ xvba_dump.h \
+ xvba_gate.h \
+ xvba_image.h \
+ xvba_subpic.h \
+ xvba_video.h \
+ $(source_glx_h) \
+ $(source_x11_h) \
+ $(NULL)
+
+source_c = \
+ color_matrix.c \
+ debug.c \
+ fglrxinfo.c \
+ object_heap.c \
+ utils.c \
+ uarray.c \
+ uasyncqueue.c \
+ ulist.c \
+ uqueue.c \
+ xvba_buffer.c \
+ xvba_decode.c \
+ xvba_driver.c \
+ xvba_dump.c \
+ xvba_gate.c \
+ xvba_image.c \
+ xvba_subpic.c \
+ xvba_video.c \
+ $(source_glx_c) \
+ $(source_x11_c) \
+ $(NULL)
+
+xvba_drv_video_la_LTLIBRARIES = xvba_drv_video.la
+xvba_drv_video_ladir = @LIBVA_DRIVERS_PATH@
+xvba_drv_video_la_SOURCES = $(source_c)
+xvba_drv_video_la_LIBADD = $(XVBA_VIDEO_LIBS) -lX11 -lXext
+xvba_drv_video_la_LDFLAGS = $(LDADD)
+
+noinst_HEADERS = $(source_h)
+
+install-data-hook:
+ cd $(DESTDIR)$(LIBVA_DRIVERS_PATH) ; \
+ for drv in $(DRIVERS); do \
+ ln -s xvba_drv_video.so $${drv}_drv_video.so; \
+ done
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = Makefile.in config.h.in
diff --git a/src/color_matrix.c b/src/color_matrix.c
new file mode 100644
index 0000000..62020d7
--- /dev/null
+++ b/src/color_matrix.c
@@ -0,0 +1,469 @@
+/*
+ * color_matrix.c - Color matrix utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "color_matrix.h"
+#include <math.h>
+
+// Default weight values
+#define Rw (0.3086)
+#define Gw (0.6094)
+#define Bw (0.0820)
+
+// 3D point
+typedef struct {
+ float x;
+ float y;
+ float z;
+} Point3D;
+
+// Print color matrix M with NAME
+#ifdef TEST
+static void cm_print(ColorMatrix m, const char *name)
+{
+ int x, y;
+
+ printf("%s = {\n", name);
+ for (y = 0; y < 4; y++) {
+ putchar(' ');
+ for (x = 0; x < 4; x++)
+ printf(" %f", m[y][x]);
+ putchar('\n');
+ }
+ printf("}\n");
+}
+#endif
+
+// Assign color matrix A to M
+void cm_copy(ColorMatrix m, ColorMatrix a)
+{
+#if 1
+ int x, y;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ m[y][x] = a[y][x];
+#else
+ m[0][0] = a[0][0];
+ m[0][1] = a[0][1];
+ m[0][2] = a[0][2];
+ m[0][3] = a[0][3];
+
+ m[1][0] = a[1][0];
+ m[1][1] = a[1][1];
+ m[1][2] = a[1][2];
+ m[1][3] = a[1][3];
+
+ m[2][0] = a[2][0];
+ m[2][1] = a[2][1];
+ m[2][2] = a[2][2];
+ m[2][3] = a[2][3];
+
+ m[3][0] = a[3][0];
+ m[3][1] = a[3][1];
+ m[3][2] = a[3][2];
+ m[3][3] = a[3][3];
+#endif
+}
+
+// Multiply color matrices A and B and set the result to M
+void cm_multiply(ColorMatrix m, ColorMatrix a, ColorMatrix b)
+{
+ ColorMatrix t;
+ int x, y;
+
+ for (y = 0; y < 4; y++)
+ for (x = 0; x < 4; x++)
+ t[y][x] = (b[y][0] * a[0][x] +
+ b[y][1] * a[1][x] +
+ b[y][2] * a[2][x] +
+ b[y][3] * a[3][x]);
+
+ cm_copy(m, t);
+}
+
+// Transform a 3D point using the color matrix
+static void cm_transform(ColorMatrix m, const Point3D *p, Point3D *tp)
+{
+ tp->x = p->x * m[0][0] + p->y * m[1][0] + p->z * m[2][0] + m[3][0];
+ tp->y = p->x * m[0][1] + p->y * m[1][1] + p->z * m[2][1] + m[3][1];
+ tp->z = p->x * m[0][2] + p->y * m[1][2] + p->z * m[2][2] + m[3][2];
+}
+
+// Create a new color matrix with a SCALE factor
+static inline void cm_set_scale(ColorMatrix m, float scale)
+{
+ m[0][0] = scale;
+ m[0][1] = 0.0f;
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+
+ m[1][0] = 0.0f;
+ m[1][1] = scale;
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = scale;
+ m[2][3] = 0.0f;
+
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+// Create a new identity matrix
+void cm_set_identity(ColorMatrix m)
+{
+ cm_set_scale(m, 1.0f);
+}
+
+// Create a new color matrix with offset R/G/B components
+static void cm_set_offset(ColorMatrix m, float r, float g, float b)
+{
+ cm_set_identity(m);
+
+ m[3][0] = r;
+ m[3][1] = g;
+ m[3][2] = b;
+}
+
+// Set color matrix components for a rotation around the x (red) axis
+static void cm_set_rotation_x(ColorMatrix m, float rs, float rc)
+{
+ m[0][0] = 1.0f;
+ m[0][1] = 0.0f;
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+
+ m[1][0] = 0.0f;
+ m[1][1] = rc;
+ m[1][2] = rs;
+ m[1][3] = 0.0f;
+
+ m[2][0] = 0.0f;
+ m[2][1] = -rs;
+ m[2][2] = rc;
+ m[2][3] = 0.0f;
+
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+// Set color matrix components for a rotation around the y (green) axis
+static void cm_set_rotation_y(ColorMatrix m, float rs, float rc)
+{
+ m[0][0] = rc;
+ m[0][1] = 0.0f;
+ m[0][2] = -rs;
+ m[0][3] = 0.0f;
+
+ m[1][0] = 0.0f;
+ m[1][1] = 1.0f;
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+
+ m[2][0] = rs;
+ m[2][1] = 0.0f;
+ m[2][2] = rc;
+ m[2][3] = 0.0f;
+
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+// Set color matrix components for a rotation around the z (blue) axis
+static void cm_set_rotation_z(ColorMatrix m, float rs, float rc)
+{
+ m[0][0] = rc;
+ m[0][1] = rs;
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+
+ m[1][0] = -rs;
+ m[1][1] = rc;
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+ m[2][3] = 0.0f;
+
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+// Shear z using x and y
+static void cm_shear_z(ColorMatrix m, float dx, float dy)
+{
+ ColorMatrix t;
+
+ t[0][0] = 1.0f;
+ t[0][1] = 0.0f;
+ t[0][2] = dx;
+ t[0][3] = 0.0f;
+
+ t[1][0] = 0.0f;
+ t[1][1] = 1.0f;
+ t[1][2] = dy;
+ t[1][3] = 0.0f;
+
+ t[2][0] = 0.0f;
+ t[2][1] = 0.0f;
+ t[2][2] = 1.0f;
+ t[2][3] = 0.0f;
+
+ t[3][0] = 0.0f;
+ t[3][1] = 0.0f;
+ t[3][2] = 0.0f;
+ t[3][3] = 1.0f;
+
+ cm_multiply(m, t, m);
+}
+
+// Return BRIGHTNESS value range
+void cm_get_brightness_range(float *vstart, float *vend, float *vdefault)
+{
+ /* Brightness value ranges from 0.0 to 10.0. A value of 1.0
+ represents no modification */
+ if (vstart)
+ *vstart = 0.0f;
+ if (vend)
+ *vend = 10.0f;
+ if (vdefault)
+ *vdefault = 1.0f;
+}
+
+// Create a new color matrix with a specific BRIGHTNESS value
+void cm_set_brightness(ColorMatrix m, float brightness)
+{
+ cm_set_scale(m, brightness);
+}
+
+// Return CONTRAST value range
+void cm_get_contrast_range(float *vstart, float *vend, float *vdefault)
+{
+ /* Contrast value ranges from 0 to 10.0. A value of 1.0
+ represents no modification */
+ if (vstart)
+ *vstart = 0.0f;
+ if (vend)
+ *vend = 10.0f;
+ if (vdefault)
+ *vdefault = 1.0f;
+}
+
+// Create a new color matrix with a specific CONTRAST value
+void cm_set_contrast(ColorMatrix m, float contrast)
+{
+ ColorMatrix n; /* offset by -0.5f */
+ ColorMatrix p; /* offset by +0.5f */
+ ColorMatrix s; /* scaled by contrast */
+ ColorMatrix t;
+
+ cm_set_scale(s, contrast);
+ cm_set_offset(n, -0.5f, -0.5f, -0.5f);
+ cm_set_offset(p, +0.5f, +0.5f, +0.5f);
+ cm_multiply(t, s, n);
+ cm_multiply(m, p, t);
+}
+
+// Return SATURATION value range
+void cm_get_saturation_range(float *vstart, float *vend, float *vdefault)
+{
+ /* Saturation value ranges from 0.0 to 10.0. A value of 1.0
+ represents no modification */
+ if (vstart)
+ *vstart = 0.0f;
+ if (vend)
+ *vend = 10.0f;
+ if (vdefault)
+ *vdefault = 1.0f;
+}
+
+// Create a new color matrix used for SATURATION
+void cm_set_saturation(ColorMatrix m, float saturation)
+{
+ /*
+ * +- -+
+ * | a d g 0 |
+ * | b e h 0 |
+ * | c f i 0 |
+ * | 0 0 0 1 |
+ * +- -+
+ *
+ * where
+ *
+ * a = (1 - s) * Rw + s
+ * b = (1 - s) * Rw
+ * c = (1 - s) * Rw
+ * d = (1 - s) * Gw
+ * e = (1 - s) * Gw + s
+ * f = (1 - s) * Gw
+ * g = (1 - s) * Bw
+ * h = (1 - s) * Bw
+ * i = (1 - s) * Bw + s
+ */
+ m[0][0] = (1.0f - saturation) * Rw + saturation;
+ m[0][1] = (1.0f - saturation) * Rw;
+ m[0][2] = (1.0f - saturation) * Rw;
+ m[0][3] = 0.0f;
+
+ m[1][0] = (1.0f - saturation) * Gw;
+ m[1][1] = (1.0f - saturation) * Gw + saturation;
+ m[1][2] = (1.0f - saturation) * Gw;
+ m[1][3] = 0.0f;
+
+ m[2][0] = (1.0f - saturation) * Bw;
+ m[2][1] = (1.0f - saturation) * Bw;
+ m[2][2] = (1.0f - saturation) * Bw + saturation;
+ m[2][3] = 0.0f;
+
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+}
+
+// Return the HUE value range
+void cm_get_hue_range(float *vstart, float *vend, float *vdefault)
+{
+ /* Hue value ranges from -PI to +PI. A value of 0.0 represents no
+ modification */
+ if (vstart)
+ *vstart = -M_PI;
+ if (vend)
+ *vend = M_PI;
+ if (vdefault)
+ *vdefault = 0.0f;
+}
+
+// Create a new color matrix used for HUE rotation
+void cm_set_hue(ColorMatrix m, float hue)
+{
+ cm_set_rotation_z(m, sin(hue), cos(hue));
+}
+
+// Rotate hue while preserving the luminance
+// From <http://www.graficaobscura.com/matrix/index.html> (Paul Haeberli, 1993)
+static void cm_rotate_hue(ColorMatrix m, ColorMatrix h)
+{
+ ColorMatrix t, xr, yr;
+ float mag;
+ Point3D lum, tlum;
+ float xrs, xrc;
+ float yrs, yrc;
+ float zsx, zsy;
+
+ /* Rotate the grey vector into positive Z */
+ mag = sqrtf(2.0f);
+ xrs = 1.0f / mag;
+ xrc = 1.0f / mag;
+ cm_set_rotation_x(xr, xrs, xrc);
+
+ mag = sqrtf(3.0f);
+ yrs = -1.0f / mag;
+ yrc = sqrtf(2.0f) / mag;
+ cm_set_rotation_y(yr, yrs, yrc);
+
+ cm_set_identity(t);
+ cm_multiply(t, xr, t);
+ cm_multiply(t, yr, t);
+
+ /* Shear the space to make the luminance plane horizontal */
+ lum.x = Rw;
+ lum.y = Gw;
+ lum.z = Bw;
+ cm_transform(t, &lum, &tlum);
+ zsx = tlum.x / tlum.z;
+ zsy = tlum.y / tlum.z;
+ cm_shear_z(t, zsx, zsy);
+
+ /* Rotate the hue */
+ cm_multiply(t, h, t);
+
+ /* Unshear the space to put the luminance plane back */
+ cm_shear_z(t, -zsx, -zsy);
+
+ /* Rotate the grey vector back into place */
+ cm_set_rotation_y(yr, -yrs, yrc);
+ cm_set_rotation_x(xr, -xrs, xrc);
+
+ cm_multiply(t, yr, t);
+ cm_multiply(t, xr, t);
+ cm_multiply(m, t, m);
+}
+
+// Create composite matrix from brightness/contrast/saturation/hue matrices
+void cm_composite(
+ ColorMatrix m,
+ ColorMatrix b,
+ ColorMatrix c,
+ ColorMatrix s,
+ ColorMatrix h
+)
+{
+ ColorMatrix t;
+
+ cm_multiply(t, c, b);
+ cm_multiply(m, t, s);
+ cm_rotate_hue(m, h);
+}
+
+#ifdef TEST
+int main(void)
+{
+ ColorMatrix brightness_matrix;
+ cm_set_brightness(brightness_matrix, 1.0f);
+ cm_print(brightness_matrix, "brightness matrix");
+
+ ColorMatrix contrast_matrix;
+ cm_set_contrast(contrast_matrix, 1.0f);
+ cm_print(contrast_matrix, "contrast_matrix");
+
+ ColorMatrix saturation_matrix;
+ cm_set_saturation(saturation_matrix, 1.0f);
+ cm_print(saturation_matrix, "saturation matrix");
+
+ ColorMatrix hue_matrix;
+ cm_set_hue(hue_matrix, 0.0f);
+ cm_print(hue_matrix, "hue matrix");
+
+ ColorMatrix color_matrix;
+ cm_composite(
+ color_matrix,
+ brightness_matrix,
+ contrast_matrix,
+ saturation_matrix,
+ hue_matrix
+ );
+ cm_print(color_matrix, "composite matrix");
+ return 0;
+}
+#endif
diff --git a/src/color_matrix.h b/src/color_matrix.h
new file mode 100644
index 0000000..dacbe75
--- /dev/null
+++ b/src/color_matrix.h
@@ -0,0 +1,79 @@
+/*
+ * color_matrix.h - Color matrix utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef COLOR_MATRIX_H
+#define COLOR_MATRIX_H
+
+typedef float ColorMatrix[4][4];
+
+// Assign color matrix A to M
+void cm_copy(ColorMatrix m, ColorMatrix a)
+ attribute_hidden;
+
+// Multiply color matrices A and B and set the result to M
+void cm_multiply(ColorMatrix m, ColorMatrix a, ColorMatrix b)
+ attribute_hidden;
+
+// Create a new identity matrix
+void cm_set_identity(ColorMatrix m)
+ attribute_hidden;
+
+// Return CONTRAST value range
+void cm_get_brightness_range(float *vstart, float *vend, float *vdefault)
+ attribute_hidden;
+
+// Create a new color matrix with a specific BRIGHTNESS value
+void cm_set_brightness(ColorMatrix m, float brightness)
+ attribute_hidden;
+
+// Return CONTRAST value range
+void cm_get_contrast_range(float *vstart, float *vend, float *vdefault)
+ attribute_hidden;
+
+// Create a new color matrix with a specific CONTRAST value
+void cm_set_contrast(ColorMatrix m, float contrast)
+ attribute_hidden;
+
+// Return SATURATION value range
+void cm_get_saturation_range(float *vstart, float *vend, float *vdefault)
+ attribute_hidden;
+
+// Create a new color matrix used for SATURATION
+void cm_set_saturation(ColorMatrix m, float saturation)
+ attribute_hidden;
+
+// Return the HUE value range
+void cm_get_hue_range(float *vstart, float *vend, float *vdefault)
+ attribute_hidden;
+
+// Create a new color matrix used for HUE rotation
+void cm_set_hue(ColorMatrix m, float hue)
+ attribute_hidden;
+
+// Create composite matrix from brightness/contrast/saturation/hue matrices
+void cm_composite(
+ ColorMatrix m,
+ ColorMatrix b,
+ ColorMatrix c,
+ ColorMatrix s,
+ ColorMatrix h
+) attribute_hidden;
+
+#endif /* COLOR_MATRIX_H */
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..b65e334
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,158 @@
+/*
+ * debug.c - Debugging utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "debug.h"
+#include <stdarg.h>
+#include "utils.h"
+
+#if USE_VALGRIND
+# include <valgrind.h>
+#endif
+
+static void do_vprintf(const char *msg, va_list args)
+{
+#if USE_VALGRIND
+ if (RUNNING_ON_VALGRIND) {
+ static char *fmt = NULL;
+ static int fmtlen = 0;
+
+ int xmsglen = vsnprintf(NULL, 0, msg, args);
+ if ((fmt = realloc(fmt, fmtlen + xmsglen + 1)) != NULL) {
+ vsnprintf(fmt + fmtlen, fmtlen + xmsglen + 1, msg, args);
+ fmt[fmtlen += xmsglen] = '\0';
+ if (fmt[fmtlen - 1] == '\n') {
+ fmt[fmtlen - 1] = '\0';
+ VALGRIND_PRINTF(fmt); /* this already adds a terminal '\n' */
+ free(fmt);
+ fmt = NULL;
+ fmtlen = 0;
+ }
+ }
+ return;
+ }
+#endif
+ vprintf(msg, args);
+}
+
+static void do_printf(const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ do_vprintf(msg, args);
+ va_end(args);
+}
+
+void xvba_error_message(const char *msg, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "%s: error: ", PACKAGE_NAME);
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+}
+
+void xvba_information_message(const char *msg, ...)
+{
+ va_list args;
+
+ do_printf("%s: ", PACKAGE_NAME);
+ va_start(args, msg);
+ do_vprintf(msg, args);
+ va_end(args);
+}
+
+static int debug_enabled(void)
+{
+ static int g_debug_enabled = -1;
+ if (g_debug_enabled < 0) {
+ if (getenv_yesno("XVBA_VIDEO_DEBUG", &g_debug_enabled) < 0)
+ g_debug_enabled = 0;
+ }
+ return g_debug_enabled;
+}
+
+void debug_message(const char *msg, ...)
+{
+ va_list args;
+
+ if (!debug_enabled())
+ return;
+
+ do_printf("%s: ", PACKAGE_NAME);
+ va_start(args, msg);
+ do_vprintf(msg, args);
+ va_end(args);
+}
+
+static int g_trace_is_new_line = 1;
+static int g_trace_indent = 0;
+
+int trace_enabled(void)
+{
+ static int g_trace_enabled = -1;
+ if (g_trace_enabled < 0) {
+ if (getenv_yesno("XVBA_VIDEO_TRACE", &g_trace_enabled) < 0)
+ g_trace_enabled = 0;
+ }
+ return g_trace_enabled;
+}
+
+static int trace_indent_width(void)
+{
+ static int g_indent_width = -1;
+ if (g_indent_width < 0) {
+ if (getenv_int("XVBA_VIDEO_TRACE_INDENT_WIDTH", &g_indent_width) < 0)
+ g_indent_width = 4;
+ }
+ return g_indent_width;
+}
+
+void trace_indent(int inc)
+{
+ g_trace_indent += inc;
+}
+
+void trace_print(const char *format, ...)
+{
+ va_list args;
+
+ if (g_trace_is_new_line) {
+ int i, j, n;
+ printf("%s: ", PACKAGE_NAME);
+ n = trace_indent_width();
+ for (i = 0; i < g_trace_indent; i++) {
+ for (j = 0; j < n / 4; j++)
+ printf(" ");
+ for (j = 0; j < n % 4; j++)
+ printf(" ");
+ }
+ }
+
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+
+ g_trace_is_new_line = (strchr(format, '\n') != NULL);
+
+ if (g_trace_is_new_line)
+ fflush(stdout);
+}
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..550b96c
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,52 @@
+/*
+ * debug.h - Debugging utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+void xvba_error_message(const char *msg, ...)
+ attribute_hidden;
+
+void xvba_information_message(const char *msg, ...)
+ attribute_hidden;
+
+void debug_message(const char *msg, ...)
+ attribute_hidden;
+
+#if DEBUG && USE_DEBUG
+# define D(x) x
+# define bug debug_message
+#else
+# define D(x)
+#endif
+
+// Returns TRUE if debug trace is enabled
+int trace_enabled(void)
+ attribute_hidden;
+
+// Increase or decrease indentation level
+void trace_indent(int inc)
+ attribute_hidden;
+
+// Print message on the debug trace output
+void trace_print(const char *format, ...)
+ attribute_hidden;
+
+#endif /* DEBUG_H */
diff --git a/src/fglrxinfo.c b/src/fglrxinfo.c
new file mode 100644
index 0000000..953069b
--- /dev/null
+++ b/src/fglrxinfo.c
@@ -0,0 +1,221 @@
+/*
+ * fglrxinfo.c - FGLRX driver info
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#define NEED_REPLIES
+#include <X11/Xlibint.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include "fglrxinfo.h"
+
+#define ATIFGL_EXTENSION_NAME "ATIFGLEXTENSION"
+#define ATIFGL_EXTENSION_EVENTS 0
+
+typedef struct _FGLGetDriverData {
+ CARD8 reqType;
+ CARD8 fireglReqType;
+ CARD16 length B16;
+ CARD32 screen B32;
+ CARD16 size B16;
+ CARD16 pad1;
+} xFGLGetDriverDataReq;
+#define sz_xFGLGetDriverDataReq sizeof(xFGLGetDriverDataReq)
+
+typedef struct {
+ BYTE type;
+ BYTE pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD8 majorVersion;
+ CARD8 minorVersion;
+ CARD8 patchlevel B16;
+ CARD8 BIOSVersionMajor;
+ CARD8 BIOSVersionMinor;
+ CARD8 HasSecondary;
+ CARD16 pad3 B16;
+ CARD16 pad4 B16;
+ CARD16 deviceID B16;
+ CARD32 pad5 B32;
+ CARD32 pad6 B32;
+ CARD32 pad7 B32;
+ // ... there are more fields
+} xFGLGetDriverDataReply;
+#define sz_xFGLGetDriverDataReply sizeof(xFGLGetDriverDataReply)
+
+#define X_FGLGetDriverData 0
+
+static XExtensionInfo _fglext_ext_info_data;
+static XExtensionInfo *fglext_ext_info = &_fglext_ext_info_data;
+static /* const */ char *fglext_extension_name = ATIFGL_EXTENSION_NAME;
+
+#define xFGLCheckExtension(dpy,i,val) \
+ XextCheckExtension (dpy, i, fglext_extension_name, val)
+
+static int close_display();
+static /* const */ XExtensionHooks fglext_extension_hooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ close_display, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ NULL, /* error_string */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (find_display, fglext_ext_info,
+ fglext_extension_name,
+ &fglext_extension_hooks,
+ ATIFGL_EXTENSION_EVENTS, NULL)
+
+static XEXT_GENERATE_CLOSE_DISPLAY (close_display, fglext_ext_info)
+
+Bool fglrx_is_dri_capable(Display *dpy, int screen)
+{
+ char **extensions;
+ int i, n_extensions, has_fglext = 0, has_fglrxdri = 0;
+
+ extensions = XListExtensions(dpy, &n_extensions);
+ if (!extensions)
+ return False;
+
+ for (i = 0; i < n_extensions; i++) {
+ if (strcmp(extensions[i], ATIFGL_EXTENSION_NAME) == 0)
+ has_fglext = 1;
+ if (strcmp(extensions[i], "ATIFGLRXDRI") == 0)
+ has_fglrxdri = 1;
+ }
+ XFreeExtensionList(extensions);
+ return has_fglext && has_fglrxdri;
+}
+
+Bool fglrx_get_version(
+ Display *dpy,
+ int screen,
+ int *ddxDriverMajorVersion,
+ int *ddxDriverMinorVersion,
+ int *ddxDriverPatchVersion
+)
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ xFGLGetDriverDataReply rep;
+ xFGLGetDriverDataReq *req;
+
+ if (ddxDriverMajorVersion)
+ *ddxDriverMajorVersion = 0;
+ if (ddxDriverMinorVersion)
+ *ddxDriverMinorVersion = 0;
+ if (ddxDriverPatchVersion)
+ *ddxDriverPatchVersion = 0;
+
+ if(!XextHasExtension(info))
+ return False;
+
+ xFGLCheckExtension (dpy, info, False);
+
+ LockDisplay (dpy);
+ GetReq (FGLGetDriverData, req);
+ req->reqType = info->codes->major_opcode;
+ req->fireglReqType = X_FGLGetDriverData;
+ req->screen = screen;
+ if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
+ UnlockDisplay (dpy);
+ SyncHandle ();
+ return False;
+ }
+ UnlockDisplay (dpy);
+ SyncHandle ();
+
+ if (ddxDriverMajorVersion)
+ *ddxDriverMajorVersion = rep.majorVersion;
+ if (ddxDriverMinorVersion)
+ *ddxDriverMinorVersion = rep.minorVersion;
+ if (ddxDriverPatchVersion)
+ *ddxDriverPatchVersion = rep.patchlevel;
+
+ return True;
+}
+
+int fglrx_check_version(int major, int minor, int micro)
+{
+ static int is_initialized = -1;
+ static int fglrx_version_major, fglrx_version_minor, fglrx_version_micro;
+
+ if (is_initialized < 0) {
+ Display *dpy = XOpenDisplay(NULL);
+ if (!dpy)
+ is_initialized = 0;
+ else {
+ is_initialized = fglrx_get_version(dpy, DefaultScreen(dpy),
+ &fglrx_version_major,
+ &fglrx_version_minor,
+ &fglrx_version_micro);
+ XCloseDisplay(dpy);
+ }
+ }
+
+ return (is_initialized &&
+ ((fglrx_version_major > major) ||
+ (fglrx_version_major == major &&
+ fglrx_version_minor > minor) ||
+ (fglrx_version_major == major &&
+ fglrx_version_minor == minor &&
+ fglrx_version_micro >= micro)));
+}
+
+Bool fglrx_get_device_id(
+ Display *dpy,
+ int screen,
+ unsigned int *deviceID
+)
+{
+ XExtDisplayInfo *info = find_display(dpy);
+ xFGLGetDriverDataReply rep;
+ xFGLGetDriverDataReq *req;
+
+ if (deviceID)
+ *deviceID = 0;
+
+ if(!XextHasExtension(info))
+ return False;
+
+ xFGLCheckExtension(dpy, info, False);
+
+ LockDisplay(dpy);
+ GetReq(FGLGetDriverData, req);
+ req->reqType = info->codes->major_opcode;
+ req->fireglReqType = X_FGLGetDriverData;
+ req->screen = screen;
+ if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ if (deviceID)
+ *deviceID = rep.deviceID;
+ return True;
+}
diff --git a/src/fglrxinfo.h b/src/fglrxinfo.h
new file mode 100644
index 0000000..d654e6b
--- /dev/null
+++ b/src/fglrxinfo.h
@@ -0,0 +1,46 @@
+/*
+ * fglrxinfo.h - FGLRX driver info
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef FGLRXINFO_H
+#define FGLRXINFO_H
+
+#include <X11/Xlib.h>
+
+Bool fglrx_is_dri_capable(Display *dpy, int screen)
+ attribute_hidden;
+
+Bool fglrx_get_version(
+ Display *dpy,
+ int screen,
+ int *ddxDriverMajorVersion,
+ int *ddxDriverMinorVersion,
+ int *ddxDriverPatchVersion
+) attribute_hidden;
+
+int fglrx_check_version(int major, int minor, int micro)
+ attribute_hidden;
+
+Bool fglrx_get_device_id(
+ Display *dpy,
+ int screen,
+ unsigned int *deviceID
+) attribute_hidden;
+
+#endif /* FGLRXINFO_H */
diff --git a/src/object_heap.c b/src/object_heap.c
new file mode 100644
index 0000000..6306179
--- /dev/null
+++ b/src/object_heap.c
@@ -0,0 +1,210 @@
+/*
+ * object_heap.c - Management of VA-API resources
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "object_heap.h"
+
+#define DEBUG 0
+#include "debug.h"
+
+/* This code is:
+ * Copyright (c) 2007 Intel Corporation. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define LAST_FREE -1
+#define ALLOCATED -2
+
+/*
+ * Expands the heap
+ * Return 0 on success, -1 on error
+ */
+static int object_heap_expand( object_heap_p heap )
+{
+ int i;
+ void *new_heap_index;
+ int next_free;
+ int new_heap_size = heap->heap_size + heap->heap_increment;
+
+ new_heap_index = (void *) realloc( heap->heap_index, new_heap_size * heap->object_size );
+ if ( NULL == new_heap_index )
+ {
+ return -1; /* Out of memory */
+ }
+ heap->heap_index = new_heap_index;
+ next_free = heap->next_free;
+ for(i = new_heap_size; i-- > heap->heap_size; )
+ {
+ object_base_p obj = (object_base_p) (heap->heap_index + i * heap->object_size);
+ obj->id = i + heap->id_offset;
+ obj->next_free = next_free;
+ next_free = i;
+ }
+ heap->next_free = next_free;
+ heap->heap_size = new_heap_size;
+ return 0; /* Success */
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+int object_heap_init( object_heap_p heap, int object_size, int id_offset)
+{
+ heap->object_size = object_size;
+ heap->id_offset = id_offset & OBJECT_HEAP_OFFSET_MASK;
+ heap->heap_size = 0;
+ heap->heap_increment = 16;
+ heap->heap_index = NULL;
+ heap->next_free = LAST_FREE;
+ return object_heap_expand(heap);
+}
+
+/*
+ * Allocates an object
+ * Returns the object ID on success, returns -1 on error
+ */
+int object_heap_allocate( object_heap_p heap )
+{
+ object_base_p obj;
+ if ( LAST_FREE == heap->next_free )
+ {
+ if( -1 == object_heap_expand( heap ) )
+ {
+ return -1; /* Out of memory */
+ }
+ }
+ ASSERT( heap->next_free >= 0 );
+
+ obj = (object_base_p) (heap->heap_index + heap->next_free * heap->object_size);
+ heap->next_free = obj->next_free;
+ obj->next_free = ALLOCATED;
+ return obj->id;
+}
+
+/*
+ * Lookup an object by object ID
+ * Returns a pointer to the object on success, returns NULL on error
+ */
+object_base_p object_heap_lookup( object_heap_p heap, int id )
+{
+ object_base_p obj;
+ if ( (id < heap->id_offset) || (id > (heap->heap_size+heap->id_offset)) )
+ {
+ return NULL;
+ }
+ id &= OBJECT_HEAP_ID_MASK;
+ obj = (object_base_p) (heap->heap_index + id * heap->object_size);
+
+ /* Check if the object has in fact been allocated */
+ if ( obj->next_free != ALLOCATED )
+ {
+ return NULL;
+ }
+ return obj;
+}
+
+/*
+ * Iterate over all objects in the heap.
+ * Returns a pointer to the first object on the heap, returns NULL if heap is empty.
+ */
+object_base_p object_heap_first( object_heap_p heap, object_heap_iterator *iter )
+{
+ *iter = -1;
+ return object_heap_next( heap, iter );
+}
+
+/*
+ * Iterate over all objects in the heap.
+ * Returns a pointer to the next object on the heap, returns NULL if heap is empty.
+ */
+object_base_p object_heap_next( object_heap_p heap, object_heap_iterator *iter )
+{
+ object_base_p obj;
+ int i = *iter + 1;
+ while ( i < heap->heap_size)
+ {
+ obj = (object_base_p) (heap->heap_index + i * heap->object_size);
+ if (obj->next_free == ALLOCATED)
+ {
+ *iter = i;
+ return obj;
+ }
+ i++;
+ }
+ *iter = i;
+ return NULL;
+}
+
+
+
+/*
+ * Frees an object
+ */
+void object_heap_free( object_heap_p heap, object_base_p obj )
+{
+ /* Don't complain about NULL pointers */
+ if (NULL != obj)
+ {
+ /* Check if the object has in fact been allocated */
+ ASSERT( obj->next_free == ALLOCATED );
+
+ obj->next_free = heap->next_free;
+ heap->next_free = obj->id & OBJECT_HEAP_ID_MASK;
+ }
+}
+
+/*
+ * Destroys a heap, the heap must be empty.
+ */
+void object_heap_destroy( object_heap_p heap )
+{
+ object_base_p obj;
+ int i;
+ /* Check if heap is empty */
+ for (i = 0; i < heap->heap_size; i++)
+ {
+ /* Check if object is not still allocated */
+ obj = (object_base_p) (heap->heap_index + i * heap->object_size);
+ ASSERT( obj->next_free != ALLOCATED );
+ }
+ free(heap->heap_index);
+ heap->heap_size = 0;
+ heap->heap_index = NULL;
+ heap->next_free = LAST_FREE;
+}
diff --git a/src/object_heap.h b/src/object_heap.h
new file mode 100644
index 0000000..25aefb4
--- /dev/null
+++ b/src/object_heap.h
@@ -0,0 +1,116 @@
+/*
+ * object_heap.h - Management of VA-API resources
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+/* This code is:
+ * Copyright (c) 2007 Intel Corporation. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef VA_OBJECT_HEAP_H
+#define VA_OBJECT_HEAP_H
+
+#define OBJECT_HEAP_OFFSET_MASK 0x7f000000
+#define OBJECT_HEAP_ID_MASK 0x00ffffff
+
+typedef struct object_base *object_base_p;
+typedef struct object_heap *object_heap_p;
+
+struct object_base {
+ int id;
+ int next_free;
+};
+
+struct object_heap {
+ int object_size;
+ int id_offset;
+ void *heap_index;
+ int next_free;
+ int heap_size;
+ int heap_increment;
+};
+
+typedef int object_heap_iterator;
+
+/*
+ * Return 0 on success, -1 on error
+ */
+int object_heap_init(object_heap_p heap, int object_size, int id_offset)
+ attribute_hidden;
+
+/*
+ * Allocates an object
+ * Returns the object ID on success, returns -1 on error
+ */
+int object_heap_allocate(object_heap_p heap)
+ attribute_hidden;
+
+/*
+ * Lookup an allocated object by object ID
+ * Returns a pointer to the object on success, returns NULL on error
+ */
+object_base_p object_heap_lookup(object_heap_p heap, int id)
+ attribute_hidden;
+
+/*
+ * Iterate over all objects in the heap.
+ * Returns a pointer to the first object on the heap, returns NULL if heap is empty.
+ */
+object_base_p object_heap_first(object_heap_p heap, object_heap_iterator *iter)
+ attribute_hidden;
+
+/*
+ * Iterate over all objects in the heap.
+ * Returns a pointer to the next object on the heap, returns NULL if heap is empty.
+ */
+object_base_p object_heap_next(object_heap_p heap, object_heap_iterator *iter)
+ attribute_hidden;
+
+/*
+ * Frees an object
+ */
+void object_heap_free(object_heap_p heap, object_base_p obj)
+ attribute_hidden;
+
+/*
+ * Destroys a heap, the heap must be empty.
+ */
+void object_heap_destroy(object_heap_p heap)
+ attribute_hidden;
+
+#endif /* VA_OBJECT_HEAP_H */
diff --git a/src/shaders/Bicubic.cg b/src/shaders/Bicubic.cg
new file mode 100644
index 0000000..92fe67b
--- /dev/null
+++ b/src/shaders/Bicubic.cg
@@ -0,0 +1,179 @@
+/*
+ * Bicubic.cg - XvBA backend for VA-API (Bicubic filtering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+/*
+ * GPU Gems - Chapter 20. Fast Third-Order Texture Filtering:
+ * <http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter20.html>
+ *
+ * 1
+ * w0(a) = - * (-a^3 + 3*a^2 - 3*a + 1)
+ * 6
+ *
+ * 1
+ * w1(a) = - * (3*a^3 - 6*a^2 + 4)
+ * 6
+ *
+ * 1
+ * w2(a) = - * (-3*a^3 + 3*a^2 + 3*a + 1)
+ * 6
+ *
+ * 1
+ * w3(a) = - * a^3
+ * 6
+ *
+ * w1(x)
+ * g0(x) = w0(x) + w1(x) ; h0(x) = 1 - ------------- + x
+ * w0(x) + w1(x)
+ *
+ * w3(x)
+ * g1(x) = w2(x) + w3(x) ; h1(x) = 1 + ------------- - x
+ * w2(x) + w3(x)
+ */
+
+#ifdef USE_TEXTURE_RECTANGLE
+#define Sampler samplerRECT
+#define loadTexture texRECT
+#else
+#define Sampler sampler2D
+#define loadTexture tex2D
+#endif
+
+float2 unpackCoord(float2 coord, float4 textureSize)
+{
+#ifndef USE_TEXTURE_RECTANGLE
+ coord *= textureSize.xy;
+#endif
+ return coord;
+}
+
+float2 packCoord(float2 coord, float4 textureSize)
+{
+#ifndef USE_TEXTURE_RECTANGLE
+ coord *= textureSize.zw;
+#endif
+ return coord;
+}
+
+struct Bicubic_input {
+ float2 coord : TEXCOORD0;
+ Sampler tex : TEXUNIT0;
+#ifdef USE_TEXTURE_FLOAT
+ sampler1D tex_hg : TEXUNIT1;
+#endif
+};
+
+struct Bicubic_output {
+ float4 color : COLOR;
+};
+
+#ifndef USE_TEXTURE_FLOAT
+float2 e2(float2 a)
+{
+ return a * a;
+}
+
+float2 e3(float2 a)
+{
+ return e2(a) * a;
+}
+
+float2 w0(float2 a)
+{
+ return (1.0f/6.0f) * (-e3(a) + 3.0f*e2(a) - 3.0f*a + 1.0f);
+}
+
+float2 w1(float2 a)
+{
+ return (1.0f/6.0f) * (3.0f*e3(a) - 6.0f*e2(a) + 4.0f);
+}
+
+float2 w2(float2 a)
+{
+ return (1.0f/6.0f) * (-3.0f*e3(a) + 3.0f*e2(a) + 3.0f*a + 1.0f);
+}
+
+float2 w3(float2 a)
+{
+ return (1.0f/6.0f) * (e3(a));
+}
+
+float2 g0(float2 x)
+{
+ return w0(x) + w1(x);
+}
+
+float2 h0(float2 x)
+{
+ //return 1.0f - w1(x) / (w0(x) + w1(x)) + x;
+ return -1.0f + w1(x) / g0(x) + 0.5f;
+}
+
+float2 g1(float2 x)
+{
+ return w2(x) + w3(x);
+}
+
+float2 h1(float2 x)
+{
+ //return 1.0f + w3(x) / (w2(x) + w3(x)) - x;
+ return 1.0f + w3(x) / g1(x) + 0.5f;
+}
+#endif
+
+float4 cubicTex2D(Bicubic_input IN, float4 textureSize)
+{
+ const float2 coord = unpackCoord(IN.coord, textureSize) - 0.5f;
+ const float2 int_coord = floor(coord);
+#ifdef USE_TEXTURE_FLOAT
+ const float4 hg_x = tex1D(IN.tex_hg, coord.x);
+ const float4 hg_y = tex1D(IN.tex_hg, coord.y);
+ const float2 g[2] = { float2(hg_x.z, hg_y.z), float2(hg_x.w, hg_y.w) };
+ const float2 h[2] = { float2(hg_x.x, hg_y.x)+int_coord, float2(hg_x.y, hg_y.y)+int_coord };
+#else
+ const float2 frc_coord = coord - int_coord;
+ const float2 g[2] = { g0(frc_coord), g1(frc_coord) };
+ const float2 h[2] = { h0(frc_coord)+int_coord, h1(frc_coord)+int_coord };
+#endif
+
+ const float2 coord00 = packCoord(float2(h[0].x, h[0].y), textureSize);
+ const float2 coord10 = packCoord(float2(h[1].x, h[0].y), textureSize);
+ const float2 coord01 = packCoord(float2(h[0].x, h[1].y), textureSize);
+ const float2 coord11 = packCoord(float2(h[1].x, h[1].y), textureSize);
+
+ float4 tex00 = loadTexture(IN.tex, coord00);
+ float4 tex10 = loadTexture(IN.tex, coord10);
+ float4 tex01 = loadTexture(IN.tex, coord01);
+ float4 tex11 = loadTexture(IN.tex, coord11);
+
+ tex00 = g[0].y * tex00 + g[1].y * tex01;
+ tex10 = g[0].y * tex10 + g[1].y * tex11;
+ return (g[0].x * tex00 + g[1].x * tex10);
+}
+
+Bicubic_output Bicubic_main(
+ Bicubic_input IN,
+ uniform float4 textureSize
+)
+{
+ Bicubic_output OUT;
+
+ OUT.color = cubicTex2D(IN, textureSize);
+ return OUT;
+}
diff --git a/src/shaders/Bicubic.pso b/src/shaders/Bicubic.pso
new file mode 100644
index 0000000..35d0693
--- /dev/null
+++ b/src/shaders/Bicubic.pso
@@ -0,0 +1,74 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: Bicubic.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Bicubic_main
+#semantic Bicubic_main.IN
+#semantic Bicubic_main.textureSize
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 Bicubic_main.color : $vout.COLOR : COL : -1 : 1
+#const c[1] = 0.5 3 1 6
+#const c[2] = 4 0.16666667 -0.5 0
+#const c[3] = -3 1.5 0
+PARAM c[4] = { program.local[0],
+ { 0.5, 3, 1, 6 },
+ { 4, 0.16666667, -0.5, 0 },
+ { -3, 1.5, 0 } };
+TEMP R0;
+TEMP R1;
+TEMP R2;
+TEMP R3;
+MUL R0.xy, fragment.texcoord[0], c[0];
+ADD R0.xy, R0, -c[1].x;
+FLR R1.xy, R0;
+ADD R2.zw, R0.xyxy, -R1.xyxy;
+MUL R3.xy, R2.zwzw, R2.zwzw;
+MUL R2.xy, R2.zwzw, R3;
+MUL R0.xy, R3, c[1].y;
+MAD R0.zw, R2.xyxy, c[3].x, R0.xyxy;
+MAD R0.xy, R2.zwzw, -R3, R0;
+MAD R0.zw, R2, c[1].y, R0;
+MUL R1.zw, -R3.xyxy, c[1].w;
+MAD R0.xy, -R2.zwzw, c[1].y, R0;
+ADD R0.zw, R0, c[1].z;
+MAD R0.zw, R2, R3.xyxy, R0;
+MAD R1.zw, R2.xyxy, c[1].y, R1;
+MUL R0.zw, R0, c[2].y;
+ADD R0.xy, R0, c[1].z;
+ADD R2.zw, R1, c[2].x;
+ADD R1.zw, R0.xyxy, R2;
+RCP R0.y, R0.w;
+RCP R0.x, R0.z;
+MUL R0.xy, R2, R0;
+MUL R2.xy, R1.zwzw, c[2].y;
+MAD R1.zw, R0.xyxy, c[2].y, R1.xyxy;
+RCP R0.y, R2.y;
+RCP R0.x, R2.x;
+MUL R0.xy, R2.zwzw, R0;
+MAD R0.xy, R0, c[2].y, R1;
+ADD R2.zw, R1, c[3].y;
+MUL R1.xy, R2.zwzw, c[0].zwzw;
+TEX R3, R1, texture[0], 2D;
+ADD R0.xy, R0, c[2].z;
+MOV R1.x, R2.z;
+MOV R1.y, R0;
+MOV R2.z, R0.x;
+MUL R1.xy, R1, c[0].zwzw;
+MUL R3, R0.w, R3;
+TEX R1, R1, texture[0], 2D;
+MAD R1, R2.y, R1, R3;
+MUL R2.zw, R2, c[0];
+TEX R3, R2.zwzw, texture[0], 2D;
+MUL R1, R0.z, R1;
+MUL R3, R3, R0.w;
+MUL R0.xy, R0, c[0].zwzw;
+TEX R0, R0, texture[0], 2D;
+MAD R0, R0, R2.y, R3;
+MAD result.color, R0, R2.x, R1;
+END
+# 47 instructions, 4 R-regs
diff --git a/src/shaders/Bicubic_FLOAT.pso b/src/shaders/Bicubic_FLOAT.pso
new file mode 100644
index 0000000..1e083bc
--- /dev/null
+++ b/src/shaders/Bicubic_FLOAT.pso
@@ -0,0 +1,53 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1 -DUSE_TEXTURE_FLOAT
+# source file: Bicubic.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Bicubic_main
+#semantic Bicubic_main.IN
+#semantic Bicubic_main.textureSize
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var sampler1D IN.tex_hg : TEXUNIT1 : texunit 1 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 Bicubic_main.color : $vout.COLOR : COL : -1 : 1
+#const c[1] = 0.5
+PARAM c[2] = { program.local[0],
+ { 0.5 } };
+TEMP R0;
+TEMP R1;
+TEMP R2;
+TEMP R3;
+TEMP R4;
+MUL R0.xy, fragment.texcoord[0], c[0];
+ADD R0.zw, R0.xyxy, -c[1].x;
+TEX R3, R0.w, texture[1], 1D;
+TEX R4, R0.z, texture[1], 1D;
+MOV R0.y, R3;
+FLR R0.zw, R0;
+MOV R0.x, R4.y;
+ADD R1.zw, R0, R0.xyxy;
+MUL R0.xy, R1.zwzw, c[0].zwzw;
+MOV R2.x, R1.z;
+MOV R1.y, R3.x;
+MOV R1.x, R4;
+ADD R1.xy, R1, R0.zwzw;
+MOV R2.y, R1;
+MOV R1.z, R1.x;
+MUL R3.xy, R2, c[0].zwzw;
+TEX R0, R0, texture[0], 2D;
+MUL R2, R3.w, R0;
+TEX R0, R3, texture[0], 2D;
+MAD R0, R3.z, R0, R2;
+MUL R1.zw, R1, c[0];
+MUL R2, R4.w, R0;
+TEX R0, R1.zwzw, texture[0], 2D;
+MUL R3.xy, R1, c[0].zwzw;
+MUL R1, R3.w, R0;
+TEX R0, R3, texture[0], 2D;
+MAD R0, R3.z, R0, R1;
+MAD result.color, R4.z, R0, R2;
+END
+# 28 instructions, 5 R-regs
diff --git a/src/shaders/Evergreen.cg b/src/shaders/Evergreen.cg
new file mode 100644
index 0000000..9f89a46
--- /dev/null
+++ b/src/shaders/Evergreen.cg
@@ -0,0 +1,65 @@
+/*
+ * Evergreen.cg - XvBA backend for VA-API (workaround for Evergreen rendering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+struct Evergreen_input {
+ float2 coord : TEXCOORD0;
+ sampler2D tex : TEXUNIT0;
+};
+
+struct Evergreen_output {
+ float4 color : COLOR;
+};
+
+/*
+ * params.xy = 1/(2*n);
+ * params.zw = (n);
+ */
+float2 swap_l(float2 v, float4 params)
+{
+ return 2.0 * params.zw * floor(v * params.xy);
+}
+
+float2 swap_r(float2 v, float4 params)
+{
+ return (v + params.zw) - 2.0 * params.zw * floor((v + params.zw) * params.xy);
+}
+
+float2 swap(float2 v, float4 params)
+{
+ return swap_l(v, params) + swap_r(v, params);
+}
+
+Evergreen_output Evergreen_main(
+ Evergreen_input IN,
+ uniform float4 textureSize,
+ uniform float4 mix_params[MIX_PARAMS]
+)
+{
+ Evergreen_output OUT;
+
+ float2 coord = IN.coord;
+ coord *= textureSize.xy;
+ for (int i = 0; i < MIX_PARAMS; i++)
+ coord = swap(coord, mix_params[i]);
+ coord *= textureSize.zw;
+
+ OUT.color = tex2D(IN.tex, coord);
+ return OUT;
+}
diff --git a/src/shaders/Evergreen_mix_1.cg b/src/shaders/Evergreen_mix_1.cg
new file mode 100644
index 0000000..23d688c
--- /dev/null
+++ b/src/shaders/Evergreen_mix_1.cg
@@ -0,0 +1,22 @@
+/*
+ * Evergreen.cg - XvBA backend for VA-API (workaround for Evergreen rendering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define MIX_PARAMS 1
+#include "Evergreen.cg"
diff --git a/src/shaders/Evergreen_mix_1.pso b/src/shaders/Evergreen_mix_1.pso
new file mode 100644
index 0000000..4fc472b
--- /dev/null
+++ b/src/shaders/Evergreen_mix_1.pso
@@ -0,0 +1,35 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: Evergreen_mix_1.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Evergreen_main
+#semantic Evergreen_main.IN
+#semantic Evergreen_main.textureSize
+#semantic Evergreen_main.mix_params
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 mix_params[0] : : c[1] : 2 : 1
+#var float4 Evergreen_main.color : $vout.COLOR : COL : -1 : 1
+#const c[2] = 2
+PARAM c[3] = { program.local[0..1],
+ { 2 } };
+TEMP R0;
+TEMP R1;
+MUL R0.zw, fragment.texcoord[0].xyxy, c[0].xyxy;
+ADD R0.xy, R0.zwzw, c[1].zwzw;
+MUL R1.xy, R0, c[1];
+FLR R1.xy, R1;
+MUL R0.zw, R0, c[1].xyxy;
+MUL R1.xy, R1, c[1].zwzw;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[2].x, R0;
+MUL R0.zw, R0, c[1];
+MAD R0.xy, R0.zwzw, c[2].x, R0;
+MUL R0.xy, R0, c[0].zwzw;
+TEX result.color, R0, texture[0], 2D;
+END
+# 12 instructions, 2 R-regs
diff --git a/src/shaders/Evergreen_mix_2.cg b/src/shaders/Evergreen_mix_2.cg
new file mode 100644
index 0000000..48183ee
--- /dev/null
+++ b/src/shaders/Evergreen_mix_2.cg
@@ -0,0 +1,22 @@
+/*
+ * Evergreen.cg - XvBA backend for VA-API (workaround for Evergreen rendering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define MIX_PARAMS 2
+#include "Evergreen.cg"
diff --git a/src/shaders/Evergreen_mix_2.pso b/src/shaders/Evergreen_mix_2.pso
new file mode 100644
index 0000000..9bc5dcc
--- /dev/null
+++ b/src/shaders/Evergreen_mix_2.pso
@@ -0,0 +1,45 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: Evergreen_mix_2.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Evergreen_main
+#semantic Evergreen_main.IN
+#semantic Evergreen_main.textureSize
+#semantic Evergreen_main.mix_params
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 mix_params[0] : : c[1] : 2 : 1
+#var float4 mix_params[1] : : c[2] : 2 : 1
+#var float4 Evergreen_main.color : $vout.COLOR : COL : -1 : 1
+#const c[3] = 2
+PARAM c[4] = { program.local[0..2],
+ { 2 } };
+TEMP R0;
+TEMP R1;
+MUL R0.zw, fragment.texcoord[0].xyxy, c[0].xyxy;
+ADD R0.xy, R0.zwzw, c[1].zwzw;
+MUL R1.xy, R0, c[1];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[1].zwzw;
+MUL R0.zw, R0, c[1].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[3].x, R0;
+MUL R0.zw, R0, c[1];
+MAD R0.zw, R0, c[3].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[2].zwzw;
+MUL R1.xy, R0, c[2];
+FLR R1.xy, R1;
+MUL R0.zw, R0, c[2].xyxy;
+MUL R1.xy, R1, c[2].zwzw;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[3].x, R0;
+MUL R0.zw, R0, c[2];
+MAD R0.xy, R0.zwzw, c[3].x, R0;
+MUL R0.xy, R0, c[0].zwzw;
+TEX result.color, R0, texture[0], 2D;
+END
+# 21 instructions, 2 R-regs
diff --git a/src/shaders/Evergreen_mix_3.cg b/src/shaders/Evergreen_mix_3.cg
new file mode 100644
index 0000000..7626301
--- /dev/null
+++ b/src/shaders/Evergreen_mix_3.cg
@@ -0,0 +1,22 @@
+/*
+ * Evergreen.cg - XvBA backend for VA-API (workaround for Evergreen rendering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define MIX_PARAMS 3
+#include "Evergreen.cg"
diff --git a/src/shaders/Evergreen_mix_3.pso b/src/shaders/Evergreen_mix_3.pso
new file mode 100644
index 0000000..e165bd5
--- /dev/null
+++ b/src/shaders/Evergreen_mix_3.pso
@@ -0,0 +1,55 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: Evergreen_mix_3.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Evergreen_main
+#semantic Evergreen_main.IN
+#semantic Evergreen_main.textureSize
+#semantic Evergreen_main.mix_params
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 mix_params[0] : : c[1] : 2 : 1
+#var float4 mix_params[1] : : c[2] : 2 : 1
+#var float4 mix_params[2] : : c[3] : 2 : 1
+#var float4 Evergreen_main.color : $vout.COLOR : COL : -1 : 1
+#const c[4] = 2
+PARAM c[5] = { program.local[0..3],
+ { 2 } };
+TEMP R0;
+TEMP R1;
+MUL R0.zw, fragment.texcoord[0].xyxy, c[0].xyxy;
+ADD R0.xy, R0.zwzw, c[1].zwzw;
+MUL R1.xy, R0, c[1];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[1].zwzw;
+MUL R0.zw, R0, c[1].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[4].x, R0;
+MUL R0.zw, R0, c[1];
+MAD R0.zw, R0, c[4].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[2].zwzw;
+MUL R1.xy, R0, c[2];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[2].zwzw;
+MUL R0.zw, R0, c[2].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[4].x, R0;
+MUL R0.zw, R0, c[2];
+MAD R0.zw, R0, c[4].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[3].zwzw;
+MUL R1.xy, R0, c[3];
+FLR R1.xy, R1;
+MUL R0.zw, R0, c[3].xyxy;
+MUL R1.xy, R1, c[3].zwzw;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[4].x, R0;
+MUL R0.zw, R0, c[3];
+MAD R0.xy, R0.zwzw, c[4].x, R0;
+MUL R0.xy, R0, c[0].zwzw;
+TEX result.color, R0, texture[0], 2D;
+END
+# 30 instructions, 2 R-regs
diff --git a/src/shaders/Evergreen_mix_4.cg b/src/shaders/Evergreen_mix_4.cg
new file mode 100644
index 0000000..f584ab4
--- /dev/null
+++ b/src/shaders/Evergreen_mix_4.cg
@@ -0,0 +1,22 @@
+/*
+ * Evergreen.cg - XvBA backend for VA-API (workaround for Evergreen rendering)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define MIX_PARAMS 4
+#include "Evergreen.cg"
diff --git a/src/shaders/Evergreen_mix_4.pso b/src/shaders/Evergreen_mix_4.pso
new file mode 100644
index 0000000..bd78fb1
--- /dev/null
+++ b/src/shaders/Evergreen_mix_4.pso
@@ -0,0 +1,65 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: Evergreen_mix_4.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program Evergreen_main
+#semantic Evergreen_main.IN
+#semantic Evergreen_main.textureSize
+#semantic Evergreen_main.mix_params
+#var float2 IN.coord : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4 textureSize : : c[0] : 1 : 1
+#var float4 mix_params[0] : : c[1] : 2 : 1
+#var float4 mix_params[1] : : c[2] : 2 : 1
+#var float4 mix_params[2] : : c[3] : 2 : 1
+#var float4 mix_params[3] : : c[4] : 2 : 1
+#var float4 Evergreen_main.color : $vout.COLOR : COL : -1 : 1
+#const c[5] = 2
+PARAM c[6] = { program.local[0..4],
+ { 2 } };
+TEMP R0;
+TEMP R1;
+MUL R0.zw, fragment.texcoord[0].xyxy, c[0].xyxy;
+ADD R0.xy, R0.zwzw, c[1].zwzw;
+MUL R1.xy, R0, c[1];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[1].zwzw;
+MUL R0.zw, R0, c[1].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[5].x, R0;
+MUL R0.zw, R0, c[1];
+MAD R0.zw, R0, c[5].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[2].zwzw;
+MUL R1.xy, R0, c[2];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[2].zwzw;
+MUL R0.zw, R0, c[2].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[5].x, R0;
+MUL R0.zw, R0, c[2];
+MAD R0.zw, R0, c[5].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[3].zwzw;
+MUL R1.xy, R0, c[3];
+FLR R1.xy, R1;
+MUL R1.xy, R1, c[3].zwzw;
+MUL R0.zw, R0, c[3].xyxy;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[5].x, R0;
+MUL R0.zw, R0, c[3];
+MAD R0.zw, R0, c[5].x, R0.xyxy;
+ADD R0.xy, R0.zwzw, c[4].zwzw;
+MUL R1.xy, R0, c[4];
+FLR R1.xy, R1;
+MUL R0.zw, R0, c[4].xyxy;
+MUL R1.xy, R1, c[4].zwzw;
+FLR R0.zw, R0;
+MAD R0.xy, -R1, c[5].x, R0;
+MUL R0.zw, R0, c[4];
+MAD R0.xy, R0.zwzw, c[5].x, R0;
+MUL R0.xy, R0, c[0].zwzw;
+TEX result.color, R0, texture[0], 2D;
+END
+# 39 instructions, 2 R-regs
diff --git a/src/shaders/Makefile.am b/src/shaders/Makefile.am
new file mode 100644
index 0000000..3408283
--- /dev/null
+++ b/src/shaders/Makefile.am
@@ -0,0 +1,46 @@
+shaders_c = \
+ Bicubic.cg \
+ NV12.cg \
+ YV12.cg \
+ ProcAmp.cg \
+ $(NULL)
+
+shaders_c += Evergreen_mix_1.cg
+shaders_c += Evergreen_mix_2.cg
+shaders_c += Evergreen_mix_3.cg
+shaders_c += Evergreen_mix_4.cg
+
+shaders_o = $(shaders_c:%.cg=%.pso)
+shaders_o += Bicubic_FLOAT.pso
+
+shaders_h = $(shaders_o:%.pso=%.h)
+
+BUILT_SOURCES =
+CLEANFILES =
+EXTRA_DIST = pso2h.py Evergreen.cg $(shaders_c) $(shaders_o) $(shaders_h)
+
+# Only add those targets if python is available
+if HAVE_PYTHON
+BUILT_SOURCES += $(shaders_h)
+CLEANFILES += $(shaders_h)
+
+%.h: %.pso pso2h.py
+ $(PYTHON) pso2h.py -n $*_fp -o $@ $<
+endif
+
+# Only add those targets if the Cg compiler is available
+if HAVE_CGC
+BUILT_SOURCES += $(shaders_o)
+
+Evergreen_%.pso: Evergreen_%.cg Evergreen.cg
+ $(CGC) -entry Evergreen_main -profile arbfp1 -o $@ $<
+
+%.pso: %.cg
+ $(CGC) -entry $*_main -profile arbfp1 -o $@ $<
+
+%_FLOAT.pso: %.cg
+ $(CGC) -entry $*_main -profile arbfp1 -o $@ -DUSE_TEXTURE_FLOAT $<
+endif
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/shaders/NV12.cg b/src/shaders/NV12.cg
new file mode 100644
index 0000000..47cba47
--- /dev/null
+++ b/src/shaders/NV12.cg
@@ -0,0 +1,46 @@
+/*
+ * NV12.cg - XvBA backend for VA-API (NV12 -> RGB colorspace conversion)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+struct NV12_input {
+ float2 Y : TEXCOORD0;
+ sampler2D Y_tex : TEXUNIT0;
+ sampler2D UV_tex : TEXUNIT1;
+};
+
+struct NV12_output {
+ float4 color : COLOR;
+};
+
+NV12_output NV12_main(NV12_input IN)
+{
+ NV12_output OUT;
+
+ /* See YV12.cg for explanations on the color conversion matrix */
+ float y = 1.16438356 * (tex2D(IN.Y_tex, IN.Y).x - 0.0625);
+ float u = tex2D(IN.UV_tex, IN.Y).x - 0.5;
+ float v = tex2D(IN.UV_tex, IN.Y).w - 0.5;
+
+ OUT.color.r = y + 1.59602678 * v;
+ OUT.color.g = y - 0.39176229 * u - 0.81296764 * v;
+ OUT.color.b = y + 2.01723214 * u;
+ OUT.color.a = 1.0;
+
+ return OUT;
+}
diff --git a/src/shaders/NV12.pso b/src/shaders/NV12.pso
new file mode 100644
index 0000000..b747ae2
--- /dev/null
+++ b/src/shaders/NV12.pso
@@ -0,0 +1,31 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: NV12.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program NV12_main
+#semantic NV12_main.IN
+#var float2 IN.Y : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.Y_tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var sampler2D IN.UV_tex : TEXUNIT1 : texunit 1 : 0 : 1
+#var float4 NV12_main.color : $vout.COLOR : COL : -1 : 1
+#const c[0] = 1 1.1643835 0.0625 2.0172322
+#const c[1] = 0.5 0.39176229 0.81296766 1.5960268
+PARAM c[2] = { { 1, 1.1643835, 0.0625, 2.0172322 },
+ { 0.5, 0.39176229, 0.81296766, 1.5960268 } };
+TEMP R0;
+TEX R0.x, fragment.texcoord[0], texture[0], 2D;
+ADD R0.y, R0.x, -c[0].z;
+TEX R0.xw, fragment.texcoord[0], texture[1], 2D;
+MUL R0.y, R0, c[0];
+ADD R0.x, R0, -c[1];
+ADD R0.w, R0, -c[1].x;
+MAD R0.z, -R0.x, c[1].y, R0.y;
+MAD result.color.y, -R0.w, c[1].z, R0.z;
+MAD result.color.z, R0.x, c[0].w, R0.y;
+MAD result.color.x, R0.w, c[1].w, R0.y;
+MOV result.color.w, c[0].x;
+END
+# 11 instructions, 1 R-regs
diff --git a/src/shaders/ProcAmp.cg b/src/shaders/ProcAmp.cg
new file mode 100644
index 0000000..99383b1
--- /dev/null
+++ b/src/shaders/ProcAmp.cg
@@ -0,0 +1,49 @@
+/*
+ * ProcAmp.cg - XvBA backend for VA-API (ProcAmp adjustments)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define USE_TEXTURE 1
+
+struct ProcAmp_input {
+#ifdef USE_TEXTURE
+ float2 coords : TEXCOORD0;
+ sampler2D texture : TEXUNIT0;
+#else
+ float4 color : COLOR;
+#endif
+};
+
+struct ProcAmp_output {
+ float4 color : COLOR;
+};
+
+ProcAmp_output ProcAmp_main(ProcAmp_input IN, uniform float4x4 color_matrix)
+{
+ ProcAmp_output OUT;
+#ifdef USE_TEXTURE
+ const float4 color = tex2D(IN.texture, IN.coords);
+#else
+ const float4 color = IN.color;
+#endif
+
+ OUT.color.rgb = mul(color_matrix, color).rgb;
+ OUT.color.a = color.a;
+
+ return OUT;
+}
diff --git a/src/shaders/ProcAmp.pso b/src/shaders/ProcAmp.pso
new file mode 100644
index 0000000..9bb6573
--- /dev/null
+++ b/src/shaders/ProcAmp.pso
@@ -0,0 +1,23 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: ProcAmp.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program ProcAmp_main
+#semantic ProcAmp_main.IN
+#semantic ProcAmp_main.color_matrix
+#var float2 IN.coords : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.texture : TEXUNIT0 : texunit 0 : 0 : 1
+#var float4x4 color_matrix : : c[0], 4 : 1 : 1
+#var float4 ProcAmp_main.color : $vout.COLOR : COL : -1 : 1
+PARAM c[4] = { program.local[0..3] };
+TEMP R0;
+TEX R0, fragment.texcoord[0], texture[0], 2D;
+MOV result.color.w, R0;
+DP4 result.color.z, R0, c[2];
+DP4 result.color.y, R0, c[1];
+DP4 result.color.x, R0, c[0];
+END
+# 5 instructions, 1 R-regs
diff --git a/src/shaders/YV12.cg b/src/shaders/YV12.cg
new file mode 100644
index 0000000..87fec78
--- /dev/null
+++ b/src/shaders/YV12.cg
@@ -0,0 +1,76 @@
+/*
+ * YV12.cg - XvBA backend for VA-API (YV12 -> RGB colorspace conversion)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+/*
+ * For 8-bit per sample:
+ *
+ * 219 219 219
+ * Y = 16 + --- * Kr * R + --- * (1 - Kr - Kb) * G + --- * Kb * B
+ * 255 255 255
+ *
+ * 112 Kr 112 1 - (Kr + Kb) 112
+ * U = 128 - --- * ------ * R - --- * ------------- * G + --- * B
+ * 255 1 - Kb 255 1 - Kb 255
+ *
+ * 112 112 1 - (Kr + Kb) 112 Kb
+ * V = 128 + --- * R - --- * ------------- * G - --- * ------ * B
+ * 255 255 1 - Kr 255 1 - Kr
+ *
+ * Constants for SDTV (ITU-R BT.601):
+ * Kb = 0.114
+ * Kr = 0.299
+ *
+ * Constants for HDTV (ITU-R BT.709):
+ * Kb = 0.0722
+ * Kr = 0.2126
+ *
+ * Matrix generation with xcas:
+ * inverse([
+ * [ Kr , 1-(Kr+Kb) , Kb ]*219/255,
+ * [ -Kr/(1-Kb) , -(1-(Kr+Kb))/(1-Kb) , 1 ]*112/255,
+ * [ 1 , -(1-(Kr+Kb))/(1-Kr) , -Kb/(1-Kr) ]*112/255])
+ */
+
+struct YV12_input {
+ float2 Y : TEXCOORD0;
+ sampler2D Y_tex : TEXUNIT0;
+ sampler2D U_tex : TEXUNIT2;
+ sampler2D V_tex : TEXUNIT1;
+};
+
+struct YV12_output {
+ float4 color : COLOR;
+};
+
+YV12_output YV12_main(YV12_input IN)
+{
+ YV12_output OUT;
+
+ float y = 1.16438356 * (tex2D(IN.Y_tex, IN.Y).g - 0.0625);
+ float u = tex2D(IN.U_tex, IN.Y).g - 0.5;
+ float v = tex2D(IN.V_tex, IN.Y).g - 0.5;
+
+ OUT.color.r = y + 1.59602678 * v;
+ OUT.color.g = y - 0.39176229 * u - 0.81296764 * v;
+ OUT.color.b = y + 2.01723214 * u;
+ OUT.color.a = 1.0;
+
+ return OUT;
+}
diff --git a/src/shaders/YV12.pso b/src/shaders/YV12.pso
new file mode 100644
index 0000000..f3a896b
--- /dev/null
+++ b/src/shaders/YV12.pso
@@ -0,0 +1,33 @@
+!!ARBfp1.0
+# cgc version 3.0.0007, build date Jul 22 2010
+# command line args: -profile arbfp1
+# source file: YV12.cg
+#vendor NVIDIA Corporation
+#version 3.0.0.07
+#profile arbfp1
+#program YV12_main
+#semantic YV12_main.IN
+#var float2 IN.Y : $vin.TEXCOORD0 : TEX0 : 0 : 1
+#var sampler2D IN.Y_tex : TEXUNIT0 : texunit 0 : 0 : 1
+#var sampler2D IN.U_tex : TEXUNIT2 : texunit 2 : 0 : 1
+#var sampler2D IN.V_tex : TEXUNIT1 : texunit 1 : 0 : 1
+#var float4 YV12_main.color : $vout.COLOR : COL : -1 : 1
+#const c[0] = 1 1.1643835 0.0625 2.0172322
+#const c[1] = 0.5 0.39176229 0.81296766 1.5960268
+PARAM c[2] = { { 1, 1.1643835, 0.0625, 2.0172322 },
+ { 0.5, 0.39176229, 0.81296766, 1.5960268 } };
+TEMP R0;
+TEX R0.y, fragment.texcoord[0], texture[0], 2D;
+ADD R0.x, R0.y, -c[0].z;
+TEX R0.y, fragment.texcoord[0], texture[2], 2D;
+ADD R0.z, R0.y, -c[1].x;
+MUL R0.x, R0, c[0].y;
+MAD result.color.z, R0, c[0].w, R0.x;
+TEX R0.y, fragment.texcoord[0], texture[1], 2D;
+ADD R0.y, R0, -c[1].x;
+MAD R0.z, -R0, c[1].y, R0.x;
+MAD result.color.y, -R0, c[1].z, R0.z;
+MAD result.color.x, R0.y, c[1].w, R0;
+MOV result.color.w, c[0].x;
+END
+# 12 instructions, 1 R-regs
diff --git a/src/shaders/pso2h.py b/src/shaders/pso2h.py
new file mode 100755
index 0000000..4f30160
--- /dev/null
+++ b/src/shaders/pso2h.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python
+"""pso2h
+
+A small python script to generated header files from compiled ARBfp1.0 shaders
+
+Usage: ./pso2h-runtime [options] file.pso
+
+Options:
+ -o, --output header file name
+ -n, --name name of the shader
+ -h, --help display this help
+ -v, --verbose verbose output
+
+ file.pso compiled shader"""
+
+import sys, os, string, getopt
+
+__author__ = "Damien Lespiau <damien.lespiau@intel.com>"
+__version__ = "0.1"
+__date__ = "20090426"
+__copyright__ = "Copyright (c) 2009 Intel Corporation"
+__license__ = "GPL v2"
+
+_verbose = 0
+
+_template = """/*
+ * This file was generated by pso2h.
+ */
+
+#ifndef %s
+#define %s
+
+/*
+ * This define is the size of the shader in bytes. More precisely it's the
+ * sum of strlen() of every string in the array.
+ */
+#define %s %d
+
+static const char *%s[] =
+{
+%s NULL
+};
+
+#endif /* %s */
+"""
+
+def define(format, filename):
+ path, file = os.path.split(filename)
+ return format % string.upper(file.replace('.', '_').capitalize())
+
+class PSO:
+ def __init__(self, filename=None, name=None):
+ self.filename = filename
+ self.name = name
+
+ def write_header(self, filename):
+ file = open(self.filename)
+ header = open(filename, "w")
+ __HEADER__ = define("SHADERS_%s", filename)
+ SIZE = define("%s_SZ", self.name)
+ body = ""
+ size = 0;
+
+ for line in file:
+ # skip comments
+ if line.startswith('#'):
+ continue
+ line = string.strip(line)
+ line += '\\n'
+ size += len(line) - 1;
+ body += " \"%s\",\n" % line
+
+ header.write(_template % (__HEADER__,
+ __HEADER__,
+ SIZE,
+ size,
+ self.name,
+ body,
+ __HEADER__))
+
+def usage():
+ print __doc__
+
+def main(argv):
+ opt_shader = None
+ opt_header = None
+ opt_name = None
+ try:
+ opts, args = getopt.getopt(argv, "hvo:n:", \
+ ["help", "verbose", "--ouput=", "--name="])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(1)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif opt in ("-v", "--verbose"):
+ global _verbose
+ _verbose = 1
+ elif opt in ("-o", "-output"):
+ opt_header = arg
+ elif opt in ("-n", "-name"):
+ opt_name = arg
+ if args:
+ opt_shader = "".join(args)
+
+ #input validation
+ if not opt_shader:
+ print "error: you must supply a shader file.\n"
+ usage()
+ sys.exit(1)
+ if not os.access(opt_shader, os.F_OK):
+ print opt_shader + ": file not found"
+ sys.exit(1)
+ file, ext = os.path.splitext(opt_shader)
+ if not opt_header:
+ opt_header = file + ".h"
+ if not opt_name:
+ path, file = os.path.split(file)
+ opt_name = file
+
+ pso = PSO(opt_shader, opt_name)
+ pso.write_header(opt_header)
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
+
diff --git a/src/sysdeps.h b/src/sysdeps.h
new file mode 100644
index 0000000..2031f31
--- /dev/null
+++ b/src/sysdeps.h
@@ -0,0 +1,68 @@
+/*
+ * sysdeps.h - System dependent definitions
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef SYSDEPS_H
+#define SYSDEPS_H
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+// Helper macros
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#undef ARRAY_ELEMS
+#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#define UINT_TO_POINTER(i) ((void *)(uintptr_t)(i))
+#define POINTER_TO_UINT(p) ((uintptr_t)(void *)(p))
+
+#ifdef HAVE_VISIBILITY_ATTRIBUTE
+# define attribute_hidden __attribute__((__visibility__("hidden")))
+#else
+# define attribute_hidden
+#endif
+
+#undef ASSERT
+#if USE_DEBUG
+# define ASSERT assert
+#else
+# define ASSERT(expr) do { \
+ if (!(expr)) { \
+ xvba_error_message("Assertion failed in file %s at line %d\n", \
+ __FILE__, __LINE__); \
+ abort(); \
+ } \
+} while (0)
+#endif
+
+/* Check for a specific version of XvBA, or newer */
+#ifndef XVBA_CHECK_VERSION
+#define XVBA_CHECK_VERSION(major, minor) \
+ (XVBA_VERSION_MAJOR > (major) || \
+ (XVBA_VERSION_MAJOR == (major) && XVBA_VERSION_MINOR >= (minor)))
+#endif
+
+#endif /* SYSDEPS_H */
diff --git a/src/uarray.c b/src/uarray.c
new file mode 100644
index 0000000..d2232cd
--- /dev/null
+++ b/src/uarray.c
@@ -0,0 +1,144 @@
+/*
+ * uarray.c - Array utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "uarray.h"
+
+typedef struct _UArrayPrivate UArrayPrivate;
+struct _UArrayPrivate {
+ UArray array;
+ unsigned int count_max;
+ unsigned int element_size;
+};
+
+#define elem_offset(p,i) ((char *)(p)->array.data + (i) * (p)->element_size)
+#define elem_size(p,n) ((n) * (p)->element_size)
+
+UArray *array_new(unsigned int element_size)
+{
+ UArrayPrivate *priv = malloc(sizeof(*priv));
+ if (!priv)
+ return NULL;
+
+ priv->array.data = NULL;
+ priv->array.count = 0;
+ priv->count_max = 0;
+ priv->element_size = element_size;
+ return &priv->array;
+}
+
+void array_free(UArray *array)
+{
+ if (!array)
+ return;
+
+ free(array->data);
+ free(array);
+}
+
+UArray *array_resize(UArray *array, unsigned int num_elements)
+{
+ UArrayPrivate * const priv = (UArrayPrivate *)array;
+ void *data;
+
+ if (num_elements <= priv->count_max)
+ return array;
+
+ num_elements += 4;
+ data = realloc(array->data, elem_size(priv, num_elements));
+ if (!data)
+ return NULL;
+
+ memset(
+ elem_offset(priv, priv->count_max),
+ 0,
+ elem_size(priv, (num_elements - priv->count_max))
+ );
+
+ array->data = data;
+ priv->count_max = num_elements;
+ return array;
+}
+
+UArray *array_append(UArray *array, const void *data)
+{
+ UArrayPrivate * const priv = (UArrayPrivate *)array;
+
+ if (!array_resize(array, array->count + 1))
+ return NULL;
+
+ memcpy(elem_offset(priv, array->count), data, elem_size(priv, 1));
+ ++array->count;
+ return array;
+}
+
+int array_lookup(UArray *array, const void *data, UArrayCompareFunc compare)
+{
+ UArrayPrivate * const priv = (UArrayPrivate *)array;
+ char *m;
+ unsigned int i;
+
+ if (!array)
+ return -1;
+
+ m = array->data;
+ if (compare) {
+ for (i = 0; i < array->count; i++, m += priv->element_size)
+ if (compare(m, data))
+ return i;
+ }
+ else {
+ for (i = 0; i < array->count; i++, m += priv->element_size)
+ if (memcmp(m, data, elem_size(priv, 1)) == 0)
+ return i;
+ }
+ return -1;
+}
+
+UArray *array_remove_at(UArray *array, int index)
+{
+ UArrayPrivate * const priv = (UArrayPrivate *)array;
+
+ if (!array)
+ return NULL;
+ if (index < 0 || index >= array->count)
+ return NULL;
+
+ memcpy(
+ elem_offset(priv, index),
+ elem_offset(priv, array->count - 1),
+ elem_size(priv, 1)
+ );
+ --array->count;
+ return array;
+}
+
+UArray *array_replace_at(UArray *array, int index, const void *data)
+{
+ UArrayPrivate * const priv = (UArrayPrivate *)array;
+
+ if (!array)
+ return NULL;
+ if (index < 0 || index >= array->count)
+ return NULL;
+
+ memcpy(elem_offset(priv, index), data, elem_size(priv, 1));
+ return array;
+}
diff --git a/src/uarray.h b/src/uarray.h
new file mode 100644
index 0000000..bcc3a63
--- /dev/null
+++ b/src/uarray.h
@@ -0,0 +1,59 @@
+/*
+ * uarray.h - Array utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UARRAY_H
+#define UARRAY_H
+
+typedef struct _UArray UArray;
+struct _UArray {
+ void *data;
+ unsigned int count;
+};
+
+typedef int (*UArrayCompareFunc)(const void *a, const void *b);
+
+UArray *array_new(unsigned int element_size)
+ attribute_hidden;
+
+void array_free(UArray *array)
+ attribute_hidden;
+
+UArray *array_resize(UArray *array, unsigned int num_elements)
+ attribute_hidden;
+
+UArray *array_append(UArray *array, const void *data)
+ attribute_hidden;
+
+#define array_append_val(array, val) \
+ array_append(array, &(val))
+
+int array_lookup(UArray *array, const void *data, UArrayCompareFunc compare)
+ attribute_hidden;
+
+#define array_index(array, type, index) \
+ *(type *)((char *)(array)->data + sizeof(type) * (index))
+
+UArray *array_remove_at(UArray *array, int index)
+ attribute_hidden;
+
+UArray *array_replace_at(UArray *array, int index, const void *data)
+ attribute_hidden;
+
+#endif /* UARRAY_H */
diff --git a/src/uasyncqueue.c b/src/uasyncqueue.c
new file mode 100644
index 0000000..8d687a2
--- /dev/null
+++ b/src/uasyncqueue.c
@@ -0,0 +1,333 @@
+/*
+ * uasyncqueue.c - Asynchronous queue utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "uasyncqueue.h"
+#include "uqueue.h"
+#include <pthread.h>
+
+struct _UAsyncQueue {
+ UQueue *queue;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned int is_waiting;
+};
+
+UAsyncQueue *async_queue_new(void)
+{
+ UAsyncQueue *queue = malloc(sizeof(*queue));
+
+ if (!queue)
+ return NULL;
+
+ queue->queue = queue_new();
+ if (!queue->queue)
+ goto error;
+
+ if (pthread_cond_init(&queue->cond, NULL) != 0)
+ goto error;
+
+ pthread_mutex_init(&queue->mutex, NULL);
+ queue->is_waiting = 0;
+ return queue;
+
+error:
+ async_queue_free(queue);
+ return NULL;
+}
+
+void async_queue_free(UAsyncQueue *queue)
+{
+ if (!queue)
+ return;
+
+ pthread_mutex_unlock(&queue->mutex);
+ queue_free(queue->queue);
+ free(queue);
+}
+
+int async_queue_is_empty(UAsyncQueue *queue)
+{
+ return queue && queue_is_empty(queue->queue);
+}
+
+static UAsyncQueue *async_queue_push_unlocked(UAsyncQueue *queue, void *data)
+{
+ queue_push(queue->queue, data);
+ if (queue->is_waiting)
+ pthread_cond_signal(&queue->cond);
+ return queue;
+}
+
+UAsyncQueue *async_queue_push(UAsyncQueue *queue, void *data)
+{
+ if (!queue)
+ return NULL;
+
+ pthread_mutex_lock(&queue->mutex);
+ async_queue_push_unlocked(queue, data);
+ pthread_mutex_unlock(&queue->mutex);
+ return queue;
+}
+
+static void *
+async_queue_timed_pop_unlocked(UAsyncQueue *queue, uint64_t end_time)
+{
+ if (queue_is_empty(queue->queue)) {
+ assert(!queue->is_waiting);
+ ++queue->is_waiting;
+ if (!end_time)
+ pthread_cond_wait(&queue->cond, &queue->mutex);
+ else {
+ struct timespec timeout;
+ timeout.tv_sec = end_time / 1000000;
+ timeout.tv_nsec = 1000 * (end_time % 1000000);
+ pthread_cond_timedwait(&queue->cond, &queue->mutex, &timeout);
+ }
+ --queue->is_waiting;
+ if (queue_is_empty(queue->queue))
+ return NULL;
+ }
+ return queue_pop(queue->queue);
+}
+
+void *async_queue_timed_pop(UAsyncQueue *queue, uint64_t end_time)
+{
+ void *data;
+
+ if (!queue)
+ return NULL;
+
+ pthread_mutex_lock(&queue->mutex);
+ data = async_queue_timed_pop_unlocked(queue, end_time);
+ pthread_mutex_unlock(&queue->mutex);
+ return data;
+}
+
+#ifdef TEST_ASYNC_QUEUE
+#include <stdarg.h>
+
+enum {
+ CMD_QUIT,
+ CMD_TIME,
+ CMD_ADD_1,
+ CMD_ADD_2,
+ CMD_ADD_3,
+};
+
+typedef enum {
+ MSG_INVOKE,
+ MSG_REPLY
+} MessageType;
+
+#define MSG_ARG(v) ((uint64_t)(v))
+
+typedef struct {
+ MessageType type;
+ unsigned int num_args;
+ uint64_t args[1];
+} Message;
+
+static Message *msg_new(MessageType type, unsigned int num_args)
+{
+ Message *msg;
+
+ msg = malloc(sizeof(*msg) + num_args * sizeof(msg->args[0]));
+ if (msg) {
+ msg->type = type;
+ msg->num_args = num_args;
+ }
+ return msg;
+}
+
+static void msg_free(Message *msg)
+{
+ free(msg);
+}
+
+static int msg_invoke(UAsyncQueue *queue, int cmd, unsigned int num_args, ...)
+{
+ Message *msg;
+ va_list args;
+ unsigned int i;
+
+ msg = msg_new(MSG_INVOKE, 1 + num_args);
+ if (!msg)
+ return 0;
+
+ msg->args[0] = cmd;
+ va_start(args, num_args);
+ for (i = 0; i < num_args; i++)
+ msg->args[1 + i] = va_arg(args, uint64_t);
+ va_end(args);
+
+ if (!async_queue_push(queue, msg)) {
+ msg_free(msg);
+ return 0;
+ }
+ return 1;
+}
+
+static int msg_wait_for_reply(UAsyncQueue *queue)
+{
+ Message *msg;
+ int ret;
+
+ msg = async_queue_pop(queue);
+ if (!msg || msg->type != MSG_REPLY)
+ return -1;
+
+ ret = msg->args[0];
+ free(msg);
+ return ret;
+}
+
+typedef struct {
+ UAsyncQueue *send_queue;
+ UAsyncQueue *recv_queue;
+} ConsumerThreadArgs;
+
+static void *consumer(void *arg)
+{
+ ConsumerThreadArgs * const args = arg;
+ Message *msg;
+ const char *msg_name;
+ unsigned int i, ret, stop = 0;
+ uint64_t end_time = 0;
+
+ while (!stop) {
+ if (end_time) {
+ msg = async_queue_timed_pop(args->recv_queue, end_time);
+ if (!msg)
+ printf("<timed out>\n");
+ }
+ msg = async_queue_pop(args->recv_queue);
+ if (!msg || msg->type != MSG_INVOKE)
+ abort();
+
+ switch (msg->args[0]) {
+ case CMD_QUIT: msg_name = "quit"; break;
+ case CMD_TIME: msg_name = "time"; break;
+ case CMD_ADD_1: msg_name = "add1"; break;
+ case CMD_ADD_2: msg_name = "add2"; break;
+ case CMD_ADD_3: msg_name = "add3"; break;
+ default: msg_name = NULL; break;
+ }
+ if (!msg_name)
+ abort();
+
+ printf("recv %s", msg_name);
+ if (msg->num_args > 1) {
+ printf(": %d args:", msg->num_args - 1);
+ for (i = 1; i < msg->num_args; i++)
+ printf(" %d", (int)msg->args[i]);
+ }
+ printf("\n");
+
+ ret = 0;
+ switch (msg->args[0]) {
+ case CMD_QUIT:
+ stop = 1;
+ break;
+ case CMD_TIME:
+ end_time = msg->args[1];
+ break;
+ case CMD_ADD_1:
+ case CMD_ADD_2:
+ case CMD_ADD_3:
+ for (i = 1; i < msg->num_args; i++)
+ ret += msg->args[i];
+ end_time = 0;
+ break;
+ }
+ msg_free(msg);
+
+ msg = msg_new(MSG_REPLY, 1);
+ if (!msg)
+ abort();
+ msg->args[0] = ret;
+ if (!async_queue_push(args->send_queue, msg))
+ abort();
+ }
+ return NULL;
+}
+
+int main(void)
+{
+ struct timespec now;
+ uint64_t end_time;
+ pthread_t consumer_thread;
+ ConsumerThreadArgs consumer_args;
+ UAsyncQueue *send_queue;
+ UAsyncQueue *recv_queue;
+ Message *msg;
+
+ send_queue = async_queue_new();
+ if (!send_queue)
+ abort();
+
+ recv_queue = async_queue_new();
+ if (!recv_queue)
+ abort();
+
+ consumer_args.send_queue = recv_queue;
+ consumer_args.recv_queue = send_queue;
+ if (pthread_create(&consumer_thread, NULL, consumer, &consumer_args) != 0)
+ abort();
+
+ sleep(1);
+ if (!msg_invoke(send_queue, CMD_ADD_1, 1, MSG_ARG(1)))
+ abort();
+ if (msg_wait_for_reply(recv_queue) != 1)
+ abort();
+
+ sleep(1);
+ if (!msg_invoke(send_queue, CMD_ADD_2, 2, MSG_ARG(1), MSG_ARG(2)))
+ abort();
+ if (msg_wait_for_reply(recv_queue) != 3)
+ abort();
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ end_time = (1 + now.tv_sec) * 1000000 + (now.tv_nsec / 1000);
+
+ sleep(1);
+ if (!msg_invoke(send_queue, CMD_TIME, 1, MSG_ARG(end_time)))
+ abort();
+ if (msg_wait_for_reply(recv_queue) != 0)
+ abort();
+
+ sleep(1);
+ if (!msg_invoke(send_queue, CMD_ADD_3, 3, MSG_ARG(1), MSG_ARG(2), MSG_ARG(3)))
+ abort();
+ if (msg_wait_for_reply(recv_queue) != 6)
+ abort();
+
+ sleep(1);
+ if (!msg_invoke(send_queue, CMD_QUIT, 0))
+ abort();
+ if (msg_wait_for_reply(recv_queue) != 0)
+ abort();
+
+ pthread_join(consumer_thread, NULL);
+ async_queue_free(recv_queue);
+ async_queue_free(send_queue);
+ return 0;
+}
+#endif
diff --git a/src/uasyncqueue.h b/src/uasyncqueue.h
new file mode 100644
index 0000000..adc5a81
--- /dev/null
+++ b/src/uasyncqueue.h
@@ -0,0 +1,44 @@
+/*
+ * uasyncqueue.h - Asynchronous queue utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UASYNCQUEUE_H
+#define UASYNCQUEUE_H
+
+typedef struct _UAsyncQueue UAsyncQueue;
+
+UAsyncQueue *async_queue_new(void)
+ attribute_hidden;
+
+void async_queue_free(UAsyncQueue *queue)
+ attribute_hidden;
+
+int async_queue_is_empty(UAsyncQueue *queue)
+ attribute_hidden;
+
+UAsyncQueue *async_queue_push(UAsyncQueue *queue, void *data)
+ attribute_hidden;
+
+void *async_queue_timed_pop(UAsyncQueue *queue, uint64_t end_time)
+ attribute_hidden;
+
+#define async_queue_pop(queue) \
+ async_queue_timed_pop(queue, 0)
+
+#endif /* UASYNCQUEUE_H */
diff --git a/src/ulist.c b/src/ulist.c
new file mode 100644
index 0000000..4acbd24
--- /dev/null
+++ b/src/ulist.c
@@ -0,0 +1,166 @@
+/*
+ * ulist.c - List utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "ulist.h"
+
+static UList *list_new(void *data, UList *prev, UList *next)
+{
+ UList *list = malloc(sizeof(*list));
+
+ if (list) {
+ list->data = data;
+ list->prev = prev;
+ list->next = next;
+ if (prev)
+ prev->next = list;
+ if (next)
+ next->prev = list;
+ }
+ return list;
+}
+
+void list_free_1(UList *list)
+{
+ free(list);
+}
+
+void list_free(UList *list)
+{
+ while (list) {
+ UList * const next = list->next;
+ list_free_1(list);
+ list = next;
+ }
+}
+
+UList *list_append(UList *list, void *data)
+{
+ UList * const node = list_new(data, list_last(list), NULL);
+
+ return list ? list : node;
+}
+
+UList *list_prepend(UList *list, void *data)
+{
+ return list_new(data, list ? list->prev : NULL, list);
+}
+
+UList *list_reverse(UList *list)
+{
+ UList *last = NULL;
+
+ while (list) {
+ last = list;
+ list = last->next;
+ last->next = last->prev;
+ last->prev = list;
+ }
+ return last;
+}
+
+UList *list_first(UList *list)
+{
+ if (list) {
+ while (list->prev)
+ list = list->prev;
+ }
+ return list;
+}
+
+UList *list_last(UList *list)
+{
+ if (list) {
+ while (list->next)
+ list = list->next;
+ }
+ return list;
+}
+
+unsigned int list_size(UList *list)
+{
+ unsigned int size = 0;
+
+ while (list) {
+ ++size;
+ list = list->next;
+ }
+ return size;
+}
+
+UList *list_lookup_full(UList *list, const void *data, UListCompareFunc compare)
+{
+ if (!list)
+ return NULL;
+
+ if (compare) {
+ for (; list; list = list->next)
+ if (compare(list->data, data))
+ return list;
+ }
+ else {
+ for (; list; list = list->next)
+ if (list->data == data)
+ return list;
+ }
+ return NULL;
+}
+
+#ifdef TEST_LIST
+int main(void)
+{
+ UList *temp, *list = NULL;
+
+ list = list_append(list, UINT_TO_POINTER(1));
+
+ temp = list_append(list, UINT_TO_POINTER(2));
+ if (temp != list)
+ abort();
+
+ temp = list_append(list, UINT_TO_POINTER(3));
+ if (temp != list)
+ abort();
+
+ list = list_prepend(list, UINT_TO_POINTER(0));
+ if (list == temp)
+ abort();
+
+ if (list_size(list) != 4)
+ abort();
+
+ if (list_first(list_last(list)) != list)
+ abort();
+
+ if (POINTER_TO_UINT(list_last(list)->data) != 3)
+ abort();
+
+ if (POINTER_TO_UINT(list_first(temp)->data) != 0)
+ abort();
+
+ temp = list_lookup(list, UINT_TO_POINTER(2));
+ if (!temp)
+ abort();
+ if (list_size(temp) != 2)
+ abort();
+
+ list_free(list);
+ return 0;
+}
+#endif
diff --git a/src/ulist.h b/src/ulist.h
new file mode 100644
index 0000000..0fc3056
--- /dev/null
+++ b/src/ulist.h
@@ -0,0 +1,63 @@
+/*
+ * ulist.h - List utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef ULIST_H
+#define ULIST_H
+
+typedef struct _UList UList;
+struct _UList {
+ void *data;
+ UList *prev;
+ UList *next;
+};
+
+typedef int (*UListCompareFunc)(const void *a, const void *b);
+
+void list_free_1(UList *list)
+ attribute_hidden;
+
+void list_free(UList *list)
+ attribute_hidden;
+
+UList *list_append(UList *list, void *data)
+ attribute_hidden;
+
+UList *list_prepend(UList *list, void *data)
+ attribute_hidden;
+
+UList *list_reverse(UList *list)
+ attribute_hidden;
+
+UList *list_first(UList *list)
+ attribute_hidden;
+
+UList *list_last(UList *list)
+ attribute_hidden;
+
+unsigned int list_size(UList *list)
+ attribute_hidden;
+
+UList *list_lookup_full(UList *list, const void *data, UListCompareFunc compare)
+ attribute_hidden;
+
+#define list_lookup(list, data) \
+ list_lookup_full(list, data, NULL)
+
+#endif /* ULIST_H */
diff --git a/src/uqueue.c b/src/uqueue.c
new file mode 100644
index 0000000..ef28e46
--- /dev/null
+++ b/src/uqueue.c
@@ -0,0 +1,107 @@
+/*
+ * uqueue.c - Queue utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "uqueue.h"
+#include "ulist.h"
+
+struct _UQueue {
+ UList *head;
+ UList *tail;
+ unsigned int size;
+};
+
+UQueue *queue_new(void)
+{
+ return calloc(1, sizeof(UQueue));
+}
+
+void queue_free(UQueue *queue)
+{
+ if (!queue)
+ return;
+
+ list_free(queue->head);
+ free(queue);
+}
+
+int queue_is_empty(UQueue *queue)
+{
+ return !queue || queue->size == 0;
+}
+
+UQueue *queue_push(UQueue *queue, void *data)
+{
+ if (!queue)
+ return NULL;
+
+ queue->tail = list_last(list_append(queue->tail, data));
+
+ if (!queue->head)
+ queue->head = queue->tail;
+
+ ++queue->size;
+ return queue;
+}
+
+void *queue_pop(UQueue *queue)
+{
+ UList *list;
+ void *data;
+
+ if (!queue || !queue->head)
+ return NULL;
+
+ list = queue->head;
+ data = list->data;
+ queue->head = list->next;
+ if (--queue->size == 0)
+ queue->tail = NULL;
+ list_free_1(list);
+ return data;
+}
+
+#ifdef TEST_QUEUE
+int main(void)
+{
+ UQueue *queue = queue_new();
+
+ if (!queue_push(queue, UINT_TO_POINTER(1)))
+ abort();
+ if (!queue_push(queue, UINT_TO_POINTER(2)))
+ abort();
+ if (queue_is_empty(queue))
+ abort();
+
+ if (POINTER_TO_UINT(queue_pop(queue)) != 1)
+ abort();
+ if (POINTER_TO_UINT(queue_pop(queue)) != 2)
+ abort();
+ if (!queue_is_empty(queue))
+ abort();
+
+ if (!queue_push(queue, UINT_TO_POINTER(3)))
+ abort();
+ if (POINTER_TO_UINT(queue_pop(queue)) != 3)
+ abort();
+
+ queue_free(queue);
+}
+#endif
diff --git a/src/uqueue.h b/src/uqueue.h
new file mode 100644
index 0000000..6594e7b
--- /dev/null
+++ b/src/uqueue.h
@@ -0,0 +1,41 @@
+/*
+ * uqueue.h - Queue utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UQUEUE_H
+#define UQUEUE_H
+
+typedef struct _UQueue UQueue;
+
+UQueue *queue_new(void)
+ attribute_hidden;
+
+void queue_free(UQueue *queue)
+ attribute_hidden;
+
+int queue_is_empty(UQueue *queue)
+ attribute_hidden;
+
+UQueue *queue_push(UQueue *queue, void *data)
+ attribute_hidden;
+
+void *queue_pop(UQueue *queue)
+ attribute_hidden;
+
+#endif /* UQUEUE_H */
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..4bc0835
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,221 @@
+/*
+ * utils.h - Utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "utils.h"
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <X11/Xutil.h>
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Parses ENV environment variable for an integer value
+int getenv_int(const char *env, int *pval)
+{
+ const char *env_str = getenv(env);
+ if (!env_str)
+ return -1;
+
+ char *end = NULL;
+ long val = strtoul(env_str, &end, 10);
+ if (end == NULL || end[0] != '\0')
+ return -1;
+
+ if (pval)
+ *pval = val;
+ return 0;
+}
+
+// Parses ENV environment variable expecting "yes" | "no" values
+int getenv_yesno(const char *env, int *pval)
+{
+ const char *env_str = getenv(env);
+ if (!env_str)
+ return -1;
+
+ int val;
+ if (strcmp(env_str, "1") == 0 || strcmp(env_str, "yes") == 0)
+ val = 1;
+ else if (strcmp(env_str, "0") == 0 || strcmp(env_str, "no") == 0)
+ val = 0;
+ else
+ return -1;
+
+ if (pval)
+ *pval = val;
+ return 0;
+}
+
+// Get current value of microsecond timer
+uint64_t get_ticks_usec(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+ return (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000;
+#else
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
+#endif
+}
+
+#if defined(__linux__)
+// Linux select() changes its timeout parameter upon return to contain
+// the remaining time. Most other unixen leave it unchanged or undefined.
+#define SELECT_SETS_REMAINING
+#elif defined(__FreeBSD__) || defined(__sun__) || (defined(__MACH__) && defined(__APPLE__))
+#define USE_NANOSLEEP
+#elif defined(HAVE_PTHREADS) && defined(sgi)
+// SGI pthreads has a bug when using pthreads+signals+nanosleep,
+// so instead of using nanosleep, wait on a CV which is never signalled.
+#include <pthread.h>
+#define USE_COND_TIMEDWAIT
+#endif
+
+// Wait for the specified amount of microseconds
+void delay_usec(unsigned int usec)
+{
+ int was_error;
+
+#if defined(USE_NANOSLEEP)
+ struct timespec elapsed, tv;
+#elif defined(USE_COND_TIMEDWAIT)
+ // Use a local mutex and cv, so threads remain independent
+ pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
+ struct timespec elapsed;
+ uint64_t future;
+#else
+ struct timeval tv;
+#ifndef SELECT_SETS_REMAINING
+ uint64_t then, now, elapsed;
+#endif
+#endif
+
+ // Set the timeout interval - Linux only needs to do this once
+#if defined(SELECT_SETS_REMAINING)
+ tv.tv_sec = 0;
+ tv.tv_usec = usec;
+#elif defined(USE_NANOSLEEP)
+ elapsed.tv_sec = 0;
+ elapsed.tv_nsec = usec * 1000;
+#elif defined(USE_COND_TIMEDWAIT)
+ future = get_ticks_usec() + usec;
+ elapsed.tv_sec = future / 1000000;
+ elapsed.tv_nsec = (future % 1000000) * 1000;
+#else
+ then = get_ticks_usec();
+#endif
+
+ do {
+ errno = 0;
+#if defined(USE_NANOSLEEP)
+ tv.tv_sec = elapsed.tv_sec;
+ tv.tv_nsec = elapsed.tv_nsec;
+ was_error = nanosleep(&tv, &elapsed);
+#elif defined(USE_COND_TIMEDWAIT)
+ was_error = pthread_mutex_lock(&delay_mutex);
+ was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
+ was_error = pthread_mutex_unlock(&delay_mutex);
+#else
+#ifndef SELECT_SETS_REMAINING
+ // Calculate the time interval left (in case of interrupt)
+ now = get_ticks_usec();
+ elapsed = now - then;
+ then = now;
+ if (elapsed >= usec)
+ break;
+ usec -= elapsed;
+ tv.tv_sec = 0;
+ tv.tv_usec = usec;
+#endif
+ was_error = select(0, NULL, NULL, NULL, &tv);
+#endif
+ } while (was_error && (errno == EINTR));
+}
+
+// Reallocates a BUFFER to NUM_ELEMENTS of ELEMENT_SIZE bytes
+void *
+realloc_buffer(
+ void **buffer_p,
+ unsigned int *max_elements_p,
+ unsigned int num_elements,
+ unsigned int element_size
+)
+{
+ if (!buffer_p || !max_elements_p)
+ return NULL;
+
+ void *buffer = *buffer_p;
+ if (*max_elements_p > num_elements)
+ return buffer;
+
+ num_elements += 4;
+ if ((buffer = realloc(buffer, num_elements * element_size)) == NULL) {
+ free(*buffer_p);
+ *buffer_p = NULL;
+ return NULL;
+ }
+ memset((uint8_t *)buffer + *max_elements_p * element_size, 0,
+ (num_elements - *max_elements_p) * element_size);
+
+ *buffer_p = buffer;
+ *max_elements_p = num_elements;
+ return buffer;
+}
+
+// Convert string array to char array
+// NOTE: dst char array shall be large enough to contain src strings
+void string_array_to_char_array(char *dst, const char **src)
+{
+ int i, n;
+
+ for (i = 0; src[i]; i++) {
+ n = strlen(src[i]);
+ memcpy(dst, src[i], n);
+ dst += n;
+ }
+ *dst = '\0';
+}
+
+// Lookup for substring NAME in string EXT using SEP as separators
+int find_string(const char *name, const char *ext, const char *sep)
+{
+ const char *end;
+ int name_len, n;
+
+ if (name == NULL || ext == NULL)
+ return 0;
+
+ end = ext + strlen(ext);
+ name_len = strlen(name);
+ while (ext < end) {
+ n = strcspn(ext, sep);
+ if (n == name_len && strncmp(name, ext, n) == 0)
+ return 1;
+ ext += (n + 1);
+ }
+ return 0;
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..f0a4b9c
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,50 @@
+/*
+ * utils.h - Utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+int getenv_int(const char *env, int *pval)
+ attribute_hidden;
+
+int getenv_yesno(const char *env, int *pval)
+ attribute_hidden;
+
+uint64_t get_ticks_usec(void)
+ attribute_hidden;
+
+void delay_usec(unsigned int usec)
+ attribute_hidden;
+
+void *
+realloc_buffer(
+ void **buffer_p,
+ unsigned int *max_elements_p,
+ unsigned int num_elements,
+ unsigned int element_size
+) attribute_hidden;
+
+void string_array_to_char_array(char *dst, const char **src)
+ attribute_hidden;
+
+int find_string(const char *name, const char *ext, const char *sep)
+ attribute_hidden;
+
+#endif /* UTILS_H */
diff --git a/src/utils_glx.c b/src/utils_glx.c
new file mode 100644
index 0000000..28273ce
--- /dev/null
+++ b/src/utils_glx.c
@@ -0,0 +1,1231 @@
+/*
+ * utils_glx.c - GLX utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define _GNU_SOURCE 1 /* RTLD_DEFAULT */
+#include "sysdeps.h"
+#include <string.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include "utils.h"
+#include "utils_glx.h"
+#include "utils_x11.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+/**
+ * gl_get_error_string:
+ * @error: an OpenGL error enumeration
+ *
+ * Retrieves the string representation the OpenGL @error.
+ *
+ * Return error: the static string representing the OpenGL @error
+ */
+const char *
+gl_get_error_string(GLenum error)
+{
+ static const struct {
+ GLenum val;
+ const char *str;
+ }
+ gl_errors[] = {
+ { GL_NO_ERROR, "no error" },
+ { GL_INVALID_ENUM, "invalid enumerant" },
+ { GL_INVALID_VALUE, "invalid value" },
+ { GL_INVALID_OPERATION, "invalid operation" },
+ { GL_STACK_OVERFLOW, "stack overflow" },
+ { GL_STACK_UNDERFLOW, "stack underflow" },
+ { GL_OUT_OF_MEMORY, "out of memory" },
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+ { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
+#endif
+ { ~0, NULL }
+ };
+
+ unsigned int i;
+ for (i = 0; gl_errors[i].str; i++) {
+ if (gl_errors[i].val == error)
+ return gl_errors[i].str;
+ }
+ return "unknown";
+}
+
+/**
+ * gl_purge_errors:
+ *
+ * Purges all OpenGL errors. This function is generally useful to
+ * clear up the pending errors prior to calling gl_check_error().
+ */
+void
+gl_purge_errors(void)
+{
+ while (glGetError() != GL_NO_ERROR)
+ ; /* nothing */
+}
+
+/**
+ * gl_check_error:
+ *
+ * Checks whether there is any OpenGL error pending.
+ *
+ * Return value: 1 if an error was encountered
+ */
+int
+gl_check_error(void)
+{
+ GLenum error;
+ int has_errors = 0;
+
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ D(bug("glError: %s caught", gl_get_error_string(error)));
+ has_errors = 1;
+ }
+ return has_errors;
+}
+
+/**
+ * gl_get_param:
+ * @param: the parameter name
+ * @pval: return location for the value
+ *
+ * This function is a wrapper around glGetIntegerv() that does extra
+ * error checking.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_get_param(GLenum param, unsigned int *pval)
+{
+ GLint val;
+
+ gl_purge_errors();
+ glGetIntegerv(param, &val);
+ if (gl_check_error())
+ return 0;
+
+ if (pval)
+ *pval = val;
+ return 1;
+}
+
+/**
+ * gl_get_texture_param:
+ * @target: the target to which the texture is bound
+ * @param: the parameter name
+ * @pval: return location for the value
+ *
+ * This function is a wrapper around glGetTexLevelParameteriv() that
+ * does extra error checking.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_get_texture_param(GLenum target, GLenum param, unsigned int *pval)
+{
+ GLint val;
+
+ gl_purge_errors();
+ glGetTexLevelParameteriv(target, 0, param, &val);
+ if (gl_check_error())
+ return 0;
+
+ if (pval)
+ *pval = val;
+ return 1;
+}
+
+/**
+ * gl_set_bgcolor:
+ * @color: the requested RGB color
+ *
+ * Sets background color to the RGB @color. This basically is a
+ * wrapper around glClearColor().
+ */
+void
+gl_set_bgcolor(uint32_t color)
+{
+ glClearColor(
+ ((color >> 16) & 0xff) / 255.0f,
+ ((color >> 8) & 0xff) / 255.0f,
+ ( color & 0xff) / 255.0f,
+ 1.0f
+ );
+}
+
+/**
+ * gl_set_texture_scaling:
+ * @target: the target to which the texture is currently bound
+ * @scale: scaling algorithm
+ *
+ * Sets scaling algorithm used for the texture currently bound.
+ */
+void
+gl_set_texture_scaling(GLenum target, GLenum scale)
+{
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, scale);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, scale);
+}
+
+/**
+ * gl_set_texture_wrapping:
+ * @target: the target to which the texture is currently bound
+ * @wrap: wrapping mode
+ *
+ * Sets wrapping mode used for the texture currently bound.
+ */
+void
+gl_set_texture_wrapping(GLenum target, GLenum wrap)
+{
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
+}
+
+/**
+ * gl_perspective:
+ * @fovy: the field of view angle, in degrees, in the y direction
+ * @aspect: the aspect ratio that determines the field of view in the
+ * x direction. The aspect ratio is the ratio of x (width) to y
+ * (height)
+ * @zNear: the distance from the viewer to the near clipping plane
+ * (always positive)
+ * @zFar: the distance from the viewer to the far clipping plane
+ * (always positive)
+ *
+ * Specified a viewing frustum into the world coordinate system. This
+ * basically is the Mesa implementation of gluPerspective().
+ */
+static void
+frustum(GLdouble left, GLdouble right,
+ GLdouble bottom, GLdouble top,
+ GLdouble nearval, GLdouble farval)
+{
+ GLdouble x, y, a, b, c, d;
+ GLdouble m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixd(m);
+}
+
+static void
+gl_perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
+{
+ GLdouble xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan(fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ /* Don't call glFrustum() because of error semantics (covglu) */
+ frustum(xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+/**
+ * gl_resize:
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Resizes the OpenGL viewport to the specified dimensions, using an
+ * orthogonal projection. (0,0) represents the top-left corner of the
+ * window.
+ */
+void
+gl_resize(unsigned int width, unsigned int height)
+{
+#if 0
+#define FOVY 60.0f
+#define ASPECT 1.0f
+#define Z_NEAR 0.1f
+#define Z_FAR 100.0f
+#define Z_CAMERA 0.869f
+
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gl_perspective(FOVY, ASPECT, Z_NEAR, Z_FAR);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glTranslatef(-0.5f, -0.5f, -Z_CAMERA);
+ glScalef(1.0f/width, -1.0f/height, 1.0f/width);
+ glTranslatef(0.0f, -1.0f*height, 0.0f);
+#else
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, height, 0, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+#endif
+}
+
+/**
+ * gl_set_current_context_cache:
+ * @is_enabled: flag to enable the current context cache
+ *
+ * Toggles use of the (TLS-based) current context cache.
+ *
+ * The cache is important in multi-threaded environments since
+ * glXGetCurrent*() functions can take up to 76 ms [fglrx 8.77.x] to
+ * complete!! However, this cannot be used in standard VA/GLX
+ * situations because foreign changes (from the user program) can
+ * occur without us knowing about.
+ */
+static int gl_current_context_cache = 0;
+static __thread Display *gl_current_display;
+static __thread Window gl_current_window;
+static __thread GLXContext gl_current_context;
+
+void
+gl_set_current_context_cache(int is_enabled)
+{
+ gl_current_context_cache = is_enabled;
+}
+
+static Bool
+gl_make_current(Display *dpy, Window win, GLXContext ctx)
+{
+ Bool ret;
+
+ if (gl_current_context_cache &&
+ gl_current_display == dpy &&
+ gl_current_window == win &&
+ gl_current_context == ctx)
+ return True;
+
+ ret = glXMakeCurrent(dpy, win, ctx);
+
+ if (ret && gl_current_context_cache) {
+ gl_current_display = dpy;
+ gl_current_window = win;
+ gl_current_context = ctx;
+ }
+ return ret;
+}
+
+/**
+ * gl_create_context:
+ * @dpy: an X11 #Display
+ * @screen: the associated screen of @dpy
+ * @parent: the parent #GLContextState, or %NULL if none is to be used
+ *
+ * Creates a GLX context sharing textures and displays lists with
+ * @parent, if not %NULL.
+ *
+ * Return value: the newly created GLX context
+ */
+GLContextState *
+gl_create_context(Display *dpy, int screen, GLContextState *parent)
+{
+ GLContextState *cs;
+ GLXFBConfig *fbconfigs = NULL;
+ int fbconfig_id, val, n, n_fbconfigs;
+ Status status;
+
+ static GLint fbconfig_attrs[] = {
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DOUBLEBUFFER, True,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ None
+ };
+
+ cs = malloc(sizeof(*cs));
+ if (!cs)
+ goto error;
+
+ cs->display = dpy;
+ cs->window = parent ? parent->window : None;
+ cs->visual = NULL;
+ cs->context = NULL;
+
+ if (parent && parent->context) {
+ status = glXQueryContext(
+ parent->display,
+ parent->context,
+ GLX_FBCONFIG_ID, &fbconfig_id
+ );
+ if (status != Success)
+ goto error;
+
+ fbconfigs = glXGetFBConfigs(dpy, screen, &n_fbconfigs);
+ if (!fbconfigs)
+ goto error;
+
+ /* Find out a GLXFBConfig compatible with the parent context */
+ for (n = 0; n < n_fbconfigs; n++) {
+ status = glXGetFBConfigAttrib(
+ dpy,
+ fbconfigs[n],
+ GLX_FBCONFIG_ID, &val
+ );
+ if (status == Success && val == fbconfig_id)
+ break;
+ }
+ if (n == n_fbconfigs)
+ goto error;
+ }
+ else {
+ fbconfigs = glXChooseFBConfig(
+ dpy,
+ screen,
+ fbconfig_attrs, &n_fbconfigs
+ );
+ if (!fbconfigs)
+ goto error;
+
+ /* Select the first one */
+ n = 0;
+ }
+
+ cs->visual = glXGetVisualFromFBConfig(dpy, fbconfigs[n]);
+ cs->context = glXCreateNewContext(
+ dpy,
+ fbconfigs[n],
+ GLX_RGBA_TYPE,
+ parent ? parent->context : NULL,
+ True
+ );
+ if (cs->context)
+ goto end;
+
+error:
+ gl_destroy_context(cs);
+ cs = NULL;
+end:
+ if (fbconfigs)
+ XFree(fbconfigs);
+ return cs;
+}
+
+/**
+ * gl_destroy_context:
+ * @cs: a #GLContextState
+ *
+ * Destroys the GLX context @cs
+ */
+void
+gl_destroy_context(GLContextState *cs)
+{
+ if (!cs)
+ return;
+
+ if (cs->visual) {
+ XFree(cs->visual);
+ cs->visual = NULL;
+ }
+
+ if (cs->display && cs->context) {
+ if (glXGetCurrentContext() == cs->context)
+ gl_make_current(cs->display, None, NULL);
+ glXDestroyContext(cs->display, cs->context);
+ cs->display = NULL;
+ cs->context = NULL;
+ }
+ free(cs);
+}
+
+/**
+ * gl_init_context:
+ * @cs: a #GLContextState
+ *
+ * Initializes the GLX context @cs with a base environment.
+ */
+void
+gl_init_context(GLContextState *cs)
+{
+ GLContextState old_cs, tmp_cs;
+
+ if (!gl_set_current_context(cs, &old_cs))
+ return;
+
+ glEnable(GL_TEXTURE_2D);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_CULL_FACE);
+ glDrawBuffer(GL_BACK);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ gl_set_current_context(&old_cs, &tmp_cs);
+}
+
+/**
+ * gl_get_current_context:
+ * @cs: return location to the current #GLContextState
+ *
+ * Retrieves the current GLX context, display and drawable packed into
+ * the #GLContextState struct.
+ */
+void
+gl_get_current_context(GLContextState *cs)
+{
+ if (gl_current_context_cache) {
+ cs->display = gl_current_display;
+ cs->window = gl_current_window;
+ cs->context = gl_current_context;
+ }
+ else {
+ cs->display = glXGetCurrentDisplay();
+ cs->window = glXGetCurrentDrawable();
+ cs->context = glXGetCurrentContext();
+ }
+}
+
+/**
+ * gl_set_current_context:
+ * @new_cs: the requested new #GLContextState
+ * @old_cs: return location to the context that was previously current
+ *
+ * Makes the @new_cs GLX context the current GLX rendering context of
+ * the calling thread, replacing the previously current context if
+ * there was one.
+ *
+ * If @old_cs is non %NULL, the previously current GLX context and
+ * window are recorded.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_set_current_context(GLContextState *new_cs, GLContextState *old_cs)
+{
+ /* If display is NULL, this could be that new_cs was retrieved from
+ gl_get_current_context() with none set previously. If that case,
+ the other fields are also NULL and we don't return an error */
+ if (!new_cs->display)
+ return !new_cs->window && !new_cs->context;
+
+ if (old_cs) {
+ if (old_cs == new_cs)
+ return 1;
+
+ gl_get_current_context(old_cs);
+ if (old_cs->display == new_cs->display &&
+ old_cs->window == new_cs->window &&
+ old_cs->context == new_cs->context)
+ return 1;
+
+ /* Make sure gl_set_current_context(old_cs, NULL); releases
+ the current GLX context */
+ if (!old_cs->display)
+ old_cs->display = new_cs->display;
+ }
+ return gl_make_current(new_cs->display, new_cs->window, new_cs->context);
+}
+
+/**
+ * gl_swap_buffers:
+ * @cs: a #GLContextState
+ *
+ * Promotes the contents of the back buffer of the @win window to
+ * become the contents of the front buffer. This simply is wrapper
+ * around glXSwapBuffers().
+ */
+void
+gl_swap_buffers(GLContextState *cs)
+{
+ glXSwapBuffers(cs->display, cs->window);
+}
+
+/**
+ * get_proc_address:
+ * @name: the name of the OpenGL extension function to lookup
+ *
+ * Returns the specified OpenGL extension function
+ *
+ * Return value: the OpenGL extension matching @name, or %NULL if none
+ * was found
+ */
+typedef void (*GLFuncPtr)(void);
+typedef GLFuncPtr (*GLXGetProcAddressProc)(const char *);
+
+static GLFuncPtr
+get_proc_address_default(const char *name)
+{
+ return NULL;
+}
+
+static GLXGetProcAddressProc
+get_proc_address_func(void)
+{
+ GLXGetProcAddressProc get_proc_func;
+
+ dlerror();
+ get_proc_func = (GLXGetProcAddressProc)
+ dlsym(RTLD_DEFAULT, "glXGetProcAddress");
+ if (!dlerror())
+ return get_proc_func;
+
+ get_proc_func = (GLXGetProcAddressProc)
+ dlsym(RTLD_DEFAULT, "glXGetProcAddressARB");
+ if (!dlerror())
+ return get_proc_func;
+
+ return get_proc_address_default;
+}
+
+static inline GLFuncPtr
+get_proc_address(const char *name)
+{
+ static GLXGetProcAddressProc get_proc_func = NULL;
+ if (!get_proc_func)
+ get_proc_func = get_proc_address_func();
+ return get_proc_func(name);
+}
+
+/**
+ * gl_init_vtable:
+ *
+ * Initializes the global #GLVTable.
+ *
+ * Return value: the #GLVTable filled in with OpenGL extensions, or
+ * %NULL on error.
+ */
+static GLVTable gl_vtable_static;
+
+static GLVTable *
+gl_init_vtable(void)
+{
+ GLVTable * const gl_vtable = &gl_vtable_static;
+ const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
+ int has_extension;
+
+ /* GL_ARB_texture_non_power_of_two */
+ has_extension = (
+ find_string("GL_ARB_texture_non_power_of_two", gl_extensions, " ")
+ );
+ if (has_extension)
+ gl_vtable->has_texture_non_power_of_two = 1;
+
+ /* GL_ARB_texture_rectangle */
+ has_extension = (
+ find_string("GL_ARB_texture_rectangle", gl_extensions, " ")
+ );
+ if (has_extension)
+ gl_vtable->has_texture_rectangle = 1;
+
+ /* GL_ARB_texture_float */
+ has_extension = (
+ find_string("GL_ARB_texture_float", gl_extensions, " ")
+ );
+ if (has_extension)
+ gl_vtable->has_texture_float = 1;
+
+ /* GL_ARB_framebuffer_object */
+ has_extension = (
+ find_string("GL_ARB_framebuffer_object", gl_extensions, " ") ||
+ find_string("GL_EXT_framebuffer_object", gl_extensions, " ")
+ );
+ if (has_extension) {
+ gl_vtable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
+ get_proc_address("glGenFramebuffersEXT");
+ if (!gl_vtable->gl_gen_framebuffers)
+ return NULL;
+ gl_vtable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
+ get_proc_address("glDeleteFramebuffersEXT");
+ if (!gl_vtable->gl_delete_framebuffers)
+ return NULL;
+ gl_vtable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
+ get_proc_address("glBindFramebufferEXT");
+ if (!gl_vtable->gl_bind_framebuffer)
+ return NULL;
+ gl_vtable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
+ get_proc_address("glGenRenderbuffersEXT");
+ if (!gl_vtable->gl_gen_renderbuffers)
+ return NULL;
+ gl_vtable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
+ get_proc_address("glDeleteRenderbuffersEXT");
+ if (!gl_vtable->gl_delete_renderbuffers)
+ return NULL;
+ gl_vtable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
+ get_proc_address("glBindRenderbufferEXT");
+ if (!gl_vtable->gl_bind_renderbuffer)
+ return NULL;
+ gl_vtable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
+ get_proc_address("glRenderbufferStorageEXT");
+ if (!gl_vtable->gl_renderbuffer_storage)
+ return NULL;
+ gl_vtable->gl_framebuffer_renderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
+ get_proc_address("glFramebufferRenderbufferEXT");
+ if (!gl_vtable->gl_framebuffer_renderbuffer)
+ return NULL;
+ gl_vtable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
+ get_proc_address("glFramebufferTexture2DEXT");
+ if (!gl_vtable->gl_framebuffer_texture_2d)
+ return NULL;
+ gl_vtable->gl_check_framebuffer_status = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+ get_proc_address("glCheckFramebufferStatusEXT");
+ if (!gl_vtable->gl_check_framebuffer_status)
+ return NULL;
+ gl_vtable->has_framebuffer_object = 1;
+ }
+
+ /* GL_ARB_fragment_program */
+ has_extension = (
+ find_string("GL_ARB_fragment_program", gl_extensions, " ")
+ );
+ if (has_extension) {
+ gl_vtable->gl_gen_programs = (PFNGLGENPROGRAMSARBPROC)
+ get_proc_address("glGenProgramsARB");
+ if (!gl_vtable->gl_gen_programs)
+ return NULL;
+ gl_vtable->gl_delete_programs = (PFNGLDELETEPROGRAMSARBPROC)
+ get_proc_address("glDeleteProgramsARB");
+ if (!gl_vtable->gl_delete_programs)
+ return NULL;
+ gl_vtable->gl_bind_program = (PFNGLBINDPROGRAMARBPROC)
+ get_proc_address("glBindProgramARB");
+ if (!gl_vtable->gl_bind_program)
+ return NULL;
+ gl_vtable->gl_program_string = (PFNGLPROGRAMSTRINGARBPROC)
+ get_proc_address("glProgramStringARB");
+ if (!gl_vtable->gl_program_string)
+ return NULL;
+ gl_vtable->gl_get_program_iv = (PFNGLGETPROGRAMIVARBPROC)
+ get_proc_address("glGetProgramivARB");
+ if (!gl_vtable->gl_get_program_iv)
+ return NULL;
+ gl_vtable->gl_program_local_parameter_4fv = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
+ get_proc_address("glProgramLocalParameter4fvARB");
+ if (!gl_vtable->gl_program_local_parameter_4fv)
+ return NULL;
+ gl_vtable->has_fragment_program = 1;
+ }
+
+ /* GL_ARB_multitexture */
+ has_extension = (
+ find_string("GL_ARB_multitexture", gl_extensions, " ")
+ );
+ if (has_extension) {
+ gl_vtable->gl_active_texture = (PFNGLACTIVETEXTUREPROC)
+ get_proc_address("glActiveTextureARB");
+ if (!gl_vtable->gl_active_texture)
+ return NULL;
+ gl_vtable->gl_multi_tex_coord_2f = (PFNGLMULTITEXCOORD2FPROC)
+ get_proc_address("glMultiTexCoord2fARB");
+ if (!gl_vtable->gl_multi_tex_coord_2f)
+ return NULL;
+ gl_vtable->has_multitexture = 1;
+ }
+
+ /* GL_ARB_gpu_shader5 */
+ has_extension = (
+ find_string("GL_ARB_gpu_shader5", gl_extensions, " ")
+ );
+ if (has_extension) {
+ gl_vtable->has_gpu_shader5 = 1;
+ }
+ return gl_vtable;
+}
+
+/**
+ * gl_get_vtable:
+ *
+ * Retrieves a VTable for OpenGL extensions.
+ *
+ * Return value: VTable for OpenGL extensions
+ */
+GLVTable *
+gl_get_vtable(void)
+{
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ static int gl_vtable_init = 1;
+ static GLVTable *gl_vtable = NULL;
+
+ pthread_mutex_lock(&mutex);
+ if (gl_vtable_init) {
+ gl_vtable_init = 0;
+ gl_vtable = gl_init_vtable();
+ }
+ pthread_mutex_unlock(&mutex);
+ return gl_vtable;
+}
+
+/**
+ * gl_create_texture:
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions and @format. The
+ * internal format will be automatically derived from @format.
+ *
+ * Return value: the newly created texture name
+ */
+GLuint
+gl_create_texture(
+ GLenum target,
+ GLenum format,
+ unsigned int width,
+ unsigned int height
+)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+ GLenum internal_format, type;
+ GLuint texture;
+ unsigned int bytes_per_component;
+
+ if (!gl_vtable)
+ return 0;
+
+ switch (target) {
+ case GL_TEXTURE_1D:
+ break;
+ case GL_TEXTURE_2D:
+ if (!gl_vtable->has_texture_non_power_of_two)
+ return 0;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ if (!gl_vtable->has_texture_rectangle)
+ return 0;
+ break;
+ default:
+ D(bug("Unsupported texture target 0x%04x\n", target));
+ return 0;
+ }
+
+ internal_format = format;
+ type = GL_UNSIGNED_BYTE;
+ switch (format) {
+ case GL_LUMINANCE:
+ bytes_per_component = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ bytes_per_component = 2;
+ break;
+ case GL_RGBA:
+ case GL_BGRA:
+ internal_format = GL_RGBA;
+ bytes_per_component = 4;
+ break;
+ case GL_RGBA32F_ARB:
+ if (!gl_vtable->has_texture_float)
+ return 0;
+ internal_format = GL_RGBA32F_ARB;
+ format = GL_RGBA;
+ type = GL_FLOAT;
+ bytes_per_component = 4 * 4;
+ break;
+ default:
+ bytes_per_component = 0;
+ break;
+ }
+ ASSERT(bytes_per_component > 0);
+
+ glEnable(target);
+ glGenTextures(1, &texture);
+ glBindTexture(target, texture);
+ gl_set_texture_scaling(target, GL_LINEAR);
+ gl_set_texture_wrapping(target, GL_CLAMP_TO_EDGE);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, bytes_per_component);
+ switch (target) {
+ case GL_TEXTURE_1D:
+ glTexImage1D(
+ target,
+ 0,
+ internal_format,
+ width,
+ 0,
+ format,
+ type,
+ NULL
+ );
+ break;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_RECTANGLE_ARB:
+ glTexImage2D(
+ target,
+ 0,
+ internal_format,
+ width, height,
+ 0,
+ format,
+ type,
+ NULL
+ );
+ break;
+ }
+ glBindTexture(target, 0);
+ return texture;
+}
+
+/**
+ * gl_create_texture_object:
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions and @format. The
+ * internal format will be automatically derived from @format.
+ *
+ * Return value: the newly created #GLTextureObject, or %NULL if
+ * an error occurred
+ */
+GLTextureObject *
+gl_create_texture_object(
+ GLenum target,
+ GLenum format,
+ unsigned int width,
+ unsigned int height
+)
+{
+ GLTextureObject *to;
+
+ to = calloc(1, sizeof(*to));
+ if (!to)
+ return NULL;
+
+ to->texture = gl_create_texture(target, format, width, height);
+ if (!to->texture)
+ goto error;
+ to->target = target;
+ to->format = format;
+ to->width = width;
+ to->height = height;
+ return to;
+
+error:
+ gl_destroy_texture_object(to);
+ return NULL;
+}
+
+/**
+ * gl_destroy_texture_object:
+ * @to: a #GLTextureObject
+ *
+ * Destroys the #GLTextureObject object.
+ */
+void
+gl_destroy_texture_object(GLTextureObject *to)
+{
+ if (!to)
+ return;
+
+ if (to->texture) {
+ glDeleteTextures(1, &to->texture);
+ to->texture = 0;
+ }
+ free(to);
+}
+
+/**
+ * gl_create_framebuffer_object:
+ * @target: the target to which the texture is bound
+ * @texture: the GL texture to hold the framebuffer
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates an FBO with the specified texture and size.
+ *
+ * Return value: the newly created #GLFramebufferObject, or %NULL if
+ * an error occurred
+ */
+GLFramebufferObject *
+gl_create_framebuffer_object(
+ GLenum target,
+ GLuint texture,
+ unsigned int width,
+ unsigned int height
+)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+ GLFramebufferObject *fbo;
+ GLenum status;
+
+ if (!gl_vtable || !gl_vtable->has_framebuffer_object)
+ return NULL;
+
+ fbo = calloc(1, sizeof(*fbo));
+ if (!fbo)
+ return NULL;
+
+ fbo->width = width;
+ fbo->height = height;
+ fbo->fbo = 0;
+ fbo->is_bound = 0;
+
+ gl_vtable->gl_gen_framebuffers(1, &fbo->fbo);
+ gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo);
+ gl_vtable->gl_framebuffer_texture_2d(
+ GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ target, texture,
+ 0
+ );
+
+ status = gl_vtable->gl_check_framebuffer_status(GL_DRAW_FRAMEBUFFER_EXT);
+ gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ goto error;
+ return fbo;
+
+error:
+ gl_destroy_framebuffer_object(fbo);
+ return NULL;
+}
+
+/**
+ * gl_destroy_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Destroys the @fbo object.
+ */
+void
+gl_destroy_framebuffer_object(GLFramebufferObject *fbo)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ if (!fbo)
+ return;
+
+ gl_unbind_framebuffer_object(fbo);
+
+ if (fbo->fbo) {
+ gl_vtable->gl_delete_framebuffers(1, &fbo->fbo);
+ fbo->fbo = 0;
+ }
+ free(fbo);
+}
+
+/**
+ * gl_bind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Binds @fbo object.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_bind_framebuffer_object(GLFramebufferObject *fbo)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+ const unsigned int width = fbo->width;
+ const unsigned int height = fbo->height;
+
+ const unsigned int attribs = (GL_VIEWPORT_BIT |
+ GL_CURRENT_BIT |
+ GL_ENABLE_BIT |
+ GL_TEXTURE_BIT |
+ GL_COLOR_BUFFER_BIT);
+
+ if (fbo->is_bound)
+ return 1;
+
+ gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, fbo->fbo);
+ glPushAttrib(attribs);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glViewport(0, 0, width, height);
+ glTranslatef(-1.0f, -1.0f, 0.0f);
+ glScalef(2.0f / width, 2.0f / height, 1.0f);
+
+ fbo->is_bound = 1;
+ return 1;
+}
+
+/**
+ * gl_unbind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Releases @fbo object.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_unbind_framebuffer_object(GLFramebufferObject *fbo)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ if (!fbo->is_bound)
+ return 1;
+
+ glPopAttrib();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ gl_vtable->gl_bind_framebuffer(GL_FRAMEBUFFER_EXT, 0);
+
+ fbo->is_bound = 0;
+ return 1;
+}
+
+/**
+ * gl_create_shader_object:
+ * @shader_fp: the shader program source
+ * @shader_fp_length: the total length of the shader program source
+ *
+ * Creates a shader object from the specified program source.
+ *
+ * Return value: the newly created #GLShaderObject, or %NULL if
+ * an error occurred
+ */
+GLShaderObject *
+gl_create_shader_object(
+ const char **shader_fp,
+ unsigned int shader_fp_length
+)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+ GLShaderObject *so;
+
+ if (!gl_vtable || !gl_vtable->has_fragment_program)
+ return NULL;
+
+ if (!shader_fp || !shader_fp_length)
+ return NULL;
+
+ so = calloc(1, sizeof(*so));
+ if (!so)
+ return NULL;
+
+ char *shader = malloc(shader_fp_length + 1);
+ if (!shader)
+ goto error;
+ string_array_to_char_array(shader, shader_fp);
+
+ glEnable(GL_FRAGMENT_PROGRAM);
+ gl_vtable->gl_gen_programs(1, &so->shader);
+ gl_vtable->gl_bind_program(GL_FRAGMENT_PROGRAM, so->shader);
+ gl_vtable->gl_program_string(
+ GL_FRAGMENT_PROGRAM,
+ GL_PROGRAM_FORMAT_ASCII,
+ shader_fp_length, shader
+ );
+ free(shader);
+
+ GLint error_position;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &error_position);
+ if (error_position != -1) {
+ D(bug("Error while loading fragment program: %s\n",
+ glGetString(GL_PROGRAM_ERROR_STRING)));
+ goto error;
+ }
+
+ GLint is_native;
+ gl_vtable->gl_get_program_iv(
+ GL_FRAGMENT_PROGRAM,
+ GL_PROGRAM_UNDER_NATIVE_LIMITS,
+ &is_native
+ );
+ if (!is_native) {
+ D(bug("Fragment program is not native\n"));
+ goto error;
+ }
+ gl_vtable->gl_bind_program(GL_FRAGMENT_PROGRAM, 0);
+ glDisable(GL_FRAGMENT_PROGRAM);
+ return so;
+
+error:
+ gl_destroy_shader_object(so);
+ return NULL;
+}
+
+/**
+ * gl_destroy_shader_object:
+ * @fbo: a #GLShaderObject
+ *
+ * Destroys the shader program @so.
+ */
+void
+gl_destroy_shader_object(GLShaderObject *so)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ if (!so)
+ return;
+
+ gl_unbind_shader_object(so);
+
+ if (so->shader) {
+ gl_vtable->gl_delete_programs(1, &so->shader);
+ so->shader = 0;
+ }
+ free(so);
+}
+
+/**
+ * gl_bind_shader_object:
+ * @fbo: a #GLShaderObject
+ *
+ * Binds @so shader program.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_bind_shader_object(GLShaderObject *so)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ if (so->is_bound)
+ return 1;
+
+ glEnable(GL_FRAGMENT_PROGRAM);
+ gl_vtable->gl_bind_program(GL_FRAGMENT_PROGRAM, so->shader);
+
+ so->is_bound = 1;
+ return 1;
+}
+
+/**
+ * gl_unbind_shader_object:
+ * @fbo: a #GLShaderObject
+ *
+ * Releases @so shader program.
+ *
+ * Return value: 1 on success
+ */
+int
+gl_unbind_shader_object(GLShaderObject *so)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ if (!so->is_bound)
+ return 1;
+
+ gl_vtable->gl_bind_program(GL_FRAGMENT_PROGRAM, 0);
+ glDisable(GL_FRAGMENT_PROGRAM);
+
+ so->is_bound = 0;
+ return 1;
+}
diff --git a/src/utils_glx.h b/src/utils_glx.h
new file mode 100644
index 0000000..e6f9726
--- /dev/null
+++ b/src/utils_glx.h
@@ -0,0 +1,233 @@
+/*
+ * utils_glx.h - GLX utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UTILS_GLX_H
+#define UTILS_GLX_H
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+
+#ifndef GL_FRAMEBUFFER_BINDING
+#define GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
+#endif
+#ifndef GL_FRAGMENT_PROGRAM
+#define GL_FRAGMENT_PROGRAM GL_FRAGMENT_PROGRAM_ARB
+#endif
+#ifndef GL_PROGRAM_FORMAT_ASCII
+#define GL_PROGRAM_FORMAT_ASCII GL_PROGRAM_FORMAT_ASCII_ARB
+#endif
+#ifndef GL_PROGRAM_ERROR_POSITION
+#define GL_PROGRAM_ERROR_POSITION GL_PROGRAM_ERROR_POSITION_ARB
+#endif
+#ifndef GL_PROGRAM_ERROR_STRING
+#define GL_PROGRAM_ERROR_STRING GL_PROGRAM_ERROR_STRING_ARB
+#endif
+#ifndef GL_PROGRAM_UNDER_NATIVE_LIMITS
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
+#endif
+
+const char *
+gl_get_error_string(GLenum error)
+ attribute_hidden;
+
+void
+gl_purge_errors(void)
+ attribute_hidden;
+
+int
+gl_check_error(void)
+ attribute_hidden;
+
+int
+gl_get_param(GLenum param, unsigned int *pval)
+ attribute_hidden;
+
+int
+gl_get_texture_param(GLenum target, GLenum param, unsigned int *pval)
+ attribute_hidden;
+
+void
+gl_set_bgcolor(uint32_t color)
+ attribute_hidden;
+
+void
+gl_set_texture_scaling(GLenum target, GLenum scale)
+ attribute_hidden;
+
+void
+gl_set_texture_wrapping(GLenum target, GLenum wrap)
+ attribute_hidden;
+
+void
+gl_resize(unsigned int width, unsigned int height)
+ attribute_hidden;
+
+typedef struct _GLContextState GLContextState;
+struct _GLContextState {
+ Display *display;
+ Window window;
+ XVisualInfo *visual;
+ GLXContext context;
+};
+
+GLContextState *
+gl_create_context(Display *dpy, int screen, GLContextState *parent)
+ attribute_hidden;
+
+void
+gl_destroy_context(GLContextState *cs)
+ attribute_hidden;
+
+void
+gl_init_context(GLContextState *cs)
+ attribute_hidden;
+
+void
+gl_get_current_context(GLContextState *cs)
+ attribute_hidden;
+
+int
+gl_set_current_context(GLContextState *new_cs, GLContextState *old_cs)
+ attribute_hidden;
+
+void
+gl_set_current_context_cache(int is_enabled)
+ attribute_hidden;
+
+void
+gl_swap_buffers(GLContextState *cs)
+ attribute_hidden;
+
+typedef struct _GLVTable GLVTable;
+struct _GLVTable {
+ PFNGLGENFRAMEBUFFERSEXTPROC gl_gen_framebuffers;
+ PFNGLDELETEFRAMEBUFFERSEXTPROC gl_delete_framebuffers;
+ PFNGLBINDFRAMEBUFFEREXTPROC gl_bind_framebuffer;
+ PFNGLGENRENDERBUFFERSEXTPROC gl_gen_renderbuffers;
+ PFNGLDELETERENDERBUFFERSEXTPROC gl_delete_renderbuffers;
+ PFNGLBINDRENDERBUFFEREXTPROC gl_bind_renderbuffer;
+ PFNGLRENDERBUFFERSTORAGEEXTPROC gl_renderbuffer_storage;
+ PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC gl_framebuffer_renderbuffer;
+ PFNGLFRAMEBUFFERTEXTURE2DEXTPROC gl_framebuffer_texture_2d;
+ PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC gl_check_framebuffer_status;
+ PFNGLGENPROGRAMSARBPROC gl_gen_programs;
+ PFNGLDELETEPROGRAMSARBPROC gl_delete_programs;
+ PFNGLBINDPROGRAMARBPROC gl_bind_program;
+ PFNGLPROGRAMSTRINGARBPROC gl_program_string;
+ PFNGLGETPROGRAMIVARBPROC gl_get_program_iv;
+ PFNGLPROGRAMLOCALPARAMETER4FVARBPROC gl_program_local_parameter_4fv;
+ PFNGLACTIVETEXTUREPROC gl_active_texture;
+ PFNGLMULTITEXCOORD2FPROC gl_multi_tex_coord_2f;
+ unsigned int has_texture_non_power_of_two : 1;
+ unsigned int has_texture_rectangle : 1;
+ unsigned int has_texture_float : 1;
+ unsigned int has_framebuffer_object : 1;
+ unsigned int has_fragment_program : 1;
+ unsigned int has_multitexture : 1;
+ unsigned int has_gpu_shader5 : 1;
+};
+
+GLVTable *
+gl_get_vtable(void)
+ attribute_hidden;
+
+typedef struct _GLTextureObject GLTextureObject;
+struct _GLTextureObject {
+ GLenum target;
+ GLenum format;
+ GLuint texture;
+ unsigned int width;
+ unsigned int height;
+};
+
+GLuint
+gl_create_texture(
+ GLenum target,
+ GLenum format,
+ unsigned int width,
+ unsigned int height
+) attribute_hidden;
+
+GLTextureObject *
+gl_create_texture_object(
+ GLenum target,
+ GLenum format,
+ unsigned int width,
+ unsigned int height
+) attribute_hidden;
+
+void
+gl_destroy_texture_object(GLTextureObject *to)
+ attribute_hidden;
+
+typedef struct _GLFramebufferObject GLFramebufferObject;
+struct _GLFramebufferObject {
+ unsigned int width;
+ unsigned int height;
+ GLuint fbo;
+ unsigned int is_bound : 1;
+};
+
+GLFramebufferObject *
+gl_create_framebuffer_object(
+ GLenum target,
+ GLuint texture,
+ unsigned int width,
+ unsigned int height
+) attribute_hidden;
+
+void
+gl_destroy_framebuffer_object(GLFramebufferObject *fbo)
+ attribute_hidden;
+
+int
+gl_bind_framebuffer_object(GLFramebufferObject *fbo)
+ attribute_hidden;
+
+int
+gl_unbind_framebuffer_object(GLFramebufferObject *fbo)
+ attribute_hidden;
+
+typedef struct _GLShaderObject GLShaderObject;
+struct _GLShaderObject {
+ GLuint shader;
+ unsigned int is_bound : 1;
+};
+
+GLShaderObject *
+gl_create_shader_object(
+ const char **shader_fp,
+ unsigned int shader_fp_length
+) attribute_hidden;
+
+void
+gl_destroy_shader_object(GLShaderObject *so)
+ attribute_hidden;
+
+int
+gl_bind_shader_object(GLShaderObject *so)
+ attribute_hidden;
+
+int
+gl_unbind_shader_object(GLShaderObject *so)
+ attribute_hidden;
+
+#endif /* UTILS_GLX_H */
diff --git a/src/utils_x11.c b/src/utils_x11.c
new file mode 100644
index 0000000..c4ceeba
--- /dev/null
+++ b/src/utils_x11.c
@@ -0,0 +1,184 @@
+/*
+ * utils_x11.c - X11 utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include <X11/Xutil.h>
+#include "utils_x11.h"
+#include "utils.h"
+
+// X error trap
+static int x11_error_code = 0;
+static int (*old_error_handler)(Display *, XErrorEvent *);
+
+static int error_handler(Display *dpy, XErrorEvent *error)
+{
+ x11_error_code = error->error_code;
+ return 0;
+}
+
+void x11_trap_errors(void)
+{
+ x11_error_code = 0;
+ old_error_handler = XSetErrorHandler(error_handler);
+}
+
+int x11_untrap_errors(void)
+{
+ XSetErrorHandler(old_error_handler);
+ return x11_error_code;
+}
+
+// X window management
+static const int x11_event_mask = (KeyPressMask |
+ KeyReleaseMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ PointerMotionMask |
+ EnterWindowMask |
+ ExposureMask |
+ StructureNotifyMask);
+
+/**
+ * x11_create_window:
+ * @dpy: an X11 #Display
+ * @w: the requested width, in pixels
+ * @h: the requested height, in pixels
+ * @vis: the request visual
+ * @cmap: the request colormap
+ *
+ * Creates a border-less window with the specified dimensions. If @vis
+ * is %NULL, the default visual for @display will be used. If @cmap is
+ * %None, no specific colormap will be bound to the window. Also note
+ * the default background color is black.
+ *
+ * Return value: the newly created X #Window.
+ */
+
+Window
+x11_create_window(
+ Display *dpy,
+ unsigned int w,
+ unsigned int h,
+ Visual *vis,
+ Colormap cmap
+)
+{
+ Window rootwin, win;
+ int screen, depth;
+ XSetWindowAttributes xswa;
+ unsigned long xswa_mask;
+ XWindowAttributes wattr;
+ unsigned long black_pixel, white_pixel;
+
+ screen = DefaultScreen(dpy);
+ rootwin = RootWindow(dpy, screen);
+ black_pixel = BlackPixel(dpy, screen);
+ white_pixel = WhitePixel(dpy, screen);
+
+ if (!vis)
+ vis = DefaultVisual(dpy, screen);
+
+ XGetWindowAttributes(dpy, rootwin, &wattr);
+ depth = wattr.depth;
+ if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
+ depth = 24;
+
+ xswa_mask = CWBorderPixel | CWBackPixel;
+ xswa.border_pixel = black_pixel;
+ xswa.background_pixel = black_pixel;
+
+ if (cmap) {
+ xswa_mask |= CWColormap;
+ xswa.colormap = cmap;
+ }
+
+ win = XCreateWindow(
+ dpy,
+ rootwin,
+ 0, 0, w, h,
+ 0,
+ depth,
+ InputOutput,
+ vis,
+ xswa_mask, &xswa
+ );
+ if (!win)
+ return None;
+
+ XSelectInput(dpy, win, x11_event_mask);
+ return win;
+}
+
+int
+x11_get_geometry(
+ Display *dpy,
+ Drawable drawable,
+ int *px,
+ int *py,
+ unsigned int *pwidth,
+ unsigned int *pheight
+)
+{
+ Window rootwin;
+ int x, y;
+ unsigned int width, height, border_width, depth;
+
+ x11_trap_errors();
+ XGetGeometry(
+ dpy,
+ drawable,
+ &rootwin,
+ &x, &y, &width, &height,
+ &border_width,
+ &depth
+ );
+ if (x11_untrap_errors())
+ return 0;
+
+ if (px) *px = x;
+ if (py) *py = y;
+ if (pwidth) *pwidth = width;
+ if (pheight) *pheight = height;
+ return 1;
+}
+
+void x11_wait_event(Display *dpy, Window w, int type)
+{
+ XEvent e;
+ while (!XCheckTypedWindowEvent(dpy, w, type, &e))
+ delay_usec(10);
+}
+
+// Returns X window background color at specified location
+int
+x11_get_window_colorkey(Display *dpy, Window w, int x, int y, unsigned int *ck)
+{
+ XClearArea(dpy, w, x, y, 1, 1, False);
+
+ XImage *img = XGetImage(dpy, w, x, y, 1, 1, AllPlanes, ZPixmap);
+ if (img == NULL)
+ return -1;
+
+ if (ck)
+ *ck = XGetPixel(img, 0, 0);
+
+ XDestroyImage(img);
+ return 0;
+}
diff --git a/src/utils_x11.h b/src/utils_x11.h
new file mode 100644
index 0000000..43c96d7
--- /dev/null
+++ b/src/utils_x11.h
@@ -0,0 +1,59 @@
+/*
+ * utils_x11.h - X11 utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef UTILS_X11_H
+#define UTILS_X11_H
+
+#include "config.h"
+#include <X11/Xlib.h>
+
+void x11_trap_errors(void)
+ attribute_hidden;
+
+int x11_untrap_errors(void)
+ attribute_hidden;
+
+Window
+x11_create_window(
+ Display *dpy,
+ unsigned int w,
+ unsigned int h,
+ Visual *vis,
+ Colormap cmap
+) attribute_hidden;
+
+int
+x11_get_geometry(
+ Display *dpy,
+ Drawable drawable,
+ int *px,
+ int *py,
+ unsigned int *pwidth,
+ unsigned int *pheight
+) attribute_hidden;
+
+void x11_wait_event(Display *dpy, Window w, int type)
+ attribute_hidden;
+
+int
+x11_get_window_colorkey(Display *dpy, Window w, int x, int y, unsigned int *ck)
+ attribute_hidden;
+
+#endif /* UTILS_X11_H */
diff --git a/src/vaapi_compat.h b/src/vaapi_compat.h
new file mode 100644
index 0000000..08adef9
--- /dev/null
+++ b/src/vaapi_compat.h
@@ -0,0 +1,64 @@
+/*
+ * vaapi_compat.h - VA-API compatibility glue
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef VAAPI_COMPAT_H
+#define VAAPI_COMPAT_H
+
+#ifndef VA_INVALID_ID
+#define VA_INVALID_ID 0xffffffff
+#endif
+#ifndef VA_INVALID_BUFFER
+#define VA_INVALID_BUFFER VA_INVALID_ID
+#endif
+#ifndef VA_INVALID_SURFACE
+#define VA_INVALID_SURFACE VA_INVALID_ID
+#endif
+#ifndef VA_STATUS_ERROR_UNIMPLEMENTED
+#define VA_STATUS_ERROR_UNIMPLEMENTED 0x00000014
+#endif
+#ifndef VA_DISPLAY_X11
+#define VA_DISPLAY_X11 1
+#endif
+#ifndef VA_DISPLAY_GLX
+#define VA_DISPLAY_GLX 2
+#endif
+#ifndef VA_FILTER_SCALING_DEFAULT
+#define VA_FILTER_SCALING_DEFAULT 0x00000000
+#endif
+#ifndef VA_FILTER_SCALING_FAST
+#define VA_FILTER_SCALING_FAST 0x00000100
+#endif
+#ifndef VA_FILTER_SCALING_HQ
+#define VA_FILTER_SCALING_HQ 0x00000200
+#endif
+#ifndef VA_FILTER_SCALING_NL_ANAMORPHIC
+#define VA_FILTER_SCALING_NL_ANAMORPHIC 0x00000300
+#endif
+#ifndef VA_FILTER_SCALING_MASK
+#define VA_FILTER_SCALING_MASK 0x00000f00
+#endif
+
+#if VA_CHECK_VERSION(0,31,1)
+typedef void *VADrawable;
+#else
+typedef Drawable VADrawable;
+#endif
+
+#endif /* VAAPI_COMPAT_H */
diff --git a/src/xvba_buffer.c b/src/xvba_buffer.c
new file mode 100644
index 0000000..4facbbf
--- /dev/null
+++ b/src/xvba_buffer.c
@@ -0,0 +1,946 @@
+/*
+ * xvba_buffer.c - XvBA backend for VA-API (VA buffers)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_buffer.h"
+#include "xvba_driver.h"
+#include "xvba_decode.h"
+#include "xvba_video.h"
+#include "xvba_dump.h"
+#include "fglrxinfo.h"
+#include <math.h>
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Definitions for XVBAPictureDescriptor.picture_structure field
+enum {
+ PICT_TOP_FIELD = 0,
+ PICT_BOTTOM_FIELD = 1,
+ PICT_FRAME = 3
+};
+
+// Reconstruct H.264 level_idc syntax element
+static int
+vaapi_h264_get_level(
+ VAPictureParameterBufferH264 *pic_param,
+ unsigned int picture_width,
+ unsigned int picture_height
+)
+{
+ const unsigned int PicWidthInMbs = pic_param->picture_width_in_mbs_minus1 + 1;
+ const unsigned int FrameHeightInMbs = (picture_height + 15) / 16;
+
+ /* Table A-1. Level limits */
+ static const struct {
+ int level;
+ unsigned int MaxMBPS;
+ unsigned int MaxFS;
+ unsigned int MaxDPBx2;
+ unsigned int MaxBR;
+ unsigned int MaxCPB;
+ }
+ map[] = {
+ { 10, 1485, 99, 297, 64, 175 },
+ { 9, 1485, 99, 297, 128, 350 },
+ { 11, 3000, 396, 675, 192, 500 },
+ { 12, 6000, 396, 1782, 384, 1000 },
+ { 13, 11880, 396, 1782, 768, 2000 },
+ { 20, 11880, 396, 1782, 2000, 2000 },
+ { 21, 19800, 792, 3564, 4000, 4000 },
+ { 22, 20250, 1620, 6075, 4000, 4000 },
+ { 30, 40500, 1620, 6075, 10000, 10000 },
+ { 31, 108000, 3600, 13500, 14000, 14000 },
+ { 32, 216000, 5120, 15360, 20000, 20000 },
+ { 40, 245760, 8192, 24576, 20000, 25000 },
+ { 41, 245760, 8192, 24576, 50000, 62500 },
+ { 42, 522240, 8704, 26112, 50000, 62500 },
+ { 50, 589824, 22080, 82800, 135000, 135000 },
+ { 51, 983040, 36864, 138240, 240000, 240000 },
+ { -1, }
+ };
+
+ int i;
+ for (i = 0; map[i].level >= 0; i++) {
+ if (map[i].MaxFS < PicWidthInMbs * FrameHeightInMbs) /* A.3.1 (e) */
+ continue;
+ const unsigned int sqrt_8xMaxFS = sqrt(8.0 * map[i].MaxFS);
+ if (sqrt_8xMaxFS < PicWidthInMbs) /* A.3.1 (f) */
+ continue;
+ if (sqrt_8xMaxFS < FrameHeightInMbs) /* A.3.1 (g) */
+ continue;
+ const unsigned int max_ref_frames = map[i].MaxDPBx2 * 512 / (PicWidthInMbs * FrameHeightInMbs * 384);
+ if (max_ref_frames < pic_param->num_ref_frames) /* A.3.1 (h) */
+ continue;
+ return map[i].level;
+ }
+ D(bug("vaapi_h264_get_level(): could not reconstruct level\n"));
+ return 0;
+}
+
+// Reconstruct picture_structure
+static int
+vaapi_h264_get_picture_structure(VAPictureParameterBufferH264 *pic_param)
+{
+ int picture_structure;
+ switch (pic_param->CurrPic.flags & (VA_PICTURE_H264_TOP_FIELD |
+ VA_PICTURE_H264_BOTTOM_FIELD)) {
+ case VA_PICTURE_H264_TOP_FIELD:
+ picture_structure = PICT_TOP_FIELD;
+ break;
+ case VA_PICTURE_H264_BOTTOM_FIELD:
+ picture_structure = PICT_BOTTOM_FIELD;
+ break;
+ default: /* 0 || VA_PICTURE_H264_TOP_FIELD|VA_PICTURE_H264_BOTTOM_FIELD */
+ picture_structure = PICT_FRAME;
+ break;
+ }
+ return picture_structure;
+}
+
+// Reconstruct VC-1 LEVEL syntax element
+static int
+vaapi_vc1_get_level_advanced(
+ VAPictureParameterBufferVC1 *pic_param,
+ unsigned int picture_width,
+ unsigned int picture_height
+)
+{
+ /* XXX: use CODED_WIDTH and CODED_HEIGHT syntax elements instead? */
+ const unsigned int mb_width = (picture_width + 15) / 16;
+ const unsigned int mb_height = (picture_height + 15) / 16;
+ const unsigned int MB_f = mb_width * mb_height;
+ const unsigned int MB_s = MB_f * 30; /* default to 30 Hz */
+
+ /* Table 253. Limitations of profiles and levels */
+ static const struct {
+ int level;
+ unsigned int MB_s;
+ unsigned int MB_f;
+ int interlace;
+ unsigned int Rmax;
+ unsigned int Bmax;
+ }
+ map[] = {
+ { 0, 11880, 396, 0, 2000, 250 },
+ { 1, 48600, 1620, 1, 10000, 1250 },
+ { 2, 110400, 3680, 1, 20000, 2500 },
+ { 3, 245760, 8192, 1, 45000, 5500 },
+ { 4, 491520, 16384, 1, 135000, 16500 },
+ { -1, }
+ };
+
+ int i;
+ for (i = 0; map[i].level >= 0; i++) {
+ if (pic_param->sequence_fields.bits.interlace && !map[i].interlace)
+ continue;
+ if (map[i].MB_f < MB_f)
+ continue;
+ if (map[i].MB_s < MB_s)
+ continue;
+ return map[i].level;
+ }
+ D(bug("vaapi_vc1_get_level_advanced(): could not reconstruct level\n"));
+ return 0;
+}
+
+// Reconstruct picture_structure
+static int
+vaapi_vc1_get_picture_structure(VAPictureParameterBufferVC1 *pic_param)
+{
+ int picture_structure;
+ if (pic_param->sequence_fields.bits.interlace &&
+ pic_param->picture_fields.bits.frame_coding_mode == 3) {
+ /* Field-Interlace mode */
+ if (pic_param->picture_fields.bits.is_first_field &&
+ pic_param->picture_fields.bits.top_field_first)
+ picture_structure = PICT_TOP_FIELD;
+ else
+ picture_structure = PICT_BOTTOM_FIELD;
+ }
+ else
+ picture_structure = PICT_FRAME;
+ return picture_structure;
+}
+
+// Create VA buffer object
+object_buffer_p
+create_va_buffer(
+ xvba_driver_data_t *driver_data,
+ VAContextID context,
+ VABufferType buffer_type,
+ unsigned int num_elements,
+ unsigned int size
+)
+{
+ VABufferID buffer_id;
+ object_buffer_p obj_buffer;
+
+ buffer_id = object_heap_allocate(&driver_data->buffer_heap);
+ if (buffer_id == VA_INVALID_BUFFER)
+ return NULL;
+
+ obj_buffer = XVBA_BUFFER(buffer_id);
+ if (!obj_buffer)
+ return NULL;
+
+ obj_buffer->va_context = context;
+ obj_buffer->type = buffer_type;
+ obj_buffer->max_num_elements = num_elements;
+ obj_buffer->num_elements = num_elements;
+ obj_buffer->buffer_size = size * num_elements;
+ obj_buffer->buffer_data = malloc(obj_buffer->buffer_size);
+ obj_buffer->mtime = 0;
+
+ if (!obj_buffer->buffer_data) {
+ destroy_va_buffer(driver_data, obj_buffer);
+ return NULL;
+ }
+ return obj_buffer;
+}
+
+// Destroy VA buffer object
+void
+destroy_va_buffer(
+ xvba_driver_data_t *driver_data,
+ object_buffer_p obj_buffer
+)
+{
+ if (!obj_buffer)
+ return;
+
+ if (obj_buffer->buffer_data) {
+ free(obj_buffer->buffer_data);
+ obj_buffer->buffer_data = NULL;
+ }
+ object_heap_free(&driver_data->buffer_heap, &obj_buffer->base);
+}
+
+// Destroy VA buffer objects stored in VA context
+void
+destroy_va_buffers(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context
+)
+{
+ unsigned int i;
+
+ for (i = 0; i < obj_context->va_buffers_count; i++) {
+ object_buffer_p obj_buffer = XVBA_BUFFER(obj_context->va_buffers[i]);
+ if (!obj_buffer)
+ continue;
+ destroy_va_buffer(driver_data, obj_buffer);
+ }
+ obj_context->va_buffers_count = 0;
+}
+
+// Determines whether BUFFER is queued for decoding
+int
+is_queued_buffer(
+ xvba_driver_data_t *driver_data,
+ object_buffer_p obj_buffer
+)
+{
+ object_context_p obj_context = XVBA_CONTEXT(obj_buffer->va_context);
+ if (!obj_context)
+ return 0;
+
+ unsigned int i;
+ for (i = 0; i < obj_context->va_buffers_count; i++) {
+ if (obj_context->va_buffers[i] == obj_buffer->base.id)
+ return 1;
+ }
+ return 0;
+}
+
+// Translate no buffer
+static int
+translate_nothing(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ return 1;
+}
+
+// Translate VASliceDataBuffer
+static int
+translate_VASliceDataBuffer(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ /* Slice data buffers are copied in VASliceParameterBuffer
+ translation routines */
+ return 1;
+}
+
+// Translate VAPictureParameterBufferMPEG2
+static int
+translate_VAPictureParameterBufferMPEG2(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ return 0;
+}
+
+// Translate VAIQMatrixBufferMPEG2
+static int
+translate_VAIQMatrixBufferMPEG2(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ return 0;
+}
+
+// Translate VASliceParameterBufferMPEG2
+static int
+translate_VASliceParameterBufferMPEG2(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+ )
+{
+ return 0;
+}
+
+// Translate VAPictureParameterBufferH264
+static int
+translate_VAPictureParameterBufferH264(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ VAPictureParameterBufferH264 * const pic_param = obj_buffer->buffer_data;
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return 0;
+
+ object_config_p obj_config = XVBA_CONFIG(obj_context->va_config);
+ if (!obj_config)
+ return 0;
+
+ int profile, level;
+ switch (obj_config->profile) {
+ case VAProfileH264Baseline:
+ profile = XVBA_H264_BASELINE;
+ break;
+ case VAProfileH264Main:
+ profile = XVBA_H264_MAIN;
+ break;
+ case VAProfileH264High:
+ profile = XVBA_H264_HIGH;
+ break;
+ default:
+ D(bug("translate_VAPictureParameterBufferH264(): invalid profile\n"));
+ return 0;
+ }
+
+ level = vaapi_h264_get_level(
+ pic_param,
+ obj_context->picture_width,
+ obj_context->picture_height
+ );
+
+ /* Check for H.264 content over HP@L4.1 */
+ unsigned int num_ref_frames = pic_param->num_ref_frames;
+ if (profile == XVBA_H264_HIGH && level > 41) {
+ if (!driver_data->warn_h264_over_hp_l41) {
+ driver_data->warn_h264_over_hp_l41 = 1;
+ xvba_information_message(
+ "driver does not support H.264 content over HP@L4.1. "
+ "Please upgrade.\n"
+ );
+ }
+
+ /* Use fail-safe values (lower ref frames) */
+ const unsigned int mbw = pic_param->picture_width_in_mbs_minus1 + 1;
+ const unsigned int mbh = (obj_context->picture_height + 15) / 16;
+ const unsigned int max_ref_frames = 12288 * 1024 / (mbw * mbh * 384);
+ if (max_ref_frames < num_ref_frames)
+ num_ref_frames = max_ref_frames;
+ }
+
+ XVBABufferDescriptor * const xvba_buffer = obj_surface->pic_desc_buffer;
+ ASSERT(xvba_buffer);
+ if (!xvba_buffer)
+ return 0;
+
+ XVBAPictureDescriptor * const pic_desc = xvba_buffer->bufferXVBA;
+ memset(pic_desc, 0, sizeof(*pic_desc));
+
+ pic_desc->past_surface = NULL;
+ pic_desc->future_surface = NULL;
+ pic_desc->profile = profile;
+ pic_desc->level = level;
+ pic_desc->width_in_mb = 1 + pic_param->picture_width_in_mbs_minus1;
+ pic_desc->height_in_mb = 1 + pic_param->picture_height_in_mbs_minus1;
+ pic_desc->picture_structure = vaapi_h264_get_picture_structure(pic_param);
+ pic_desc->sps_info.flags = 0; /* reset all bits */
+ pic_desc->sps_info.avc.residual_colour_transform_flag = pic_param->seq_fields.bits.residual_colour_transform_flag;
+ pic_desc->sps_info.avc.delta_pic_always_zero_flag = pic_param->seq_fields.bits.delta_pic_order_always_zero_flag;
+ pic_desc->sps_info.avc.gaps_in_frame_num_value_allowed_flag = pic_param->seq_fields.bits.gaps_in_frame_num_value_allowed_flag;
+ pic_desc->sps_info.avc.frame_mbs_only_flag = pic_param->seq_fields.bits.frame_mbs_only_flag;
+ pic_desc->sps_info.avc.mb_adaptive_frame_field_flag = pic_param->seq_fields.bits.mb_adaptive_frame_field_flag;
+ pic_desc->sps_info.avc.direct_8x8_inference_flag = pic_param->seq_fields.bits.direct_8x8_inference_flag;
+ pic_desc->chroma_format = pic_param->seq_fields.bits.chroma_format_idc;
+ pic_desc->avc_bit_depth_luma_minus8 = pic_param->bit_depth_luma_minus8;
+ pic_desc->avc_bit_depth_chroma_minus8 = pic_param->bit_depth_chroma_minus8;
+ pic_desc->avc_log2_max_frame_num_minus4 = pic_param->seq_fields.bits.log2_max_frame_num_minus4;
+ pic_desc->avc_pic_order_cnt_type = pic_param->seq_fields.bits.pic_order_cnt_type;
+ pic_desc->avc_log2_max_pic_order_cnt_lsb_minus4 = pic_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4;
+ pic_desc->avc_num_ref_frames = num_ref_frames;
+ pic_desc->pps_info.flags = 0; /* reset all bits */
+ pic_desc->pps_info.avc.entropy_coding_mode_flag = pic_param->pic_fields.bits.entropy_coding_mode_flag;
+ pic_desc->pps_info.avc.pic_order_present_flag = pic_param->pic_fields.bits.pic_order_present_flag;
+ pic_desc->pps_info.avc.weighted_pred_flag = pic_param->pic_fields.bits.weighted_pred_flag;
+ pic_desc->pps_info.avc.weighted_bipred_idc = pic_param->pic_fields.bits.weighted_bipred_idc;
+ pic_desc->pps_info.avc.deblocking_filter_control_present_flag = pic_param->pic_fields.bits.deblocking_filter_control_present_flag;
+ pic_desc->pps_info.avc.constrained_intra_pred_flag = pic_param->pic_fields.bits.constrained_intra_pred_flag;
+ pic_desc->pps_info.avc.redundant_pic_cnt_present_flag = pic_param->pic_fields.bits.redundant_pic_cnt_present_flag;
+ pic_desc->pps_info.avc.transform_8x8_mode_flag = pic_param->pic_fields.bits.transform_8x8_mode_flag;
+ pic_desc->avc_num_slice_groups_minus1 = pic_param->num_slice_groups_minus1;
+ pic_desc->avc_slice_group_map_type = pic_param->slice_group_map_type;
+ pic_desc->avc_pic_init_qp_minus26 = pic_param->pic_init_qp_minus26;
+ pic_desc->avc_pic_init_qs_minus26 = pic_param->pic_init_qs_minus26;
+ pic_desc->avc_chroma_qp_index_offset = pic_param->chroma_qp_index_offset;
+ pic_desc->avc_second_chroma_qp_index_offset = pic_param->second_chroma_qp_index_offset;
+ pic_desc->avc_slice_group_change_rate_minus1 = pic_param->slice_group_change_rate_minus1;
+ pic_desc->avc_frame_num = pic_param->frame_num;
+ pic_desc->avc_reference = pic_param->pic_fields.bits.reference_pic_flag;
+
+ pic_desc->avc_curr_field_order_cnt_list[0] = pic_param->CurrPic.TopFieldOrderCnt;
+ pic_desc->avc_curr_field_order_cnt_list[1] = pic_param->CurrPic.BottomFieldOrderCnt;
+
+ xvba_buffer->data_size_in_buffer = sizeof(*pic_desc);
+ return 1;
+}
+
+// Translate VAIQMatrixBufferH264
+static int
+translate_VAIQMatrixBufferH264(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ VAIQMatrixBufferH264 * const iq_matrix = obj_buffer->buffer_data;
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_buffer = obj_surface->iq_matrix_buffer;
+ if (!xvba_buffer)
+ return 0;
+
+ XVBAQuantMatrixAvc * const qm = xvba_buffer->bufferXVBA;
+ int i, j;
+
+ if (sizeof(qm->bScalingLists4x4) == sizeof(iq_matrix->ScalingList4x4))
+ memcpy(qm->bScalingLists4x4, iq_matrix->ScalingList4x4,
+ sizeof(qm->bScalingLists4x4));
+ else {
+ for (j = 0; j < 6; j++) {
+ for (i = 0; i < 16; i++)
+ qm->bScalingLists4x4[j][i] = iq_matrix->ScalingList4x4[j][i];
+ }
+ }
+
+ if (sizeof(qm->bScalingLists8x8) == sizeof(iq_matrix->ScalingList8x8))
+ memcpy(qm->bScalingLists8x8, iq_matrix->ScalingList8x8,
+ sizeof(qm->bScalingLists8x8));
+ else {
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < 64; i++)
+ qm->bScalingLists8x8[j][i] = iq_matrix->ScalingList8x8[j][i];
+ }
+ }
+
+ xvba_buffer->data_size_in_buffer = sizeof(*qm);
+ return 1;
+}
+
+// Translate VASliceParameterBufferH264
+static int
+translate_VASliceParameterBufferH264(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ VASliceParameterBufferH264 * const slice_param = obj_buffer->buffer_data;
+
+ /* XXX: we don't handle partial slice data buffers yet */
+ if (slice_param->slice_data_flag != VA_SLICE_DATA_FLAG_ALL) {
+ D(bug("partial slice data buffers are not handled\n"));
+ return 0;
+ }
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_pic_desc_buffer = obj_surface->pic_desc_buffer;
+ if (!xvba_pic_desc_buffer)
+ return 0;
+
+ XVBAPictureDescriptor * const pic_desc = xvba_pic_desc_buffer->bufferXVBA;
+ pic_desc->avc_intra_flag = slice_param->slice_type == 2; /* I-type */
+ pic_desc->avc_num_ref_idx_l0_active_minus1 = slice_param->num_ref_idx_l0_active_minus1;
+ pic_desc->avc_num_ref_idx_l1_active_minus1 = slice_param->num_ref_idx_l1_active_minus1;
+
+ object_buffer_p data_buffer = obj_context->data_buffer;
+ ASSERT(data_buffer);
+ if (!data_buffer)
+ return 0;
+ ASSERT(slice_param->slice_data_offset + slice_param->slice_data_size <= data_buffer->buffer_size);
+ if (slice_param->slice_data_offset + slice_param->slice_data_size > data_buffer->buffer_size)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_data_buffer = obj_surface->data_buffer;
+ ASSERT(xvba_data_buffer);
+ if (!xvba_data_buffer)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_data_ctrl_buffer = obj_surface->data_ctrl_buffers[obj_context->slice_count++];
+ ASSERT(xvba_data_ctrl_buffer);
+ if (!xvba_data_ctrl_buffer)
+ return 0;
+
+ XVBADataCtrl * const data_ctrl = xvba_data_ctrl_buffer->bufferXVBA;
+ const unsigned int data_offset = xvba_data_buffer->data_size_in_buffer;
+
+ const uint8_t * const va_slice_data = ((uint8_t *)data_buffer->buffer_data +
+ slice_param->slice_data_offset);
+
+ static const uint8_t start_code_prefix_one_3byte[3] = { 0x00, 0x00, 0x01 };
+ if (memcmp(va_slice_data, start_code_prefix_one_3byte, 3) != 0)
+ append_buffer(xvba_data_buffer, start_code_prefix_one_3byte, 3);
+ append_buffer(xvba_data_buffer, va_slice_data, slice_param->slice_data_size);
+
+ /* XXX: should XVBA_DATA_CTRL_BUFFER.SliceBytesInBuffer and
+ SliceBitsInBuffer be required to account for padding bytes too? */
+ data_ctrl->SliceDataLocation = data_offset;
+ data_ctrl->SliceBytesInBuffer = xvba_data_buffer->data_size_in_buffer - data_offset;
+ data_ctrl->SliceBitsInBuffer = 8 * data_ctrl->SliceBytesInBuffer;
+ pad_buffer(xvba_data_buffer);
+
+ xvba_data_ctrl_buffer->data_size_in_buffer = sizeof(*data_ctrl);
+ return 1;
+}
+
+// Translate VAPictureParameterBufferVC1
+static int
+translate_VAPictureParameterBufferVC1(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ VAPictureParameterBufferVC1 * const pic_param = obj_buffer->buffer_data;
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return 0;
+
+ object_config_p obj_config = XVBA_CONFIG(obj_context->va_config);
+ if (!obj_config)
+ return 0;
+
+ int profile, level = 0;
+ switch (obj_config->profile) {
+ case VAProfileVC1Simple:
+ profile = XVBA_VC1_SIMPLE;
+ break;
+ case VAProfileVC1Main:
+ profile = XVBA_VC1_MAIN;
+ break;
+ case VAProfileVC1Advanced:
+ profile = XVBA_VC1_ADVANCED;
+ level = vaapi_vc1_get_level_advanced(
+ pic_param,
+ obj_context->picture_width,
+ obj_context->picture_height
+ );
+ break;
+ default:
+ D(bug("translate_VAPictureParameterBufferVC1(): invalid profile\n"));
+ return 0;
+ }
+
+ /* Check for VC-1 content over AP@L3 */
+ if (profile == XVBA_VC1_ADVANCED && level > 3) {
+ if (!driver_data->warn_vc1_over_ap_l3) {
+ driver_data->warn_vc1_over_ap_l3 = 1;
+ xvba_information_message(
+ "driver does not support VC-1 content over AP@L3. "
+ "Please upgrade.\n"
+ );
+ }
+ }
+
+ XVBAPictureDescriptor * const pic_desc = obj_surface->pic_desc_buffer->bufferXVBA;
+ memset(pic_desc, 0, sizeof(*pic_desc));
+
+ pic_desc->past_surface = NULL;
+ pic_desc->future_surface = NULL;
+ pic_desc->profile = profile;
+ pic_desc->level = level;
+ pic_desc->width_in_mb = pic_param->coded_width;
+ pic_desc->height_in_mb = pic_param->coded_height;
+ pic_desc->picture_structure = vaapi_vc1_get_picture_structure(pic_param);
+ pic_desc->sps_info.flags = 0; /* reset all bits */
+ pic_desc->sps_info.vc1.postprocflag = pic_param->post_processing != 0;
+ pic_desc->sps_info.vc1.pulldown = pic_param->sequence_fields.bits.pulldown;
+ pic_desc->sps_info.vc1.interlace = pic_param->sequence_fields.bits.interlace;
+ pic_desc->sps_info.vc1.tfcntrflag = pic_param->sequence_fields.bits.tfcntrflag;
+ pic_desc->sps_info.vc1.finterpflag = pic_param->sequence_fields.bits.finterpflag;
+ pic_desc->sps_info.vc1.psf = pic_param->sequence_fields.bits.psf;
+ pic_desc->sps_info.vc1.second_field = !pic_param->picture_fields.bits.is_first_field;
+ pic_desc->chroma_format = 1; /* XXX: 4:2:0 */
+ pic_desc->pps_info.flags = 0; /* reset all bits */
+ pic_desc->pps_info.vc1.panscan_flag = pic_param->entrypoint_fields.bits.panscan_flag;
+ pic_desc->pps_info.vc1.refdist_flag = pic_param->reference_fields.bits.reference_distance_flag;
+ pic_desc->pps_info.vc1.loopfilter = pic_param->entrypoint_fields.bits.loopfilter;
+ pic_desc->pps_info.vc1.fastuvmc = pic_param->fast_uvmc_flag;
+ pic_desc->pps_info.vc1.extended_mv = pic_param->mv_fields.bits.extended_mv_flag;
+ pic_desc->pps_info.vc1.dquant = pic_param->pic_quantizer_fields.bits.dquant;
+ pic_desc->pps_info.vc1.vstransform = pic_param->transform_fields.bits.variable_sized_transform_flag;
+ pic_desc->pps_info.vc1.overlap = pic_param->conditional_overlap_flag;
+ pic_desc->pps_info.vc1.quantizer = pic_param->pic_quantizer_fields.bits.quantizer;
+ pic_desc->pps_info.vc1.extended_dmv = pic_param->mv_fields.bits.extended_dmv_flag;
+ pic_desc->pps_info.vc1.maxbframes = pic_param->sequence_fields.bits.max_b_frames;
+ pic_desc->pps_info.vc1.rangered = pic_param->sequence_fields.bits.rangered;
+ pic_desc->pps_info.vc1.syncmarker = pic_param->sequence_fields.bits.syncmarker;
+ pic_desc->pps_info.vc1.multires = pic_param->sequence_fields.bits.multires;
+ pic_desc->pps_info.vc1.range_mapy_flag = pic_param->range_mapping_fields.bits.luma_flag;
+ pic_desc->pps_info.vc1.range_mapy = pic_param->range_mapping_fields.bits.luma;
+ pic_desc->pps_info.vc1.range_mapuv_flag = pic_param->range_mapping_fields.bits.chroma_flag;
+ pic_desc->pps_info.vc1.range_mapuv = pic_param->range_mapping_fields.bits.chroma;
+
+ if (pic_param->backward_reference_picture != VA_INVALID_SURFACE) {
+ object_surface_p s = XVBA_SURFACE(pic_param->backward_reference_picture);
+ ASSERT(s);
+ if (!s)
+ return 0;
+ pic_desc->past_surface = s->xvba_surface;
+ }
+
+ if (pic_param->forward_reference_picture != VA_INVALID_SURFACE) {
+ object_surface_p s = XVBA_SURFACE(pic_param->forward_reference_picture);
+ ASSERT(s);
+ if (!s)
+ return 0;
+ pic_desc->future_surface = s->xvba_surface;
+ }
+
+ obj_surface->pic_desc_buffer->data_size_in_buffer = sizeof(*pic_desc);
+ return 1;
+}
+
+// Translate VASliceParameterBufferVC1
+static int
+translate_VASliceParameterBufferVC1(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ VASliceParameterBufferVC1 * const slice_param = obj_buffer->buffer_data;
+
+ /* XXX: we don't handle partial slice data buffers yet */
+ if (slice_param->slice_data_flag != VA_SLICE_DATA_FLAG_ALL) {
+ D(bug("partial slice data buffers are not handled\n"));
+ return 0;
+ }
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_pic_desc_buffer = obj_surface->pic_desc_buffer;
+ if (!xvba_pic_desc_buffer)
+ return 0;
+
+ XVBAPictureDescriptor * const pic_desc = xvba_pic_desc_buffer->bufferXVBA;
+
+ object_buffer_p data_buffer = obj_context->data_buffer;
+ ASSERT(data_buffer);
+ if (!data_buffer)
+ return 0;
+ ASSERT(slice_param->slice_data_offset + slice_param->slice_data_size <= data_buffer->buffer_size);
+ if (slice_param->slice_data_offset + slice_param->slice_data_size > data_buffer->buffer_size)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_data_buffer = obj_surface->data_buffer;
+ ASSERT(xvba_data_buffer);
+ if (!xvba_data_buffer)
+ return 0;
+
+ XVBABufferDescriptor * const xvba_data_ctrl_buffer = obj_surface->data_ctrl_buffers[obj_context->slice_count++];
+ ASSERT(xvba_data_ctrl_buffer);
+ if (!xvba_data_ctrl_buffer)
+ return 0;
+
+ XVBADataCtrl * const data_ctrl = xvba_data_ctrl_buffer->bufferXVBA;
+ const unsigned int data_offset = xvba_data_buffer->data_size_in_buffer;
+
+ const uint8_t * const va_slice_data = ((uint8_t *)data_buffer->buffer_data +
+ slice_param->slice_data_offset);
+
+ static const uint8_t start_code_prefix[3] = { 0x00, 0x00, 0x01 };
+ if (memcmp(va_slice_data, start_code_prefix, sizeof(start_code_prefix)) != 0) {
+ append_buffer(xvba_data_buffer, start_code_prefix, sizeof(start_code_prefix));
+
+ uint8_t start_code_ext = 0;
+ if (pic_desc->picture_structure == PICT_FRAME) {
+ /* XXX: we only support Progressive mode at this time */
+ start_code_ext = 0x0d;
+ }
+ ASSERT(start_code_ext);
+ append_buffer(xvba_data_buffer, &start_code_ext, 1);
+ }
+
+ append_buffer(xvba_data_buffer, va_slice_data, slice_param->slice_data_size);
+
+ /* XXX: should XVBA_DATA_CTRL_BUFFER.SliceBytesInBuffer and
+ SliceBitsInBuffer be required to account for padding bytes too? */
+ data_ctrl->SliceDataLocation = data_offset;
+ data_ctrl->SliceBytesInBuffer = xvba_data_buffer->data_size_in_buffer - data_offset;
+ data_ctrl->SliceBitsInBuffer = 8 * data_ctrl->SliceBytesInBuffer;
+ pad_buffer(xvba_data_buffer);
+
+ xvba_data_ctrl_buffer->data_size_in_buffer = sizeof(*data_ctrl);
+ return 1;
+}
+
+// Translate VA buffer
+typedef int
+(*translate_buffer_func_t)(xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer);
+
+typedef struct translate_buffer_info translate_buffer_info_t;
+struct translate_buffer_info {
+ XVBACodec codec;
+ VABufferType type;
+ translate_buffer_func_t func;
+};
+
+int
+translate_buffer(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+)
+{
+ static const translate_buffer_info_t translate_info[] = {
+#define _(CODEC, TYPE) \
+ { XVBA_CODEC_##CODEC, VA##TYPE##BufferType, \
+ translate_VA##TYPE##Buffer##CODEC }
+ _(MPEG2, PictureParameter),
+ _(MPEG2, IQMatrix),
+ _(MPEG2, SliceParameter),
+ _(H264, PictureParameter),
+ _(H264, IQMatrix),
+ _(H264, SliceParameter),
+ _(VC1, PictureParameter),
+ _(VC1, SliceParameter),
+#undef _
+ { XVBA_CODEC_VC1, VABitPlaneBufferType, translate_nothing },
+ { 0, VASliceDataBufferType, translate_VASliceDataBuffer },
+ { 0, 0, NULL }
+ };
+ const translate_buffer_info_t *tbip;
+ for (tbip = translate_info; tbip->func != NULL; tbip++) {
+ if (tbip->codec && tbip->codec != obj_context->xvba_codec)
+ continue;
+ if (tbip->type != obj_buffer->type)
+ continue;
+ return tbip->func(driver_data, obj_context, obj_buffer);
+ }
+ D(bug("ERROR: no translate function found for %s%s\n",
+ string_of_VABufferType(obj_buffer->type),
+ obj_context->xvba_codec ? string_of_XVBACodec(obj_context->xvba_codec) : NULL));
+ return 0;
+}
+
+// vaCreateBuffer
+VAStatus
+xvba_CreateBuffer(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferType type,
+ unsigned int size,
+ unsigned int num_elements,
+ void *data,
+ VABufferID *buf_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (buf_id)
+ *buf_id = VA_INVALID_BUFFER;
+
+ /* Validate type */
+ switch (type) {
+ case VAPictureParameterBufferType:
+ case VAIQMatrixBufferType:
+ case VASliceParameterBufferType:
+ case VASliceDataBufferType:
+ case VABitPlaneBufferType:
+ case VAImageBufferType:
+ /* Ok */
+ break;
+ default:
+ D(bug("ERROR: unsupported buffer type %d\n", type));
+ return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
+ }
+
+ object_buffer_p obj_buffer;
+ obj_buffer = create_va_buffer(driver_data, context, type, num_elements, size);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ if (data)
+ memcpy(obj_buffer->buffer_data, data, obj_buffer->buffer_size);
+
+ if (buf_id)
+ *buf_id = obj_buffer->base.id;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDestroyBuffer
+VAStatus
+xvba_DestroyBuffer(
+ VADriverContextP ctx,
+ VABufferID buffer_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(buffer_id);
+
+ if (obj_buffer) {
+ if (!is_queued_buffer(driver_data, obj_buffer))
+ destroy_va_buffer(driver_data, obj_buffer);
+ /* else, it will be destroyed in the next commit_picture() call */
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// vaBufferSetNumElements
+VAStatus
+xvba_BufferSetNumElements(
+ VADriverContextP ctx,
+ VABufferID buf_id,
+ unsigned int num_elements
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(buf_id);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ if (num_elements < 0 || num_elements > obj_buffer->max_num_elements)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ obj_buffer->num_elements = num_elements;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaMapBuffer
+VAStatus
+xvba_MapBuffer(
+ VADriverContextP ctx,
+ VABufferID buf_id,
+ void **pbuf
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(buf_id);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ if (pbuf)
+ *pbuf = obj_buffer->buffer_data;
+
+ if (!obj_buffer->buffer_data)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ ++obj_buffer->mtime;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaUnmapBuffer
+VAStatus
+xvba_UnmapBuffer(
+ VADriverContextP ctx,
+ VABufferID buf_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(buf_id);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ ++obj_buffer->mtime;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaBufferInfo
+VAStatus
+xvba_BufferInfo(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferID buf_id,
+ VABufferType *type,
+ unsigned int *size,
+ unsigned int *num_elements
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(buf_id);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ if (type)
+ *type = obj_buffer->type;
+ if (size)
+ *size = obj_buffer->buffer_size / obj_buffer->num_elements;
+ if (num_elements)
+ *num_elements = obj_buffer->num_elements;
+ return VA_STATUS_SUCCESS;
+}
diff --git a/src/xvba_buffer.h b/src/xvba_buffer.h
new file mode 100644
index 0000000..518b724
--- /dev/null
+++ b/src/xvba_buffer.h
@@ -0,0 +1,129 @@
+/*
+ * xvba_buffer.h - XvBA backend for VA-API (VA buffers)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_BUFFER_H
+#define XVBA_BUFFER_H
+
+#include "xvba_driver.h"
+
+typedef struct object_buffer object_buffer_t;
+struct object_buffer {
+ struct object_base base;
+ VAContextID va_context;
+ VABufferType type;
+ void *buffer_data;
+ unsigned int buffer_size;
+ unsigned int max_num_elements;
+ unsigned int num_elements;
+ uint64_t mtime;
+};
+
+// Create VA buffer object
+object_buffer_p
+create_va_buffer(
+ xvba_driver_data_t *driver_data,
+ VAContextID context,
+ VABufferType buffer_type,
+ unsigned int num_elements,
+ unsigned int size
+) attribute_hidden;
+
+// Destroy VA buffer object
+void
+destroy_va_buffer(
+ xvba_driver_data_t *driver_data,
+ object_buffer_p obj_buffer
+) attribute_hidden;
+
+// Destroy VA buffer objects stored in VA context
+void
+destroy_va_buffers(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context
+) attribute_hidden;
+
+// Determines whether BUFFER is queued for decoding
+int
+is_queued_buffer(
+ xvba_driver_data_t *driver_data,
+ object_buffer_p obj_buffer
+) attribute_hidden;
+
+// Translate VA buffer
+int translate_buffer(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_buffer_p obj_buffer
+) attribute_hidden;
+
+// vaCreateBuffer
+VAStatus
+xvba_CreateBuffer(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferType type,
+ unsigned int size,
+ unsigned int num_elements,
+ void *data,
+ VABufferID *buf_id
+) attribute_hidden;
+
+// vaDestroyBuffer
+VAStatus
+xvba_DestroyBuffer(
+ VADriverContextP ctx,
+ VABufferID buffer_id
+) attribute_hidden;
+
+// vaBufferSetNumElements
+VAStatus
+xvba_BufferSetNumElements(
+ VADriverContextP ctx,
+ VABufferID buf_id,
+ unsigned int num_elements
+) attribute_hidden;
+
+// vaMapBuffer
+VAStatus
+xvba_MapBuffer(
+ VADriverContextP ctx,
+ VABufferID buf_id,
+ void **pbuf
+) attribute_hidden;
+
+// vaUnmapBuffer
+VAStatus
+xvba_UnmapBuffer(
+ VADriverContextP ctx,
+ VABufferID buf_id
+) attribute_hidden;
+
+// vaBufferInfo
+VAStatus
+xvba_BufferInfo(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferID buf_id,
+ VABufferType *type,
+ unsigned int *size,
+ unsigned int *num_elements
+) attribute_hidden;
+
+#endif /* XVBA_BUFFER_H */
diff --git a/src/xvba_decode.c b/src/xvba_decode.c
new file mode 100644
index 0000000..5c9ec71
--- /dev/null
+++ b/src/xvba_decode.c
@@ -0,0 +1,716 @@
+/*
+ * xvba_decode.c - XvBA backend for VA-API (decoding)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_decode.h"
+#include "xvba_driver.h"
+#include "xvba_video.h"
+#include "xvba_buffer.h"
+#include "xvba_dump.h"
+#include "xvba_image.h"
+#include "utils.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// NAL units in XVBA_DATA_BUFFER must be 128-byte aligned
+#define XVBA_BUFFER_ALIGN 128
+
+// Determines XVBA_CAPABILITY_ID from VAProfile/VAEntrypoint
+static XVBA_CAPABILITY_ID
+get_XVBA_CAPABILITY_ID(VAProfile profile, VAEntrypoint entrypoint)
+{
+ switch (profile) {
+ case VAProfileMPEG2Simple:
+ case VAProfileMPEG2Main:
+ switch (entrypoint) {
+ case VAEntrypointIDCT: return XVBA_MPEG2_IDCT;
+ case VAEntrypointVLD: return XVBA_MPEG2_VLD;
+ default: return 0;
+ }
+ return 0;
+ case VAProfileMPEG4Simple:
+ case VAProfileMPEG4AdvancedSimple:
+ case VAProfileMPEG4Main:
+ return 0;
+#if VA_CHECK_VERSION(0,30,0)
+ case VAProfileH263Baseline:
+ return 0;
+#endif
+ case VAProfileH264Baseline:
+ case VAProfileH264Main:
+ case VAProfileH264High:
+ switch (entrypoint) {
+ case VAEntrypointVLD: return XVBA_H264;
+ default: return 0;
+ }
+ return 0;
+ case VAProfileVC1Simple:
+ case VAProfileVC1Main:
+ case VAProfileVC1Advanced:
+ switch (entrypoint) {
+ case VAEntrypointVLD: return XVBA_VC1;
+ default: return 0;
+ }
+ return 0;
+#if VA_CHECK_VERSION(0,31,0)
+ case VAProfileJPEGBaseline:
+ return 0;
+#endif
+ }
+ return 0;
+}
+
+// Translates VAProfile to XVBA_DECODE_FLAGS
+static XVBA_DECODE_FLAGS get_XVBA_DECODE_FLAGS(VAProfile profile)
+{
+ switch (profile) {
+ case VAProfileMPEG2Simple:
+ case VAProfileMPEG2Main:
+ return 0;
+ case VAProfileMPEG4Simple:
+ case VAProfileMPEG4AdvancedSimple:
+ case VAProfileMPEG4Main:
+ return 0;
+#if VA_CHECK_VERSION(0,30,0)
+ case VAProfileH263Baseline:
+ return 0;
+#endif
+ case VAProfileH264Baseline: return XVBA_H264_BASELINE;
+ case VAProfileH264Main: return XVBA_H264_MAIN;
+ case VAProfileH264High: return XVBA_H264_HIGH;
+ case VAProfileVC1Simple: return XVBA_VC1_SIMPLE;
+ case VAProfileVC1Main: return XVBA_VC1_MAIN;
+ case VAProfileVC1Advanced: return XVBA_VC1_ADVANCED;
+#if VA_CHECK_VERSION(0,31,0)
+ case VAProfileJPEGBaseline:
+ return 0;
+#endif
+ }
+ return 0;
+}
+
+// Initializes XvBA decode caps
+static int ensure_decode_caps(xvba_driver_data_t *driver_data)
+{
+ int status;
+
+ if (driver_data->xvba_decode_caps && driver_data->xvba_decode_caps_count)
+ return 1;
+
+ if (driver_data->xvba_decode_caps) {
+ free(driver_data->xvba_decode_caps);
+ driver_data->xvba_decode_caps = NULL;
+ }
+ driver_data->xvba_decode_caps_count = 0;
+
+ status = xvba_get_decode_caps(
+ driver_data->xvba_context,
+ &driver_data->xvba_decode_caps_count,
+ &driver_data->xvba_decode_caps
+ );
+ if (status < 0)
+ return 0;
+ return 1;
+}
+
+// Translates VAProfile/VAEntrypoint to XVBADecodeCap
+static XVBADecodeCap *
+get_XVBADecodeCap(
+ xvba_driver_data_t *driver_data,
+ VAProfile profile,
+ VAEntrypoint entrypoint
+)
+{
+ unsigned int i;
+
+ if (!ensure_decode_caps(driver_data))
+ return NULL;
+
+ XVBA_CAPABILITY_ID cap_id = get_XVBA_CAPABILITY_ID(profile, entrypoint);
+ XVBA_DECODE_FLAGS decode_flags = get_XVBA_DECODE_FLAGS(profile);
+ for (i = 0; i < driver_data->xvba_decode_caps_count; i++) {
+ XVBADecodeCap * const decode_cap = &driver_data->xvba_decode_caps[i];
+ if (decode_cap->capability_id == cap_id &&
+ decode_cap->flags == decode_flags)
+ return decode_cap;
+ }
+ return NULL;
+}
+
+// Translates VABufferType to XVBA_BUFFER
+static XVBA_DECODE_FLAGS get_XVBA_BUFFER(VABufferType buffer_type)
+{
+ switch (buffer_type) {
+ case VAPictureParameterBufferType: return XVBA_PICTURE_DESCRIPTION_BUFFER;
+ case VASliceDataBufferType: return XVBA_DATA_BUFFER;
+ case VASliceParameterBufferType: return XVBA_DATA_CTRL_BUFFER;
+ case VAIQMatrixBufferType: return XVBA_QM_BUFFER;
+ default: break;
+ }
+ return XVBA_NONE;
+}
+
+// Checks decoder for profile/entrypoint is available
+int
+has_decoder(
+ xvba_driver_data_t *driver_data,
+ VAProfile profile,
+ VAEntrypoint entrypoint
+)
+{
+ return get_XVBADecodeCap(driver_data, profile, entrypoint) != NULL;
+}
+
+// Checks whether VA profile is implemented
+static int
+is_supported_profile(VAProfile profile)
+{
+ switch (profile) {
+ case VAProfileH264Baseline:
+ case VAProfileH264Main:
+ case VAProfileH264High:
+ case VAProfileVC1Simple:
+ case VAProfileVC1Main:
+ case VAProfileVC1Advanced:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// Creates current XvBA decode session
+VAStatus
+create_decoder(xvba_driver_data_t *driver_data, object_context_p obj_context)
+{
+ object_config_p obj_config = XVBA_CONFIG(obj_context->va_config);
+ if (!obj_config)
+ return VA_STATUS_ERROR_INVALID_CONFIG;
+
+ XVBADecodeCap *decode_cap;
+ decode_cap = get_XVBADecodeCap(
+ driver_data,
+ obj_config->profile,
+ obj_config->entrypoint
+ );
+ if (!decode_cap)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ XVBASession *decode_session;
+ decode_session = xvba_create_decode_session(
+ driver_data->xvba_context,
+ obj_context->picture_width,
+ obj_context->picture_height,
+ decode_cap
+ );
+ if (!decode_session)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ obj_context->xvba_decoder = decode_session;
+ obj_context->xvba_session = decode_session;
+ return VA_STATUS_SUCCESS;
+}
+
+// Destroys current XvBA decode session
+void
+destroy_decoder(xvba_driver_data_t *driver_data, object_context_p obj_context)
+{
+ if (!obj_context->xvba_decoder)
+ return;
+ xvba_destroy_decode_session(obj_context->xvba_decoder);
+ if (obj_context->xvba_session == obj_context->xvba_decoder)
+ obj_context->xvba_session = NULL;
+ obj_context->xvba_decoder = NULL;
+}
+
+// Allocates a new XvBA buffer
+int
+create_buffer(
+ object_context_p obj_context,
+ XVBABufferDescriptor **buffer_p,
+ XVBA_BUFFER type
+)
+{
+ if (buffer_p)
+ *buffer_p = NULL;
+
+ XVBABufferDescriptor *buffer;
+ buffer = xvba_create_decode_buffers(obj_context->xvba_decoder, type, 1);
+ if (!buffer)
+ return 0;
+
+ if (buffer_p)
+ *buffer_p = buffer;
+
+ buffer->appPrivate = obj_context;
+ buffer->size = sizeof(*buffer);
+ clear_buffer(buffer);
+ return 1;
+}
+
+// Destroys XvBA buffer
+void
+destroy_buffer(
+ object_context_p obj_context,
+ XVBABufferDescriptor **buffer_p
+)
+{
+ if (!buffer_p || !*buffer_p)
+ return;
+
+ /* Something went wrong otherwise */
+ ASSERT((*buffer_p)->appPrivate == obj_context);
+ if (!obj_context)
+ return;
+
+ xvba_destroy_decode_buffers(obj_context->xvba_decoder, *buffer_p, 1);
+ *buffer_p = NULL;
+}
+
+// Appends data to the specified buffer
+void
+append_buffer(
+ XVBABufferDescriptor *xvba_buffer,
+ const uint8_t *buf,
+ unsigned int buf_size
+)
+{
+ memcpy(
+ ((uint8_t *)xvba_buffer->bufferXVBA + xvba_buffer->data_size_in_buffer),
+ buf,
+ buf_size
+ );
+ xvba_buffer->data_size_in_buffer += buf_size;
+}
+
+// Pads buffer to 128-byte boundaries
+void pad_buffer(XVBABufferDescriptor *xvba_buffer)
+{
+ unsigned int r, align;
+
+ if ((r = xvba_buffer->data_size_in_buffer % XVBA_BUFFER_ALIGN) != 0) {
+ align = XVBA_BUFFER_ALIGN - r;
+ ASSERT(xvba_buffer->data_size_in_buffer + align <= xvba_buffer->buffer_size);
+ memset(((uint8_t *)xvba_buffer->bufferXVBA + xvba_buffer->data_size_in_buffer), 0, align);
+ xvba_buffer->data_size_in_buffer += align;
+ }
+}
+
+// Clears an XvBA buffer
+void clear_buffer(XVBABufferDescriptor *xvba_buffer)
+{
+ if (!xvba_buffer)
+ return;
+ xvba_buffer->data_offset = 0;
+ xvba_buffer->data_size_in_buffer = 0;
+}
+
+// Creates XvBA buffers associated to a surface
+static VAStatus
+ensure_buffer(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ object_buffer_p obj_buffer
+)
+{
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ XVBABufferDescriptor **buffer_p = NULL;
+ XVBA_BUFFER xvba_buffer_type = get_XVBA_BUFFER(obj_buffer->type);
+ switch (obj_buffer->type) {
+ case VAPictureParameterBufferType:
+ buffer_p = &obj_surface->pic_desc_buffer;
+ break;
+ case VAIQMatrixBufferType:
+ buffer_p = &obj_surface->iq_matrix_buffer;
+ break;
+ case VASliceDataBufferType:
+ buffer_p = &obj_surface->data_buffer;
+ break;
+ case VASliceParameterBufferType:
+ if (realloc_buffer(&obj_surface->data_ctrl_buffers,
+ &obj_surface->data_ctrl_buffers_count_max,
+ 1 + obj_surface->data_ctrl_buffers_count,
+ sizeof(*obj_surface->data_ctrl_buffers)) == NULL)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ buffer_p = &obj_surface->data_ctrl_buffers[obj_surface->data_ctrl_buffers_count++];
+ break;
+ default:
+ break;
+ }
+ if (buffer_p && !*buffer_p &&
+ !create_buffer(obj_context, buffer_p, xvba_buffer_type))
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+ensure_buffers(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface
+)
+{
+ unsigned int i;
+ for (i = 0; i < obj_context->va_buffers_count; i++) {
+ object_buffer_p obj_buffer = XVBA_BUFFER(obj_context->va_buffers[i]);
+ if (!obj_buffer)
+ continue;
+ VAStatus status = ensure_buffer(driver_data, obj_surface, obj_buffer);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Destroys XvBA buffers associated to a surface
+void
+destroy_surface_buffers(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+)
+{
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return;
+
+ destroy_buffer(obj_context, &obj_surface->pic_desc_buffer);
+ destroy_buffer(obj_context, &obj_surface->iq_matrix_buffer);
+ destroy_buffer(obj_context, &obj_surface->data_buffer);
+
+ unsigned int i;
+ for (i = 0; i < obj_surface->data_ctrl_buffers_count_max; i++)
+ destroy_buffer(obj_context, &obj_surface->data_ctrl_buffers[i]);
+ free(obj_surface->data_ctrl_buffers);
+ obj_surface->data_ctrl_buffers = NULL;
+ obj_surface->data_ctrl_buffers_count = 0;
+ obj_surface->data_ctrl_buffers_count_max = 0;
+}
+
+// Send picture to the HW for decoding
+static VAStatus
+decode_picture(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface
+)
+{
+ XVBASession * const xvba_decoder = obj_context->xvba_decoder;
+ XVBABufferDescriptor *xvba_buffers[2];
+ unsigned int i, n_buffers;
+
+ if (xvba_decode_picture_start(xvba_decoder, obj_surface->xvba_surface) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ n_buffers = 0;
+ xvba_buffers[n_buffers++] = obj_surface->pic_desc_buffer;
+ if (obj_surface->iq_matrix_buffer)
+ xvba_buffers[n_buffers++] = obj_surface->iq_matrix_buffer;
+ if (xvba_decode_picture(xvba_decoder, xvba_buffers, n_buffers) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ for (i = 0; i < obj_surface->data_ctrl_buffers_count; i++) {
+ n_buffers = 0;
+ xvba_buffers[n_buffers++] = obj_surface->data_buffer;
+ xvba_buffers[n_buffers++] = obj_surface->data_ctrl_buffers[i];
+ if (xvba_decode_picture(xvba_decoder, xvba_buffers, n_buffers) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+ }
+
+ if (xvba_decode_picture_end(xvba_decoder) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ obj_surface->va_surface_status = VASurfaceRendering;
+ return 0;
+}
+
+// Translate picture buffers and send it to the HW for decoding
+static VAStatus
+commit_picture(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface
+)
+{
+ VAStatus va_status = ensure_buffers(driver_data, obj_context, obj_surface);
+ if (va_status != VA_STATUS_SUCCESS)
+ return va_status;
+
+ obj_context->data_buffer = NULL;
+ obj_context->slice_count = 0;
+
+ int i, j, slice_data_is_first = -1;
+ for (i = 0; i < obj_context->va_buffers_count; i++) {
+ object_buffer_p obj_buffer = XVBA_BUFFER(obj_context->va_buffers[i]);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ switch (obj_buffer->type) {
+ case VASliceDataBufferType:
+ if (slice_data_is_first < 0)
+ slice_data_is_first = 1;
+ break;
+ case VASliceParameterBufferType:
+ if (slice_data_is_first < 0)
+ slice_data_is_first = 0;
+ if (slice_data_is_first) {
+ for (j = i - 1; j >= 0; j--) {
+ object_buffer_p data_buffer = XVBA_BUFFER(obj_context->va_buffers[j]);
+ ASSERT(data_buffer);
+ if (data_buffer->type == VASliceDataBufferType) {
+ obj_context->data_buffer = data_buffer;
+ break;
+ }
+ }
+ }
+ else {
+ for (j = i + 1; j < obj_context->va_buffers_count; j++) {
+ object_buffer_p data_buffer = XVBA_BUFFER(obj_context->va_buffers[j]);
+ ASSERT(data_buffer);
+ if (data_buffer->type == VASliceDataBufferType) {
+ obj_context->data_buffer = data_buffer;
+ break;
+ }
+ }
+ }
+ ASSERT(obj_context->data_buffer);
+ break;
+ default:
+ break;
+ }
+
+ if (!translate_buffer(driver_data, obj_context, obj_buffer))
+ return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
+ }
+
+ /* Wait for the surface to be free for decoding */
+ if (sync_surface(driver_data, obj_context, obj_surface) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ /* Send picture to the HW */
+ return decode_picture(driver_data, obj_context, obj_surface);
+}
+
+// vaQueryConfigProfiles
+VAStatus
+xvba_QueryConfigProfiles(
+ VADriverContextP ctx,
+ VAProfile *profile_list,
+ int *num_profiles
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ static const VAProfile va_profiles[] = {
+ VAProfileMPEG2Simple,
+ VAProfileMPEG2Main,
+ VAProfileH264Baseline,
+ VAProfileH264Main,
+ VAProfileH264High,
+ VAProfileVC1Simple,
+ VAProfileVC1Main,
+ VAProfileVC1Advanced
+ };
+
+ static const VAEntrypoint va_entrypoints[] = {
+ VAEntrypointVLD,
+ VAEntrypointIDCT
+ };
+
+ int i, j, n = 0;
+ for (i = 0; i < ARRAY_ELEMS(va_profiles); i++) {
+ VAProfile profile = va_profiles[i];
+ if (!is_supported_profile(profile))
+ continue;
+ for (j = 0; j < ARRAY_ELEMS(va_entrypoints); j++) {
+ VAEntrypoint entrypoint = va_entrypoints[j];
+ if (has_decoder(driver_data, profile, entrypoint)) {
+ profile_list[n++] = profile;
+ break;
+ }
+ }
+ }
+
+ /* If the assert fails then XVBA_MAX_PROFILES needs to be bigger */
+ ASSERT(n <= XVBA_MAX_PROFILES);
+ if (num_profiles)
+ *num_profiles = n;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaQueryConfigEntrypoints
+VAStatus
+xvba_QueryConfigEntrypoints(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint *entrypoint_list,
+ int *num_entrypoints
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ static const VAEntrypoint va_entrypoints[] = {
+ VAEntrypointVLD,
+ VAEntrypointIDCT
+ };
+
+ if (!is_supported_profile(profile))
+ return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+ int i, n = 0;
+ for (i = 0; i < ARRAY_ELEMS(va_entrypoints); i++) {
+ const VAEntrypoint entrypoint = va_entrypoints[i];
+ if (has_decoder(driver_data, profile, entrypoint))
+ entrypoint_list[n++] = entrypoint;
+ }
+
+ /* If the assert fails then XVBA_MAX_ENTRUYPOINTS needs to be bigger */
+ ASSERT(n <= XVBA_MAX_ENTRYPOINTS);
+ if (num_entrypoints)
+ *num_entrypoints = n;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaBeginPicture
+VAStatus
+xvba_BeginPicture(
+ VADriverContextP ctx,
+ VAContextID context,
+ VASurfaceID render_target
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ D(bug("vaBeginPicture(): context 0x%08x, surface 0x%08x\n",
+ context, render_target));
+
+ object_context_p obj_context = XVBA_CONTEXT(context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(render_target);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ /* Destroy any previous surface override from vaPutImage() */
+ putimage_hacks_disable(driver_data, obj_surface);
+
+ obj_context->current_render_target = obj_surface->base.id;
+ obj_surface->va_surface_status = VASurfaceRendering;
+ obj_surface->used_for_decoding = 1;
+
+ ASSERT(!obj_context->va_buffers_count);
+ destroy_va_buffers(driver_data, obj_context);
+
+ unsigned int i;
+ clear_buffer(obj_surface->pic_desc_buffer);
+ clear_buffer(obj_surface->iq_matrix_buffer);
+ clear_buffer(obj_surface->data_buffer);
+ for (i = 0; i < obj_surface->data_ctrl_buffers_count; i++)
+ clear_buffer(obj_surface->data_ctrl_buffers[i]);
+ obj_surface->data_ctrl_buffers_count = 0;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaRenderPicture
+VAStatus
+xvba_RenderPicture(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferID *buffers,
+ int num_buffers
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+ int i;
+
+ D(bug("vaRenderPicture(): context 0x%08x, %d buffers\n",
+ context, num_buffers));
+
+ object_context_p obj_context = XVBA_CONTEXT(context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ /* Verify that we got valid buffer references */
+ for (i = 0; i < num_buffers; i++) {
+ object_buffer_p obj_buffer = XVBA_BUFFER(buffers[i]);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+ }
+
+ /* Record buffers. They will be processed in EndPicture() */
+ for (i = 0; i < num_buffers; i++) {
+ object_buffer_p obj_buffer = XVBA_BUFFER(buffers[i]);
+
+ D(bug(" buffer 0x%08x\n", buffers[i]));
+
+ VABufferID *va_buffers;
+ va_buffers = realloc_buffer(
+ &obj_context->va_buffers,
+ &obj_context->va_buffers_count_max,
+ 1 + obj_context->va_buffers_count,
+ sizeof(*va_buffers)
+ );
+ if (!va_buffers)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ va_buffers[obj_context->va_buffers_count++] = obj_buffer->base.id;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// vaEndPicture
+VAStatus
+xvba_EndPicture(
+ VADriverContextP ctx,
+ VAContextID context
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ D(bug("vaEndPicture(): context 0x%08x\n", context));
+
+ object_context_p obj_context = XVBA_CONTEXT(context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(obj_context->current_render_target);
+ if (!obj_surface || !obj_surface->xvba_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ /* Send picture bits to the HW and free VA resources (buffers) */
+ VAStatus va_status = commit_picture(driver_data, obj_context, obj_surface);
+
+ /* XXX: assume we are done with rendering right away */
+ obj_context->current_render_target = VA_INVALID_SURFACE;
+
+ destroy_va_buffers(driver_data, obj_context);
+ return va_status;
+}
diff --git a/src/xvba_decode.h b/src/xvba_decode.h
new file mode 100644
index 0000000..22478a3
--- /dev/null
+++ b/src/xvba_decode.h
@@ -0,0 +1,130 @@
+/*
+ * xvba_decode.h - XvBA backend for VA-API (decoding)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_DECODE_H
+#define XVBA_DECODE_H
+
+#include "xvba_driver.h"
+
+// Checks decoder for profile/entrypoint is available
+int
+has_decoder(
+ xvba_driver_data_t *driver_data,
+ VAProfile profile,
+ VAEntrypoint entrypoint
+) attribute_hidden;
+
+// Create XvBA decode session
+VAStatus
+create_decoder(xvba_driver_data_t *driver_data, object_context_p obj_context)
+ attribute_hidden;
+
+// Destroy XvBA decode session
+void
+destroy_decoder(xvba_driver_data_t *driver_data, object_context_p obj_context)
+ attribute_hidden;
+
+// Create XvBA buffer
+int
+create_buffer(
+ object_context_p obj_context,
+ XVBABufferDescriptor **buffer_p,
+ XVBA_BUFFER type
+) attribute_hidden;
+
+// Destroy XvBA buffer
+void
+destroy_buffer(
+ object_context_p obj_context,
+ XVBABufferDescriptor **buffer_p
+) attribute_hidden;
+
+// Append data to the XvBA buffer
+void
+append_buffer(
+ XVBABufferDescriptor *xvba_buffer,
+ const uint8_t *buf,
+ unsigned int buf_size
+) attribute_hidden;
+
+// Pad XvBA buffer to 128-byte boundaries
+void pad_buffer(XVBABufferDescriptor *xvba_buffer)
+ attribute_hidden;
+
+// Clear XvBA buffer
+void clear_buffer(XVBABufferDescriptor *xvba_buffer)
+ attribute_hidden;
+
+// Create surface XvBA buffers
+VAStatus
+create_surface_buffers(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// Destroy surface XvBA buffers
+void
+destroy_surface_buffers(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// vaQueryConfigProfiles
+VAStatus
+xvba_QueryConfigProfiles(
+ VADriverContextP ctx,
+ VAProfile *profile_list,
+ int *num_profiles
+) attribute_hidden;
+
+// vaQueryConfigEntrypoints
+VAStatus
+xvba_QueryConfigEntrypoints(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint *entrypoint_list,
+ int *num_entrypoints
+) attribute_hidden;
+
+// vaBeginPicture
+VAStatus
+xvba_BeginPicture(
+ VADriverContextP ctx,
+ VAContextID context,
+ VASurfaceID render_target
+) attribute_hidden;
+
+// vaRenderPicture
+VAStatus
+xvba_RenderPicture(
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferID *buffers,
+ int num_buffers
+) attribute_hidden;
+
+// vaEndPicture
+VAStatus
+xvba_EndPicture(
+ VADriverContextP ctx,
+ VAContextID context
+) attribute_hidden;
+
+#endif /* XVBA_DECODE_H */
diff --git a/src/xvba_driver.c b/src/xvba_driver.c
new file mode 100644
index 0000000..12e03ab
--- /dev/null
+++ b/src/xvba_driver.c
@@ -0,0 +1,282 @@
+/*
+ * xvba_driver.c - XvBA driver
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_driver.h"
+#include "xvba_buffer.h"
+#include "xvba_decode.h"
+#include "xvba_image.h"
+#include "xvba_subpic.h"
+#include "xvba_video.h"
+#include "xvba_video_x11.h"
+#if USE_GLX
+#include "xvba_video_glx.h"
+#include <va/va_backend_glx.h>
+#endif
+#include "fglrxinfo.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Set display type
+int xvba_set_display_type(xvba_driver_data_t *driver_data, unsigned int type)
+{
+ if (driver_data->va_display_type == 0) {
+ driver_data->va_display_type = type;
+ return 1;
+ }
+ return driver_data->va_display_type == type;
+}
+
+// Destroy BUFFER objects
+static void destroy_buffer_cb(object_base_p obj, void *user_data)
+{
+ object_buffer_p const obj_buffer = (object_buffer_p)obj;
+ xvba_driver_data_t * const driver_data = user_data;
+
+ destroy_va_buffer(driver_data, obj_buffer);
+}
+
+// Destroy object heap
+typedef void (*destroy_heap_func_t)(object_base_p obj, void *user_data);
+
+static void
+destroy_heap(
+ const char *name,
+ object_heap_p heap,
+ destroy_heap_func_t destroy_func,
+ void *user_data
+)
+{
+ object_base_p obj;
+ object_heap_iterator iter;
+
+ if (!heap)
+ return;
+
+ obj = object_heap_first(heap, &iter);
+ while (obj) {
+ xvba_information_message("vaTerminate(): %s ID 0x%08x is still allocated, destroying\n", name, obj->id);
+ if (destroy_func)
+ destroy_func(obj, user_data);
+ else
+ object_heap_free(heap, obj);
+ obj = object_heap_next(heap, &iter);
+ }
+ object_heap_destroy(heap);
+}
+
+#define DESTROY_HEAP(heap, func) \
+ destroy_heap(#heap, &driver_data->heap##_heap, func, driver_data)
+
+#define CREATE_HEAP(type, id) do { \
+ int result = object_heap_init(&driver_data->type##_heap, \
+ sizeof(struct object_##type), \
+ XVBA_##id##_ID_OFFSET); \
+ ASSERT(result == 0); \
+ if (result != 0) \
+ return VA_STATUS_ERROR_ALLOCATION_FAILED; \
+ } while (0)
+
+// vaTerminate
+static void xvba_common_Terminate(xvba_driver_data_t *driver_data)
+{
+ if (driver_data->xvba_decode_caps) {
+ free(driver_data->xvba_decode_caps);
+ driver_data->xvba_decode_caps = NULL;
+ driver_data->xvba_decode_caps_count = 0;
+ }
+
+ if (driver_data->xvba_surface_caps) {
+ free(driver_data->xvba_surface_caps);
+ driver_data->xvba_surface_caps = NULL;
+ driver_data->xvba_surface_caps_count = 0;
+ }
+
+ DESTROY_HEAP(buffer, destroy_buffer_cb);
+ DESTROY_HEAP(output, NULL);
+ DESTROY_HEAP(image, NULL);
+ DESTROY_HEAP(subpicture, NULL);
+ DESTROY_HEAP(surface, NULL);
+ DESTROY_HEAP(context, NULL);
+ DESTROY_HEAP(config, NULL);
+
+ if (driver_data->xvba_context) {
+ xvba_destroy_context(driver_data->xvba_context);
+ driver_data->xvba_context = NULL;
+ }
+
+ xvba_gate_exit();
+}
+
+// vaInitialize
+static VAStatus xvba_common_Initialize(xvba_driver_data_t *driver_data)
+{
+ int xvba_version;
+ int fglrx_major_version, fglrx_minor_version, fglrx_micro_version;
+ unsigned int device_id;
+
+ driver_data->x11_dpy_local = XOpenDisplay(driver_data->x11_dpy_name);
+ if (!driver_data->x11_dpy_local)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ if (!fglrx_is_dri_capable(driver_data->x11_dpy, driver_data->x11_screen))
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ if (!fglrx_get_version(driver_data->x11_dpy, driver_data->x11_screen,
+ &fglrx_major_version,
+ &fglrx_minor_version,
+ &fglrx_micro_version))
+ return VA_STATUS_ERROR_UNKNOWN;
+ D(bug("FGLRX driver version %d.%d.%d detected\n",
+ fglrx_major_version, fglrx_minor_version, fglrx_micro_version));
+
+ if (!fglrx_check_version(8,80,5)) {
+ xvba_error_message("FGLRX driver version 8.80.5 (Catalyst 10.12) or later is required\n");
+ return VA_STATUS_ERROR_UNKNOWN;
+ }
+
+ if (!fglrx_get_device_id(driver_data->x11_dpy, driver_data->x11_screen,
+ &device_id))
+ return VA_STATUS_ERROR_UNKNOWN;
+ D(bug("FGLRX device ID 0x%04x\n", device_id));
+ driver_data->device_id = device_id;
+ switch (device_id & 0xff00) {
+ case 0x6700: // Radeon HD 6000 series
+ case 0x6800: // Radeon HD 5000 series
+ D(bug("Evergreen GPU detected\n"));
+ driver_data->is_evergreen_gpu = 1;
+ break;
+ case 0x9800: // Fusion series
+ D(bug("Fusion IGP detected\n"));
+ driver_data->is_evergreen_gpu = 1;
+ driver_data->is_fusion_igp = 1;
+ break;
+ }
+
+ if (xvba_gate_init() < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ if (xvba_query_extension(driver_data->x11_dpy, &xvba_version) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+ D(bug("XvBA version %d.%d detected\n",
+ (xvba_version >> 16) & 0xffff, xvba_version & 0xffff));
+
+ if (!xvba_check_version(0,74)) {
+ xvba_information_message("Please upgrade to XvBA >= 0.74\n");
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+ }
+
+ driver_data->xvba_context = xvba_create_context(driver_data->x11_dpy, None);
+ if (!driver_data->xvba_context)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ sprintf(driver_data->va_vendor, "%s %s - %d.%d.%d",
+ XVBA_STR_DRIVER_VENDOR,
+ XVBA_STR_DRIVER_NAME,
+ XVBA_VIDEO_MAJOR_VERSION,
+ XVBA_VIDEO_MINOR_VERSION,
+ XVBA_VIDEO_MICRO_VERSION);
+
+ if (XVBA_VIDEO_PRE_VERSION > 0) {
+ const int len = strlen(driver_data->va_vendor);
+ sprintf(&driver_data->va_vendor[len], ".pre%d", XVBA_VIDEO_PRE_VERSION);
+ }
+
+ CREATE_HEAP(config, CONFIG);
+ CREATE_HEAP(context, CONTEXT);
+ CREATE_HEAP(surface, SURFACE);
+ CREATE_HEAP(buffer, BUFFER);
+ CREATE_HEAP(output, OUTPUT);
+ CREATE_HEAP(image, IMAGE);
+ CREATE_HEAP(subpicture, SUBPICTURE);
+
+ return VA_STATUS_SUCCESS;
+}
+
+#if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION >= 31
+#define VA_INIT_VERSION_MAJOR 0
+#define VA_INIT_VERSION_MINOR 31
+#define VA_INIT_VERSION_MICRO 0
+#define VA_INIT_SUFFIX 0_31_0
+#include "xvba_driver_template.h"
+
+#define VA_INIT_VERSION_MAJOR 0
+#define VA_INIT_VERSION_MINOR 31
+#define VA_INIT_VERSION_MICRO 1
+#define VA_INIT_SUFFIX 0_31_1
+#define VA_INIT_GLX USE_GLX
+#include "xvba_driver_template.h"
+
+#define VA_INIT_VERSION_MAJOR 0
+#define VA_INIT_VERSION_MINOR 31
+#define VA_INIT_VERSION_MICRO 2
+#define VA_INIT_SUFFIX 0_31_2
+#define VA_INIT_GLX USE_GLX
+#include "xvba_driver_template.h"
+
+VAStatus __vaDriverInit_0_31(void *ctx)
+{
+ VADriverContextP_0_31_0 const ctx0 = ctx;
+ VADriverContextP_0_31_1 const ctx1 = ctx;
+ VADriverContextP_0_31_2 const ctx2 = ctx;
+
+ /* Assume a NULL display implies VA-API 0.31.1 struct with the
+ vtable_tpi field placed just after the vtable, thus replacing
+ original native_dpy field */
+ if (ctx0->native_dpy)
+ return xvba_Initialize_0_31_0(ctx);
+ if (ctx1->native_dpy)
+ return xvba_Initialize_0_31_1(ctx);
+ if (ctx2->native_dpy)
+ return xvba_Initialize_0_31_2(ctx);
+ return VA_STATUS_ERROR_INVALID_DISPLAY;
+}
+#endif
+
+#if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION >= 32
+#define VA_INIT_VERSION_MAJOR 0
+#define VA_INIT_VERSION_MINOR 32
+#define VA_INIT_VERSION_MICRO 0
+#define VA_INIT_SUFFIX 0_32_0
+#define VA_INIT_GLX USE_GLX
+#include "xvba_driver_template.h"
+
+VAStatus __vaDriverInit_0_32(void *ctx)
+{
+ return xvba_Initialize_0_32_0(ctx);
+}
+#endif
+
+#define VA_INIT_VERSION_MAJOR VA_MAJOR_VERSION
+#define VA_INIT_VERSION_MINOR VA_MINOR_VERSION
+#define VA_INIT_VERSION_MICRO VA_MICRO_VERSION
+#define VA_INIT_VERSION_SDS VA_SDS_VERSION
+#define VA_INIT_GLX USE_GLX
+#include "xvba_driver_template.h"
+
+VAStatus VA_DRIVER_INIT_FUNC(void *ctx)
+{
+#if VA_MAJOR_VERSION == 0 && VA_MINOR_VERSION == 31
+ return __vaDriverInit_0_31(ctx);
+#endif
+ return xvba_Initialize_Current(ctx);
+}
diff --git a/src/xvba_driver.h b/src/xvba_driver.h
new file mode 100644
index 0000000..855f8ed
--- /dev/null
+++ b/src/xvba_driver.h
@@ -0,0 +1,110 @@
+/*
+ * xvba_driver.h - XvBA driver
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_DRIVER_H
+#define XVBA_DRIVER_H
+
+#include <va/va_backend.h>
+#include "vaapi_compat.h"
+#include "xvba_gate.h"
+#include "object_heap.h"
+#include "color_matrix.h"
+
+#define XVBA_DRIVER_DATA_INIT \
+ struct xvba_driver_data *driver_data = \
+ (struct xvba_driver_data *)ctx->pDriverData
+
+#define XVBA_OBJECT(id, type) \
+ ((object_##type##_p)object_heap_lookup(&driver_data->type##_heap, (id)))
+
+#define XVBA_CONFIG(id) XVBA_OBJECT(id, config)
+#define XVBA_CONTEXT(id) XVBA_OBJECT(id, context)
+#define XVBA_SURFACE(id) XVBA_OBJECT(id, surface)
+#define XVBA_BUFFER(id) XVBA_OBJECT(id, buffer)
+#define XVBA_OUTPUT(id) XVBA_OBJECT(id, output)
+#define XVBA_IMAGE(id) XVBA_OBJECT(id, image)
+#define XVBA_SUBPICTURE(id) XVBA_OBJECT(id, subpicture)
+
+#define XVBA_CONFIG_ID_OFFSET 0x01000000
+#define XVBA_CONTEXT_ID_OFFSET 0x02000000
+#define XVBA_SURFACE_ID_OFFSET 0x03000000
+#define XVBA_BUFFER_ID_OFFSET 0x04000000
+#define XVBA_OUTPUT_ID_OFFSET 0x05000000
+#define XVBA_IMAGE_ID_OFFSET 0x06000000
+#define XVBA_SUBPICTURE_ID_OFFSET 0x07000000
+
+#define XVBA_MAX_DELAYED_PICTURES 32
+#define XVBA_MAX_PROFILES 12
+#define XVBA_MAX_ENTRYPOINTS 5
+#define XVBA_MAX_CONFIG_ATTRIBUTES 10
+#define XVBA_MAX_IMAGE_FORMATS 10
+#define XVBA_MAX_DISPLAY_ATTRIBUTES 6
+#define XVBA_STR_DRIVER_VENDOR "Splitted-Desktop Systems"
+#define XVBA_STR_DRIVER_NAME "XvBA backend for VA-API"
+
+typedef struct xvba_driver_data xvba_driver_data_t;
+struct xvba_driver_data {
+ XVBAContext *xvba_context;
+ struct object_heap config_heap;
+ struct object_heap context_heap;
+ struct object_heap surface_heap;
+ struct object_heap buffer_heap;
+ struct object_heap output_heap;
+ struct object_heap image_heap;
+ struct object_heap subpicture_heap;
+ Display *x11_dpy;
+ const char *x11_dpy_name;
+ int x11_screen;
+ Display *x11_dpy_local;
+ XVBADecodeCap *xvba_decode_caps;
+ unsigned int xvba_decode_caps_count;
+ XVBASurfaceCap *xvba_surface_caps;
+ unsigned int xvba_surface_caps_count;
+ VADisplayAttribute *va_background_color;
+ VADisplayAttribute va_display_attrs[XVBA_MAX_DISPLAY_ATTRIBUTES];
+ uint64_t va_display_attrs_mtime[XVBA_MAX_DISPLAY_ATTRIBUTES];
+ unsigned int va_display_attrs_count;
+ unsigned int va_display_type;
+ ColorMatrix cm_brightness;
+ ColorMatrix cm_contrast;
+ ColorMatrix cm_saturation;
+ ColorMatrix cm_hue;
+ ColorMatrix cm_composite;
+ unsigned int cm_composite_ok;
+ char va_vendor[256];
+ unsigned int device_id;
+ unsigned int is_evergreen_gpu : 1;
+ unsigned int is_fusion_igp : 1;
+ unsigned int warn_h264_over_hp_l41 : 1;
+ unsigned int warn_vc1_over_ap_l3 : 1;
+};
+
+typedef struct object_config *object_config_p;
+typedef struct object_context *object_context_p;
+typedef struct object_surface *object_surface_p;
+typedef struct object_buffer *object_buffer_p;
+typedef struct object_output *object_output_p;
+typedef struct object_image *object_image_p;
+
+// Set display type
+int xvba_set_display_type(xvba_driver_data_t *driver_data, unsigned int type)
+ attribute_hidden;
+
+#endif /* XVBA_DRIVER_H */
diff --git a/src/xvba_driver_template.h b/src/xvba_driver_template.h
new file mode 100644
index 0000000..b5a7700
--- /dev/null
+++ b/src/xvba_driver_template.h
@@ -0,0 +1,676 @@
+/*
+ * xvba_driver_template.h - XvBA driver initialization template
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#undef CONCAT_
+#define CONCAT_(x, y) x##y
+#undef CONCAT
+#define CONCAT(x, y) CONCAT_(x, y)
+#undef FUNC
+#define FUNC(name) CONCAT(CONCAT(CONCAT(xvba_,name),_),VA_INIT_SUFFIX)
+
+#undef VA_INIT_CHECK_VERSION
+#define VA_INIT_CHECK_VERSION(major, minor, micro) \
+ (VA_INIT_VERSION_MAJOR > (major) || \
+ (VA_INIT_VERSION_MAJOR == (major) && \
+ VA_INIT_VERSION_MINOR > (minor)) || \
+ (VA_INIT_VERSION_MAJOR == (major) && \
+ VA_INIT_VERSION_MINOR == (minor) && \
+ VA_INIT_VERSION_MICRO >= (micro)))
+
+#undef VA_INIT_CHECK_VERSION_SDS
+#define VA_INIT_CHECK_VERSION_SDS(major, minor, micro, sds) \
+ (VA_INIT_CHECK_VERSION(major, minor, (micro)+1) || \
+ (VA_INIT_CHECK_VERSION(major, minor, micro) && \
+ VA_INIT_VERSION_SDS >= (sds)))
+
+#ifndef VA_INIT_SUFFIX
+#define VA_INIT_SUFFIX Current
+#define VA_INIT_CURRENT 1
+#else
+#define VA_INIT_CURRENT 0
+#endif
+
+#ifndef VA_INIT_VERSION_SDS
+#define VA_INIT_VERSION_SDS 0
+#endif
+
+#ifndef VA_INIT_GLX
+#define VA_INIT_GLX 0
+#endif
+
+#if VA_INIT_CURRENT
+#define VA_DRIVER_VTABLE VADriverVTable
+#define VA_DRIVER_CONTEXT VADriverContext
+#define VA_DRIVER_CONTEXT_P VADriverContextP
+#else
+#define VA_DRIVER_VTABLE CONCAT(VADriverVTable_,VA_INIT_SUFFIX)
+#define VA_DRIVER_VTABLE_GLX_P CONCAT(VADriverVTableGLX_,VA_INIT_SUFFIX)
+#define VA_DRIVER_CONTEXT CONCAT(VADriverContext_,VA_INIT_SUFFIX)
+#define VA_DRIVER_CONTEXT_P CONCAT(VADriverContextP_,VA_INIT_SUFFIX)
+
+typedef struct VA_DRIVER_CONTEXT *VA_DRIVER_CONTEXT_P;
+
+/* Driver VTable */
+struct VA_DRIVER_VTABLE {
+ VAStatus (*vaTerminate) ( VA_DRIVER_CONTEXT_P ctx );
+
+ VAStatus (*vaQueryConfigProfiles) (
+ VADriverContextP ctx,
+ VAProfile *profile_list, /* out */
+ int *num_profiles /* out */
+ );
+
+ VAStatus (*vaQueryConfigEntrypoints) (
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint *entrypoint_list, /* out */
+ int *num_entrypoints /* out */
+ );
+
+ VAStatus (*vaGetConfigAttributes) (
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list, /* in/out */
+ int num_attribs
+ );
+
+ VAStatus (*vaCreateConfig) (
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list,
+ int num_attribs,
+ VAConfigID *config_id /* out */
+ );
+
+ VAStatus (*vaDestroyConfig) (
+ VADriverContextP ctx,
+ VAConfigID config_id
+ );
+
+ VAStatus (*vaQueryConfigAttributes) (
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ VAProfile *profile, /* out */
+ VAEntrypoint *entrypoint, /* out */
+ VAConfigAttrib *attrib_list, /* out */
+ int *num_attribs /* out */
+ );
+
+ VAStatus (*vaCreateSurfaces) (
+ VADriverContextP ctx,
+ int width,
+ int height,
+ int format,
+ int num_surfaces,
+ VASurfaceID *surfaces /* out */
+ );
+
+ VAStatus (*vaDestroySurfaces) (
+ VADriverContextP ctx,
+ VASurfaceID *surface_list,
+ int num_surfaces
+ );
+
+ VAStatus (*vaCreateContext) (
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ int picture_width,
+ int picture_height,
+ int flag,
+ VASurfaceID *render_targets,
+ int num_render_targets,
+ VAContextID *context /* out */
+ );
+
+ VAStatus (*vaDestroyContext) (
+ VADriverContextP ctx,
+ VAContextID context
+ );
+
+ VAStatus (*vaCreateBuffer) (
+ VADriverContextP ctx,
+ VAContextID context, /* in */
+ VABufferType type, /* in */
+ unsigned int size, /* in */
+ unsigned int num_elements, /* in */
+ void *data, /* in */
+ VABufferID *buf_id /* out */
+ );
+
+ VAStatus (*vaBufferSetNumElements) (
+ VADriverContextP ctx,
+ VABufferID buf_id, /* in */
+ unsigned int num_elements /* in */
+ );
+
+ VAStatus (*vaMapBuffer) (
+ VADriverContextP ctx,
+ VABufferID buf_id, /* in */
+ void **pbuf /* out */
+ );
+
+ VAStatus (*vaUnmapBuffer) (
+ VADriverContextP ctx,
+ VABufferID buf_id /* in */
+ );
+
+ VAStatus (*vaDestroyBuffer) (
+ VADriverContextP ctx,
+ VABufferID buffer_id
+ );
+
+ VAStatus (*vaBeginPicture) (
+ VADriverContextP ctx,
+ VAContextID context,
+ VASurfaceID render_target
+ );
+
+ VAStatus (*vaRenderPicture) (
+ VADriverContextP ctx,
+ VAContextID context,
+ VABufferID *buffers,
+ int num_buffers
+ );
+
+ VAStatus (*vaEndPicture) (
+ VADriverContextP ctx,
+ VAContextID context
+ );
+
+ VAStatus (*vaSyncSurface) (
+ VADriverContextP ctx,
+ VASurfaceID render_target
+ );
+
+ VAStatus (*vaQuerySurfaceStatus) (
+ VADriverContextP ctx,
+ VASurfaceID render_target,
+ VASurfaceStatus *status /* out */
+ );
+
+#if VA_INIT_CHECK_VERSION(0,31,2)
+ VAStatus (*vaQuerySurfaceError) (
+ VADriverContextP ctx,
+ VASurfaceID render_target,
+ VAStatus error_status,
+ void **error_info /*out*/
+ );
+#endif
+
+ VAStatus (*vaPutSurface) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VADrawable draw, /* X Drawable */
+ short srcx,
+ short srcy,
+ unsigned short srcw,
+ unsigned short srch,
+ short destx,
+ short desty,
+ unsigned short destw,
+ unsigned short desth,
+ VARectangle *cliprects, /* client supplied clip list */
+ unsigned int number_cliprects, /* number of clip rects in the clip list */
+ unsigned int flags /* de-interlacing flags */
+ );
+
+ VAStatus (*vaQueryImageFormats) (
+ VADriverContextP ctx,
+ VAImageFormat *format_list, /* out */
+ int *num_formats /* out */
+ );
+
+ VAStatus (*vaCreateImage) (
+ VADriverContextP ctx,
+ VAImageFormat *format,
+ int width,
+ int height,
+ VAImage *image /* out */
+ );
+
+ VAStatus (*vaDeriveImage) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImage *image /* out */
+ );
+
+ VAStatus (*vaDestroyImage) (
+ VADriverContextP ctx,
+ VAImageID image
+ );
+
+ VAStatus (*vaSetImagePalette) (
+ VADriverContextP ctx,
+ VAImageID image,
+ /*
+ * pointer to an array holding the palette data. The size of the array is
+ * num_palette_entries * entry_bytes in size. The order of the components
+ * in the palette is described by the component_order in VAImage struct
+ */
+ unsigned char *palette
+ );
+
+ VAStatus (*vaGetImage) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ int x, /* coordinates of the upper left source pixel */
+ int y,
+ unsigned int width, /* width and height of the region */
+ unsigned int height,
+ VAImageID image
+ );
+
+ VAStatus (*vaPutImage) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImageID image,
+ int src_x,
+ int src_y,
+ unsigned int src_width,
+ unsigned int src_height,
+ int dest_x,
+ int dest_y,
+ unsigned int dest_width,
+ unsigned int dest_height
+ );
+
+ VAStatus (*vaQuerySubpictureFormats) (
+ VADriverContextP ctx,
+ VAImageFormat *format_list, /* out */
+ unsigned int *flags, /* out */
+ unsigned int *num_formats /* out */
+ );
+
+ VAStatus (*vaCreateSubpicture) (
+ VADriverContextP ctx,
+ VAImageID image,
+ VASubpictureID *subpicture /* out */
+ );
+
+ VAStatus (*vaDestroySubpicture) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture
+ );
+
+ VAStatus (*vaSetSubpictureImage) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VAImageID image
+ );
+
+ VAStatus (*vaSetSubpictureChromakey) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ unsigned int chromakey_min,
+ unsigned int chromakey_max,
+ unsigned int chromakey_mask
+ );
+
+ VAStatus (*vaSetSubpictureGlobalAlpha) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ float global_alpha
+ );
+
+ VAStatus (*vaAssociateSubpicture) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces,
+ short src_x, /* upper left offset in subpicture */
+ short src_y,
+ unsigned short src_width,
+ unsigned short src_height,
+ short dest_x, /* upper left offset in surface */
+ short dest_y,
+ unsigned short dest_width,
+ unsigned short dest_height,
+ /*
+ * whether to enable chroma-keying or global-alpha
+ * see VA_SUBPICTURE_XXX values
+ */
+ unsigned int flags
+ );
+
+ VAStatus (*vaDeassociateSubpicture) (
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces
+ );
+
+ VAStatus (*vaQueryDisplayAttributes) (
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list, /* out */
+ int *num_attributes /* out */
+ );
+
+ VAStatus (*vaGetDisplayAttributes) (
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list, /* in/out */
+ int num_attributes
+ );
+
+ VAStatus (*vaSetDisplayAttributes) (
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int num_attributes
+ );
+
+#if VA_INIT_CHECK_VERSION(0,31,1)
+ /* used by va trace */
+ VAStatus (*vaBufferInfo) (
+ VADriverContextP ctx,
+ VAContextID context, /* in */
+ VABufferID buf_id, /* in */
+ VABufferType *type, /* out */
+ unsigned int *size, /* out */
+ unsigned int *num_elements /* out */
+ );
+
+ /* lock/unlock surface for external access */
+ VAStatus (*vaLockSurface) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc, /* out for follow argument */
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ unsigned int *buffer_name, /* if it is not NULL, assign the low lever
+ * surface buffer name
+ */
+ void **buffer /* if it is not NULL, map the surface buffer for
+ * CPU access
+ */
+ );
+
+ VAStatus (*vaUnlockSurface) (
+ VADriverContextP ctx,
+ VASurfaceID surface
+ );
+
+#if !VA_INIT_CHECK_VERSION(0,32,0)
+ /* Optional: GLX support hooks */
+ struct VADriverVTableGLX *glx;
+#endif
+#else
+ /* device specific */
+ VAStatus (*vaCreateSurfaceFromCIFrame) (
+ VADriverContextP ctx,
+ unsigned long frame_id,
+ VASurfaceID *surface /* out */
+ );
+
+
+ VAStatus (*vaCreateSurfaceFromV4L2Buf) (
+ VADriverContextP ctx,
+ int v4l2_fd, /* file descriptor of V4L2 device */
+ struct v4l2_format *v4l2_fmt, /* format of V4L2 */
+ struct v4l2_buffer *v4l2_buf, /* V4L2 buffer */
+ VASurfaceID *surface /* out */
+ );
+
+ VAStatus (*vaCopySurfaceToBuffer) (
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc, /* out for follow argument */
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ void **buffer
+ );
+#endif
+};
+
+/* Driver context */
+struct VA_DRIVER_CONTEXT {
+ void *pDriverData;
+#if VA_INIT_CHECK_VERSION(0,32,0)
+ struct VA_DRIVER_VTABLE *vtable;
+ struct VADriverVTableGLX *vtable_glx;
+ struct VADriverVTableEGL *vtable_egl;
+#else
+ struct VA_DRIVER_VTABLE vtable;
+#endif
+#if VA_INIT_CHECK_VERSION(0,31,1)
+ void *vtable_tpi; /* the structure is malloc-ed */
+#endif
+
+ Display *native_dpy;
+ int x11_screen;
+ int version_major;
+ int version_minor;
+ int max_profiles;
+ int max_entrypoints;
+ int max_attributes;
+ int max_image_formats;
+ int max_subpic_formats;
+ int max_display_attributes;
+ const char *str_vendor;
+
+ void *handle; /* dlopen handle */
+
+ void *dri_state;
+#if VA_INIT_CHECK_VERSION(0,31,1)
+ void *glx; /* opaque for GLX code */
+#endif
+};
+#endif
+
+// Check for VA/GLX changes from libVA API >= 0.31.0-sds2
+#if VA_INIT_GLX
+#if VA_INIT_CHECK_VERSION_SDS(0,31,0,2)
+typedef struct VADriverVTableGLX *VA_DRIVER_VTABLE_GLX_P;
+#else
+typedef struct VA_DRIVER_VTABLE *VA_DRIVER_VTABLE_GLX_P;
+#endif
+
+static inline VA_DRIVER_VTABLE_GLX_P FUNC(GetVTableGLX)(VA_DRIVER_CONTEXT_P ctx)
+{
+#if VA_INIT_CHECK_VERSION_SDS(0,31,0,6)
+#if VA_INIT_CHECK_VERSION(0,32,0)
+ /* Upstream VA-API 0.32 */
+ VA_DRIVER_VTABLE_GLX_P *p_vtable_glx = &ctx->vtable_glx;
+#else
+ /* Upstream VA-API 0.31.1 or SDS >= 0.31.0-sds6 */
+ VA_DRIVER_VTABLE_GLX_P *p_vtable_glx = &ctx->vtable.glx;
+#endif
+ VA_DRIVER_VTABLE_GLX_P vtable_glx = *p_vtable_glx;
+
+ if (!vtable_glx) {
+ vtable_glx = calloc(1, sizeof(*vtable_glx));
+ if (!vtable_glx)
+ return NULL;
+ *p_vtable_glx = vtable_glx;
+ }
+ return vtable_glx;
+#elif VA_INIT_CHECK_VERSION_SDS(0,31,0,2)
+ /* SDS >= 0.31.0-sds2 */
+ return &ctx->vtable.glx;
+#else
+ /* Any other VA-API version 0.31.0 or lower */
+ return &ctx->vtable;
+#endif
+}
+
+static inline void FUNC(ReleaseVTableGLX)(VA_DRIVER_CONTEXT_P ctx)
+{
+#if VA_INIT_CHECK_VERSION(0,32,0)
+ free(ctx->vtable_glx);
+ ctx->vtable_glx = NULL;
+#elif VA_INIT_CHECK_VERSION_SDS(0,31,0,6)
+ free(ctx->vtable.glx);
+ ctx->vtable.glx = NULL;
+#endif
+}
+#endif
+
+static VAStatus FUNC(Terminate)(VA_DRIVER_CONTEXT_P ctx)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ xvba_common_Terminate(driver_data);
+
+#if VA_INIT_GLX
+ FUNC(ReleaseVTableGLX)(ctx);
+#endif
+
+ free(ctx->pDriverData);
+ ctx->pDriverData = NULL;
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus FUNC(Initialize)(VA_DRIVER_CONTEXT_P ctx)
+{
+ struct xvba_driver_data *driver_data;
+
+ driver_data = calloc(1, sizeof(*driver_data));
+ if (!driver_data)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ ctx->pDriverData = driver_data;
+ driver_data->x11_dpy = ctx->native_dpy;
+ driver_data->x11_screen = ctx->x11_screen;
+
+ VAStatus va_status = xvba_common_Initialize(driver_data);
+ if (va_status != VA_STATUS_SUCCESS) {
+ FUNC(Terminate)(ctx);
+ return va_status;
+ }
+
+ ctx->version_major = VA_INIT_VERSION_MAJOR;
+ ctx->version_minor = VA_INIT_VERSION_MINOR;
+ ctx->max_profiles = XVBA_MAX_PROFILES;
+ ctx->max_entrypoints = XVBA_MAX_ENTRYPOINTS;
+ ctx->max_attributes = XVBA_MAX_CONFIG_ATTRIBUTES;
+ ctx->max_image_formats = XVBA_MAX_IMAGE_FORMATS;
+ ctx->max_subpic_formats = XVBA_MAX_SUBPICTURE_FORMATS;
+ ctx->max_display_attributes = XVBA_MAX_DISPLAY_ATTRIBUTES;
+ ctx->str_vendor = driver_data->va_vendor;
+
+ struct VA_DRIVER_VTABLE *vtable;
+#if VA_INIT_CHECK_VERSION(0,32,0)
+ vtable = ctx->vtable;
+#else
+ vtable = &ctx->vtable;
+#endif
+ memset(vtable, 0, sizeof(*vtable));
+ vtable->vaTerminate = FUNC(Terminate);
+ vtable->vaQueryConfigEntrypoints = xvba_QueryConfigEntrypoints;
+ vtable->vaQueryConfigProfiles = xvba_QueryConfigProfiles;
+ vtable->vaQueryConfigEntrypoints = xvba_QueryConfigEntrypoints;
+ vtable->vaQueryConfigAttributes = xvba_QueryConfigAttributes;
+ vtable->vaCreateConfig = xvba_CreateConfig;
+ vtable->vaDestroyConfig = xvba_DestroyConfig;
+ vtable->vaGetConfigAttributes = xvba_GetConfigAttributes;
+ vtable->vaCreateSurfaces = xvba_CreateSurfaces;
+ vtable->vaDestroySurfaces = xvba_DestroySurfaces;
+ vtable->vaCreateContext = xvba_CreateContext;
+ vtable->vaDestroyContext = xvba_DestroyContext;
+ vtable->vaCreateBuffer = xvba_CreateBuffer;
+ vtable->vaBufferSetNumElements = xvba_BufferSetNumElements;
+ vtable->vaMapBuffer = xvba_MapBuffer;
+ vtable->vaUnmapBuffer = xvba_UnmapBuffer;
+ vtable->vaDestroyBuffer = xvba_DestroyBuffer;
+ vtable->vaBeginPicture = xvba_BeginPicture;
+ vtable->vaRenderPicture = xvba_RenderPicture;
+ vtable->vaEndPicture = xvba_EndPicture;
+#if VA_INIT_CHECK_VERSION(0,31,0)
+ vtable->vaSyncSurface = xvba_SyncSurface2;
+#else
+ vtable->vaSyncSurface = xvba_SyncSurface3;
+#endif
+ vtable->vaQuerySurfaceStatus = xvba_QuerySurfaceStatus;
+ vtable->vaPutSurface = xvba_PutSurface;
+ vtable->vaQueryImageFormats = xvba_QueryImageFormats;
+ vtable->vaCreateImage = xvba_CreateImage;
+ vtable->vaDeriveImage = xvba_DeriveImage;
+ vtable->vaDestroyImage = xvba_DestroyImage;
+ vtable->vaSetImagePalette = xvba_SetImagePalette;
+ vtable->vaGetImage = xvba_GetImage;
+#if VA_INIT_CHECK_VERSION(0,31,0)
+ vtable->vaPutImage = xvba_PutImage_full;
+#else
+ vtable->vaPutImage = xvba_PutImage;
+ vtable->vaPutImage2 = xvba_PutImage_full;
+#endif
+ vtable->vaQuerySubpictureFormats = xvba_QuerySubpictureFormats;
+ vtable->vaCreateSubpicture = xvba_CreateSubpicture;
+ vtable->vaDestroySubpicture = xvba_DestroySubpicture;
+ vtable->vaSetSubpictureImage = xvba_SetSubpictureImage;
+ vtable->vaSetSubpictureChromakey = xvba_SetSubpictureChromakey;
+ vtable->vaSetSubpictureGlobalAlpha = xvba_SetSubpictureGlobalAlpha;
+#if VA_INIT_CHECK_VERSION(0,31,0)
+ vtable->vaAssociateSubpicture = xvba_AssociateSubpicture_full;
+#else
+ vtable->vaAssociateSubpicture = xvba_AssociateSubpicture;
+ vtable->vaAssociateSubpicture2 = xvba_AssociateSubpicture_full;
+#endif
+ vtable->vaDeassociateSubpicture = xvba_DeassociateSubpicture;
+ vtable->vaQueryDisplayAttributes = xvba_QueryDisplayAttributes;
+ vtable->vaGetDisplayAttributes = xvba_GetDisplayAttributes;
+ vtable->vaSetDisplayAttributes = xvba_SetDisplayAttributes;
+#if VA_INIT_CHECK_VERSION(0,31,1)
+ vtable->vaBufferInfo = xvba_BufferInfo;
+ vtable->vaLockSurface = xvba_LockSurface;
+ vtable->vaUnlockSurface = xvba_UnlockSurface;
+#else
+#if VA_INIT_CHECK_VERSION(0,30,0)
+ vtable->vaCreateSurfaceFromCIFrame = xvba_CreateSurfaceFromCIFrame;
+ vtable->vaCreateSurfaceFromV4L2Buf = xvba_CreateSurfaceFromV4L2Buf;
+ vtable->vaCopySurfaceToBuffer = xvba_CopySurfaceToBuffer;
+#else
+ vtable->vaSetSubpicturePalette = xvba_SetSubpicturePalette;
+ vtable->vaDbgCopySurfaceToBuffer = xvba_DbgCopySurfaceToBuffer;
+#endif
+#endif
+
+#if VA_INIT_GLX
+ VA_DRIVER_VTABLE_GLX_P const glx_vtable = FUNC(GetVTableGLX)(ctx);
+ if (!glx_vtable)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ glx_vtable->vaCreateSurfaceGLX = xvba_CreateSurfaceGLX;
+ glx_vtable->vaDestroySurfaceGLX = xvba_DestroySurfaceGLX;
+ glx_vtable->vaCopySurfaceGLX = xvba_CopySurfaceGLX;
+#endif
+ return VA_STATUS_SUCCESS;
+}
+
+#undef VA_INIT_CURRENT
+#undef VA_INIT_VERSION_MAJOR
+#undef VA_INIT_VERSION_MINOR
+#undef VA_INIT_VERSION_MICRO
+#undef VA_INIT_VERSION_SDS
+#undef VA_INIT_SUFFIX
+#undef VA_INIT_GLX
+
+#undef VA_DRIVER_VTABLE
+#undef VA_DRIVER_VTABLE_GLX_P
+#undef VA_DRIVER_CONTEXT
+#undef VA_DRIVER_CONTEXT_P
diff --git a/src/xvba_dump.c b/src/xvba_dump.c
new file mode 100644
index 0000000..5b63950
--- /dev/null
+++ b/src/xvba_dump.c
@@ -0,0 +1,705 @@
+/*
+ * xvba_dump.c - Dump utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_dump.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Returns string representation of FOURCC
+const char *string_of_FOURCC(uint32_t fourcc)
+{
+ static char str[5];
+ str[0] = fourcc;
+ str[1] = fourcc >> 8;
+ str[2] = fourcc >> 16;
+ str[3] = fourcc >> 24;
+ str[4] = '\0';
+ return str;
+}
+
+// Returns string representation of VA surface format
+const char *string_of_VAConfigAttribRTFormat(unsigned int format)
+{
+ switch (format) {
+#define FORMAT(FORMAT) \
+ case VA_RT_FORMAT_##FORMAT: return #FORMAT
+ FORMAT(YUV420);
+ FORMAT(YUV422);
+ FORMAT(YUV444);
+ }
+ return "<unknown>";
+}
+
+// Returns string representation of XVBA_SURFACE_FLAG
+const char *string_of_XVBA_SURFACE_FLAG(XVBA_SURFACE_FLAG flag)
+{
+ switch (flag) {
+#define FLAG(flag) \
+ case XVBA_##flag: return "XVBA_" #flag
+ FLAG(FRAME);
+ FLAG(TOP_FIELD);
+ FLAG(BOTTOM_FIELD);
+#undef FLAG
+ }
+ return "<unknown>";
+}
+
+// Returns string representation of XVBA_BUFFER
+const char *string_of_XVBA_BUFFER(XVBA_BUFFER buffer_type)
+{
+ switch (buffer_type) {
+#define BUFFER_TYPE(t) \
+ case XVBA_##t##_BUFFER: return "XVBA_" #t "_BUFFER"
+ BUFFER_TYPE(PICTURE_DESCRIPTION);
+ BUFFER_TYPE(QM);
+ BUFFER_TYPE(DATA);
+ BUFFER_TYPE(DATA_CTRL);
+#undef BUFFER_TYPE
+ }
+ return "<unknown>";
+}
+
+// Returns string representation of XVBA_CAPABILITY_ID
+const char *string_of_XVBA_CAPABILITY_ID(XVBA_CAPABILITY_ID cap_id)
+{
+ switch (cap_id) {
+#define CAP_ID(cap_id) \
+ case XVBA_##cap_id: return "XVBA_" #cap_id
+ CAP_ID(H264);
+ CAP_ID(VC1);
+ CAP_ID(MPEG2_IDCT);
+ CAP_ID(MPEG2_VLD);
+#undef CAP_ID
+ }
+ return "<unknown>";
+}
+
+// Returns string representation of XVBA_DECODE_FLAGS
+const char *string_of_XVBA_DECODE_FLAGS(XVBA_DECODE_FLAGS flag)
+{
+ switch (flag) {
+#define FLAG(flag) \
+ case XVBA_##flag: return "XVBA_" #flag
+ FLAG(NOFLAG);
+ FLAG(H264_BASELINE);
+ FLAG(H264_MAIN);
+ FLAG(H264_HIGH);
+ FLAG(VC1_SIMPLE);
+ FLAG(VC1_MAIN);
+ FLAG(VC1_ADVANCED);
+#undef FLAG
+ }
+ return "<unknown>";
+}
+
+// Returns string representation of XVBACodec
+const char *string_of_XVBACodec(XVBACodec codec)
+{
+ const char *str = NULL;
+ switch (codec) {
+#define _(X) case XVBA_CODEC_##X: str = #X; break
+ _(MPEG1);
+ _(MPEG2);
+ _(MPEG4);
+ _(H264);
+ _(VC1);
+#undef _
+ }
+ return str;
+}
+
+// Returns string representation of VABufferType
+const char *string_of_VABufferType(VABufferType type)
+{
+ const char *str = NULL;
+ switch (type) {
+#define _(X) case X: str = #X; break
+ _(VAPictureParameterBufferType);
+ _(VAIQMatrixBufferType);
+ _(VABitPlaneBufferType);
+ _(VASliceGroupMapBufferType);
+ _(VASliceParameterBufferType);
+ _(VASliceDataBufferType);
+ _(VAMacroblockParameterBufferType);
+ _(VAResidualDataBufferType);
+ _(VADeblockingParameterBufferType);
+ _(VAImageBufferType);
+#if VA_CHECK_VERSION(0,30,0)
+ _(VAProtectedSliceDataBufferType);
+ _(VAEncCodedBufferType);
+ _(VAEncSequenceParameterBufferType);
+ _(VAEncPictureParameterBufferType);
+ _(VAEncSliceParameterBufferType);
+ _(VAEncH264VUIBufferType);
+ _(VAEncH264SEIBufferType);
+#endif
+#undef _
+ }
+ return str;
+}
+
+#if USE_TRACER
+#define TRACE trace_print
+#define INDENT(INC) trace_indent(INC)
+#define DUMPi(S, M) TRACE("." #M " = %d,\n", S->M)
+#define DUMPx(S, M) TRACE("." #M " = 0x%08x,\n", S->M)
+#define DUMPp(S, M) TRACE("." #M " = %p,\n", S->M)
+#define DUMPm(S, M, I, J) dump_matrix_NxM(#M, (uint8_t *)S->M, I, J, I * J)
+#else
+#define trace_enabled() (0)
+#define do_nothing() do { } while (0)
+#define TRACE(FORMAT,...) do_nothing()
+#define INDENT(INC) do_nothing()
+#define DUMPi(S, M) do_nothing()
+#define DUMPx(S, M) do_nothing()
+#define DUMPp(S, M) do_nothing()
+#define DUMPm(S, M, I, J) do_nothing()
+#endif
+
+// Dumps matrix[N][M] = N rows x M columns (uint8_t)
+static void
+dump_matrix_NxM(const char *label, uint8_t *matrix, int N, int M, int L)
+{
+ int i, j, n = 0;
+
+ TRACE(".%s = {\n", label);
+ INDENT(1);
+ for (j = 0; j < N; j++) {
+ for (i = 0; i < M; i++, n++) {
+ if (n >= L)
+ break;
+ if (i > 0)
+ TRACE(", ");
+ TRACE("0x%02x", matrix[n]);
+ }
+ if (j < (N - 1))
+ TRACE(",");
+ TRACE("\n");
+ if (n >= L)
+ break;
+ }
+ INDENT(-1);
+ TRACE("}\n");
+}
+
+// Dump XVBAPictureDescriptor buffer
+static void
+dump_XVBABufferDescriptor__XVBA_PICTURE_DESCRIPTION_BUFFER(
+ XVBABufferDescriptor *buffer
+)
+{
+ if (!buffer)
+ return;
+
+ object_context_p obj_context = buffer->appPrivate;
+ ASSERT(obj_context);
+ if (!obj_context)
+ return;
+
+ XVBAPictureDescriptor *pic_desc = buffer->bufferXVBA;
+ if (!pic_desc)
+ return;
+
+ DUMPp(pic_desc, past_surface);
+ DUMPp(pic_desc, future_surface);
+ DUMPi(pic_desc, profile);
+ DUMPi(pic_desc, level);
+ DUMPi(pic_desc, width_in_mb);
+ DUMPi(pic_desc, height_in_mb);
+ DUMPi(pic_desc, picture_structure);
+
+ switch (obj_context->xvba_codec) {
+ case XVBA_CODEC_H264:
+ TRACE(".sps_info.flags = 0x%08x, /* %d:%d:%d:%d:%d:%d */\n",
+ pic_desc->sps_info.flags,
+ pic_desc->sps_info.avc.residual_colour_transform_flag,
+ pic_desc->sps_info.avc.delta_pic_always_zero_flag,
+ pic_desc->sps_info.avc.gaps_in_frame_num_value_allowed_flag,
+ pic_desc->sps_info.avc.frame_mbs_only_flag,
+ pic_desc->sps_info.avc.mb_adaptive_frame_field_flag,
+ pic_desc->sps_info.avc.direct_8x8_inference_flag);
+ break;
+ case XVBA_CODEC_VC1:
+ TRACE(".sps_info.flags = 0x%08x, /* %d:%d:%d:%d:%d:%d:%d */\n",
+ pic_desc->sps_info.flags,
+ pic_desc->sps_info.vc1.postprocflag,
+ pic_desc->sps_info.vc1.pulldown,
+ pic_desc->sps_info.vc1.interlace,
+ pic_desc->sps_info.vc1.tfcntrflag,
+ pic_desc->sps_info.vc1.finterpflag,
+ pic_desc->sps_info.vc1.psf,
+ pic_desc->sps_info.vc1.second_field);
+ break;
+ default:
+ break;
+ }
+
+ DUMPi(pic_desc, chroma_format);
+
+ if (obj_context->xvba_codec == XVBA_CODEC_H264) {
+ DUMPi(pic_desc, avc_bit_depth_luma_minus8);
+ DUMPi(pic_desc, avc_bit_depth_chroma_minus8);
+ DUMPi(pic_desc, avc_log2_max_frame_num_minus4);
+ DUMPi(pic_desc, avc_pic_order_cnt_type);
+ DUMPi(pic_desc, avc_log2_max_pic_order_cnt_lsb_minus4);
+ DUMPi(pic_desc, avc_num_ref_frames);
+ }
+
+ switch (obj_context->xvba_codec) {
+ case XVBA_CODEC_H264:
+ TRACE(".pps_info.flags = 0x%08x, /* %d:%d:%d:%d:%d:%d:%d:%d */\n",
+ pic_desc->pps_info.flags,
+ pic_desc->pps_info.avc.entropy_coding_mode_flag,
+ pic_desc->pps_info.avc.pic_order_present_flag,
+ pic_desc->pps_info.avc.weighted_pred_flag,
+ pic_desc->pps_info.avc.weighted_bipred_idc,
+ pic_desc->pps_info.avc.deblocking_filter_control_present_flag,
+ pic_desc->pps_info.avc.constrained_intra_pred_flag,
+ pic_desc->pps_info.avc.redundant_pic_cnt_present_flag,
+ pic_desc->pps_info.avc.transform_8x8_mode_flag);
+ break;
+ case XVBA_CODEC_VC1:
+ TRACE(".pps_info.flags = 0x%08x, /* %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d */\n",
+ pic_desc->pps_info.flags,
+ pic_desc->pps_info.vc1.panscan_flag,
+ pic_desc->pps_info.vc1.refdist_flag,
+ pic_desc->pps_info.vc1.loopfilter,
+ pic_desc->pps_info.vc1.fastuvmc,
+ pic_desc->pps_info.vc1.extended_mv,
+ pic_desc->pps_info.vc1.dquant,
+ pic_desc->pps_info.vc1.vstransform,
+ pic_desc->pps_info.vc1.overlap,
+ pic_desc->pps_info.vc1.quantizer,
+ pic_desc->pps_info.vc1.extended_dmv,
+ pic_desc->pps_info.vc1.maxbframes,
+ pic_desc->pps_info.vc1.rangered,
+ pic_desc->pps_info.vc1.syncmarker,
+ pic_desc->pps_info.vc1.multires,
+ pic_desc->pps_info.vc1.range_mapy_flag,
+ pic_desc->pps_info.vc1.range_mapy,
+ pic_desc->pps_info.vc1.range_mapuv_flag,
+ pic_desc->pps_info.vc1.range_mapuv);
+ break;
+ default:
+ break;
+ }
+
+ if (obj_context->xvba_codec == XVBA_CODEC_H264) {
+ DUMPi(pic_desc, avc_num_slice_groups_minus1);
+ DUMPi(pic_desc, avc_slice_group_map_type);
+ DUMPi(pic_desc, avc_num_ref_idx_l0_active_minus1);
+ DUMPi(pic_desc, avc_num_ref_idx_l1_active_minus1);
+
+ DUMPi(pic_desc, avc_pic_init_qp_minus26);
+ DUMPi(pic_desc, avc_pic_init_qs_minus26);
+ DUMPi(pic_desc, avc_chroma_qp_index_offset);
+ DUMPi(pic_desc, avc_second_chroma_qp_index_offset);
+
+ DUMPi(pic_desc, avc_slice_group_change_rate_minus1);
+
+ DUMPi(pic_desc, avc_curr_field_order_cnt_list[0]);
+ DUMPi(pic_desc, avc_curr_field_order_cnt_list[1]);
+ }
+
+ DUMPi(pic_desc, avc_frame_num);
+ DUMPi(pic_desc, avc_intra_flag);
+ DUMPi(pic_desc, avc_reference);
+}
+
+// Dump data buffer
+static void
+dump_XVBABufferDescriptor__XVBA_DATA_BUFFER(XVBABufferDescriptor *buffer)
+{
+ if (!buffer)
+ return;
+
+ uint8_t *data = buffer->bufferXVBA;
+ if (!data)
+ return;
+
+ dump_matrix_NxM("data", data + buffer->data_offset, 4, 12, buffer->data_size_in_buffer);
+}
+
+// Dump XVBADataCtrl buffer
+static void
+dump_XVBABufferDescriptor__XVBA_DATA_CTRL_BUFFER(XVBABufferDescriptor *buffer)
+{
+ if (!buffer)
+ return;
+
+ XVBADataCtrl *data_ctrl = buffer->bufferXVBA;
+ if (!data_ctrl)
+ return;
+
+ DUMPi(data_ctrl, SliceBitsInBuffer);
+ DUMPi(data_ctrl, SliceDataLocation);
+ DUMPi(data_ctrl, SliceBytesInBuffer);
+}
+
+// Dump quantization matrix buffer (H.264 only for now)
+static void
+dump_XVBABufferDescriptor__XVBA_QM_BUFFER(XVBABufferDescriptor *buffer)
+{
+ if (!buffer)
+ return;
+
+ object_context_p obj_context = buffer->appPrivate;
+ ASSERT(obj_context);
+ if (!obj_context)
+ return;
+
+ if (obj_context->xvba_codec != XVBA_CODEC_H264)
+ return;
+
+ XVBAQuantMatrixAvc *qm = buffer->bufferXVBA;
+ if (!qm)
+ return;
+
+ DUMPm(qm, bScalingLists4x4, 6, 16);
+ DUMPm(qm, bScalingLists8x8[0], 8, 8);
+ DUMPm(qm, bScalingLists8x8[1], 8, 8);
+}
+
+// Dump XVBABufferDescriptor
+static void dump_XVBABufferDescriptor(XVBABufferDescriptor *buffer)
+{
+ if (!buffer)
+ return;
+
+ TRACE("%s = {\n", string_of_XVBA_BUFFER(buffer->buffer_type));
+ INDENT(1);
+ DUMPi(buffer, buffer_size);
+ DUMPp(buffer, bufferXVBA);
+ DUMPi(buffer, data_size_in_buffer);
+ DUMPi(buffer, data_offset);
+ switch (buffer->buffer_type) {
+ case XVBA_PICTURE_DESCRIPTION_BUFFER:
+ dump_XVBABufferDescriptor__XVBA_PICTURE_DESCRIPTION_BUFFER(buffer);
+ break;
+ case XVBA_DATA_BUFFER:
+ dump_XVBABufferDescriptor__XVBA_DATA_BUFFER(buffer);
+ break;
+ case XVBA_DATA_CTRL_BUFFER:
+ dump_XVBABufferDescriptor__XVBA_DATA_CTRL_BUFFER(buffer);
+ break;
+ case XVBA_QM_BUFFER:
+ dump_XVBABufferDescriptor__XVBA_QM_BUFFER(buffer);
+ break;
+ default:
+ break;
+ }
+ INDENT(-1);
+ TRACE("};\n");
+}
+
+// Dumps XVBACreateContext()
+void dump_XVBACreateContext(void *input_arg)
+{
+ XVBA_Create_Context_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateContext(): display %p, drawable 0x%08x\n",
+ input->display,
+ input->draw);
+}
+
+void dump_XVBACreateContext_output(void *output_arg)
+{
+ XVBA_Create_Context_Output * const output = output_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateContext(): -> context %p\n", output->context);
+}
+
+// Dumps XVBADestroyContext()
+void dump_XVBADestroyContext(void *context)
+{
+ if (trace_enabled())
+ TRACE("XVBADestroyContext(): context %p\n", context);
+}
+
+// Dumps XVBACreateSurface()
+void dump_XVBACreateSurface(void *input_arg)
+{
+ XVBA_Create_Surface_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateSurface(): session %p, size %ux%u, format %s\n",
+ input->session,
+ input->width,
+ input->height,
+ string_of_FOURCC(input->surface_type));
+}
+
+void dump_XVBACreateSurface_output(void *output_arg)
+{
+ XVBA_Create_Surface_Output * const output = output_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateSurface(): -> surface %p\n", output->surface);
+}
+
+// Dumps XVBACreateGLSharedSurface()
+void dump_XVBACreateGLSharedSurface(void *input_arg)
+{
+ XVBA_Create_GLShared_Surface_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateGLSharedSurface(): session %p, GLXContext %p, texture %d\n",
+ input->session,
+ input->glcontext,
+ input->gltexture);
+}
+
+void dump_XVBACreateGLSharedSurface_output(void *output_arg)
+{
+ XVBA_Create_GLShared_Surface_Output * const output = output_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateGLSharedSurface(): -> surface %p\n", output->surface);
+}
+
+// Dumps XVBADestroySurface()
+void dump_XVBADestroySurface(void *surface)
+{
+ if (trace_enabled())
+ TRACE("XVBADestroySurface(): surface %p\n", surface);
+}
+
+// Dumps XVBAGetCapDecode()
+void dump_XVBAGetCapDecode(void *input_arg)
+{
+ XVBA_GetCapDecode_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBAGetCapDecode(): context %p\n", input->context);
+}
+
+void
+dump_XVBAGetCapDecode_output_decode_caps(
+ unsigned int num_decode_caps,
+ XVBADecodeCap *decode_caps
+)
+{
+ unsigned int i;
+
+ if (!trace_enabled())
+ return;
+
+ INDENT(1);
+ for (i = 0; i < num_decode_caps; i++) {
+ XVBADecodeCap * const decode_cap = &decode_caps[i];
+ TRACE("capability %d = {\n", i + 1);
+ INDENT(1);
+ TRACE("capability_id = %s\n",
+ string_of_XVBA_CAPABILITY_ID(decode_cap->capability_id));
+ TRACE("flags = %s\n",
+ string_of_XVBA_DECODE_FLAGS(decode_cap->flags));
+ TRACE("surface_type = %s\n",
+ string_of_FOURCC(decode_cap->surface_type));
+ INDENT(-1);
+ TRACE("}\n");
+ }
+ INDENT(-1);
+}
+
+void
+dump_XVBAGetCapDecode_output_surface_caps(
+ unsigned int num_surface_caps,
+ XVBASurfaceCap *surface_caps
+)
+{
+ unsigned int i;
+
+ if (!trace_enabled())
+ return;
+
+ INDENT(1);
+ for (i = 0; i < num_surface_caps; i++) {
+ XVBASurfaceCap * const surface_cap = &surface_caps[i];
+ TRACE("getsurface target %d = {\n", i + 1);
+ INDENT(1);
+ TRACE(" format = %s\n",
+ string_of_FOURCC(surface_cap->format));
+ TRACE(" flag = %s\n",
+ string_of_XVBA_SURFACE_FLAG(surface_cap->flag));
+ INDENT(-1);
+ TRACE("}\n");
+ }
+ INDENT(-1);
+}
+
+// Dumps XVBACreateDecode()
+void dump_XVBACreateDecode(void *input_arg)
+{
+ XVBA_Create_Decode_Session_Input * const input = input_arg;
+
+ if (!trace_enabled())
+ return;
+
+ TRACE("XVBACreateDecode()");
+ TRACE(": context %p", input->context);
+ TRACE(", size %ux%u", input->width, input->height);
+
+ if (input->decode_cap) {
+ XVBADecodeCap * const decode_cap = input->decode_cap;
+ TRACE(", capability_id %s, flags %s, surface_type %s",
+ string_of_XVBA_CAPABILITY_ID(decode_cap->capability_id),
+ string_of_XVBA_DECODE_FLAGS(decode_cap->flags),
+ string_of_FOURCC(decode_cap->surface_type));
+ }
+ TRACE("\n");
+}
+
+void dump_XVBACreateDecode_output(void *output_arg)
+{
+ XVBA_Create_Decode_Session_Output * const output = output_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateDecode(): -> session %p\n", output->session);
+}
+
+// Dumps XVBADestroyDecode()
+void dump_XVBADestroyDecode(void *session)
+{
+ if (trace_enabled())
+ TRACE("XVBADestroyDecode(): session %p\n", session);
+}
+
+// Dumps XVBACreateDecodeBuffers()
+void dump_XVBACreateDecodeBuffers(void *input_arg)
+{
+ XVBA_Create_DecodeBuff_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateDecodeBuffers(): session %p, %s x %d\n",
+ input->session,
+ string_of_XVBA_BUFFER(input->buffer_type),
+ input->num_of_buffers);
+}
+
+void dump_XVBACreateDecodeBuffers_output(void *output_arg)
+{
+ XVBA_Create_DecodeBuff_Output * const output = output_arg;
+
+ if (trace_enabled())
+ TRACE("XVBACreateDecodeBuffers(): -> buffers %p\n",
+ output->buffer_list);
+}
+
+// Dumps XVBADestroyDecodeBuffers()
+void dump_XVBADestroyDecodeBuffers(void *input_arg)
+{
+ XVBA_Destroy_Decode_Buffers_Input const * input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBADestroyDecodeBuffers(): session %p, buffers %p x %d\n",
+ input->session,
+ input->buffer_list,
+ input->num_of_buffers_in_list);
+}
+
+// Dumps XVBAStartDecodePicture()
+void dump_XVBAStartDecodePicture(void *input_arg)
+{
+ XVBA_Decode_Picture_Start_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBAStartDecodePicture(): session %p, surface %p\n",
+ input->session,
+ input->target_surface);
+}
+
+// Dumps XVBADecodePicture()
+void dump_XVBADecodePicture(void *input_arg)
+{
+ XVBA_Decode_Picture_Input * const input = input_arg;
+
+ if (!trace_enabled())
+ return;
+
+ TRACE("XVBADecodePicture(): session %p\n", input->session);
+
+ unsigned int i;
+ for (i = 0; i < input->num_of_buffers_in_list; i++)
+ dump_XVBABufferDescriptor(input->buffer_list[i]);
+}
+
+// Dumps XVBAEndDecodePicture()
+void dump_XVBAEndDecodePicture(void *input_arg)
+{
+ XVBA_Decode_Picture_End_Input * const input = input_arg;
+
+ if (trace_enabled())
+ TRACE("XVBAEndDecodePicture(): session %p\n", input->session);
+}
+
+// Dumps XVBAGetSurface()
+void dump_XVBAGetSurface(void *input_arg)
+{
+ if (!trace_enabled())
+ return;
+
+#if XVBA_CHECK_VERSION(0,74)
+ if (!xvba_check_version(0,74))
+ return;
+
+ XVBA_Get_Surface_Input * const input = input_arg;
+
+ TRACE("XVBAGetSurface()");
+ TRACE(": session %p", input->session);
+ TRACE(", surface %p", input->src_surface);
+ TRACE(", dest pixels %p size %ux%u pitch %d format %s",
+ input->target_buffer,
+ input->target_width,
+ input->target_height,
+ input->target_pitch,
+ string_of_FOURCC(input->target_parameter.surfaceType));
+#if 0
+ /* XXX: always default to XVBA_FRAME here */
+ TRACE(" flag %s",string_of_XVBA_SURFACE_FLAG(input->target_parameter.flag));
+#endif
+ TRACE("\n");
+#endif
+}
+
+// Dumps XVBATransferSurface()
+void dump_XVBATransferSurface(void *input_arg)
+{
+ if (!trace_enabled())
+ return;
+
+#if XVBA_CHECK_VERSION(0,74)
+ if (!xvba_check_version(0,74))
+ return;
+
+ XVBA_Transfer_Surface_Input * const input = input_arg;
+
+ TRACE("XVBATransferSurface()");
+ TRACE(": session %p", input->session);
+ TRACE(", from surface %p", input->src_surface);
+ TRACE(", to GL surface %p", input->target_surface);
+ TRACE(", flag %s", string_of_XVBA_SURFACE_FLAG(input->flag));
+ TRACE("\n");
+#endif
+}
diff --git a/src/xvba_dump.h b/src/xvba_dump.h
new file mode 100644
index 0000000..2f4ff14
--- /dev/null
+++ b/src/xvba_dump.h
@@ -0,0 +1,145 @@
+/*
+ * xvba_dump.h - Dump utilities
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_DUMP_H
+#define XVBA_DUMP_H
+
+#include "xvba_driver.h"
+#include "xvba_video.h"
+
+// Returns string representation of FOURCC
+const char *string_of_FOURCC(uint32_t fourcc)
+ attribute_hidden;
+
+// Returns string representation of VA surface format
+const char *string_of_VAConfigAttribRTFormat(unsigned int format)
+ attribute_hidden;
+
+// Returns string representation of XVBA_SURFACE_FLAG
+const char *string_of_XVBA_SURFACE_FLAG(XVBA_SURFACE_FLAG flag)
+ attribute_hidden;
+
+// Returns string representation of XVBA_BUFFER
+const char *string_of_XVBA_BUFFER(XVBA_BUFFER buffer_type)
+ attribute_hidden;
+
+// Returns string representation of XVBA_CAPABILITY_ID
+const char *string_of_XVBA_CAPABILITY_ID(XVBA_CAPABILITY_ID cap_id)
+ attribute_hidden;
+
+// Returns string representation of XVBA_DECODE_FLAGS
+const char *string_of_XVBA_DECODE_FLAGS(XVBA_DECODE_FLAGS flag)
+ attribute_hidden;
+
+// Returns string representation of XVBACodec
+const char *string_of_XVBACodec(XVBACodec codec)
+ attribute_hidden;
+
+// Returns string representation of VABufferType
+const char *string_of_VABufferType(VABufferType type)
+ attribute_hidden;
+
+// Dumps XVBACreateContext()
+void dump_XVBACreateContext(void *input)
+ attribute_hidden;
+void dump_XVBACreateContext_output(void *output)
+ attribute_hidden;
+
+// Dumps XVBADestroyContext()
+void dump_XVBADestroyContext(void *context)
+ attribute_hidden;
+
+// Dumps XVBACreateSurface()
+void dump_XVBACreateSurface(void *input)
+ attribute_hidden;
+void dump_XVBACreateSurface_output(void *output)
+ attribute_hidden;
+
+// Dumps XVBACreateGLSharedSurface()
+void dump_XVBACreateGLSharedSurface(void *input)
+ attribute_hidden;
+void dump_XVBACreateGLSharedSurface_output(void *output)
+ attribute_hidden;
+
+// Dumps XVBADestroySurface()
+void dump_XVBADestroySurface(void *surface)
+ attribute_hidden;
+
+// Dumps XVBAGetCapDecode()
+void dump_XVBAGetCapDecode(void *input)
+ attribute_hidden;
+
+void
+dump_XVBAGetCapDecode_output_decode_caps(
+ unsigned int num_decode_caps,
+ XVBADecodeCap *decode_caps
+) attribute_hidden;
+
+void
+dump_XVBAGetCapDecode_output_surface_caps(
+ unsigned int num_surface_caps,
+ XVBASurfaceCap *surface_caps
+) attribute_hidden;
+
+// Dumps XVBACreateDecode()
+void dump_XVBACreateDecode(void *input)
+ attribute_hidden;
+void dump_XVBACreateDecode_output(void *output)
+ attribute_hidden;
+
+// Dumps XVBADestroyDecode()
+void dump_XVBADestroyDecode(void *session)
+ attribute_hidden;
+
+// Dumps XVBACreateDecodeBuffers()
+void dump_XVBACreateDecodeBuffers(void *input)
+ attribute_hidden;
+void dump_XVBACreateDecodeBuffers_output(void *output)
+ attribute_hidden;
+
+// Dumps XVBADestroyDecodeBuffers()
+void dump_XVBADestroyDecodeBuffers(void *input)
+ attribute_hidden;
+
+// Dumps XVBAStartDecodePicture()
+void dump_XVBAStartDecodePicture(void *input)
+ attribute_hidden;
+
+// Dumps XVBADecodePicture()
+void dump_XVBADecodePicture(void *input)
+ attribute_hidden;
+
+// Dumps XVBAEndDecodePicture()
+void dump_XVBAEndDecodePicture(void *input)
+ attribute_hidden;
+
+// Dumps XVBAUpdateSurface()
+void dump_XVBAUpdateSurface(void *input)
+ attribute_hidden;
+
+// Dumps XVBAGetSurface()
+void dump_XVBAGetSurface(void *input)
+ attribute_hidden;
+
+// Dumps XVBATransferSurface()
+void dump_XVBATransferSurface(void *input)
+ attribute_hidden;
+
+#endif /* XVBA_DUMP_H */
diff --git a/src/xvba_gate.c b/src/xvba_gate.c
new file mode 100644
index 0000000..bb66975
--- /dev/null
+++ b/src/xvba_gate.c
@@ -0,0 +1,956 @@
+/*
+ * xvba_gate.c - XvBA hooks
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_gate.h"
+#include "xvba_dump.h"
+#include "utils.h"
+#include "fglrxinfo.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+#if USE_DLOPEN
+# include <dlfcn.h>
+#endif
+
+#define OPENGL_LIBRARY "libGL.so.1"
+#define XVBA_LIBRARY "libXvBAW.so.1"
+//#define XVBA_LIBRARY "libAMDXvBA.so.1"
+
+/* Only call into the tracer if tracer is enabled */
+#if USE_TRACER
+# define TRACE(func, args) dump_##func args
+#else
+# define TRACE(func, args) do { } while (0)
+#endif
+
+/* Defined to 1 if lazy XvBA context destruction is used */
+#define USE_REFCOUNT 1
+
+
+/* ====================================================================== */
+/* === XvBA VTable === */
+/* ====================================================================== */
+
+typedef Bool (*XVBAQueryExtensionProc) (Display *dpy, int *vers);
+typedef Status (*XVBACreateContextProc) (void *input, void *output);
+typedef Status (*XVBADestroyContextProc) (void *context);
+typedef Bool (*XVBAGetSessionInfoProc) (void *input, void *output);
+typedef Status (*XVBACreateSurfaceProc) (void *input, void *output);
+typedef Status (*XVBACreateGLSharedSurfaceProc)(void *input, void *output);
+typedef Status (*XVBADestroySurfaceProc) (void *surface);
+typedef Status (*XVBACreateDecodeBuffersProc) (void *input, void *output);
+typedef Status (*XVBADestroyDecodeBuffersProc) (void *input);
+typedef Status (*XVBAGetCapDecodeProc) (void *input, void *output);
+typedef Status (*XVBACreateDecodeProc) (void *input, void *output);
+typedef Status (*XVBADestroyDecodeProc) (void *session);
+typedef Status (*XVBAStartDecodePictureProc) (void *input);
+typedef Status (*XVBADecodePictureProc) (void *input);
+typedef Status (*XVBAEndDecodePictureProc) (void *input);
+typedef Status (*XVBASyncSurfaceProc) (void *input, void *output);
+typedef Status (*XVBAGetSurfaceProc) (void *input);
+typedef Status (*XVBATransferSurfaceProc) (void *input);
+
+static struct {
+ XVBAQueryExtensionProc QueryExtension;
+ XVBACreateContextProc CreateContext;
+ XVBADestroyContextProc DestroyContext;
+ XVBAGetSessionInfoProc GetSessionInfo;
+ XVBACreateSurfaceProc CreateSurface;
+ XVBACreateGLSharedSurfaceProc CreateGLSharedSurface;
+ XVBADestroySurfaceProc DestroySurface;
+ XVBACreateDecodeBuffersProc CreateDecodeBuffers;
+ XVBADestroyDecodeBuffersProc DestroyDecodeBuffers;
+ XVBAGetCapDecodeProc GetCapDecode;
+ XVBACreateDecodeProc CreateDecode;
+ XVBADestroyDecodeProc DestroyDecode;
+ XVBAStartDecodePictureProc StartDecodePicture;
+ XVBADecodePictureProc DecodePicture;
+ XVBAEndDecodePictureProc EndDecodePicture;
+ XVBASyncSurfaceProc SyncSurface;
+ XVBAGetSurfaceProc GetSurface;
+ XVBATransferSurfaceProc TransferSurface;
+} g_XVBA_vtable;
+
+static unsigned int g_init_count;
+static void *g_gl_lib_handle;
+static void *g_XVBA_lib_handle;
+
+int xvba_gate_init(void)
+{
+ void *handle;
+
+ if (g_init_count > 0) {
+ g_init_count++;
+ return 0;
+ }
+
+#if USE_DLOPEN
+ /* XXX: workaround broken XvBA libraries */
+ dlerror();
+ if ((handle = dlopen(OPENGL_LIBRARY, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
+ xvba_error_message("dlopen(%s): %s\n", OPENGL_LIBRARY, dlerror());
+ return -1;
+ }
+ g_gl_lib_handle = handle;
+
+ dlerror();
+ if ((handle = dlopen(XVBA_LIBRARY, RTLD_LAZY)) == NULL) {
+ xvba_error_message("dlopen(%s): %s\n", XVBA_LIBRARY, dlerror());
+ return -1;
+ }
+ g_XVBA_lib_handle = handle;
+
+#define INIT_PROC(PREFIX, PROC) do { \
+ g_##PREFIX##_vtable.PROC = (PREFIX##PROC##Proc) \
+ dlsym(g_##PREFIX##_lib_handle, #PREFIX #PROC); \
+ } while (0)
+
+#define INIT_PROC_CHECK(PREFIX, PROC) do { \
+ dlerror(); \
+ INIT_PROC(PREFIX, PROC); \
+ if (dlerror()) { \
+ dlclose(g_##PREFIX##_lib_handle); \
+ g_##PREFIX##_lib_handle = NULL; \
+ return -1; \
+ } \
+ } while (0)
+
+#define XVBA_INIT_PROC(PROC) INIT_PROC_CHECK(XVBA, PROC)
+
+ XVBA_INIT_PROC(QueryExtension);
+ XVBA_INIT_PROC(CreateContext);
+ XVBA_INIT_PROC(DestroyContext);
+ XVBA_INIT_PROC(GetSessionInfo);
+ XVBA_INIT_PROC(CreateSurface);
+ XVBA_INIT_PROC(CreateGLSharedSurface);
+ XVBA_INIT_PROC(DestroySurface);
+ XVBA_INIT_PROC(CreateDecodeBuffers);
+ XVBA_INIT_PROC(DestroyDecodeBuffers);
+ XVBA_INIT_PROC(GetCapDecode);
+ XVBA_INIT_PROC(CreateDecode);
+ XVBA_INIT_PROC(DestroyDecode);
+ XVBA_INIT_PROC(StartDecodePicture);
+ XVBA_INIT_PROC(DecodePicture);
+ XVBA_INIT_PROC(EndDecodePicture);
+ XVBA_INIT_PROC(SyncSurface);
+
+ /* Optional hooks (XvBA >= 0.74) */
+ INIT_PROC(XVBA, GetSurface);
+ INIT_PROC(XVBA, TransferSurface);
+
+#undef XVBA_INIT_PROC
+#undef INIT_PROC
+
+#endif
+
+ g_init_count++;
+ return 0;
+}
+
+void xvba_gate_exit(void)
+{
+#if USE_DLOPEN
+ if (--g_init_count > 0)
+ return;
+
+ if (g_XVBA_lib_handle) {
+ dlclose(g_XVBA_lib_handle);
+ g_XVBA_lib_handle = NULL;
+ }
+
+ if (g_gl_lib_handle) {
+ dlclose(g_gl_lib_handle);
+ g_gl_lib_handle = NULL;
+ }
+#endif
+}
+
+#if USE_DLOPEN
+#define DEFINE_VTABLE_ENTRY(PREFIX, PROC, RETVAL, DECL_ARGS, CALL_ARGS) \
+static inline RETVAL PREFIX##_##PROC DECL_ARGS \
+{ \
+ ASSERT(g_##PREFIX##_vtable.PROC); \
+ return g_##PREFIX##_vtable.PROC CALL_ARGS; \
+}
+#else
+#define DEFINE_VTABLE_ENTRY(PREFIX, PROC, RETVAL, DECL_ARGS, CALL_ARGS) \
+static inline RETVAL PREFIX##_##PROC DECL_ARGS \
+{ \
+ return PREFIX##PROC CALL_ARGS; \
+}
+#endif
+
+DEFINE_VTABLE_ENTRY(
+ XVBA, QueryExtension,
+ Bool, (Display *dpy, int *version),
+ (dpy, version));
+DEFINE_VTABLE_ENTRY(
+ XVBA, CreateContext,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, DestroyContext,
+ Status, (void *context),
+ (context));
+DEFINE_VTABLE_ENTRY(
+ XVBA, GetSessionInfo,
+ Bool, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, CreateSurface,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, CreateGLSharedSurface,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, DestroySurface,
+ Status, (void *surface),
+ (surface));
+DEFINE_VTABLE_ENTRY(
+ XVBA, CreateDecodeBuffers,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, DestroyDecodeBuffers,
+ Status, (void *input),
+ (input));
+DEFINE_VTABLE_ENTRY(
+ XVBA, GetCapDecode,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, CreateDecode,
+ Status, (void *input, void *output),
+ (input, output));
+DEFINE_VTABLE_ENTRY(
+ XVBA, DestroyDecode,
+ Status, (void *session),
+ (session));
+DEFINE_VTABLE_ENTRY(
+ XVBA, StartDecodePicture,
+ Status, (void *input),
+ (input));
+DEFINE_VTABLE_ENTRY(
+ XVBA, DecodePicture,
+ Status, (void *input),
+ (input));
+DEFINE_VTABLE_ENTRY(
+ XVBA, EndDecodePicture,
+ Status, (void *input),
+ (input));
+DEFINE_VTABLE_ENTRY(
+ XVBA, SyncSurface,
+ Status, (void *input, void *output),
+ (input, output));
+#if XVBA_CHECK_VERSION(0,74)
+DEFINE_VTABLE_ENTRY(
+ XVBA, GetSurface,
+ Status, (void *input),
+ (input));
+DEFINE_VTABLE_ENTRY(
+ XVBA, TransferSurface,
+ Status, (void *input),
+ (input));
+#endif
+
+#undef DEFINE_VTABLE_ENTRY
+
+static int g_version_major = -1;
+static int g_version_minor = -1;
+
+int xvba_get_version(int *pmajor, int *pminor)
+{
+ /* XXX: call XVBAQueryExtension() with a dummy display here? */
+ if (g_version_major < 0 || g_version_minor < 0)
+ return -1;
+
+ if (pmajor)
+ *pmajor = g_version_major;
+ if (pminor)
+ *pminor = g_version_minor;
+ return 0;
+}
+
+static inline int check_version(int major, int minor)
+{
+ /* Compile-time checks */
+ if (XVBA_VERSION_MAJOR < major)
+ return 0;
+ if (XVBA_VERSION_MAJOR == major && XVBA_VERSION_MINOR < minor)
+ return 0;
+
+ /* Run-time checks */
+ if (g_version_major < major)
+ return 0;
+ if (g_version_major == major && g_version_minor < minor)
+ return 0;
+
+ return 1;
+}
+
+int xvba_check_version(int major, int minor)
+{
+ if (xvba_get_version(NULL, NULL) < 0) /* XXX: ensure global version init */
+ return 0;
+ return check_version(major, minor);
+}
+
+
+/* ====================================================================== */
+/* === XvBA Wrappers === */
+/* ====================================================================== */
+
+static int xvba_destroy_context_real(XVBAContext *context);
+static int xvba_destroy_decode_session_real(XVBASession *session);
+
+static inline XVBAContext *xvba_context_ref(XVBAContext *context)
+{
+ ++context->refcount;
+ return context;
+}
+
+static inline void xvba_context_unref(XVBAContext *context)
+{
+ if (--context->refcount == 0)
+ xvba_destroy_context_real(context);
+}
+
+static inline XVBASession *xvba_session_ref(XVBASession *session)
+{
+ ++session->refcount;
+ return session;
+}
+
+static inline void xvba_session_unref(XVBASession *session)
+{
+ if (--session->refcount == 0)
+ session->destroy(session);
+}
+
+static int xvba_check_status(Status status, const char *msg)
+{
+ if (status != Success) {
+ xvba_information_message("%s: status %d\n", msg, status);
+ return 0;
+ }
+ return 1;
+}
+
+int xvba_query_extension(Display *display, int *pversion)
+{
+ int version;
+
+ if (pversion)
+ *pversion = 0;
+
+ if (!XVBA_QueryExtension(display, &version))
+ return -1;
+
+ if (pversion)
+ *pversion = version;
+
+ g_version_major = (version >> 16) & 0xffff;
+ g_version_minor = version & 0xffff;
+ return 0;
+}
+
+XVBAContext *xvba_create_context(Display *display, Drawable drawable)
+{
+ XVBA_Create_Context_Input input;
+ XVBA_Create_Context_Output output;
+ XVBAContext *context = NULL;
+ Status status;
+
+ context = malloc(sizeof(*context));
+ if (!context)
+ goto error;
+
+ input.size = sizeof(input);
+ input.display = display;
+ input.draw = drawable;
+ output.size = sizeof(output);
+ output.context = NULL;
+
+ TRACE(XVBACreateContext, (&input));
+
+ status = XVBA_CreateContext(&input, &output);
+
+ if (!xvba_check_status(status, "XVBA_CreateContext()"))
+ goto error;
+ if (!output.context)
+ goto error;
+
+ context->context = output.context;
+ context->refcount = 1;
+
+ TRACE(XVBACreateContext_output, (&output));
+ return context;
+
+error:
+ free(context);
+ return NULL;
+}
+
+static int xvba_destroy_context_real(XVBAContext *context)
+{
+ TRACE(XVBADestroyContext, (context->context));
+
+ Status status = XVBA_DestroyContext(context->context);
+ free(context);
+ if (!xvba_check_status(status, "XVBA_DestroyContext()"))
+ return -1;
+ return 0;
+}
+
+int xvba_destroy_context(XVBAContext *context)
+{
+ if (USE_REFCOUNT) {
+ xvba_context_unref(context);
+ return 0;
+ }
+ return xvba_destroy_context_real(context);
+}
+
+XVBASurface *
+xvba_create_surface(
+ XVBASession *session,
+ unsigned int width,
+ unsigned int height,
+ XVBA_SURFACE_FORMAT format
+)
+{
+ XVBA_Create_Surface_Input input;
+ XVBA_Create_Surface_Output output;
+ XVBASurface *surface;
+ Status status;
+
+ surface = malloc(sizeof(*surface));
+ if (!surface)
+ return NULL;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.width = width;
+ input.height = height;
+ input.surface_type = format;
+ output.size = sizeof(output);
+ output.surface = NULL;
+
+ TRACE(XVBACreateSurface, (&input));
+
+ status = XVBA_CreateSurface(&input, &output);
+ if (!xvba_check_status(status, "XVBA_CreateSurface()"))
+ goto error;
+ if (!output.surface)
+ goto error;
+
+ TRACE(XVBACreateSurface_output, (&output));
+
+ surface->session = xvba_session_ref(session);
+ surface->type = XVBA_SURFACETYPE_NORMAL;
+ surface->surface = output.surface;
+ surface->info.normal.width = width;
+ surface->info.normal.height = height;
+ surface->info.normal.format = format;
+ return surface;
+
+error:
+ free(surface);
+ return NULL;
+}
+
+#if USE_GLX
+XVBASurface *
+xvba_create_surface_gl(
+ XVBASession *session,
+ GLXContext gl_context,
+ unsigned int gl_texture
+)
+{
+ XVBA_Create_GLShared_Surface_Input input;
+ XVBA_Create_GLShared_Surface_Output output;
+ XVBASurface *surface;
+ Status status;
+
+ surface = malloc(sizeof(*surface));
+ if (!surface)
+ return NULL;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.glcontext = gl_context;
+ input.gltexture = gl_texture;
+ output.size = sizeof(output);
+ output.surface = NULL;
+
+ TRACE(XVBACreateGLSharedSurface, (&input));
+
+ status = XVBA_CreateGLSharedSurface(&input, &output);
+ if (!xvba_check_status(status, "XVBA_CreateGLSharedSurface()"))
+ goto error;
+ if (!output.surface)
+ goto error;
+
+ TRACE(XVBACreateGLSharedSurface_output, (&output));
+
+ surface->session = xvba_session_ref(session);
+ surface->type = XVBA_SURFACETYPE_GLSHARED;
+ surface->surface = output.surface;
+ surface->info.glshared.glcontext = gl_context;
+ surface->info.glshared.gltexture = gl_texture;
+ return surface;
+
+error:
+ free(surface);
+ return NULL;
+}
+#endif
+
+int xvba_destroy_surface(XVBASurface *surface)
+{
+ TRACE(XVBADestroySurface, (surface->surface));
+
+ Status status = XVBA_DestroySurface(surface->surface);
+ xvba_session_unref(surface->session);
+ free(surface);
+ if (!xvba_check_status(status, "XVBA_DestroySurface()"))
+ return -1;
+ return 0;
+}
+
+int
+xvba_get_session_info(
+ XVBAContext *context,
+ unsigned int *getcapdecode_size
+)
+{
+ XVBA_GetSessionInfo_Input input;
+ XVBA_GetSessionInfo_Output output;
+ Status status;
+
+ if (getcapdecode_size)
+ *getcapdecode_size = 0;
+
+ input.size = sizeof(input);
+ input.context = context->context;
+ output.size = sizeof(output);
+
+ status = XVBA_GetSessionInfo(&input, &output);
+ if (!xvba_check_status(status, "XVBA_GetSessionInfo()"))
+ return -1;
+
+ if (getcapdecode_size)
+ *getcapdecode_size = output.getcapdecode_output_size;
+ return 0;
+}
+
+/* This data structure is compatible with XvBA >= 0.73 */
+typedef struct {
+ unsigned int size;
+ unsigned int num_decode_caps;
+ XVBADecodeCap decode_caps_list[];
+} XVBA_GetCapDecode_Output_Base;
+
+int
+xvba_get_decode_caps(
+ XVBAContext *context,
+ unsigned int *pdecode_caps_count,
+ XVBADecodeCap **pdecode_caps
+)
+{
+ XVBA_GetCapDecode_Input input;
+ XVBA_GetCapDecode_Output_Base *output;
+ XVBADecodeCap *decode_caps;
+ unsigned int output_size, num_decode_caps;
+ Status status;
+
+ if (pdecode_caps_count)
+ *pdecode_caps_count = 0;
+ if (pdecode_caps)
+ *pdecode_caps = NULL;
+
+ input.size = sizeof(input);
+ input.context = context->context;
+ if (xvba_get_session_info(context, &output_size) < 0)
+ return -1;
+ output_size = MAX(output_size, sizeof(XVBA_GetCapDecode_Output));
+ output = alloca(output_size);
+ output->size = output_size;
+
+ TRACE(XVBAGetCapDecode, (&input));
+
+ status = XVBA_GetCapDecode(&input, output);
+ if (!xvba_check_status(status, "XVBA_GetCapDecode()"))
+ return -1;
+
+ num_decode_caps = output->num_decode_caps;
+ decode_caps = malloc(num_decode_caps * sizeof(decode_caps[0]));
+ if (!decode_caps)
+ return -1;
+ memcpy(decode_caps, output->decode_caps_list,
+ num_decode_caps * sizeof(decode_caps[0]));
+
+ if (pdecode_caps_count)
+ *pdecode_caps_count = num_decode_caps;
+ if (pdecode_caps)
+ *pdecode_caps = decode_caps;
+
+ TRACE(XVBAGetCapDecode_output_decode_caps, (num_decode_caps, decode_caps));
+ return 0;
+}
+
+int
+xvba_get_surface_caps(
+ XVBAContext *context,
+ unsigned int *psurface_caps_count,
+ XVBASurfaceCap **psurface_caps
+)
+{
+ if (psurface_caps_count)
+ *psurface_caps_count = 0;
+ if (psurface_caps)
+ *psurface_caps = NULL;
+
+ if (!check_version(0,74))
+ return 0;
+
+#if XVBA_CHECK_VERSION(0,74)
+ XVBA_GetCapDecode_Input input;
+ XVBA_GetCapDecode_Output *output;
+ XVBASurfaceCap *surface_caps;
+ unsigned int i, output_size, num_surface_caps;
+ Status status;
+
+ input.size = sizeof(input);
+ input.context = context->context;
+ if (xvba_get_session_info(context, &output_size) < 0)
+ return -1;
+ output_size = MAX(output_size, sizeof(XVBA_GetCapDecode_Output));
+ output = alloca(output_size);
+ output->size = output_size;
+
+ TRACE(XVBAGetCapDecode, (&input));
+
+ status = XVBA_GetCapDecode(&input, output);
+ if (!xvba_check_status(status, "XVBA_GetCapDecode()"))
+ return -1;
+
+ num_surface_caps = output->num_of_getsurface_target;
+ surface_caps = malloc(num_surface_caps * sizeof(surface_caps[0]));
+ if (!surface_caps)
+ return -1;
+ for (i = 0; i < num_surface_caps; i++) {
+ surface_caps[i].format = output->getsurface_target_list[i].surfaceType;
+ surface_caps[i].flag = output->getsurface_target_list[i].flag;
+ }
+
+ if (psurface_caps_count)
+ *psurface_caps_count = num_surface_caps;
+ if (psurface_caps)
+ *psurface_caps = surface_caps;
+
+ TRACE(XVBAGetCapDecode_output_surface_caps, (num_surface_caps, surface_caps));
+ return 0;
+#endif
+ return -1;
+}
+
+XVBASession *
+xvba_create_decode_session(
+ XVBAContext *context,
+ unsigned int width,
+ unsigned int height,
+ XVBADecodeCap *decode_cap
+)
+{
+ XVBA_Create_Decode_Session_Input input;
+ XVBA_Create_Decode_Session_Output output;
+ XVBASession *session = NULL;
+ Status status;
+
+ session = malloc(sizeof(*session));
+ if (!session)
+ goto error;
+
+ input.size = sizeof(input);
+ input.width = width;
+ input.height = height;
+ input.context = context->context;
+ input.decode_cap = decode_cap;
+ output.size = sizeof(output);
+ output.session = NULL;
+
+ TRACE(XVBACreateDecode, (&input));
+
+ status = XVBA_CreateDecode(&input, &output);
+ if (!xvba_check_status(status, "XVBA_CreateDecode()"))
+ return NULL;
+ if (!output.session)
+ return NULL;
+
+ session->context = xvba_context_ref(context);
+ session->session = output.session;
+ session->refcount = 1;
+ session->destroy = xvba_destroy_decode_session_real;
+
+ TRACE(XVBACreateDecode_output, (&output));
+ return session;
+
+error:
+ free(session);
+ return NULL;
+}
+
+static int xvba_destroy_decode_session_real(XVBASession *session)
+{
+ TRACE(XVBADestroyDecode, (session->session));
+
+ Status status = XVBA_DestroyDecode(session->session);
+ xvba_context_unref(session->context);
+ free(session);
+ if (!xvba_check_status(status, "XVBA_DestroyDecode()"))
+ return -1;
+ return 0;
+}
+
+int xvba_destroy_decode_session(XVBASession *session)
+{
+ if (USE_REFCOUNT) {
+ xvba_session_unref(session);
+ return 0;
+ }
+ return xvba_destroy_decode_session_real(session);
+}
+
+void *
+xvba_create_decode_buffers(
+ XVBASession *session,
+ int type,
+ unsigned int num_buffers
+)
+{
+ XVBA_Create_DecodeBuff_Input input;
+ XVBA_Create_DecodeBuff_Output output;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.buffer_type = type;
+ input.num_of_buffers = num_buffers;
+ output.size = sizeof(output);
+
+ TRACE(XVBACreateDecodeBuffers, (&input));
+
+ status = XVBA_CreateDecodeBuffers(&input, &output);
+ if (!xvba_check_status(status, "XVBA_CreateDecodeBuffers()"))
+ return NULL;
+ if (output.num_of_buffers_in_list != num_buffers)
+ return NULL;
+
+ TRACE(XVBACreateDecodeBuffers_output, (&output));
+ return output.buffer_list;
+}
+
+int
+xvba_destroy_decode_buffers(
+ XVBASession *session,
+ void *buffers,
+ unsigned int num_buffers
+)
+{
+ XVBA_Destroy_Decode_Buffers_Input input;
+ Status status;
+
+ if (buffers == NULL || num_buffers == 0)
+ return 0;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.num_of_buffers_in_list = num_buffers;
+ input.buffer_list = buffers;
+
+ TRACE(XVBADestroyDecodeBuffers, (&input));
+
+ status = XVBA_DestroyDecodeBuffers(&input);
+ if (!xvba_check_status(status, "XVBA_DestroyDecodeBuffers()"))
+ return -1;
+ return 0;
+}
+
+int xvba_decode_picture_start(XVBASession *session, XVBASurface *surface)
+{
+ XVBA_Decode_Picture_Start_Input input;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.target_surface = surface->surface;
+
+ TRACE(XVBAStartDecodePicture, (&input));
+
+ status = XVBA_StartDecodePicture(&input);
+ if (!xvba_check_status(status, "XVBA_StartDecodePicture()"))
+ return -1;
+ return 0;
+}
+
+int
+xvba_decode_picture(
+ XVBASession *session,
+ XVBABufferDescriptor **buffers,
+ unsigned int num_buffers
+)
+{
+ XVBA_Decode_Picture_Input input;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.num_of_buffers_in_list= num_buffers;
+ input.buffer_list = buffers;
+
+ TRACE(XVBADecodePicture, (&input));
+
+ status = XVBA_DecodePicture(&input);
+ if (!xvba_check_status(status, "XVBA_DecodePicture()"))
+ return -1;
+ return 0;
+}
+
+int xvba_decode_picture_end(XVBASession *session)
+{
+ XVBA_Decode_Picture_End_Input input;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+
+ TRACE(XVBAEndDecodePicture, (&input));
+
+ status = XVBA_EndDecodePicture(&input);
+ if (!xvba_check_status(status, "XVBA_EndDecodePicture()"))
+ return -1;
+ return 0;
+}
+
+int xvba_sync_surface(XVBASession *session, XVBASurface *surface, int query)
+{
+ XVBA_Surface_Sync_Input input;
+ XVBA_Surface_Sync_Output output;
+ int status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.surface = surface->surface;
+ input.query_status = query;
+ output.size = sizeof(output);
+
+ status = XVBA_SyncSurface(&input, &output);
+ if (!xvba_check_status(status, "XVBA_SyncSurface()"))
+ return -1;
+
+ switch (query) {
+ case XVBA_GET_SURFACE_STATUS:
+ status = output.status_flags;
+ break;
+ case XVBA_GET_DECODE_ERRORS:
+ status = output.decode_error.type;
+ break;
+ default:
+ status = -1;
+ break;
+ }
+
+ return status;
+}
+
+int
+xvba_get_surface(
+ XVBASession *session,
+ XVBASurface *surface,
+ XVBA_SURFACE_FORMAT format,
+ uint8_t *target,
+ unsigned int pitch,
+ unsigned int width,
+ unsigned int height
+)
+{
+ if (!check_version(0,74))
+ return -1;
+
+#if XVBA_CHECK_VERSION(0,74)
+ XVBA_Get_Surface_Input input;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.src_surface = surface->surface;
+ input.target_buffer = target;
+ input.target_pitch = pitch;
+ input.target_width = width;
+ input.target_height = height;
+ input.target_parameter.size = sizeof(input.target_parameter);
+ input.target_parameter.surfaceType = format;
+ input.target_parameter.flag = XVBA_FRAME;
+
+ TRACE(XVBAGetSurface, (&input));
+
+ status = XVBA_GetSurface(&input);
+ if (!xvba_check_status(status, "XVBA_GetSurface()"))
+ return -1;
+ return 0;
+#endif
+ return -1;
+}
+
+int
+xvba_transfer_surface(
+ XVBASession *session,
+ XVBASurface *dst_surface,
+ const XVBASurface *src_surface,
+ unsigned int flags
+)
+{
+ if (!check_version(0,74))
+ return -1;
+
+#if XVBA_CHECK_VERSION(0,74)
+ XVBA_Transfer_Surface_Input input;
+ Status status;
+
+ input.size = sizeof(input);
+ input.session = session->session;
+ input.src_surface = src_surface->surface;
+ input.target_surface = dst_surface->surface;
+ input.flag = flags;
+
+ TRACE(XVBATransferSurface, (&input));
+
+ status = XVBA_TransferSurface(&input);
+ if (!xvba_check_status(status, "XVBA_TransferSurface()"))
+ return -1;
+ return 0;
+#endif
+ return -1;
+}
diff --git a/src/xvba_gate.h b/src/xvba_gate.h
new file mode 100644
index 0000000..ca06bb9
--- /dev/null
+++ b/src/xvba_gate.h
@@ -0,0 +1,218 @@
+/*
+ * xvba_gate.h - XvBA hooks
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_GATE_H
+#define XVBA_GATE_H
+
+#include <X11/Xlib.h>
+#include <amdxvba.h>
+
+#if USE_GLX
+#include <GL/glx.h>
+#endif
+
+#define XVBA_FAKE XVBA_FOURCC('F','A','K','E')
+#define XVBA_MAX_SUBPICTURES 16
+#define XVBA_MAX_SUBPICTURE_FORMATS 3
+
+typedef struct _XVBAContext {
+ void *context;
+ unsigned int refcount;
+} XVBAContext;
+
+typedef struct _XVBASession {
+ XVBAContext *context;
+ void *session;
+ unsigned int refcount;
+ int (*destroy)(struct _XVBASession *);
+} XVBASession;
+
+typedef struct _XVBASurfaceCap {
+ XVBA_SURFACE_FORMAT format;
+ XVBA_SURFACE_FLAG flag;
+} XVBASurfaceCap;
+
+typedef enum {
+ XVBA_SURFACETYPE_NORMAL = 0,
+ XVBA_SURFACETYPE_GLSHARED
+} XVBASurfaceType;
+
+typedef struct {
+ XVBASession *session;
+ XVBASurfaceType type;
+ void *surface;
+ union {
+ struct {
+ unsigned int width;
+ unsigned int height;
+ XVBA_SURFACE_FORMAT format;
+ } normal;
+ struct {
+ void *glcontext;
+ unsigned int gltexture;
+ } glshared;
+ } info;
+} XVBASurface;
+
+/** Initialize XvBA API hooks */
+int xvba_gate_init(void)
+ attribute_hidden;
+
+/** Deinitialize XvBA API hooks */
+void xvba_gate_exit(void)
+ attribute_hidden;
+
+/** Get version major, minor */
+int xvba_get_version(int *major, int *minor)
+ attribute_hidden;
+
+/** Check the minimal version requirement is met */
+int xvba_check_version(int major, int minor)
+ attribute_hidden;
+
+/** XVBAQueryExtension */
+int xvba_query_extension(Display *display, int *version)
+ attribute_hidden;
+
+/** XVBACreateContext */
+XVBAContext *xvba_create_context(Display *display, Drawable drawable)
+ attribute_hidden;
+
+/** XVBADestroyContext */
+int xvba_destroy_context(XVBAContext *context)
+ attribute_hidden;
+
+/** XVBACreateSurface */
+XVBASurface *
+xvba_create_surface(
+ XVBASession *session,
+ unsigned int width,
+ unsigned int height,
+ XVBA_SURFACE_FORMAT format
+) attribute_hidden;
+
+#if USE_GLX
+/** XVBACreateGLSharedSurface */
+XVBASurface *
+xvba_create_surface_gl(
+ XVBASession *session,
+ GLXContext gl_context,
+ unsigned int gl_texture
+) attribute_hidden;
+#endif
+
+/** XVBADestroySurface */
+int xvba_destroy_surface(XVBASurface *surface)
+ attribute_hidden;
+
+/** XVBAGetSessionInfo */
+int
+xvba_get_session_info(
+ XVBAContext *context,
+ unsigned int *getcapdecode_size
+) attribute_hidden;
+
+/** XVBAGetCapDecode (XVBA_GetCapDecode_Output.decode_caps_list) */
+int
+xvba_get_decode_caps(
+ XVBAContext *context,
+ unsigned int *pdecode_caps_count,
+ XVBADecodeCap **pdecode_caps
+) attribute_hidden;
+
+/** XVBAGetCapDecode (XVBA_GetCapDecode_Output.getsurface_target_list) */
+int
+xvba_get_surface_caps(
+ XVBAContext *context,
+ unsigned int *psurface_caps_count,
+ XVBASurfaceCap **psurface_caps
+) attribute_hidden;
+
+/** XVBACreateDecode */
+XVBASession *
+xvba_create_decode_session(
+ XVBAContext *context,
+ unsigned int width,
+ unsigned int height,
+ XVBADecodeCap *decode_cap
+) attribute_hidden;
+
+/** XVBADestroyDecode */
+int xvba_destroy_decode_session(XVBASession *session)
+ attribute_hidden;
+
+/** XVBACreateDecodeBuffers */
+void *
+xvba_create_decode_buffers(
+ XVBASession *session,
+ int type,
+ unsigned int num_buffers
+) attribute_hidden;
+
+/** XVBADestroyDecodeBuffers */
+int
+xvba_destroy_decode_buffers(
+ XVBASession *session,
+ void *buffers,
+ unsigned int num_buffers
+) attribute_hidden;
+
+/** XVBAStartDecodePicture */
+int xvba_decode_picture_start(XVBASession *session, XVBASurface *surface)
+ attribute_hidden;
+
+/** XVBADecodePicture */
+int
+xvba_decode_picture(
+ XVBASession *session,
+ XVBABufferDescriptor **buffers,
+ unsigned int num_buffers
+) attribute_hidden;
+
+/** XVBAEndDecodePicture */
+int xvba_decode_picture_end(XVBASession *session)
+ attribute_hidden;
+
+/** XVBASyncSurface */
+int xvba_sync_surface(XVBASession *session, XVBASurface *surface, int query)
+ attribute_hidden;
+
+/** XVBAGetSurface */
+int
+xvba_get_surface(
+ XVBASession *session,
+ XVBASurface *surface,
+ XVBA_SURFACE_FORMAT format,
+ uint8_t *target,
+ unsigned int pitch,
+ unsigned int width,
+ unsigned int height
+) attribute_hidden;
+
+/** XVBATransferSurface */
+int
+xvba_transfer_surface(
+ XVBASession *session,
+ XVBASurface *dst_surface,
+ const XVBASurface *src_surface,
+ unsigned int flags
+) attribute_hidden;
+
+#endif /* XVBA_GATE_H */
diff --git a/src/xvba_image.c b/src/xvba_image.c
new file mode 100644
index 0000000..7e0ae50
--- /dev/null
+++ b/src/xvba_image.c
@@ -0,0 +1,822 @@
+/*
+ * xvba_image.c - XvBA backend for VA-API (VAImage)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_image.h"
+#include "xvba_video.h"
+#include "xvba_buffer.h"
+#include "xvba_decode.h"
+#include "xvba_dump.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// List of supported image formats
+typedef struct {
+ uint32_t format;
+ VAImageFormat va_format;
+} xvba_image_format_map_t;
+
+static const xvba_image_format_map_t xvba_image_formats_map[] = {
+ { XVBA_NV12, { VA_FOURCC('N','V','1','2'), VA_LSB_FIRST, 12 } },
+ { XVBA_YV12, { VA_FOURCC('Y','V','1','2'), VA_LSB_FIRST, 12 } },
+ { XVBA_YV12, { VA_FOURCC('I','4','2','0'), VA_LSB_FIRST, 12 } },
+ { XVBA_ARGB, { VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32,
+ 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 } },
+ { XVBA_FAKE, { VA_FOURCC('R','G','B','A'), VA_LSB_FIRST, 32,
+ 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 } },
+ { 0, }
+};
+
+// Initializes XvBA decode caps
+static int ensure_surface_caps(xvba_driver_data_t *driver_data)
+{
+ int status;
+
+ if (driver_data->xvba_surface_caps && driver_data->xvba_surface_caps_count)
+ return 1;
+
+ if (driver_data->xvba_surface_caps) {
+ free(driver_data->xvba_surface_caps);
+ driver_data->xvba_surface_caps = NULL;
+ }
+ driver_data->xvba_surface_caps_count = 0;
+
+ status = xvba_get_surface_caps(
+ driver_data->xvba_context,
+ &driver_data->xvba_surface_caps_count,
+ &driver_data->xvba_surface_caps
+ );
+ if (status < 0)
+ return 0;
+ return 1;
+}
+
+// Check VA image format represents RGB
+int is_rgb_format(const VAImageFormat *image_format)
+{
+ switch (image_format->fourcc) {
+ case VA_FOURCC('B','G','R','A'):
+ case VA_FOURCC('R','G','B','A'):
+ case VA_FOURCC('A','R','G','B'):
+ case VA_FOURCC('A','B','G','R'):
+ return 1;
+ }
+ return 0;
+}
+
+// Check VA image formats are the same
+int compare_image_formats(const VAImageFormat *a, const VAImageFormat *b)
+{
+ return (a->fourcc == b->fourcc &&
+ a->byte_order == b->byte_order &&
+ a->bits_per_pixel == b->bits_per_pixel &&
+ (is_rgb_format(a)
+ ? (a->depth == b->depth &&
+ a->red_mask == b->red_mask &&
+ a->green_mask == b->green_mask &&
+ a->blue_mask == b->blue_mask &&
+ a->alpha_mask == b->alpha_mask)
+ : 1));
+}
+
+// Checks whether the XvBA implementation supports the specified image format
+static inline int
+is_supported_format(xvba_driver_data_t *driver_data, uint32_t format)
+{
+ unsigned int i;
+
+ if (!ensure_surface_caps(driver_data))
+ return 0;
+
+ for (i = 0; i < driver_data->xvba_surface_caps_count; i++) {
+ XVBASurfaceCap * const surface_cap = &driver_data->xvba_surface_caps[i];
+ if (surface_cap->format == format && surface_cap->flag == XVBA_FRAME)
+ return 1;
+ }
+ return 0;
+}
+
+// Enable "PutImage hacks", this reinitializes the XvBA state
+static VAStatus
+putimage_hacks_enable(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ object_image_p obj_image,
+ PutImageHacksType type
+)
+{
+ ASSERT(type == PUTIMAGE_HACKS_SURFACE ||
+ type == PUTIMAGE_HACKS_IMAGE);
+
+ PutImageHacks *h = obj_surface->putimage_hacks;
+ if (!h) {
+ h = malloc(sizeof(*h));
+ if (!h)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ h->type = type;
+ h->xvba_surface = NULL;
+ h->obj_image = NULL;
+ obj_surface->putimage_hacks = h;
+ }
+
+ if (type == PUTIMAGE_HACKS_IMAGE) {
+ if (h->obj_image &&
+ !compare_image_formats(&h->obj_image->image.format, &obj_image->image.format)) {
+ destroy_image(driver_data, h->obj_image);
+ h->obj_image = NULL;
+ }
+
+ if (!h->obj_image) {
+ h->obj_image = create_image(
+ driver_data,
+ obj_surface->width,
+ obj_surface->height,
+ &obj_image->image.format
+ );
+ if (!h->obj_image)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+ ASSERT(h->obj_image->image.width == obj_surface->width);
+ ASSERT(h->obj_image->image.height == obj_surface->height);
+
+ h->type = PUTIMAGE_HACKS_IMAGE;
+ return VA_STATUS_SUCCESS;
+ }
+
+ if (h->xvba_surface) {
+ if (h->xvba_surface->info.normal.format == obj_image->xvba_format)
+ return VA_STATUS_SUCCESS;
+ xvba_destroy_surface(h->xvba_surface);
+ h->xvba_surface = NULL;
+ }
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ h->xvba_surface = xvba_create_surface(
+ obj_context->xvba_session,
+ obj_surface->width,
+ obj_surface->height,
+ obj_image->xvba_format
+ );
+ if (!h->xvba_surface)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// Disable "PutImage hacks", flush pending pictures
+void
+putimage_hacks_disable(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+)
+{
+ if (!obj_surface->putimage_hacks)
+ return;
+
+ if (obj_surface->putimage_hacks->obj_image) {
+ destroy_image(driver_data, obj_surface->putimage_hacks->obj_image);
+ obj_surface->putimage_hacks->obj_image = NULL;
+ }
+
+ if (obj_surface->putimage_hacks->xvba_surface) {
+ xvba_destroy_surface(obj_surface->putimage_hacks->xvba_surface);
+ obj_surface->putimage_hacks->xvba_surface = NULL;
+ }
+
+ free(obj_surface->putimage_hacks);
+ obj_surface->putimage_hacks = NULL;
+}
+
+// Check we need the "PutImage hacks"
+static VAStatus
+putimage_hacks_check(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ object_image_p obj_image
+)
+{
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+
+ PutImageHacksType type;
+ /* If the surface was never used for decoding, it's safe to be
+ aliased to plain pixels data (represented via a VAImage) */
+ if (!obj_surface->used_for_decoding)
+ type = PUTIMAGE_HACKS_IMAGE;
+ else
+ type = PUTIMAGE_HACKS_SURFACE;
+
+ if (obj_surface->putimage_hacks &&
+ obj_surface->putimage_hacks->type != type)
+ putimage_hacks_disable(driver_data, obj_surface);
+
+ VAStatus status;
+ switch (type) {
+ case PUTIMAGE_HACKS_NONE:
+ status = VA_STATUS_SUCCESS;
+ break;
+ case PUTIMAGE_HACKS_SURFACE:
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+ // fall-through
+ default:
+ status = putimage_hacks_enable(
+ driver_data,
+ obj_surface,
+ obj_image,
+ type
+ );
+ break;
+ }
+ return status;
+}
+
+// vaQueryImageFormats
+VAStatus
+xvba_QueryImageFormats(
+ VADriverContextP ctx,
+ VAImageFormat *format_list,
+ int *num_formats
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!format_list)
+ return VA_STATUS_SUCCESS;
+
+ int i, n = 0;
+ for (i = 0; xvba_image_formats_map[i].format != 0; i++) {
+ const xvba_image_format_map_t * const f = &xvba_image_formats_map[i];
+ /* XXX: XvBA is really too stupid: the set of supported formats for
+ XVBAGetSurface() and for XVBAUploadSurface() do NOT intersect... */
+ if (1 || is_supported_format(driver_data, f->format))
+ format_list[n++] = f->va_format;
+ }
+
+ /* If the assert fails then XVBA_MAX_IMAGE_FORMATS needs to be bigger */
+ ASSERT(n <= XVBA_MAX_IMAGE_FORMATS);
+ if (num_formats)
+ *num_formats = n;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// Create image
+object_image_p
+create_image(
+ xvba_driver_data_t *driver_data,
+ unsigned int width,
+ unsigned int height,
+ VAImageFormat *format
+)
+{
+ VAImageID image_id = object_heap_allocate(&driver_data->image_heap);
+ if (image_id == VA_INVALID_ID)
+ return NULL;
+
+ object_image_p obj_image = XVBA_IMAGE(image_id);
+ if (!obj_image)
+ return NULL;
+
+ VAImage * const image = &obj_image->image;
+ image->image_id = image_id;
+ image->buf = VA_INVALID_ID;
+
+ /* XXX: we align size to 16-pixel boundaries because the image may
+ be used to retrieve XvBA surface pixels and this requires exact
+ match of the dimensions. And since yet another stupid AMD bug
+ requires 16-pixel alignment for surfaces... */
+ unsigned int width2, height2, size2, awidth, aheight, size;
+ awidth = (width + 15) & -16U;
+ aheight = (height + 15) & -16U;
+ size = awidth * aheight;
+ width2 = (awidth + 1) / 2;
+ height2 = (aheight + 1) / 2;
+ size2 = width2 * height2;
+
+ XVBA_SURFACE_FORMAT xvba_format;
+ switch (format->fourcc) {
+ case VA_FOURCC('N','V','1','2'):
+ xvba_format = XVBA_NV12;
+ image->num_planes = 2;
+ image->pitches[0] = awidth;
+ image->offsets[0] = 0;
+ image->pitches[1] = awidth;
+ image->offsets[1] = size;
+ image->data_size = size + 2 * size2;
+ break;
+ case VA_FOURCC('I','4','2','0'):
+ xvba_format = XVBA_YV12;
+ image->num_planes = 3;
+ image->pitches[0] = awidth;
+ image->offsets[0] = 0;
+ image->pitches[1] = width2;
+ image->offsets[1] = size + size2;
+ image->pitches[2] = width2;
+ image->offsets[2] = size;
+ image->data_size = size + 2 * size2;
+ break;
+ case VA_FOURCC('Y','V','1','2'):
+ xvba_format = XVBA_YV12;
+ image->num_planes = 3;
+ image->pitches[0] = awidth;
+ image->offsets[0] = 0;
+ image->pitches[1] = width2;
+ image->offsets[1] = size;
+ image->pitches[2] = width2;
+ image->offsets[2] = size + size2;
+ image->data_size = size + 2 * size2;
+ break;
+ case VA_FOURCC('Y','U','Y','2'):
+ xvba_format = XVBA_YUY2;
+ image->num_planes = 1;
+ image->pitches[0] = awidth * 2;
+ image->offsets[0] = 0;
+ image->data_size = image->pitches[0] * aheight;
+ break;
+ case VA_FOURCC('B','G','R','A'):
+ if (format->bits_per_pixel != 32)
+ goto error;
+ xvba_format = XVBA_ARGB;
+ image->num_planes = 1;
+ image->pitches[0] = awidth * 4;
+ image->offsets[0] = 0;
+ image->data_size = image->pitches[0] * aheight;
+ break;
+ case VA_FOURCC('R','G','B','A'):
+ if (format->bits_per_pixel != 32)
+ goto error;
+ xvba_format = XVBA_NONE;
+ image->num_planes = 1;
+ image->pitches[0] = awidth * 4;
+ image->offsets[0] = 0;
+ image->data_size = image->pitches[0] * aheight;
+ break;
+ default:
+ goto error;
+ }
+ obj_image->xvba_format = xvba_format;
+ obj_image->xvba_width = awidth;
+ obj_image->xvba_height = aheight;
+ obj_image->hw.mtime = 0;
+ obj_image->hw.xvba = NULL;
+ obj_image->hw.glx = NULL;
+
+ object_buffer_p obj_buffer;
+ obj_buffer = create_va_buffer(
+ driver_data,
+ VA_INVALID_ID,
+ VAImageBufferType,
+ 1, image->data_size
+ );
+ if (!obj_buffer)
+ goto error;
+
+ image->image_id = image_id;
+ image->buf = obj_buffer->base.id;
+ image->format = *format;
+ image->width = width;
+ image->height = height;
+
+ /* XXX: no paletted formats supported yet */
+ image->num_palette_entries = 0;
+ image->entry_bytes = 0;
+ return obj_image;
+
+error:
+ destroy_image(driver_data, obj_image);
+ return NULL;
+}
+
+// Destroy image
+void
+destroy_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+)
+{
+ obj_image->image.image_id = VA_INVALID_ID;
+ destroy_hw_image(driver_data, obj_image);
+ destroy_va_buffer(driver_data, XVBA_BUFFER(obj_image->image.buf));
+ object_heap_free(&driver_data->image_heap, (object_base_p)obj_image);
+}
+
+#if USE_GLX
+const HWImageHooks hw_image_hooks_glx attribute_hidden;
+#endif
+
+// Commit image to the HW
+VAStatus
+commit_hw_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ XVBASession *session,
+ unsigned int flags
+)
+{
+ VAStatus status;
+
+ object_buffer_p const obj_buffer = XVBA_BUFFER(obj_image->image.buf);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ /* Update video surface only if the image (hence its buffer) was
+ updated since our last synchronisation.
+
+ NOTE: this assumes the user really unmaps the buffer when he is
+ done with it, as it is actually required */
+ if (obj_image->hw.mtime < obj_buffer->mtime) {
+#if USE_GLX
+ if (flags & HWIMAGE_TYPE_GLX) {
+ if (!obj_image->hw.glx) {
+ ASSERT(hw_image_hooks_glx.create);
+ status = hw_image_hooks_glx.create(
+ driver_data,
+ obj_image,
+ session
+ );
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+ ASSERT(hw_image_hooks_glx.commit);
+ status = hw_image_hooks_glx.commit(
+ driver_data,
+ obj_image,
+ obj_buffer,
+ session
+ );
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+#endif
+ obj_image->hw.mtime = obj_buffer->mtime;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Destroy HW image
+void
+destroy_hw_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+)
+{
+ if (!obj_image)
+ return;
+
+#if USE_GLX
+ if (obj_image->hw.glx) {
+ if (hw_image_hooks_glx.destroy)
+ hw_image_hooks_glx.destroy(driver_data, obj_image);
+ obj_image->hw.glx = NULL;
+ }
+#endif
+}
+
+// Copy image
+static VAStatus
+copy_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p dst_obj_image,
+ object_image_p src_obj_image
+)
+{
+ if (!compare_image_formats(&dst_obj_image->image.format,
+ &src_obj_image->image.format))
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ object_buffer_p dst_obj_buffer = XVBA_BUFFER(dst_obj_image->image.buf);
+ if (!dst_obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ object_buffer_p src_obj_buffer = XVBA_BUFFER(src_obj_image->image.buf);
+ if (!src_obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ /* XXX: use map/unmap functions */
+ ASSERT(dst_obj_image->image.data_size == src_obj_image->image.data_size);
+ memcpy(
+ dst_obj_buffer->buffer_data,
+ src_obj_buffer->buffer_data,
+ dst_obj_image->image.data_size
+ );
+ dst_obj_buffer->mtime = src_obj_buffer->mtime;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaCreateImage
+VAStatus
+xvba_CreateImage(
+ VADriverContextP ctx,
+ VAImageFormat *format,
+ int width,
+ int height,
+ VAImage *out_image
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!format || !out_image)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ out_image->image_id = VA_INVALID_ID;
+ out_image->buf = VA_INVALID_ID;
+
+ object_image_p obj_image;
+ obj_image = create_image(driver_data, width, height, format);
+ if (!obj_image)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ *out_image = obj_image->image;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDestroyImage
+VAStatus
+xvba_DestroyImage(
+ VADriverContextP ctx,
+ VAImageID image_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_image_p obj_image = XVBA_IMAGE(image_id);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ destroy_image(driver_data, obj_image);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDeriveImage
+VAStatus
+xvba_DeriveImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImage *image
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+}
+
+// vaSetImagePalette
+VAStatus
+xvba_SetImagePalette(
+ VADriverContextP ctx,
+ VAImageID image,
+ unsigned char *palette
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+}
+
+// Get image from surface
+static VAStatus
+get_image(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface,
+ object_image_p obj_image,
+ const VARectangle *rect
+)
+{
+ /* XVBAGetSurface() API appeared in XvBA 0.74 */
+ if (!xvba_check_version(0,74))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(obj_image->image.buf);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ /* XXX: only support full surface readback for now */
+ if (rect->x != 0 ||
+ rect->y != 0 ||
+ rect->width != obj_surface->width ||
+ rect->height != obj_surface->height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ /* Make sure the surface is decoded prior to extracting it */
+ /* XXX: API doc mentions this as implicit in XVBAGetSurface() though... */
+ if (sync_surface(driver_data, obj_context, obj_surface) < 0)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ /* XXX: stupid driver requires 16-pixels alignment */
+ ASSERT(obj_surface->xvba_surface->type == XVBA_SURFACETYPE_NORMAL);
+ if (obj_image->xvba_width != obj_surface->xvba_surface->info.normal.width ||
+ obj_image->xvba_height != obj_surface->xvba_surface->info.normal.height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ if (xvba_get_surface(obj_context->xvba_decoder,
+ obj_surface->xvba_surface,
+ obj_image->xvba_format,
+ obj_buffer->buffer_data,
+ obj_image->image.pitches[0],
+ obj_image->xvba_width,
+ obj_image->xvba_height) < 0)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaGetImage
+VAStatus
+xvba_GetImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ VAImageID image
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(surface);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_image_p obj_image = XVBA_IMAGE(image);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ VARectangle rect;
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ return get_image(driver_data, obj_context, obj_surface, obj_image, &rect);
+}
+
+// Put image to surface
+static VAStatus
+put_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ object_surface_p obj_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect
+)
+{
+#if 0
+ /* Don't do anything if the surface is used for rendering for example */
+ if (obj_surface->va_surface_status != VASurfaceReady)
+ return VA_STATUS_ERROR_SURFACE_BUSY;
+#endif
+
+ /* Only support upload to normal video surfaces */
+ if (obj_surface->xvba_surface &&
+ obj_surface->xvba_surface->type != XVBA_SURFACETYPE_NORMAL)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ /* Check we are not overriding the whole surface */
+ if (dst_rect->x == 0 &&
+ dst_rect->y == 0 &&
+ dst_rect->width == obj_surface->width &&
+ dst_rect->height == obj_surface->height) {
+ obj_surface->used_for_decoding = 0;
+ obj_surface->va_surface_status = VASurfaceReady;
+ }
+
+ /* XXX: XvBA does not have a real PutImage API. It requires
+ image and surface to have the same dimensions... */
+ if (obj_image->image.width != obj_surface->width ||
+ obj_image->image.height != obj_surface->height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ /* XXX: XvBA implementation cannot do partial surface uploads, though
+ the API permits it... Neither can it scale the data for us */
+ if (src_rect->x != 0 ||
+ src_rect->y != 0 ||
+ src_rect->width != obj_image->image.width ||
+ src_rect->height != obj_image->image.height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ if (dst_rect->x != 0 ||
+ dst_rect->y != 0 ||
+ dst_rect->width != obj_surface->width ||
+ dst_rect->height != obj_surface->height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ if (src_rect->width != dst_rect->width ||
+ src_rect->height != dst_rect->height)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ VAStatus status = putimage_hacks_check(driver_data, obj_surface, obj_image);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ PutImageHacks * const h = obj_surface->putimage_hacks;
+ if (h && h->type == PUTIMAGE_HACKS_IMAGE) {
+ status = copy_image(
+ driver_data,
+ obj_surface->putimage_hacks->obj_image,
+ obj_image
+ );
+ return status;
+ }
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+}
+
+// vaPutImage
+VAStatus
+xvba_PutImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImageID image,
+ int src_x,
+ int src_y,
+ unsigned int width,
+ unsigned int height,
+ int dest_x,
+ int dest_y
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(surface);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_image_p obj_image = XVBA_IMAGE(image);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ VARectangle src_rect, dst_rect;
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.width = width;
+ src_rect.height = height;
+ dst_rect.x = dest_x;
+ dst_rect.y = dest_y;
+ dst_rect.width = width;
+ dst_rect.height = height;
+ return put_image(driver_data, obj_image, obj_surface, &src_rect, &dst_rect);
+}
+
+// vaPutImage2
+VAStatus
+xvba_PutImage_full(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImageID image,
+ int src_x,
+ int src_y,
+ unsigned int src_width,
+ unsigned int src_height,
+ int dest_x,
+ int dest_y,
+ unsigned int dest_width,
+ unsigned int dest_height
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(surface);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ object_image_p obj_image = XVBA_IMAGE(image);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ VARectangle src_rect, dst_rect;
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.width = src_width;
+ src_rect.height = src_height;
+ dst_rect.x = dest_x;
+ dst_rect.y = dest_y;
+ dst_rect.width = dest_width;
+ dst_rect.height = dest_height;
+ return put_image(driver_data, obj_image, obj_surface, &src_rect, &dst_rect);
+}
diff --git a/src/xvba_image.h b/src/xvba_image.h
new file mode 100644
index 0000000..415122f
--- /dev/null
+++ b/src/xvba_image.h
@@ -0,0 +1,234 @@
+/*
+ * xvba_image.h - XvBA backend for VA-API (VAImage)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_IMAGE_H
+#define XVBA_IMAGE_H
+
+#include "xvba_driver.h"
+
+typedef struct object_image_glx *object_image_glx_p;
+typedef struct object_image_xvba *object_image_xvba_p;
+struct object_image_xvba {
+ XVBASurface *surface;
+ unsigned int width;
+ unsigned int height;
+};
+
+enum {
+ HWIMAGE_TYPE_XVBA = 1,
+ HWIMAGE_TYPE_GLX = 2
+};
+
+typedef struct _HWImageHooks HWImageHooks;
+struct _HWImageHooks {
+ VAStatus (*create)(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ XVBASession *session
+ );
+
+ void (*destroy)(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+ );
+
+ VAStatus (*commit)(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ object_buffer_p obj_buffer,
+ XVBASession *session
+ );
+};
+
+typedef struct _HWImage HWImage;
+struct _HWImage {
+ uint64_t mtime;
+ object_image_xvba_p xvba;
+ object_image_glx_p glx;
+};
+
+typedef struct object_image object_image_t;
+struct object_image {
+ struct object_base base;
+ VAImage image;
+ XVBA_SURFACE_FORMAT xvba_format;
+ unsigned int xvba_width;
+ unsigned int xvba_height;
+ HWImage hw;
+};
+
+typedef struct GetImageHacks {
+ unsigned int picnum; /* Current index into delayed_pictures[] */
+} GetImageHacks;
+
+typedef enum {
+ PUTIMAGE_HACKS_NONE,
+ PUTIMAGE_HACKS_SURFACE,
+ PUTIMAGE_HACKS_IMAGE
+} PutImageHacksType;
+
+typedef struct PutImageHacks {
+ PutImageHacksType type;
+ XVBASurface *xvba_surface;
+ object_image_p obj_image;
+} PutImageHacks;
+
+void
+getimage_hacks_disable(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context
+) attribute_hidden;
+
+void
+putimage_hacks_disable(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// Check VA image format represents RGB
+int is_rgb_format(const VAImageFormat *image_format)
+ attribute_hidden;
+
+// Check VA image format represents YUV
+static inline int is_yuv_format(const VAImageFormat *image_format)
+{
+ return !is_rgb_format(image_format);
+}
+
+// Check VA image formats are the same
+int compare_image_formats(const VAImageFormat *a, const VAImageFormat *b)
+ attribute_hidden;
+
+// Create image
+object_image_p
+create_image(
+ xvba_driver_data_t *driver_data,
+ unsigned int width,
+ unsigned int height,
+ VAImageFormat *format
+) attribute_hidden;
+
+// Destroy image
+void
+destroy_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+) attribute_hidden;
+
+// Destroy HW image
+void
+destroy_hw_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+) attribute_hidden;
+
+// Commit image to the HW
+VAStatus
+commit_hw_image(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ XVBASession *session,
+ unsigned int flags
+) attribute_hidden;
+
+// vaQueryImageFormats
+VAStatus
+xvba_QueryImageFormats(
+ VADriverContextP ctx,
+ VAImageFormat *format_list,
+ int *num_formats
+) attribute_hidden;
+
+// vaCreateImage
+VAStatus
+xvba_CreateImage(
+ VADriverContextP ctx,
+ VAImageFormat *format,
+ int width,
+ int height,
+ VAImage *image
+) attribute_hidden;
+
+// vaDestroyImage
+VAStatus
+xvba_DestroyImage(
+ VADriverContextP ctx,
+ VAImageID image_id
+) attribute_hidden;
+
+// vaDeriveImage
+VAStatus
+xvba_DeriveImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImage *image
+) attribute_hidden;
+
+// vaSetImagePalette
+VAStatus
+xvba_SetImagePalette(
+ VADriverContextP ctx,
+ VAImageID image,
+ unsigned char *palette
+) attribute_hidden;
+
+// vaGetImage
+VAStatus
+xvba_GetImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ VAImageID image_id
+) attribute_hidden;
+
+// vaPutImage
+VAStatus
+xvba_PutImage(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImageID image,
+ int src_x,
+ int src_y,
+ unsigned int width,
+ unsigned int height,
+ int dest_x,
+ int dest_y
+) attribute_hidden;
+
+// vaPutImage2
+VAStatus
+xvba_PutImage_full(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VAImageID image,
+ int src_x,
+ int src_y,
+ unsigned int src_width,
+ unsigned int src_height,
+ int dest_x,
+ int dest_y,
+ unsigned int dest_width,
+ unsigned int dest_height
+) attribute_hidden;
+
+#endif /* XVBA_IMAGE_H */
diff --git a/src/xvba_subpic.c b/src/xvba_subpic.c
new file mode 100644
index 0000000..0cb6e88
--- /dev/null
+++ b/src/xvba_subpic.c
@@ -0,0 +1,585 @@
+/*
+ * xvba_subpic.c - XvBA backend for VA-API (VA subpictures)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_subpic.h"
+#include "xvba_video.h"
+#include "xvba_image.h"
+#include "xvba_buffer.h"
+#include "utils.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// List of supported subpicture formats
+typedef struct {
+ uint32_t format;
+ VAImageFormat va_format;
+ unsigned int va_flags;
+} xvba_subpic_format_map_t;
+
+static const xvba_subpic_format_map_t xvba_subpic_formats_map[] = {
+ { XVBA_ARGB, { VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32,
+ 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
+ VA_SUBPICTURE_GLOBAL_ALPHA },
+ { XVBA_FAKE, { VA_FOURCC('R','G','B','A'), VA_LSB_FIRST, 32,
+ 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
+ VA_SUBPICTURE_GLOBAL_ALPHA },
+ { 0, }
+};
+
+// Append association to the subpicture
+static int
+subpicture_add_association(
+ object_subpicture_p obj_subpicture,
+ SubpictureAssociationP assoc
+)
+{
+ SubpictureAssociationP *assocs;
+ assocs = realloc_buffer(&obj_subpicture->assocs,
+ &obj_subpicture->assocs_count_max,
+ 1 + obj_subpicture->assocs_count,
+ sizeof(obj_subpicture->assocs[0]));
+ if (!assocs)
+ return -1;
+
+ assocs[obj_subpicture->assocs_count++] = assoc;
+ return 0;
+}
+
+// Remove association at the specified index from the subpicture
+static inline int
+subpicture_remove_association_at(object_subpicture_p obj_subpicture, int index)
+{
+ ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
+ if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
+ return -1;
+
+ /* Replace with the last association */
+ const unsigned int last = obj_subpicture->assocs_count - 1;
+ obj_subpicture->assocs[index] = obj_subpicture->assocs[last];
+ obj_subpicture->assocs[last] = NULL;
+ --obj_subpicture->assocs_count;
+ return 0;
+}
+
+// Remove association from the subpicture
+static int
+subpicture_remove_association(
+ object_subpicture_p obj_subpicture,
+ SubpictureAssociationP assoc
+)
+{
+ ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
+ if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
+ return -1;
+
+ unsigned int i;
+ for (i = 0; i < obj_subpicture->assocs_count; i++) {
+ if (obj_subpicture->assocs[i] == assoc)
+ return subpicture_remove_association_at(obj_subpicture, i);
+ }
+ return -1;
+}
+
+// Associate one surface to the subpicture
+VAStatus
+subpicture_associate_1(
+ object_subpicture_p obj_subpicture,
+ object_surface_p obj_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ unsigned int flags
+)
+{
+ /* XXX: some flags are not supported */
+ static const unsigned int supported_flags = VA_SUBPICTURE_GLOBAL_ALPHA;
+ if (flags & ~supported_flags)
+ return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
+
+ SubpictureAssociationP assoc = malloc(sizeof(*assoc));
+ if (!assoc)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ assoc->subpicture = obj_subpicture->base.id;
+ assoc->surface = obj_surface->base.id;
+ assoc->src_rect = *src_rect;
+ assoc->dst_rect = *dst_rect;
+ assoc->flags = flags;
+
+ if (surface_add_association(obj_surface, assoc) < 0) {
+ free(assoc);
+ return VA_STATUS_ERROR_UNKNOWN;
+ }
+
+ if (subpicture_add_association(obj_subpicture, assoc) < 0) {
+ surface_remove_association(obj_surface, assoc);
+ free(assoc);
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Associate surfaces to the subpicture
+static VAStatus
+associate_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture,
+ VASurfaceID *surfaces,
+ unsigned int num_surfaces,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ unsigned int flags
+)
+{
+ VAStatus status;
+ unsigned int i;
+
+ object_image_p obj_image = XVBA_IMAGE(obj_subpicture->image_id);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ /* Check subpicture association bounds */
+ if (src_rect->x < 0 ||
+ src_rect->y < 0 ||
+ src_rect->x + src_rect->width > obj_image->image.width ||
+ src_rect->y + src_rect->height > obj_image->image.height)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+ if (dst_rect->x < 0 ||
+ dst_rect->y < 0)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ for (i = 0; i < num_surfaces; i++) {
+ object_surface_p const obj_surface = XVBA_SURFACE(surfaces[i]);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (dst_rect->x + dst_rect->width > obj_surface->width ||
+ dst_rect->y + dst_rect->height > obj_surface->height)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ status = subpicture_associate_1(
+ obj_subpicture,
+ obj_surface,
+ src_rect,
+ dst_rect,
+ flags
+ );
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Deassociate one surface from the subpicture
+VAStatus
+subpicture_deassociate_1(
+ object_subpicture_p obj_subpicture,
+ object_surface_p obj_surface
+)
+{
+ ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
+ if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ unsigned int i;
+ for (i = 0; i < obj_subpicture->assocs_count; i++) {
+ SubpictureAssociationP const assoc = obj_subpicture->assocs[i];
+ ASSERT(assoc);
+ if (assoc && assoc->surface == obj_surface->base.id) {
+ surface_remove_association(obj_surface, assoc);
+ subpicture_remove_association_at(obj_subpicture, i);
+ free(assoc);
+ return VA_STATUS_SUCCESS;
+ }
+ }
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+}
+
+// Deassociate surfaces from the subpicture
+static VAStatus
+deassociate_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture,
+ VASurfaceID *surfaces,
+ unsigned int num_surfaces
+)
+{
+ VAStatus status, error = VA_STATUS_SUCCESS;
+ unsigned int i;
+
+ for (i = 0; i < num_surfaces; i++) {
+ object_surface_p const obj_surface = XVBA_SURFACE(surfaces[i]);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ status = subpicture_deassociate_1(obj_subpicture, obj_surface);
+ if (status != VA_STATUS_SUCCESS) {
+ /* Simply report the first error to the user */
+ if (error == VA_STATUS_SUCCESS)
+ error = status;
+ }
+ }
+ return error;
+}
+
+// Commit subpicture to video surface
+VAStatus
+commit_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture,
+ void *session,
+ unsigned int flags
+)
+{
+ object_image_p obj_image = XVBA_IMAGE(obj_subpicture->image_id);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ return commit_hw_image(driver_data, obj_image, session, flags);
+}
+
+// Create subpicture with image
+static object_subpicture_p
+create_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+)
+{
+ VASubpictureID subpic_id;
+ subpic_id = object_heap_allocate(&driver_data->subpicture_heap);
+ if (subpic_id == VA_INVALID_ID)
+ return NULL;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpic_id);
+ ASSERT(obj_subpicture);
+ if (!obj_subpicture)
+ return NULL;
+
+ obj_subpicture->image_id = obj_image->base.id;
+ obj_subpicture->assocs = NULL;
+ obj_subpicture->assocs_count = 0;
+ obj_subpicture->assocs_count_max = 0;
+ obj_subpicture->chromakey_min = 0;
+ obj_subpicture->chromakey_max = 0;
+ obj_subpicture->chromakey_mask = 0;
+ obj_subpicture->alpha = 1.0f;
+ return obj_subpicture;
+}
+
+// Destroy XvBA surface bound to VA subpicture
+void
+destroy_subpicture_surface(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture
+)
+{
+ if (!obj_subpicture)
+ return;
+
+ object_image_p const obj_image = XVBA_IMAGE(obj_subpicture->image_id);
+ if (obj_image)
+ destroy_hw_image(driver_data, obj_image);
+}
+
+// Destroy subpicture
+static void
+destroy_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture
+)
+{
+ object_surface_p obj_surface;
+ VAStatus status;
+ unsigned int i, n;
+
+ destroy_subpicture_surface(driver_data, obj_subpicture);
+
+ if (obj_subpicture->assocs) {
+ const unsigned int n_assocs = obj_subpicture->assocs_count;
+ for (i = 0, n = 0; i < n_assocs; i++) {
+ SubpictureAssociationP const assoc = obj_subpicture->assocs[0];
+ if (!assoc)
+ continue;
+ obj_surface = XVBA_SURFACE(assoc->surface);
+ ASSERT(obj_surface);
+ if (!obj_surface)
+ continue;
+ status = subpicture_deassociate_1(obj_subpicture, obj_surface);
+ if (status == VA_STATUS_SUCCESS)
+ ++n;
+ }
+ if (n != n_assocs)
+ xvba_error_message("vaDestroySubpicture(): subpicture 0x%08x still "
+ "has %d surfaces associated to it\n",
+ obj_subpicture->base.id, n_assocs - n);
+ free(obj_subpicture->assocs);
+ obj_subpicture->assocs = NULL;
+ }
+ obj_subpicture->assocs_count = 0;
+ obj_subpicture->assocs_count_max = 0;
+
+ obj_subpicture->image_id = VA_INVALID_ID;
+ object_heap_free(&driver_data->subpicture_heap,
+ (object_base_p)obj_subpicture);
+}
+
+// vaQuerySubpictureFormats
+VAStatus
+xvba_QuerySubpictureFormats(
+ VADriverContextP ctx,
+ VAImageFormat *format_list,
+ unsigned int *flags,
+ unsigned int *num_formats
+)
+{
+ int n;
+
+ for (n = 0; xvba_subpic_formats_map[n].format != 0; n++) {
+ if (format_list)
+ format_list[n] = xvba_subpic_formats_map[n].va_format;
+ if (flags)
+ flags[n] = xvba_subpic_formats_map[n].va_flags;
+ }
+
+ if (num_formats)
+ *num_formats = n;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaCreateSubpicture
+VAStatus
+xvba_CreateSubpicture(
+ VADriverContextP ctx,
+ VAImageID image,
+ VASubpictureID *subpicture
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!subpicture)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ object_image_p obj_image = XVBA_IMAGE(image);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ object_subpicture_p obj_subpicture;
+ obj_subpicture = create_subpicture(driver_data, obj_image);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ *subpicture = obj_subpicture->base.id;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDestroySubpicture
+VAStatus
+xvba_DestroySubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ destroy_subpicture(driver_data, obj_subpicture);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaSetSubpictureImage
+VAStatus
+xvba_SetSubpictureImage(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VAImageID image
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ object_image_p obj_image = XVBA_IMAGE(image);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ obj_subpicture->image_id = obj_image->base.id;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaSetSubpicturePalette (not a PUBLIC interface)
+VAStatus
+xvba_SetSubpicturePalette(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ unsigned char *palette
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+}
+
+// vaSetSubpictureChromaKey
+VAStatus
+xvba_SetSubpictureChromakey(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ unsigned int chromakey_min,
+ unsigned int chromakey_max,
+ unsigned int chromakey_mask
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ obj_subpicture->chromakey_min = chromakey_min;
+ obj_subpicture->chromakey_max = chromakey_max;
+ obj_subpicture->chromakey_mask = chromakey_mask;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaSetSubpictureGlobalAlpha
+VAStatus
+xvba_SetSubpictureGlobalAlpha(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ float global_alpha
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ obj_subpicture->alpha = global_alpha;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaAssociateSubpicture
+VAStatus
+xvba_AssociateSubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces,
+ short src_x,
+ short src_y,
+ short dest_x,
+ short dest_y,
+ unsigned short width,
+ unsigned short height,
+ unsigned int flags
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!target_surfaces || num_surfaces == 0)
+ return VA_STATUS_SUCCESS;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ VARectangle src_rect, dst_rect;
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.width = width;
+ src_rect.height = height;
+ dst_rect.x = dest_x;
+ dst_rect.y = dest_y;
+ dst_rect.width = width;
+ dst_rect.height = height;
+ return associate_subpicture(driver_data, obj_subpicture,
+ target_surfaces, num_surfaces,
+ &src_rect, &dst_rect, flags);
+}
+
+// vaAssociateSubpicture2
+VAStatus
+xvba_AssociateSubpicture_full(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces,
+ short src_x,
+ short src_y,
+ unsigned short src_width,
+ unsigned short src_height,
+ short dest_x,
+ short dest_y,
+ unsigned short dest_width,
+ unsigned short dest_height,
+ unsigned int flags
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!target_surfaces || num_surfaces == 0)
+ return VA_STATUS_SUCCESS;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ VARectangle src_rect, dst_rect;
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.width = src_width;
+ src_rect.height = src_height;
+ dst_rect.x = dest_x;
+ dst_rect.y = dest_y;
+ dst_rect.width = dest_width;
+ dst_rect.height = dest_height;
+ return associate_subpicture(driver_data, obj_subpicture,
+ target_surfaces, num_surfaces,
+ &src_rect, &dst_rect, flags);
+}
+
+// vaDeassociateSubpicture
+VAStatus
+xvba_DeassociateSubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!target_surfaces || num_surfaces == 0)
+ return VA_STATUS_SUCCESS;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(subpicture);
+ if (!obj_subpicture)
+ return VA_STATUS_ERROR_INVALID_SUBPICTURE;
+
+ return deassociate_subpicture(driver_data, obj_subpicture,
+ target_surfaces, num_surfaces);
+}
diff --git a/src/xvba_subpic.h b/src/xvba_subpic.h
new file mode 100644
index 0000000..6796993
--- /dev/null
+++ b/src/xvba_subpic.h
@@ -0,0 +1,175 @@
+/*
+ * xvba_subpic.h - XvBA backend for VA-API (VA subpictures)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_SUBPIC_H
+#define XVBA_SUBPIC_H
+
+#include "xvba_video.h"
+
+typedef struct object_subpicture object_subpicture_t;
+typedef struct object_subpicture *object_subpicture_p;
+
+struct object_subpicture {
+ struct object_base base;
+ VAImageID image_id;
+ SubpictureAssociationP *assocs;
+ unsigned int assocs_count;
+ unsigned int assocs_count_max;
+ unsigned int chromakey_min;
+ unsigned int chromakey_max;
+ unsigned int chromakey_mask;
+ float alpha;
+};
+
+// Destroy XvBA surface bound to VA subpictures
+void
+destroy_subpicture_surface(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture
+) attribute_hidden;
+
+// Associate one surface to the subpicture
+VAStatus
+subpicture_associate_1(
+ object_subpicture_p obj_subpicture,
+ object_surface_p obj_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ unsigned int flags
+) attribute_hidden;
+
+// Deassociate one surface from the subpicture
+VAStatus
+subpicture_deassociate_1(
+ object_subpicture_p obj_subpicture,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// Commit subpicture to video surface
+VAStatus
+commit_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture,
+ void *session,
+ unsigned int flags
+) attribute_hidden;
+
+// vaQuerySubpictureFormats
+VAStatus
+xvba_QuerySubpictureFormats(
+ VADriverContextP ctx,
+ VAImageFormat *format_list,
+ unsigned int *flags,
+ unsigned int *num_formats
+) attribute_hidden;
+
+// vaCreateSubpicture
+VAStatus
+xvba_CreateSubpicture(
+ VADriverContextP ctx,
+ VAImageID image,
+ VASubpictureID *subpicture
+) attribute_hidden;
+
+// vaDestroySubpicture
+VAStatus
+xvba_DestroySubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture
+) attribute_hidden;
+
+// vaSetSubpictureImage
+VAStatus
+xvba_SetSubpictureImage(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VAImageID image
+) attribute_hidden;
+
+// vaSetSubpicturePalette (not a PUBLIC interface)
+VAStatus
+xvba_SetSubpicturePalette(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ unsigned char *palette
+) attribute_hidden;
+
+// vaSetSubpictureChromaKey
+VAStatus
+xvba_SetSubpictureChromakey(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ unsigned int chromakey_min,
+ unsigned int chromakey_max,
+ unsigned int chromakey_mask
+) attribute_hidden;
+
+// vaSetSubpictureGlobalAlpha
+VAStatus
+xvba_SetSubpictureGlobalAlpha(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ float global_alpha
+) attribute_hidden;
+
+// vaAssociateSubpicture
+VAStatus
+xvba_AssociateSubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces,
+ short src_x,
+ short src_y,
+ short dest_x,
+ short dest_y,
+ unsigned short width,
+ unsigned short height,
+ unsigned int flags
+) attribute_hidden;
+
+// vaAssociateSubpicture2
+VAStatus
+xvba_AssociateSubpicture_full(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces,
+ short src_x,
+ short src_y,
+ unsigned short src_width,
+ unsigned short src_height,
+ short dest_x,
+ short dest_y,
+ unsigned short dest_width,
+ unsigned short dest_height,
+ unsigned int flags
+) attribute_hidden;
+
+// vaDeassociateSubpicture
+VAStatus
+xvba_DeassociateSubpicture(
+ VADriverContextP ctx,
+ VASubpictureID subpicture,
+ VASurfaceID *target_surfaces,
+ int num_surfaces
+) attribute_hidden;
+
+#endif /* XVBA_SUBPIC_H */
diff --git a/src/xvba_video.c b/src/xvba_video.c
new file mode 100644
index 0000000..b47b2ba
--- /dev/null
+++ b/src/xvba_video.c
@@ -0,0 +1,1131 @@
+/*
+ * xvba_video.c - XvBA backend for VA-API (VA context, config, surfaces)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "xvba_video.h"
+#include "xvba_dump.h"
+#include "xvba_buffer.h"
+#include "xvba_decode.h"
+#include "xvba_image.h"
+#include "xvba_subpic.h"
+#include "xvba_video_x11.h"
+#if USE_GLX
+#include "xvba_video_glx.h"
+#endif
+#include "utils.h"
+#include "utils_x11.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Translates VAProfile to XVBACodec
+static XVBACodec get_XVBACodec(VAProfile profile)
+{
+ switch (profile) {
+ case VAProfileMPEG2Simple:
+ case VAProfileMPEG2Main:
+ return XVBA_CODEC_MPEG2;
+ case VAProfileMPEG4Simple:
+ case VAProfileMPEG4AdvancedSimple:
+ case VAProfileMPEG4Main:
+ break;
+#if VA_CHECK_VERSION(0,30,0)
+ case VAProfileH263Baseline:
+ break;
+#endif
+ case VAProfileH264Baseline:
+ case VAProfileH264Main:
+ case VAProfileH264High:
+ return XVBA_CODEC_H264;
+ case VAProfileVC1Simple:
+ case VAProfileVC1Main:
+ case VAProfileVC1Advanced:
+ return XVBA_CODEC_VC1;
+#if VA_CHECK_VERSION(0,31,0)
+ case VAProfileJPEGBaseline:
+ break;
+#endif
+ }
+ return 0;
+}
+
+// Destroys XvBA subpictures bound to a VA surface
+static void
+destroy_subpictures(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+)
+{
+ unsigned int i;
+ for (i = 0; i < obj_surface->assocs_count; i++) {
+ SubpictureAssociationP const assoc = obj_surface->assocs[i];
+ destroy_subpicture_surface(
+ driver_data,
+ XVBA_SUBPICTURE(assoc->subpicture)
+ );
+ }
+}
+
+// Creates XvBA surface
+static VAStatus
+ensure_surface_size(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ unsigned int width,
+ unsigned int height
+)
+{
+ if (obj_surface->xvba_surface &&
+ obj_surface->xvba_surface_width == width &&
+ obj_surface->xvba_surface_height == height)
+ return VA_STATUS_SUCCESS;
+
+ if (obj_surface->xvba_surface) {
+ xvba_destroy_surface(obj_surface->xvba_surface);
+ obj_surface->xvba_surface = NULL;
+ }
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ obj_surface->xvba_surface = xvba_create_surface(
+ obj_context->xvba_session,
+ width,
+ height,
+ XVBA_NV12
+ );
+ if (!obj_surface->xvba_surface)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ obj_surface->xvba_surface_width = width;
+ obj_surface->xvba_surface_height = height;
+ return VA_STATUS_SUCCESS;
+}
+
+// Destroys XvBA surface and associated buffers
+static void
+destroy_surface(xvba_driver_data_t *driver_data, object_surface_p obj_surface)
+{
+ destroy_subpictures(driver_data, obj_surface);
+ destroy_surface_buffers(driver_data, obj_surface);
+
+ if (obj_surface->xvba_surface) {
+ xvba_destroy_surface(obj_surface->xvba_surface);
+ obj_surface->xvba_surface = NULL;
+ }
+}
+
+// Query surface status
+int
+query_surface_status(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface,
+ VASurfaceStatus *surface_status
+)
+{
+ int status;
+
+ if (surface_status)
+ *surface_status = VASurfaceReady;
+
+ if (!obj_surface)
+ return 0;
+
+ switch (obj_surface->va_surface_status) {
+ case VASurfaceRendering: /* Rendering (XvBA level) */
+ ASSERT(obj_surface->used_for_decoding);
+ if (!obj_context || !obj_context->xvba_decoder)
+ return 0;
+ if (!obj_surface->xvba_surface)
+ return 0;
+ status = xvba_sync_surface(
+ obj_context->xvba_decoder,
+ obj_surface->xvba_surface,
+ XVBA_GET_SURFACE_STATUS
+ );
+ if (status < 0)
+ return -1;
+ if (status == XVBA_COMPLETED)
+ obj_surface->va_surface_status = VASurfaceReady;
+ break;
+ case VASurfaceDisplaying:
+ status = query_surface_status_glx(driver_data, obj_surface);
+ if (status < 0)
+ return -1;
+ if (status == XVBA_COMPLETED)
+ obj_surface->va_surface_status = VASurfaceReady;
+ break;
+ }
+
+ if (surface_status)
+ *surface_status = obj_surface->va_surface_status;
+ return 0;
+}
+
+// Synchronize surface
+int
+sync_surface(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface
+)
+{
+ VASurfaceStatus surface_status;
+ int status;
+
+ while ((status = query_surface_status(driver_data, obj_context, obj_surface, &surface_status)) == 0 &&
+ surface_status != VASurfaceReady)
+ delay_usec(XVBA_SYNC_DELAY);
+ return status;
+}
+
+// Add subpicture association to surface
+// NOTE: the subpicture owns the SubpictureAssociation object
+int surface_add_association(
+ object_surface_p obj_surface,
+ SubpictureAssociationP assoc
+)
+{
+ /* Check that we don't already have this association */
+ if (obj_surface->assocs) {
+ unsigned int i;
+ for (i = 0; i < obj_surface->assocs_count; i++) {
+ if (obj_surface->assocs[i] == assoc)
+ return 0;
+ if (obj_surface->assocs[i]->subpicture == assoc->subpicture) {
+ /* XXX: this should not happen, but replace it in the interim */
+ ASSERT(obj_surface->assocs[i]->surface == assoc->surface);
+ obj_surface->assocs[i] = assoc;
+ return 0;
+ }
+ }
+ }
+
+ /* Check that we have not reached the maximum subpictures capacity yet */
+ if (obj_surface->assocs_count >= XVBA_MAX_SUBPICTURES)
+ return -1;
+
+ /* Append this subpicture association */
+ SubpictureAssociationP *assocs;
+ assocs = realloc_buffer(
+ &obj_surface->assocs,
+ &obj_surface->assocs_count_max,
+ 1 + obj_surface->assocs_count,
+ sizeof(obj_surface->assocs[0])
+ );
+ if (!assocs)
+ return -1;
+
+ assocs[obj_surface->assocs_count++] = assoc;
+ return 0;
+}
+
+// Remove subpicture association from surface
+// NOTE: the subpicture owns the SubpictureAssociation object
+int surface_remove_association(
+ object_surface_p obj_surface,
+ SubpictureAssociationP assoc
+)
+{
+ if (!obj_surface->assocs || obj_surface->assocs_count == 0)
+ return -1;
+
+ unsigned int i;
+ const unsigned int last = obj_surface->assocs_count - 1;
+ for (i = 0; i <= last; i++) {
+ if (obj_surface->assocs[i] == assoc) {
+ /* Swap with the last subpicture */
+ obj_surface->assocs[i] = obj_surface->assocs[last];
+ obj_surface->assocs[last] = NULL;
+ obj_surface->assocs_count--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+// vaGetConfigAttributes
+VAStatus
+xvba_GetConfigAttributes(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list,
+ int num_attribs
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (!has_decoder(driver_data, profile, entrypoint))
+ return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+ int i;
+ for (i = 0; i < num_attribs; i++) {
+ switch (attrib_list[i].type) {
+ case VAConfigAttribRTFormat:
+ attrib_list[i].value = VA_RT_FORMAT_YUV420;
+ break;
+ default:
+ attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
+ break;
+ }
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+xvba_update_attribute(object_config_p obj_config, VAConfigAttrib *attrib)
+{
+ int i;
+
+ /* Check existing attributes */
+ for (i = 0; obj_config->attrib_count < i; i++) {
+ if (obj_config->attrib_list[i].type == attrib->type) {
+ /* Update existing attribute */
+ obj_config->attrib_list[i].value = attrib->value;
+ return VA_STATUS_SUCCESS;
+ }
+ }
+ if (obj_config->attrib_count < XVBA_MAX_CONFIG_ATTRIBUTES) {
+ i = obj_config->attrib_count;
+ obj_config->attrib_list[i].type = attrib->type;
+ obj_config->attrib_list[i].value = attrib->value;
+ obj_config->attrib_count++;
+ return VA_STATUS_SUCCESS;
+ }
+ return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
+}
+
+// vaCreateConfig
+VAStatus
+xvba_CreateConfig(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list,
+ int num_attribs,
+ VAConfigID *config_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ VAStatus va_status;
+ int configID;
+ object_config_p obj_config;
+ int i;
+
+ /* Validate profile and entrypoint */
+ switch (profile) {
+ case VAProfileMPEG2Simple:
+ case VAProfileMPEG2Main:
+ if (entrypoint == VAEntrypointIDCT || entrypoint == VAEntrypointVLD)
+ va_status = VA_STATUS_SUCCESS;
+ else
+ va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
+ break;
+ case VAProfileH264Baseline:
+ case VAProfileH264Main:
+ case VAProfileH264High:
+ if (entrypoint == VAEntrypointVLD)
+ va_status = VA_STATUS_SUCCESS;
+ else
+ va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
+ break;
+ case VAProfileVC1Simple:
+ case VAProfileVC1Main:
+ case VAProfileVC1Advanced:
+ if (entrypoint == VAEntrypointVLD)
+ va_status = VA_STATUS_SUCCESS;
+ else
+ va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
+ break;
+ default:
+ va_status = VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
+ break;
+ }
+
+ if (va_status != VA_STATUS_SUCCESS)
+ return va_status;
+
+ if (!has_decoder(driver_data, profile, entrypoint))
+ return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+ configID = object_heap_allocate(&driver_data->config_heap);
+ obj_config = XVBA_CONFIG(configID);
+ if (!obj_config)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ obj_config->profile = profile;
+ obj_config->entrypoint = entrypoint;
+ obj_config->attrib_list[0].type = VAConfigAttribRTFormat;
+ obj_config->attrib_list[0].value = VA_RT_FORMAT_YUV420;
+ obj_config->attrib_count = 1;
+
+ for (i = 0; i < num_attribs; i++) {
+ va_status = xvba_update_attribute(obj_config, &attrib_list[i]);
+ if (va_status != VA_STATUS_SUCCESS) {
+ xvba_DestroyConfig(ctx, configID);
+ return va_status;
+ }
+ }
+
+ if (config_id)
+ *config_id = configID;
+
+ return va_status;
+}
+
+// vaDestroyConfig
+VAStatus
+xvba_DestroyConfig(
+ VADriverContextP ctx,
+ VAConfigID config_id
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_config_p obj_config = XVBA_CONFIG(config_id);
+ if (!obj_config)
+ return VA_STATUS_ERROR_INVALID_CONFIG;
+
+ object_heap_free(&driver_data->config_heap, (object_base_p)obj_config);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaQueryConfigAttributes
+VAStatus
+xvba_QueryConfigAttributes(
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ VAProfile *profile,
+ VAEntrypoint *entrypoint,
+ VAConfigAttrib *attrib_list,
+ int *num_attribs
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ VAStatus va_status = VA_STATUS_SUCCESS;
+ object_config_p obj_config;
+ int i;
+
+ obj_config = XVBA_CONFIG(config_id);
+ if (!obj_config)
+ return VA_STATUS_ERROR_INVALID_CONFIG;
+
+ if (profile)
+ *profile = obj_config->profile;
+
+ if (entrypoint)
+ *entrypoint = obj_config->entrypoint;
+
+ if (num_attribs)
+ *num_attribs = obj_config->attrib_count;
+
+ if (attrib_list) {
+ for (i = 0; i < obj_config->attrib_count; i++)
+ attrib_list[i] = obj_config->attrib_list[i];
+ }
+
+ return va_status;
+}
+
+// vaCreateSurfaces
+VAStatus
+xvba_CreateSurfaces(
+ VADriverContextP ctx,
+ int width,
+ int height,
+ int format,
+ int num_surfaces,
+ VASurfaceID *surfaces
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ D(bug("vaCreateSurfaces(): size %dx%d, format %s\n", width, height,
+ string_of_VAConfigAttribRTFormat(format)));
+
+ VAStatus va_status = VA_STATUS_SUCCESS;
+ int i;
+
+ /* We only support one format */
+ if (format != VA_RT_FORMAT_YUV420)
+ return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
+
+ for (i = 0; i < num_surfaces; i++) {
+ int va_surface = object_heap_allocate(&driver_data->surface_heap);
+ object_surface_p obj_surface = XVBA_SURFACE(va_surface);
+ if (!obj_surface) {
+ va_status = VA_STATUS_ERROR_ALLOCATION_FAILED;
+ break;
+ }
+ D(bug(" surface 0x%08x\n", va_surface));
+ obj_surface->va_context = VA_INVALID_ID;
+ obj_surface->va_surface_status = VASurfaceReady;
+ obj_surface->xvba_surface = NULL;
+ obj_surface->xvba_surface_width = width;
+ obj_surface->xvba_surface_height = height;
+ obj_surface->output_surfaces = NULL;
+ obj_surface->output_surfaces_count = 0;
+ obj_surface->output_surfaces_count_max = 0;
+ obj_surface->width = width;
+ obj_surface->height = height;
+ obj_surface->gl_surface = NULL;
+ obj_surface->pic_desc_buffer = NULL;
+ obj_surface->iq_matrix_buffer = NULL;
+ obj_surface->data_buffer = NULL;
+ obj_surface->data_ctrl_buffers = NULL;
+ obj_surface->data_ctrl_buffers_count = 0;
+ obj_surface->data_ctrl_buffers_count_max = 0;
+ obj_surface->assocs = NULL;
+ obj_surface->assocs_count = 0;
+ obj_surface->assocs_count_max = 0;
+ obj_surface->putimage_hacks = NULL;
+ surfaces[i] = va_surface;
+ }
+
+ /* Error recovery */
+ if (va_status != VA_STATUS_SUCCESS)
+ xvba_DestroySurfaces(ctx, surfaces, i);
+
+ return va_status;
+}
+
+// vaDestroySurfaces
+VAStatus
+xvba_DestroySurfaces(
+ VADriverContextP ctx,
+ VASurfaceID *surface_list,
+ int num_surfaces
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ D(bug("vaDestroySurfaces()\n"));
+
+ int i, j, n;
+ for (i = num_surfaces - 1; i >= 0; i--) {
+ object_surface_p obj_surface = XVBA_SURFACE(surface_list[i]);
+ if (!obj_surface)
+ continue;
+
+ D(bug(" surface 0x%08x\n", obj_surface->base.id));
+ destroy_surface(driver_data, obj_surface);
+
+#if USE_GLX
+ if (obj_surface->gl_surface) {
+ glx_surface_unref(driver_data, obj_surface->gl_surface);
+ obj_surface->gl_surface = NULL;
+ }
+#endif
+
+ for (j = 0; j < obj_surface->output_surfaces_count; j++) {
+ output_surface_unref(driver_data, obj_surface->output_surfaces[j]);
+ obj_surface->output_surfaces[j] = NULL;
+ }
+ free(obj_surface->output_surfaces);
+ obj_surface->output_surfaces_count = 0;
+ obj_surface->output_surfaces_count_max = 0;
+
+ if (obj_surface->assocs) {
+ object_subpicture_p obj_subpicture;
+ VAStatus status;
+ const unsigned int n_assocs = obj_surface->assocs_count;
+
+ for (j = 0, n = 0; j < n_assocs; j++) {
+ SubpictureAssociationP const assoc = obj_surface->assocs[0];
+ if (!assoc)
+ continue;
+ obj_subpicture = XVBA_SUBPICTURE(assoc->subpicture);
+ if (!obj_subpicture)
+ continue;
+ status = subpicture_deassociate_1(obj_subpicture, obj_surface);
+ if (status == VA_STATUS_SUCCESS)
+ ++n;
+ }
+ if (n != n_assocs)
+ xvba_error_message("vaDestroySurfaces(): surface 0x%08x still "
+ "has %d subpictures associated to it\n",
+ obj_surface->base.id, n_assocs - n);
+ free(obj_surface->assocs);
+ obj_surface->assocs = NULL;
+ }
+ obj_surface->assocs_count = 0;
+ obj_surface->assocs_count_max = 0;
+
+ putimage_hacks_disable(driver_data, obj_surface);
+
+ object_heap_free(&driver_data->surface_heap, (object_base_p)obj_surface);
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// vaCreateContext
+VAStatus
+xvba_CreateContext(
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ int picture_width,
+ int picture_height,
+ int flag,
+ VASurfaceID *render_targets,
+ int num_render_targets,
+ VAContextID *context
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (context)
+ *context = VA_INVALID_ID;
+
+ D(bug("vaCreateContext(): config 0x%08x, size %dx%d\n", config_id,
+ picture_width, picture_height));
+
+ object_config_p const obj_config = XVBA_CONFIG(config_id);
+ if (!obj_config)
+ return VA_STATUS_ERROR_INVALID_CONFIG;
+
+ /* XXX: validate flag */
+
+ int i;
+ for (i = 0; i < num_render_targets; i++) {
+ object_surface_p const obj_surface = XVBA_SURFACE(render_targets[i]);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ if (obj_surface->va_context != VA_INVALID_ID) {
+ xvba_error_message("vaCreateContext(): surface 0x%08x is already "
+ "bound to context 0x%08x\n",
+ obj_surface->base.id, obj_surface->va_context);
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ }
+ if (obj_surface->width != picture_width ||
+ obj_surface->height != picture_height)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ }
+
+ VAContextID context_id = object_heap_allocate(&driver_data->context_heap);
+ object_context_p const obj_context = XVBA_CONTEXT(context_id);
+ if (!obj_context)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ /* XXX: workaround XvBA internal bugs. Round up so that to create
+ surfaces of the "expected" size */
+ picture_width = (picture_width + 15) & -16;
+ picture_height = (picture_height + 15) & -16;
+
+ obj_context->va_config = config_id;
+ obj_context->picture_width = picture_width;
+ obj_context->picture_height = picture_height;
+ obj_context->flags = flag;
+ obj_context->num_render_targets = num_render_targets;
+ obj_context->render_targets = (VASurfaceID *)
+ calloc(num_render_targets, sizeof(VASurfaceID));
+ obj_context->current_render_target = VA_INVALID_SURFACE;
+ obj_context->xvba_codec = get_XVBACodec(obj_config->profile);
+ obj_context->xvba_session = NULL;
+ obj_context->xvba_decoder = NULL;
+ obj_context->va_buffers = NULL;
+ obj_context->va_buffers_count = 0;
+ obj_context->va_buffers_count_max = 0;
+ obj_context->data_buffer = NULL;
+ obj_context->slice_count = 0;
+
+ if (!obj_context->render_targets) {
+ xvba_DestroyContext(ctx, context_id);
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+
+ VAStatus va_status = create_decoder(driver_data, obj_context);
+ if (va_status != VA_STATUS_SUCCESS) {
+ xvba_DestroyContext(ctx, context_id);
+ return va_status;
+ }
+
+ for (i = 0; i < num_render_targets; i++) {
+ object_surface_t * const obj_surface = XVBA_SURFACE(render_targets[i]);
+ obj_context->render_targets[i] = render_targets[i];
+ obj_surface->va_context = context_id;
+
+ D(bug(" surface 0x%08x\n", render_targets[i]));
+ va_status = ensure_surface_size(
+ driver_data,
+ obj_surface,
+ picture_width,
+ picture_height
+ );
+ if (va_status != VA_STATUS_SUCCESS) {
+ xvba_DestroyContext(ctx, context_id);
+ return va_status;
+ }
+ }
+
+ D(bug(" context 0x%08x\n", context_id));
+ if (context)
+ *context = context_id;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDestroyContext
+VAStatus
+xvba_DestroyContext(
+ VADriverContextP ctx,
+ VAContextID context
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ D(bug("vaDestroyContext(): context 0x%08x\n", context));
+
+ object_context_p obj_context = XVBA_CONTEXT(context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ destroy_decoder(driver_data, obj_context);
+
+ if (obj_context->va_buffers) {
+ destroy_va_buffers(driver_data, obj_context);
+ free(obj_context->va_buffers);
+ obj_context->va_buffers = NULL;
+ }
+
+ if (obj_context->render_targets) {
+ int i;
+ for (i = 0; i < obj_context->num_render_targets; i++) {
+ object_surface_p obj_surface;
+ obj_surface = XVBA_SURFACE(obj_context->render_targets[i]);
+ if (obj_surface)
+ obj_surface->va_context = VA_INVALID_ID;
+ }
+ free(obj_context->render_targets);
+ obj_context->render_targets = NULL;
+ }
+
+ obj_context->va_config = VA_INVALID_ID;
+ obj_context->current_render_target = VA_INVALID_SURFACE;
+ obj_context->picture_width = 0;
+ obj_context->picture_height = 0;
+ obj_context->num_render_targets = 0;
+ obj_context->flags = 0;
+
+ object_heap_free(&driver_data->context_heap, (object_base_p)obj_context);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaQuerySurfaceStatus
+VAStatus
+xvba_QuerySurfaceStatus(
+ VADriverContextP ctx,
+ VASurfaceID render_target,
+ VASurfaceStatus *status
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(render_target);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ if (query_surface_status(driver_data, obj_context, obj_surface, status) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaSyncSurface
+VAStatus
+xvba_SyncSurface2(
+ VADriverContextP ctx,
+ VASurfaceID render_target
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(render_target);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (sync_surface(driver_data, NULL, obj_surface) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ return VA_STATUS_SUCCESS;
+}
+
+VAStatus
+xvba_SyncSurface3(
+ VADriverContextP ctx,
+ VAContextID context,
+ VASurfaceID render_target
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ object_context_p obj_context = XVBA_CONTEXT(context);
+ if (!obj_context)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ object_surface_p obj_surface = XVBA_SURFACE(render_target);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (sync_surface(driver_data, obj_context, obj_surface) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+
+ return VA_STATUS_SUCCESS;
+}
+
+
+// Ensure VA Display Attributes are initialized
+static int ensure_display_attributes(xvba_driver_data_t *driver_data)
+{
+ VADisplayAttribute *attr;
+
+ if (driver_data->va_display_attrs_count > 0)
+ return 0;
+
+ memset(driver_data->va_display_attrs_mtime, 0,
+ sizeof(driver_data->va_display_attrs_mtime));
+
+ cm_set_identity(driver_data->cm_brightness);
+ cm_set_identity(driver_data->cm_contrast);
+ cm_set_identity(driver_data->cm_saturation);
+ cm_set_identity(driver_data->cm_hue);
+ driver_data->cm_composite_ok = 0;
+
+ attr = &driver_data->va_display_attrs[0];
+
+ attr->type = VADisplayAttribDirectSurface;
+ attr->value = 1; /* GLX: async transfer */
+ attr->min_value = attr->value;
+ attr->max_value = attr->value;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE;
+ attr++;
+
+ attr->type = VADisplayAttribBackgroundColor;
+ attr->value = WhitePixel(driver_data->x11_dpy, driver_data->x11_screen);
+ attr->min_value = 0;
+ attr->max_value = 0xffffff;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE|VA_DISPLAY_ATTRIB_SETTABLE;
+ attr++;
+
+ attr->type = VADisplayAttribBrightness;
+ attr->value = 0;
+ attr->min_value = -100;
+ attr->max_value = 100;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE|VA_DISPLAY_ATTRIB_SETTABLE;
+ attr++;
+
+ attr->type = VADisplayAttribContrast;
+ attr->value = 0;
+ attr->min_value = -100;
+ attr->max_value = 100;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE|VA_DISPLAY_ATTRIB_SETTABLE;
+ attr++;
+
+ attr->type = VADisplayAttribHue;
+ attr->value = 0;
+ attr->min_value = -100;
+ attr->max_value = 100;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE|VA_DISPLAY_ATTRIB_SETTABLE;
+ attr++;
+
+ attr->type = VADisplayAttribSaturation;
+ attr->value = 0;
+ attr->min_value = -100;
+ attr->max_value = 100;
+ attr->flags = VA_DISPLAY_ATTRIB_GETTABLE|VA_DISPLAY_ATTRIB_SETTABLE;
+ attr++;
+
+ driver_data->va_display_attrs_count = attr - driver_data->va_display_attrs;
+ ASSERT(driver_data->va_display_attrs_count <= XVBA_MAX_DISPLAY_ATTRIBUTES);
+ return 0;
+}
+
+// Look up for the specified VA display attribute
+static VADisplayAttribute *
+get_display_attribute(
+ xvba_driver_data_t *driver_data,
+ VADisplayAttribType type
+)
+{
+ if (ensure_display_attributes(driver_data) < 0)
+ return NULL;
+
+ unsigned int i;
+ for (i = 0; i < driver_data->va_display_attrs_count; i++) {
+ if (driver_data->va_display_attrs[i].type == type)
+ return &driver_data->va_display_attrs[i];
+ }
+ return NULL;
+}
+
+// vaQueryDisplayAttributes
+VAStatus
+xvba_QueryDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int *num_attributes
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ if (ensure_display_attributes(driver_data) < 0)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ if (attr_list)
+ memcpy(attr_list, driver_data->va_display_attrs,
+ driver_data->va_display_attrs_count * sizeof(attr_list[0]));
+
+ if (num_attributes)
+ *num_attributes = driver_data->va_display_attrs_count;
+
+ return VA_STATUS_SUCCESS;
+}
+
+// vaGetDisplayAttributes
+VAStatus
+xvba_GetDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int num_attributes
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ unsigned int i;
+ for (i = 0; i < num_attributes; i++) {
+ VADisplayAttribute * const dst_attr = &attr_list[i];
+ VADisplayAttribute *src_attr;
+
+ src_attr = get_display_attribute(driver_data, dst_attr->type);
+ if (src_attr && (src_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) != 0) {
+ dst_attr->min_value = src_attr->min_value;
+ dst_attr->max_value = src_attr->max_value;
+ dst_attr->value = src_attr->value;
+ }
+ else
+ dst_attr->flags &= ~VA_DISPLAY_ATTRIB_GETTABLE;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Normalize -100..100 value into the specified range
+static float get_normalized_value(
+ const VADisplayAttribute *attr,
+ float vstart,
+ float vend,
+ float vdefault
+)
+{
+ return (vdefault + (attr->value / 100.0f) *
+ (attr->value >= 0 ? (vend - vdefault) : (vdefault - vstart)));
+}
+
+// vaSetDisplayAttributes
+VAStatus
+xvba_SetDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int num_attributes
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ unsigned int i;
+ for (i = 0; i < num_attributes; i++) {
+ VADisplayAttribute * const src_attr = &attr_list[i];
+ VADisplayAttribute *dst_attr;
+
+ dst_attr = get_display_attribute(driver_data, src_attr->type);
+ if (!dst_attr)
+ return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
+
+ if ((dst_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) != 0) {
+ int value_changed = dst_attr->value != src_attr->value;
+ dst_attr->value = src_attr->value;
+
+ int procamp_changed = 0;
+ float value, start, end, def;
+ switch (dst_attr->type) {
+ case VADisplayAttribBackgroundColor:
+ driver_data->va_background_color = dst_attr;
+ break;
+ case VADisplayAttribBrightness:
+ if (value_changed) {
+ cm_get_brightness_range(&start, &end, &def);
+ value = get_normalized_value(dst_attr, start, end, def);
+ cm_set_brightness(driver_data->cm_brightness, value);
+ procamp_changed = 1;
+ }
+ break;
+ case VADisplayAttribContrast:
+ if (value_changed) {
+ cm_get_contrast_range(&start, &end, &def);
+ value = get_normalized_value(dst_attr, start, end, def);
+ cm_set_contrast(driver_data->cm_contrast, value);
+ procamp_changed = 1;
+ }
+ break;
+ case VADisplayAttribSaturation:
+ if (value_changed) {
+ cm_get_saturation_range(&start, &end, &def);
+ value = get_normalized_value(dst_attr, start, end, def);
+ cm_set_saturation(driver_data->cm_saturation, value);
+ procamp_changed = 1;
+ }
+ break;
+ case VADisplayAttribHue:
+ if (value_changed) {
+ cm_get_hue_range(&start, &end, &def);
+ value = get_normalized_value(dst_attr, start, end, def);
+ cm_set_hue(driver_data->cm_hue, value);
+ procamp_changed = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (procamp_changed) {
+ cm_composite(
+ driver_data->cm_composite,
+ driver_data->cm_brightness,
+ driver_data->cm_contrast,
+ driver_data->cm_saturation,
+ driver_data->cm_hue
+ );
+ driver_data->cm_composite_ok = 1;
+ }
+
+ static uint64_t mtime;
+ const int dst_attr_index = dst_attr - driver_data->va_display_attrs;
+ ASSERT(dst_attr_index < XVBA_MAX_DISPLAY_ATTRIBUTES);
+ driver_data->va_display_attrs_mtime[dst_attr_index] = ++mtime;
+ }
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDbgCopySurfaceToBuffer (not a PUBLIC interface)
+VAStatus
+xvba_DbgCopySurfaceToBuffer(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ void **buffer,
+ unsigned int *stride
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_UNKNOWN;
+}
+
+#if VA_CHECK_VERSION(0,30,0)
+// vaCreateSurfaceFromCIFrame
+VAStatus
+xvba_CreateSurfaceFromCIFrame(
+ VADriverContextP ctx,
+ unsigned long frame_id,
+ VASurfaceID *surface
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_UNKNOWN;
+}
+
+// vaCreateSurfaceFromV4L2Buf
+VAStatus
+xvba_CreateSurfaceFromV4L2Buf(
+ VADriverContextP ctx,
+ int v4l2_fd,
+ struct v4l2_format *v4l2_fmt,
+ struct v4l2_buffer *v4l2_buf,
+ VASurfaceID *surface
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_UNKNOWN;
+}
+
+// vaCopySurfaceToBuffer
+VAStatus
+xvba_CopySurfaceToBuffer(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc,
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ void **buffer
+)
+{
+ /* TODO */
+ return VA_STATUS_ERROR_UNKNOWN;
+}
+#endif
+
+#if VA_CHECK_VERSION(0,31,1)
+// vaLockSurface
+VAStatus
+xvba_LockSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc,
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ unsigned int *buffer_name,
+ void **buffer
+)
+{
+ if (fourcc) *fourcc = VA_FOURCC('N','V','1','2');
+ if (luma_stride) *luma_stride = 0;
+ if (chroma_u_stride) *chroma_u_stride = 0;
+ if (chroma_v_stride) *chroma_v_stride = 0;
+ if (luma_offset) *luma_offset = 0;
+ if (chroma_u_offset) *chroma_u_offset = 0;
+ if (chroma_v_offset) *chroma_v_offset = 0;
+ if (buffer_name) *buffer_name = 0;
+ if (buffer) *buffer = NULL;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaUnlockSurface
+VAStatus
+xvba_UnlockSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface
+)
+{
+ return VA_STATUS_SUCCESS;
+}
+#endif
diff --git a/src/xvba_video.h b/src/xvba_video.h
new file mode 100644
index 0000000..e9daa8b
--- /dev/null
+++ b/src/xvba_video.h
@@ -0,0 +1,329 @@
+/*
+ * xvba_video.h - XvBA backend for VA-API (VA context, config, surfaces)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_VIDEO_H
+#define XVBA_VIDEO_H
+
+#include "xvba_driver.h"
+
+/* Define wait delay (in microseconds) between two XVBASyncSurface() calls */
+#define XVBA_SYNC_DELAY 10
+
+typedef enum {
+ XVBA_CODEC_MPEG1 = 1,
+ XVBA_CODEC_MPEG2,
+ XVBA_CODEC_MPEG4,
+ XVBA_CODEC_H264,
+ XVBA_CODEC_VC1
+} XVBACodec;
+
+typedef struct SubpictureAssociation *SubpictureAssociationP;
+struct SubpictureAssociation {
+ VASubpictureID subpicture;
+ VASurfaceID surface;
+ VARectangle src_rect;
+ VARectangle dst_rect;
+ unsigned int flags;
+};
+
+typedef struct object_config object_config_t;
+struct object_config {
+ struct object_base base;
+ VAProfile profile;
+ VAEntrypoint entrypoint;
+ VAConfigAttrib attrib_list[XVBA_MAX_CONFIG_ATTRIBUTES];
+ unsigned int attrib_count;
+};
+
+typedef struct object_context object_context_t;
+struct object_context {
+ struct object_base base;
+ VAConfigID va_config;
+ unsigned int picture_width;
+ unsigned int picture_height;
+ unsigned int flags;
+ unsigned int num_render_targets;
+ VASurfaceID *render_targets;
+ VASurfaceID current_render_target;
+ XVBACodec xvba_codec;
+ XVBASession *xvba_session;
+ XVBASession *xvba_decoder;
+ VABufferID *va_buffers;
+ unsigned int va_buffers_count;
+ unsigned int va_buffers_count_max;
+
+ /* Temporary data */
+ void *data_buffer; /* commit_picture() */
+ unsigned int slice_count; /* commit_picture() */
+};
+
+typedef struct object_surface object_surface_t;
+struct object_surface {
+ struct object_base base;
+ VAContextID va_context;
+ VASurfaceID va_surface_status;
+ XVBASurface *xvba_surface;
+ unsigned int xvba_surface_width;
+ unsigned int xvba_surface_height;
+ object_output_p *output_surfaces;
+ unsigned int output_surfaces_count;
+ unsigned int output_surfaces_count_max;
+ unsigned int width;
+ unsigned int height;
+ struct object_glx_surface *gl_surface;
+ XVBABufferDescriptor *pic_desc_buffer;
+ XVBABufferDescriptor *iq_matrix_buffer;
+ XVBABufferDescriptor *data_buffer;
+ XVBABufferDescriptor **data_ctrl_buffers;
+ unsigned int data_ctrl_buffers_count;
+ unsigned int data_ctrl_buffers_count_max;
+ SubpictureAssociationP *assocs;
+ unsigned int assocs_count;
+ unsigned int assocs_count_max;
+ struct PutImageHacks *putimage_hacks; /* vaPutImage() hacks */
+ unsigned int used_for_decoding : 1;
+};
+
+// Add subpicture association to surface
+// NOTE: the subpicture owns the SubpictureAssociation object
+int surface_add_association(
+ object_surface_p obj_surface,
+ SubpictureAssociationP assoc
+) attribute_hidden;
+
+// Remove subpicture association from surface
+// NOTE: the subpicture owns the SubpictureAssociation object
+int surface_remove_association(
+ object_surface_p obj_surface,
+ SubpictureAssociationP assoc
+) attribute_hidden;
+
+// Query surface status
+int
+query_surface_status(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface,
+ VASurfaceStatus *surface_status
+) attribute_hidden;
+
+// Synchronize surface
+int
+sync_surface(
+ xvba_driver_data_t *driver_data,
+ object_context_p obj_context,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// vaGetConfigAttributes
+VAStatus
+xvba_GetConfigAttributes(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list,
+ int num_attribs
+) attribute_hidden;
+
+// vaCreateConfig
+VAStatus
+xvba_CreateConfig(
+ VADriverContextP ctx,
+ VAProfile profile,
+ VAEntrypoint entrypoint,
+ VAConfigAttrib *attrib_list,
+ int num_attribs,
+ VAConfigID *config_id
+) attribute_hidden;
+
+// vaDestroyConfig
+VAStatus
+xvba_DestroyConfig(
+ VADriverContextP ctx,
+ VAConfigID config_id
+) attribute_hidden;
+
+// vaQueryConfigAttributes
+VAStatus
+xvba_QueryConfigAttributes(
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ VAProfile *profile,
+ VAEntrypoint *entrypoint,
+ VAConfigAttrib *attrib_list,
+ int *num_attribs
+) attribute_hidden;
+
+// vaCreateSurfaces
+VAStatus
+xvba_CreateSurfaces(
+ VADriverContextP ctx,
+ int width,
+ int height,
+ int format,
+ int num_surfaces,
+ VASurfaceID *surfaces
+) attribute_hidden;
+
+// vaDestroySurfaces
+VAStatus
+xvba_DestroySurfaces(
+ VADriverContextP ctx,
+ VASurfaceID *surface_list,
+ int num_surfaces
+) attribute_hidden;
+
+// vaCreateContext
+VAStatus
+xvba_CreateContext(
+ VADriverContextP ctx,
+ VAConfigID config_id,
+ int picture_width,
+ int picture_height,
+ int flag,
+ VASurfaceID *render_targets,
+ int num_render_targets,
+ VAContextID *context
+) attribute_hidden;
+
+// vaDestroyContext
+VAStatus
+xvba_DestroyContext(
+ VADriverContextP ctx,
+ VAContextID context
+) attribute_hidden;
+
+// vaQuerySurfaceStatus
+VAStatus
+xvba_QuerySurfaceStatus(
+ VADriverContextP ctx,
+ VASurfaceID render_target,
+ VASurfaceStatus *status
+) attribute_hidden;
+
+// vaSyncSurface 2-args variant (>= 0.31)
+VAStatus
+xvba_SyncSurface2(
+ VADriverContextP ctx,
+ VASurfaceID render_target
+) attribute_hidden;
+
+// vaSyncSurface 3-args variant (<= 0.30)
+VAStatus
+xvba_SyncSurface3(
+ VADriverContextP ctx,
+ VAContextID context,
+ VASurfaceID render_target
+) attribute_hidden;
+
+// vaQueryDisplayAttributes
+VAStatus
+xvba_QueryDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int *num_attributes
+) attribute_hidden;
+
+// vaGetDisplayAttributes
+VAStatus
+xvba_GetDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int num_attributes
+) attribute_hidden;
+
+// vaSetDisplayAttributes
+VAStatus
+xvba_SetDisplayAttributes(
+ VADriverContextP ctx,
+ VADisplayAttribute *attr_list,
+ int num_attributes
+) attribute_hidden;
+
+// vaDbgCopySurfaceToBuffer (not a PUBLIC interface)
+VAStatus
+xvba_DbgCopySurfaceToBuffer(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ void **buffer,
+ unsigned int *stride
+) attribute_hidden;
+
+#if VA_CHECK_VERSION(0,30,0)
+// vaCreateSurfaceFromCIFrame
+VAStatus
+xvba_CreateSurfaceFromCIFrame(
+ VADriverContextP ctx,
+ unsigned long frame_id,
+ VASurfaceID *surface
+) attribute_hidden;
+
+// vaCreateSurfaceFromV4L2Buf
+VAStatus
+xvba_CreateSurfaceFromV4L2Buf(
+ VADriverContextP ctx,
+ int v4l2_fd,
+ struct v4l2_format *v4l2_fmt,
+ struct v4l2_buffer *v4l2_buf,
+ VASurfaceID *surface
+) attribute_hidden;
+
+// vaCopySurfaceToBuffer
+VAStatus
+xvba_CopySurfaceToBuffer(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc,
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ void **buffer
+) attribute_hidden;
+#endif
+
+#if VA_CHECK_VERSION(0,31,1)
+// vaLockSurface
+VAStatus
+xvba_LockSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ unsigned int *fourcc,
+ unsigned int *luma_stride,
+ unsigned int *chroma_u_stride,
+ unsigned int *chroma_v_stride,
+ unsigned int *luma_offset,
+ unsigned int *chroma_u_offset,
+ unsigned int *chroma_v_offset,
+ unsigned int *buffer_name,
+ void **buffer
+) attribute_hidden;
+
+// vaUnlockSurface
+VAStatus
+xvba_UnlockSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface
+) attribute_hidden;
+#endif
+
+#endif /* XVBA_VIDEO_H */
diff --git a/src/xvba_video_glx.c b/src/xvba_video_glx.c
new file mode 100644
index 0000000..550a434
--- /dev/null
+++ b/src/xvba_video_glx.c
@@ -0,0 +1,2349 @@
+/*
+ * xvba_video_glx.c - XvBA backend for VA-API (rendering to GLX)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#define _GNU_SOURCE 1 /* RTLD_NEXT */
+#include "sysdeps.h"
+#include "fglrxinfo.h"
+#include "xvba_video.h"
+#include "xvba_video_glx.h"
+#include "xvba_video_x11.h"
+#include "xvba_decode.h"
+#include "xvba_image.h"
+#include "xvba_subpic.h"
+#include "xvba_buffer.h"
+#include "utils.h"
+#include "utils_x11.h"
+#include "utils_glx.h"
+#include <dlfcn.h>
+#include <GL/glext.h>
+#include <GL/glxext.h>
+#include "shaders/Evergreen_mix_1.h"
+#include "shaders/Evergreen_mix_2.h"
+#include "shaders/Evergreen_mix_3.h"
+#include "shaders/Evergreen_mix_4.h"
+#include "shaders/YV12.h"
+#include "shaders/NV12.h"
+#include "shaders/ProcAmp.h"
+#include "shaders/Bicubic.h"
+#include "shaders/Bicubic_FLOAT.h"
+
+#define DEBUG 1
+#include "debug.h"
+
+
+/* Define which Evergreen rendering workaround to use */
+#define EVERGREEN_WORKAROUND (EVERGREEN_WORKAROUND_AUTODETECT)
+
+enum {
+ EVERGREEN_WORKAROUND_SWAP8_X = 1 << 0,
+ EVERGREEN_WORKAROUND_SWAP8_Y = 1 << 1,
+ EVERGREEN_WORKAROUND_SWAP16_X = 1 << 2,
+ EVERGREEN_WORKAROUND_SWAP16_Y = 1 << 3,
+ EVERGREEN_WORKAROUND_SWAP32_X = 1 << 4,
+ EVERGREEN_WORKAROUND_SWAP32_Y = 1 << 5,
+ EVERGREEN_WORKAROUND_SWAP64_X = 1 << 6,
+ EVERGREEN_WORKAROUND_SWAP64_Y = 1 << 7,
+ EVERGREEN_WORKAROUND_COPY = 1 << 8,
+ EVERGREEN_WORKAROUND_AUTODETECT = 1 << 31,
+};
+
+/* Defined to 1 to use a multi-threaded vaPutSurface() implementation */
+#define USE_PUTSURFACE_FAST 0
+
+static int get_use_putsurface_fast_env(void)
+{
+ int use_putsurface_fast;
+ if (getenv_yesno("XVBA_VIDEO_PUTSURFACE_FAST", &use_putsurface_fast) < 0)
+ use_putsurface_fast = USE_PUTSURFACE_FAST;
+ return use_putsurface_fast;
+}
+
+static inline int use_putsurface_fast(void)
+{
+ static int g_use_putsurface_fast = -1;
+ if (g_use_putsurface_fast < 0)
+ g_use_putsurface_fast = get_use_putsurface_fast_env();
+ return g_use_putsurface_fast;
+}
+
+static int get_evergreen_workaround_env(void)
+{
+ int evergreen_workaround;
+ if (getenv_int("XVBA_VIDEO_EVERGREEN_WORKAROUND",
+ &evergreen_workaround) < 0) {
+ const char *evergreen_workaround_str;
+ evergreen_workaround_str = getenv("XVBA_VIDEO_EVERGREEN_WORKAROUND");
+ if (evergreen_workaround_str &&
+ strcmp(evergreen_workaround_str, "auto") == 0)
+ evergreen_workaround = EVERGREEN_WORKAROUND_AUTODETECT;
+ else
+ evergreen_workaround = EVERGREEN_WORKAROUND;
+ }
+ return evergreen_workaround;
+}
+
+static inline int get_evergreen_workaround(void)
+{
+ static int g_evergreen_workaround = -1;
+ if (g_evergreen_workaround < 0)
+ g_evergreen_workaround = get_evergreen_workaround_env();
+ return g_evergreen_workaround;
+}
+
+// Prototypes
+static VAStatus
+do_put_surface_glx(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output,
+ object_surface_p obj_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+);
+
+static VAStatus
+flip_surface(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output
+);
+
+static void
+glx_output_surface_lock(object_glx_output_p obj_output);
+
+static void
+glx_output_surface_unlock(object_glx_output_p obj_output);
+
+// Renderer thread messenger
+#define MSG2PTR(v) ((void *)(uintptr_t)(v))
+#define PTR2MSG(v) ((uintptr_t)(void *)(v))
+enum {
+ MSG_TYPE_QUIT = 1,
+ MSG_TYPE_FLIP
+};
+
+typedef struct {
+ object_surface_p obj_surface;
+ VARectangle src_rect;
+ VARectangle dst_rect;
+ unsigned int flags;
+} PutSurfaceMsg;
+
+// Renderer thread
+typedef struct {
+ xvba_driver_data_t *driver_data;
+ object_glx_output_p obj_output;
+} RenderThreadArgs;
+
+static const unsigned int VIDEO_REFRESH = 1000000 / 60;
+
+static void *render_thread(void *arg)
+{
+ RenderThreadArgs * const args = arg;
+ xvba_driver_data_t * const driver_data = args->driver_data;
+ object_glx_output_p const obj_output = args->obj_output;
+ unsigned int stop = 0, num_surfaces = 0;
+ uint64_t next;
+
+ /* RenderThreadArgs were allocated in the main thread and the
+ render thread is responsible for deallocating them */
+ free(args);
+
+#if 0
+ /* Create a new X connection so that glXSwapBuffers() doesn't get
+ through the main thread X queue that probably wasn't set up as
+ MT-safe [XInitThreads()].
+
+ XXX: this assumes the Catalyst driver can still share GLX
+ contexts from another Display struct, though actually the very
+ same underlying X11 display (XDisplayString() shall match). */
+ Display *x11_dpy;
+ x11_dpy = XOpenDisplay(driver_data->x11_dpy_name);
+ if (!x11_dpy) {
+ obj_output->render_thread_ok = 0;
+ return NULL;
+ }
+#else
+ /* Use the xvba-video global X11 display */
+ Display * const x11_dpy = driver_data->x11_dpy_local;
+#endif
+
+ GLContextState old_cs;
+ obj_output->render_context = gl_create_context(
+ x11_dpy,
+ driver_data->x11_screen,
+ obj_output->gl_context
+ );
+ if (!obj_output->render_context) {
+ obj_output->render_thread_ok = 0;
+ return NULL;
+ }
+ gl_set_current_context(obj_output->render_context, &old_cs);
+ gl_init_context(obj_output->render_context);
+
+ while (!stop) {
+ PutSurfaceMsg *msg;
+
+ // Handle message
+ next = get_ticks_usec() + VIDEO_REFRESH;
+ msg = async_queue_timed_pop(obj_output->render_comm, next);
+ if (!msg) {
+ /* No new surface received during this video time slice,
+ make an explicit flip with what was received so far */
+ goto do_flip;
+ }
+
+ switch (PTR2MSG(msg)) {
+ case MSG_TYPE_QUIT:
+ stop = 1;
+ break;
+ case MSG_TYPE_FLIP:
+ do_flip:
+ if (num_surfaces > 0) {
+ glx_output_surface_lock(obj_output);
+ gl_resize(obj_output->window.width, obj_output->window.height);
+ flip_surface(driver_data, obj_output);
+ gl_bind_framebuffer_object(obj_output->gl_surface->fbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ gl_unbind_framebuffer_object(obj_output->gl_surface->fbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glx_output_surface_unlock(obj_output);
+ num_surfaces = 0;
+ }
+ break;
+ default:
+ glx_output_surface_lock(obj_output);
+ do_put_surface_glx(
+ driver_data,
+ obj_output,
+ msg->obj_surface,
+ &msg->src_rect,
+ &msg->dst_rect,
+ NULL, 0,
+ msg->flags
+ );
+ glx_output_surface_unlock(obj_output);
+ free(msg);
+ num_surfaces++;
+ break;
+ }
+ }
+ gl_set_current_context(&old_cs, NULL);
+ return NULL;
+}
+
+// Ensure FBO and shader extensions are available
+static inline int ensure_extensions(void)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ return (gl_vtable &&
+ gl_vtable->has_framebuffer_object &&
+ gl_vtable->has_fragment_program &&
+ gl_vtable->has_multitexture);
+}
+
+// Ensure FBO surface is create
+static int fbo_ensure(object_glx_surface_p obj_glx_surface)
+{
+ if (!obj_glx_surface->fbo) {
+ obj_glx_surface->fbo = gl_create_framebuffer_object(
+ obj_glx_surface->target,
+ obj_glx_surface->texture,
+ obj_glx_surface->width,
+ obj_glx_surface->height
+ );
+ if (!obj_glx_surface->fbo)
+ return 0;
+ }
+ ASSERT(obj_glx_surface->fbo);
+ return 1;
+}
+
+// Destroy HW image
+static void destroy_hw_image_glx(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image
+)
+{
+ unsigned int i;
+
+ if (!obj_image || !obj_image->hw.glx)
+ return;
+
+ object_image_glx_p const hwi = obj_image->hw.glx;
+
+ if (hwi->num_textures > 0) {
+ glDeleteTextures(hwi->num_textures, hwi->textures);
+ for (i = 0; i < hwi->num_textures; i++) {
+ hwi->formats[i] = GL_NONE;
+ hwi->textures[i] = 0;
+ }
+ hwi->num_textures = 0;
+ }
+
+ if (hwi->shader) {
+ gl_destroy_shader_object(hwi->shader);
+ hwi->shader = NULL;
+ }
+
+ free(hwi);
+ obj_image->hw.glx = NULL;
+}
+
+// Create HW image
+static VAStatus
+create_hw_image_glx(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ XVBASession *session
+)
+{
+ object_image_glx_p hwi = calloc(1, sizeof(*hwi));
+ if (!hwi)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ obj_image->hw.glx = hwi;
+
+ const char **shader_fp = NULL;
+ unsigned int shader_fp_length = 0;
+ switch (obj_image->image.format.fourcc) {
+ case VA_FOURCC('B','G','R','A'):
+ hwi->num_textures = 1;
+ hwi->formats[0] = GL_BGRA;
+ break;
+ case VA_FOURCC('R','G','B','A'):
+ hwi->num_textures = 1;
+ hwi->formats[0] = GL_RGBA;
+ break;
+ case VA_FOURCC('Y','V','1','2'):
+ case VA_FOURCC('I','4','2','0'):
+ hwi->num_textures = 3;
+ hwi->formats[0] = GL_LUMINANCE;
+ hwi->formats[1] = GL_LUMINANCE;
+ hwi->formats[2] = GL_LUMINANCE;
+ shader_fp = YV12_fp;
+ shader_fp_length = YV12_FP_SZ;
+ break;
+ case VA_FOURCC('N','V','1','2'):
+ hwi->num_textures = 2;
+ hwi->formats[0] = GL_LUMINANCE;
+ hwi->formats[1] = GL_LUMINANCE_ALPHA;
+ shader_fp = NV12_fp;
+ shader_fp_length = NV12_FP_SZ;
+ break;
+ default:
+ hwi->num_textures = 0;
+ break;
+ }
+ ASSERT(hwi->num_textures > 0);
+ if (hwi->num_textures == 0) {
+ destroy_hw_image_glx(driver_data, obj_image);
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+ }
+
+ unsigned int i;
+ hwi->target = GL_TEXTURE_2D;
+ for (i = 0; i < hwi->num_textures; i++) {
+ hwi->textures[i] = gl_create_texture(
+ hwi->target,
+ hwi->formats[i],
+ obj_image->xvba_width >> (i > 0),
+ obj_image->xvba_height >> (i > 0)
+ );
+ if (!hwi->textures[i]) {
+ destroy_hw_image_glx(driver_data, obj_image);
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+ }
+
+ if (hwi->num_textures > 1) {
+ ASSERT(shader_fp);
+ ASSERT(shader_fp_length > 0);
+
+ hwi->shader = gl_create_shader_object(shader_fp, shader_fp_length);
+ if (!hwi->shader)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ }
+
+ hwi->width = obj_image->xvba_width;
+ hwi->height = obj_image->xvba_height;
+ return VA_STATUS_SUCCESS;
+}
+
+// Commit HW image
+static VAStatus
+commit_hw_image_glx(
+ xvba_driver_data_t *driver_data,
+ object_image_p obj_image,
+ object_buffer_p obj_buffer,
+ XVBASession *session
+)
+{
+ object_image_glx_p const hwi = obj_image->hw.glx;
+
+ const int is_I420 = obj_image->image.format.fourcc == VA_FOURCC('I','4','2','0');
+ unsigned int offsets[3];
+ switch (obj_image->image.num_planes) {
+ case 3:
+ offsets[2] = obj_image->image.offsets[is_I420 ? 1 : 2];
+ case 2:
+ offsets[1] = obj_image->image.offsets[is_I420 ? 2 : 1];
+ case 1:
+ offsets[0] = obj_image->image.offsets[0];
+ }
+
+ unsigned int i;
+ for (i = 0; i < hwi->num_textures; i++) {
+ glBindTexture(hwi->target, hwi->textures[i]);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glTexSubImage2D(
+ hwi->target,
+ 0,
+ 0,
+ 0,
+ hwi->width >> (i > 0),
+ hwi->height >> (i > 0),
+ hwi->formats[i], GL_UNSIGNED_BYTE,
+ (uint8_t *)obj_buffer->buffer_data + offsets[i]
+ );
+ glBindTexture(hwi->target, 0);
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+const HWImageHooks hw_image_hooks_glx = {
+ create_hw_image_glx,
+ destroy_hw_image_glx,
+ commit_hw_image_glx
+};
+
+// Render subpictures
+static VAStatus
+render_subpicture(
+ xvba_driver_data_t *driver_data,
+ object_subpicture_p obj_subpicture,
+ object_surface_p obj_surface,
+ const VARectangle *surface_rect,
+ const SubpictureAssociationP assoc
+)
+{
+ VAStatus status = commit_subpicture(
+ driver_data,
+ obj_subpicture,
+ NULL,
+ HWIMAGE_TYPE_GLX
+ );
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ object_image_p const obj_image = XVBA_IMAGE(obj_subpicture->image_id);
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ object_image_glx_p const hwi = obj_image->hw.glx;
+ if (!hwi)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ float alpha = 1.0;
+ if (assoc->flags & VA_SUBPICTURE_GLOBAL_ALPHA)
+ alpha = obj_subpicture->alpha;
+
+ /* XXX: we only support RGBA and BGRA subpictures */
+ if (hwi->num_textures != 1 &&
+ hwi->formats[0] != GL_RGBA && hwi->formats[0] != GL_BGRA)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ glBindTexture(hwi->target, hwi->textures[0]);
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ {
+ VARectangle const * src_rect = &assoc->src_rect;
+ VARectangle const * dst_rect = &assoc->dst_rect;
+ int x1, x2, y1, y2;
+ float tx1, tx2, ty1, ty2;
+
+ /* Clip source area by visible area */
+ const unsigned int subpic_width = hwi->width;
+ const unsigned int subpic_height = hwi->height;
+ tx1 = src_rect->x / (float)subpic_width;
+ ty1 = src_rect->y / (float)subpic_height;
+ tx2 = (src_rect->x + src_rect->width) / (float)subpic_width;
+ ty2 = (src_rect->y + src_rect->height) / (float)subpic_height;
+
+ const float spx = src_rect->width / ((float)subpic_width * (float)obj_surface->width);
+ const float spy = src_rect->height / ((float)subpic_height * (float)obj_surface->height);
+ const float srx1 = tx1 + surface_rect->x * spx;
+ const float srx2 = srx1 + surface_rect->width * spx;
+ const float sry1 = ty1 + surface_rect->y * spy;
+ const float sry2 = sry1 + surface_rect->height * spy;
+
+ if (tx1 < srx1)
+ tx1 = srx1;
+ if (ty1 < sry1)
+ ty1 = sry1;
+ if (tx2 > srx2)
+ tx2 = srx2;
+ if (ty2 > sry2)
+ ty2 = sry2;
+
+ /* Clip dest area by visible area */
+ x1 = dst_rect->x;
+ y1 = dst_rect->y;
+ x2 = dst_rect->x + dst_rect->width;
+ y2 = dst_rect->y + dst_rect->height;
+
+ if (x1 < surface_rect->x)
+ x1 = surface_rect->x;
+ if (y1 < surface_rect->y)
+ y1 = surface_rect->y;
+ if (x2 > surface_rect->x + surface_rect->width)
+ x2 = surface_rect->x + surface_rect->width;
+ if (y2 > surface_rect->y + surface_rect->height)
+ y2 = surface_rect->y + surface_rect->height;
+
+ /* Translate and scale to fit surface size */
+ const float sx = obj_surface->width / (float)surface_rect->width;
+ const float sy = obj_surface->height / (float)surface_rect->height;
+ x1 = (float)(x1 - surface_rect->x) * sx;
+ x2 = (float)(x2 - surface_rect->x) * sx;
+ y1 = (float)(y1 - surface_rect->y) * sy;
+ y2 = (float)(y2 - surface_rect->y) * sy;
+
+ switch (hwi->target) {
+ case GL_TEXTURE_RECTANGLE_ARB:
+ tx1 *= subpic_width;
+ tx2 *= subpic_width;
+ ty1 *= subpic_height;
+ ty2 *= subpic_height;
+ break;
+ }
+
+ glTexCoord2f(tx1, ty1); glVertex2i(x1, y1);
+ glTexCoord2f(tx1, ty2); glVertex2i(x1, y2);
+ glTexCoord2f(tx2, ty2); glVertex2i(x2, y2);
+ glTexCoord2f(tx2, ty1); glVertex2i(x2, y1);
+ }
+ glEnd();
+ glBindTexture(hwi->target, 0);
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+render_subpictures(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ const VARectangle *surface_rect
+)
+{
+ unsigned int i;
+ for (i = 0; i < obj_surface->assocs_count; i++) {
+ SubpictureAssociationP const assoc = obj_surface->assocs[i];
+ ASSERT(assoc);
+ if (!assoc)
+ continue;
+
+ object_subpicture_p obj_subpicture = XVBA_SUBPICTURE(assoc->subpicture);
+ ASSERT(obj_subpicture);
+ if (!obj_subpicture)
+ continue;
+
+ VAStatus status = render_subpicture(
+ driver_data,
+ obj_subpicture,
+ obj_surface,
+ surface_rect,
+ assoc
+ );
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Destroy VA/GLX surface
+static void
+destroy_glx_surface(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+)
+{
+ if (!obj_glx_surface)
+ return;
+
+ if (obj_glx_surface->fbo) {
+ gl_destroy_framebuffer_object(obj_glx_surface->fbo);
+ obj_glx_surface->fbo = NULL;
+ }
+
+ if (obj_glx_surface->tx_xvba_surface) {
+ xvba_destroy_surface(obj_glx_surface->tx_xvba_surface);
+ obj_glx_surface->tx_xvba_surface = NULL;
+ }
+
+ if (obj_glx_surface->tx_texture) {
+ glDeleteTextures(1, &obj_glx_surface->tx_texture);
+ obj_glx_surface->tx_texture = 0;
+ }
+
+ if (obj_glx_surface->xvba_surface) {
+ xvba_destroy_surface(obj_glx_surface->xvba_surface);
+ obj_glx_surface->xvba_surface = NULL;
+ }
+
+ if (obj_glx_surface->procamp_shader) {
+ gl_destroy_shader_object(obj_glx_surface->procamp_shader);
+ obj_glx_surface->procamp_shader = NULL;
+ }
+
+ if (obj_glx_surface->evergreen_fbo) {
+ gl_destroy_framebuffer_object(obj_glx_surface->evergreen_fbo);
+ obj_glx_surface->evergreen_fbo = NULL;
+ }
+
+ if (obj_glx_surface->evergreen_texture) {
+ glDeleteTextures(1, &obj_glx_surface->evergreen_texture);
+ obj_glx_surface->evergreen_texture = 0;
+ }
+
+ if (obj_glx_surface->evergreen_shader) {
+ gl_destroy_shader_object(obj_glx_surface->evergreen_shader);
+ obj_glx_surface->evergreen_shader = NULL;
+ }
+
+ if (obj_glx_surface->hqscaler) {
+ gl_destroy_shader_object(obj_glx_surface->hqscaler);
+ obj_glx_surface->hqscaler = NULL;
+ }
+
+ if (obj_glx_surface->hqscaler_texture) {
+ glDeleteTextures(1, &obj_glx_surface->hqscaler_texture);
+ obj_glx_surface->hqscaler_texture = 0;
+ }
+ free(obj_glx_surface);
+}
+
+// Create VA/GLX surface
+static object_glx_surface_p
+create_glx_surface(
+ xvba_driver_data_t *driver_data,
+ unsigned int width,
+ unsigned int height
+)
+{
+ object_glx_surface_p obj_glx_surface = calloc(1, sizeof(*obj_glx_surface));
+ if (!obj_glx_surface)
+ return NULL;
+
+ obj_glx_surface->refcount = 1;
+ obj_glx_surface->target = GL_TEXTURE_2D;
+ obj_glx_surface->format = GL_BGRA;
+ obj_glx_surface->texture = gl_create_texture(
+ obj_glx_surface->target,
+ obj_glx_surface->format,
+ width,
+ height
+ );
+ obj_glx_surface->width = width;
+ obj_glx_surface->height = height;
+ obj_glx_surface->evergreen_workaround = -1;
+
+ if (!obj_glx_surface->texture) {
+ destroy_glx_surface(driver_data, obj_glx_surface);
+ obj_glx_surface = NULL;
+ }
+ return obj_glx_surface;
+}
+
+// Check internal texture format is supported
+static int
+is_supported_internal_format(GLenum format)
+{
+ /* XXX: we don't support other textures than RGBA */
+ switch (format) {
+ case 4:
+ case GL_RGBA:
+ case GL_RGBA8:
+ return 1;
+ }
+ return 0;
+}
+
+static object_glx_surface_p
+create_glx_surface_from_texture(
+ xvba_driver_data_t *driver_data,
+ GLenum target,
+ GLuint texture
+)
+{
+ object_glx_surface_p obj_glx_surface = NULL;
+ unsigned int iformat, border_width, width, height;
+ int is_error = 1;
+
+ obj_glx_surface = calloc(1, sizeof(*obj_glx_surface));
+ if (!obj_glx_surface)
+ goto end;
+
+ obj_glx_surface->refcount = 1;
+ obj_glx_surface->target = target;
+ obj_glx_surface->format = GL_NONE;
+ obj_glx_surface->texture = texture;
+ obj_glx_surface->evergreen_workaround = -1;
+
+ /* XXX: we don't support other textures than RGBA */
+ glBindTexture(target, texture);
+ if (!gl_get_texture_param(target, GL_TEXTURE_INTERNAL_FORMAT, &iformat))
+ goto end;
+ if (!is_supported_internal_format(iformat))
+ goto end;
+
+ /* Check texture format */
+ /* XXX: huh, there does not seem to exist any way to achieve this... */
+
+ /* Check texture dimensions */
+ if (!gl_get_texture_param(target, GL_TEXTURE_BORDER, &border_width))
+ goto end;
+ if (!gl_get_texture_param(target, GL_TEXTURE_WIDTH, &width))
+ goto end;
+ if (!gl_get_texture_param(target, GL_TEXTURE_HEIGHT, &height))
+ goto end;
+
+ width -= 2 * border_width;
+ height -= 2 * border_width;
+ if (width == 0 || height == 0)
+ goto end;
+
+ obj_glx_surface->width = width;
+ obj_glx_surface->height = height;
+
+ is_error = 0;
+end:
+ glBindTexture(target, 0);
+ if (is_error && obj_glx_surface) {
+ destroy_glx_surface(driver_data, obj_glx_surface);
+ obj_glx_surface = NULL;
+ }
+ return obj_glx_surface;
+}
+
+// Unreferences GLX surface
+void
+glx_surface_unref(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+)
+{
+ if (obj_glx_surface && --obj_glx_surface->refcount == 0)
+ destroy_glx_surface(driver_data, obj_glx_surface);
+}
+
+// References GLX surface
+object_glx_surface_p
+glx_surface_ref(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+)
+{
+ if (!obj_glx_surface)
+ return NULL;
+ ++obj_glx_surface->refcount;
+ return obj_glx_surface;
+}
+
+static object_glx_surface_p
+glx_surface_lookup(
+ xvba_driver_data_t *driver_data,
+ unsigned int width,
+ unsigned int height
+)
+{
+ object_base_p obj;
+ object_heap_iterator iter;
+ obj = object_heap_first(&driver_data->surface_heap, &iter);
+ while (obj) {
+ object_surface_p const obj_surface = (object_surface_p)obj;
+ if (obj_surface->gl_surface &&
+ obj_surface->gl_surface->width == width &&
+ obj_surface->gl_surface->height == height)
+ return obj_surface->gl_surface;
+ obj = object_heap_next(&driver_data->surface_heap, &iter);
+ }
+ return NULL;
+}
+
+static object_glx_surface_p
+glx_surface_ensure(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ object_glx_output_p obj_output
+)
+{
+ object_glx_surface_p gl_surface = obj_surface->gl_surface;
+
+ /* Try to find a VA/GLX surface with the same dimensions */
+ if (!gl_surface) {
+ gl_surface = glx_surface_lookup(
+ driver_data,
+ obj_surface->xvba_surface_width,
+ obj_surface->xvba_surface_height
+ );
+ if (gl_surface)
+ obj_surface->gl_surface = glx_surface_ref(driver_data, gl_surface);
+ }
+
+ /* Allocate a new VA/GLX surface */
+ if (!gl_surface) {
+ gl_surface = create_glx_surface(
+ driver_data,
+ obj_surface->xvba_surface_width,
+ obj_surface->xvba_surface_height
+ );
+ if (gl_surface) {
+ gl_surface->gl_context = obj_output->gl_context;
+ obj_surface->gl_surface = gl_surface;
+ }
+ }
+ return gl_surface;
+}
+
+// Translates vaPutSurface flags to XVBA_SURFACE_FLAG
+static inline XVBA_SURFACE_FLAG get_XVBA_SURFACE_FLAG(unsigned int flags)
+{
+ switch (flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD)) {
+ case VA_TOP_FIELD: return XVBA_TOP_FIELD;
+ case VA_BOTTOM_FIELD: return XVBA_BOTTOM_FIELD;
+ }
+ return XVBA_FRAME;
+}
+
+// Check whether surface actually has contents to be displayed
+static inline int is_empty_surface(object_surface_p obj_surface)
+{
+ return !obj_surface->used_for_decoding && !obj_surface->putimage_hacks;
+}
+
+static inline void
+fill_evergreen_params(float **pparams, int n)
+{
+ float * const params = *pparams;
+ params[0] = 1.0f / (n * 2);
+ params[2] = (float)n;
+ *pparams += 4;
+}
+
+// Transfer XvBA surface to GLX surface
+static VAStatus
+transfer_surface_native(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface,
+ object_surface_p obj_surface,
+ unsigned int flags
+)
+{
+ GLVTable * const gl_vtable = gl_get_vtable();
+
+ object_context_p obj_context = XVBA_CONTEXT(obj_surface->va_context);
+ if (!obj_context || !obj_context->xvba_session)
+ return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+ /* Create XvBA/GLX surface */
+ if (!obj_glx_surface->xvba_surface) {
+ obj_glx_surface->xvba_surface = xvba_create_surface_gl(
+ obj_context->xvba_decoder,
+ obj_glx_surface->gl_context->context,
+ obj_glx_surface->texture
+ );
+ if (!obj_glx_surface->xvba_surface)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+ ASSERT(obj_glx_surface->xvba_surface);
+
+ /* Make sure the picture is decoded */
+ if (obj_surface->va_surface_status == VASurfaceRendering) {
+ if (sync_surface(driver_data, obj_context, obj_surface) < 0)
+ return VA_STATUS_ERROR_UNKNOWN;
+ }
+
+ XVBASurface *dst_xvba_surface, *src_xvba_surface;
+ dst_xvba_surface = obj_glx_surface->xvba_surface;
+ src_xvba_surface = (obj_surface->putimage_hacks ?
+ obj_surface->putimage_hacks->xvba_surface :
+ obj_surface->xvba_surface);
+
+ /* Check for Evergreen workaround */
+ int needs_evergreen_texture = 0;
+ int evergreen_workaround = obj_glx_surface->evergreen_workaround;
+ if (evergreen_workaround < 0) {
+ evergreen_workaround = get_evergreen_workaround();
+
+ if (evergreen_workaround == EVERGREEN_WORKAROUND_AUTODETECT) {
+ evergreen_workaround = 0;
+ if (driver_data->is_evergreen_gpu) {
+ switch (driver_data->va_display_type) {
+ case VA_DISPLAY_X11:
+ if (fglrx_check_version(0,80,5))
+ evergreen_workaround = 0;
+ else if (driver_data->is_fusion_igp)
+ evergreen_workaround = EVERGREEN_WORKAROUND_COPY;
+ else if (fglrx_check_version(8,78,6))
+ evergreen_workaround = (EVERGREEN_WORKAROUND_SWAP8_X |
+ EVERGREEN_WORKAROUND_SWAP8_Y |
+ EVERGREEN_WORKAROUND_SWAP16_X |
+ EVERGREEN_WORKAROUND_SWAP16_Y);
+ break;
+ case VA_DISPLAY_GLX:
+ if (fglrx_check_version(8,80,5))
+ evergreen_workaround = 0;
+ else if (fglrx_check_version(8,79,4) &&
+ driver_data->is_fusion_igp)
+ evergreen_workaround = (EVERGREEN_WORKAROUND_SWAP8_X |
+ EVERGREEN_WORKAROUND_SWAP8_Y |
+ EVERGREEN_WORKAROUND_SWAP16_X);
+ else if (fglrx_check_version(8,78,6) &&
+ driver_data->is_fusion_igp)
+ evergreen_workaround = (EVERGREEN_WORKAROUND_SWAP8_X |
+ EVERGREEN_WORKAROUND_SWAP8_Y |
+ EVERGREEN_WORKAROUND_SWAP16_Y);
+ else if (fglrx_check_version(8,78,6))
+ evergreen_workaround = (EVERGREEN_WORKAROUND_SWAP8_X |
+ EVERGREEN_WORKAROUND_SWAP16_Y |
+ EVERGREEN_WORKAROUND_SWAP32_Y |
+ EVERGREEN_WORKAROUND_SWAP64_Y);
+ break;
+ }
+ }
+ }
+
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_COPY)
+ evergreen_workaround = EVERGREEN_WORKAROUND_COPY;
+
+ D(bug("Using Evergreen workaround %d\n", evergreen_workaround));
+ obj_glx_surface->evergreen_workaround = evergreen_workaround;
+ }
+
+ if (evergreen_workaround) {
+ needs_evergreen_texture = 1;
+
+ if (!obj_glx_surface->evergreen_texture) {
+ obj_glx_surface->evergreen_texture = gl_create_texture(
+ GL_TEXTURE_2D,
+ GL_BGRA,
+ src_xvba_surface->info.normal.width,
+ src_xvba_surface->info.normal.height
+ );
+ if (!obj_glx_surface->evergreen_texture)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ /* XXX: some algorithms work modulo the texture size */
+ glBindTexture(GL_TEXTURE_2D, obj_glx_surface->evergreen_texture);
+ gl_set_texture_wrapping(GL_TEXTURE_2D, GL_REPEAT);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ if (!obj_glx_surface->evergreen_fbo) {
+ obj_glx_surface->evergreen_fbo = gl_create_framebuffer_object(
+ GL_TEXTURE_2D,
+ obj_glx_surface->evergreen_texture,
+ src_xvba_surface->info.normal.width,
+ src_xvba_surface->info.normal.height
+ );
+ if (!obj_glx_surface->evergreen_fbo)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+
+ if (evergreen_workaround != EVERGREEN_WORKAROUND_COPY &&
+ !obj_glx_surface->evergreen_shader) {
+ const char **shader_fp = NULL;
+ unsigned int shader_fp_length = 0;
+ float *params;
+ int i, n_params, n_x_params, n_y_params;
+
+ // program.local[0] = textureSize
+ params = obj_glx_surface->evergreen_params[0];
+ params[0] = (float)src_xvba_surface->info.normal.width;
+ params[1] = (float)src_xvba_surface->info.normal.height;
+ params[2] = 1.0f / src_xvba_surface->info.normal.width;
+ params[3] = 1.0f / src_xvba_surface->info.normal.height;
+
+ // program.local[1..4] = mix_params[0..3]
+ for (i = 1; i <= XVBA_MAX_EVERGREEN_PARAMS; i++) {
+ params = obj_glx_surface->evergreen_params[i];
+ params[0] = 1.0f;
+ params[1] = 1.0f;
+ params[2] = 0.0f;
+ params[3] = 0.0f;
+ }
+
+ // fill in X params
+ params = &obj_glx_surface->evergreen_params[1][0];
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP8_X)
+ fill_evergreen_params(&params, 8);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP16_X)
+ fill_evergreen_params(&params, 16);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP32_X)
+ fill_evergreen_params(&params, 32);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP64_X)
+ fill_evergreen_params(&params, 64);
+ n_x_params = (params - &obj_glx_surface->evergreen_params[1][0])/4;
+
+ // fill in Y params
+ params = &obj_glx_surface->evergreen_params[1][1];
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP8_Y)
+ fill_evergreen_params(&params, 8);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP16_Y)
+ fill_evergreen_params(&params, 16);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP32_Y)
+ fill_evergreen_params(&params, 32);
+ if (evergreen_workaround & EVERGREEN_WORKAROUND_SWAP64_Y)
+ fill_evergreen_params(&params, 64);
+ n_y_params = (params - &obj_glx_surface->evergreen_params[1][1])/4;
+
+ // load shader
+ n_params = MAX(n_x_params, n_y_params);
+ switch (n_params) {
+ case 1:
+ shader_fp = Evergreen_mix_1_fp;
+ shader_fp_length = EVERGREEN_MIX_1_FP_SZ;
+ break;
+ case 2:
+ shader_fp = Evergreen_mix_2_fp;
+ shader_fp_length = EVERGREEN_MIX_2_FP_SZ;
+ break;
+ case 3:
+ shader_fp = Evergreen_mix_3_fp;
+ shader_fp_length = EVERGREEN_MIX_3_FP_SZ;
+ break;
+ case 4:
+ shader_fp = Evergreen_mix_4_fp;
+ shader_fp_length = EVERGREEN_MIX_4_FP_SZ;
+ break;
+ default:
+ /* XXX: unsupported combination, disable Evergreen workaround */
+ D(bug("ERROR: unsupported Evergreen workaround 0x%x, disabling\n",
+ evergreen_workaround));
+ obj_glx_surface->evergreen_workaround = 0;
+ break;
+ }
+ obj_glx_surface->evergreen_params_count = n_params;
+
+ if (shader_fp && shader_fp_length) {
+ obj_glx_surface->evergreen_shader = gl_create_shader_object(
+ shader_fp,
+ shader_fp_length
+ );
+ if (!obj_glx_surface->evergreen_shader)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ }
+ }
+ }
+
+ /* Make sure GLX texture has the same dimensions as the surface */
+ int needs_tx_texture = 0;
+ if (needs_evergreen_texture ||
+ obj_glx_surface->format == GL_RGBA || // XXX: XvBA bug, no RGBA support
+ (/*!fglrx_check_version(8,76,7) &&*/ // XXX: #70011.64 supposedly fixed
+ (obj_glx_surface->width != src_xvba_surface->info.normal.width ||
+ obj_glx_surface->height != src_xvba_surface->info.normal.height))) {
+ again:
+ needs_tx_texture = 1;
+
+ if (!obj_glx_surface->tx_texture) {
+ obj_glx_surface->tx_texture = gl_create_texture(
+ GL_TEXTURE_2D,
+ GL_BGRA,
+ src_xvba_surface->info.normal.width,
+ src_xvba_surface->info.normal.height
+ );
+ if (!obj_glx_surface->tx_texture)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+
+ if (!obj_glx_surface->tx_xvba_surface) {
+ obj_glx_surface->tx_xvba_surface = xvba_create_surface_gl(
+ obj_context->xvba_decoder,
+ obj_glx_surface->gl_context->context,
+ obj_glx_surface->tx_texture
+ );
+ if (!obj_glx_surface->tx_xvba_surface)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+
+ if (!fbo_ensure(obj_glx_surface))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ dst_xvba_surface = obj_glx_surface->tx_xvba_surface;
+ }
+
+ /* Transfer XvBA surface */
+ if (xvba_transfer_surface(obj_context->xvba_session,
+ dst_xvba_surface,
+ src_xvba_surface,
+ get_XVBA_SURFACE_FLAG(flags)) < 0) {
+ /* XXX: the user texture is probably RGBA so, create the tx texture */
+ if (!needs_tx_texture && obj_glx_surface->format == GL_NONE) {
+ obj_glx_surface->format = GL_RGBA;
+ goto again;
+ }
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ }
+ if (!needs_tx_texture && obj_glx_surface->format == GL_NONE)
+ obj_glx_surface->format = GL_BGRA;
+
+ GLuint alternate_texture;
+ int needs_alternate_texture = 0;
+ if (needs_evergreen_texture) {
+ needs_alternate_texture = 1;
+ alternate_texture = obj_glx_surface->evergreen_texture;
+
+ gl_bind_framebuffer_object(obj_glx_surface->evergreen_fbo);
+ glBindTexture(GL_TEXTURE_2D, obj_glx_surface->tx_texture);
+ if (obj_glx_surface->evergreen_shader) {
+ gl_bind_shader_object(obj_glx_surface->evergreen_shader);
+
+ int i;
+ for (i = 0; i <= obj_glx_surface->evergreen_params_count; i++)
+ gl_vtable->gl_program_local_parameter_4fv(
+ GL_FRAGMENT_PROGRAM,
+ i,
+ obj_glx_surface->evergreen_params[i]
+ );
+ }
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ {
+ const unsigned int w = src_xvba_surface->info.normal.width;
+ const unsigned int h = src_xvba_surface->info.normal.height;
+ glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+ glTexCoord2f(1.0f, 0.0f); glVertex2i(w, 0);
+ glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h);
+ glTexCoord2f(0.0f, 1.0f); glVertex2i(0, h);
+ }
+ glEnd();
+ if (obj_glx_surface->evergreen_shader)
+ gl_unbind_shader_object(obj_glx_surface->evergreen_shader);
+ gl_unbind_framebuffer_object(obj_glx_surface->evergreen_fbo);
+ }
+ else if (needs_tx_texture) {
+ needs_alternate_texture = 1;
+ alternate_texture = obj_glx_surface->tx_texture;
+ }
+
+ if (needs_alternate_texture) {
+ gl_bind_framebuffer_object(obj_glx_surface->fbo);
+ glBindTexture(GL_TEXTURE_2D, alternate_texture);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ {
+ /* Both TX and Evergreen textures are GL_TEXTURE_2D */
+ const unsigned int w = obj_glx_surface->width;
+ const unsigned int h = obj_glx_surface->height;
+ const float tw = obj_surface->width / (float)src_xvba_surface->info.normal.width;
+ const float th = obj_surface->height / (float)src_xvba_surface->info.normal.height;
+ glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+ glTexCoord2f(tw, 0.0f); glVertex2i(w, 0);
+ glTexCoord2f(tw, th ); glVertex2i(w, h);
+ glTexCoord2f(0.0f, th ); glVertex2i(0, h);
+ }
+ glEnd();
+ gl_unbind_framebuffer_object(obj_glx_surface->fbo);
+ }
+ return VA_STATUS_SUCCESS;
+}
+
+// Transfer VA surface to GLX surface
+static VAStatus
+transfer_surface(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface,
+ object_surface_p obj_surface,
+ unsigned int flags
+)
+{
+ PutImageHacks * const h = obj_surface->putimage_hacks;
+
+ if (!h || h->type == PUTIMAGE_HACKS_SURFACE)
+ return transfer_surface_native(driver_data,
+ obj_glx_surface,
+ obj_surface,
+ flags);
+
+ object_image_p obj_image = h->obj_image;
+ if (!obj_image)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ VAStatus status;
+ status = commit_hw_image(driver_data, obj_image, NULL, HWIMAGE_TYPE_GLX);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ object_image_glx_p const hwi = obj_image->hw.glx;
+ if (!hwi)
+ return VA_STATUS_ERROR_INVALID_IMAGE;
+
+ if (!fbo_ensure(obj_glx_surface))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ object_buffer_p obj_buffer = XVBA_BUFFER(obj_image->image.buf);
+ if (!obj_buffer)
+ return VA_STATUS_ERROR_INVALID_BUFFER;
+
+ GLVTable * const gl_vtable = gl_get_vtable();
+ unsigned int i;
+ for (i = 0; i < hwi->num_textures; i++) {
+ if (hwi->shader)
+ gl_vtable->gl_active_texture(GL_TEXTURE0 + i);
+ glBindTexture(hwi->target, hwi->textures[i]);
+ }
+
+ gl_bind_framebuffer_object(obj_glx_surface->fbo);
+ if (hwi->shader)
+ gl_bind_shader_object(hwi->shader);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ {
+ float tw, th;
+ switch (hwi->target) {
+ case GL_TEXTURE_2D:
+ tw = obj_image->image.width == hwi->width ?
+ 1.0f :
+ (obj_image->image.width - 0.5f) / (float)hwi->width;
+ th = obj_image->image.height == hwi->height ?
+ 1.0f :
+ (obj_image->image.height - 0.5f) / (float)hwi->height;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ tw = (float)obj_image->image.width;
+ th = (float)obj_image->image.height;
+ break;
+ default:
+ tw = 0.0f;
+ th = 0.0f;
+ ASSERT(hwi->target == GL_TEXTURE_2D ||
+ hwi->target == GL_TEXTURE_RECTANGLE_ARB);
+ break;
+ }
+
+ const unsigned int w = obj_glx_surface->width;
+ const unsigned int h = obj_glx_surface->height;
+ glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+ glTexCoord2f(0.0f, th ); glVertex2i(0, h);
+ glTexCoord2f(tw , th ); glVertex2i(w, h);
+ glTexCoord2f(tw , 0.0f); glVertex2i(w, 0);
+ }
+ glEnd();
+ if (hwi->shader)
+ gl_unbind_shader_object(hwi->shader);
+ gl_unbind_framebuffer_object(obj_glx_surface->fbo);
+
+ i = hwi->num_textures;
+ do {
+ --i;
+ if (hwi->shader)
+ gl_vtable->gl_active_texture(GL_TEXTURE0 + i);
+ glBindTexture(hwi->target, 0);
+ } while (i > 0);
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+ensure_procamp_shader(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+)
+{
+ uint64_t new_mtime = obj_glx_surface->procamp_mtime;
+ unsigned int i, n_procamp_zeros = 0;
+
+ for (i = 0; i < driver_data->va_display_attrs_count; i++) {
+ VADisplayAttribute * const attr = &driver_data->va_display_attrs[i];
+
+ switch (attr->type) {
+ case VADisplayAttribBrightness:
+ case VADisplayAttribContrast:
+ case VADisplayAttribSaturation:
+ case VADisplayAttribHue:
+ if (attr->value == 0)
+ ++n_procamp_zeros;
+ if (new_mtime < driver_data->va_display_attrs_mtime[i])
+ new_mtime = driver_data->va_display_attrs_mtime[i];
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Check that ProcAmp adjustments were made since the last call */
+ if (new_mtime <= obj_glx_surface->procamp_mtime)
+ return VA_STATUS_SUCCESS;
+
+ /* Check that we really need a shader (ProcAmp with non-default values) */
+ if (n_procamp_zeros == 4) {
+ obj_glx_surface->use_procamp_shader = 0;
+ obj_glx_surface->procamp_mtime = new_mtime;
+ return VA_STATUS_SUCCESS;
+ }
+
+ if (obj_glx_surface->procamp_shader) {
+ gl_destroy_shader_object(obj_glx_surface->procamp_shader);
+ obj_glx_surface->procamp_shader = NULL;
+ }
+ obj_glx_surface->procamp_shader = gl_create_shader_object(
+ ProcAmp_fp,
+ PROCAMP_FP_SZ
+ );
+ if (!obj_glx_surface->procamp_shader)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ obj_glx_surface->use_procamp_shader = 1;
+ obj_glx_surface->procamp_mtime = new_mtime;
+ return VA_STATUS_SUCCESS;
+}
+
+static GLuint
+ensure_hqscaler_texture(void)
+{
+ const int N = 128;
+ float *data = NULL;
+ GLuint tex = 0;
+ unsigned int i;
+
+ tex = gl_create_texture(GL_TEXTURE_1D, GL_RGBA32F_ARB, N, 0);
+ if (!tex)
+ goto error;
+
+ data = malloc(N * 4 * sizeof(*data));
+ if (!data)
+ goto error;
+
+ /* Generate weights and offsets */
+ for (i = 0; i < N; i++) {
+ const float x = (1.0f*i) / N;
+ const float x2 = x*x;
+ const float x3 = x2*x;
+ const float w0 = (1.0f/6.0f) * ( -x3 + 3.0f*x2 - 3.0f*x + 1.0f);
+ const float w1 = (1.0f/6.0f) * ( 3.0f*x3 - 6.0f*x2 + 4.0f);
+ const float w2 = (1.0f/6.0f) * (-3.0f*x3 + 3.0f*x2 + 3.0f*x + 1.0f);
+ const float w3 = (1.0f/6.0f) * ( x3);
+ const float g0 = w0 + w1;
+ const float h0 = -1.0f + w1 / g0 + 0.5f;
+ const float g1 = w2 + w3;
+ const float h1 = 1.0f + w3 / g1 + 0.5f;
+
+ /* float4 = (h0, h1, g0, g1) */
+ data[i*4 + 0] = h0;
+ data[i*4 + 1] = h1;
+ data[i*4 + 2] = g0;
+ data[i*4 + 3] = g1;
+ }
+
+ glBindTexture(GL_TEXTURE_1D, tex);
+ gl_set_texture_scaling(GL_TEXTURE_1D, GL_NEAREST);
+ gl_set_texture_wrapping(GL_TEXTURE_1D, GL_REPEAT);
+ glTexSubImage1D(
+ GL_TEXTURE_1D,
+ 0,
+ 0,
+ N,
+ GL_RGBA,
+ GL_FLOAT,
+ data
+ );
+ glBindTexture(GL_TEXTURE_1D, 0);
+ free(data);
+ return tex;
+
+ /* ERRORS */
+error:
+ if (tex)
+ glDeleteTextures(1, &tex);
+ if (data)
+ free(data);
+ return 0;
+}
+
+static VAStatus
+ensure_scaler(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface,
+ unsigned int flags
+)
+{
+ const unsigned int va_scale = flags & VA_FILTER_SCALING_MASK;
+
+ if (obj_glx_surface->va_scale == va_scale)
+ return VA_STATUS_SUCCESS;
+
+ if (obj_glx_surface->hqscaler) {
+ gl_destroy_shader_object(obj_glx_surface->hqscaler);
+ obj_glx_surface->hqscaler = NULL;
+ }
+
+ if (obj_glx_surface->hqscaler_texture) {
+ glDeleteTextures(1, &obj_glx_surface->hqscaler_texture);
+ obj_glx_surface->hqscaler_texture = 0;
+ }
+
+ const GLenum target = obj_glx_surface->target;
+ switch (va_scale) {
+ case VA_FILTER_SCALING_DEFAULT:
+ glBindTexture(target, obj_glx_surface->texture);
+ gl_set_texture_scaling(target, GL_LINEAR);
+ glBindTexture(target, 0);
+ break;
+ case VA_FILTER_SCALING_FAST:
+ glBindTexture(target, obj_glx_surface->texture);
+ gl_set_texture_scaling(target, GL_NEAREST);
+ glBindTexture(target, 0);
+ break;
+ case VA_FILTER_SCALING_HQ: {
+ const char **shader_fp = NULL;
+ unsigned int shader_fp_length = 0;
+
+ glBindTexture(target, obj_glx_surface->texture);
+ gl_set_texture_scaling(target, GL_LINEAR);
+ glBindTexture(target, 0);
+
+ obj_glx_surface->hqscaler_texture = ensure_hqscaler_texture();
+ if (obj_glx_surface->hqscaler_texture) {
+ shader_fp = Bicubic_FLOAT_fp;
+ shader_fp_length = BICUBIC_FLOAT_FP_SZ;
+ }
+ else {
+ shader_fp = Bicubic_fp;
+ shader_fp_length = BICUBIC_FP_SZ;
+ }
+
+ obj_glx_surface->hqscaler = gl_create_shader_object(
+ shader_fp,
+ shader_fp_length
+ );
+ if (!obj_glx_surface->hqscaler)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ break;
+ }
+ }
+
+ obj_glx_surface->va_scale = va_scale;
+ return VA_STATUS_SUCCESS;
+}
+
+// vaCreateSurfaceGLX
+VAStatus
+xvba_CreateSurfaceGLX(
+ VADriverContextP ctx,
+ unsigned int target,
+ unsigned int texture,
+ void **gl_surface
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ xvba_set_display_type(driver_data, VA_DISPLAY_GLX);
+
+ if (!gl_surface)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ /* Make sure it is a valid GL texture object */
+ if (!glIsTexture(texture))
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ /* Make sure we have the necessary GLX extensions */
+ if (!ensure_extensions())
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ /* Setup new GLX context */
+ GLContextState old_cs, *new_cs;
+ gl_get_current_context(&old_cs);
+ old_cs.display = driver_data->x11_dpy;
+ new_cs = gl_create_context(driver_data->x11_dpy, driver_data->x11_screen, &old_cs);
+ if (!new_cs)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ if (!gl_set_current_context(new_cs, NULL))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ gl_init_context(new_cs);
+
+ object_glx_surface_p obj_glx_surface;
+ obj_glx_surface = create_glx_surface_from_texture(
+ driver_data,
+ target,
+ texture
+ );
+ if (!obj_glx_surface)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ *gl_surface = obj_glx_surface;
+ obj_glx_surface->gl_context = new_cs;
+
+ gl_set_current_context(&old_cs, NULL);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaDestroySurfaceGLX
+VAStatus
+xvba_DestroySurfaceGLX(
+ VADriverContextP ctx,
+ void *gl_surface
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ xvba_set_display_type(driver_data, VA_DISPLAY_GLX);
+
+ /* Make sure we have the necessary GLX extensions */
+ if (!ensure_extensions())
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ object_glx_surface_p obj_glx_surface = gl_surface;
+ if (!obj_glx_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ GLContextState old_cs, *new_cs = obj_glx_surface->gl_context;
+ if (!gl_set_current_context(new_cs, &old_cs))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ destroy_glx_surface(driver_data, obj_glx_surface);
+
+ gl_destroy_context(new_cs);
+ gl_set_current_context(&old_cs, NULL);
+ return VA_STATUS_SUCCESS;
+}
+
+// vaCopySurfaceGLX
+static VAStatus
+do_copy_surface_glx(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface,
+ object_surface_p obj_surface,
+ unsigned int flags
+)
+{
+ VAStatus status;
+
+ /* Transfer surface to texture */
+ if (!is_empty_surface(obj_surface)) {
+ status = transfer_surface(driver_data, obj_glx_surface, obj_surface, flags);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+
+ /* Make sure color matrix for ProcAmp adjustments is setup */
+ status = ensure_procamp_shader(driver_data, obj_glx_surface);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ /* Check if FBO is needed. e.g. for subpictures */
+ const int needs_fbo = (obj_surface->assocs_count > 0 ||
+ obj_glx_surface->use_procamp_shader);
+ if (!needs_fbo)
+ return VA_STATUS_SUCCESS;
+
+ /* Create framebuffer surface */
+ if (!fbo_ensure(obj_glx_surface))
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ gl_bind_framebuffer_object(obj_glx_surface->fbo);
+
+ /* Re-render the video frame with ProcAmp adjustments */
+ if (obj_glx_surface->use_procamp_shader) {
+ GLVTable * const gl_vtable = gl_get_vtable();
+ int i;
+
+ gl_bind_shader_object(obj_glx_surface->procamp_shader);
+
+ /* Commit the new ProcAmp color matrix */
+ for (i = 0; i < 4; i++)
+ gl_vtable->gl_program_local_parameter_4fv(
+ GL_FRAGMENT_PROGRAM, i,
+ driver_data->cm_composite[i]
+ );
+
+ /* Render the picture frame */
+ glBindTexture(obj_glx_surface->target, obj_glx_surface->texture);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ {
+ float tw, th;
+ switch (obj_glx_surface->target) {
+ case GL_TEXTURE_2D:
+ tw = 1.0f;
+ th = 1.0f;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ tw = (float)obj_glx_surface->width;
+ th = (float)obj_glx_surface->height;
+ break;
+ default:
+ tw = 0.0f;
+ th = 0.0f;
+ ASSERT(obj_glx_surface->target == GL_TEXTURE_2D ||
+ obj_glx_surface->target == GL_TEXTURE_RECTANGLE_ARB);
+ break;
+ }
+
+ const unsigned int w = obj_glx_surface->width;
+ const unsigned int h = obj_glx_surface->height;
+ glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+ glTexCoord2f(tw , 0.0f); glVertex2i(w, 0);
+ glTexCoord2f(tw , th ); glVertex2i(w, h);
+ glTexCoord2f(0.0f, th ); glVertex2i(0, h);
+ }
+ glEnd();
+ glBindTexture(obj_glx_surface->target, 0);
+ gl_unbind_shader_object(obj_glx_surface->procamp_shader);
+ }
+
+ /* Render subpictures to FBO */
+ VARectangle surface_rect;
+ surface_rect.x = 0;
+ surface_rect.y = 0;
+ surface_rect.width = obj_surface->width;
+ surface_rect.height = obj_surface->height;
+ status = render_subpictures(driver_data, obj_surface, &surface_rect);
+
+ gl_unbind_framebuffer_object(obj_glx_surface->fbo);
+ return status;
+}
+
+VAStatus
+xvba_CopySurfaceGLX(
+ VADriverContextP ctx,
+ void *gl_surface,
+ VASurfaceID surface,
+ unsigned int flags
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ xvba_set_display_type(driver_data, VA_DISPLAY_GLX);
+
+ object_glx_surface_p obj_glx_surface = gl_surface;
+ if (!obj_glx_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ object_surface_p obj_surface = XVBA_SURFACE(surface);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ /* Make sure we have the necessary GLX extensions */
+ if (!ensure_extensions())
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ GLContextState old_cs, *new_cs = obj_glx_surface->gl_context;
+ if (!gl_set_current_context(new_cs, &old_cs))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ VAStatus status;
+ status = do_copy_surface_glx(
+ driver_data,
+ obj_glx_surface,
+ obj_surface,
+ flags
+ );
+
+ gl_set_current_context(&old_cs, NULL);
+ return status;
+}
+
+// Locks output surface
+static void
+glx_output_surface_lock(object_glx_output_p obj_output)
+{
+ if (!obj_output || !obj_output->render_thread_ok)
+ return;
+ pthread_mutex_lock(&obj_output->lock);
+}
+
+// Unlocks output surface
+static void
+glx_output_surface_unlock(object_glx_output_p obj_output)
+{
+ if (!obj_output || !obj_output->render_thread_ok)
+ return;
+ pthread_mutex_unlock(&obj_output->lock);
+}
+
+// Destroys output surface
+void
+glx_output_surface_destroy(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output
+)
+{
+ if (!obj_output)
+ return;
+
+ if (1) {
+ const uint64_t end = get_ticks_usec();
+ const uint64_t start = obj_output->render_start;
+ const uint64_t ticks = obj_output->render_ticks;
+
+ D(bug("%llu refreshes in %llu usec (%.1f fps)\n",
+ ticks, end - start,
+ ticks * 1000000.0 / (end - start)));
+ }
+
+ if (obj_output->render_thread_ok) {
+ async_queue_push(obj_output->render_comm, MSG2PTR(MSG_TYPE_QUIT));
+ pthread_join(obj_output->render_thread, NULL);
+ obj_output->render_thread = 0;
+ obj_output->render_thread_ok = 0;
+ }
+
+ if (obj_output->render_comm) {
+ async_queue_free(obj_output->render_comm);
+ obj_output->render_comm = NULL;
+ }
+
+ if (obj_output->render_context) {
+ gl_destroy_context(obj_output->render_context);
+ obj_output->render_context = NULL;
+ }
+
+ if (obj_output->parent)
+ --obj_output->parent->children_count;
+
+ if (obj_output->gl_surface) {
+ if (!obj_output->parent)
+ destroy_glx_surface(driver_data, obj_output->gl_surface);
+ obj_output->gl_surface = NULL;
+ }
+
+ if (obj_output->gl_context) {
+ glFinish();
+ GLContextState dummy_cs;
+ dummy_cs.display = driver_data->x11_dpy;
+ dummy_cs.window = None;
+ dummy_cs.context = NULL;
+ gl_set_current_context(&dummy_cs, NULL);
+ if (!obj_output->parent)
+ gl_destroy_context(obj_output->gl_context);
+ obj_output->gl_context = NULL;
+ }
+
+ if (obj_output->gl_window.xid != None) {
+#if 0
+ /* User's XDestroyWindow() on the parent window will destroy
+ our child windows too */
+ if (!obj_output->parent) {
+ XUnmapWindow(driver_data->x11_dpy, obj_output->gl_window.xid);
+ x11_wait_event(driver_data->x11_dpy, obj_output->gl_window.xid, UnmapNotify);
+ XDestroyWindow(driver_data->x11_dpy, obj_output->gl_window.xid);
+ }
+#endif
+ obj_output->gl_window.xid = None;
+ }
+
+ if (obj_output->gl_window.cmap != None) {
+ if (!obj_output->parent)
+ XFreeColormap(driver_data->x11_dpy, obj_output->gl_window.cmap);
+ obj_output->gl_window.cmap = None;
+ }
+
+ if (obj_output->gl_window.vi) {
+ if (!obj_output->parent)
+ XFree(obj_output->gl_window.vi);
+ obj_output->gl_window.vi = NULL;
+ }
+ free(obj_output);
+}
+
+// Creates output surface
+static object_glx_output_p
+glx_output_surface_create(
+ xvba_driver_data_t *driver_data,
+ Window window,
+ unsigned int width,
+ unsigned int height
+)
+{
+ object_glx_output_p obj_output = calloc(1, sizeof(*obj_output));
+ if (!obj_output)
+ return NULL;
+
+ obj_output->va_surface_status = VASurfaceReady;
+ obj_output->window.xid = window;
+ obj_output->window.width = width;
+ obj_output->window.height = height;
+
+ pthread_mutex_init(&obj_output->lock, NULL);
+
+ /* XXX: recurse through parents until we find an output surface */
+ Window root_window, parent_window, *child_windows = NULL;
+ unsigned int n_child_windows = 0;
+ XQueryTree(
+ driver_data->x11_dpy,
+ window,
+ &root_window,
+ &parent_window,
+ &child_windows, &n_child_windows
+ );
+ if (child_windows)
+ XFree(child_windows);
+
+ GLContextState old_cs, *parent_cs = NULL;
+ gl_get_current_context(&old_cs);
+ old_cs.display = driver_data->x11_dpy;
+
+ if (parent_window != None) {
+ object_output_p parent_obj_output;
+ parent_obj_output = output_surface_lookup(driver_data, parent_window);
+ if (parent_obj_output && parent_obj_output->glx) {
+ obj_output->parent = parent_obj_output->glx;
+ parent_cs = parent_obj_output->glx->gl_context;
+ }
+ }
+
+ static GLint gl_visual_attr[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GL_NONE
+ };
+
+ XWindowAttributes wattr;
+ XGetWindowAttributes(driver_data->x11_dpy, window, &wattr);
+ int depth = wattr.depth;
+ if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
+ depth = 24;
+
+ obj_output->gl_window.vi = glXChooseVisual(
+ driver_data->x11_dpy,
+ driver_data->x11_screen,
+ gl_visual_attr
+ );
+ if (!obj_output->gl_window.vi)
+ goto error;
+
+ obj_output->gl_window.cmap = XCreateColormap(
+ driver_data->x11_dpy,
+ RootWindow(driver_data->x11_dpy, driver_data->x11_screen),
+ obj_output->gl_window.vi->visual,
+ AllocNone
+ );
+ if (obj_output->gl_window.cmap == None)
+ goto error;
+
+ x11_get_window_colorkey(driver_data->x11_dpy, window, 0, 0, &obj_output->bgcolor);
+ if (driver_data->va_background_color)
+ obj_output->bgcolor = driver_data->va_background_color->value;
+
+ XSetWindowAttributes xswa;
+ unsigned long xswa_mask = CWBorderPixel | CWBackPixel | CWColormap;
+ xswa.border_pixel = BlackPixel(driver_data->x11_dpy, driver_data->x11_screen);
+ xswa.background_pixel = obj_output->bgcolor;
+ xswa.colormap = obj_output->gl_window.cmap;
+
+ obj_output->gl_window.xid = XCreateWindow(
+ driver_data->x11_dpy,
+ window,
+ 0,
+ 0,
+ width,
+ height,
+ 0,
+ depth,
+ InputOutput,
+ obj_output->gl_window.vi->visual,
+ xswa_mask, &xswa
+ );
+ if (obj_output->gl_window.xid == None)
+ goto error;
+
+ XSelectInput(driver_data->x11_dpy, obj_output->gl_window.xid, StructureNotifyMask);
+ XMapWindow(driver_data->x11_dpy, obj_output->gl_window.xid);
+ XLowerWindow(driver_data->x11_dpy, obj_output->gl_window.xid);
+ x11_wait_event(driver_data->x11_dpy, obj_output->gl_window.xid, MapNotify);
+
+ /* XXX: assume the program will only be using vaPutSurface() and
+ doesn't have any other GLX context managed itself */
+ ASSERT(driver_data->va_display_type == VA_DISPLAY_X11);
+ gl_set_current_context_cache(1);
+
+ /* XXX: check that we don't already have a valid GLX context */
+ obj_output->gl_context = gl_create_context(
+ driver_data->x11_dpy,
+ driver_data->x11_screen,
+ parent_cs
+ );
+ if (!obj_output->gl_context)
+ goto error;
+ obj_output->gl_context->window = obj_output->gl_window.xid;
+ if (!gl_set_current_context(obj_output->gl_context, NULL))
+ goto error;
+ if (!ensure_extensions()) {
+ gl_set_current_context(&old_cs, NULL);
+ goto error;
+ }
+
+ gl_init_context(obj_output->gl_context);
+ gl_set_bgcolor(obj_output->bgcolor);
+ glClear(GL_COLOR_BUFFER_BIT);
+ gl_set_current_context(&old_cs, NULL);
+
+ if (use_putsurface_fast()) {
+ RenderThreadArgs *args = NULL;
+
+ obj_output->render_comm = async_queue_new();
+ if (!obj_output->render_comm)
+ goto render_thread_init_end;
+
+ args = malloc(sizeof(*args));
+ if (!args)
+ goto render_thread_init_end;
+ args->driver_data = driver_data;
+ args->obj_output = obj_output;
+ obj_output->render_thread_ok = !pthread_create(
+ &obj_output->render_thread,
+ NULL,
+ render_thread,
+ args
+ );
+ render_thread_init_end:
+ if (!obj_output->render_thread_ok)
+ free(args);
+ }
+ obj_output->render_ticks = 0;
+ obj_output->render_start = get_ticks_usec();
+ return obj_output;
+
+error:
+ glx_output_surface_destroy(driver_data, obj_output);
+ return NULL;
+}
+
+// Returns thread-specific GL context
+static inline GLContextState *
+glx_output_surface_get_context(object_glx_output_p obj_output)
+{
+ if (obj_output->render_thread_ok &&
+ obj_output->render_thread == pthread_self())
+ return obj_output->render_context;
+ return obj_output->gl_context;
+}
+
+// Ensures output surface exists
+static object_glx_output_p
+glx_output_surface_ensure(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ Window window
+)
+{
+ object_output_p obj_output;
+ obj_output = output_surface_ensure(driver_data, obj_surface, window);
+ if (!obj_output)
+ return NULL;
+
+ object_glx_output_p glx_output = obj_output->glx;
+ if (!glx_output) {
+ unsigned int w, h;
+ x11_get_geometry(driver_data->x11_dpy, window, NULL, NULL, &w, &h);
+ glx_output = glx_output_surface_create(driver_data, window, w, h);
+ if (!glx_output)
+ return NULL;
+ obj_output->glx = glx_output;
+ }
+ return glx_output;
+}
+
+// Ensures output surface size matches drawable size
+static int
+glx_output_surface_ensure_size(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p glx_output
+)
+{
+ GLContextState * const gl_context = glx_output_surface_get_context(glx_output);
+ Display * const dpy = gl_context->display;
+ const Window win = glx_output->window.xid;
+ unsigned int width, height;
+ int size_changed = 0;
+
+ x11_get_geometry(dpy, win, NULL, NULL, &width, &height);
+ if (glx_output->window.width != width ||
+ glx_output->window.height != height) {
+ /* If there is still a ConfigureNotify event in the queue,
+ this means the user-application was not notified of the
+ change yet. So, just don't assume any change in this case */
+ XEvent e;
+ if (XCheckTypedWindowEvent(dpy, win, ConfigureNotify, &e))
+ XPutBackEvent(dpy, &e);
+ else {
+ glx_output->window.width = width;
+ glx_output->window.height = height;
+ size_changed = 1;
+
+ /* Resize GL rendering window to fit new window size */
+ XMoveResizeWindow(
+ dpy,
+ glx_output->gl_window.xid,
+ 0, 0, width, height
+ );
+ XSync(dpy, False);
+ }
+ }
+
+ /* Make sure the VA/GLX surface is created */
+ if (size_changed) {
+ destroy_glx_surface(driver_data, glx_output->gl_surface);
+ glx_output->gl_surface = NULL;
+ }
+ if (!glx_output->gl_surface) {
+ glx_output->gl_surface = create_glx_surface(
+ driver_data,
+ width,
+ height
+ );
+ if (!glx_output->gl_surface)
+ return -1;
+ glx_output->gl_surface->gl_context = glx_output->gl_context;
+
+ /* Make sure the FBO is created */
+ if (!fbo_ensure(glx_output->gl_surface))
+ return -1;
+ gl_bind_framebuffer_object(glx_output->gl_surface->fbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ gl_unbind_framebuffer_object(glx_output->gl_surface->fbo);
+ }
+ return 0;
+}
+
+// Ensure rectangle is within specified bounds
+static inline void
+ensure_bounds(VARectangle *r, unsigned int width, unsigned int height)
+{
+ if (r->x < 0)
+ r->x = 0;
+ if (r->y < 0)
+ r->y = 0;
+ if (r->width > width - r->x)
+ r->width = width - r->x;
+ if (r->height > height - r->y)
+ r->height = height - r->y;
+}
+
+// Query GLX surface status
+int
+query_surface_status_glx(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+)
+{
+ unsigned int i;
+ for (i = 0; i < obj_surface->output_surfaces_count; i++) {
+ object_glx_output_p obj_output = obj_surface->output_surfaces[i]->glx;
+ if (!obj_output)
+ continue;
+ if (obj_output->va_surface_status != VASurfaceDisplaying)
+ continue;
+ obj_output->va_surface_status = VASurfaceReady;
+
+ /* Make sure all pending OpenGL commands have completed */
+ GLContextState old_cs;
+ if (gl_set_current_context(obj_output->gl_context, &old_cs)) {
+ glFinish();
+ gl_swap_buffers(obj_output->gl_context);
+ gl_set_current_context(&old_cs, NULL);
+ }
+ }
+ return XVBA_COMPLETED;
+}
+
+// Queue surface for display
+VAStatus
+flip_surface(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output
+)
+{
+ object_glx_surface_p const obj_glx_surface = obj_output->gl_surface;
+
+ /* Draw GL surface to screen */
+ glBindTexture(obj_glx_surface->target, obj_glx_surface->texture);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ {
+ float tw, th;
+ switch (obj_glx_surface->target) {
+ case GL_TEXTURE_2D:
+ tw = 1.0f;
+ th = 1.0f;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ tw = (float)obj_glx_surface->width;
+ th = (float)obj_glx_surface->height;
+ break;
+ default:
+ tw = 0.0f;
+ th = 0.0f;
+ ASSERT(obj_glx_surface->target == GL_TEXTURE_2D ||
+ obj_glx_surface->target == GL_TEXTURE_RECTANGLE_ARB);
+ break;
+ }
+
+ const unsigned int w = obj_glx_surface->width;
+ const unsigned int h = obj_glx_surface->height;
+ glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+ glTexCoord2f(0.0f, 1.0f); glVertex2i(0, h);
+ glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h);
+ glTexCoord2f(1.0f, 0.0f); glVertex2i(w, 0);
+ }
+ glEnd();
+ glBindTexture(obj_glx_surface->target, 0);
+
+ gl_swap_buffers(glx_output_surface_get_context(obj_output));
+ obj_output->render_ticks++;
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+queue_surface(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output,
+ object_surface_p obj_surface
+)
+{
+ /* Commit framebuffer to screen */
+ obj_surface->va_surface_status = VASurfaceDisplaying;
+ obj_output->va_surface_status = VASurfaceDisplaying;
+
+ if (obj_output->render_thread_ok)
+ return VA_STATUS_SUCCESS;
+ return flip_surface(driver_data, obj_output);
+}
+
+// Render video surface (and subpictures) into the specified drawable
+static VAStatus
+do_put_surface_glx(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output,
+ object_surface_p obj_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+)
+{
+ /* Ensure VA/GLX surface exists with the specified dimensions */
+ object_glx_surface_p obj_glx_surface;
+ obj_glx_surface = glx_surface_ensure(driver_data, obj_surface, obj_output);
+ if (!obj_glx_surface)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ if (glx_output_surface_ensure_size(driver_data, obj_output) < 0)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ /* Ensure visible rect is within parent window bounds */
+ VARectangle vis_rect = *dst_rect;
+ ensure_bounds(&vis_rect, obj_output->window.width, obj_output->window.height);
+
+ /* Reset GLX viewport for active context */
+ gl_resize(obj_output->window.width, obj_output->window.height);
+
+ /* Transfer surface to texture */
+ VAStatus status;
+ if (!is_empty_surface(obj_surface)) {
+ status = transfer_surface(driver_data, obj_glx_surface, obj_surface, flags);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+ }
+
+ /* Make sure color matrix for ProcAmp adjustments is setup */
+ status = ensure_procamp_shader(driver_data, obj_glx_surface);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ /* Setup scaling algorithm */
+ status = ensure_scaler(driver_data, obj_glx_surface, flags);
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ /* Render picture */
+ GLVTable * const gl_vtable = gl_get_vtable();
+ float params[4];
+ unsigned int i;
+
+ gl_bind_framebuffer_object(obj_output->gl_surface->fbo);
+ gl_vtable->gl_active_texture(GL_TEXTURE0);
+ glBindTexture(obj_glx_surface->target, obj_glx_surface->texture);
+ if (obj_glx_surface->hqscaler) {
+ gl_bind_shader_object(obj_glx_surface->hqscaler);
+ params[0] = (float)obj_glx_surface->width;
+ params[1] = (float)obj_glx_surface->height;
+ params[2] = 1.0f / obj_glx_surface->width;
+ params[3] = 1.0f / obj_glx_surface->height;
+ gl_vtable->gl_program_local_parameter_4fv(
+ GL_FRAGMENT_PROGRAM,
+ 0,
+ params
+ );
+ if (obj_glx_surface->hqscaler_texture) {
+ gl_vtable->gl_active_texture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_1D, obj_glx_surface->hqscaler_texture);
+ }
+ }
+ if (obj_glx_surface->use_procamp_shader) {
+ gl_bind_shader_object(obj_glx_surface->procamp_shader);
+ for (i = 0; i < 4; i++)
+ gl_vtable->gl_program_local_parameter_4fv(
+ GL_FRAGMENT_PROGRAM, i,
+ driver_data->cm_composite[i]
+ );
+ }
+ if (flags & VA_CLEAR_DRAWABLE) {
+ if (driver_data->va_background_color &&
+ driver_data->va_background_color->value != obj_output->bgcolor) {
+ obj_output->bgcolor = driver_data->va_background_color->value;
+ gl_set_bgcolor(obj_output->bgcolor);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ glPushMatrix();
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glTranslatef((float)vis_rect.x, (float)vis_rect.y, 0.0f);
+ if (!is_empty_surface(obj_surface)) {
+ const float surface_width = obj_surface->xvba_surface_width;
+ const float surface_height = obj_surface->xvba_surface_height;
+ float tx1 = src_rect->x / surface_width;
+ float ty1 = src_rect->y / surface_height;
+ float tx2 = tx1 + src_rect->width / surface_width;
+ float ty2 = ty1 + src_rect->height / surface_height;
+ const int w = vis_rect.width;
+ const int h = vis_rect.height;
+
+ switch (obj_glx_surface->target) {
+ case GL_TEXTURE_RECTANGLE_ARB:
+ tx1 *= obj_glx_surface->width;
+ tx2 *= obj_glx_surface->width;
+ ty1 *= obj_glx_surface->height;
+ ty2 *= obj_glx_surface->height;
+ break;
+ }
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(tx1, ty1); glVertex2i(0, 0);
+ glTexCoord2f(tx1, ty2); glVertex2i(0, h);
+ glTexCoord2f(tx2, ty2); glVertex2i(w, h);
+ glTexCoord2f(tx2, ty1); glVertex2i(w, 0);
+ glEnd();
+ }
+ gl_vtable->gl_active_texture(GL_TEXTURE0);
+ glBindTexture(obj_glx_surface->target, 0);
+
+ /* Render subpictures */
+ glScalef(
+ (float)dst_rect->width / (float)obj_surface->width,
+ (float)dst_rect->height / (float)obj_surface->height,
+ 1.0f
+ );
+ status = render_subpictures(driver_data, obj_surface, src_rect);
+ glPopMatrix();
+ if (obj_glx_surface->use_procamp_shader)
+ gl_unbind_shader_object(obj_glx_surface->procamp_shader);
+ if (obj_glx_surface->hqscaler) {
+ if (obj_glx_surface->hqscaler_texture) {
+ gl_vtable->gl_active_texture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_1D, 0);
+ }
+ gl_unbind_shader_object(obj_glx_surface->hqscaler);
+ }
+ gl_unbind_framebuffer_object(obj_output->gl_surface->fbo);
+
+ /* Queue surface for display */
+ return queue_surface(driver_data, obj_output, obj_surface);
+}
+
+VAStatus
+put_surface_glx(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ Drawable drawable,
+ const VARectangle *source_rect,
+ const VARectangle *target_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+)
+{
+ /* XXX: no clip rects supported */
+ if (cliprects || num_cliprects > 0)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ /* Ensure output surface (child window) is set up */
+ object_glx_output_p obj_output;
+ obj_output = glx_output_surface_ensure(driver_data, obj_surface, drawable);
+ if (!obj_output)
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ ASSERT(obj_output->window.xid == drawable);
+ ASSERT(obj_output->gl_window.xid != None);
+ ASSERT(obj_output->gl_context);
+
+ /* Ensure source rect is within surface bounds */
+ VARectangle src_rect = *source_rect;
+ ensure_bounds(&src_rect, obj_surface->width, obj_surface->height);
+
+ /* Send args to render thread */
+ if (obj_output->render_thread_ok) {
+ uint64_t now = get_ticks_usec();
+ PutSurfaceMsg *msg;
+
+ if (now >= obj_output->render_timestamp + VIDEO_REFRESH) {
+ if (!async_queue_push(obj_output->render_comm, MSG2PTR(MSG_TYPE_FLIP)))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ obj_output->render_timestamp = now;
+ }
+
+ msg = malloc(sizeof(*msg));
+ if (!msg)
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+ msg->obj_surface = obj_surface;
+ msg->src_rect = src_rect;
+ msg->dst_rect = *target_rect;
+ msg->flags = flags;
+ if (!async_queue_push(obj_output->render_comm, msg))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+ return VA_STATUS_SUCCESS;
+ }
+
+ GLContextState old_cs;
+ if (!gl_set_current_context(obj_output->gl_context, &old_cs))
+ return VA_STATUS_ERROR_OPERATION_FAILED;
+
+ VAStatus status;
+ status = do_put_surface_glx(
+ driver_data,
+ obj_output,
+ obj_surface,
+ &src_rect,
+ target_rect,
+ cliprects, num_cliprects,
+ flags
+ );
+
+ gl_set_current_context(&old_cs, NULL);
+ return status;
+}
diff --git a/src/xvba_video_glx.h b/src/xvba_video_glx.h
new file mode 100644
index 0000000..ceeb882
--- /dev/null
+++ b/src/xvba_video_glx.h
@@ -0,0 +1,166 @@
+/*
+ * xvba_video_glx.c - XvBA backend for VA-API (rendering to GLX)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_VIDEO_GLX_H
+#define XVBA_VIDEO_GLX_H
+
+#include <va/va.h>
+#include <va/va_backend.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <pthread.h>
+#include "object_heap.h"
+#include "xvba_video_x11.h"
+#include "utils_glx.h"
+#include "uasyncqueue.h"
+
+#define XVBA_MAX_EVERGREEN_PARAMS 4
+
+typedef struct object_glx_output object_glx_output_t;
+typedef struct object_glx_surface object_glx_surface_t;
+typedef struct object_glx_surface *object_glx_surface_p;
+
+struct object_image_glx {
+ GLenum target;
+ GLenum formats[3];
+ GLuint textures[3];
+ unsigned int num_textures;
+ unsigned int width;
+ unsigned int height;
+ GLShaderObject *shader;
+};
+
+struct object_glx_output {
+ VASurfaceStatus va_surface_status;
+ object_glx_output_p parent;
+ unsigned int children_count;
+ struct {
+ Window xid;
+ unsigned int width;
+ unsigned int height;
+ } window;
+ unsigned int bgcolor;
+ struct {
+ Window xid;
+ XVisualInfo *vi;
+ Colormap cmap;
+ } gl_window;
+ GLContextState *gl_context;
+ object_glx_surface_p gl_surface;
+ UAsyncQueue *render_comm;
+ pthread_t render_thread;
+ unsigned int render_thread_ok;
+ GLContextState *render_context;
+ uint64_t render_timestamp;
+ uint64_t render_ticks;
+ uint64_t render_start;
+ pthread_mutex_t lock;
+};
+
+struct object_glx_surface {
+ unsigned int refcount;
+ GLContextState *gl_context;
+ GLenum target;
+ GLenum format;
+ GLuint texture;
+ unsigned int width;
+ unsigned int height;
+ unsigned int va_scale;
+ XVBASurface *xvba_surface;
+ GLFramebufferObject *fbo;
+ unsigned int use_procamp_shader;
+ GLShaderObject *procamp_shader;
+ uint64_t procamp_mtime;
+ GLuint tx_texture; // temporary used for transfer_surface()
+ XVBASurface *tx_xvba_surface;
+ int evergreen_workaround;
+ GLuint evergreen_texture;
+ GLFramebufferObject *evergreen_fbo;
+ GLShaderObject *evergreen_shader;
+ float evergreen_params[1 + XVBA_MAX_EVERGREEN_PARAMS][4];
+ unsigned int evergreen_params_count;
+ GLShaderObject *hqscaler;
+ GLuint hqscaler_texture;
+};
+
+// Destroys GLX output surface
+void
+glx_output_surface_destroy(
+ xvba_driver_data_t *driver_data,
+ object_glx_output_p obj_output
+) attribute_hidden;
+
+// Unreferences GLX surface
+void
+glx_surface_unref(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+) attribute_hidden;
+
+// References GLX surface
+object_glx_surface_p
+glx_surface_ref(
+ xvba_driver_data_t *driver_data,
+ object_glx_surface_p obj_glx_surface
+) attribute_hidden;
+
+// Query GLX surface status
+int
+query_surface_status_glx(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface
+) attribute_hidden;
+
+// Render video surface (and subpictures) into the specified drawable
+VAStatus
+put_surface_glx(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ Drawable drawable,
+ const VARectangle *source_rect,
+ const VARectangle *target_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+) attribute_hidden;
+
+// vaCreateSurfaceGLX
+VAStatus xvba_CreateSurfaceGLX(
+ VADriverContextP ctx,
+ unsigned int target,
+ unsigned int texture,
+ void **gl_surface
+) attribute_hidden;
+
+// vaDestroySurfaceGLX
+VAStatus xvba_DestroySurfaceGLX(
+ VADriverContextP ctx,
+ void *gl_surface
+) attribute_hidden;
+
+// vaCopySurfaceGLX
+VAStatus xvba_CopySurfaceGLX(
+ VADriverContextP ctx,
+ void *gl_surface,
+ VASurfaceID surface,
+ unsigned int flags
+) attribute_hidden;
+
+#endif /* XVBA_VIDEO_GLX_H */
diff --git a/src/xvba_video_x11.c b/src/xvba_video_x11.c
new file mode 100644
index 0000000..9439b91
--- /dev/null
+++ b/src/xvba_video_x11.c
@@ -0,0 +1,223 @@
+/*
+ * xvba_video_x11.c - XvBA backend for VA-API (rendering to X11 through PCOM)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "utils.h"
+#include "xvba_video.h"
+#include "xvba_video_x11.h"
+#if USE_GLX
+#include "xvba_video_glx.h"
+#endif
+
+#define DEBUG 1
+#include "debug.h"
+
+
+// Create output surface
+static object_output_p
+output_surface_create(
+ xvba_driver_data_t *driver_data,
+ Drawable drawable
+)
+{
+ VASurfaceID surface = object_heap_allocate(&driver_data->output_heap);
+ if (surface == VA_INVALID_ID)
+ return NULL;
+
+ object_output_p obj_output = XVBA_OUTPUT(surface);
+ if (!obj_output)
+ return NULL;
+
+ obj_output->refcount = 1;
+ obj_output->drawable = drawable;
+ obj_output->glx = NULL;
+ return obj_output;
+}
+
+// Destroy output surface
+void
+output_surface_destroy(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+)
+{
+#if USE_GLX
+ if (obj_output->glx) {
+ glx_output_surface_destroy(driver_data, obj_output->glx);
+ obj_output->glx = NULL;
+ }
+#endif
+
+ object_heap_free(&driver_data->output_heap, (object_base_p)obj_output);
+}
+
+// Reference output surface
+object_output_p
+output_surface_ref(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+)
+{
+ if (obj_output)
+ ++obj_output->refcount;
+ return obj_output;
+}
+
+// Unreference output surface
+// NOTE: this destroys the surface if refcount reaches zero
+void
+output_surface_unref(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+)
+{
+ if (obj_output && --obj_output->refcount == 0)
+ output_surface_destroy(driver_data, obj_output);
+}
+
+// Lookup output surface in the whole output heap
+object_output_p
+output_surface_lookup(
+ xvba_driver_data_t *driver_data,
+ Drawable drawable
+)
+{
+ object_heap_iterator iter;
+ object_base_p obj = object_heap_first(&driver_data->output_heap, &iter);
+ while (obj) {
+ object_output_p obj_output = (object_output_p)obj;
+ if (obj_output->drawable == drawable)
+ return obj_output;
+ obj = object_heap_next(&driver_data->output_heap, &iter);
+ }
+ return NULL;
+}
+
+// Ensure an output surface is created for the specified surface and drawable
+object_output_p
+output_surface_ensure(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ Drawable drawable
+)
+{
+ object_output_p obj_output = NULL;
+ int new_obj_output = 0;
+ unsigned int i;
+
+ if (!obj_surface)
+ return NULL;
+
+ /* Check for an output surface matching Drawable */
+ for (i = 0; i < obj_surface->output_surfaces_count; i++) {
+ ASSERT(obj_surface->output_surfaces[i]);
+ if (obj_surface->output_surfaces[i]->drawable == drawable) {
+ obj_output = obj_surface->output_surfaces[i];
+ break;
+ }
+ }
+
+ /* ... that might have been created for another video surface */
+ if (!obj_output) {
+ object_output_p m = output_surface_lookup(driver_data, drawable);
+ if (m) {
+ obj_output = output_surface_ref(driver_data, m);
+ new_obj_output = 1;
+ }
+ }
+
+ /* Fallback: create a new output surface */
+ if (!obj_output) {
+ obj_output = output_surface_create(driver_data, drawable);
+ if (!obj_output)
+ return NULL;
+ new_obj_output = 1;
+ }
+
+ /* Append output surface */
+ if (new_obj_output) {
+ if (realloc_buffer(&obj_surface->output_surfaces,
+ &obj_surface->output_surfaces_count_max,
+ 1 + obj_surface->output_surfaces_count,
+ sizeof(*obj_surface->output_surfaces)) == NULL)
+ return NULL;
+ obj_surface->output_surfaces[obj_surface->output_surfaces_count++] = obj_output;
+ }
+ return obj_output;
+}
+
+// vaPutSurface
+VAStatus
+xvba_PutSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VADrawable draw,
+ short srcx,
+ short srcy,
+ unsigned short srcw,
+ unsigned short srch,
+ short destx,
+ short desty,
+ unsigned short destw,
+ unsigned short desth,
+ VARectangle *cliprects,
+ unsigned int number_cliprects,
+ unsigned int flags
+)
+{
+ XVBA_DRIVER_DATA_INIT;
+
+ xvba_set_display_type(driver_data, VA_DISPLAY_X11);
+
+ D(bug("vaPutSurface(): surface 0x%08x, drawable 0x%08x, "
+ "src rect (%d,%d):%dx%d, dest rect (%d,%d):%dx%d\n",
+ surface, POINTER_TO_UINT(draw),
+ srcx, srcy, srcw, srch,
+ destx, desty, destw, desth));
+
+ /* Make sure drawable is valid */
+ /* XXX: check the drawable is actually a window */
+ if (draw == None)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ object_surface_p obj_surface = XVBA_SURFACE(surface);
+ if (!obj_surface)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ VARectangle src_rect, dst_rect;
+ src_rect.x = srcx;
+ src_rect.y = srcy;
+ src_rect.width = srcw;
+ src_rect.height = srch;
+ dst_rect.x = destx;
+ dst_rect.y = desty;
+ dst_rect.width = destw;
+ dst_rect.height = desth;
+
+ const XID xid = POINTER_TO_UINT(draw);
+#if USE_GLX
+ return put_surface_glx(driver_data, obj_surface,
+ xid,
+ &src_rect, &dst_rect,
+ cliprects, number_cliprects,
+ flags);
+#endif
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+}
diff --git a/src/xvba_video_x11.h b/src/xvba_video_x11.h
new file mode 100644
index 0000000..99a3498
--- /dev/null
+++ b/src/xvba_video_x11.h
@@ -0,0 +1,92 @@
+/*
+ * xvba_video_x11.h - XvBA backend for VA-API (rendering to X11 through PCOM)
+ *
+ * xvba-video (C) 2009-2011 Splitted-Desktop Systems
+ *
+ * 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
+ */
+
+#ifndef XVBA_VIDEO_X11_H
+#define XVBA_VIDEO_X11_H
+
+#include "xvba_driver.h"
+
+typedef struct object_glx_output *object_glx_output_p;
+
+typedef struct object_output object_output_t;
+struct object_output {
+ struct object_base base;
+ unsigned int refcount;
+ Drawable drawable;
+ object_glx_output_p glx;
+};
+
+// Destroy output surface
+void
+output_surface_destroy(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+) attribute_hidden;
+
+// Reference output surface
+object_output_p
+output_surface_ref(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+) attribute_hidden;
+
+// Unreference output surface
+// NOTE: this destroys the surface if refcount reaches zero
+void
+output_surface_unref(
+ xvba_driver_data_t *driver_data,
+ object_output_p obj_output
+) attribute_hidden;
+
+// Lookup output surface in the whole output heap
+object_output_p
+output_surface_lookup(
+ xvba_driver_data_t *driver_data,
+ Drawable drawable
+) attribute_hidden;
+
+// Ensure an output surface is created for the specified surface and drawable
+object_output_p
+output_surface_ensure(
+ xvba_driver_data_t *driver_data,
+ object_surface_p obj_surface,
+ Drawable drawable
+) attribute_hidden;
+
+// vaPutSurface
+VAStatus
+xvba_PutSurface(
+ VADriverContextP ctx,
+ VASurfaceID surface,
+ VADrawable draw,
+ short srcx,
+ short srcy,
+ unsigned short srcw,
+ unsigned short srch,
+ short destx,
+ short desty,
+ unsigned short destw,
+ unsigned short desth,
+ VARectangle *cliprects,
+ unsigned int number_cliprects,
+ unsigned int flags
+) attribute_hidden;
+
+#endif /* XVBA_VIDEO_X11_H */