Repository: directfb2/DirectFB2 Branch: master Commit: 7d4682d0cc09 Files: 395 Total size: 5.1 MB Directory structure: gitextract_fkdzfd_8/ ├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Kconfig ├── Make.defs ├── Makefile ├── NEWS ├── README ├── README.md ├── dfb-update-pkgconfig.in ├── include/ │ ├── dfiff.h │ ├── dfvff.h │ ├── dgiff.h │ ├── directfb.h │ ├── directfb_keyboard.h │ ├── directfb_util.h │ ├── directfb_windows.h │ ├── directfbgl.h │ ├── gen_directfb_keynames.sh │ ├── gen_directfb_strings.sh │ └── meson.build ├── inputdrivers/ │ ├── linux_input/ │ │ ├── linux_input.c │ │ └── meson.build │ └── nuttx_input/ │ └── nuttx_input.c ├── interfaces/ │ ├── ICoreResourceManager/ │ │ ├── icoreresourcemanager_default.c │ │ └── meson.build │ ├── IDirectFBFont/ │ │ ├── idirectfbfont_dgiff.c │ │ └── meson.build │ ├── IDirectFBImageProvider/ │ │ ├── idirectfbimageprovider_dfiff.c │ │ └── meson.build │ ├── IDirectFBVideoProvider/ │ │ ├── idirectfbvideoprovider_dfvff.c │ │ └── meson.build │ └── IDirectFBWindows/ │ ├── idirectfbwindows_default.c │ └── meson.build ├── lib/ │ ├── direct/ │ │ ├── atomic.h │ │ ├── clock.c │ │ ├── clock.h │ │ ├── compiler.h │ │ ├── conf.c │ │ ├── conf.h │ │ ├── debug.c │ │ ├── debug.h │ │ ├── direct.c │ │ ├── direct.h │ │ ├── direct_result.c │ │ ├── direct_result.h │ │ ├── filesystem.h │ │ ├── hash.c │ │ ├── hash.h │ │ ├── init.c │ │ ├── interface.c │ │ ├── interface.h │ │ ├── interface_implementation.h │ │ ├── list.h │ │ ├── log.c │ │ ├── log.h │ │ ├── log_domain.c │ │ ├── log_domain.h │ │ ├── map.c │ │ ├── map.h │ │ ├── mem.c │ │ ├── mem.h │ │ ├── memcpy.c │ │ ├── memcpy.h │ │ ├── meson.build │ │ ├── messages.c │ │ ├── messages.h │ │ ├── modules.c │ │ ├── modules.h │ │ ├── mutex.h │ │ ├── os/ │ │ │ ├── clock.h │ │ │ ├── filesystem.h │ │ │ ├── linux/ │ │ │ │ ├── clock.c │ │ │ │ ├── filesystem.c │ │ │ │ ├── filesystem.h │ │ │ │ ├── log.c │ │ │ │ ├── mem.c │ │ │ │ ├── mutex.c │ │ │ │ ├── mutex.h │ │ │ │ ├── signals.c │ │ │ │ ├── system.c │ │ │ │ ├── thread.c │ │ │ │ ├── thread.h │ │ │ │ ├── types.h │ │ │ │ └── waitqueue.h │ │ │ ├── log.h │ │ │ ├── mem.h │ │ │ ├── mutex.h │ │ │ ├── nuttx/ │ │ │ │ ├── clock.c │ │ │ │ ├── configs/ │ │ │ │ │ ├── sim/ │ │ │ │ │ │ └── defconfig │ │ │ │ │ └── stm32f429i-disco/ │ │ │ │ │ └── defconfig │ │ │ │ ├── filesystem.c │ │ │ │ ├── filesystem.h │ │ │ │ ├── log.c │ │ │ │ ├── mem.c │ │ │ │ ├── mutex.c │ │ │ │ ├── mutex.h │ │ │ │ ├── signals.c │ │ │ │ ├── system.c │ │ │ │ ├── thread.c │ │ │ │ ├── thread.h │ │ │ │ ├── types.h │ │ │ │ └── waitqueue.h │ │ │ ├── signals.h │ │ │ ├── system.h │ │ │ ├── thread.h │ │ │ ├── types.h │ │ │ └── waitqueue.h │ │ ├── result.c │ │ ├── result.h │ │ ├── serial.h │ │ ├── signals.h │ │ ├── stream.c │ │ ├── stream.h │ │ ├── system.c │ │ ├── system.h │ │ ├── thread.c │ │ ├── thread.h │ │ ├── trace.c │ │ ├── trace.h │ │ ├── types.h │ │ ├── utf8.h │ │ ├── util.c │ │ ├── util.h │ │ └── waitqueue.h │ └── fusion/ │ ├── arena.c │ ├── arena.h │ ├── call.c │ ├── call.h │ ├── conf.c │ ├── conf.h │ ├── fusion.c │ ├── fusion.h │ ├── fusion_internal.h │ ├── hash.c │ ├── hash.h │ ├── init.c │ ├── lock.c │ ├── lock.h │ ├── meson.build │ ├── object.c │ ├── object.h │ ├── protocol.h │ ├── reactor.c │ ├── reactor.h │ ├── ref.c │ ├── ref.h │ ├── shm/ │ │ ├── fake.c │ │ ├── heap.c │ │ ├── pool.c │ │ ├── pool.h │ │ ├── shm.c │ │ ├── shm.h │ │ └── shm_internal.h │ ├── shmalloc.c │ ├── shmalloc.h │ ├── types.h │ ├── vector.c │ └── vector.h ├── meson.build ├── meson_options.txt ├── src/ │ ├── core/ │ │ ├── CoreDFB.flux │ │ ├── CoreDFB_CallMode.h │ │ ├── CoreDFB_includes.h │ │ ├── CoreDFB_real.c │ │ ├── CoreGraphicsState.flux │ │ ├── CoreGraphicsStateClient.c │ │ ├── CoreGraphicsStateClient.h │ │ ├── CoreGraphicsState_includes.h │ │ ├── CoreGraphicsState_real.c │ │ ├── CoreInputDevice.flux │ │ ├── CoreInputDevice_includes.h │ │ ├── CoreInputDevice_real.c │ │ ├── CoreLayer.flux │ │ ├── CoreLayerContext.flux │ │ ├── CoreLayerContext_includes.h │ │ ├── CoreLayerContext_real.c │ │ ├── CoreLayerRegion.flux │ │ ├── CoreLayerRegion_includes.h │ │ ├── CoreLayerRegion_real.c │ │ ├── CoreLayer_includes.h │ │ ├── CoreLayer_real.c │ │ ├── CorePalette.flux │ │ ├── CorePalette_includes.h │ │ ├── CorePalette_real.c │ │ ├── CoreScreen.flux │ │ ├── CoreScreen_includes.h │ │ ├── CoreScreen_real.c │ │ ├── CoreSlave.flux │ │ ├── CoreSlave_includes.h │ │ ├── CoreSlave_real.c │ │ ├── CoreSurface.flux │ │ ├── CoreSurfaceAllocation.flux │ │ ├── CoreSurfaceAllocation_includes.h │ │ ├── CoreSurfaceAllocation_real.c │ │ ├── CoreSurfaceClient.flux │ │ ├── CoreSurfaceClient_includes.h │ │ ├── CoreSurfaceClient_real.c │ │ ├── CoreSurface_includes.h │ │ ├── CoreSurface_real.c │ │ ├── CoreWindow.flux │ │ ├── CoreWindowStack.flux │ │ ├── CoreWindowStack_includes.h │ │ ├── CoreWindowStack_real.c │ │ ├── CoreWindow_includes.h │ │ ├── CoreWindow_real.c │ │ ├── clipboard.c │ │ ├── clipboard.h │ │ ├── colorhash.c │ │ ├── colorhash.h │ │ ├── core.c │ │ ├── core.h │ │ ├── core_parts.c │ │ ├── core_parts.h │ │ ├── core_resourcemanager.h │ │ ├── core_system.h │ │ ├── coredefs.h │ │ ├── coretypes.h │ │ ├── cursor.h │ │ ├── fluxcomp.py │ │ ├── fonts.c │ │ ├── fonts.h │ │ ├── gfxcard.c │ │ ├── gfxcard.h │ │ ├── graphics_driver.h │ │ ├── graphics_state.c │ │ ├── graphics_state.h │ │ ├── input.c │ │ ├── input.h │ │ ├── input_driver.h │ │ ├── layer_context.c │ │ ├── layer_context.h │ │ ├── layer_control.c │ │ ├── layer_control.h │ │ ├── layer_region.c │ │ ├── layer_region.h │ │ ├── layers.c │ │ ├── layers.h │ │ ├── local_surface_pool.c │ │ ├── meson.build │ │ ├── palette.c │ │ ├── palette.h │ │ ├── prealloc_surface_pool.c │ │ ├── prealloc_surface_pool_bridge.c │ │ ├── screen.c │ │ ├── screen.h │ │ ├── screens.c │ │ ├── screens.h │ │ ├── shared_secure_surface_pool.c │ │ ├── shared_surface_pool.c │ │ ├── state.c │ │ ├── state.h │ │ ├── surface.c │ │ ├── surface.h │ │ ├── surface_allocation.c │ │ ├── surface_allocation.h │ │ ├── surface_buffer.c │ │ ├── surface_buffer.h │ │ ├── surface_client.c │ │ ├── surface_client.h │ │ ├── surface_core.c │ │ ├── surface_core.h │ │ ├── surface_pool.c │ │ ├── surface_pool.h │ │ ├── surface_pool_bridge.c │ │ ├── surface_pool_bridge.h │ │ ├── system.c │ │ ├── system.h │ │ ├── video_mode.h │ │ ├── windows.c │ │ ├── windows.h │ │ ├── windowstack.c │ │ ├── windowstack.h │ │ ├── wm.c │ │ ├── wm.h │ │ └── wm_module.h │ ├── directfb.c │ ├── directfb_result.c │ ├── directfb_result.h │ ├── display/ │ │ ├── idirectfbdisplaylayer.c │ │ ├── idirectfbdisplaylayer.h │ │ ├── idirectfbpalette.c │ │ ├── idirectfbpalette.h │ │ ├── idirectfbscreen.c │ │ ├── idirectfbscreen.h │ │ ├── idirectfbsurface.c │ │ ├── idirectfbsurface.h │ │ ├── idirectfbsurface_layer.c │ │ ├── idirectfbsurface_layer.h │ │ ├── idirectfbsurface_window.c │ │ ├── idirectfbsurface_window.h │ │ ├── idirectfbsurfaceallocation.c │ │ └── idirectfbsurfaceallocation.h │ ├── gfx/ │ │ ├── clip.c │ │ ├── clip.h │ │ ├── convert.c │ │ ├── convert.h │ │ ├── generic/ │ │ │ ├── duffs_device.h │ │ │ ├── generic.c │ │ │ ├── generic.h │ │ │ ├── generic_64.h │ │ │ ├── generic_blit.c │ │ │ ├── generic_blit.h │ │ │ ├── generic_draw_line.c │ │ │ ├── generic_draw_line.h │ │ │ ├── generic_fill_rectangle.c │ │ │ ├── generic_fill_rectangle.h │ │ │ ├── generic_mmx.h │ │ │ ├── generic_neon.h │ │ │ ├── generic_stretch_blit.c │ │ │ ├── generic_stretch_blit.h │ │ │ ├── generic_texture_triangles.c │ │ │ ├── generic_texture_triangles.h │ │ │ ├── generic_util.c │ │ │ ├── generic_util.h │ │ │ ├── stretch_hvx_16.h │ │ │ ├── stretch_hvx_32.h │ │ │ ├── stretch_hvx_8.h │ │ │ ├── stretch_hvx_88.h │ │ │ ├── stretch_hvx_N.h │ │ │ ├── stretch_up_down_16.h │ │ │ ├── stretch_up_down_32.h │ │ │ ├── stretch_up_down_8.h │ │ │ ├── stretch_up_down_88.h │ │ │ ├── stretch_up_down_table.h │ │ │ ├── template_acc_16.h │ │ │ ├── template_acc_24.h │ │ │ ├── template_acc_32.h │ │ │ ├── template_colorkey_16.h │ │ │ ├── template_colorkey_24.h │ │ │ └── template_colorkey_32.h │ │ ├── util.c │ │ └── util.h │ ├── idirectfb.c │ ├── idirectfb.h │ ├── init.c │ ├── input/ │ │ ├── idirectfbeventbuffer.c │ │ ├── idirectfbeventbuffer.h │ │ ├── idirectfbinputdevice.c │ │ └── idirectfbinputdevice.h │ ├── media/ │ │ ├── idirectfbdatabuffer.c │ │ ├── idirectfbdatabuffer.h │ │ ├── idirectfbdatabuffer_file.c │ │ ├── idirectfbdatabuffer_file.h │ │ ├── idirectfbdatabuffer_memory.c │ │ ├── idirectfbdatabuffer_memory.h │ │ ├── idirectfbdatabuffer_streamed.c │ │ ├── idirectfbdatabuffer_streamed.h │ │ ├── idirectfbfont.c │ │ ├── idirectfbfont.h │ │ ├── idirectfbimageprovider.c │ │ ├── idirectfbimageprovider.h │ │ ├── idirectfbvideoprovider.c │ │ └── idirectfbvideoprovider.h │ ├── meson.build │ ├── misc/ │ │ ├── conf.c │ │ ├── conf.h │ │ ├── gfx_util.c │ │ ├── gfx_util.h │ │ └── util.c │ └── windows/ │ ├── idirectfbwindow.c │ └── idirectfbwindow.h ├── systems/ │ ├── drmkms/ │ │ ├── drmkms_layer.c │ │ ├── drmkms_mode.c │ │ ├── drmkms_mode.h │ │ ├── drmkms_screen.c │ │ ├── drmkms_surface_pool.c │ │ ├── drmkms_system.c │ │ ├── drmkms_system.h │ │ ├── drmkms_vt.c │ │ ├── drmkms_vt.h │ │ └── meson.build │ ├── dummy/ │ │ ├── dummy.c │ │ └── meson.build │ ├── fbdev/ │ │ ├── fbdev_layer.c │ │ ├── fbdev_mode.c │ │ ├── fbdev_mode.h │ │ ├── fbdev_screen.c │ │ ├── fbdev_surface_pool.c │ │ ├── fbdev_surfacemanager.c │ │ ├── fbdev_surfacemanager.h │ │ ├── fbdev_system.c │ │ ├── fbdev_system.h │ │ ├── fbdev_vt.c │ │ ├── fbdev_vt.h │ │ └── meson.build │ └── nuttxfb/ │ ├── nuttxfb_layer.c │ ├── nuttxfb_screen.c │ ├── nuttxfb_surface_pool.c │ ├── nuttxfb_system.c │ └── nuttxfb_system.h └── wm/ └── default/ ├── default.c └── meson.build ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /build ================================================ FILE: AUTHORS ================================================ (c) Copyright 2017-2025 DirectFB2 Open Source Project (fork of DirectFB) (c) Copyright 2012-2016 DirectFB integrated media GmbH (c) Copyright 2001-2013 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH DirectFB was originally written by Denis Oliver Kropp, Andreas Shimokawa, Marek Pikarski, Sven Neumann, Ville Syrjala and Claudio Ciccani. DirectFB2 is the work of Nicolas Caramelli whose goal is to preserve and maintain DirectFB. Contributors are listed, but if you think you're missing out on this list, feel free to request to be added. Denis Oliver Kropp Andreas Shimokawa Marek Pikarski Sven Neumann Ville Syrjala Claudio Ciccani Michael Natterer Holger Waechtler Johannes Stezenbach Jiri Svoboda Hallvar Helleseth Sebastian Klemke Andreas Kotes Antonino Daplas Andreas Oberritter Martin Mueller Sebastian Ley Maurizio Monge Andreas Robinson Michael Hunold Tom Bridgwater Stefan Lucke Mike Emmel Ivan Daniluk Mark Salter Marcel Siegert Marko Makela Mark Adams Damian Kowalewski Jakub Bogusz Andy Stewart Nikita Egorov Jeff Bailey Ben Combee Daniel Laird Guillem Jover Attilio Fiandrotti Vaclav Slavik Phil Endecott Kamijo Takashi Mike Crowe Kieran Bingham Niels Roest Mandy Wu Keith Mok Guillaume Gardet Young Hoon Timothy Strelchun Andre Draszik Sorin Otescu Jacques Luder Stanislav Bezzubtsev Mike Frysinger Ilyes Gouta Tim Ross Russell Dawson Haithem Rahmani Holger Freyther Rob McConnell Daniel Schaal Bryce Poole Mike Nelis Tarik Sekmen Kazunori Kobayashi Chris Tomlinson Takanari Hayama Kui Zheng Daniel Palmer Shengwen Cheng Stephen Bird Nicolas Caramelli ================================================ FILE: COPYING ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: ChangeLog ================================================ commit 3b6508281d8c23270dde6002f1142a3906fb2da0 Author: Nicolas Caramelli Date: Sun Jun 22 19:43:02 2025 +0200 Use unsigned int for accelerator ID selecting graphics driver commit f321b9a48c657acea37b7f23fb2eb040cca49602 Merge: 77c71dc 5c81466 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Mar 15 12:12:51 2025 +0100 Merge pull request #156 from caramelli/master Don't generate .pc files for static modules when building for shared type libraries commit 5c81466de693cb180712a71b36e7ccbcc8ad43ef Author: Nicolas Caramelli Date: Sat Mar 15 12:05:34 2025 +0100 Update ChangeLog commit d83df032ec719b8d22d893e227e7d39f74e7b6f4 Author: Nicolas Caramelli Date: Sat Mar 15 12:04:19 2025 +0100 Don't generate .pc files for static modules when building for shared type libraries commit 77c71dcf072a5c7d1944073793c3030c14af049e Merge: 4d6b7dd db0c8b9 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Mar 8 23:35:58 2025 +0100 Merge pull request #155 from stefan11111/master increase maximum number of input evdev devices commit db0c8b938902b6a69772782c347b847c150a0ebc Author: stefan11111 Date: Sat Mar 8 20:30:54 2025 +0200 increase maximum number of input evdev devices commit 4d6b7ddd8477b4b52aa78ec82a3add28ade0c965 Merge: 51af532 7a9e58a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Oct 9 22:05:07 2024 +0200 Merge pull request #154 from shengwen-tw/master Check DRM plane type before attaching it as main plane commit 7a9e58ac9d2c1f610c8cafe7d3c0c6a63b33c130 Author: Shengwen Cheng Date: Wed Oct 9 00:18:36 2024 +0800 Check DRM plane type before attaching it as main plane Linux DRM allows using multiplane overlay (MPO) model for power-saving. The plane types consist of PRIMARY, CURSOR, and OVERLAY, with only the PRIMARY plane supporting operations like modesetting, flipping, etc. This commit introduces type checking for plane attachment, ensuring that DirectFB2 does not misuse other plane types as the main plane. Reference: [1] https://dri.freedesktop.org/docs/drm/gpu/amdgpu/display/mpo-overview.html commit 51af532e5c1d6c0c742092d3bc3f93770475e626 Merge: 2952d1d 97d74c9 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Sep 23 22:55:51 2024 +0200 Merge pull request #152 from kootrit/patch-1 Change SA_NOMASK to SA_NODEFER in lib/fusion/lock.c commit 97d74c98b9e133027a273fbea84bc5e64167bcd0 Author: kootrit Date: Sun Sep 22 13:15:04 2024 +0000 Change SA_NOMASK to SA_NODEFER in lib/fusion/lock.c This fixes compiling on musl. SA_NOMASK is deprecated. commit 2952d1d16b546be09e1cbb5da5e0c718d8f5ee32 Merge: 9ea1879 699ec04 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Jun 27 16:57:48 2024 +0200 Merge pull request #150 from shengwen-tw/master Alias __NR_futex with __NR_futex_time64 for RV32 platform commit 699ec0471dec73639e1d18eb4426590440c28642 Author: Shengwen Cheng Date: Thu Jun 27 21:20:10 2024 +0800 Alias __NR_futex with __NR_futex_time64 for RV32 platform Since version 5.1, Linux has dropped several RISC-V 32-bit syscalls by removing __ARCH_WANT_TIME32_SYSCALLS macro, causing the compilation of DirectFB2 to fail on RV32 platform with error of no definition of __NR_futex is declared. To resolve the issue, this commit aliases __NR_futex with __NR_futex_time64 as a fallback solution. Reference: [1] https://sourceware.org/legacy-ml/libc-alpha/2019-06/msg00557.html [2] https://git.openembedded.org/openembedded-core/tree/meta/recipes-support/boost/boost/0001-fiber-libs-Define-SYS_futex-if-it-does-not-exist.patch?h=honister commit 9ea1879446e1ccdb9a25e91e3b03d1980a0ec53e Merge: 38ad79a ed0ade2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Apr 2 22:58:16 2024 +0200 Merge pull request #146 from caramelli/master Disable shadow warnings commit ed0ade2ef88686b4b50c46310de2aa2233ebeaeb Author: Nicolas Caramelli Date: Tue Apr 2 22:51:52 2024 +0200 Disable shadow warnings commit 38ad79a4d63955fa7c3a8d307fc9d0c63de36a9b Merge: d1ed180 cf13a79 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Mar 14 16:10:52 2024 +0100 Merge pull request #145 from caramelli/master Input/NuttX: Fix build on sim board commit cf13a798e5258190109a4808bdaf93483ff2599e Author: Nicolas Caramelli Date: Thu Mar 14 16:07:20 2024 +0100 Input/NuttX: Fix build on sim board commit d1ed1801f0b8485f4ebc246fac2f280e47e11b44 Merge: 65c2707 ef1f5d5 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Dec 18 22:24:36 2023 +0100 Merge pull request #140 from caramelli/master meson: Add fluxcomp option commit ef1f5d505491c650b9d59b73f7e967a80c49e6b5 Author: Nicolas Caramelli Date: Mon Dec 18 16:16:34 2023 +0100 Update ChangeLog commit d2af10462639dfb0fb9293e358a7cc03b3b8bda9 Author: Nicolas Caramelli Date: Mon Dec 18 16:15:17 2023 +0100 meson: Add fluxcomp option commit 65c27072986793a646cb75cc2b0f5562227e1717 Merge: 16b05d0 ed8084e Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Dec 11 22:45:02 2023 +0100 Merge pull request #139 from caramelli/master Python implementation of fluxcomp commit ed8084e7fdd6054be7065e760f2607811ea7d3de Author: Nicolas Caramelli Date: Mon Dec 11 22:41:44 2023 +0100 Python implementation of fluxcomp commit 16b05d03e95032acca6aef3c527650ca94e048a5 Merge: a7a176b 26daf3f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Oct 6 19:19:51 2023 +0200 Merge pull request #138 from caramelli/master IDirectFBGL: Add SwapBuffers() commit 26daf3fc9ef84e0bbf88c09df2c075e2ac57b504 Author: Nicolas Caramelli Date: Fri Oct 6 18:48:55 2023 +0200 Update ChangeLog commit 5c5202a50e2f2ddb7d56738b290cfce5f70c42d9 Author: Nicolas Caramelli Date: Fri Oct 6 18:48:50 2023 +0200 IDirectFBGL: Add SwapBuffers() commit a7a176bb501c0730cd24bf06420ce35f53e85a15 Merge: abf3795 d1b396f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Aug 16 08:06:57 2023 +0200 Merge pull request #137 from fifteenhex/fixdrmkms-on-mstar-20230816 drmkms: Enumerate all planes when looking for the primary format commit d1b396f67827e236d734f902874ff9568ca0256b Author: Daniel Palmer Date: Tue Aug 15 20:18:17 2023 +0900 drmkms: Enumerate all planes when looking for the primary format commit abf379572bdc2271ddedea42c78a442218963d3c Merge: e4921b7 30e4afd Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Aug 12 09:25:49 2023 +0200 Merge pull request #135 from miyoo-oss/feature/screen_rot_fixes Fix screen rotation to read the proper props values commit 30e4afdd8be64cde0c73a6c9de69f64a3286e392 Author: Stephen Bird Date: Fri Aug 11 15:35:14 2023 -0700 Fix screen rotation to read the proper props values This inner loop breaks screen rotation for devices that require it and is unneccessary. commit e4921b7349329e6c1e4720adf5dec5979a31f48f Merge: c85b06b a8a327e Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Aug 6 10:44:23 2023 +0200 Merge pull request #133 from caramelli/master STM32F429I-DISCO NuttX defconfig: Use PL_MPEG video provider commit a8a327eb44cffa0f3111a05ba77e5b5f33aad534 Author: Nicolas Caramelli Date: Sun Aug 6 10:34:59 2023 +0200 STM32F429I-DISCO NuttX defconfig: Use PL_MPEG video provider commit c85b06b8fe6abc3853cf3b1be3cfa815fa09b542 Merge: 27dbab6 6077fca Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jul 17 12:53:57 2023 +0200 Merge pull request #131 from caramelli/master Add support for DirectFBGL module initialization when constructor attribute is not used (MCU targets) commit 6077fcae36d306b82f9060bd538a55b0ba38677a Author: Nicolas Caramelli Date: Mon Jul 17 12:42:56 2023 +0200 Update ChangeLog commit 22d42e25bc73daf61a612a88ff4e9c6d969aad00 Author: Nicolas Caramelli Date: Mon Jul 17 12:42:40 2023 +0200 Add support for DirectFBGL module initialization when constructor attribute is not used (MCU targets) commit 27dbab6d58662cbe7dfbb54315dcfc0b459af98f Merge: b99f492 42d7daf Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jul 3 10:55:24 2023 +0200 Merge pull request #130 from caramelli/master NuttX Input Driver: Translate raw X/Y touchscreen data into pixel coordinates commit 42d7daf26d56704326abbe73c838f44f102046fb Author: Nicolas Caramelli Date: Mon Jul 3 10:51:16 2023 +0200 NuttX Input Driver: Translate raw X/Y touchscreen data into pixel coordinates commit b99f49243bab1c8ffccd6c2401d7085c2d66caab Merge: b60149a 69f0558 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Jun 22 15:09:53 2023 +0200 Merge pull request #129 from caramelli/master NuttX defconfig: CONFIG_PTHREAD_CLEANUP => CONFIG_PTHREAD_CLEANUP_STACKSIZE commit 69f05580ecde6eae418608623229bf8645d1ea38 Author: Nicolas Caramelli Date: Thu Jun 22 15:05:57 2023 +0200 NuttX defconfig: CONFIG_PTHREAD_CLEANUP => CONFIG_PTHREAD_CLEANUP_STACKSIZE commit b60149ab11185167f03876448edb863247c8bc19 Merge: 2276c80 26fdee5 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Jun 22 08:25:07 2023 +0200 Merge pull request #128 from caramelli/master NuttX Input Driver: Add support for buttons and keyboard commit 26fdee5e4811fd2592145ae75b51c35cae998ba4 Author: Nicolas Caramelli Date: Thu Jun 22 08:20:15 2023 +0200 NuttX Input Driver: Add support for buttons and keyboard commit 2276c8096dd5effa235c0f672b212f50a5256f91 Merge: 1c65e0c 6a64478 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Jun 18 11:34:06 2023 +0200 Merge pull request #127 from caramelli/master NuttX: Add defconfig for STM32F429I-DISCO board commit 6a64478037c017cabadc64a4c7c7c719f37ce328 Author: Nicolas Caramelli Date: Sun Jun 18 11:28:29 2023 +0200 NuttX: Add defconfig for STM32F429I-DISCO board commit 1c65e0c2c668b5d59705b0d0005b8976bddde8d2 Merge: ab61370 ffe97c4 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Jun 13 05:53:49 2023 +0200 Merge pull request #126 from caramelli/master drmkms: Fix plane layers registration with multi application core commit ffe97c43f621af0946b32a40b30f4a8ae4258178 Author: Nicolas Caramelli Date: Tue Jun 13 05:41:33 2023 +0200 drmkms: Fix plane layers registration with multi application core commit ab613703de874a59be5847b5068d8791d69881d7 Merge: 62fb8e2 c1e5099 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Jun 2 08:17:17 2023 +0200 Merge pull request #125 from caramelli/master drmkms: Implement system_get_modes() / system_get_current_mode() commit c1e5099fb3d40b55118f8cb32a0313d3f8634d57 Author: Nicolas Caramelli Date: Fri Jun 2 08:03:57 2023 +0200 Update ChangeLog commit d96c8c43ae375d28d58ccc71b40e3670830f4f9a Author: Nicolas Caramelli Date: Fri Jun 2 08:03:32 2023 +0200 drmkms: Implement system_get_modes() / system_get_current_mode() commit 62fb8e283b2acff8afbb41cd365ee2c4ed3104e8 Merge: 69975b9 fc38845 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat May 27 08:27:54 2023 +0200 Merge pull request #124 from caramelli/master Add NuttX input driver module commit fc38845b7878773fa7c12e4073cbf253f2ef183d Author: Nicolas Caramelli Date: Sat May 27 08:22:26 2023 +0200 Add NuttX input driver module commit 69975b9a9e96f3f1253f5818e89b1c9e7c3e03e5 Merge: 6a1e50d 5435e13 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri May 26 14:58:14 2023 +0200 Merge pull request #123 from caramelli/master Direct/Stream: Restore RTSP support commit 5435e137d1a95674acaa656b6a7f064459b9ec09 Author: Nicolas Caramelli Date: Fri May 26 14:42:52 2023 +0200 Direct/Stream: Restore RTSP support commit 6a1e50d741ef552b36fcf73d30be2dd35cf93bc5 Merge: 223ad60 648adcd Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed May 24 19:01:26 2023 +0200 Merge pull request #122 from caramelli/master Direct/Stream: Add D_STREAM_BYPASS environment variable commit 648adcdab2a342a051608b48845ec6c267c38c0b Author: Nicolas Caramelli Date: Wed May 24 18:50:48 2023 +0200 Direct/Stream: Add D_STREAM_BYPASS environment variable commit 223ad60872f6b95c1d01bacf6e3e85e2ab360b4e Merge: 0beca0f 5b6504f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon May 22 15:50:48 2023 +0200 Merge pull request #121 from caramelli/master NuttX: Add NuttXFB System Module commit 5b6504f4ca36b1fc303de4588ec094b308d16d11 Author: Nicolas Caramelli Date: Mon May 22 15:23:36 2023 +0200 NuttX: Add NuttXFB System Module commit 0beca0f2c47a57885fcd5d910188a5961ab87d12 Merge: e3919ee 70c600a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu May 18 08:18:00 2023 +0200 Merge pull request #120 from caramelli/master dfb_scale_linear_32(): Fix premultiplication when loading a scaled image commit 70c600a530324d7cc36c82a35f22eff1dbe8fb8a Author: Nicolas Caramelli Date: Thu May 18 08:13:46 2023 +0200 dfb_scale_linear_32(): Fix premultiplication when loading a scaled image commit e3919eee1bfca09d88b2280ca06ca7fa127a6d76 Merge: 68666a6 42f6d22 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun May 14 16:26:08 2023 +0200 Merge pull request #119 from caramelli/master Direct/Stream: Add RTSP URL stub commit 42f6d220e2f33a875ec2d62605303764a2730e80 Author: Nicolas Caramelli Date: Sun May 14 16:09:08 2023 +0200 Direct/Stream: Add RTSP URL stub commit 68666a61e47f6c386f08889fa781a6b1f14e61a1 Merge: cb33e33 72698b2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat May 13 21:40:13 2023 +0200 Merge pull request #118 from caramelli/master Update to NuttX 12.1.0 commit 72698b25fef7de684374b50761c675eaaf1d5355 Author: Nicolas Caramelli Date: Sat May 13 21:33:18 2023 +0200 Update to NuttX 12.1.0 commit cb33e33cd5ccfb0d084ed13153f71501110f7784 Merge: 2692779 5879443 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed May 10 17:04:49 2023 +0200 Merge pull request #116 from caramelli/master IDirectFBFont: Fix loading from streamed data buffer commit 58794434bc29f6e5706eece867d5a614cec9aa5f Author: Nicolas Caramelli Date: Wed May 10 16:54:39 2023 +0200 Update ChangeLog commit 0f9d5265270031d4a8d03a892beef4481b6a97a4 Author: Nicolas Caramelli Date: Wed May 10 16:53:42 2023 +0200 IDirectFBFont: Fix loading from streamed data buffer commit 26927796d587aafccedceb9faf531670347448a1 Merge: 84a3131 1c4cf69 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat May 6 11:32:07 2023 +0200 Merge pull request #115 from caramelli/master Add build option for piped stream support commit 1c4cf69ab193fc8e0b59062415f1c1022aa5c406 Author: Nicolas Caramelli Date: Sat May 6 11:24:15 2023 +0200 Update ChangeLog commit 8cb3a8a67eb51b3b5b6b5eed44082bd51f522568 Author: Nicolas Caramelli Date: Sat May 6 11:24:07 2023 +0200 Add build option for piped stream support commit 84a31310821fb4af12df7651376b3bd3debd3f65 Merge: 6269d4a 646c725 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Apr 29 14:22:05 2023 +0200 Merge pull request #114 from caramelli/master DGIFF/DFIFF/DFVFF: Add support for input data located in memory or streamed commit 646c7259d6f17f71fc5de4d60e3e5a9e429b99c8 Author: Nicolas Caramelli Date: Sat Apr 29 14:11:56 2023 +0200 DGIFF/DFIFF/DFVFF: Add support for input data located in memory or streamed commit 6269d4a55d013737704997dadccdf32e07890dd4 Merge: 632cba0 d06f9b3 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Apr 16 13:04:34 2023 +0200 Merge pull request #113 from caramelli/master drmkms: Only register planes with possible_crtcs compatible with primary CRTC commit d06f9b3dc2ccfb08a1420c0c3ef30d6299325c5a Author: Nicolas Caramelli Date: Sun Apr 16 12:57:31 2023 +0200 drmkms: Only register planes with possible_crtcs compatible with primary CRTC commit 632cba05c265346cc2cd27c99b311f99526f1ce1 Merge: f0d703b fb01984 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Apr 15 14:28:02 2023 +0200 Merge pull request #112 from caramelli/master Add definition for the SCHED_SPORADIC scheduling policy commit fb0198449e57efd89d7e1b51416e5efa92088c08 Author: Nicolas Caramelli Date: Sat Apr 15 14:11:15 2023 +0200 Update ChangeLog commit 820a2146f7eb83348ad22356fb915ad1bf04d8f0 Author: Nicolas Caramelli Date: Sat Apr 15 14:10:47 2023 +0200 Add definition for the SCHED_SPORADIC scheduling policy commit f0d703b7a3aaf38b94815449cbf86e3420e20a2f Merge: 452b899 95d9fb3 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Apr 13 18:41:10 2023 +0200 Merge pull request #111 from caramelli/master Input/Linux: Initialize device_info before calling get_device_info() commit 95d9fb31694c6a5aeaedb9b6b27911b97fb92dba Author: Nicolas Caramelli Date: Thu Apr 13 18:36:44 2023 +0200 Input/Linux: Initialize device_info before calling get_device_info() commit 452b899a28fbc13710af16d6798a587bbfd51ae1 Merge: d01c4df 9bddf65 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Apr 10 12:21:58 2023 +0200 Merge pull request #109 from caramelli/master If the AR24 format is not supported, look at all formats to find a fallback format (not just the first one) commit 9bddf65c1f29b37fabf92eedd7836df96fd65391 Author: Nicolas Caramelli Date: Mon Apr 10 01:00:35 2023 +0200 If the AR24 format is not supported, look at all formats to find a fallback format (not just the first one) commit d01c4dff74bb9be5f9b66bed410befd572e401de Merge: 2f872de d11102d Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Apr 7 09:56:14 2023 +0200 Merge pull request #107 from caramelli/master Add NuttX support for running DirectFB apps on MCU devices commit d11102daba0af1f75339d9a27b3b5c9eba242884 Author: Nicolas Caramelli Date: Fri Apr 7 09:50:46 2023 +0200 Add NuttX support for running DirectFB apps on MCU devices commit 2f872de307cc9db0749122fa33286268d4e1be49 Merge: f0904fd 3d9375c Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Apr 5 22:19:09 2023 +0200 Merge pull request #106 from caramelli/master Fix -Wshadow and -Woverflow warnings when using bare metal toolchain commit 3d9375c67041849fcf37f674218b008cd08c04ce Author: Nicolas Caramelli Date: Wed Apr 5 22:13:01 2023 +0200 Update ChangeLog commit ff14133b16a0bffcc9e597cd33e8cb551f964703 Author: Nicolas Caramelli Date: Wed Apr 5 22:10:23 2023 +0200 Fix -Wshadow and -Woverflow warnings when using bare metal toolchain commit f0904fdd06c972384bd526f440823a8e95393c19 Merge: f904c12 b039561 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Apr 5 12:37:43 2023 +0200 Merge pull request #105 from caramelli/master meson: Update INSTALL instructions commit b0395614ea9213b86fde03b842132778233bf068 Author: Nicolas Caramelli Date: Wed Apr 5 13:35:05 2023 +0200 meson: Update INSTALL instructions commit f904c1206e7b729024e91d9a20bc558a85bb9e30 Merge: b4b351b 440784a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Apr 4 02:52:28 2023 +0200 Merge pull request #104 from caramelli/master Add os/signals.h commit 440784ab747a2547cab4b72f0b134ad7f30e3a5e Author: Nicolas Caramelli Date: Tue Apr 4 03:53:30 2023 +0200 Add os/signals.h commit b4b351b98f0933c509b7223afe27a9dcaa8650cd Merge: ac474a2 9af0ca5 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Apr 3 15:00:32 2023 +0200 Merge pull request #103 from caramelli/master Move signals.c to the os directory commit 9af0ca58cbefee17e0200e9f2aca582e6641f88a Author: Nicolas Caramelli Date: Mon Apr 3 16:00:19 2023 +0200 Move signals.c to the os directory commit ac474a2e9d85a5bc5ec5639f04755963c82082eb Merge: 1d310d2 c71f508 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Apr 3 11:14:49 2023 +0200 Merge pull request #102 from caramelli/master Fix warning: function declaration isn't a prototype [-Wstrict-prototypes] commit c71f508b3b58c101560a6726b94d9235cb17db98 Author: Nicolas Caramelli Date: Mon Apr 3 12:12:06 2023 +0200 Fix warning: function declaration isn't a prototype [-Wstrict-prototypes] commit 1d310d2f9a08df42c17225289029a54f144b21f4 Merge: 4a02a2b 7555132 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Apr 2 20:43:43 2023 +0200 Merge pull request #101 from caramelli/master Restore build option for network support commit 75551320d921327a536d6f22d405d8752d26de1e Author: Nicolas Caramelli Date: Sun Apr 2 20:32:14 2023 +0200 Restore build option for network support commit 4a02a2b3c418daa84a3050ba0c71cfe71ca22918 Merge: 1ac8ead 0daf53e Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Apr 1 09:59:32 2023 +0200 Merge pull request #100 from caramelli/master Add build option for constructor attribute commit 0daf53ebc8c80d67b32540d1053730d60580b01c Author: Nicolas Caramelli Date: Sat Apr 1 09:51:11 2023 +0200 Add build option for constructor attribute commit 1ac8ead8f18870f3a42cd5aa159fe0e1741d9bdd Merge: db494a2 2d69fe6 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Mar 31 22:27:39 2023 +0200 Merge pull request #99 from caramelli/master drmkms: alpha range is [0 - 65535] commit 2d69fe606ae125b476508322683124567781c190 Author: Nicolas Caramelli Date: Fri Mar 31 22:25:38 2023 +0200 drmkms: alpha range is [0 - 65535] commit db494a279fdff50f4b1480783f766e058e611767 Merge: 27037bc a83ef2c Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Mar 28 17:41:07 2023 +0200 Merge pull request #97 from caramelli/master Fix type cast when calling direct_file_seek() in file_peek() commit a83ef2c5640b93deb4a4cd0624877250933c3c27 Author: Nicolas Caramelli Date: Tue Mar 28 17:41:43 2023 +0200 Fix type cast when calling direct_file_seek() in file_peek() commit 27037bcf84dbb8f280637ba149c5f793f7231c15 Merge: 1b87ca6 85cc655 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Mar 12 10:46:51 2023 +0100 Merge pull request #96 from caramelli/master VideoProvider/DFVFF: Add support for speed multiplier below and over 1.0 commit 85cc65592a45ce9bee035130f3559360b543ed92 Author: Nicolas Caramelli Date: Sun Mar 12 10:40:41 2023 +0100 Update ChangeLog commit 318c33fbf2244b876b8067b2e3ac4f4aa62e5bfd Author: Nicolas Caramelli Date: Sun Mar 12 10:40:29 2023 +0100 VideoProvider/DFVFF: Add support for speed multiplier below and over 1.0 commit 1b87ca61d16b46a06960c1fd29428316bc87a547 Merge: ac4f10c bf501d7 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Mar 10 16:31:56 2023 +0100 Merge pull request #18 from fifteenhex/gfx_neon_20220217 Genefx: Add NEON assembly support commit bf501d779dad8ecf038e6f8ffb7377e489bca318 Merge: 2cea303 ac4f10c Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Mar 10 16:31:14 2023 +0100 Merge branch 'master' into gfx_neon_20220217 commit 2cea3031d8078fc64ee6ea7b34c9fdc36488a8a2 Author: Nicolas Caramelli Date: Fri Mar 10 16:10:53 2023 +0100 Merge ARM NEON optimization commit ac4f10ca5dcb9fb8c848fcde26a19d88cc8afd25 Merge: d1182ae f87bad2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Mar 1 03:55:09 2023 +0100 Merge pull request #92 from caramelli/master Restore global variables for DirectFB version commit f87bad231f8c6239a9ce7eb8a9b9ea6897553c1c Author: Nicolas Caramelli Date: Wed Mar 1 03:55:03 2023 +0100 Update ChangeLog commit 185a5fce4aeb8b581c0b42fc040c83c5a1b6943a Author: Nicolas Caramelli Date: Wed Mar 1 03:54:58 2023 +0100 Restore global variables for DirectFB version commit d1182aeace2fbc3877266f52cf1b640235442390 Merge: 8bea71e 70045be Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Feb 27 11:15:50 2023 +0100 Merge pull request #91 from caramelli/master dfb-update-pkgconfig: Add DESTDIR commit 70045be30a4414c45c806dbf0c88a894023210cd Author: Nicolas Caramelli Date: Mon Feb 27 10:58:34 2023 +0100 Update ChangeLog commit 5731e6d121ec20c67aecbd2d4ededc93a2565404 Author: Nicolas Caramelli Date: Mon Feb 27 10:58:28 2023 +0100 dfb-update-pkgconfig: Add DESTDIR commit 8bea71e1e5e0fe185a264b66a40bc83291fe5f06 Merge: d33e3d4 e1a7adf Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Feb 22 08:44:07 2023 +0100 Merge pull request #88 from caramelli/master Add pkg-config files per module (for static build) commit e1a7adf6e1b0107f930cfa3a5e98647a556b8715 Author: Nicolas Caramelli Date: Wed Feb 22 08:37:07 2023 +0100 Update ChangeLog commit 3e2638eb08d581d7f8bac4d34303a4859506990e Author: Nicolas Caramelli Date: Wed Feb 22 08:36:47 2023 +0100 Add pkg-config files per module (for static build) commit d33e3d40c20d3f50cb6e48882f670477068e3288 Merge: be72f1f d244ae0 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Feb 19 07:07:13 2023 +0100 Merge pull request #86 from caramelli/master drmkms: Set default pixel format using drmModePlane formats array commit d244ae07fd84d511a82066bf0b37a648534311e5 Author: Nicolas Caramelli Date: Sun Feb 19 07:06:13 2023 +0100 drmkms: Ask the kernel to expose all planes to userspace, thanks to Daniel Palmer! commit c6db97e3ee85b81e7fd3ca778664b989d42db679 Author: Nicolas Caramelli Date: Sat Feb 18 09:59:05 2023 +0100 drmkms: Set default pixel format using drmModePlane formats array if AR24 is not supported commit be72f1f0ca0fc5a6f0b42a0bb0164dad654d875e Merge: e510f61 3770869 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Feb 2 20:33:51 2023 +0100 Merge pull request #84 from caramelli/master Use Libs.private in pkg-config files corresponding to modules commit 3770869d315e1db1a4a85001f17e767863f78969 Author: Nicolas Caramelli Date: Thu Feb 2 20:29:45 2023 +0100 Use Libs.private in pkg-config files corresponding to modules commit e510f613a422a88fd3b556dc2346a0f51c18e17f Merge: b859a6a d26374d Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Feb 2 06:37:44 2023 +0100 Merge pull request #83 from caramelli/master DRMKMS/Screen: Get panel orientation on screen initialization commit d26374df50878001ea591bdf72e3bfa7765e2d15 Author: Nicolas Caramelli Date: Thu Feb 2 06:31:18 2023 +0100 Update ChangeLog commit 5e7d9f13ef93d974947391250b8edd747777f368 Author: Nicolas Caramelli Date: Thu Feb 2 06:30:58 2023 +0100 DRMKMS/Screen: Get panel orientation on screen initialization commit b859a6a2f57c72432e57df198e57b3853c11891e Merge: c17a0d9 8396440 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jan 30 11:03:13 2023 +0100 Merge pull request #82 from caramelli/master Merge dfb_types.h into directfb.h commit 8396440cc5c77e06023d5d21f197e02a0c13d052 Author: Nicolas Caramelli Date: Mon Jan 30 11:03:26 2023 +0100 Update ChangeLog commit 5670235d139e4395b5dba725a4cec75843c66b1e Author: Nicolas Caramelli Date: Mon Jan 30 11:03:11 2023 +0100 Merge dfb_types.h into directfb.h commit c17a0d9a67272420afe7677d8f03e15672839546 Merge: ef867c1 3ebe7ea Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Jan 27 18:47:57 2023 +0100 Merge pull request #81 from caramelli/master Add support for BGR24 format commit 3ebe7ea437f3d38adad9d4d1ee3fd9b706da08dc Author: Nicolas Caramelli Date: Fri Jan 27 18:47:19 2023 +0100 Update ChangeLog commit 0da4139930f6d644e4001c62ad7a25aa1b4f8378 Author: Nicolas Caramelli Date: Fri Jan 27 18:47:05 2023 +0100 Add support for BGR24 format commit ef867c10dc63f8f734d9aa8c7f17396e9dc1838a Merge: b80fbc8 d14c65f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jan 16 14:28:25 2023 +0100 Merge pull request #80 from caramelli/master Meson: Fix debug buildtype commit d14c65fa1b4d7e79e1576dde682049730f316a4e Author: Nicolas Caramelli Date: Mon Jan 16 14:21:04 2023 +0100 Meson: Fix debug buildtype commit b80fbc8cdb98839108676ae9cc24fabdec3b34b5 Merge: 68367a4 acae2dc Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Jan 14 03:16:33 2023 +0100 Merge pull request #79 from caramelli/master Add check for state->source in dfb_gfxcard_state_check_acquire() commit acae2dc598e5f41397e0e69844758870ace7bd53 Author: Nicolas Caramelli Date: Sat Jan 14 03:15:44 2023 +0100 Core/GfxState: Add check for state->source in dfb_gfxcard_state_check_acquire() commit 68367a48c745630e3180437405ec3e2975036c78 Merge: cd4172c 5be9975 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Jan 7 08:18:47 2023 +0100 Merge pull request #78 from caramelli/master Core/Screen: Add screen_data argument for GetScreenRotation() function commit 5be99757310e92e2922f10162f74ed2e51b9c789 Author: Nicolas Caramelli Date: Sat Jan 7 08:17:31 2023 +0100 Update ChangeLog commit c3742ae6cae0efa30e4ecd53c70d1c3b52c0b676 Author: Nicolas Caramelli Date: Sat Jan 7 08:17:23 2023 +0100 Core/Screen: Add screen_data argument for GetScreenRotation() function commit cd4172c5c38ccfd11caaa53cbc33acb7724b55b4 Merge: bf85d08 47b5604 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jan 2 10:47:38 2023 +0100 Merge pull request #76 from caramelli/master Meson: Use install_symlink() function instead of meson_symlink.sh script commit 47b5604a830d1bab9abf2c881717aee6b0c8f552 Author: Nicolas Caramelli Date: Mon Jan 2 10:34:16 2023 +0100 Update ChangeLog commit 9bdd8911aed12a5b6a293aded3d3c54c27ccc7cb Author: Nicolas Caramelli Date: Mon Jan 2 10:33:47 2023 +0100 Meson: Use install_symlink() function instead of meson_symlink.sh script commit bf85d083d07ffca28361235c6c10caf73961776e Merge: d942ae0 487211f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Dec 29 16:42:08 2022 +0100 Merge pull request #75 from caramelli/master Fix loop initial declarations (due to removal of -std=gnu99 option) commit 487211ffd4b4a13bc59a1b5f658908835619da28 Author: Nicolas Caramelli Date: Thu Dec 29 16:42:29 2022 +0100 Fix loop initial declarations (due to removal of -std=gnu99 option) commit d942ae051557c7aae03b65f4b1e14dd7ddde0223 Merge: 1278837 36f78a5 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Dec 28 19:55:37 2022 +0100 Merge pull request #73 from fifteenhex/drmkmsrotsupport-20221227 WorkInProgress: Allow DRM/KMS orientation to configure the rotation commit 36f78a5dca1ac9d48a341cf4b5a201a7e40a9a30 Author: Nicolas Caramelli Date: Wed Dec 28 19:55:51 2022 +0100 Allow DRM/KMS orientation to configure the rotation commit 76ae5f3c50fd06b94c5ca56565769b4ca71b8eb7 Author: Daniel Palmer Date: Fri Nov 11 21:47:05 2022 +0900 system: drmkms: Probe for panel rotation On some embedded systems the LCD panel is mounted in the chassis upside down. To render the image correctly it needs to be rotated in userspace. The kernel part of DRM/KMS exposes the panel orientation via a connector property. So grab the orientation for the panel from the kernel and present that as the screen rotation so that the image is flipped when blitted. commit 16cc14cf28dc5cfc75cb29456f4e443495e7f2a3 Author: Daniel Palmer Date: Sun Feb 20 11:39:10 2022 +0900 core: layer: Get the physical rotation from the system For drmkms the physical orientation of the display can be probed so it is possible to automatically correct for a rotated display. If the user hasn't set the rotation in their config ask the system what the rotation should be. commit 5525df479e8ced0287e7c3b325bc3c4dc7b69c13 Author: Daniel Palmer Date: Sat Feb 19 11:02:57 2022 +0900 conf: Add flag for whether the rotation was configured or not. If the user specified a rotation the value could be 0,90,180 or 270. If they didn't specify anything it will be 0. Currently it's not possible to tell if they asked for 0 or it's just the default. If the value is 0 but the user didn't set it we should ask the system what it thinks the rotation is (i.e. the panel orientation from DRM/KMS). So a flag is needed to tell if the 0 came from the user. Add a flag for whether the rotation was user set. commit 1278837fafc6d85d3a4dd316d848b5bb7dd19ec6 Merge: 0fdf5df 7da29a8 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Dec 20 13:22:23 2022 +0100 Merge pull request #71 from caramelli/master fusion: Install shm/pool.h header file commit 7da29a843e2a765f53c87874c7ffdc37a2312f51 Author: Nicolas Caramelli Date: Tue Dec 20 13:19:21 2022 +0100 fusion: Install shm/pool.h header file commit 0fdf5df3995bbcb4d2e06fd5d2b979651bc60f0c Merge: 7fd8c8e 5bd77be Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Dec 12 17:27:35 2022 +0100 Merge pull request #69 from caramelli/master Move shutdown-info parameter definition to fusion config commit 5bd77be2daf48c36a22d6fccf1f8e6970705e1d1 Author: Nicolas Caramelli Date: Mon Dec 12 17:27:09 2022 +0100 Update ChangeLog commit 1e4c97c588121b3c814b108a26a356d977a946a6 Author: Nicolas Caramelli Date: Mon Dec 12 17:26:49 2022 +0100 Move shutdown-info parameter definition to fusion config commit 7fd8c8ef0492711667e668a73c2cc336636a97b4 Merge: 96a680d 4388a63 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Dec 3 08:07:36 2022 +0100 Merge pull request #68 from caramelli/master Move tools to DirectFB2-tools repository (for static library support) commit 4388a633a043f34f3b12fdb6aa329d4ea800c45a Author: Nicolas Caramelli Date: Sat Dec 3 07:25:42 2022 +0100 Update ChangeLog commit 5ff1a698b3d5607c089b50910fa73138f98e4ec9 Author: Nicolas Caramelli Date: Sat Dec 3 07:25:11 2022 +0100 Move tools to DirectFB2-tools repository (for static library support) commit 96a680da988cf3466f5106b943bc9739b2199fa9 Merge: 2519295 4db5565 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Nov 30 17:59:49 2022 +0100 Merge pull request #67 from caramelli/master Add DIRECT_DEALLOCATE_INTERFACE() calls on error commit 4db5565d6ec9e5c5c06fe528bf111209bf11a112 Author: Nicolas Caramelli Date: Wed Nov 30 17:52:13 2022 +0100 Add DIRECT_DEALLOCATE_INTERFACE() calls on error commit 2519295bc91765c1fc036d6ee206f163f7509c37 Merge: ab42607 896141d Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Nov 19 10:33:09 2022 +0100 Merge pull request #65 from caramelli/master IDirectFBSurface: Set flip_func to control the triggering of the actual Flip commit 896141dcd2ccb610c6aedad904dc1602ba9289f4 Author: Nicolas Caramelli Date: Sat Nov 19 10:33:03 2022 +0100 Update ChangeLog commit 64471d3ce80ff3f948e02d809c51247a50e058ca Author: Nicolas Caramelli Date: Sat Nov 19 10:32:50 2022 +0100 IDirectFBSurface: Set flip_func to control the triggering of the actual Flip commit ab426077fe6c9dbfa8b0dfe95b7789d15172a159 Merge: 1989def ee6ffd6 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Nov 14 12:20:31 2022 +0100 Merge pull request #64 from caramelli/master drmkms: Unused PoolData commit ee6ffd6e8ff0d09cd886e7abbcc2dc26a0c06873 Author: Nicolas Caramelli Date: Mon Nov 14 12:00:12 2022 +0100 drmkms: Unused PoolData commit 1989def37e4768782f98f57ba60be5f4b9d53f69 Merge: e2814bb 3310069 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Nov 10 12:11:25 2022 +0100 Merge pull request #63 from caramelli/master tools: Add dfiffinfo commit 331006993b9d711fe88e74a82013e1debbddcb90 Author: Nicolas Caramelli Date: Thu Nov 10 11:41:08 2022 +0100 Update ChangeLog commit 27d02177ae28cec5f8ea1e9afff402298c83d9f7 Author: Nicolas Caramelli Date: Thu Nov 10 11:40:56 2022 +0100 tools: Add dfiffinfo commit e2814bb5c8b21072896026c3d8c318e4697ac4db Merge: 634b1a2 b781bc9 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Nov 7 21:17:53 2022 +0100 Merge pull request #62 from caramelli/master IDirectFB: Add GetFontSurfaceFormat() commit b781bc98cbf1587a1a14110416750c6cc39d99c9 Author: Nicolas Caramelli Date: Mon Nov 7 19:57:32 2022 +0100 Update ChangeLog commit 76fa4a7639c60fbddaf295fdef0aa97079128fe7 Author: Nicolas Caramelli Date: Mon Nov 7 19:57:00 2022 +0100 IDirectFB: Add GetFontSurfaceFormat() commit 634b1a25488bc8a64b7026416712ebf99f66b91f Merge: ae9393d 54efecd Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Oct 27 03:46:51 2022 +0200 Merge pull request #60 from caramelli/master Core/Main: Call fusion_hash_set_autofree() commit 54efecd8acae0e6828f75c7ea8b1e2f128e2919d Author: Nicolas Caramelli Date: Thu Oct 27 03:38:15 2022 +0200 Update ChangeLog commit fb7411f36a7bbc0af99089a9dc179fffe30b0c29 Author: Nicolas Caramelli Date: Thu Oct 27 03:38:00 2022 +0200 Core/Main: Call fusion_hash_set_autofree() commit ae9393d2d756a7a6907da5ec481e2b3e4e91efb0 Merge: 85ee588 0659ed2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Oct 26 10:33:49 2022 +0200 Merge pull request #59 from caramelli/master Fusion: Fix memory leak and destroy event_dispatcher_thread on exit commit 0659ed23c1d3bd86e06b70cdc1680d1c1e8de88e Author: Nicolas Caramelli Date: Wed Oct 26 09:51:13 2022 +0200 Fusion: Fix memory leak and destroy event_dispatcher_thread on exit commit 85ee588f636d4836bdf7c1d0db47b74d4ec3827d Merge: 3e0a706 d2a158a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Oct 24 18:50:13 2022 +0200 Merge pull request #58 from caramelli/master Add musl libc compatibility commit d2a158a3a89910e99f50e6ff8f073a457dcfcea0 Author: Nicolas Caramelli Date: Mon Oct 24 18:46:49 2022 +0200 Add musl libc compatibility commit 3e0a706978538a2e2050a2745edb6ad0c30ad39c Merge: 651ac43 cb3fb64 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Oct 22 15:59:59 2022 +0200 Merge pull request #56 from caramelli/master Input/Linux: Uninitialised value was created by a stack allocation commit cb3fb6487b6b8e5b66a9c1cb7a08673d50d49cc4 Author: Nicolas Caramelli Date: Sat Oct 22 15:59:16 2022 +0200 Input/Linux: Uninitialised value was created by a stack allocation commit 651ac43bbb8daf812b410a66736a0ce457b00498 Merge: 3392959 857032f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Oct 17 17:57:33 2022 +0200 Merge pull request #55 from caramelli/master Meson: Add the boolean check kwarg to the run_command() call commit 857032f9a16800f352cead58a1958965231c5ff7 Author: Nicolas Caramelli Date: Mon Oct 17 17:47:12 2022 +0200 Meson: Add the boolean check kwarg to the run_command() call commit 339295980e9a0eeda55641dd35691942512bc70b Merge: 9a2d1bf 00c3612 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Oct 8 02:45:31 2022 +0200 Merge pull request #54 from caramelli/master Add support for static libraries (MCU targets) commit 00c361275f506b798f06ff0979b6fa0ec89e1a80 Author: Nicolas Caramelli Date: Sat Oct 8 02:45:07 2022 +0200 Update ChangeLog commit 821cffd5f7102eaa5bf75da1190e0670293e50a9 Author: Nicolas Caramelli Date: Sat Oct 8 02:44:17 2022 +0200 Add support for static libraries (MCU targets) commit 9a2d1bf1beb2c8d8c8bf1ca5154a19acffe2f4f8 Merge: 1989eb1 c61ab74 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Sep 29 17:49:11 2022 +0200 Merge pull request #53 from caramelli/master Add support for BT.2020 conversion commit c61ab74f402dab12de791a69d40fe8cae2a399bc Author: Nicolas Caramelli Date: Thu Sep 29 17:49:33 2022 +0200 Update ChangeLog commit 9328df9ddd34e097606b47776a94b73c947fb417 Author: Nicolas Caramelli Date: Thu Sep 29 17:49:25 2022 +0200 Add support for BT.2020 conversion commit 1989eb1c12b329cb618c3c7669d6bfc29f9480d9 Merge: 4b49dda 0bd4a4f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Sep 28 21:38:41 2022 +0200 Merge pull request #52 from caramelli/master Direct/Interface: Ignore character case for 'default-interface-implementation' option commit 0bd4a4f14ba57a27cfbd2767eaa1329405aaa574 Author: Nicolas Caramelli Date: Wed Sep 28 21:08:59 2022 +0200 Update ChangeLog commit a31867801de215e6f92c0fbaf1f192d454784846 Author: Nicolas Caramelli Date: Wed Sep 28 21:08:37 2022 +0200 Direct/Interface: Ignore character case for 'default-interface-implementation' option commit 4b49dda3e337774f04ff77773afadcb409610f94 Merge: 4260493 e613839 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Sep 24 11:36:15 2022 +0200 Merge pull request #51 from caramelli/master Add dfb_colorspace_parse() commit e613839786d0e9e48828f50bd1a3e06e887f4ac1 Author: Nicolas Caramelli Date: Sat Sep 24 11:24:38 2022 +0200 Update ChangeLog commit 58b530ab60abe2fe5b7ba32a7f9fa9fc80d5efdb Author: Nicolas Caramelli Date: Sat Sep 24 11:24:08 2022 +0200 Add dfb_colorspace_parse() commit 4260493757d59f0fe750fa6ade2397247bcf1dce Merge: 002b6f3 9de9d06 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Sep 16 08:57:22 2022 +0200 Merge pull request #50 from caramelli/master Direct/Stream: Add file_wait() commit 9de9d06d1a7f58ab5eb468373cb10a3dba566f93 Author: Nicolas Caramelli Date: Fri Sep 16 08:24:15 2022 +0200 Update ChangeLog commit 1694795f34e698b7544f86d688fcec6613666ab4 Author: Nicolas Caramelli Date: Fri Sep 16 08:24:03 2022 +0200 Direct/Stream: Add file_wait() commit 002b6f331a2b202359d601fc4c3425b7e9307449 Merge: ad438fc fc9ce01 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Sep 15 10:11:30 2022 +0200 Merge pull request #49 from caramelli/master Add support for BT.709 conversion commit fc9ce013b85b514843a6962140ab668a55d4af70 Author: Nicolas Caramelli Date: Thu Sep 15 10:11:17 2022 +0200 Update ChangeLog commit 0d188b62f3519fcdd1ee100bc992414d60dfaff6 Author: Nicolas Caramelli Date: Thu Sep 15 10:11:04 2022 +0200 Add support for BT.709 conversion commit ad438fce3601e86658e72e4f795bec187014ef4f Merge: 4bfa300 46ee720 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Sep 7 12:55:18 2022 +0200 Merge pull request #48 from caramelli/master Add support for NV24 and NV42 video format commit 46ee7207cf3678fea84f2ea96dbc58842069b5fc Author: Nicolas Caramelli Date: Wed Sep 7 12:45:53 2022 +0200 Update ChangeLog commit ccd58c3e9c96f964a01f9c4937381c6ce6cad54c Author: Nicolas Caramelli Date: Wed Sep 7 12:45:35 2022 +0200 Add support for NV24 and NV42 video format commit 4bfa300a8f25334d29815cca44d594382b7b2c2e Merge: 0c0a38c 16623ff Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Sep 5 11:21:07 2022 +0200 Merge pull request #47 from caramelli/master Font/DGIFF: return DFB_INVARG if height not set in font description commit 16623ff93089d404505d9279d3247c27a0611a0c Author: Nicolas Caramelli Date: Mon Sep 5 11:16:18 2022 +0200 Update ChangeLog commit 80f94b0867308ce373a1c4ffd2dbc33d300adf34 Author: Nicolas Caramelli Date: Mon Sep 5 11:16:03 2022 +0200 Font/DGIFF: return DFB_INVARG if height not set in font description commit 0c0a38cd0dc67a8fb254b1ca7ff4913222d038b8 Merge: 0b9984b 396d28e Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Sep 1 09:00:50 2022 +0200 Merge pull request #46 from caramelli/master Add support for YVU 4:4:4 planar format commit 396d28e145e0f205718861e4d4ee5376319d80dc Author: Nicolas Caramelli Date: Thu Sep 1 08:58:36 2022 +0200 Update ChangeLog commit badf1d0b52ea7e6d39070dcd68c968dd0ed9f5fa Author: Nicolas Caramelli Date: Thu Sep 1 08:58:29 2022 +0200 Add support for YVU 4:4:4 planar format commit 0b9984b5d680d48422badff6f36f3439c806d3f4 Merge: eb7ab25 dea029a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Aug 24 13:38:14 2022 +0200 Merge pull request #45 from caramelli/master Add support for YUV 4:2:2 planar format commit dea029adcb4daf103956aa73ebd32c57db400596 Author: Nicolas Caramelli Date: Wed Aug 24 13:08:55 2022 +0200 Update ChangeLog commit a7bcf7475493700e166f44ed5307105eabc0676e Author: Nicolas Caramelli Date: Wed Aug 24 13:04:37 2022 +0200 Add support for YUV 4:2:2 planar format commit eb7ab25c193f90743553e6e09724756723348038 Merge: c750bb9 1d99b8a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Aug 21 11:09:20 2022 +0200 Merge pull request #44 from caramelli/master drmkms: Remove libkms dependency commit 1d99b8a946dfbb4ed6011380448738a78fb49272 Author: Nicolas Caramelli Date: Sun Aug 21 10:56:22 2022 +0200 Update ChangeLog commit 958aab760292281eff4ca41d3de11a8581fa45ef Author: Nicolas Caramelli Date: Sun Aug 21 10:08:11 2022 +0200 drmkms: Remove libkms dependency commit c750bb98c76191e8149e501db3d408175983d30a Merge: 33c7613 2690e4b Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Aug 14 09:11:37 2022 +0200 Merge pull request #43 from caramelli/master Core_Resource_AddIdentity(): if (call_owner != fusion_id), return DFB_FAILURE commit 2690e4bfcca798b6f183a07cbe038b4b4f105c34 Author: Nicolas Caramelli Date: Sun Aug 14 09:10:10 2022 +0200 Core_Resource_AddIdentity(): if (call_owner != fusion_id), return DFB_FAILURE commit 33c7613704c0055019d6085dbddcd5b972fb1c9f Merge: e629f8b 402acc7 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Aug 11 07:16:42 2022 +0200 Merge pull request #41 from caramelli/master Core/LayerContext: Add dfb_layer_context_set_cursor_shape() and dfb_layer_context_get_cursor_shape() commit 402acc7c68497321ad732d4c8594df63bb7f30e2 Author: Nicolas Caramelli Date: Thu Aug 11 07:10:26 2022 +0200 Update ChangeLog commit 5c309b21c5094d540f3835d37ee17f3dff8cfe68 Author: Nicolas Caramelli Date: Thu Aug 11 07:10:17 2022 +0200 Core/LayerContext: Add dfb_layer_context_set_cursor_shape() and dfb_layer_context_get_cursor_shape() commit e629f8baefc649b0488846992ffea1f9b442676b Merge: 61ceb79 462e44a Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Aug 9 03:55:00 2022 +0200 Merge pull request #40 from caramelli/master IDirectFBWindow: by default the cursor surface is not set => cursor_flags = DWCF_INVISIBLE commit 462e44a28259d2ca2947142486cf5ce51cde2ed5 Author: Nicolas Caramelli Date: Tue Aug 9 03:10:42 2022 +0200 Update ChangeLog commit db66ecd667499014531a3a553c1c5d93acc9b414 Author: Nicolas Caramelli Date: Tue Aug 9 03:09:24 2022 +0200 IDirectFBWindow: by default the cursor surface is not set => cursor_flags = DWCF_INVISIBLE commit 61ceb79564a81905c5521018892c5816e9d9a4af Merge: 4a08b68 5dab035 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Aug 5 09:28:21 2022 +0200 Merge pull request #39 from caramelli/master IDirectFBDisplayLayer: SetCursorShape() accept NULL for shape to restore default cursor commit 5dab03540a293328363f6484a0170d37468cffcd Author: Nicolas Caramelli Date: Fri Aug 5 09:27:45 2022 +0200 Update ChangeLog commit b603d612311b99c55ef94d732b5048e74dc1dde8 Author: Nicolas Caramelli Date: Fri Aug 5 09:27:37 2022 +0200 IDirectFBDisplayLayer: SetCursorShape() accept NULL for shape to restore default cursor commit 4a08b6867fb69a5850bda36f3362591dbe632f8a Merge: 0377501 04f63f2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Aug 4 16:43:22 2022 +0200 Merge pull request #38 from caramelli/master Core/WindowStack: unused CoreDFB object in dfb_windowstack_cursor_enable() commit 04f63f29661b63385fff8f4b5dad010b7f74a674 Author: Nicolas Caramelli Date: Thu Aug 4 16:11:48 2022 +0200 Update ChangeLog commit 2c23979f3e978567fbc210af941d943fd91d3d6c Author: Nicolas Caramelli Date: Thu Aug 4 16:10:24 2022 +0200 Core/WindowStack: unused CoreDFB object in dfb_windowstack_cursor_enable() commit 0377501c0eb71f6d96342b57a63bfe41b6d8e663 Merge: 39c7500 1d5a410 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Jul 17 11:45:10 2022 +0200 Merge pull request #37 from caramelli/master IDirectFBInputDevice: unused buttonmask, locks, modifiers... commit 1d5a4109ce66101ca6d3e55c1fde2b23ec69dde8 Author: Nicolas Caramelli Date: Sun Jul 17 11:43:12 2022 +0200 IDirectFBInputDevice: unused buttonmask, locks, modifiers... commit 39c75006b18de38e845ffbec66856ddc18c23136 Merge: 7c956f6 e2c1690 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Jun 26 07:49:54 2022 +0200 Merge pull request #36 from caramelli/master WM/Default: Set the shape of the cursor bound to a window commit e2c16907872af39a4ce53c4bce1318d563772caa Author: Nicolas Caramelli Date: Sun Jun 26 07:42:30 2022 +0200 WM/Default: Set the shape of the cursor bound to a window commit 7c956f69fc624616e3f3a4b0e95dc82bf865cb79 Merge: 23cf9e4 508fc28 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Jun 24 18:45:11 2022 +0200 Merge pull request #35 from caramelli/master Restore dfb_clip_edges() as a public function commit 508fc2822a14b43ae660beb4a209e9a24f6ecc64 Author: Nicolas Caramelli Date: Fri Jun 24 18:43:14 2022 +0200 Restore dfb_clip_edges() as a public function commit 23cf9e4e0016c6ff0cb2c3edf0b8a77857a827d0 Merge: 45da19c fafb9ad Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Jun 2 15:12:22 2022 +0200 Merge pull request #33 from caramelli/master Add DSI to DFBScreenEncoderDescription commit fafb9adbc80b5dae6ca0e92f29002d1ff46e643d Author: Nicolas Caramelli Date: Thu Jun 2 15:08:30 2022 +0200 Update ChangeLog commit 9439817cec072630c900eaf4dfbebfea82634c10 Author: Nicolas Caramelli Date: Thu Jun 2 15:08:23 2022 +0200 Add DSI to DFBScreenEncoderDescription commit 45da19c04a67004f0228ad59b68b7975ca821dc9 Merge: e019fbd f91877e Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Jun 1 12:41:38 2022 +0200 Merge pull request #32 from caramelli/master Add support for multi-touch input device commit f91877ed968907248c64e06aa9e9640bc0c3a4e2 Author: Nicolas Caramelli Date: Wed Jun 1 11:41:15 2022 +0200 Update ChangeLog commit 6d8293dc6d4684e77c9aef4bae2898354b85dd23 Author: Nicolas Caramelli Date: Wed Jun 1 11:40:36 2022 +0200 Add support for multi-touch input device commit e019fbd1be6683f608d861472e7f43caaede6a3b Merge: 2537495 bbf1c7b Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat May 14 12:28:55 2022 +0200 Merge pull request #31 from caramelli/master Core/Layers: Increase the maximum number of layers commit bbf1c7b4adb4b87f31675efbb6676e9bdd1ceb26 Author: Nicolas Caramelli Date: Sat May 14 12:27:36 2022 +0200 Update ChangeLog commit 7b7443a96e050fcf62bf0f8c2ebedd0aba81c4b3 Author: Nicolas Caramelli Date: Sat May 14 12:27:23 2022 +0200 Core/Layers: Increase the maximum number of layers commit 2537495e4fc014168b9249dd367e6d954327aea3 Merge: 00aeac6 b7e82e1 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed May 11 09:56:46 2022 +0200 Merge pull request #30 from caramelli/master Fix issue with preallocated surfaces when application is slave commit b7e82e1ae52992b7207b1ef6ac8326253ac42b75 Author: Nicolas Caramelli Date: Wed May 11 09:55:25 2022 +0200 Update ChangeLog commit 6e0a7e205fafe9f8b409e57b28f8390d05ed2945 Author: Nicolas Caramelli Date: Wed May 11 09:55:01 2022 +0200 Fix issue with preallocated surfaces when application is slave commit 00aeac631fca9a206270740ad166349b321feb90 Merge: 98d4278 c75e202 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue May 3 17:31:49 2022 +0200 Merge pull request #29 from caramelli/master DFVFF: Add missing DIRECT_DEALLOCATE_INTERFACE( thiz ) commit c75e20207b9044f671c45829ce1ebd76b9fee790 Author: Nicolas Caramelli Date: Tue May 3 17:30:29 2022 +0200 Update ChangeLog commit 92f23cc01a45183d7022c97fbc2c66baea0b748a Author: Nicolas Caramelli Date: Tue May 3 17:30:02 2022 +0200 DFVFF: Add missing DIRECT_DEALLOCATE_INTERFACE( thiz ) commit 98d4278476ccaa7a787721cec30e503c23f84bf2 Merge: 35a7c6b 291ace5 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun May 1 09:31:40 2022 +0200 Merge pull request #28 from caramelli/master Fix uninitialised byte(s) commit 291ace5a7fa6f0dc67ed37683513044331702be1 Author: Nicolas Caramelli Date: Sun May 1 09:30:52 2022 +0200 Fix uninitialised byte(s) commit 35a7c6ba5300582218d323eca562ffc7d5537335 Merge: 19049c5 5d32b0b Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sat Apr 30 14:25:32 2022 +0200 Merge pull request #27 from caramelli/master drmkms: Management of connectors not bound to an encoder commit 5d32b0b88a0bd0be7d29d851ebffb48db31dccb1 Author: Nicolas Caramelli Date: Sat Apr 30 14:23:36 2022 +0200 drmkms: Management of connectors not bound to an encoder commit 19049c5d29210551d8626d30c307ce140573db30 Merge: 1f2a613 34b8225 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Apr 29 18:41:00 2022 +0200 Merge pull request #26 from caramelli/master Add -lrt for compatibility with old glibc commit 34b8225b7c75074a87c50adef1ceb4a29a384fee Author: Nicolas Caramelli Date: Fri Apr 29 18:37:46 2022 +0200 Add -lrt for compatibility with old glibc commit 1f2a613206dc1ddd7ed301f79468d5b3397ea11f Merge: d90c877 724b2f2 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Apr 28 18:14:17 2022 +0200 Merge pull request #25 from caramelli/master Fix palette index check in InitLayers() commit 724b2f259d5871485ec12aee5a5977303317c560 Author: Nicolas Caramelli Date: Thu Apr 28 18:12:00 2022 +0200 Fix palette index check in InitLayers() commit d90c8770e1b844fcd4698592a2281b5a749ddce7 Merge: 6b74bc4 3a428e9 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Thu Apr 28 14:18:15 2022 +0200 Merge pull request #24 from caramelli/master readdir_r() is deprecated commit 3a428e985c2320b989921b1d5b0aaa846d8fe04f Author: Nicolas Caramelli Date: Thu Apr 28 14:18:22 2022 +0200 readdir_r() is deprecated commit 6b74bc443cdcc1c1127581bbc1b02ed1fec16bf7 Merge: 9d0781a 0505492 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Mar 30 19:13:40 2022 +0200 Merge pull request #22 from caramelli/master Fix SYSCONFDIR commit 0505492baf1b3abb4b2e08c07118a3c1d5161ec5 Author: Nicolas Caramelli Date: Wed Mar 30 19:09:28 2022 +0200 Update ChangeLog commit 7ac237d1be6517acbc97b03dc85aa775e12dd484 Author: Nicolas Caramelli Date: Wed Mar 30 19:08:00 2022 +0200 Fix SYSCONFDIR commit 9d0781a02e700e09bc7e7ae5fa4ffa1050950e28 Author: Nicolas Caramelli Date: Mon Feb 28 20:00:45 2022 +0100 build: Fix issues with build order and directfb_strings commit 9406153d9dc1cdda12146afdd63e3fd0330b587b Author: Daniel Palmer Date: Sun Feb 27 12:56:12 2022 +0900 build: Fix issues with build order and directfb_strings The header generated by directfb_strings is used in other places. If the build is done in parallel and directfb_strings hasn't completed yet the build will fail. Add directfb_strings as an input to the places that need it so that it always happens before it's needed. commit 4d1418f50f039cd18363fe58a6b75393eca93316 Author: Daniel Palmer Date: Thu Feb 17 22:25:42 2022 +0900 gfx: generic: Add NEON assembly support At some point Linaro added NEON assembly for generic graphics. It looks like it never got upstreamed. This pulls in their assembly and wires it in the same way MMX assembly is. Link: https://blueprints.launchpad.net/linaro-multimedia-project/+spec/engr-multimedia-directfb-neon-optimization commit 30e3ebe19e9b94a9fedba565fa2b55de30f98cbc Merge: c3aa9c0 9f6b8f4 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Feb 14 11:13:38 2022 +0100 Merge pull request #17 from fifteenhex/valgrindfixes_20220214 core: core: Fix use after free when calling fusion_shm_pool_destroy() commit 9f6b8f45d2ac4bb6dcd15c3d0d6db1fe356aea4d Author: Daniel Palmer Date: Mon Feb 14 18:06:15 2022 +0900 core: core: Fix use after free when calling fusion_shm_pool_destroy() fusion_shm_pool_destory() is called with shared->shmpool as it's second argument but shared has just been freed in the in previous line. Pull shared->shmpool out into a local variable and use that instead. commit c3aa9c056209349dee935d69f2ca9b593687bcea Merge: 1209d65 c51e925 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Sun Feb 13 22:50:06 2022 +0100 Merge pull request #16 from fifteenhex/valgrind_fixes_20220213 Valgrind fixes 20220213 commit c51e9255f05f599a2b5e8a0b2c62beeebdee8d56 Author: Daniel Palmer Date: Sat Feb 12 22:55:32 2022 +0900 input: linux: Initialise input event in set_led() Not all the fields in the struct are initialised so the struct should be allocated with initialisation. commit bf5d6d23050bb15d3d81a50d86b128d1de54e70f Author: Daniel Palmer Date: Sat Feb 12 21:08:47 2022 +0900 system: drmkms: vt: Initialise vt_mode struct. Not all of the fields in vt_mode struct are filled so we will be passing uninitilised data unless we ask for it to be zero initialised. commit 1209d657c2534c6175477177cf3ef5fdb0c33634 Merge: b3e66e4 75d2237 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Fri Feb 11 14:14:32 2022 +0100 Merge pull request #14 from fifteenhex/valgrind_fixes Valgrind splat fixes commit 75d2237fccf638ece90919e3aba393a701f4ebc0 Author: Daniel Palmer Date: Fri Feb 11 11:28:09 2022 +0900 libdirect: signals: Use mark/sweep to free signal handlers Valgrind is complaining a lot about handlers being accessed after they have been freed. To make this easier to debug refactor freeing the actually memory into a single location and change the remove function to just mark the handler as dead. commit 270cd1b150e71d8d3d8f82c676db8915fdcc9cf5 Author: Daniel Palmer Date: Fri Feb 11 10:38:44 2022 +0900 libdirect: os: linux: thread: Fix passing of null pointer to prctl prctl(PR_GET_NAME, arg2, ...) expects a pointer to a 16 byte buffer in arg2. Currently the code is checking if thread->name is null and then calling prctl(PR_GET_NAME, thread->name, ...) if it is. This results in a null pointer always being passed to prctl(). Put a 16 byte buffer on the stack, pass that to prctl() if thread->name is null, then copy the result into thread->name. commit b3e66e4b8b78d443d9920f12b385e5c580f56570 Merge: ef3583f ff02c1f Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Feb 9 08:00:35 2022 +0100 Merge pull request #12 from caramelli/master Add support for NV61 commit ff02c1f7058a84d99c612fafdff7b02e83474e3f Author: Nicolas Caramelli Date: Wed Feb 9 07:57:36 2022 +0100 Update ChangeLog commit f6358663a118e8f3bf04c4a87442fd22e58efd5a Author: Nicolas Caramelli Date: Wed Feb 9 07:57:14 2022 +0100 Add support for NV61 commit ef3583fd6d9484019dece42dc18f528b053f6beb Author: Nicolas Caramelli Date: Tue Feb 8 14:58:04 2022 +0100 Update ChangeLog commit 521eebe4042d988c04930e0e148cf41ac3db085c Author: Nicolas Caramelli Date: Tue Feb 8 14:57:43 2022 +0100 Replace SIGUNUSED with the standard SIGSYS signal commit ad206f371b4ad5f14e25ac6ab3906f226061eefc Author: Nicolas Caramelli Date: Tue Feb 8 14:54:06 2022 +0100 Update ChangeLog commit 33de3256220022401644ffa264ccfdd6d7d50e00 Author: Nicolas Caramelli Date: Tue Feb 8 14:51:50 2022 +0100 Declare CorePart variables with extern commit c1df2aa105be7f24b99b205c92f31147c7ea9681 Merge: 5ec744b 4f95de7 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Feb 2 10:00:21 2022 +0100 Merge pull request #8 from caramelli/master Add pixel format conversion functions commit 4f95de7d778bbcd5c3910945f1903b92e748989c Author: Nicolas Caramelli Date: Wed Feb 2 09:59:21 2022 +0100 Update ChangeLog commit d404af89d1f55a98c091417531be6f1e8f5d451e Author: Nicolas Caramelli Date: Wed Feb 2 09:59:07 2022 +0100 Add pixel format conversion functions commit 5ec744bbfaad38838051d41bad95d8159ebee93e Merge: dcfa6e8 47be2bd Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Wed Feb 2 09:37:26 2022 +0100 Merge pull request #7 from caramelli/master Add BT.2020 color space definition commit 47be2bd015301a57ad77d2f29a6e0af58442bfd6 Author: Nicolas Caramelli Date: Wed Feb 2 09:34:50 2022 +0100 Update ChangeLog commit d75e3b98b64622ffb6cab2d48c75900feac2a1e6 Author: Nicolas Caramelli Date: Wed Feb 2 09:33:49 2022 +0100 Add BT.2020 color space definition commit dcfa6e8bdfce590bb4e2a95beb17fa30c9f23a22 Author: Nicolas Caramelli Date: Tue Jan 18 21:56:00 2022 +0100 DirectFB2 at FOSDEM 2022 commit cefad0b1bbda67ae2414e99c140c8234e96c366f Merge: e8e8bfc 1de2c28 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Jan 18 21:53:06 2022 +0100 Merge pull request #4 from caramelli/master DFVFF: Restart from the beginning after stopping commit 1de2c28a29b473832202d90b0d7f137bef7e4831 Author: Nicolas Caramelli Date: Tue Jan 18 21:50:39 2022 +0100 Update ChangeLog commit ed3efb3ada2e6bb6ef7d00e72c08f29a64e47808 Author: Nicolas Caramelli Date: Tue Jan 18 21:44:42 2022 +0100 DFVFF: Restart from the beginning after stopping commit e8e8bfcc7bdbffbbcc74e5ca55e50cf2fa8933b9 Merge: 33e96c5 84697e1 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Tue Jan 11 06:28:27 2022 +0100 Merge pull request #3 from caramelli/master DFVFF: no interlaced support commit 84697e114951385b0d262811b59b9055b5c796c4 Author: Nicolas Caramelli Date: Tue Jan 11 06:24:40 2022 +0100 Update ChangeLog commit decbeb69a473d30244958f29b1d45e6131ad3beb Author: Nicolas Caramelli Date: Tue Jan 11 06:23:41 2022 +0100 DFVFF: no interlaced support commit 33e96c5c8030c1b37448bd43ea115f082cf056a8 Merge: ac69e79 5a49ce4 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Jan 10 09:51:26 2022 +0100 Merge pull request #2 from caramelli/master Restore DirectFBGL interface version commit 5a49ce419408b0c5e96b9c0c4a630f85e3155763 Author: Nicolas Caramelli Date: Mon Jan 10 09:43:33 2022 +0100 Update ChangeLog commit b6c80b871c6fc4a76824d86b2b58ab52d27fb451 Author: Nicolas Caramelli Date: Mon Jan 10 09:38:34 2022 +0100 Restore DirectFBGL interface version commit ac69e79742b633ef553da667a6d68308d7dedd89 Merge: 39e2044 99a4109 Author: DirectFB2 <80045286+directfb2@users.noreply.github.com> Date: Mon Dec 6 15:45:17 2021 +0100 Merge pull request #1 from caramelli/master Revival of DirectFB commit 99a41095baa5d84c39b035057b26ec1b51d080c5 Author: Nicolas Caramelli Date: Mon Dec 6 15:42:37 2021 +0100 Add ChangeLog commit 84f00f65d763389c0fba5a28d150c418c8ce9990 Author: Nicolas Caramelli Date: Mon Dec 6 15:42:23 2021 +0100 Revival of DirectFB commit 39e204404329144622d26586587657f6a4b6fb2c Author: Nicolas Caramelli Date: Mon Dec 6 15:37:21 2021 +0100 Initial revision ================================================ FILE: INSTALL ================================================ Installation Instructions ========================= DirectFB2 is built using Meson. You will also need a C compiler and fluxcomp for converting .flux interface description files to .c files. With the default build of DirectFB2, only one application can be running (single application core). However you have the option to use the multi application core which allows multiple applications to run at the same time within a session. The applications then communicate through a layer called Fusion implemented either completely in user space, or by relying on the linux-fusion kernel module (which implements the critical parts of Fusion). To build the single application core: $ meson setup build/ To build the multi application core with Fusion implemented completely in user space: $ meson setup -Dmulti=true build/ or with Fusion based on the linux-fusion kernel module: $ meson setup -Dmulti=true -Dmulti-kernel=true build/ Linux ===== On Linux, start the build with: $ meson compile -C build/ And install DirectFB2 using: $ meson install -C build/ Next, install and run DirectFB applications, such as those available in DirectFB-examples. NuttX ===== On NuttX, copy the DirectFB2 directory to your NuttX apps/graphics/ directory. A defconfig file for the NuttX simulator is available. It must be placed in a directory nuttx/boards/sim/sim/sim/configs/directfb/ Add a DirectFB application, such as those available in DirectFB-examples. Configure the simulator: ./tools/configure.sh sim:directfb And start the build with: $ make Run the simulator using: $ ./nuttx ================================================ FILE: Kconfig ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA menuconfig GRAPHICS_DIRECTFB2 bool "DirectFB2" default n ---help--- Enable support for DirectFB2. ================================================ FILE: Make.defs ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ifneq ($(CONFIG_GRAPHICS_DIRECTFB2),) CONFIGURED_APPS += $(APPDIR)/graphics/DirectFB2 CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/DirectFB2/include CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/DirectFB2/lib endif ================================================ FILE: Makefile ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA include $(APPDIR)/Make.defs CFLAGS += -I. CFLAGS += -Isrc CFLAGS += -DBUILDTIME=\"$(shell date -u "+%Y-%m-%d\ %H:%M")\" CFLAGS += -DSYSCONFDIR=\"/etc\" DIRECT_CSRCS = lib/direct/clock.c DIRECT_CSRCS += lib/direct/conf.c DIRECT_CSRCS += lib/direct/debug.c DIRECT_CSRCS += lib/direct/direct.c DIRECT_CSRCS += lib/direct/direct_result.c DIRECT_CSRCS += lib/direct/hash.c DIRECT_CSRCS += lib/direct/init.c DIRECT_CSRCS += lib/direct/interface.c DIRECT_CSRCS += lib/direct/log.c DIRECT_CSRCS += lib/direct/log_domain.c DIRECT_CSRCS += lib/direct/map.c DIRECT_CSRCS += lib/direct/mem.c DIRECT_CSRCS += lib/direct/memcpy.c DIRECT_CSRCS += lib/direct/messages.c DIRECT_CSRCS += lib/direct/modules.c DIRECT_CSRCS += lib/direct/result.c DIRECT_CSRCS += lib/direct/stream.c DIRECT_CSRCS += lib/direct/system.c DIRECT_CSRCS += lib/direct/thread.c DIRECT_CSRCS += lib/direct/trace.c DIRECT_CSRCS += lib/direct/util.c DIRECT_CSRCS += lib/direct/os/nuttx/clock.c DIRECT_CSRCS += lib/direct/os/nuttx/filesystem.c DIRECT_CSRCS += lib/direct/os/nuttx/log.c DIRECT_CSRCS += lib/direct/os/nuttx/mem.c DIRECT_CSRCS += lib/direct/os/nuttx/mutex.c DIRECT_CSRCS += lib/direct/os/nuttx/signals.c DIRECT_CSRCS += lib/direct/os/nuttx/system.c DIRECT_CSRCS += lib/direct/os/nuttx/thread.c FUSION_CSRCS = lib/fusion/arena.c FUSION_CSRCS += lib/fusion/call.c FUSION_CSRCS += lib/fusion/conf.c FUSION_CSRCS += lib/fusion/fusion.c FUSION_CSRCS += lib/fusion/hash.c FUSION_CSRCS += lib/fusion/init.c FUSION_CSRCS += lib/fusion/lock.c FUSION_CSRCS += lib/fusion/object.c FUSION_CSRCS += lib/fusion/reactor.c FUSION_CSRCS += lib/fusion/ref.c FUSION_CSRCS += lib/fusion/shmalloc.c FUSION_CSRCS += lib/fusion/vector.c FUSION_CSRCS += lib/fusion/shm/fake.c DIRECTFB_CSRCS = src/directfb.c DIRECTFB_CSRCS += src/directfb_result.c DIRECTFB_CSRCS += src/idirectfb.c DIRECTFB_CSRCS += src/init.c DIRECTFB_CSRCS += src/core/CoreDFB_real.c DIRECTFB_CSRCS += src/core/CoreGraphicsState_real.c DIRECTFB_CSRCS += src/core/CoreGraphicsStateClient.c DIRECTFB_CSRCS += src/core/CoreInputDevice_real.c DIRECTFB_CSRCS += src/core/CoreLayer_real.c DIRECTFB_CSRCS += src/core/CoreLayerContext_real.c DIRECTFB_CSRCS += src/core/CoreLayerRegion_real.c DIRECTFB_CSRCS += src/core/CorePalette_real.c DIRECTFB_CSRCS += src/core/CoreScreen_real.c DIRECTFB_CSRCS += src/core/CoreSlave_real.c DIRECTFB_CSRCS += src/core/CoreSurface_real.c DIRECTFB_CSRCS += src/core/CoreSurfaceAllocation_real.c DIRECTFB_CSRCS += src/core/CoreSurfaceClient_real.c DIRECTFB_CSRCS += src/core/CoreWindow_real.c DIRECTFB_CSRCS += src/core/CoreWindowStack_real.c DIRECTFB_CSRCS += src/core/clipboard.c DIRECTFB_CSRCS += src/core/colorhash.c DIRECTFB_CSRCS += src/core/core.c DIRECTFB_CSRCS += src/core/core_parts.c DIRECTFB_CSRCS += src/core/fonts.c DIRECTFB_CSRCS += src/core/gfxcard.c DIRECTFB_CSRCS += src/core/graphics_state.c DIRECTFB_CSRCS += src/core/input.c DIRECTFB_CSRCS += src/core/layer_context.c DIRECTFB_CSRCS += src/core/layer_control.c DIRECTFB_CSRCS += src/core/layer_region.c DIRECTFB_CSRCS += src/core/layers.c DIRECTFB_CSRCS += src/core/local_surface_pool.c DIRECTFB_CSRCS += src/core/palette.c DIRECTFB_CSRCS += src/core/prealloc_surface_pool_bridge.c DIRECTFB_CSRCS += src/core/prealloc_surface_pool.c DIRECTFB_CSRCS += src/core/screen.c DIRECTFB_CSRCS += src/core/screens.c DIRECTFB_CSRCS += src/core/state.c DIRECTFB_CSRCS += src/core/surface.c DIRECTFB_CSRCS += src/core/surface_allocation.c DIRECTFB_CSRCS += src/core/surface_buffer.c DIRECTFB_CSRCS += src/core/surface_client.c DIRECTFB_CSRCS += src/core/surface_core.c DIRECTFB_CSRCS += src/core/surface_pool.c DIRECTFB_CSRCS += src/core/surface_pool_bridge.c DIRECTFB_CSRCS += src/core/system.c DIRECTFB_CSRCS += src/core/windows.c DIRECTFB_CSRCS += src/core/windowstack.c DIRECTFB_CSRCS += src/core/wm.c DIRECTFB_CSRCS += src/display/idirectfbdisplaylayer.c DIRECTFB_CSRCS += src/display/idirectfbpalette.c DIRECTFB_CSRCS += src/display/idirectfbscreen.c DIRECTFB_CSRCS += src/display/idirectfbsurface.c DIRECTFB_CSRCS += src/display/idirectfbsurfaceallocation.c DIRECTFB_CSRCS += src/display/idirectfbsurface_layer.c DIRECTFB_CSRCS += src/display/idirectfbsurface_window.c DIRECTFB_CSRCS += src/gfx/clip.c DIRECTFB_CSRCS += src/gfx/convert.c DIRECTFB_CSRCS += src/gfx/util.c DIRECTFB_CSRCS += src/gfx/generic/generic.c DIRECTFB_CSRCS += src/gfx/generic/generic_blit.c DIRECTFB_CSRCS += src/gfx/generic/generic_draw_line.c DIRECTFB_CSRCS += src/gfx/generic/generic_fill_rectangle.c DIRECTFB_CSRCS += src/gfx/generic/generic_stretch_blit.c DIRECTFB_CSRCS += src/gfx/generic/generic_texture_triangles.c DIRECTFB_CSRCS += src/gfx/generic/generic_util.c DIRECTFB_CSRCS += src/input/idirectfbeventbuffer.c DIRECTFB_CSRCS += src/input/idirectfbinputdevice.c DIRECTFB_CSRCS += src/media/idirectfbdatabuffer.c DIRECTFB_CSRCS += src/media/idirectfbdatabuffer_file.c DIRECTFB_CSRCS += src/media/idirectfbdatabuffer_memory.c DIRECTFB_CSRCS += src/media/idirectfbdatabuffer_streamed.c DIRECTFB_CSRCS += src/media/idirectfbfont.c DIRECTFB_CSRCS += src/media/idirectfbimageprovider.c DIRECTFB_CSRCS += src/media/idirectfbvideoprovider.c DIRECTFB_CSRCS += src/misc/conf.c DIRECTFB_CSRCS += src/misc/gfx_util.c DIRECTFB_CSRCS += src/misc/util.c DIRECTFB_CSRCS += src/windows/idirectfbwindow.c FLUX_CSRCS = src/core/CoreDFB.c FLUX_CSRCS += src/core/CoreGraphicsState.c FLUX_CSRCS += src/core/CoreInputDevice.c FLUX_CSRCS += src/core/CoreLayer.c FLUX_CSRCS += src/core/CoreLayerContext.c FLUX_CSRCS += src/core/CoreLayerRegion.c FLUX_CSRCS += src/core/CorePalette.c FLUX_CSRCS += src/core/CoreSlave.c FLUX_CSRCS += src/core/CoreScreen.c FLUX_CSRCS += src/core/CoreSurface.c FLUX_CSRCS += src/core/CoreSurfaceAllocation.c FLUX_CSRCS += src/core/CoreSurfaceClient.c FLUX_CSRCS += src/core/CoreWindow.c FLUX_CSRCS += src/core/CoreWindowStack.c FLUX_HDRS = $(patsubst %.c,%.h,$(FLUX_CSRCS)) CSRCS = $(DIRECT_CSRCS) $(FUSION_CSRCS) $(DIRECTFB_CSRCS) $(FLUX_CSRCS) CORE_SYSTEM_CSRCS = systems/nuttxfb/nuttxfb_layer.c CORE_SYSTEM_CSRCS += systems/nuttxfb/nuttxfb_screen.c CORE_SYSTEM_CSRCS += systems/nuttxfb/nuttxfb_surface_pool.c CORE_SYSTEM_CSRCS += systems/nuttxfb/nuttxfb_system.c CSRCS += $(CORE_SYSTEM_CSRCS) INPUT_DRIVER_CSRCS = inputdrivers/nuttx_input/nuttx_input.c CSRCS += $(INPUT_DRIVER_CSRCS) FONT_PROVIDER_CSRCS = interfaces/IDirectFBFont/idirectfbfont_dgiff.c CSRCS += $(FONT_PROVIDER_CSRCS) IMAGE_PROVIDER_CSRCS = interfaces/IDirectFBImageProvider/idirectfbimageprovider_dfiff.c CSRCS += $(IMAGE_PROVIDER_CSRCS) VIDEO_PROVIDER_CSRCS = interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_dfvff.c CSRCS += $(VIDEO_PROVIDER_CSRCS) WINDOW_MANAGER_CSRCS = wm/default/default.c CSRCS += $(WINDOW_MANAGER_CSRCS) config.h: $(Q) echo "#pragma once" > $@; \ echo "#define SIZEOF_LONG 8" >> $@ include/directfb_build.h: $(Q) echo "#pragma once" > $@; \ echo "#define FLUXED_ARGS_BYTES 1024" >> $@ include/directfb_keynames.h: include/directfb_keyboard.h $(Q) ./include/gen_directfb_keynames.sh $^ > $@ include/directfb_strings.h: include/directfb.h $(Q) ./include/gen_directfb_strings.sh $^ > $@ include/directfb_version.h: $(Q) echo "#pragma once" > $@; \ echo "#define DIRECTFB_MAJOR_VERSION 2" >> $@; \ echo "#define DIRECTFB_MICRO_VERSION 0" >> $@; \ echo "#define DIRECTFB_MINOR_VERSION 0" >> $@ lib/direct/build.h: $(Q) echo "#pragma once" > $@; \ echo "#define DIRECT_BUILD_CTORS 0" >> $@; \ echo "#define DIRECT_BUILD_DEBUG 0" >> $@; \ echo "#define DIRECT_BUILD_DEBUGS 0" >> $@; \ echo "#define DIRECT_BUILD_DYNLOAD 0" >> $@; \ echo "#define DIRECT_BUILD_MEMCPY_PROBING 0" >> $@; \ echo "#define DIRECT_BUILD_NETWORK 0" >> $@; \ echo "#define DIRECT_BUILD_OS_NUTTX 1" >> $@; \ echo "#define DIRECT_BUILD_PIPED_STREAM 0" >> $@; \ echo "#define DIRECT_BUILD_SENTINELS 0" >> $@; \ echo "#define DIRECT_BUILD_TEXT 1" >> $@; \ echo "#define DIRECT_BUILD_TRACE 0" >> $@ lib/fusion/build.h: $(Q) echo "#pragma once" > $@; \ echo "#define FUSION_BUILD_MULTI 0" >> $@ src/build.h: $(Q) echo "#pragma once" > $@; \ echo "#define DFB_SMOOTH_SCALING 1" >> $@; \ echo "#define DIRECTFB_VERSION_VENDOR \"\"" >> $@ FLUXCOMP ?= fluxcomp FLUX_ARGS = --call-mode --dispatch-error-abort --identity --include-prefix=core --object-ptrs --static-args-bytes=FLUXED_ARGS_BYTES src/core/%.c: src/core/%.flux $(FLUXCOMP) $(FLUX_ARGS) -c $^ -o=src/core context:: config.h include/directfb_build.h include/directfb_keynames.h include/directfb_strings.h include/directfb_version.h lib/direct/build.h lib/fusion/build.h src/build.h $(FLUX_CSRCS) distclean:: $(call DELFILE, config.h) $(call DELFILE, include/directfb_build.h) $(call DELFILE, include/directfb_keynames.h) $(call DELFILE, include/directfb_strings.h) $(call DELFILE, include/directfb_version.h) $(call DELFILE, lib/direct/build.h) $(call DELFILE, lib/fusion/build.h) $(call DELFILE, src/build.h) $(call DELFILE, $(FLUX_CSRCS)) $(call DELFILE, $(FLUX_HDRS)) include $(APPDIR)/Application.mk ================================================ FILE: NEWS ================================================ 2.0.0 ----- Meson build system Pure C implementation No external dependency (except fluxcomp for converting .flux interface description files to .c files) Static library support for MCU targets Modularization of the source code, which now only contains: - libdirect / libfusion / libdirectfb core libraries - a generic system module and a generic input driver for supported operating systems: - legacy Linux FBDev or modern DRM/KMS system module and Linux input driver - NuttX Framebuffer system module and NuttX input driver - the default WM module - the DGIFF (DirectFB Glyph Image File Format) font provider - the DFIFF (DirectFB Fast Image File Format) image provider - the DFVFF (DirectFB Fast Video File Format) video provider Separate packages for: - additional system modules - additional input drivers - additional WM modules - additional font/image/video providers - GFX drivers (hardware acceleration) ================================================ FILE: README ================================================ DirectFB2 ========= DirectFB2 is a fork of DirectFB, a graphics library which was designed with embedded systems in mind. Linux and NuttX operating systems are supported. See the file INSTALL for installation instructions. Enjoy! ================================================ FILE: README.md ================================================ The DirectFB2 open source project --------------------------------- https://directfb2.github.io ________________________________________________________________ **2024-04-02** Various font/image/music/video providers available in [DirectFB2-media](https://github.com/directfb2/DirectFB2-media) (can be tested via [DirectFB-media-samples](https://github.com/directfb2/DirectFB-media-samples)) **2023-10-06** OpenGL ES and EGL for DirectFB platform with [SwiftShaderGL-DirectFB](https://github.com/directfb2/SwiftShaderGL-DirectFB) (DirectFBGL accessible via [DirectFBGL-EGL](https://github.com/directfb2/DirectFBGL-EGL)) **2023-07-17** OpenGL software rendering with [DirectFBGL-PortableGL](https://github.com/directfb2/DirectFBGL-PortableGL) **2023-06-12** Play with [DirectFB-examples](https://github.com/directfb2/DirectFB-examples) and [LiTE-examples](https://github.com/directfb2/LiTE-examples) on MCU devices using available NuttX support **2023-01-01** Restoring [FusionSound](https://github.com/directfb2/FusionSound2) to add sound in DirectFB apps **2022-12-02** All platforms supporting generic buffer management can use the [DirectFB2-eglgbm](https://github.com/directfb2/DirectFB2-eglgbm) system module **2022-11-09** Start Raspberry Pi boards again with [DirectFB2-eglrpi](https://github.com/directfb2/DirectFB2-eglrpi) system module and [DirectFB2-gles2](https://github.com/directfb2/DirectFB2-gles2) GFX driver (HW acceleration) **2022-10-30** [DFBTerm](https://github.com/directfb2/DFBTerm) and [Projektor](https://github.com/directfb2/Projektor) are DirectFB applications based on LiTE **2022-08-01** Create embedded UIs on top of DirectFB with [LiTE](https://github.com/directfb2/LiTE) **2022-06-02** Support multi-touch screens with [DirectFB2-tslib](https://github.com/directfb2/DirectFB2-tslib) or remote controls with [DirectFB2-lirc](https://github.com/directfb2/DirectFB2-lirc) **2022-02-05** DirectFB2 at [FOSDEM 2022](https://archive.fosdem.org/2022/schedule/event/directfb) **2021-12-06** Revival of [DirectFB](https://github.com/directfb2/DirectFB2) ================================================ FILE: dfb-update-pkgconfig.in ================================================ #!/bin/sh # # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA mkpc() { if [ "`echo $DESTDIR@PKGCONFIGDIR@/directfb-$1-*`" != "$DESTDIR@PKGCONFIGDIR@/directfb-$1-*" ]; then REQUIRES_PRIVATE=$(basename -s .pc -a $DESTDIR@PKGCONFIGDIR@/directfb-$1-* | tr '\n' ' ' | sed 's/ $//') fi cat > $DESTDIR@PKGCONFIGDIR@/directfb-$1.pc << EOF Name: DirectFB-$1 Description: DirectFB $1 modules Version: @VERSION@ Requires.private: $REQUIRES_PRIVATE EOF } mkpc gfxdriver mkpc inputdriver mkpc interface mkpc system mkpc wm ================================================ FILE: include/dfiff.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DFIFF_H__ #define __DFIFF_H__ #include typedef struct { u8 magic[5]; /* "DFIFF" magic */ u8 major; /* Major version number */ u8 minor; /* Minor version number */ u8 flags; u32 width; u32 height; DFBSurfacePixelFormat format; u32 pitch; } DFIFFHeader; #endif ================================================ FILE: include/dfvff.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DFVFF_H__ #define __DFVFF_H__ #include typedef struct { u8 magic[5]; /* "DFVFF" magic */ u8 major; /* Major version number */ u8 minor; /* Minor version number */ u8 flags; u32 width; u32 height; DFBSurfacePixelFormat format; DFBSurfaceColorSpace colorspace; u32 framerate_num; u32 framerate_den; } DFVFFHeader; #endif ================================================ FILE: include/dgiff.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DGIFF_H__ #define __DGIFF_H__ #include typedef struct { u8 magic[5]; /* "DGIFF" magic */ u8 major; /* Major version number */ u8 minor; /* Minor version number */ u8 flags; u32 num_faces; u32 __pad; } DGIFFHeader; typedef struct { s32 next_face; /* byte offset from this to next face */ s32 size; s32 ascender; s32 descender; s32 height; s32 max_advance; u32 pixelformat; u32 num_glyphs; u32 num_rows; DFBSurfaceBlittingFlags blittingflags; } DGIFFFaceHeader; typedef struct { u32 unicode; u32 row; s32 offset; s32 width; s32 height; s32 left; s32 top; s32 advance; } DGIFFGlyphInfo; typedef struct { s32 width; s32 height; s32 pitch; u32 __pad; /* Raw pixel data follows, 'height * pitch' bytes. */ } DGIFFGlyphRow; #endif ================================================ FILE: include/directfb.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFB_H__ #define __DIRECTFB_H__ #ifdef __cplusplus extern "C" { #endif #include #include #include /* * Main interface of DirectFB. */ D_DECLARE_INTERFACE( IDirectFB ) /* * Interface to different display outputs, encoders, connector settings, power management and synchronization. */ D_DECLARE_INTERFACE( IDirectFBScreen ) /* * Layer interface for configuration, window stack usage or direct surface access, with shared/exclusive context. */ D_DECLARE_INTERFACE( IDirectFBDisplayLayer ) /* * Interface to a surface object, being a graphics context for rendering and state control, buffer operations, palette * access and sub area translate'n'clip logic. */ D_DECLARE_INTERFACE( IDirectFBSurface ) /* * Interface to a surface allocation object, being an actual buffer being allocated for a surface. */ D_DECLARE_INTERFACE( IDirectFBSurfaceAllocation ) /* * Interface for read/write access to the colors of a palette object and for cloning it. */ D_DECLARE_INTERFACE( IDirectFBPalette ) /* * Input device interface for keymap access, event buffers and state queries. */ D_DECLARE_INTERFACE( IDirectFBInputDevice ) /* * Interface to a local event buffer to send/receive events, wait for events, abort waiting or reset buffer. */ D_DECLARE_INTERFACE( IDirectFBEventBuffer ) /* * Interface to a window object, controlling appearance and focus, positioning and stacking, event buffers and surface * access. */ D_DECLARE_INTERFACE( IDirectFBWindow ) /* * Interface to a font provider, getting metrics, measuring strings or single characters, query/choose encodings. */ D_DECLARE_INTERFACE( IDirectFBFont ) /* * Interface to an image provider, retrieving information about the image and rendering it to a surface. */ D_DECLARE_INTERFACE( IDirectFBImageProvider ) /* * Interface to a video provider for playback with advanced control and basic stream information. */ D_DECLARE_INTERFACE( IDirectFBVideoProvider ) /* * Data buffer interface, providing unified access to different kinds of data storage and live feed. */ D_DECLARE_INTERFACE( IDirectFBDataBuffer ) /* * OpenGL interface. */ D_DECLARE_INTERFACE( IDirectFBGL ) /**********************************************************************************************************************/ #define DIRECTFB_API /* * A boolean. */ typedef enum { DFB_FALSE = 0, /* false */ DFB_TRUE = !DFB_FALSE /* true */ } DFBBoolean; /* * Return code of all interface methods and most functions. * * Whenever a method has to return any information, it is done * via output parameters. */ typedef enum { /* * Aliases for backward compatibility and uniform look in * DirectFB code. */ DFB_OK = DR_OK, /* No error occurred. */ DFB_FAILURE = DR_FAILURE, /* A general or unknown error occurred. */ DFB_INIT = DR_INIT, /* A general initialization error occurred. */ DFB_BUG = DR_BUG, /* Internal bug or inconsistency has been detected. */ DFB_DEAD = DR_DEAD, /* Interface has a zero reference counter (available in debug mode). */ DFB_UNSUPPORTED = DR_UNSUPPORTED, /* The requested operation or an argument is (currently) not supported. */ DFB_UNIMPLEMENTED = DR_UNIMPLEMENTED, /* The requested operation is not implemented, yet. */ DFB_ACCESSDENIED = DR_ACCESSDENIED, /* Access to the resource is denied. */ DFB_INVAREA = DR_INVAREA, /* An invalid area has been specified or detected. */ DFB_INVARG = DR_INVARG, /* An invalid argument has been specified. */ DFB_NOSYSTEMMEMORY = DR_NOLOCALMEMORY, /* There's not enough system memory. */ DFB_NOSHAREDMEMORY = DR_NOSHAREDMEMORY, /* There's not enough shared memory. */ DFB_LOCKED = DR_LOCKED, /* The resource is (already) locked. */ DFB_BUFFEREMPTY = DR_BUFFEREMPTY, /* The buffer is empty. */ DFB_FILENOTFOUND = DR_FILENOTFOUND, /* The specified file has not been found. */ DFB_IO = DR_IO, /* A general I/O error occurred. */ DFB_BUSY = DR_BUSY, /* The resource or device is busy. */ DFB_NOIMPL = DR_NOIMPL, /* No implementation for this interface or content type has been found. */ DFB_TIMEOUT = DR_TIMEOUT, /* The operation timed out. */ DFB_THIZNULL = DR_THIZNULL, /* 'thiz' pointer is NULL. */ DFB_IDNOTFOUND = DR_IDNOTFOUND, /* No resource has been found by the specified id. */ DFB_DESTROYED = DR_DESTROYED, /* The requested object has been destroyed. */ DFB_FUSION = DR_FUSION, /* Internal fusion error detected, most likely related to IPC resources. */ DFB_BUFFERTOOLARGE = DR_BUFFERTOOLARGE, /* Buffer is too large. */ DFB_INTERRUPTED = DR_INTERRUPTED, /* The operation has been interrupted. */ DFB_NOCONTEXT = DR_NOCONTEXT, /* No context available. */ DFB_TEMPUNAVAIL = DR_TEMPUNAVAIL, /* Temporarily unavailable. */ DFB_LIMITEXCEEDED = DR_LIMITEXCEEDED, /* Attempted to exceed limit, i.e. any kind of maximum size, count etc. */ DFB_NOSUCHMETHOD = DR_NOSUCHMETHOD, /* Requested method is not known. */ DFB_NOSUCHINSTANCE = DR_NOSUCHINSTANCE, /* Requested instance is not known. */ DFB_ITEMNOTFOUND = DR_ITEMNOTFOUND, /* No such item found. */ DFB_VERSIONMISMATCH = DR_VERSIONMISMATCH, /* Some versions didn't match. */ DFB_EOF = DR_EOF, /* Reached end of file. */ DFB_SUSPENDED = DR_SUSPENDED, /* The requested object is suspended. */ DFB_INCOMPLETE = DR_INCOMPLETE, /* The operation has been executed, but not completely. */ DFB_NOCORE = DR_NOCORE, /* Core part not available. */ /* * DirectFB specific result codes starting at this offset. */ DFB__RESULT_BASE = D_RESULT_TYPE_CODE_BASE( 'D','F','B','1' ), DFB_NOVIDEOMEMORY, /* There's not enough video memory. */ DFB_MISSINGFONT, /* No font has been set. */ DFB_MISSINGIMAGE, /* No image has been set. */ DFB_NOALLOCATION, /* No allocation. */ DFB_NOBUFFER, /* No buffer. */ DFB__RESULT_END } DFBResult; /* * Return value of callback function of enumerations. */ typedef enum { DFENUM_OK = 0, /* Proceed with enumeration. */ DFENUM_CANCEL = 1 /* Cancel enumeration. */ } DFBEnumerationResult; /**********************************************************************************************************************/ /* * Dynamic version handling. */ extern const unsigned int directfb_major_version; extern const unsigned int directfb_minor_version; extern const unsigned int directfb_micro_version; /* * Singleton. */ extern IDirectFB *idirectfb_singleton; /* * Checks for a certain DirectFB version. * In case of an error a message is returned describing * the mismatch. */ const char DIRECTFB_API *DirectFBCheckVersion ( unsigned int required_major, /* major version */ unsigned int required_minor, /* minor version */ unsigned int required_micro /* micro version */ ); /* * Retrieves usage information about supported command-line flags. */ const char DIRECTFB_API *DirectFBUsageString ( void ); /* * Parses the command-line and initializes some variables. * You absolutely need to call this before doing anything else. * Removes all options used by DirectFB from argv. */ DFBResult DIRECTFB_API DirectFBInit ( int *argc, /* pointer to main()'s argc */ char **argv[] /* pointer to main()'s argv */ ); #if !DIRECT_BUILD_CTORS #define StringizeDirectFBCoreSystemInit(name) directfb_##name##_ctor() #define DirectFBCoreSystemInit(name) StringizeDirectFBCoreSystemInit( name ) #define StringizeDirectFBCoreSystemInitProtoype(name) void directfb_##name##_ctor( void ) #define DirectFBCoreSystemInitProtoype(name) StringizeDirectFBCoreSystemInitProtoype( name ) #ifdef DFB_GRAPHICS_DRIVER #define StringizeGraphicsDriverInit(name) directfb_##name##_ctor() #define DirectFBGraphicsDriverInit(name) StringizeDirectFBGraphicsDriverInit( name ) #define StringizeDirectFBGraphicsDriverInitProtoype(name) void directfb_##name##_ctor( void ) #define DirectFBGraphicsDriverInitProtoype(name) StringizeDirectFBGraphicsDriverInitProtoype( name ) #else #define DirectFBGraphicsDriverInit(name) #define DirectFBGraphicsDriverInitProtoype(name) #endif #ifdef DFB_INPUT_DRIVER #define StringizeDirectFBInputDriverInit(name) directfb_##name##_ctor() #define DirectFBInputDriverInit(name) StringizeDirectFBInputDriverInit( name ) #define StringizeDirectFBInputDriverInitProtoype(name) void directfb_##name##_ctor( void ) #define DirectFBInputDriverInitProtoype(name) StringizeDirectFBInputDriverInitProtoype( name ) #else #define DirectFBInputDriverInit(name) #define DirectFBInputDriverInitProtoype(name) #endif #ifdef DFB_FONT_PROVIDER #define StringizeDirectFBFontProviderInit(name) IDirectFBFont_##name##_ctor() #define DirectFBFontProviderInit(name) StringizeDirectFBFontProviderInit( name ) #define StringizeDirectFBFontProviderInitProtoype(name) void IDirectFBFont_##name##_ctor( void ) #define DirectFBFontProviderInitProtoype(name) StringizeDirectFBFontProviderInitProtoype( name ) #else #define DirectFBFontProviderInit(name) #define DirectFBFontProviderInitProtoype(name) #endif #ifdef DFB_IMAGE_PROVIDER #define StringizeDirectFBImageProviderInit(name) IDirectFBImageProvider_##name##_ctor() #define DirectFBImageProviderInit(name) StringizeDirectFBImageProviderInit( name ) #define StringizeDirectFBImageProviderInitProtoype(name) void IDirectFBImageProvider_##name##_ctor( void ) #define DirectFBImageProviderInitProtoype(name) StringizeDirectFBImageProviderInitProtoype( name ) #else #define DirectFBImageProviderInit(name) #define DirectFBImageProviderInitProtoype(name) #endif #ifdef DFB_VIDEO_PROVIDER #define StringizeDirectFBVideoProviderInit(name) IDirectFBVideoProvider_##name##_ctor() #define DirectFBVideoProviderInit(name) StringizeDirectFBVideoProviderInit( name ) #define StringizeDirectFBVideoProviderInitProtoype(name) void IDirectFBVideoProvider_##name##_ctor( void ) #define DirectFBVideoProviderInitProtoype(name) StringizeDirectFBVideoProviderInitProtoype( name ) #else #define DirectFBVideoProviderInit(name) #define DirectFBVideoProviderInitProtoype(name) #endif #ifdef DFB_OPENGL_IMPLEMENTATION #define StringizeDirectFBGLInit(name) IDirectFBGL_##name##_ctor() #define DirectFBGLInit(name) StringizeDirectFBGLInit( name ) #define StringizeDirectFBGLInitProtoype(name) void IDirectFBGL_##name##_ctor( void ) #define DirectFBGLInitProtoype(name) StringizeDirectFBGLInitProtoype( name ) #else #define DirectFBGLInit(name) #define DirectFBGLInitProtoype(name) #endif #define StringizeDirectFBWindowManagerInit(name) directfb_##name##_ctor() #define DirectFBWindowManagerInit(name) StringizeDirectFBWindowManagerInit( name ) #define StringizeDirectFBWindowManagerInitProtoype(name) void directfb_##name##_ctor( void ) #define DirectFBWindowManagerInitProtoype(name) StringizeDirectFBWindowManagerInitProtoype( name ) #if defined(DFB_CORE_SYSTEM) && defined(DFB_WINDOW_MANAGER) DirectFBCoreSystemInitProtoype ( DFB_CORE_SYSTEM ); DirectFBGraphicsDriverInitProtoype( DFB_GRAPHICS_DRIVER ); DirectFBInputDriverInitProtoype ( DFB_INPUT_DRIVER ); DirectFBFontProviderInitProtoype ( DFB_FONT_PROVIDER ); DirectFBImageProviderInitProtoype ( DFB_IMAGE_PROVIDER ); DirectFBVideoProviderInitProtoype ( DFB_VIDEO_PROVIDER ); DirectFBGLInitProtoype ( DFB_OPENGL_IMPLEMENTATION ); DirectFBWindowManagerInitProtoype ( DFB_WINDOW_MANAGER ); #define DirectFBInit( argc_ptr, argv_ptr ) \ DirectFBInit ( argc_ptr, argv_ptr ); \ DirectFBCoreSystemInit ( DFB_CORE_SYSTEM ); \ DirectFBGraphicsDriverInit( DFB_GRAPHICS_DRIVER ); \ DirectFBInputDriverInit ( DFB_INPUT_DRIVER ); \ DirectFBFontProviderInit ( DFB_FONT_PROVIDER ); \ DirectFBImageProviderInit ( DFB_IMAGE_PROVIDER ); \ DirectFBVideoProviderInit ( DFB_VIDEO_PROVIDER ); \ DirectFBGLInit ( DFB_OPENGL_IMPLEMENTATION ); \ DirectFBWindowManagerInit ( DFB_WINDOW_MANAGER ); #endif #endif /* * Sets configuration parameters supported on command line and in * config file. Can only be called before DirectFBCreate but after * DirectFBInit. */ DFBResult DIRECTFB_API DirectFBSetOption ( const char *name, /* option name */ const char *value /* option value */ ); /* * Creates the main interface. */ DFBResult DIRECTFB_API DirectFBCreate ( IDirectFB **ret_interface /* pointer to the created interface */ ); /* * Prints a description of the result code along with an * optional message that is put in front with a colon. */ DFBResult DIRECTFB_API DirectFBError ( const char *msg, /* optional message */ DFBResult result /* result code to interpret */ ); /* * Returns a string describing result. */ const char DIRECTFB_API *DirectFBErrorString ( DFBResult result /* result code to describe */ ); /* * Behaves like DirectFBError, but shuts down the calling * application. */ DFBResult DIRECTFB_API DirectFBErrorFatal ( const char *msg, /* optional message */ DFBResult result /* result code to interpret */ ); /**********************************************************************************************************************/ /* * A rectangle specified by two points. * * The defined rectangle includes the top left but not the * bottom right endpoint. */ typedef struct { int x1; /* X coordinate of top-left point (inclusive) */ int y1; /* Y coordinate of top-left point (inclusive) */ int x2; /* X coordinate of lower-right point (exclusive) */ int y2; /* Y coordinate of lower-right point (exclusive) */ } DFBBox; /* * A color defined by channels with 8bit each. */ typedef struct { u8 a; /* alpha channel */ u8 r; /* red channel */ u8 g; /* green channel */ u8 b; /* blue channel */ } DFBColor; /* * Flags defining which fields of a DFBColorAdjustment are * valid. */ typedef enum { DCAF_NONE = 0x00000000, /* None of these. */ DCAF_BRIGHTNESS = 0x00000001, /* Brightness field is valid. */ DCAF_CONTRAST = 0x00000002, /* Contrast field is valid. */ DCAF_HUE = 0x00000004, /* Hue field is valid. */ DCAF_SATURATION = 0x00000008, /* Saturation field is valid. */ DCAF_ALL = 0x0000000F /* All of these. */ } DFBColorAdjustmentFlags; /* * Color Adjustment used to adjust video colors. * * All fields are in the range 0x0 to 0xffff with 0x8000 as the * default value (no adjustment). */ typedef struct { DFBColorAdjustmentFlags flags; /* Validation of fields. */ u16 brightness; /* Color brightness. */ u16 contrast; /* Color contrast. */ u16 hue; /* Color hue. */ u16 saturation; /* Color saturation. */ } DFBColorAdjustment; /* * A color key defined by R,G,B and eventually a color index. */ typedef struct { u8 index; /* color index */ u8 r; /* red channel */ u8 g; /* green channel */ u8 b; /* blue channel */ } DFBColorKey; /* * Color key polarity. */ typedef enum { DCKP_DEFAULT = 0x00000000, /* default */ DCKP_OTHER = 0x00000001 /* other */ } DFBColorKeyPolarity; /* * Extended color key definition. */ typedef struct { DFBColorKeyPolarity polarity; /* color key polarity */ DFBColor lower; /* lower color key */ DFBColor upper; /* upper color key */ } DFBColorKeyExtended; /* * A color defined by channels with 8bit each. */ typedef struct { u8 a; /* alpha channel */ u8 y; /* luma channel */ u8 u; /* chroma channel */ u8 v; /* chroma channel */ } DFBColorYUV; /* * Convolution filter. */ typedef struct { s32 kernel[9]; /* The kernel consists of 3x3 matrix. */ s32 scale; /* Scale. */ s32 bias; /* Bias. */ } DFBConvolutionFilter; /* * A dimension specified by width and height. */ typedef struct { int w; /* width of it */ int h; /* height of it */ } DFBDimension; /* * Insets specify a distance from each edge of a rectangle. * * Positive values always mean outside. */ typedef struct { int l; /* distance from left edge */ int t; /* distance from top edge */ int r; /* distance from right edge */ int b; /* distance from bottom edge */ } DFBInsets; /* * A rectangle specified by normalized coordinates. * * E.g. using 0.0, 0.0, 1.0, 1.0 would specify the whole screen. */ typedef struct { float x; /* normalized X coordinate */ float y; /* normalized Y coordinate */ float w; /* normalized width */ float h; /* normalized height */ } DFBLocation; /* * A point specified by x/y coordinates. */ typedef struct { int x; /* X coordinate of it */ int y; /* Y coordinate of it */ } DFBPoint; /* * A rectangle specified by a point and a dimension. */ typedef struct { int x; /* X coordinate of its top-left point */ int y; /* Y coordinate of its top-left point */ int w; /* width of it */ int h; /* height of it */ } DFBRectangle; /* * A region specified by two points. * * The defined region includes both endpoints. */ typedef struct { int x1; /* X coordinate of top-left point */ int y1; /* Y coordinate of top-left point */ int x2; /* X coordinate of lower-right point */ int y2; /* Y coordinate of lower-right point */ } DFBRegion; /* * A horizontal line specified by x and width. */ typedef struct { int x; /* X coordinate */ int w; /* width of span */ } DFBSpan; /* * A trapezoid specified by two points with a width each. */ typedef struct { int x1; /* X coordinate of first span */ int y1; /* Y coordinate of first span */ int w1; /* width of first span */ int x2; /* X coordinate of second span */ int y2; /* Y coordinate of second span */ int w2; /* width of second span */ } DFBTrapezoid; /* * A triangle specified by three points. */ typedef struct { int x1; /* X coordinate of first edge */ int y1; /* Y coordinate of first edge */ int x2; /* X coordinate of second edge */ int y2; /* Y coordinate of second edge */ int x3; /* X coordinate of third edge */ int y3; /* Y coordinate of third edge */ } DFBTriangle; /* * Way of building triangles from the list of vertices. */ typedef enum { DTTF_LIST = 0x00000000, /* 0/1/2 3/4/5 6/7/8 ... */ DTTF_STRIP = 0x00000001, /* 0/1/2 1/2/3 2/3/4 ... */ DTTF_FAN = 0x00000002 /* 0/1/2 0/2/3 0/3/4 ... */ } DFBTriangleFormation; /* * Transformed vertex of a textured triangle. */ typedef struct { float x; /* Destination X coordinate (in pixels) */ float y; /* Destination Y coordinate (in pixels) */ float z; /* Z coordinate */ float w; /* W coordinate */ float s; /* Texture S coordinate */ float t; /* Texture T coordinate */ } DFBVertex; /**********************************************************************************************************************/ typedef unsigned int DFBColorID; typedef unsigned int DFBDisplayLayerID; typedef unsigned int DFBDisplayLayerIDs; typedef unsigned int DFBDisplayLayerSourceID; typedef unsigned int DFBInputDeviceID; typedef unsigned int DFBScreenID; typedef unsigned int DFBSurfaceID; typedef unsigned int DFBTextEncodingID; typedef unsigned int DFBWindowID; /* Predefined color ids. */ #define DCID_PRIMARY 0x00000000 /* primary color */ #define DCID_OUTLINE 0x00000001 /* outline color */ /* Predefined display layer ids. */ #define DLID_PRIMARY 0x00000000 /* primary layer */ /* Predefined display layer source ids */ #define DLSID_SURFACE 0x00000000 /* surface layer source */ /* Predefined input device ids. */ #define DIDID_KEYBOARD 0x00000000 /* primary keyboard */ #define DIDID_MOUSE 0x00000001 /* primary mouse */ #define DIDID_JOYSTICK 0x00000002 /* primary joystick */ #define DIDID_REMOTE 0x00000003 /* primary remote control */ #define DIDID_BUTTONS 0x00000004 /* primary buttons */ #define DIDID_ANY 0x00000010 /* no primary device */ /* Predefined screen ids. */ #define DSCID_PRIMARY 0x00000000 /* primary screen */ /* Predefined text encoding ids. */ #define DTEID_UTF8 0x00000000 /* UTF-8 */ #define DTEID_OTHER 0x00000001 /* Other */ /************* * IDirectFB * *************/ /* * The cooperative level controls the main interface's behaviour * in functions like SetVideoMode() or CreateSurface() for the * primary. */ typedef enum { DFSCL_NORMAL = 0x00000000, /* Normal shared access, primary surface will be the buffer of an implicitly created window at the resolution given by SetVideoMode(). */ DFSCL_FULLSCREEN = 0x00000001, /* Application grabs the primary layer, SetVideoMode() automates layer control. Primary surface is the primary layer surface. */ DFSCL_EXCLUSIVE = 0x00000002 /* All but the primary layer will be disabled, the application has full control over layers if desired, other applications have no input/output/control. Primary surface is the primary layer surface. */ } DFBCooperativeLevel; /* * Mask of accelerated functions. */ typedef enum { DFXL_NONE = 0x00000000, /* None of these. */ DFXL_FILLRECTANGLE = 0x00000001, /* FillRectangle() is accelerated. */ DFXL_DRAWRECTANGLE = 0x00000002, /* DrawRectangle() is accelerated. */ DFXL_DRAWLINE = 0x00000004, /* DrawLine() is accelerated. */ DFXL_FILLTRIANGLE = 0x00000008, /* FillTriangle() is accelerated. */ DFXL_FILLTRAPEZOID = 0x00000010, /* FillTrapezoids() is accelerated. */ DFXL_FILLQUADRANGLE = 0x00000020, /* FillQuadrangles() is accelerated. */ DFXL_DRAWMONOGLYPH = 0x00001000, /* DrawMonoGlyphs() is accelerated. */ DFXL_BLIT = 0x00010000, /* Blit() is accelerated. */ DFXL_STRETCHBLIT = 0x00020000, /* StretchBlit() is accelerated. */ DFXL_TEXTRIANGLES = 0x00040000, /* TextureTriangles() is accelerated. */ DFXL_BLIT2 = 0x00080000, /* Blit2() is accelerated. */ DFXL_DRAWSTRING = 0x01000000, /* DrawString() is accelerated. */ DFXL_ALL = 0x010F003F, /* All drawing/blitting functions. */ DFXL_ALL_DRAW = 0x0000103F, /* All drawing functions. */ DFXL_ALL_BLIT = 0x010F0000 /* All blitting functions. */ } DFBAccelerationMask; #define DFB_DRAWING_FUNCTION(a) ((a) & 0x0000FFFF) #define DFB_BLITTING_FUNCTION(a) ((a) & 0xFFFF0000) /* * Flags controlling blitting commands. */ typedef enum { DSBLIT_NOFX = 0x00000000, /* uses none of the effects */ DSBLIT_BLEND_ALPHACHANNEL = 0x00000001, /* enables blending and uses alphachannel from source */ DSBLIT_BLEND_COLORALPHA = 0x00000002, /* enables blending and uses alpha value from color */ DSBLIT_COLORIZE = 0x00000004, /* modulates source color with the color's r/g/b values */ DSBLIT_SRC_COLORKEY = 0x00000008, /* don't blit pixels matching the source color key */ DSBLIT_DST_COLORKEY = 0x00000010, /* write to destination only if the destination pixel matches the destination color key */ DSBLIT_SRC_PREMULTIPLY = 0x00000020, /* modulates the source color with the (modulated) source alpha */ DSBLIT_DST_PREMULTIPLY = 0x00000040, /* modulates the dest. color with the dest. alpha */ DSBLIT_DEMULTIPLY = 0x00000080, /* divides the color by the alpha before writing the data to the destination */ DSBLIT_DEINTERLACE = 0x00000100, /* deinterlaces the source during blitting by reading only one field (every second line of full image) scaling it vertically by factor two */ DSBLIT_SRC_PREMULTCOLOR = 0x00000200, /* modulates the source color with the color alpha */ DSBLIT_XOR = 0x00000400, /* bitwise xor the destination pixels with the source pixels after premultiplication */ DSBLIT_INDEX_TRANSLATION = 0x00000800, /* do fast indexed to indexed translation, this flag is mutual exclusive with all others */ DSBLIT_ROTATE180 = 0x00001000, /* rotate the image by 180 degree */ DSBLIT_ROTATE90 = 0x00002000, /* rotate the image by 90 degree */ DSBLIT_ROTATE270 = 0x00004000, /* rotate the image by 270 degree */ DSBLIT_COLORKEY_PROTECT = 0x00010000, /* make sure written pixels don't match color key */ DSBLIT_SRC_COLORKEY_EXTENDED = 0x00020000, /* use extended source color key */ DSBLIT_DST_COLORKEY_EXTENDED = 0x00040000, /* use extended destination color key */ DSBLIT_SRC_MASK_ALPHA = 0x00100000, /* modulate source alpha channel with alpha channel from source mask */ DSBLIT_SRC_MASK_COLOR = 0x00200000, /* modulate source color channels with color channels from source mask */ DSBLIT_FLIP_HORIZONTAL = 0x01000000, /* flip the image horizontally */ DSBLIT_FLIP_VERTICAL = 0x02000000, /* flip the image vertically */ DSBLIT_SRC_COLORMATRIX = 0x08000000, /* use source color matrix setting */ DSBLIT_SRC_CONVOLUTION = 0x10000000 /* use source convolution filter */ } DFBSurfaceBlittingFlags; /* * Flags controlling drawing commands. */ typedef enum { DSDRAW_NOFX = 0x00000000, /* uses none of the effects */ DSDRAW_BLEND = 0x00000001, /* uses alpha from color */ DSDRAW_DST_COLORKEY = 0x00000002, /* write to destination only if the destination pixel matches the destination color key */ DSDRAW_SRC_PREMULTIPLY = 0x00000004, /* multiplies the color's rgb channels by the alpha channel before drawing */ DSDRAW_DST_PREMULTIPLY = 0x00000008, /* modulates the dest. color with the dest. alpha */ DSDRAW_DEMULTIPLY = 0x00000010, /* divides the color by the alpha before writing the data to the destination */ DSDRAW_XOR = 0x00000020 /* bitwise xor the destination pixels with the specified color after premultiplication */ } DFBSurfaceDrawingFlags; #define DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH 40 #define DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH 60 /* * Driver information. */ typedef struct { int major; /* Major version */ int minor; /* Minor version */ char name[DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH]; /* Driver name */ char vendor[DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH]; /* Driver vendor */ } DFBGraphicsDriverInfo; #define DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH 48 #define DFB_GRAPHICS_DEVICE_DESC_VENDOR_LENGTH 64 /* * Description of the graphics device capabilities. */ typedef struct { DFBAccelerationMask acceleration_mask; /* Accelerated functions */ DFBSurfaceBlittingFlags blitting_flags; /* Supported blitting flags */ DFBSurfaceDrawingFlags drawing_flags; /* Supported drawing flags */ unsigned int video_memory; /* Amount of video memory in bytes */ char name[DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH]; /* Device/Chipset name */ char vendor[DFB_GRAPHICS_DEVICE_DESC_VENDOR_LENGTH]; /* Device vendor */ DFBGraphicsDriverInfo driver; /* Device driver information */ } DFBGraphicsDeviceDescription; /* * Flags defining which fields of a DFBSurfaceDescription are * valid. */ typedef enum { DSDESC_NONE = 0x00000000, /* None of these. */ DSDESC_CAPS = 0x00000001, /* caps field is valid. */ DSDESC_WIDTH = 0x00000002, /* width field is valid. */ DSDESC_HEIGHT = 0x00000004, /* height field is valid. */ DSDESC_PIXELFORMAT = 0x00000008, /* pixelformat field is valid. */ DSDESC_PREALLOCATED = 0x00000010, /* Surface uses data that has been preallocated by the application. The field array preallocated has to be set using the first element for the front buffer and eventually the second one for the back buffer. */ DSDESC_PALETTE = 0x00000020, /* Initialize the surfaces palette with the entries specified in the description. */ DSDESC_COLORSPACE = 0x00000040, /* colorspace field is valid. */ DSDESC_RESOURCE_ID = 0x00000100, /* User defined resource id for general purpose surfaces is specified, or resource id of window, layer, user is returned. */ DSDESC_HINTS = 0x00000200, /* Flags for optimized allocation and pixel format selection are set. */ DSDESC_ALL = 0x0000037F /* All of these. */ } DFBSurfaceDescriptionFlags; /* * The surface capabilities. */ typedef enum { DSCAPS_NONE = 0x00000000, /* None of these. */ DSCAPS_PRIMARY = 0x00000001, /* It's the primary surface. */ DSCAPS_SYSTEMONLY = 0x00000002, /* Surface data is permanently stored in system memory. There's no video memory allocation/storage. */ DSCAPS_VIDEOONLY = 0x00000004, /* Surface data is permanently stored in video memory. There's no system memory allocation/storage. */ DSCAPS_GL = 0x00000008, /* Surface data is stored in memory that can be accessed by a GL accelerator. */ DSCAPS_DOUBLE = 0x00000010, /* Surface is double buffered. */ DSCAPS_SUBSURFACE = 0x00000020, /* Surface is just a sub area of another one sharing the surface data. */ DSCAPS_INTERLACED = 0x00000040, /* Each buffer contains interlaced video (or graphics) data consisting of two fields. Their lines are stored interleaved. One field's height is a half of the surface's height. */ DSCAPS_SEPARATED = 0x00000080, /* For usage with DSCAPS_INTERLACED. DSCAPS_SEPARATED specifies that the fields are not interleaved line by line in the buffer. The first field is followed by the second one. */ DSCAPS_STATIC_ALLOC = 0x00000100, /* The amount of video or system memory allocated for the surface is never less than its initial value. This way a surface can be resized (smaller and bigger up to the initial size) without reallocation of the buffers. It's useful for surfaces that need a guaranteed space in video memory after resizing. */ DSCAPS_TRIPLE = 0x00000200, /* Surface is triple buffered. */ DSCAPS_PREMULTIPLIED = 0x00001000, /* Surface stores data with premultiplied alpha. */ DSCAPS_DEPTH = 0x00010000, /* A depth buffer is allocated. */ DSCAPS_STEREO = 0x00020000, /* Both left & right buffers are allocated. Only valid with windows and layers with the DLOP_STEREO or DWCAPS_STEREO flags set. */ DSCAPS_SHARED = 0x00100000, /* The surface will be accessible among processes. */ DSCAPS_ROTATED = 0x01000000, /* The back buffers are allocated with swapped width/height. */ DSCAPS_ALL = 0x011113FF, /* All of these. */ DSCAPS_FLIPPING = DSCAPS_DOUBLE | DSCAPS_TRIPLE /* Surface needs Flip() calls to make updates/changes visible/usable. */ } DFBSurfaceCapabilities; /* * Encodes pixel format constants in the following way (bit 31 - 0): * * lkjj:hhgg | gfff:eeed | cccc:bbbb | baaa:aaaa * * a) pixelformat index * b) effective color (or index) bits per pixel of format * c) effective alpha bits per pixel of format * d) alpha channel present * e) bytes per "pixel in a row" (1/8 fragment, i.e. bits) * f) bytes per "pixel in a row" (decimal part, i.e. bytes) * g) smallest number of pixels aligned to byte boundary * h) multiplier for planes minus one (1/4 fragment) * j) multiplier for planes minus one (decimal part) * k) color and/or alpha lookup table present * l) alpha channel is inverted */ #define DFB_SURFACE_PIXELFORMAT(index,color_bits, \ alpha_bits,has_alpha, \ row_bits,row_bytes, \ align,mul_f,mul_d, \ has_lut,inv_alpha) \ ( (((index ) & 0x7F) ) | \ (((color_bits) & 0x1F) << 7) | \ (((alpha_bits) & 0x0F) << 12) | \ (((has_alpha ) ? 1 :0) << 16) | \ (((row_bits ) & 0x07) << 17) | \ (((row_bytes ) & 0x07) << 20) | \ (((align ) & 0x07) << 23) | \ (((mul_f ) & 0x03) << 26) | \ (((mul_d ) & 0x03) << 28) | \ (((has_lut ) ? 1 :0) << 30) | \ (((inv_alpha ) ? 1 :0) << 31) ) /* * Pixel format of a surface. */ typedef enum { /* unknown or unspecified format */ DSPF_UNKNOWN = 0x00000000, /* 16 bit ARGB (2 byte, alpha 1@15, red 5@10, green 5@5, blue 5@0) */ DSPF_ARGB1555 = DFB_SURFACE_PIXELFORMAT( 0, 15, 1, 1, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit RGB (2 byte, red 5@11, green 6@5, blue 5@0) */ DSPF_RGB16 = DFB_SURFACE_PIXELFORMAT( 1, 16, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 24 bit RGB (3 byte, red 8@16, green 8@8, blue 8@0) */ DSPF_RGB24 = DFB_SURFACE_PIXELFORMAT( 2, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0 ), /* 24 bit RGB (4 byte, nothing@24, red 8@16, green 8@8, blue 8@0) */ DSPF_RGB32 = DFB_SURFACE_PIXELFORMAT( 3, 24, 0, 0, 0, 4, 0, 0, 0, 0, 0 ), /* 32 bit ARGB (4 byte, alpha 8@24, red 8@16, green 8@8, blue 8@0) */ DSPF_ARGB = DFB_SURFACE_PIXELFORMAT( 4, 24, 8, 1, 0, 4, 0, 0, 0, 0, 0 ), /* 8 bit alpha (1 byte, alpha 8@0), e.g. anti-aliased glyphs */ DSPF_A8 = DFB_SURFACE_PIXELFORMAT( 5, 0, 8, 1, 0, 1, 0, 0, 0, 0, 0 ), /* 16 bit YUV (4 byte/ 2 pixel, macropixel contains CbYCrY [31:0]) */ DSPF_YUY2 = DFB_SURFACE_PIXELFORMAT( 6, 16, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 8 bit RGB (1 byte, red 3@5, green 3@2, blue 2@0) */ DSPF_RGB332 = DFB_SURFACE_PIXELFORMAT( 7, 8, 0, 0, 0, 1, 0, 0, 0, 0, 0 ), /* 16 bit YUV (4 byte/ 2 pixel, macropixel contains YCbYCr [31:0]) */ DSPF_UYVY = DFB_SURFACE_PIXELFORMAT( 8, 16, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 12 bit YUV (8 bit Y plane followed by quarter-size 8 bit U/V planes) */ DSPF_I420 = DFB_SURFACE_PIXELFORMAT( 9, 12, 0, 0, 0, 1, 0, 2, 0, 0, 0 ), /* 12 bit YUV (8 bit Y plane followed by quarter-size 8 bit V/U planes) */ DSPF_YV12 = DFB_SURFACE_PIXELFORMAT( 10, 12, 0, 0, 0, 1, 0, 2, 0, 0, 0 ), /* 8 bit LUT (8 bit color and alpha lookup from palette) */ DSPF_LUT8 = DFB_SURFACE_PIXELFORMAT( 11, 8, 0, 1, 0, 1, 0, 0, 0, 1, 0 ), /* 8 bit ALUT (1 byte, alpha 4@4, color lookup 4@0) */ DSPF_ALUT44 = DFB_SURFACE_PIXELFORMAT( 12, 4, 4, 1, 0, 1, 0, 0, 0, 1, 0 ), /* 32 bit ARGB (4 byte, inv. alpha 8@24, red 8@16, green 8@8, blue 8@0) */ DSPF_AiRGB = DFB_SURFACE_PIXELFORMAT( 13, 24, 8, 1, 0, 4, 0, 0, 0, 0, 1 ), /* 1 bit alpha (1 byte/ 8 pixel, most significant bit used first) */ DSPF_A1 = DFB_SURFACE_PIXELFORMAT( 14, 0, 1, 1, 1, 0, 7, 0, 0, 0, 0 ), /* 12 bit YUV (8 bit Y plane followed by quarter-size 16 bit Cb|Cr [7:0|7:0] plane) */ DSPF_NV12 = DFB_SURFACE_PIXELFORMAT( 15, 12, 0, 0, 0, 1, 0, 2, 0, 0, 0 ), /* 16 bit YUV (8 bit Y plane followed by half-size 16 bit Cb|Cr [7:0|7:0] plane) */ DSPF_NV16 = DFB_SURFACE_PIXELFORMAT( 16, 16, 0, 0, 0, 1, 0, 0, 1, 0, 0 ), /* 16 bit ARGB (2 byte, alpha 2@14, red 5@9, green 5@4, blue 4@0) */ DSPF_ARGB2554 = DFB_SURFACE_PIXELFORMAT( 17, 14, 2, 1, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit ARGB (2 byte, alpha 4@12, red 4@8, green 4@4, blue 4@0) */ DSPF_ARGB4444 = DFB_SURFACE_PIXELFORMAT( 18, 12, 4, 1, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit RGBA (2 byte, red 4@12, green 4@8, blue 4@4, alpha 4@0) */ DSPF_RGBA4444 = DFB_SURFACE_PIXELFORMAT( 19, 12, 4, 1, 0, 2, 0, 0, 0, 0, 0 ), /* 12 bit YUV (8 bit Y plane followed by quarter-size 16 bit Cr|Cb [7:0|7:0] plane) */ DSPF_NV21 = DFB_SURFACE_PIXELFORMAT( 20, 12, 0, 0, 0, 1, 0, 2, 0, 0, 0 ), /* 32 bit AYUV (4 byte, alpha 8@24, Y 8@16, Cb 8@8, Cr 8@0) */ DSPF_AYUV = DFB_SURFACE_PIXELFORMAT( 21, 24, 8, 1, 0, 4, 0, 0, 0, 0, 0 ), /* 4 bit alpha (1 byte/ 2 pixel, more significant nibble used first) */ DSPF_A4 = DFB_SURFACE_PIXELFORMAT( 22, 0, 4, 1, 4, 0, 1, 0, 0, 0, 0 ), /* 1 bit alpha (3 byte, alpha 1@18, red 6@12, green 6@6, blue 6@0) */ DSPF_ARGB1666 = DFB_SURFACE_PIXELFORMAT( 23, 18, 1, 1, 0, 3, 0, 0, 0, 0, 0 ), /* 6 bit alpha (3 byte, alpha 6@18, red 6@12, green 6@6, blue 6@0) */ DSPF_ARGB6666 = DFB_SURFACE_PIXELFORMAT( 24, 18, 6, 1, 0, 3, 0, 0, 0, 0, 0 ), /* 24 bit RGB (3 byte, nothing @18, red 6@12, green 6@6, blue 6@0) */ DSPF_RGB18 = DFB_SURFACE_PIXELFORMAT( 25, 18, 0, 0, 0, 3, 0, 0, 0, 0, 0 ), /* 2 bit LUT (1 byte/ 4 pixel, 2 bit color and alpha lookup from palette) */ DSPF_LUT2 = DFB_SURFACE_PIXELFORMAT( 26, 2, 0, 1, 2, 0, 3, 0, 0, 1, 0 ), /* 16 bit RGB (2 byte, nothing @12, red 4@8, green 4@4, blue 4@0) */ DSPF_RGB444 = DFB_SURFACE_PIXELFORMAT( 27, 12, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit RGB (2 byte, nothing @15, red 5@10, green 5@5, blue 5@0) */ DSPF_RGB555 = DFB_SURFACE_PIXELFORMAT( 28, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit BGR (2 byte, nothing @15, blue 5@10, green 5@5, red 5@0) */ DSPF_BGR555 = DFB_SURFACE_PIXELFORMAT( 29, 15, 0, 0, 0, 2, 0, 0, 0, 0, 0 ), /* 16 bit RGBA (2 byte, red 5@11, green 5@6, blue 5@1, alpha 1@0) */ DSPF_RGBA5551 = DFB_SURFACE_PIXELFORMAT( 30, 15, 1, 1, 0, 2, 0, 0, 0, 0, 0 ), /* 24 bit YUV (8 bit Y plane followed by 8 bit U/V planes) */ DSPF_Y444 = DFB_SURFACE_PIXELFORMAT( 31, 24, 0, 0, 0, 1, 0, 0, 2, 0, 0 ), /* 24 bit ARGB (3 byte, alpha 8@16, red 5@11, green 6@5, blue 5@0) */ DSPF_ARGB8565 = DFB_SURFACE_PIXELFORMAT( 32, 16, 8, 1, 0, 3, 0, 0, 0, 0, 0 ), /* 32 bit AVYU (4 byte, alpha 8@24, Cr 8@16, Y 8@8, Cb 8@0) */ DSPF_AVYU = DFB_SURFACE_PIXELFORMAT( 33, 24, 8, 1, 0, 4, 0, 0, 0, 0, 0 ), /* 24 bit VYU (3 byte, Cr 8@16, Y 8@8, Cb 8@0) */ DSPF_VYU = DFB_SURFACE_PIXELFORMAT( 34, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0 ), /* 1 bit alpha (1 byte/ 8 pixel, least significant bit used first) */ DSPF_A1_LSB = DFB_SURFACE_PIXELFORMAT( 35, 0, 1, 1, 1, 0, 7, 0, 0, 0, 0 ), /* 16 bit YUV (8 bit Y plane followed by half-size 8 bit V/U planes) */ DSPF_YV16 = DFB_SURFACE_PIXELFORMAT( 36, 16, 0, 0, 0, 1, 0, 0, 1, 0, 0 ), /* 32 bit ABGR (4 byte, alpha 8@24, blue 8@16, green 8@8, red 8@0) */ DSPF_ABGR = DFB_SURFACE_PIXELFORMAT( 37, 24, 8, 1, 0, 4, 0, 0, 0, 0, 0 ), /* 32 bit RGBAF (4 byte, red 8@24, green 8@16, blue 8@8, alpha 7@1, flash 1@0 */ DSPF_RGBAF88871 = DFB_SURFACE_PIXELFORMAT( 38, 24, 7, 1, 0, 4, 0, 0, 0, 0, 0 ), /* 4 bit LUT (1 byte/ 2 pixel, 4 bit color and alpha lookup from palette) */ DSPF_LUT4 = DFB_SURFACE_PIXELFORMAT( 39, 4, 0, 1, 4, 0, 1, 0, 0, 1, 0 ), /* 16 bit LUT (1 byte alpha and 8 bit color lookup from palette) */ DSPF_ALUT8 = DFB_SURFACE_PIXELFORMAT( 40, 8, 8, 1, 0, 2, 0, 0, 0, 1, 0 ), /* 1 bit LUT (1 byte/ 8 pixel, 1 bit color and alpha lookup from palette) */ DSPF_LUT1 = DFB_SURFACE_PIXELFORMAT( 41, 1, 0, 1, 1, 0, 7, 0, 0, 1, 0 ), /* 16 bit YUV (8 bit Y plane followed by half-size 16 bit Cr|Cb [7:0|7:0] plane) */ DSPF_NV61 = DFB_SURFACE_PIXELFORMAT( 42, 16, 0, 0, 0, 1, 0, 0, 1, 0, 0 ), /* 16 bit YUV (8 bit Y plane followed by half-size 8 bit U/V planes) */ DSPF_Y42B = DFB_SURFACE_PIXELFORMAT( 43, 16, 0, 0, 0, 1, 0, 0, 1, 0, 0 ), /* 24 bit YUV (8 bit Y plane followed by 8 bit V/U planes) */ DSPF_YV24 = DFB_SURFACE_PIXELFORMAT( 44, 24, 0, 0, 0, 1, 0, 0, 2, 0, 0 ), /* 24 bit YUV (8 bit Y plane followed by 16 bit Cb|Cr [7:0|7:0] plane) */ DSPF_NV24 = DFB_SURFACE_PIXELFORMAT( 45, 24, 0, 0, 0, 1, 0, 0, 2, 0, 0 ), /* 24 bit YUV (8 bit Y plane followed by 16 bit Cr|Cb [7:0|7:0] plane) */ DSPF_NV42 = DFB_SURFACE_PIXELFORMAT( 46, 24, 0, 0, 0, 1, 0, 0, 2, 0, 0 ), /* 24 bit BGR (3 byte, blue 8@16, green 8@8, red 8@0) */ DSPF_BGR24 = DFB_SURFACE_PIXELFORMAT( 47, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0 ) } DFBSurfacePixelFormat; #define DSPF_YUV420P DSPF_I420 #define DSPF_YUV422P DSPF_Y42B #define DSPF_YUV444P DSPF_Y444 /* Number of pixelformats defined. */ #define DFB_NUM_PIXELFORMATS 48 /* These macros extract information about the pixel format. */ #define DFB_PIXELFORMAT_INDEX(fmt) ((fmt) & 0x0000007F) #define DFB_COLOR_BITS_PER_PIXEL(fmt) (((fmt) & 0x00000F80) >> 7) #define DFB_ALPHA_BITS_PER_PIXEL(fmt) (((fmt) & 0x0000F000) >> 12) #define DFB_PIXELFORMAT_HAS_ALPHA(fmt) (((fmt) & 0x00010000) != 0) #define DFB_BITS_PER_PIXEL(fmt) (((fmt) & 0x007E0000) >> 17) #define DFB_BYTES_PER_PIXEL(fmt) (((fmt) & 0x00700000) >> 20) #define DFB_BYTES_PER_LINE(fmt,width) (((((fmt) & 0x007E0000) >> 17) * (width) + 7) >> 3) #define DFB_PIXELFORMAT_ALIGNMENT(fmt) (((fmt) & 0x03800000) >> 23) #define DFB_PLANE_MULTIPLY(fmt,height) ((((((fmt) & 0x3C000000) >> 26) + 4) * (height)) >> 2) #define DFB_PIXELFORMAT_IS_INDEXED(fmt) (((fmt) & 0x40000000) != 0) #define DFB_PLANAR_PIXELFORMAT(fmt) (((fmt) & 0x3C000000) != 0) #define DFB_PIXELFORMAT_INV_ALPHA(fmt) (((fmt) & 0x80000000) != 0) #define DFB_COLOR_IS_RGB(fmt) \ (((fmt) == DSPF_ARGB1555) || \ ((fmt) == DSPF_RGB16) || \ ((fmt) == DSPF_RGB24) || \ ((fmt) == DSPF_RGB32) || \ ((fmt) == DSPF_ARGB) || \ ((fmt) == DSPF_RGB332) || \ ((fmt) == DSPF_AiRGB) || \ ((fmt) == DSPF_ARGB2554) || \ ((fmt) == DSPF_ARGB4444) || \ ((fmt) == DSPF_RGBA4444) || \ ((fmt) == DSPF_ARGB1666) || \ ((fmt) == DSPF_ARGB6666) || \ ((fmt) == DSPF_RGB18) || \ ((fmt) == DSPF_RGB444) || \ ((fmt) == DSPF_RGB555) || \ ((fmt) == DSPF_BGR555) || \ ((fmt) == DSPF_ARGB8565) || \ ((fmt) == DSPF_ABGR) || \ ((fmt) == DSPF_RGBAF88871) || \ ((fmt) == DSPF_BGR24)) #define DFB_COLOR_IS_YUV(fmt) \ (((fmt) == DSPF_YUY2) || \ ((fmt) == DSPF_UYVY) || \ ((fmt) == DSPF_I420) || \ ((fmt) == DSPF_YV12) || \ ((fmt) == DSPF_NV12) || \ ((fmt) == DSPF_NV16) || \ ((fmt) == DSPF_NV21) || \ ((fmt) == DSPF_AYUV) || \ ((fmt) == DSPF_Y444) || \ ((fmt) == DSPF_AVYU) || \ ((fmt) == DSPF_VYU) || \ ((fmt) == DSPF_YV16) || \ ((fmt) == DSPF_NV61) || \ ((fmt) == DSPF_Y42B) || \ ((fmt) == DSPF_YV24) || \ ((fmt) == DSPF_NV24) || \ ((fmt) == DSPF_NV42)) /* * Hint flags for optimized allocation, format selection etc. */ typedef enum { DSHF_NONE = 0x00000000, /* None of these. */ DSHF_LAYER = 0x00000001, /* Surface optimized for display layer usage. */ DSHF_WINDOW = 0x00000002, /* Surface optimized for being a window buffer. */ DSHF_CURSOR = 0x00000004, /* Surface optimized for usage as a cursor shape. */ DSHF_FONT = 0x00000008, /* Surface optimized for text rendering. */ DSHF_ALL = 0x0000000F /* All of these. */ } DFBSurfaceHintFlags; /* * Color space used by the colors in the surface. */ typedef enum { DSCS_UNKNOWN = 0x00000000, /* unknown color space */ DSCS_RGB = 0x00000001, /* standard RGB */ DSCS_BT601 = 0x00000002, /* ITU BT.601 */ DSCS_BT709 = 0x00000004, /* ITU BT.709 */ DSCS_BT2020 = 0x00000005 /* ITU BT.2020 */ } DFBSurfaceColorSpace; #define DFB_COLORSPACE_IS_COMPATIBLE(cs,fmt) \ ((DFB_COLOR_IS_RGB((fmt)) && ((cs) == DSCS_RGB)) || \ (DFB_COLOR_IS_YUV((fmt)) && (((cs) == DSCS_BT601) || \ ((cs) == DSCS_BT709) || \ ((cs) == DSCS_BT2020)))) #define DFB_COLORSPACE_DEFAULT(fmt) \ (DFB_COLOR_IS_RGB((fmt)) ? DSCS_RGB : DFB_COLOR_IS_YUV((fmt)) ? DSCS_BT601 : DSCS_UNKNOWN) /* * Description of the surface that is to be created. */ typedef struct { DFBSurfaceDescriptionFlags flags; /* field validation */ DFBSurfaceCapabilities caps; /* capabilities */ int width; /* pixel width */ int height; /* pixel height */ DFBSurfacePixelFormat pixelformat; /* pixel format */ struct { void *data; /* data pointer of existing buffer */ int pitch; /* pitch of buffer */ } preallocated[3]; /* preallocated data */ struct { const DFBColor *entries; /* palette entries */ unsigned int size; /* number of entries */ } palette; /* initial palette */ unsigned long resource_id; /* universal resource id, either user specified for general purpose surfaces or id of layer or window */ DFBSurfaceHintFlags hints; /* usage hints for optimized allocation, format selection, etc */ DFBSurfaceColorSpace colorspace; /* color space */ } DFBSurfaceDescription; /* * Flags defining which fields of a DFBPaletteDescription are * valid. */ typedef enum { DPDESC_CAPS = 0x00000001, /* Specify palette capabilities. */ DPDESC_SIZE = 0x00000002, /* Specify number of entries. */ DPDESC_ENTRIES = 0x00000004, /* Initialize the palette with the entries specified in the description. */ DPDESC_COLORSPACE = 0x00000008 /* Specify palette color space. */ } DFBPaletteDescriptionFlags; /* * The palette capabilities. */ typedef enum { DPCAPS_NONE = 0x00000000 /* None of these. */ } DFBPaletteCapabilities; /* * Description of the palette that is to be created. */ typedef struct { DFBPaletteDescriptionFlags flags; /* Validation of fields. */ DFBPaletteCapabilities caps; /* Palette capabilities. */ unsigned int size; /* Number of entries. */ const DFBColor *entries; /* Preset palette entries. */ DFBSurfaceColorSpace colorspace; /* Palette color space. */ } DFBPaletteDescription; /* * Capabilities of a screen. */ typedef enum { DSCCAPS_NONE = 0x00000000, /* None of these. */ DSCCAPS_VSYNC = 0x00000001, /* Synchronization with the vertical retrace supported. */ DSCCAPS_POWER_MANAGEMENT = 0x00000002, /* Power management supported. */ DSCCAPS_MIXERS = 0x00000010, /* Has mixers. */ DSCCAPS_ENCODERS = 0x00000020, /* Has encoders. */ DSCCAPS_OUTPUTS = 0x00000040, /* Has outputs. */ DSCCAPS_ALL = 0x00000073 /* All of these. */ } DFBScreenCapabilities; #define DFB_SCREEN_DESC_NAME_LENGTH 32 /* * Description of the display encoder capabilities. */ typedef struct { DFBScreenCapabilities caps; /* Capability flags of the screen. */ char name[DFB_SCREEN_DESC_NAME_LENGTH]; /* Rough description. */ int mixers; /* Number of mixers available. */ int encoders; /* Number of display encoders available. */ int outputs; /* Number of output connectors available. */ } DFBScreenDescription; /* * Type of display layer for basic classification. */ typedef enum { DLTF_NONE = 0x00000000, /* Unclassified, no specific type. */ DLTF_GRAPHICS = 0x00000001, /* Can be used for graphics output. */ DLTF_VIDEO = 0x00000002, /* Can be used for live video output.*/ DLTF_STILL_PICTURE = 0x00000004, /* Can be used for single frames. */ DLTF_BACKGROUND = 0x00000008, /* Can be used as a background layer.*/ DLTF_ALL = 0x0000000F /* All type flags set. */ } DFBDisplayLayerTypeFlags; /* * Capabilities of a display layer. */ typedef enum { DLCAPS_NONE = 0x00000000, /* None of these. */ DLCAPS_SURFACE = 0x00000001, /* The layer has a surface that can be drawn to. This may not be provided by layers that display realtime data, e.g. from an MPEG decoder chip. Playback control may be provided by an external API. */ DLCAPS_OPACITY = 0x00000002, /* The layer supports blending with layer(s) below based on a global alpha factor. */ DLCAPS_ALPHACHANNEL = 0x00000004, /* The layer supports blending with layer(s) below based on each pixel's alpha value. */ DLCAPS_SCREEN_LOCATION = 0x00000008, /* The layer location on the screen can be changed, this includes position and size as normalized values. This implies DLCAPS_SCREEN_POSITION and _SIZE. */ DLCAPS_FLICKER_FILTERING = 0x00000010, /* Flicker filtering can be enabled for smooth output on interlaced display devices. */ DLCAPS_DEINTERLACING = 0x00000020, /* The layer provides optional deinterlacing for displaying interlaced video data on progressive display devices. */ DLCAPS_SRC_COLORKEY = 0x00000040, /* A specific color can be declared as transparent. */ DLCAPS_DST_COLORKEY = 0x00000080, /* A specific color of layers below can be specified as the color of the only locations where the layer is visible. */ DLCAPS_BRIGHTNESS = 0x00000100, /* Adjustment of brightness is supported. */ DLCAPS_CONTRAST = 0x00000200, /* Adjustment of contrast is supported. */ DLCAPS_HUE = 0x00000400, /* Adjustment of hue is supported. */ DLCAPS_SATURATION = 0x00000800, /* Adjustment of saturation is supported. */ DLCAPS_LEVELS = 0x00001000, /* Adjustment of the layer's level (z position) is supported. */ DLCAPS_FIELD_PARITY = 0x00002000, /* Field parity can be selected */ DLCAPS_WINDOWS = 0x00004000, /* Hardware window support. */ DLCAPS_SOURCES = 0x00008000, /* Sources can be selected. */ DLCAPS_ALPHA_RAMP = 0x00010000, /* Alpha values for formats with one or two alpha bits can be chosen, i.e. using ARGB1555 or ARGB2554 the user can define the meaning of the two or four possibilities. In short, this feature provides a lookup table for the alpha bits of these formats. */ DLCAPS_PREMULTIPLIED = 0x00020000, /* Surfaces with premultiplied alpha are supported. */ DLCAPS_SCREEN_POSITION = 0x00100000, /* The layer position on the screen can be changed. */ DLCAPS_SCREEN_SIZE = 0x00200000, /* The layer size (defined by its source rectangle) can be scaled to a different size on the screen (defined by its screen/destination rectangle or its normalized size) and does not have to be 1:1 with it. */ DLCAPS_CLIP_REGIONS = 0x00400000, /* Supports SetClipRegions(). */ DLCAPS_LR_MONO = 0x01000000, /* Supports L/R mono stereoscopic display. */ DLCAPS_STEREO = 0x02000000, /* Supports independent L/R stereoscopic display. */ DLCAPS_ALL = 0x0373FFFF /* All of these. */ } DFBDisplayLayerCapabilities; #define DFB_DISPLAY_LAYER_DESC_NAME_LENGTH 32 /* * Description of the display layer capabilities. */ typedef struct { DFBDisplayLayerTypeFlags type; /* Classification of the display layer. */ DFBDisplayLayerCapabilities caps; /* Capability flags of the display layer. */ char name[DFB_DISPLAY_LAYER_DESC_NAME_LENGTH]; /* Display layer name. */ int level; /* Default level. */ int regions; /* Number of concurrent regions supported: -1 = unlimited, 0 = unknown/one, >0 = actual number */ int sources; /* Number of selectable sources. */ int clip_regions; /* Number of clipping regions. */ DFBSurfaceCapabilities surface_caps; /* Capabilities. */ unsigned int surface_accessor; /* Accessor. */ } DFBDisplayLayerDescription; /* * Type of input device for basic classification. */ typedef enum { DIDTF_NONE = 0x00000000, /* Unclassified, no specific type. */ DIDTF_KEYBOARD = 0x00000001, /* Is a keyboard. */ DIDTF_MOUSE = 0x00000002, /* Is a mouse. */ DIDTF_JOYSTICK = 0x00000004, /* Is a joystick. */ DIDTF_REMOTE = 0x00000008, /* Is a remote control. */ DIDTF_VIRTUAL = 0x00000010, /* Is a virtual input device. */ DIDTF_BUTTONS = 0x00000020, /* Is buttons. */ DIDTF_ALL = 0x0000003F /* All type flags set. */ } DFBInputDeviceTypeFlags; /* * Basic input device features. */ typedef enum { DICAPS_KEYS = 0x00000001, /* device supports key events */ DICAPS_AXES = 0x00000002, /* device supports axis events */ DICAPS_BUTTONS = 0x00000004, /* device supports button events */ DICAPS_ALL = 0x00000007 /* all capabilities */ } DFBInputDeviceCapabilities; /* * Axis identifier (index) for mouse or joystick. * * The X, Y and Z axis are predefined. To access other axes, * use DIAI_FIRST plus a zero based index, e.g. the 4th axis * would be (DIAI_FIRST + 3). */ typedef enum { DIAI_X = 0x00000000, /* X axis */ DIAI_Y = 0x00000001, /* Y axis */ DIAI_Z = 0x00000002, /* Z axis */ DIAI_FIRST = DIAI_X, /* other axis: DIAI_FIRST + zero based index */ DIAI_LAST = 0x0000001F /* 32 axes maximum */ } DFBInputDeviceAxisIdentifier; /* * Identifier (index) for e.g. mouse or joystick buttons. */ typedef enum { DIBI_LEFT = 0x00000000, /* left mouse button */ DIBI_RIGHT = 0x00000001, /* right mouse button */ DIBI_MIDDLE = 0x00000002, /* middle mouse button */ DIBI_FIRST = DIBI_LEFT, /* other buttons: DIBI_FIRST + zero based index */ DIBI_LAST = 0x0000001F /* 32 buttons maximum */ } DFBInputDeviceButtonIdentifier; #define DFB_INPUT_DEVICE_DESC_NAME_LENGTH 32 #define DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH 40 /* * Description of the input device capabilities. */ typedef struct { DFBInputDeviceTypeFlags type; /* classification of input device */ DFBInputDeviceCapabilities caps; /* capabilities, validates the following fields */ int min_keycode; /* minimum hardware keycode or -1 if no differentiation between hardware keys is made */ int max_keycode; /* maximum hardware keycode or -1 if no differentiation between hardware keys is made */ DFBInputDeviceAxisIdentifier max_axis; /* highest axis identifier */ DFBInputDeviceButtonIdentifier max_button; /* highest button identifier */ char name[DFB_INPUT_DEVICE_DESC_NAME_LENGTH]; /* device name */ char vendor[DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH]; /* device vendor */ int vendor_id; /* vendor ID */ int product_id; /* product ID */ } DFBInputDeviceDescription; /* * Flags defining which fields of a DFBFontDescription are * valid. */ typedef enum { DFDESC_ATTRIBUTES = 0x00000001, /* attributes field is valid */ DFDESC_HEIGHT = 0x00000002, /* height is specified */ DFDESC_WIDTH = 0x00000004, /* width is specified */ DFDESC_INDEX = 0x00000008, /* index is specified */ DFDESC_FIXEDADVANCE = 0x00000010, /* specify a fixed advance overriding any character advance of fixed or proportional fonts */ DFDESC_FRACT_HEIGHT = 0x00000020, /* fractional height is set */ DFDESC_FRACT_WIDTH = 0x00000040, /* fractional width is set */ DFDESC_OUTLINE_WIDTH = 0x00000080, /* outline width is set */ DFDESC_OUTLINE_OPACITY = 0x00000100, /* outline opacity is set */ DFDESC_ROTATION = 0x00000200 /* rotation is set */ } DFBFontDescriptionFlags; /* * Flags describing how to load a font. * * These flags describe how a font is loaded and affect how the * glyphs are drawn. There is no way to change this after the * font has been loaded. * If you need to render a font with different attributes, you * have to create multiple FontProviders of the same font file. */ typedef enum { DFFA_NONE = 0x00000000, /* none of these flags */ DFFA_NOKERNING = 0x00000001, /* don't use kerning */ DFFA_NOHINTING = 0x00000002, /* don't use hinting */ DFFA_MONOCHROME = 0x00000004, /* don't use anti-aliasing */ DFFA_NOCHARMAP = 0x00000008, /* no char map, glyph indices are specified directly */ DFFA_FIXEDCLIP = 0x00000010, /* width fixed advance, clip to it */ DFFA_NOBITMAP = 0x00000020, /* ignore bitmap strikes; for bitmap-only fonts this flag is ignored */ DFFA_OUTLINED = 0x00000040, /* outlined font */ DFFA_AUTOHINTING = 0x00000080, /* prefer auto-hinter over the font's native hinter */ DFFA_SOFTHINTING = 0x00000100, /* use a lighter hinting algorithm that produces glyphs that are more fuzzy but better resemble the original shape */ DFFA_STYLE_ITALIC = 0x00000200, /* load italic style */ DFFA_VERTICAL_LAYOUT = 0x00000400, /* load vertical layout */ DFFA_STYLE_BOLD = 0x00000800 /* load bold style */ } DFBFontAttributes; /* * Description of how to load glyphs from a font file. * * The attributes control how the glyphs are rendered. Width and * height can be used to specify the desired face size in * pixels. If you are loading a non-scalable font, you shouldn't * specify a font size. * Please note that the height value in the DFBFontDescription * doesn't correspond to the height returned by GetHeight(). * The index field controls which face is loaded from a font * file that provides a collection of faces. * Fractional sizes (fract_height and fract_width) are 26.6 * fixed point integers and override the pixel sizes if both are * specified. * Outline parameters are ignored if DFFA_OUTLINED is not used. * To change the default values of 1.0 each use * DFDESC_OUTLINE_WIDTH and/or DFDESC_OUTLINE_OPACITY. * The rotation value is a 0.24 fixed point number of rotations. * Use the macros DFB_DEGREES and DFB_RADIANS to convert from * those units. */ typedef struct { DFBFontDescriptionFlags flags; /* field validation */ DFBFontAttributes attributes; /* font attributes */ int height; /* font height */ int width; /* font width */ unsigned int index; /* font index */ int fixed_advance; /* fixed advance */ int fract_height; /* fractional height */ int fract_width; /* fractional width */ int outline_width; /* outline width as 16.16 fixed point integer */ int outline_opacity; /* outline opacity as 16.16 fixed point integer */ int rotation; /* font rotation */ } DFBFontDescription; /* * Flags defining which fields of a DFBDataBufferDescription are * valid. */ typedef enum { DBDESC_FILE = 0x00000001, /* Create a static buffer for the specified filename. */ DBDESC_MEMORY = 0x00000002 /* Create a static buffer for the specified memory area. */ } DFBDataBufferDescriptionFlags; /* * Description of a data buffer that is to be created. */ typedef struct { DFBDataBufferDescriptionFlags flags; /* field validation */ const char *file; /* for file based data buffers */ struct { const void *data; /* static data pointer */ unsigned int length; /* length of buffer */ } memory; /* memory based buffers */ } DFBDataBufferDescription; /* * Called for each supported video mode. */ typedef DFBEnumerationResult (*DFBVideoModeCallback) ( int width, int height, int bpp, void *callbackdata ); /* * Called for each existing screen. * 'screen_id' can be used to get an interface to the screen. */ typedef DFBEnumerationResult (*DFBScreenCallback) ( DFBScreenID screen_id, DFBScreenDescription desc, void *callbackdata ); /* * Called for each existing display layer. * 'layer_id' can be used to get an interface to the layer. */ typedef DFBEnumerationResult (*DFBDisplayLayerCallback) ( DFBDisplayLayerID layer_id, DFBDisplayLayerDescription desc, void *callbackdata ); /* * Called for each existing input device. * 'device_id' can be used to get an interface to the device. */ typedef DFBEnumerationResult (*DFBInputDeviceCallback) ( DFBInputDeviceID device_id, DFBInputDeviceDescription desc, void *callbackdata ); /* * IDirectFB is the main interface. It can be retrieved by a * call to DirectFBCreate(). It's the only interface with a * global creation facility. Other interfaces are created by * this interface or interfaces created by it. * * Hardware capabilities such as the amount of video memory or * a list of supported drawing/blitting functions and flags can * be retrieved. It also provides enumeration of all supported * video modes. * * Input devices and display layers> that are present can be * enumerated via a callback mechanism.The callback is given the * capabilities and the device or layer ID. * An interface to specific input devices or display layers * can be retrieved by passing the device or layer ID to the * corresponding method. * * Surfaces for general purpose use can be created via * CreateSurface(). These surfaces are so called "offscreen * surfaces" and could be used for sprites or icons. * * The primary surface is an abstraction and API shortcut for * getting a surface for visual output. Fullscreen games for * example have the whole screen as their primary surface. * Alternatively fullscreen applications can be forced to run * in a window. The primary surface is also created via * CreateSurface() but with the special capability * DSCAPS_PRIMARY. * * The cooperative level selects the type of the primary * surface. With a call to SetCooperativeLevel() the * application can choose between the surface of an implicitly * created window and the surface of the primary layer * (deactivating the window stack). The application doesn't need * to have any extra functionality to run in a window. If the * application is forced to run in a window the call to * SetCooperativeLevel() fails with DFB_ACCESSDENIED. * Applications that want to be "window aware" shouldn't exit on * this error. * * The video mode can be changed via SetVideoMode() and is the * size and depth of the primary surface, i.e. the * screen when * in exclusive cooperative level. * Without exclusive access SetVideoMode() sets the size of the * implicitly created window. * * Event buffers can be created with an option to automatically * attach input devices matching the specified capabilities. * If DICAPS_NONE is passed, an event buffer with nothing * attached to is created. An event buffer can be attached to * input devices and windows. * * Fonts, images and videos are created by this interface. There * are different implementations for different content types. On * creation a suitable implementation is automatically chosen. */ D_DEFINE_INTERFACE( IDirectFB, /** Cooperative level, video mode **/ /* * Put the interface into the specified cooperative level. * * Function fails with DFB_LOCKED if another instance is * already in a cooperative level other than DFSCL_NORMAL. */ DFBResult (*SetCooperativeLevel) ( IDirectFB *thiz, DFBCooperativeLevel level ); /* * Switch the current video mode (primary layer). * * If in shared cooperative level this function sets the * resolution of the window that is created implicitly for * the primary surface. * The following values are valid for bpp: * 2, 8, 12, 14, 15, 18, 24, 32. * These will result in the following formats, respectively * DSPF_LUT2, DSPF_LUT8, DSPF_ARGB4444, DSPF_ARGB2554, * DSPF_ARGB1555, DSPF_RGB16, DSPF_RGB18, DSPF_RGB24, * DSPF_RGB32. */ DFBResult (*SetVideoMode) ( IDirectFB *thiz, int width, int height, int bpp ); /** Hardware capabilities **/ /* * Get a description of the graphics device. * * For more detailed information use GetAccelerationMask(). */ DFBResult (*GetDeviceDescription) ( IDirectFB *thiz, DFBGraphicsDeviceDescription *ret_desc ); /* * Enumerate supported video modes. * * Calls the given callback for all available video modes. * Useful to select a certain mode to be used with * SetVideoMode(). */ DFBResult (*EnumVideoModes) ( IDirectFB *thiz, DFBVideoModeCallback callback, void *callbackdata ); /** Surfaces & Palettes **/ /* * Create a surface matching the specified description. */ DFBResult (*CreateSurface) ( IDirectFB *thiz, const DFBSurfaceDescription *desc, IDirectFBSurface **ret_interface ); /* * Create a palette matching the specified description. * * Passing a NULL description creates a default palette * with 256 entries filled with colors matching the * RGB332 format. */ DFBResult (*CreatePalette) ( IDirectFB *thiz, const DFBPaletteDescription *desc, IDirectFBPalette **ret_interface ); /** Screens **/ /* * Enumerate all existing screen. * * Calls the given callback for each available screen. * The callback is passed the screen id that can be used * to retrieve an interface to a specific screen using * GetScreen(). */ DFBResult (*EnumScreens) ( IDirectFB *thiz, DFBScreenCallback callback, void *callbackdata ); /* * Retrieve an interface to a specific screen. */ DFBResult (*GetScreen) ( IDirectFB *thiz, DFBScreenID screen_id, IDirectFBScreen **ret_interface ); /** Display Layers **/ /* * Enumerate all existing display layers. * * Calls the given callback for each available display * layer. The callback is passed the layer id that can be * used to retrieve an interface to a specific layer using * GetDisplayLayer(). */ DFBResult (*EnumDisplayLayers) ( IDirectFB *thiz, DFBDisplayLayerCallback callback, void *callbackdata ); /* * Retrieve an interface to a specific display layer. * * The default 'layer_id' is DLID_PRIMARY. * Others can be obtained using EnumDisplayLayers(). */ DFBResult (*GetDisplayLayer) ( IDirectFB *thiz, DFBDisplayLayerID layer_id, IDirectFBDisplayLayer **ret_interface ); /** Input Devices **/ /* * Enumerate all existing input devices. * * Calls the given callback for all available input * devices. * The callback is passed the device id that can be used to * retrieve an interface on a specific device using * GetInputDevice(). */ DFBResult (*EnumInputDevices) ( IDirectFB *thiz, DFBInputDeviceCallback callback, void *callbackdata ); /* * Retrieve an interface to a specific input device. */ DFBResult (*GetInputDevice) ( IDirectFB *thiz, DFBInputDeviceID device_id, IDirectFBInputDevice **ret_interface ); /* * Create a buffer for events. * * Creates an empty event buffer without event sources * connected to it. */ DFBResult (*CreateEventBuffer) ( IDirectFB *thiz, IDirectFBEventBuffer **ret_interface ); /* * Create a buffer for events with input devices connected. * * Creates an event buffer and attaches all input devices * with matching capabilities. If no input devices match, * e.g. by specifying DICAPS_NONE, a buffer will be * returned that has no event sources connected to it. * If 'global' is DFB_FALSE, events will only be delivered * if this instance of IDirectFB has a focused primary * (either running fullscreen or running in windowed mode * with the window being focused). * If 'global' is DFB_TRUE no event will be discarded. */ DFBResult (*CreateInputEventBuffer) ( IDirectFB *thiz, DFBInputDeviceCapabilities caps, DFBBoolean global, IDirectFBEventBuffer **ret_interface ); /** Media **/ /* * Create an image provider for the specified file. */ DFBResult (*CreateImageProvider) ( IDirectFB *thiz, const char *filename, IDirectFBImageProvider **ret_interface ); /* * Create a video provider. */ DFBResult (*CreateVideoProvider) ( IDirectFB *thiz, const char *filename, IDirectFBVideoProvider **ret_interface ); /* * Load a font from the specified file given a description * of how to load the glyphs. */ DFBResult (*CreateFont) ( IDirectFB *thiz, const char *filename, const DFBFontDescription *desc, IDirectFBFont **ret_interface ); /* * Create a data buffer. * * If no description is specified (NULL), a streamed * data buffer is created. */ DFBResult (*CreateDataBuffer) ( IDirectFB *thiz, const DFBDataBufferDescription *desc, IDirectFBDataBuffer **ret_interface ); /** Clipboard **/ /* * Set clipboard content. */ DFBResult (*SetClipboardData) ( IDirectFB *thiz, const char *mime_type, const void *clip_data, unsigned int size, struct timeval *timestamp ); /* * Get clipboard content. * * Memory returned in '*ret_mimetype' and '*ret_clip_data' * has to be freed. */ DFBResult (*GetClipboardData) ( IDirectFB *thiz, char **ret_mimetype, void **ret_clip_data, unsigned int *ret_size ); /* * Get time stamp of last SetClipboardData() call. */ DFBResult (*GetClipboardTimeStamp) ( IDirectFB *thiz, struct timeval *ret_timestamp ); /** Misc **/ /* * Suspend, no other calls are allowed until Resume() * has been called. */ DFBResult (*Suspend) ( IDirectFB *thiz ); /* * Resume, only to be called after Suspend(). */ DFBResult (*Resume) ( IDirectFB *thiz ); /* * Wait until graphics card is idle, * i.e. finish all drawing/blitting functions. */ DFBResult (*WaitIdle) ( IDirectFB *thiz ); /* * Wait for next vertical retrace. */ DFBResult (*WaitForSync) ( IDirectFB *thiz ); /** Extensions **/ /* * Load an implementation of a specific interface type. * * This methods loads an interface implementation of the * specified 'type' of interface, e.g. "IDirectFBWindows". * A specific implementation can be forced with the * optional 'implementation' argument. * Implementations are passed 'arg' during probing and * construction. * If an implementation has been successfully probed and * the interface has been constructed, the resulting * interface pointer is stored in 'interface'. */ DFBResult (*GetInterface) ( IDirectFB *thiz, const char *type, const char *implementation, void *arg, void **ret_interface ); /** Surfaces **/ /* * Get a surface by ID. */ DFBResult (*GetSurface) ( IDirectFB *thiz, DFBSurfaceID surface_id, IDirectFBSurface **ret_interface ); /* * Get surface pixel format suitable for fonts. */ DFBResult (*GetFontSurfaceFormat) ( IDirectFB *thiz, DFBSurfacePixelFormat *ret_fontformat ); ) /******************* * IDirectFBScreen * *******************/ /* * Screen Power Mode. */ typedef enum { DSPM_ON = 0x00000000, /* On. */ DSPM_STANDBY = 0x00000001, /* Standby. */ DSPM_SUSPEND = 0x00000002, /* Suspend. */ DSPM_OFF = 0x00000003 /* Off. */ } DFBScreenPowerMode; /* * Capabilities of a mixer. */ typedef enum { DSMCAPS_NONE = 0x00000000, /* None of these. */ DSMCAPS_FULL = 0x00000001, /* Can mix full tree as specified in the description. */ DSMCAPS_SUB_LEVEL = 0x00000002, /* Can set a maximum layer level, e.g. to exclude an OSD from VCR output. */ DSMCAPS_SUB_LAYERS = 0x00000004, /* Can select a number of layers individually as specified in the description. */ DSMCAPS_BACKGROUND = 0x00000008 /* Background color is configurable. */ } DFBScreenMixerCapabilities; #define DFB_SCREEN_MIXER_DESC_NAME_LENGTH 24 /* * Description of a mixer. */ typedef struct { DFBScreenMixerCapabilities caps; /* Mixer capabilities. */ DFBDisplayLayerIDs layers; /* Visible layers if the full tree is selected. */ int sub_num; /* Number of layers that can be selected in sub mode. */ DFBDisplayLayerIDs sub_layers; /* Layers available for sub mode with layer selection. */ char name[DFB_SCREEN_MIXER_DESC_NAME_LENGTH]; /* Mixer name. */ } DFBScreenMixerDescription; /* * Flags for mixer configuration. */ typedef enum { DSMCONF_NONE = 0x00000000, /* None of these. */ DSMCONF_TREE = 0x00000001, /* (Sub) tree is selected. */ DSMCONF_LEVEL = 0x00000002, /* Level is specified. */ DSMCONF_LAYERS = 0x00000004, /* Layer selection is set. */ DSMCONF_BACKGROUND = 0x00000010, /* Background color is set. */ DSMCONF_ALL = 0x00000017 /* All of these. */ } DFBScreenMixerConfigFlags; /* * (Sub) tree selection. */ typedef enum { DSMT_UNKNOWN = 0x00000000, /* Unknown mode */ DSMT_FULL = 0x00000001, /* Full tree. */ DSMT_SUB_LEVEL = 0x00000002, /* Sub tree via maximum level. */ DSMT_SUB_LAYERS = 0x00000003 /* Sub tree via layer selection. */ } DFBScreenMixerTree; /* * Configuration of a mixer. */ typedef struct { DFBScreenMixerConfigFlags flags; /* Validates struct members. */ DFBScreenMixerTree tree; /* Selected (sub) tree. */ int level; /* Maximum level of sub level mode. */ DFBDisplayLayerIDs layers; /* Layers for sub layers mode. */ DFBColor background; /* Background color. */ } DFBScreenMixerConfig; /* * Capabilities of a display encoder. */ typedef enum { DSECAPS_NONE = 0x00000000, /* None of these. */ DSECAPS_TV_STANDARDS = 0x00000001, /* TV standards can be selected. */ DSECAPS_TEST_PICTURE = 0x00000002, /* Test picture generation supported. */ DSECAPS_MIXER_SEL = 0x00000004, /* Mixer can be selected. */ DSECAPS_OUT_SIGNALS = 0x00000008, /* Different output signals are supported. */ DSECAPS_SCANMODE = 0x00000010, /* Can switch between interlaced and progressive output. */ DSECAPS_FREQUENCY = 0x00000020, /* Can switch between different frequencies. */ DSECAPS_BRIGHTNESS = 0x00000100, /* Adjustment of brightness is supported. */ DSECAPS_CONTRAST = 0x00000200, /* Adjustment of contrast is supported. */ DSECAPS_HUE = 0x00000400, /* Adjustment of hue is supported. */ DSECAPS_SATURATION = 0x00000800, /* Adjustment of saturation is supported. */ DSECAPS_CONNECTORS = 0x00001000, /* Select output connector(s). */ DSECAPS_SLOW_BLANKING = 0x00002000, /* Slow Blanking on outputs is supported. */ DSECAPS_RESOLUTION = 0x00004000, /* Different encoder resolutions supported */ DSECAPS_FRAMING = 0x00008000, /* Can select picture framing mode for stereo */ DSECAPS_ASPECT_RATIO = 0x00010000, /* Can specify display aspect ratio */ DSECAPS_ALL = 0x0001FF3F /* All of these. */ } DFBScreenEncoderCapabilities; /* * Type of display encoder. */ typedef enum { DSET_UNKNOWN = 0x00000000, /* Unknown type */ DSET_CRTC = 0x00000001, /* Encoder is a CRTC. */ DSET_TV = 0x00000002, /* TV output encoder. */ DSET_DIGITAL = 0x00000004 /* Support signals other than SD TV standards. */ } DFBScreenEncoderType; /* * TV standards. */ typedef enum { DSETV_UNKNOWN = 0x00000000, /* Unknown standard */ DSETV_PAL = 0x00000001, /* PAL */ DSETV_NTSC = 0x00000002, /* NTSC */ DSETV_SECAM = 0x00000004, /* SECAM */ DSETV_PAL_60 = 0x00000008, /* PAL-60 */ DSETV_PAL_BG = 0x00000010, /* PAL BG support (specific) */ DSETV_PAL_I = 0x00000020, /* PAL I support (specific) */ DSETV_PAL_M = 0x00000040, /* PAL M support (specific) */ DSETV_PAL_N = 0x00000080, /* PAL N support (specific) */ DSETV_PAL_NC = 0x00000100, /* PAL NC support (specific) */ DSETV_NTSC_M_JPN = 0x00000200, /* NTSC_JPN support */ DSETV_DIGITAL = 0x00000400, /* TV standards from the digital domain */ DSETV_NTSC_443 = 0x00000800, /* NTSC with 4.43MHz colour carrier */ DSETV_ALL = 0x00000FFF /* All TV Standards */ } DFBScreenEncoderTVStandards; /* * Type of output signal. */ typedef enum { DSOS_NONE = 0x00000000, /* No signal */ DSOS_VGA = 0x00000001, /* VGA signal */ DSOS_YC = 0x00000002, /* Y/C signal */ DSOS_CVBS = 0x00000004, /* CVBS signal */ DSOS_RGB = 0x00000008, /* R/G/B signal */ DSOS_YCBCR = 0x00000010, /* Y/Cb/Cr signal */ DSOS_HDMI = 0x00000020, /* HDMI signal */ DSOS_656 = 0x00000040, /* 656 Digital output signal */ DSOS_DSI = 0x00000080 /* DSI signal */ } DFBScreenOutputSignals; /* * Type of output connector. */ typedef enum { DSOC_UNKNOWN = 0x00000000, /* Unknown type */ DSOC_VGA = 0x00000001, /* VGA connector */ DSOC_SCART = 0x00000002, /* SCART connector */ DSOC_YC = 0x00000004, /* Y/C connector */ DSOC_CVBS = 0x00000008, /* CVBS connector */ DSOC_SCART2 = 0x00000010, /* 2nd SCART connector */ DSOC_COMPONENT = 0x00000020, /* Component video connector */ DSOC_HDMI = 0x00000040, /* HDMI connector */ DSOC_656 = 0x00000080, /* DVO connector */ DSOC_DSI = 0x00000100 /* DSI connector */ } DFBScreenOutputConnectors; /* * Resolutions. */ typedef enum { DSOR_UNKNOWN = 0x00000000, /* Unknown Resolution */ DSOR_640_480 = 0x00000001, /* 640x480 Resolution */ DSOR_720_480 = 0x00000002, /* 720x480 Resolution */ DSOR_720_576 = 0x00000004, /* 720x576 Resolution */ DSOR_800_600 = 0x00000008, /* 800x600 Resolution */ DSOR_1024_768 = 0x00000010, /* 1024x768 Resolution */ DSOR_1152_864 = 0x00000020, /* 1152x864 Resolution */ DSOR_1280_720 = 0x00000040, /* 1280x720 Resolution */ DSOR_1280_768 = 0x00000080, /* 1280x768 Resolution */ DSOR_1280_960 = 0x00000100, /* 1280x960 Resolution */ DSOR_1280_1024 = 0x00000200, /* 1280x1024 Resolution */ DSOR_1400_1050 = 0x00000400, /* 1400x1050 Resolution */ DSOR_1600_1200 = 0x00000800, /* 1600x1200 Resolution */ DSOR_1920_1080 = 0x00001000, /* 1920x1080 Resolution */ DSOR_960_540 = 0x00002000, /* 960x540 Resolution */ DSOR_1440_540 = 0x00004000, /* 1440x540 Resolution */ DSOR_800_480 = 0x00008000, /* 800x480 Resolution */ DSOR_1024_600 = 0x00010000, /* 1024x600 Resolution */ DSOR_1366_768 = 0x00020000, /* 1366x768 Resolution */ DSOR_1920_1200 = 0x00040000, /* 1920x1200 Resolution */ DSOR_2560_1440 = 0x00080000, /* 2560x1440 Resolution */ DSOR_2560_1600 = 0x00100000, /* 2650x1600 Resolution */ DSOR_3840_2160 = 0x00200000, /* 3840x2160 Resolution */ DSOR_4096_2160 = 0x00400000, /* 4096x2160 Resolution */ DSOR_ALL = 0x004FFFFF /* All Resolutions */ } DFBScreenOutputResolution; /* * Encoder picture delivery method. */ typedef enum { DSEPF_UNKNOWN = 0x00000000, /* Unknown encoder picture framing */ DSEPF_MONO = 0x00000001, /* Normal output to non-stereoscopic (3D) TV. No L/R content provided to TV. Frame is output on each vsync. */ DSEPF_STEREO_SIDE_BY_SIDE_HALF = 0x00000002, /* L/R frames are downscaled horizontally by 2 and packed side-by-side into a single frame, left on left half of frame. The packed frame is output on each vsync. Some stereoscopic TV's support this mode using HDMI v1.3 and a special menu configuration. */ DSEPF_STEREO_TOP_AND_BOTTOM = 0x00000004, /* L/R frames are downscaled vertically by 2 and packed into a single frame, left on top. The packed frame is output on each vsync. Some stereoscopic TV's support this mode using HDMI v1.3 and a special menu configuration. */ DSEPF_STEREO_FRAME_PACKING = 0x00000008, /* Full resolution L/R frames or fields are delivered sequentially to the TV, alternating left & right with an active space between each video frame. Vsync occurs after each sequence of: vblank, left eye video frame, active space, right eye video frame. Requires HDMI v1.4a. */ DSEPF_STEREO_SIDE_BY_SIDE_FULL = 0x00000010, /* L/R frames are packed side-by-side into a double width single frame, left on left half of frame. The packed frame is output on each vsync. Requires HDMI v1.4a. */ DSEPF_ALL = 0x0000001F /* All of these. */ } DFBScreenEncoderPictureFraming; /* * Display aspect ratio. */ typedef enum { DFB_ASPECT_RATIO_eAuto = 0x00000000, /* 4x3 for SD and 480p, 16x9 for HD (including 720p, 1080i, etc.) */ DFB_ASPECT_RATIO_e4x3 = 0x00000001, /* 4x3 */ DFB_ASPECT_RATIO_e16x9 = 0x00000002 /* 16x9 */ } DFBDisplayAspectRatio; #define DFB_SCREEN_ENCODER_DESC_NAME_LENGTH 24 /* * Description of a display encoder. */ typedef struct { DFBScreenEncoderCapabilities caps; /* Encoder capabilities. */ DFBScreenEncoderType type; /* Type of encoder. */ DFBScreenEncoderTVStandards tv_standards; /* Supported TV standards. */ DFBScreenOutputSignals out_signals; /* Supported output signals. */ DFBScreenOutputConnectors all_connectors; /* Supported output connectors */ DFBScreenOutputResolution all_resolutions; /* Supported Resolutions. */ char name[DFB_SCREEN_ENCODER_DESC_NAME_LENGTH]; /* Encoder name. */ DFBScreenEncoderPictureFraming all_framing; /* Supported HDMI signaling modes. */ DFBDisplayAspectRatio all_aspect_ratio; /* Supported display aspect ratios. */ } DFBScreenEncoderDescription; /* * Flags for display encoder configuration. */ typedef enum { DSECONF_NONE = 0x00000000, /* None of these. */ DSECONF_TV_STANDARD = 0x00000001, /* Set TV standard. */ DSECONF_TEST_PICTURE = 0x00000002, /* Set test picture mode. */ DSECONF_MIXER = 0x00000004, /* Select mixer. */ DSECONF_OUT_SIGNALS = 0x00000008, /* Select generated output signal(s). */ DSECONF_SCANMODE = 0x00000010, /* Select interlaced or progressive output. */ DSECONF_TEST_COLOR = 0x00000020, /* Set color for DSETP_SINGLE. */ DSECONF_ADJUSTMENT = 0x00000040, /* Set color adjustment. */ DSECONF_FREQUENCY = 0x00000080, /* Set Output Frequency*/ DSECONF_CONNECTORS = 0x00000100, /* Select output connector(s). */ DSECONF_SLOW_BLANKING = 0x00000200, /* Can select slow blanking support. */ DSECONF_RESOLUTION = 0x00000400, /* Can change resolution of the encoder.*/ DSECONF_FRAMING = 0x00000800, /* Set method for delivering pictures to display. */ DSECONF_ASPECT_RATIO = 0x00001000, /* Set display aspect ratio. */ DSECONF_ALL = 0x00001FFF /* All of these. */ } DFBScreenEncoderConfigFlags; /* * Test picture mode. */ typedef enum { DSETP_OFF = 0x00000000, /* Disable test picture. */ DSETP_MULTI = 0x00000001, /* Show color bars. */ DSETP_SINGLE = 0x00000002, /* Whole screen as defined in configuration. */ DSETP_WHITE = 0x00000010, /* Whole screen (ff, ff, ff). */ DSETP_YELLOW = 0x00000020, /* Whole screen (ff, ff, 00). */ DSETP_CYAN = 0x00000030, /* Whole screen (00, ff, ff). */ DSETP_GREEN = 0x00000040, /* Whole screen (00, ff, 00). */ DSETP_MAGENTA = 0x00000050, /* Whole screen (ff, 00, ff). */ DSETP_RED = 0x00000060, /* Whole screen (ff, 00, 00). */ DSETP_BLUE = 0x00000070, /* Whole screen (00, 00, ff). */ DSETP_BLACK = 0x00000080 /* Whole screen (00, 00, 00). */ } DFBScreenEncoderTestPicture; /* * Type of slow blanking signalling. */ typedef enum { DSOSB_OFF = 0x00000000, /* No signal. */ DSOSB_16x9 = 0x00000001, /* 16x9 Widescreen signalling. */ DSOSB_4x3 = 0x00000002, /* 4x3 widescreen signalling. */ DSOSB_FOLLOW = 0x00000004, /* Follow signalling. */ DSOSB_MONITOR = 0x00000008 /* Monitor. */ } DFBScreenOutputSlowBlankingSignals; /* * Scan modes. */ typedef enum { DSESM_UNKNOWN = 0x00000000, /* Unknown mode. */ DSESM_INTERLACED = 0x00000001, /* Interlaced scan mode. */ DSESM_PROGRESSIVE = 0x00000002 /* Progressive scan mode. */ } DFBScreenEncoderScanMode; /* * Frequency of output signal. */ typedef enum { DSEF_UNKNOWN = 0x00000000, /* Unknown Frequency. */ DSEF_25HZ = 0x00000001, /* 25 Hz Output. */ DSEF_29_97HZ = 0x00000002, /* 29.97 Hz Output. */ DSEF_50HZ = 0x00000004, /* 50 Hz Output. */ DSEF_59_94HZ = 0x00000008, /* 59.94 Hz Output. */ DSEF_60HZ = 0x00000010, /* 60 Hz Output. */ DSEF_75HZ = 0x00000020, /* 75 Hz Output. */ DSEF_30HZ = 0x00000040, /* 30 Hz Output. */ DSEF_24HZ = 0x00000080, /* 24 Hz Output. */ DSEF_23_976HZ = 0x00000100 /* 23.976 Hz Output. */ } DFBScreenEncoderFrequency; /* * Configuration of a display encoder. */ typedef struct { DFBScreenEncoderConfigFlags flags; /* Validates struct members. */ DFBScreenEncoderTVStandards tv_standard; /* TV standard. */ DFBScreenEncoderTestPicture test_picture; /* Test picture mode. */ int mixer; /* Selected mixer. */ DFBScreenOutputSignals out_signals; /* Generated output signals. */ DFBScreenOutputConnectors out_connectors; /* Selected output connector(s). */ DFBScreenOutputSlowBlankingSignals slow_blanking; /* Slow Blanking signals. */ DFBScreenEncoderScanMode scanmode; /* Interlaced or progressive output. */ DFBColor test_color; /* Color for DSETP_SINGLE. */ DFBColorAdjustment adjustment; /* Color adjustment. */ DFBScreenEncoderFrequency frequency; /* Selected Output Frequency*/ DFBScreenOutputResolution resolution; /* Selected Output resolution*/ DFBScreenEncoderPictureFraming framing; /* Selected picture delivery method. */ DFBDisplayAspectRatio aspect_ratio; /* screen aspect ratio */ } DFBScreenEncoderConfig; /* * Capabilities of an output. */ typedef enum { DSOCAPS_NONE = 0x00000000, /* None of these. */ DSOCAPS_CONNECTORS = 0x00000001, /* Output connectors are available. */ DSOCAPS_ENCODER_SEL = 0x00000010, /* Encoder can be selected. */ DSOCAPS_SIGNAL_SEL = 0x00000020, /* Signal(s) can be selected. */ DSOCAPS_CONNECTOR_SEL = 0x00000040, /* Connector(s) can be selected. */ DSOCAPS_SLOW_BLANKING = 0x00000080, /* Slow Blanking on outputs is supported. */ DSOCAPS_RESOLUTION = 0x00000100, /* Output Resolution can be changed. */ DSOCAPS_ALL = 0x000001F1 /* All of these. */ } DFBScreenOutputCapabilities; #define DFB_SCREEN_OUTPUT_DESC_NAME_LENGTH 24 /* * Description of a screen output. */ typedef struct { DFBScreenOutputCapabilities caps; /* Screen capabilities. */ DFBScreenOutputConnectors all_connectors; /* Output connectors. */ DFBScreenOutputSignals all_signals; /* Output signals. */ DFBScreenOutputResolution all_resolutions; /* Output Resolutions */ char name[DFB_SCREEN_OUTPUT_DESC_NAME_LENGTH]; /* Output name */ } DFBScreenOutputDescription; /* * Flags for screen output configuration. */ typedef enum { DSOCONF_NONE = 0x00000000, /* None of these. */ DSOCONF_ENCODER = 0x00000001, /* Set encoder the signal(s) comes from. */ DSOCONF_SIGNALS = 0x00000002, /* Select signal(s) from encoder. */ DSOCONF_CONNECTORS = 0x00000004, /* Select output connector(s). */ DSOCONF_SLOW_BLANKING = 0x00000008, /* Can select slow blanking support. */ DSOCONF_RESOLUTION = 0x00000010, /* Can change output resolution */ DSOCONF_ALL = 0x0000001F /* All of these. */ } DFBScreenOutputConfigFlags; /* * Configuration of an output. */ typedef struct { DFBScreenOutputConfigFlags flags; /* Validates struct members. */ int encoder; /* Chosen encoder. */ DFBScreenOutputSignals out_signals; /* Selected encoder signal(s). */ DFBScreenOutputConnectors out_connectors; /* Selected output connector(s). */ DFBScreenOutputSlowBlankingSignals slow_blanking; /* Slow Blanking signals. */ DFBScreenOutputResolution resolution; /* Output Resolution */ } DFBScreenOutputConfig; /* * IDirectFBScreen is the screen interface. */ D_DEFINE_INTERFACE( IDirectFBScreen, /** Retrieving information **/ /* * Get the unique screen ID. */ DFBResult (*GetID) ( IDirectFBScreen *thiz, DFBScreenID *ret_screen_id ); /* * Get a description of this screen, i.e. the capabilities. */ DFBResult (*GetDescription) ( IDirectFBScreen *thiz, DFBScreenDescription *ret_desc ); /* * Get the screen's width and height in pixels. */ DFBResult (*GetSize) ( IDirectFBScreen *thiz, int *ret_width, int *ret_height ); /** Display Layers **/ /* * Enumerate all existing display layers for this screen. * * Calls the given callback for each available display * layer. The callback is passed the layer id that can be * used to retrieve an interface to a specific layer using * GetDisplayLayer(). */ DFBResult (*EnumDisplayLayers) ( IDirectFBScreen *thiz, DFBDisplayLayerCallback callback, void *callbackdata ); /** Power management **/ /* * Set screen power mode. */ DFBResult (*SetPowerMode) ( IDirectFBScreen *thiz, DFBScreenPowerMode mode ); /** Synchronization **/ /* * Wait for next vertical retrace. */ DFBResult (*WaitForSync) ( IDirectFBScreen *thiz ); /** Mixers **/ /* * Get a description of available mixers. * * All descriptions are written to the array pointed to by * 'ret_descriptions'. The number of mixers is returned by * GetDescription(). */ DFBResult (*GetMixerDescriptions) ( IDirectFBScreen *thiz, DFBScreenMixerDescription *ret_descriptions ); /* * Get current mixer configuration. */ DFBResult (*GetMixerConfiguration) ( IDirectFBScreen *thiz, int mixer, DFBScreenMixerConfig *ret_config ); /* * Test mixer configuration. * * If configuration fails and 'ret_failed' is not NULL, it * will indicate which fields of the configuration caused * the error. */ DFBResult (*TestMixerConfiguration) ( IDirectFBScreen *thiz, int mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ); /* * Set mixer configuration. */ DFBResult (*SetMixerConfiguration) ( IDirectFBScreen *thiz, int mixer, const DFBScreenMixerConfig *config ); /** Encoders **/ /* * Get a description of available display encoders. * * All descriptions are written to the array pointed to by * 'ret_descriptions'. The number of encoders is returned * by GetDescription(). */ DFBResult (*GetEncoderDescriptions) ( IDirectFBScreen *thiz, DFBScreenEncoderDescription *ret_descriptions ); /* * Get current encoder configuration. */ DFBResult (*GetEncoderConfiguration) ( IDirectFBScreen *thiz, int encoder, DFBScreenEncoderConfig *ret_config ); /* * Test encoder configuration. * * If configuration fails and 'ret_failed' is not NULL, it * will indicate which fields of the configuration caused * the error. */ DFBResult (*TestEncoderConfiguration) ( IDirectFBScreen *thiz, int encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ); /* * Set encoder configuration. */ DFBResult (*SetEncoderConfiguration) ( IDirectFBScreen *thiz, int encoder, const DFBScreenEncoderConfig *config ); /** Outputs **/ /* * Get a description of available outputs. * * All descriptions are written to the array pointed to by * 'ret_descriptions'. The number of outputs is returned * by GetDescription(). */ DFBResult (*GetOutputDescriptions) ( IDirectFBScreen *thiz, DFBScreenOutputDescription *ret_descriptions ); /* * Get current output configuration. */ DFBResult (*GetOutputConfiguration) ( IDirectFBScreen *thiz, int output, DFBScreenOutputConfig *ret_config ); /* * Test output configuration. * * If configuration fails and 'ret_failed' is not NULL, it * will indicate which fields of the configuration caused * the error. */ DFBResult (*TestOutputConfiguration) ( IDirectFBScreen *thiz, int output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ); /* * Set output configuration. */ DFBResult (*SetOutputConfiguration) ( IDirectFBScreen *thiz, int output, const DFBScreenOutputConfig *config ); /** Synchronization **/ /* * Return current VSync count. */ DFBResult (*GetVSyncCount) ( IDirectFBScreen *thiz, unsigned long *ret_count ); ) /************************* * IDirectFBDisplayLayer * *************************/ /* * Capabilities of a display layer source. */ typedef enum { DDLSCAPS_NONE = 0x00000000, /* None of these. */ DDLSCAPS_SURFACE = 0x00000001, /* Source has an accessable surface. */ DDLSCAPS_ALL = 0x00000001 /* All of these. */ } DFBDisplayLayerSourceCaps; #define DFB_DISPLAY_LAYER_SOURCE_DESC_NAME_LENGTH 24 /* * Description of a display layer source. */ typedef struct { DFBDisplayLayerSourceID source_id; /* ID of the source. */ char name[DFB_DISPLAY_LAYER_SOURCE_DESC_NAME_LENGTH]; /* Name of the source. */ DFBDisplayLayerSourceCaps caps; /* Capabilites of the source. */ } DFBDisplayLayerSourceDescription; /* * Cooperative level handling the access permissions. */ typedef enum { DLSCL_SHARED = 0x00000000, /* Shared access. */ DLSCL_EXCLUSIVE = 0x00000001, /* Exclusive access, fullscreen/mode switching. */ DLSCL_ADMINISTRATIVE = 0x00000002 /* Administrative access, enumerate windows, control them. */ } DFBDisplayLayerCooperativeLevel; /* * Layer configuration flags. */ typedef enum { DLCONF_NONE = 0x00000000, /* none of these */ DLCONF_WIDTH = 0x00000001, /* layer width */ DLCONF_HEIGHT = 0x00000002, /* layer height */ DLCONF_PIXELFORMAT = 0x00000004, /* pixel format */ DLCONF_BUFFERMODE = 0x00000008, /* buffer mode */ DLCONF_OPTIONS = 0x00000010, /* layer options */ DLCONF_SOURCE = 0x00000020, /* layer source */ DLCONF_SURFACE_CAPS = 0x00000040, /* surface capabilities */ DLCONF_COLORSPACE = 0x00000080, /* color space */ DLCONF_ALL = 0x000000FF /* all of these */ } DFBDisplayLayerConfigFlags; /* * Layer Buffer Mode. */ typedef enum { DLBM_UNKNOWN = 0x00000000, /* unknown buffer mode */ DLBM_FRONTONLY = 0x00000001, /* no backbuffer */ DLBM_BACKVIDEO = 0x00000002, /* backbuffer in video memory */ DLBM_BACKSYSTEM = 0x00000004, /* backbuffer in system memory */ DLBM_TRIPLE = 0x00000008, /* triple buffering */ DLBM_WINDOWS = 0x00000010 /* no layer buffers at all, using buffer of each window */ } DFBDisplayLayerBufferMode; /* * Layer options used to enable some capabilities like * flicker filtering or colorkeying. */ typedef enum { DLOP_NONE = 0x00000000, /* None of these. */ DLOP_ALPHACHANNEL = 0x00000001, /* Make usage of alpha channel for blending on a pixel per pixel basis. */ DLOP_FLICKER_FILTERING = 0x00000002, /* Enable flicker filtering. */ DLOP_DEINTERLACING = 0x00000004, /* Enable deinterlacing of an interlaced source. */ DLOP_SRC_COLORKEY = 0x00000008, /* Enable source color key. */ DLOP_DST_COLORKEY = 0x00000010, /* Enable destination color key. */ DLOP_OPACITY = 0x00000020, /* Make usage of the global alpha factor set by SetOpacity(). */ DLOP_FIELD_PARITY = 0x00000040, /* Set field parity. */ DLOP_LR_MONO = 0x00000100, /* Layer has a single set of surface buffers and a stereo depth. The number of buffers in each set is deteremined by DSCAPS_DOUBLE, DSCAPS_TRIPLE, etc. If they exist, the windows on this layer must not be stereo or L/R mono, otherwise window information will be lost when they are composited to the layer. The layer contents (composited windows if they exist) will be shifted horizontally left and right by the stereo depth value when the layer is composited on the display screen. */ DLOP_STEREO = 0x00000200, /* Layer has two independent sets of surface buffers (left eye and right eye buffers), each with unique content. The number of buffers in each set is deteremined by DSCAPS_DOUBLE, DSCAPS_TRIPLE, etc. This option is required if any of the windows on this layer have DWCAPS_STEREO or DWCAPS_LR_MONO set, otherwise the stereo or L/R depth content of the windows cannot be preserved when compositing to the layer. */ DLOP_ALL = 0x000003FF /* All of these. */ } DFBDisplayLayerOptions; /* * Layer configuration. */ typedef struct { DFBDisplayLayerConfigFlags flags; /* Validates struct members. */ int width; /* Pixel width. */ int height; /* Pixel height. */ DFBSurfacePixelFormat pixelformat; /* Pixel format. */ DFBSurfaceColorSpace colorspace; /* Color space. */ DFBDisplayLayerBufferMode buffermode; /* Buffer mode. */ DFBDisplayLayerOptions options; /* Enable capabilities. */ DFBDisplayLayerSourceID source; /* Selected layer source. */ DFBSurfaceCapabilities surface_caps; /* Choose surface capabilities, available: INTERLACED, SEPARATED, PREMULTIPLIED. */ } DFBDisplayLayerConfig; #define DLSO_FIXED_LIMIT 0x7f /* Stereo fixed depth value must be between +DLSO_FIXED_LIMIT and -DLSO_FIXED_LIMIT. */ /* * Background mode defining how to erase/initialize the area for * a windowstack repaint. */ typedef enum { DLBM_DONTCARE = 0x00000000, /* do not clear the layer before repainting the window stack */ DLBM_COLOR = 0x00000001, /* fill with solid color set by SetBackgroundColor() */ DLBM_IMAGE = 0x00000002, /* use an image set by SetBackgroundImage() */ DLBM_TILE = 0x00000003 /* use a tiled image set by SetBackgroundImage() */ } DFBDisplayLayerBackgroundMode; /* * Flags defining which fields of a DFBWindowDescription are * valid. */ typedef enum { DWDESC_CAPS = 0x00000001, /* caps field is valid. */ DWDESC_WIDTH = 0x00000002, /* width field is valid. */ DWDESC_HEIGHT = 0x00000004, /* height field is valid. */ DWDESC_PIXELFORMAT = 0x00000008, /* pixelformat field is valid */ DWDESC_POSX = 0x00000010, /* posx field is valid */ DWDESC_POSY = 0x00000020, /* posy field is valid */ DWDESC_SURFACE_CAPS = 0x00000040, /* Create the window surface with special capabilities. */ DWDESC_PARENT = 0x00000080, /* This window has a parent according to parent_id field. */ DWDESC_OPTIONS = 0x00000100, /* Initial window options have been set. */ DWDESC_STACKING = 0x00000200, /* Initial stacking class has been set. */ DWDESC_TOPLEVEL_ID = 0x00000400, /* The top level window is set in toplevel_id field. */ DWDESC_COLORSPACE = 0x00000800, /* colorspace field is valid */ DWDESC_RESOURCE_ID = 0x00001000 /* resource_id for window surface creation has been set. */ } DFBWindowDescriptionFlags; /* * Capabilities a window can have. */ typedef enum { DWCAPS_NONE = 0x00000000, /* None of these. */ DWCAPS_ALPHACHANNEL = 0x00000001, /* The window has an alphachannel for pixel-per-pixel blending. */ DWCAPS_DOUBLEBUFFER = 0x00000002, /* The window's surface is double buffered. This is very useful to avoid visibility of content that is still in preparation. Normally a window's content can get visible before an update if there is another reason causing a window stack repaint. */ DWCAPS_INPUTONLY = 0x00000004, /* The window has no surface. You can not draw to it but it receives events. */ DWCAPS_NODECORATION = 0x00000008, /* The window won't be decorated. */ DWCAPS_SUBWINDOW = 0x00000010, /* Not a top level window. */ DWCAPS_COLOR = 0x00000020, /* The window has no buffer. It consumes no backing store. It is filled with a constant color and it receives events. The color is never specified premultiplied. */ DWCAPS_NOFOCUS = 0x00000100, /* Window will never get focus or receive key events, unless it grabs them. */ DWCAPS_LR_MONO = 0x00001000, /* Window has a single set of surface buffers and a stereo depth. The number of buffers in each set is deteremined by DSCAPS_DOUBLE, DSCAPS_TRIPLE, etc. Selecting this option requires the underlying layer to have DLOP_STEREO set, otherwise the stereo depth for the left and right eye cannot be preserved when compositing to the underlying layer. The buffer is composited to both the left and right eye buffers of the layer with an x-axis right and left shift of depth pixels, respectively. */ DWCAPS_STEREO = 0x00002000, /* Window has 2 independent sets of surface buffers (left eye & right eye buffers), each with unique content. The number of buffers in each set is deteremined by DSCAPS_DOUBLE, DSCAPS_TRIPLE, etc as usual. Selecting this option requires the underlying layer to have DLOP_STEREO set, otherwise the independent content of the left and right eye cannot be preserved when compositing to the layer. */ DWCAPS_ALL = 0x0000313F /* All of these. */ } DFBWindowCapabilities; /* * Flags controlling the appearance and behaviour of the window. */ typedef enum { DWOP_NONE = 0x00000000, /* None of these. */ DWOP_COLORKEYING = 0x00000001, /* Enable color key. */ DWOP_ALPHACHANNEL = 0x00000002, /* Enable alpha blending using the window's alpha channel. */ DWOP_OPAQUE_REGION = 0x00000004, /* Overrides DWOP_ALPHACHANNEL for the region set by SetOpaqueRegion() */ DWOP_SHAPED = 0x00000008, /* Window doesn't receive mouse events for invisible regions, must be used with DWOP_ALPHACHANNEL or DWOP_COLORKEYING. */ DWOP_KEEP_POSITION = 0x00000010, /* Window can't be moved with the mouse. */ DWOP_KEEP_SIZE = 0x00000020, /* Window can't be resized with the mouse. */ DWOP_KEEP_STACKING = 0x00000040, /* Window can't be raised or lowered with the mouse. */ DWOP_GHOST = 0x00001000, /* Never get focus or input, clicks will go through, implies DWOP_KEEP. */ DWOP_INDESTRUCTIBLE = 0x00002000, /* Window can't be destroyed by internal shortcut. */ DWOP_INPUTONLY = 0x00004000, /* The window will be input only. It will receive events but is not shown. Note that toggling this bit will not free/assign the window surface. */ DWOP_STEREO_SIDE_BY_SIDE_HALF = 0x00008000, /* Treat single buffer as combined left/right buffers, side by side. */ DWOP_SCALE = 0x00010000, /* Surface won't be changed if window size on screen changes. The surface can be resized separately using ResizeSurface(). */ DWOP_KEEP_ABOVE = 0x00100000, /* Keep window above parent window. */ DWOP_KEEP_UNDER = 0x00200000, /* Keep window under parent window. */ DWOP_FOLLOW_BOUNDS = 0x00400000, /* Follow window bounds from parent. */ DWOP_ALL = 0x0071F07F /* all possible options */ } DFBWindowOptions; /* * The stacking class restricts the stacking order of windows. */ typedef enum { DWSC_MIDDLE = 0x00000000, /* This is the default stacking class of new windows. */ DWSC_UPPER = 0x00000001, /* Window is always above windows in the middle stacking class. Only windows that are also in the upper stacking class can get above them. */ DWSC_LOWER = 0x00000002 /* Window is always below windows in the middle stacking class. Only windows that are also in the lower stacking class can get below them. */ } DFBWindowStackingClass; /* * Description of the window that is to be created. */ typedef struct { DFBWindowDescriptionFlags flags; /* field validation */ DFBWindowCapabilities caps; /* capabilities */ int width; /* pixel width */ int height; /* pixel height */ DFBSurfacePixelFormat pixelformat; /* pixel format */ int posx; /* distance from left layer border */ int posy; /* distance from upper layer border */ DFBSurfaceCapabilities surface_caps; /* surface capabilities */ DFBWindowID parent_id; /* window id of parent window */ DFBWindowOptions options; /* initial window options */ DFBWindowStackingClass stacking; /* initial stacking class */ unsigned long resource_id; /* resource id used to create the window surface */ DFBWindowID toplevel_id; /* top level window: if not zero, window will be a sub window */ DFBSurfaceColorSpace colorspace; /* color space */ } DFBWindowDescription; /* * IDirectFBDisplayLayer is the display layer interface. */ D_DEFINE_INTERFACE( IDirectFBDisplayLayer, /** Retrieving information **/ /* * Get the unique layer ID. */ DFBResult (*GetID) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerID *ret_layer_id ); /* * Get a description of this display layer, i.e. the capabilities. */ DFBResult (*GetDescription) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerDescription *ret_desc ); /* * Get a description of available sources. * * All descriptions are written to the array pointed to by * ret_descriptions. The number of sources is returned by * GetDescription(). */ DFBResult (*GetSourceDescriptions) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerSourceDescription *ret_descriptions ); /* * For an interlaced display, this returns the currently * inactive field: 0 for the top field, and 1 for the * bottom field. * * The inactive field is the one you should draw to next * to avoid tearing, the active field is the one currently * being displayed. * For a progressive output, this should always return 0. */ DFBResult (*GetCurrentOutputField) ( IDirectFBDisplayLayer *thiz, int *ret_field ); /** Interfaces **/ /* * Get an interface to layer's surface. * * Only available in exclusive mode. */ DFBResult (*GetSurface) ( IDirectFBDisplayLayer *thiz, IDirectFBSurface **ret_interface ); /* * Get an interface to the screen to which the layer * belongs. */ DFBResult (*GetScreen) ( IDirectFBDisplayLayer *thiz, IDirectFBScreen **ret_interface ); /** Configuration **/ /* * Set cooperative level to get control over the layer or * the windows within this layer. */ DFBResult (*SetCooperativeLevel) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerCooperativeLevel level ); /* * Get current layer configuration. */ DFBResult (*GetConfiguration) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerConfig *ret_config ); /* * Test layer configuration. * * If configuration fails and 'ret_failed' is not NULL, it * will indicate which fields of the configuration caused * the error. */ DFBResult (*TestConfiguration) ( IDirectFBDisplayLayer *thiz, const DFBDisplayLayerConfig *config, DFBDisplayLayerConfigFlags *ret_failed ); /* * Set layer configuration. * * Only available in exclusive or administrative mode. */ DFBResult (*SetConfiguration) ( IDirectFBDisplayLayer *thiz, const DFBDisplayLayerConfig *config ); /** Layout **/ /* * Set location on screen as normalized values. * * So the whole screen is 0.0, 0.0, 1.0, 1.0. */ DFBResult (*SetScreenLocation) ( IDirectFBDisplayLayer *thiz, float x, float y, float width, float height ); /* * Set location on screen in pixels. */ DFBResult (*SetScreenPosition) ( IDirectFBDisplayLayer *thiz, int x, int y ); /* * Set location on screen in pixels. */ DFBResult (*SetScreenRectangle) ( IDirectFBDisplayLayer *thiz, int x, int y, int width, int height ); /* * Get stereo depth. */ DFBResult (*GetStereoDepth) ( IDirectFBDisplayLayer *thiz, bool *follow_video, int *ret_z ); /* * Set stereo depth. * * If 'follow_video' is true then the pixel offset value * from the video metadata will be used to set the * perceived depth. * Otherwise, the z value specified will cause the left eye * buffer content to be shifted on the x-axis by +z and the * right eye buffer to be shifted by -z. A positive z value * will cause the layer to appear closer than the TV plane * while a negative z value will make the layer appear * farther away. The depth is limited to a value between * +DLSO_FIXED_LIMIT and -DLSO_FIXED_LIMIT. */ DFBResult (*SetStereoDepth) ( IDirectFBDisplayLayer *thiz, bool follow_video, int z ); /** Misc Settings **/ /* * Set global alpha factor for blending with * layer(s) below. */ DFBResult (*SetOpacity) ( IDirectFBDisplayLayer *thiz, u8 opacity ); /* * Set the source rectangle. * * Only this part of the layer will be displayed. */ DFBResult (*SetSourceRectangle) ( IDirectFBDisplayLayer *thiz, int x, int y, int width, int height ); /* * For an interlaced display, this sets the field parity. * * 'field' is set to 0 for top field first, and set to 1 * for bottom field first. */ DFBResult (*SetFieldParity) ( IDirectFBDisplayLayer *thiz, int field ); /* * Set the clipping region(s). * * If supported, this method sets the clipping 'regions' * that are used to to enable or disable visibility of * parts of the layer. The 'num_regions' must not exceed * the limit as stated in the display layer description. * If 'positive' is DFB_TRUE the layer will be shown only * in these regions, otherwise it's shown as usual except * in these regions. */ DFBResult (*SetClipRegions) ( IDirectFBDisplayLayer *thiz, const DFBRegion *regions, int num_regions, DFBBoolean positive ); /** Color keys **/ /* * Set the source color key. * * If a pixel of the layer matches this color the * underlying pixel is visible at this point. */ DFBResult (*SetSrcColorKey) ( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b ); /* * Set the destination color key. * * The layer is only visible at points where the underlying * pixel matches this color. */ DFBResult (*SetDstColorKey) ( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b ); /** Z Order **/ /* * Get the current display layer level. * * The level describes the z axis position of a layer. The * primary layer is always on level zero unless a special * driver adds support for level adjustment on the primary * layer. Layers above have a positive level, e.g. video * overlays. Layers below have a negative level, e.g. video * underlays or background layers. */ DFBResult (*GetLevel) ( IDirectFBDisplayLayer *thiz, int *ret_level ); /* * Set the display layer level. * * Moves the layer to the specified level. The order of all * other layers won't be changed. Note that only a few * layers support level adjustment which is reflected by * their capabilities. */ DFBResult (*SetLevel) ( IDirectFBDisplayLayer *thiz, int level ); /** Background handling **/ /* * Set the erase behaviour for windowstack repaints. * * Only available in exclusive or administrative mode. */ DFBResult (*SetBackgroundMode) ( IDirectFBDisplayLayer *thiz, DFBDisplayLayerBackgroundMode mode ); /* * Set the background image for the imaged background mode. * * Only available in exclusive or administrative mode. */ DFBResult (*SetBackgroundImage) ( IDirectFBDisplayLayer *thiz, IDirectFBSurface *surface ); /* * Set the color for a solid colored background. * * Only available in exclusive or administrative mode. */ DFBResult (*SetBackgroundColor) ( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b, u8 a ); /** Color adjustment **/ /* * Get the layers color adjustment. */ DFBResult (*GetColorAdjustment) ( IDirectFBDisplayLayer *thiz, DFBColorAdjustment *ret_adj ); /* * Set the layers color adjustment. * * Only available in exclusive or administrative mode. * * This function only has an effect if the underlying * hardware supports this operation. Check the layers * capabilities to find out if this is the case. */ DFBResult (*SetColorAdjustment) ( IDirectFBDisplayLayer *thiz, const DFBColorAdjustment *adj ); /** Windows **/ /* * Create a window within this layer given a description of * the window that is to be created. */ DFBResult (*CreateWindow) ( IDirectFBDisplayLayer *thiz, const DFBWindowDescription *desc, IDirectFBWindow **ret_interface ); /* * Retrieve an interface to an existing window. * * The window is identified by its window id. */ DFBResult (*GetWindow) ( IDirectFBDisplayLayer *thiz, DFBWindowID window_id, IDirectFBWindow **ret_interface ); /** Cursor handling **/ /* * Enable/disable the mouse cursor for this layer. * * Windows on a layer will only receive motion events if * the cursor is enabled. This function is only available * in exclusive/administrative mode. */ DFBResult (*EnableCursor) ( IDirectFBDisplayLayer *thiz, int enable ); /* * Return the x/y coordinates of the layer's mouse cursor. */ DFBResult (*GetCursorPosition) ( IDirectFBDisplayLayer *thiz, int *ret_x, int *ret_y ); /* * Move cursor to specified position. * * Handles movement like a real one, i.e. generates events. */ DFBResult (*WarpCursor) ( IDirectFBDisplayLayer *thiz, int x, int y ); /* * Set cursor acceleration. * * Sets the acceleration of cursor movements. The amount * beyond the 'threshold' will be multiplied with the * acceleration factor. The acceleration factor is * 'numerator' / 'denominator'. */ DFBResult (*SetCursorAcceleration) ( IDirectFBDisplayLayer *thiz, int numerator, int denominator, int threshold ); /* * Set the cursor shape and the hotspot. * * Passing NULL will restore the default cursor shape. */ DFBResult (*SetCursorShape) ( IDirectFBDisplayLayer *thiz, IDirectFBSurface *shape, int hot_x, int hot_y ); /* * Set the cursor opacity. * * This function is especially useful if you want to hide * the cursor but still want windows on this display layer * to receive motion events. * In this case, simply set the cursor opacity to zero. */ DFBResult (*SetCursorOpacity) ( IDirectFBDisplayLayer *thiz, u8 opacity ); /** Synchronization **/ /* * Wait for next vertical retrace. */ DFBResult (*WaitForSync) ( IDirectFBDisplayLayer *thiz ); /** Contexts **/ /* * Switch the layer context. * * Switches to the shared context unless 'exclusive' is * DFB_TRUE and the cooperative level of this interface is * DLSCL_EXCLUSIVE. */ DFBResult (*SwitchContext) ( IDirectFBDisplayLayer *thiz, DFBBoolean exclusive ); /** Rotation **/ /* * Set the rotation of data within the layer. * * Only available in exclusive or administrative mode. * Any 'rotation' other than 0, 90, 180 or 270 is not * supported. No layer hardware feature usage, only rotated * blitting is used. */ DFBResult (*SetRotation) ( IDirectFBDisplayLayer *thiz, int rotation ); /* * Get the rotation of data within the layer. */ DFBResult (*GetRotation) ( IDirectFBDisplayLayer *thiz, int *ret_rotation ); /** Windows **/ /* * Retrieve an interface to an existing window. * * The window is identified by its surface resource id. */ DFBResult (*GetWindowByResourceID) ( IDirectFBDisplayLayer *thiz, unsigned long resource_id, IDirectFBWindow **ret_interface ); /** Surface **/ /* * Set the surface to be shown by the layer. * * Only available in exclusive mode. */ DFBResult (*SetSurface) ( IDirectFBDisplayLayer *thiz, IDirectFBSurface *surface ); ) /******************** * IDirectFBSurface * ********************/ /* * Stereo eye buffer. */ typedef enum { DSSE_NONE = 0x00000000, /* None */ DSSE_LEFT = 0x00000001, /* Left eye buffers to be used for all future operations on this surface. */ DSSE_RIGHT = 0x00000002 /* Right eye buffers to be used for all future operations on this surface. */ } DFBSurfaceStereoEye; /* * Flags defining the type of data access. * These are important for surface swapping management. */ typedef enum { DSLF_READ = 0x00000001, /* Request read access while surface is locked. */ DSLF_WRITE = 0x00000002 /* Request write access. If specified and surface has a back buffer, it will be used. Otherwise, the front buffer is used. */ } DFBSurfaceLockFlags; /* * Flipping flags controlling the behaviour of Flip(). */ typedef enum { DSFLIP_NONE = 0x00000000, /* None of these. */ DSFLIP_WAIT = 0x00000001, /* Flip() returns upon vertical sync. Flipping is still done immediately unless DSFLIP_ONSYNC is specified, too. */ DSFLIP_BLIT = 0x00000002, /* Copy from back buffer to front buffer rather than just swapping these buffers. This behaviour is enforced if the region passed to Flip() is not NULL or if the surface being flipped is a sub surface. */ DSFLIP_ONSYNC = 0x00000004, /* Do the actual flipping upon the next vertical sync. The Flip() method will still return immediately unless DSFLIP_WAIT is specified, too. */ DSFLIP_PIPELINE = 0x00000008, /* Advanced synchronization with the accelerator. It is especially for accelerators with a command buffer that can store more graphics operations than required to render one frame. */ DSFLIP_ONCE = 0x00000010, /* Cause Flip() to wait until all other updating window surfaces are being flipped. */ DSFLIP_QUEUE = 0x00000100, /* Queuing updates */ DSFLIP_FLUSH = 0x00000200, /* Flushing */ DSFLIP_SWAP = 0x00000400, /* Cause real flip even though region was specified. */ DSFLIP_UPDATE = 0x00000800, /* Update from front only, no swapping */ DSFLIP_NOWAIT = 0x00001000, DSFLIP_WAITFORSYNC = DSFLIP_WAIT | DSFLIP_ONSYNC /* Flip() returns after the actual flipping performed during the next vertical sync */ } DFBSurfaceFlipFlags; /* * Blend functions to use for source and destination blending. * * pixel color = sc * cf[sf] + dc * cf[df] * pixel alpha = sa * af[sf] + da * af[df] * sc = source color * sa = source alpha * dc = destination color * da = destination alpha * sf = source blend function * df = destination blend function * cf[x] = color factor for blend function x * af[x] = alpha factor for blend function x * */ typedef enum { DSBF_UNKNOWN = 0x00000000, /* unknown blend function */ DSBF_ZERO = 0x00000001, /* cf: 0 af: 0 */ DSBF_ONE = 0x00000002, /* cf: 1 af: 1 */ DSBF_SRCCOLOR = 0x00000003, /* cf: sc af: sa */ DSBF_INVSRCCOLOR = 0x00000004, /* cf: 1-sc af: 1-sa */ DSBF_SRCALPHA = 0x00000005, /* cf: sa af: sa */ DSBF_INVSRCALPHA = 0x00000006, /* cf: 1-sa af: 1-sa */ DSBF_DESTALPHA = 0x00000007, /* cf: da af: da */ DSBF_INVDESTALPHA = 0x00000008, /* cf: 1-da af: 1-da */ DSBF_DESTCOLOR = 0x00000009, /* cf: dc af: da */ DSBF_INVDESTCOLOR = 0x0000000A, /* cf: 1-dc af: 1-da */ DSBF_SRCALPHASAT = 0x0000000B /* cf: min(sa, 1-da) af: 1 */ } DFBSurfaceBlendFunction; /* * Available Porter/Duff rules. * * pixel = (source * fs + destination * fd) * sa = source alpha, * da = destination alpha */ typedef enum { DSPD_NONE = 0x00000000, /* fs: sa fd: 1-sa */ DSPD_CLEAR = 0x00000001, /* fs: 0 fd: 0 */ DSPD_SRC = 0x00000002, /* fs: 1 fd: 0 */ DSPD_SRC_OVER = 0x00000003, /* fs: 1 fd: 1-sa */ DSPD_DST_OVER = 0x00000004, /* fs: 1-da fd: 1 */ DSPD_SRC_IN = 0x00000005, /* fs: da fd: 0 */ DSPD_DST_IN = 0x00000006, /* fs: 0 fd: sa */ DSPD_SRC_OUT = 0x00000007, /* fs: 1-da fd: 0 */ DSPD_DST_OUT = 0x00000008, /* fs: 0 fd: 1-sa */ DSPD_SRC_ATOP = 0x00000009, /* fs: da fd: 1-sa */ DSPD_DST_ATOP = 0x0000000A, /* fs: 1-da fd: sa */ DSPD_ADD = 0x0000000B, /* fs: 1 fd: 1 */ DSPD_XOR = 0x0000000C, /* fs: 1-da fd: 1-sa */ DSPD_DST = 0x0000000D /* fs: 0 fd: 1 */ } DFBSurfacePorterDuffRule; /* * Flags controlling the text layout. */ typedef enum { DSTF_NONE = 0x00000000, /* no flags */ DSTF_LEFT = 0x00000000, /* left aligned */ DSTF_CENTER = 0x00000001, /* horizontally centered */ DSTF_RIGHT = 0x00000002, /* right aligned */ DSTF_TOP = 0x00000004, /* 'y' specifies the top instead of the baseline */ DSTF_BOTTOM = 0x00000008, /* 'y' specifies the bottom instead of the baseline */ DSTF_OUTLINE = 0x00000010, /* enables outline rendering */ DSTF_BLEND_FUNCS = 0x00000020, /* keeps src/dst blend functions as set on destination */ DSTF_TOPLEFT = DSTF_TOP | DSTF_LEFT, /* left aligned, 'y' specifying the top */ DSTF_TOPCENTER = DSTF_TOP | DSTF_CENTER, /* horizontally centered, 'y' specifying the top */ DSTF_TOPRIGHT = DSTF_TOP | DSTF_RIGHT, /* right aligned, 'y' specifying the top */ DSTF_BOTTOMLEFT = DSTF_BOTTOM | DSTF_LEFT, /* left aligned, 'y' specifying the bottom */ DSTF_BOTTOMCENTER = DSTF_BOTTOM | DSTF_CENTER, /* horizontally centered, 'y' specifying the bottom */ DSTF_BOTTOMRIGHT = DSTF_BOTTOM | DSTF_RIGHT /* right aligned, 'y' specifying the bottom */ } DFBSurfaceTextFlags; /* * Options for drawing and blitting operations. */ typedef enum { DSRO_NONE = 0x00000000, /* None of these. */ DSRO_SMOOTH_UPSCALE = 0x00000001, /* Use interpolation for upscale StretchBlit(). */ DSRO_SMOOTH_DOWNSCALE = 0x00000002, /* Use interpolation for downscale StretchBlit(). */ DSRO_MATRIX = 0x00000004, /* Use the transformation matrix set via SetMatrix(). */ DSRO_ANTIALIAS = 0x00000008, /* Enable anti-aliasing for edges (alpha blending must be enabled). */ DSRO_ALL = 0x0000000F /* All of these. */ } DFBSurfaceRenderOptions; /* * Flags controlling surface masks set via SetSourceMask(). */ typedef enum { DSMF_NONE = 0x00000000, /* None of these. */ DSMF_STENCIL = 0x00000001, /* Take 'x' and 'y' as fixed start coordinates in the mask. */ DSMF_ALL = 0x00000001 /* All of these. */ } DFBSurfaceMaskFlags; /* * Monochrome glyph attributes. */ typedef struct { int width; /* glyph width */ int height; /* glyph height */ int rowbyte; /* glyph rowbyte */ int bitoffset; /* glyph bitoffset */ int fgcolor; /* foreground color */ int bgcolor; /* background color */ int hzoom; /* horizontal zoom factor */ int vzoom; /* vertical zoom factor */ } DFBMonoGlyphAttributes; /* * Frame time configuration flags. */ typedef enum { DFTCF_NONE = 0x00000000, /* None of these. */ DFTCF_INTERVAL = 0x00000001, /* Interval is specified, otherwise the interval is set automatically depending on screen refresh. */ DFTCF_MAX_ADVANCE = 0x00000002, /* Maximum time to render in advance, GetFrameTime() will block to keep the limit. */ DFTCF_ALL = 0x00000003, /* All of these. */ } DFBFrameTimeConfigFlags; /* * Frame time configuration. */ typedef struct { DFBFrameTimeConfigFlags flags; /* Validation of fields. */ long long interval; /* Interval time. */ long long max_advance; /* Maximum time ahead for rendering frames. */ } DFBFrameTimeConfig; /* * Buffer role. */ typedef enum { DSBR_FRONT = 0x00000000, /* Front buffer. */ DSBR_BACK = 0x00000001, /* Back buffer */ DSBR_IDLE = 0x00000002 /* Idle buffer. */ } DFBSurfaceBufferRole; /* * IDirectFBSurface is the surface interface. */ D_DEFINE_INTERFACE( IDirectFBSurface, /** Retrieving information **/ /* * Return the capabilities of this surface. */ DFBResult (*GetCapabilities) ( IDirectFBSurface *thiz, DFBSurfaceCapabilities *ret_caps ); /* * Get the surface's position in pixels. */ DFBResult (*GetPosition) ( IDirectFBSurface *thiz, int *ret_x, int *ret_y ); /* * Get the surface's width and height in pixels. */ DFBResult (*GetSize) ( IDirectFBSurface *thiz, int *ret_width, int *ret_height ); /* * Created sub surfaces might be clipped by their parents, * this function returns the resulting rectangle relative * to this surface. * * For non sub surfaces this function returns * { 0, 0, width, height }. */ DFBResult (*GetVisibleRectangle) ( IDirectFBSurface *thiz, DFBRectangle *ret_rect ); /* * Get the current pixel format. */ DFBResult (*GetPixelFormat) ( IDirectFBSurface *thiz, DFBSurfacePixelFormat *ret_pixelformat ); /* * Get the current color space. */ DFBResult (*GetColorSpace) ( IDirectFBSurface *thiz, DFBSurfaceColorSpace *ret_colorspace ); /* * Get a mask of drawing functions that are hardware * accelerated with the current settings. * * If a source surface is specified the mask will also * contain accelerated blitting functions. Note that there * is no guarantee that these will actually be accelerated * since the surface storage (video/system) is examined * only when something actually gets drawn or blitted. */ DFBResult (*GetAccelerationMask) ( IDirectFBSurface *thiz, IDirectFBSurface *source, DFBAccelerationMask *ret_mask ); /** Palette & Alpha Ramp **/ /* * Get access to the surface's palette. * * Returns an interface that can be used to gain read * and/or write access to the surface's palette. */ DFBResult (*GetPalette) ( IDirectFBSurface *thiz, IDirectFBPalette **ret_interface ); /* * Change the surface's palette. */ DFBResult (*SetPalette) ( IDirectFBSurface *thiz, IDirectFBPalette *palette ); /* * Set the alpha ramp for formats with one or two * alpha bits. * * Either all four values or the first and the last one * are used, depending on the format. * Default values are: 0x00, 0x55, 0xaa, 0xff. */ DFBResult (*SetAlphaRamp) ( IDirectFBSurface *thiz, u8 a0, u8 a1, u8 a2, u8 a3 ); /** Buffer operations **/ /* * Get the current stereo eye. * * Only applicable to window/layer surfaces with the * DWCAPS_STEREO or DLOP_STEREO option. This method will * retrieve which set of buffers (left or right) is * currently active for operations on this surface. */ DFBResult (*GetStereoEye) ( IDirectFBSurface *thiz, DFBSurfaceStereoEye *ret_eye ); /* * Select the stereo eye for future operations. * * Only applicable to window/layer surfaces with the * DWCAPS_STEREO or DLOP_STEREO option. This method will * specify which set of buffers (left or right) is to be * used for future operations on this surface. */ DFBResult (*SetStereoEye) ( IDirectFBSurface *thiz, DFBSurfaceStereoEye eye ); /* * Lock the surface for the access type specified. * * Returns a data pointer and the line pitch of it. * Note: if the surface is double/triple buffered and the * DSLF_WRITE flag is specified, the pointer is to the back * buffer. In all other cases, the pointer is to the front * buffer. */ DFBResult (*Lock) ( IDirectFBSurface *thiz, DFBSurfaceLockFlags flags, void **ret_ptr, int *ret_pitch ); /* * Return the framebuffer offset of a locked surface. */ DFBResult (*GetFramebufferOffset) ( IDirectFBSurface *thiz, int *offset ); /* * Unlock the surface after direct access. */ DFBResult (*Unlock) ( IDirectFBSurface *thiz ); /* * Flip/Update surface buffers. * * If no region is specified the whole surface is flipped, * otherwise blitting is used to update the region. * If surface capabilities don't include DSCAPS_FLIPPING, * this method has the effect to make visible changes * made to the surface contents. */ DFBResult (*Flip) ( IDirectFBSurface *thiz, const DFBRegion *region, DFBSurfaceFlipFlags flags ); /* * Flip/Update stereo surface buffers. * * Flips both the left and right buffers simultaneously to * ensure synchronization between the two. * Only applicable to window and layer surfaces with the * DWCAPS_STEREO or DLOP_STEREO option. This method will * fail with all other surfaces. * If no region is specified the whole surface is flipped, * otherwise blitting is used to update the region. * If surface capabilities don't include DSCAPS_FLIPPING, * this method has the effect to make visible changes made * to the surface contents. */ DFBResult (*FlipStereo) ( IDirectFBSurface *thiz, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ); /* * Set the active field. * * Interlaced surfaces consist of two fields. Software * driven deinterlacing uses this method to manually switch * the field that is displayed, e.g. scaled up vertically * by two. */ DFBResult (*SetField) ( IDirectFBSurface *thiz, int field ); /* * Clear the surface and its depth buffer if existent. * * Fills the whole (sub) surface with the specified color * while ignoring drawing flags and color of the current * state, but limited to the current clip. * As with all drawing and blitting functions the * backbuffer is written to. If you are initializing a * double buffered surface you may want to clear both * buffers by doing a Clear-Flip-Clear sequence. */ DFBResult (*Clear) ( IDirectFBSurface *thiz, u8 r, u8 g, u8 b, u8 a ); /** Drawing/blitting control **/ /* * Set the clipping region used to limit the area for * drawing, blitting and text functions. * * If no region is specified (NULL passed) the clip is set * to the surface extents (initial clip). */ DFBResult (*SetClip) ( IDirectFBSurface *thiz, const DFBRegion *clip ); /* * Get the clipping region used to limit the area for * drawing, blitting and text functions. */ DFBResult (*GetClip) ( IDirectFBSurface *thiz, DFBRegion *ret_clip ); /* * Set the color used for drawing/text functions or * alpha/color modulation (blitting functions). * * If you are not using the alpha value it should be set to * 0xff to ensure visibility when the code is ported to or * used for surfaces with an alpha channel. */ DFBResult (*SetColor) ( IDirectFBSurface *thiz, u8 r, u8 g, u8 b, u8 a ); /* * Set the color like with SetColor() but using an index to * the color/alpha lookup table. * * This method is only supported by surfaces with an * indexed pixelformat, e.g. DSPF_LUT8. For these formats * this method should be used instead of SetColor(). */ DFBResult (*SetColorIndex) ( IDirectFBSurface *thiz, unsigned int index ); /* * Set the blend function that applies to the source. */ DFBResult (*SetSrcBlendFunction) ( IDirectFBSurface *thiz, DFBSurfaceBlendFunction function ); /* * Set the blend function that applies to the destination. */ DFBResult (*SetDstBlendFunction) ( IDirectFBSurface *thiz, DFBSurfaceBlendFunction function ); /* * Set the source and destination blend function by * specifying a Porter/Duff rule. */ DFBResult (*SetPorterDuff) ( IDirectFBSurface *thiz, DFBSurfacePorterDuffRule rule ); /* * Set the source color key, i.e. the color that is * excluded when blitting from this surface to another * that has source color keying enabled. */ DFBResult (*SetSrcColorKey) ( IDirectFBSurface *thiz, u8 r, u8 g, u8 b ); /* * Set the source color key like with SetSrcColorKey() but * using an index to the color/alpha lookup table. * * This method is only supported by surfaces with an * indexed pixelformat, e.g. DSPF_LUT8. For these formats * this method should be used instead of SetSrcColorKey(). */ DFBResult (*SetSrcColorKeyIndex) ( IDirectFBSurface *thiz, unsigned int index ); /* * Set the destination color key, i.e. the only color that * gets overwritten by drawing and blitting to this surface * when destination color keying is enabled. */ DFBResult (*SetDstColorKey) ( IDirectFBSurface *thiz, u8 r, u8 g, u8 b ); /* * Set the destination color key like with SetDstColorKey() * but using an index to the color/alpha lookup table. * * This method is only supported by surfaces with an * indexed pixelformat, e.g. DSPF_LUT8. For these formats * this method should be used instead of SetDstColorKey(). */ DFBResult (*SetDstColorKeyIndex) ( IDirectFBSurface *thiz, unsigned int index ); /** Blitting functions **/ /* * Set the flags for all subsequent blitting commands. */ DFBResult (*SetBlittingFlags) ( IDirectFBSurface *thiz, DFBSurfaceBlittingFlags flags ); /* * Blit an area from the source to this surface. * * Pass a NULL rectangle to use the whole source surface. * Source may be the same surface. */ DFBResult (*Blit) ( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, int x, int y ); /* * Blit an area from the source tiled to this surface. * * Pass a NULL rectangle to use the whole source surface. * Source may be the same surface. */ DFBResult (*TileBlit) ( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, int x, int y ); /* * Blit a bunch of areas at once. * * Source may be the same surface. */ DFBResult (*BatchBlit) ( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rects, const DFBPoint *dest_points, int num ); /* * Blit an area scaled from the source to the destination * rectangle. * * Pass a NULL rectangle to use the whole source surface. */ DFBResult (*StretchBlit) ( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, const DFBRectangle *dest_rect ); /* * Texture mapping support. * * Maps a 'texture' onto triangles being built from * 'vertices' according to the chosen 'formation'. * Optional 'indices' can be used to avoid rearrangement * of vertex lists, otherwise the vertex list is processed * consecutively, i.e. as if 'indices' are ascending * numbers starting at zero. * Either the number of 'indices' or the number of * 'vertices' is specified by 'num' and has to be three * at least. If the chosen 'formation' is DTTF_LIST, * it also has to be a multiple of three. */ DFBResult (*TextureTriangles) ( IDirectFBSurface *thiz, IDirectFBSurface *texture, const DFBVertex *vertices, const int *indices, int num, DFBTriangleFormation formation ); /** Drawing functions **/ /* * Set the flags for all subsequent drawing commands. */ DFBResult (*SetDrawingFlags) ( IDirectFBSurface *thiz, DFBSurfaceDrawingFlags flags ); /* * Fill the specified rectangle with the given color * following the drawing flags. */ DFBResult (*FillRectangle) ( IDirectFBSurface *thiz, int x, int y, int w, int h ); /* * Draw an outline of the specified rectangle with the * given color following the drawing flags. */ DFBResult (*DrawRectangle) ( IDirectFBSurface *thiz, int x, int y, int w, int h ); /* * Draw a line from one point to the other with the given * color following the drawing flags. */ DFBResult (*DrawLine) ( IDirectFBSurface *thiz, int x1, int y1, int x2, int y2 ); /* * Draw lines. * * Draw 'num_lines' lines with the given color following * the drawing flags. Each line specified by a DFBRegion. */ DFBResult (*DrawLines) ( IDirectFBSurface *thiz, const DFBRegion *lines, unsigned int num_lines ); /* * Fill a non-textured triangle with the given color * following the drawing flags. */ DFBResult (*FillTriangle) ( IDirectFBSurface *thiz, int x1, int y1, int x2, int y2, int x3, int y3 ); /* * Fill a bunch of rectangles with a single call. * * Fill 'num_rects' rectangles with the current color * following the drawing flags. Each rectangle specified * by a DFBRectangle. */ DFBResult (*FillRectangles) ( IDirectFBSurface *thiz, const DFBRectangle *rects, unsigned int num_rects ); /* * Fill spans. * * Fill 'num_spans' spans with the given color following * the drawing flags. Each span is specified by a DFBSpan. */ DFBResult (*FillSpans) ( IDirectFBSurface *thiz, int y, const DFBSpan *spans, unsigned int num_spans ); /* * Fill a bunch of triangles with a single call. * * Fill 'num_tris' triangles with the current color * following the drawing flags. Each triangle specified * by a DFBTriangle. */ DFBResult (*FillTriangles) ( IDirectFBSurface *thiz, const DFBTriangle *tris, unsigned int num_tris ); /** Text functions **/ /* * Set the font used by DrawString() and DrawGlyph(). * You can pass NULL here to unset the font. */ DFBResult (*SetFont) ( IDirectFBSurface *thiz, IDirectFBFont *font ); /* * Get the font associated with a surface. * * This function increases the font's reference count. */ DFBResult (*GetFont) ( IDirectFBSurface *thiz, IDirectFBFont **ret_interface ); /* * Draw a string at the specified position with the given * color following the specified flags. * * Bytes specifies the number of bytes to take from the * string or -1 for the complete NULL-terminated string. * You need to set a font using the SetFont() method before * calling this function. */ DFBResult (*DrawString) ( IDirectFBSurface *thiz, const char *text, int bytes, int x, int y, DFBSurfaceTextFlags flags ); /* * Draw a single glyph specified by its character code at * the specified position with the given color following * the specified flags. * * If font was loaded with the DFFA_NOCHARMAP flag, index * specifies the raw glyph index in the font. * You need to set a font using the SetFont() method before * calling this function. */ DFBResult (*DrawGlyph) ( IDirectFBSurface *thiz, unsigned int character, int x, int y, DFBSurfaceTextFlags flags ); /* * Change the encoding used for text rendering. */ DFBResult (*SetEncoding) ( IDirectFBSurface *thiz, DFBTextEncodingID encoding ); /** Lightweight helpers **/ /* * Get an interface to a sub area of this surface. * * No image data is duplicated, this is a clipped graphics * within the original surface. This is very helpful for * lightweight components in a GUI toolkit. The new * surface's state (color, drawing flags, etc.) is * independent from this one. So it's a handy graphics * context. If no rectangle is specified, the whole surface * (or a part if this surface is a subsurface itself) is * represented by the new one. */ DFBResult (*GetSubSurface) ( IDirectFBSurface *thiz, const DFBRectangle *rect, IDirectFBSurface **ret_interface ); /** OpenGL **/ /* * Get a unique OpenGL context for this surface. */ DFBResult (*GetGL) ( IDirectFBSurface *thiz, IDirectFBGL **ret_interface ); /** Debug **/ /* * Dump the contents of the surface to one or two files. * * Create a PPM file containing the RGB data and a PGM file * with the alpha data if present. * The complete filenames will be * 'directory'/'prefix'_####.ppm for RGB and * 'directory'/'prefix'_####.pgm for the alpha channel * if present. * No existing files will be overwritten. */ DFBResult (*Dump) ( IDirectFBSurface *thiz, const char *directory, const char *prefix ); /* * Disable hardware acceleration. * * If any function in 'mask' is set, acceleration will not * be used for it. Default is DFXL_NONE. */ DFBResult (*DisableAcceleration) ( IDirectFBSurface *thiz, DFBAccelerationMask mask ); /** Resources **/ /* * Release possible reference to source surface. * * For performance reasons the last surface that has been * used for Blit() and others stays attached to the state * of the destination surface to save the overhead of * reprogramming the same values each time. The worst case * is generation of thumbnails using StretchBlit() from a * huge surface to a small one. The small thumbnail surface * keeps the big one alive, because no other blitting will * be done to the small surface afterwards. To solve this, * here is the method to use in such a case. */ DFBResult (*ReleaseSource) ( IDirectFBSurface *thiz ); /** Blitting control **/ /* * Set index translation table. * * Set the translation table used for fast indexed to * indexed pixel format conversion. A negative index means * that the pixel will not be written. * Undefined indices will be treated like negative ones. */ DFBResult (*SetIndexTranslation) ( IDirectFBSurface *thiz, const int *indices, int num_indices ); /** Rendering **/ /* * Set options affecting the output of drawing and blitting * operations. * * None of these is mandatory and therefore unsupported * flags will not cause a software fallback. */ DFBResult (*SetRenderOptions) ( IDirectFBSurface *thiz, DFBSurfaceRenderOptions options ); /** Drawing/blitting control **/ /* * Set the transformation matrix. * * Enable usage of this matrix by setting DSRO_MATRIX via * SetRenderOptions(). * The order in the array is from left to right and from * top to bottom. * All drawing and blitting will be transformed: * X' = (X * v0 + Y * v1 + v2) / (X * v6 + Y * v7 + v8) * Y' = (X * v3 + Y * v4 + v5) / (X * v6 + Y * v7 + v8) */ DFBResult (*SetMatrix) ( IDirectFBSurface *thiz, const s32 *matrix ); /* * Set the surface to be used as a mask for blitting. * * The 'mask' applies when DSBLIT_SRC_MASK_ALPHA or * DSBLIT_SRC_MASK_COLOR is used. * Depending on the 'flags' reading either starts at a * fixed location in the mask with absolute 'x' and 'y', * or at the same location as in the source, with 'x'and * and 'y' used as an offset. */ DFBResult (*SetSourceMask) ( IDirectFBSurface *thiz, IDirectFBSurface *mask, int x, int y, DFBSurfaceMaskFlags flags ); /** Lightweight helpers **/ /* * Make this a sub surface or adjust the rectangle of this * sub surface. */ DFBResult (*MakeSubSurface) ( IDirectFBSurface *thiz, IDirectFBSurface *from, const DFBRectangle *rect ); /** Direct Write/Read **/ /* * Write to the surface without the need for (Un)Lock(). * * 'rect' defines the area inside the surface. * 'ptr' and 'pitch' specify the source. * The format of the surface and the source data must be * the same. */ DFBResult (*Write) ( IDirectFBSurface *thiz, const DFBRectangle *rect, const void *ptr, int pitch ); /* * Read from the surface without the need for (Un)Lock(). * * 'rect' defines the area inside the surface to be read. * 'ptr' and 'pitch' specify the destination. * The destination data will have the same format as the * surface. */ DFBResult (*Read) ( IDirectFBSurface *thiz, const DFBRectangle *rect, void *ptr, int pitch ); /** Drawing/blitting control **/ /* * Set color values used for drawing/text functions or * alpha/color modulation (blitting functions). */ DFBResult (*SetColors) ( IDirectFBSurface *thiz, const DFBColorID *ids, const DFBColor *colors, unsigned int num ); /** Blitting functions **/ /* * Blit a bunch of areas at once using secondary source for * reading instead of destination. * * Source may be the same surface. */ DFBResult (*BatchBlit2) ( IDirectFBSurface *thiz, IDirectFBSurface *source, IDirectFBSurface *source2, const DFBRectangle *source_rects, const DFBPoint *dest_points, const DFBPoint *source2_points, int num ); /** Buffer operations **/ /* * Return the physical address of a locked surface. * * The surface must exist in a video memory pool. */ DFBResult (*GetPhysicalAddress) ( IDirectFBSurface *thiz, unsigned long *addr ); /** Drawing functions **/ /* * Fill a bunch of trapezoids with a single call. * * Fill 'num_traps' trapezoids with the current color * following the drawing flags. Each trapezoid specified * by a DFBTrapezoid. */ DFBResult (*FillTrapezoids) ( IDirectFBSurface *thiz, const DFBTrapezoid *traps, unsigned int num_traps ); /* * Fill quadrangles with the given color following the * drawing flags. */ DFBResult (*FillQuadrangles) ( IDirectFBSurface *thiz, const DFBPoint *points, unsigned int num_points ); /** Extended color keys **/ /* * Set extended source color keying. */ DFBResult (*SetSrcColorKeyExtended) ( IDirectFBSurface *thiz, const DFBColorKeyExtended *colorkey_extended ); /* * Set extended destination color keying. */ DFBResult (*SetDstColorKeyExtended) ( IDirectFBSurface *thiz, const DFBColorKeyExtended *colorkey_extended ); /** Drawing functions **/ /* * Blit monochrome glyph data with attributes. */ DFBResult (*DrawMonoGlyphs) ( IDirectFBSurface *thiz, const void *glyph[], const DFBMonoGlyphAttributes *attributes, const DFBPoint *dest_points, unsigned int num ); /** Blitting control **/ /* * Set the source color matrix. * * Enable usage of this matrix by setting * DSBLIT_SRC_COLORMATRIX via SetBlittingFlags(). * The order in the array is from left to right and from * top to bottom. * All RGB values will be transformed: * R' = R * v0 + G * v1 + B * v2 + v3 * G' = R * v4 + G * v5 + B * v6 + v7 * B' = R * v8 + G * v9 + B * v10 + v11 */ DFBResult (*SetSrcColorMatrix) ( IDirectFBSurface *thiz, const s32 *matrix ); /* * Set the source convolution filter. * * Enable usage of this filter by setting * DSBLIT_SRC_CONVOLUTION via SetBlittingFlags(). */ DFBResult (*SetSrcConvolution) ( IDirectFBSurface *thiz, const DFBConvolutionFilter *filter ); /** Retrieving information **/ /* * Get the unique surface ID. */ DFBResult (*GetID) ( IDirectFBSurface *thiz, DFBSurfaceID *ret_surface_id ); /** Process security **/ /* * Allow access. */ DFBResult (*AllowAccess) ( IDirectFBSurface *thiz, const char *executable ); /** Event buffers **/ /* * Create an event buffer for this surface and attach it. */ DFBResult (*CreateEventBuffer) ( IDirectFBSurface *thiz, IDirectFBEventBuffer **ret_interface ); /* * Attach an existing event buffer to this surface. * * Note: attaching multiple times generates multiple * events. */ DFBResult (*AttachEventBuffer) ( IDirectFBSurface *thiz, IDirectFBEventBuffer *buffer ); /* * Detach an event buffer from this surface. */ DFBResult (*DetachEventBuffer) ( IDirectFBSurface *thiz, IDirectFBEventBuffer *buffer ); /** Blitting functions **/ /* * Blit a bunch of areas scaled from the source to the * destination rectangles. * * 'source_rects' and 'dest_rects' will be modified. */ DFBResult (*BatchStretchBlit) ( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rects, const DFBRectangle *dest_rects, int num ); /** Client **/ /* * Put in client mode for frame synchronization. */ DFBResult (*MakeClient) ( IDirectFBSurface *thiz ); /* * Acknowledge frame. */ DFBResult (*FrameAck) ( IDirectFBSurface *thiz, u32 flip_count ); /** Debug **/ /* * Dump the contents of the surface to one or two files in * raw format. * * Create a RAW file containing the ARGB data. * The complete filename will be: * 'directory'/'prefix'_####.raw for ARGB. * No existing files will be overwritten. */ DFBResult (*DumpRaw) ( IDirectFBSurface *thiz, const char *directory, const char *prefix ); /** Timing **/ /* * Retrieve timestamp for next frame to be rendered. */ DFBResult (*GetFrameTime) ( IDirectFBSurface *thiz, long long *ret_micros ); /* * Set configuration for GetFrameTime(). */ DFBResult (*SetFrameTimeConfig) ( IDirectFBSurface *thiz, const DFBFrameTimeConfig *config ); /** Allocations **/ /* * Add implementation specific handle as buffer allocation. */ DFBResult (*Allocate) ( IDirectFBSurface *thiz, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, u64 handle, IDirectFBSurfaceAllocation **ret_interface ); /* * Acquire implementation specific handle from surface. */ DFBResult (*GetAllocation) ( IDirectFBSurface *thiz, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, IDirectFBSurfaceAllocation **ret_interface ); /* * Acquire implementation specific handles from surface. */ DFBResult (*GetAllocations) ( IDirectFBSurface *thiz, const char *key, unsigned int max_num, unsigned int *ret_num, IDirectFBSurfaceAllocation **ret_interface_left, IDirectFBSurfaceAllocation **ret_interface_right ); /** Interface **/ /* * Flush pending drawing operations. * * This function flushes the internal buffer like done * implicitly by Flip(). * This can be used to transfer the interface to another * thread, as call buffers are bound to each thread. */ DFBResult (*Flush) ( IDirectFBSurface *thiz ); ) /****************************** * IDirectFBSurfaceAllocation * ******************************/ /* * IDirectFBSurfaceAllocation is the surface allocation * interface. */ D_DEFINE_INTERFACE( IDirectFBSurfaceAllocation, /** Retrieving information **/ /* * Get a description of the allocation's surface. */ DFBResult (*GetDescription) ( IDirectFBSurfaceAllocation *thiz, DFBSurfaceDescription *ret_desc ); /** Access **/ /* * Get the surface allocation data. */ DFBResult (*GetHandle) ( IDirectFBSurfaceAllocation *thiz, u64 *ret_handle ); /* * Get the surface allocation pitch. */ DFBResult (*GetPitch) ( IDirectFBSurfaceAllocation *thiz, int *ret_pitch ); /* * Updated the allocation's surface. */ DFBResult (*Updated) ( IDirectFBSurfaceAllocation *thiz, const DFBBox *updates, unsigned int num_updates ); ) /******************** * IDirectFBPalette * ********************/ /* * IDirectFBPalette is the palette interface. */ D_DEFINE_INTERFACE( IDirectFBPalette, /** Retrieving information **/ /* * Return the capabilities of this palette. */ DFBResult (*GetCapabilities) ( IDirectFBPalette *thiz, DFBPaletteCapabilities *ret_caps ); /* * Get the number of entries in the palette. */ DFBResult (*GetSize) ( IDirectFBPalette *thiz, unsigned int *ret_size ); /** Palette entries **/ /* * Write entries to the palette. * * Writes the specified number of entries to the palette * at the specified offset. */ DFBResult (*SetEntries) ( IDirectFBPalette *thiz, const DFBColor *entries, unsigned int num_entries, unsigned int offset ); /* * Read entries from the palette. * * Reads the specified number of entries from the palette * at the specified offset. */ DFBResult (*GetEntries) ( IDirectFBPalette *thiz, DFBColor *ret_entries, unsigned int num_entries, unsigned int offset ); /* * Find the best matching entry. * * Searches the map for an entry which best matches the * specified color. */ DFBResult (*FindBestMatch) ( IDirectFBPalette *thiz, u8 r, u8 g, u8 b, u8 a, unsigned int *ret_index ); /** Clone **/ /* * Create a copy of the palette. */ DFBResult (*CreateCopy) ( IDirectFBPalette *thiz, IDirectFBPalette **ret_interface ); /** YUV Palette **/ /* * Write entries to the palette. * * Writes the specified number of entries to the palette * at the specified offset. */ DFBResult (*SetEntriesYUV) ( IDirectFBPalette *thiz, const DFBColorYUV *entries, unsigned int num_entries, unsigned int offset ); /* * Read entries from the palette. * * Reads the specified number of entries from the palette * at the specified offset. */ DFBResult (*GetEntriesYUV) ( IDirectFBPalette *thiz, DFBColorYUV *ret_entries, unsigned int num_entries, unsigned int offset ); /* * Find the best matching entry. * * Searches the map for an entry which best matches the * specified color. */ DFBResult (*FindBestMatchYUV) ( IDirectFBPalette *thiz, u8 y, u8 u, u8 v, u8 a, unsigned int *ret_index ); ) /************************ * IDirectFBInputDevice * ************************/ /* * Specifies whether a key is currently down. */ typedef enum { DIKS_UP = 0x00000000, /* key is not pressed */ DIKS_DOWN = 0x00000001 /* key is pressed */ } DFBInputDeviceKeyState; /* * Flags specifying which modifiers are currently pressed. */ typedef enum { DIMM_SHIFT = (1< = = .... (up to 4) */ DFBResult (*LoadKeymap) ( IDirectFBInputDevice *thiz, char *filename ); /** Event buffers **/ /* * Create an event buffer for this device and attach it. */ DFBResult (*CreateEventBuffer) ( IDirectFBInputDevice *thiz, IDirectFBEventBuffer **ret_interface ); /* * Attach an existing event buffer to this device. * * Note: attaching multiple times generates multiple * events. * */ DFBResult (*AttachEventBuffer) ( IDirectFBInputDevice *thiz, IDirectFBEventBuffer *buffer ); /* * Detach an event buffer from this device. */ DFBResult (*DetachEventBuffer) ( IDirectFBInputDevice *thiz, IDirectFBEventBuffer *buffer ); /** General state queries **/ /* * Get the current state of one key. */ DFBResult (*GetKeyState) ( IDirectFBInputDevice *thiz, DFBInputDeviceKeyIdentifier key_id, DFBInputDeviceKeyState *ret_state ); /* * Get the current modifier mask. */ DFBResult (*GetModifiers) ( IDirectFBInputDevice *thiz, DFBInputDeviceModifierMask *ret_modifiers ); /* * Get the current state of the key locks. */ DFBResult (*GetLockState) ( IDirectFBInputDevice *thiz, DFBInputDeviceLockState *ret_locks ); /* * Get a mask of currently pressed buttons. * * The first button corrensponds to the right most bit. */ DFBResult (*GetButtons) ( IDirectFBInputDevice *thiz, DFBInputDeviceButtonMask *ret_buttons ); /* * Get the state of a button. */ DFBResult (*GetButtonState) ( IDirectFBInputDevice *thiz, DFBInputDeviceButtonIdentifier button, DFBInputDeviceButtonState *ret_state ); /* * Get the current value of the specified axis. */ DFBResult (*GetAxis) ( IDirectFBInputDevice *thiz, DFBInputDeviceAxisIdentifier axis, int *ret_pos ); /** Specialized queries **/ /* * Utility function combining two calls to GetAxis(). * * You may leave one of the x/y arguments NULL. */ DFBResult (*GetXY) ( IDirectFBInputDevice *thiz, int *ret_x, int *ret_y ); /** Configuration **/ /* * Change config values for the input device. */ DFBResult (*SetConfiguration) ( IDirectFBInputDevice *thiz, const DFBInputDeviceConfig *config ); ) /************************ * IDirectFBEventBuffer * ************************/ /* * Event class. */ typedef enum { DFEC_NONE = 0x00000000, /* none of these */ DFEC_INPUT = 0x00000001, /* raw input event */ DFEC_WINDOW = 0x00000002, /* windowing event */ DFEC_USER = 0x00000003, /* custom event for the user */ DFEC_UNIVERSAL = 0x00000004, /* universal event for custom usage with variable size */ DFEC_VIDEOPROVIDER = 0x00000005, /* video provider event */ DFEC_SURFACE = 0x00000006 /* surface event */ } DFBEventClass; /* * The type of an input event. */ typedef enum { DIET_UNKNOWN = 0x00000000, /* unknown event */ DIET_KEYPRESS = 0x00000001, /* a key is been pressed */ DIET_KEYRELEASE = 0x00000002, /* a key is been released */ DIET_BUTTONPRESS = 0x00000003, /* a (mouse) button is been pressed */ DIET_BUTTONRELEASE = 0x00000004, /* a (mouse) button is been released */ DIET_AXISMOTION = 0x00000005, /* mouse/joystick movement */ } DFBInputEventType; /* * Flags defining which additional (optional) event fields are * valid. */ typedef enum { DIEF_NONE = 0x00000000, /* No additional fields. */ DIEF_TIMESTAMP = 0x00000001, /* Timestamp is valid. */ DIEF_AXISABS = 0x00000002, /* Axis and axisabs are valid. */ DIEF_AXISREL = 0x00000004, /* Axis and axisrel are valid. */ DIEF_KEYCODE = 0x00000008, /* Used internally by the input core, always set at application level. */ DIEF_KEYID = 0x00000010, /* Used internally by the input core, always set at application level. */ DIEF_KEYSYMBOL = 0x00000020, /* Used internally by the input core, always set at application level. */ DIEF_MODIFIERS = 0x00000040, /* Used internally by the input core, always set at application level. */ DIEF_LOCKS = 0x00000080, /* Used internally by the input core, always set at application level. */ DIEF_BUTTONS = 0x00000100, /* Used internally by the input core, always set at application level. */ DIEF_GLOBAL = 0x00000200, /* Only for event buffers created by CreateInputEventBuffer() with global events enabled. Indicates that the event would have been filtered if the buffer hadn't been global. */ DIEF_REPEAT = 0x00000400, /* Repeated event, e.g. key or button press. */ DIEF_FOLLOW = 0x00000800, /* Another event will follow immediately, e.g. x/y axis. */ DIEF_MIN = 0x00001000, /* Minimum value is set, e.g. for absolute axis motion. */ DIEF_MAX = 0x00002000 /* Maximum value is set, e.g. for absolute axis motion. */ } DFBInputEventFlags; /* * An input event, item of an input buffer. */ typedef struct { DFBEventClass clazz; /* clazz of event */ DFBInputEventType type; /* type of event */ DFBInputDeviceID device_id; /* source of event */ DFBInputEventFlags flags; /* which optional fields are valid */ struct timeval timestamp; /* time of event creation */ int key_code; /* hardware keycode, no mapping, -1 if device doesn't differentiate between several keys */ DFBInputDeviceKeyIdentifier key_id; /* basic mapping, modifier independent */ DFBInputDeviceKeySymbol key_symbol; /* advanced mapping, unicode compatible, modifier dependent */ DFBInputDeviceModifierMask modifiers; /* pressed modifiers (optional) */ DFBInputDeviceLockState locks; /* active locks (optional) */ DFBInputDeviceButtonIdentifier button; /* in case of a button event */ DFBInputDeviceButtonMask buttons; /* mask of currently pressed buttons */ DFBInputDeviceAxisIdentifier axis; /* in case of an axis event */ int axisabs; /* absolute mouse/joystick coordinate */ int axisrel; /* relative mouse/joystick movement */ int min; /* minimum possible value */ int max; /* maximum possible value */ int slot_id; /* touch contact */ } DFBInputEvent; /* * Window Event Types. * * Can also be used as flags for event filters. */ typedef enum { DWET_NONE = 0x00000000, /* None of these. */ DWET_POSITION = 0x00000001, /* Window has been moved by window manager or the application itself. */ DWET_SIZE = 0x00000002, /* Window has been resized by window manager or the application itself. */ DWET_CLOSE = 0x00000004, /* Closing this window has been requested only. */ DWET_DESTROYED = 0x00000008, /* Window got destroyed by global deinitialization function or the application itself. */ DWET_GOTFOCUS = 0x00000010, /* Window got focus. */ DWET_LOSTFOCUS = 0x00000020, /* Window lost focus. */ DWET_KEYDOWN = 0x00000100, /* A key has gone down while window has focus. */ DWET_KEYUP = 0x00000200, /* A key has gone up while window has focus. */ DWET_BUTTONDOWN = 0x00010000, /* Mouse button went down in the window. */ DWET_BUTTONUP = 0x00020000, /* Mouse button went up in the window. */ DWET_MOTION = 0x00040000, /* Mouse cursor changed its position in window. */ DWET_ENTER = 0x00080000, /* Mouse cursor entered the window. */ DWET_LEAVE = 0x00100000, /* Mouse cursor left the window. */ DWET_WHEEL = 0x00200000, /* Mouse wheel was moved while window has focus. */ DWET_POSITION_SIZE = DWET_POSITION | DWET_SIZE, /* Initially sent to window when it's created. */ DWET_UPDATE = 0x01000000, /* Update event (upon Flip), this way another process can capture the output of the application. */ DWET_ALL = 0x013F033F /* All event types. */ } DFBWindowEventType; /* * Flags for a window event. */ typedef enum { DWEF_NONE = 0x00000000, /* None of these. */ DWEF_RETURNED = 0x00000001, /* This is a returned event, e.g. unconsumed key. */ DWEF_RELATIVE = 0x00000002, /* This is a relative motion event. */ DWEF_REPEAT = 0x00000010, /* This is a repeat event, e.g. repeating key */ DWEF_DEVICE_ID = 0x00000020, /* device_id field of DFBInputEvent is valid. */ DWEF_ALL = 0x00000033 /* All of these. */ } DFBWindowEventFlags; /* * Event from the windowing system. */ typedef struct { DFBEventClass clazz; /* clazz of event */ DFBWindowEventType type; /* type of event */ /* used by DWET_KEYDOWN, DWET_KEYUP */ DFBWindowEventFlags flags; /* event flags */ DFBWindowID window_id; /* window id */ /* used by DWET_MOVE, DWET_MOTION, DWET_BUTTONDOWN, DWET_BUTTONUP, DWET_ENTER, DWET_LEAVE */ int x; /* x position of window or coordinate within window */ int y; /* y position of window or coordinate within window */ /* used by DWET_MOTION, DWET_BUTTONDOWN, DWET_BUTTONUP, DWET_ENTER, DWET_LEAVE */ int cx; /* x cursor position */ int cy; /* y cursor position */ /* used by DWET_WHEEL */ int step; /* wheel step */ /* used by DWET_RESIZE */ int w; /* width of window */ int h; /* height of window */ /* used by DWET_KEYDOWN, DWET_KEYUP */ int key_code; /* hardware keycode, no mapping, -1 if device doesn't differentiate between several keys */ DFBInputDeviceKeyIdentifier key_id; /* basic mapping, modifier independent */ DFBInputDeviceKeySymbol key_symbol; /* advanced mapping, unicode compatible, modifier dependent */ DFBInputDeviceModifierMask modifiers; /* pressed modifiers */ DFBInputDeviceLockState locks; /* active locks */ /* used by DWET_BUTTONDOWN, DWET_BUTTONUP */ DFBInputDeviceButtonIdentifier button; /* button being pressed or released */ /* used by DWET_MOTION, DWET_BUTTONDOWN, DWET_BUTTONUP */ DFBInputDeviceButtonMask buttons; /* mask of currently pressed buttons */ struct timeval timestamp; /* time stamp */ DFBInputDeviceID device_id; /* source of event */ } DFBWindowEvent; /* * Event for usage by the user. */ typedef struct { DFBEventClass clazz; /* clazz of event */ unsigned int type; /* custom type */ void *data; /* custom data */ } DFBUserEvent; /* * Universal event for custom usage with variable size. */ typedef struct { DFBEventClass clazz; /* clazz of event */ unsigned int size; /* size of this event, minimum is sizeof(DFBUniversalEvent) */ /* custom data follows, size of this data is 'size' - sizeof(DFBUniversalEvent) */ } DFBUniversalEvent; /* * Video Provider Event Types. * * Can also be used as flags for event filters. */ typedef enum { DVPET_NONE = 0x00000000, /* None of these. */ DVPET_STARTED = 0x00000001, /* The video provider has started the playback. */ DVPET_STOPPED = 0x00000002, /* The video provider has stopped the playback. */ DVPET_SPEEDCHANGE = 0x00000004, /* A speed change has occurred. */ DVPET_STREAMCHANGE = 0x00000008, /* A stream description change has occurred. */ DVPET_FATALERROR = 0x00000010, /* A fatal error has occurred: restart must be done. */ DVPET_FINISHED = 0x00000020, /* The video provider has finished the playback. */ DVPET_SURFACECHANGE = 0x00000040, /* A surface description change has occurred. */ DVPET_FRAMEDECODED = 0x00000080, /* A frame has been decoded by the decoder. */ DVPET_FRAMEDISPLAYED = 0x00000100, /* A frame has been rendered to the output. */ DVPET_DATAEXHAUSTED = 0x00000200, /* There is no more data available for consumption. */ DVPET_VIDEOACTION = 0x00000400, /* An action is required on the video provider. */ DVPET_DATALOW = 0x00000800, /* The stream buffer is running low in data. */ DVPET_DATAHIGH = 0x00001000, /* The stream buffer is high. */ DVPET_BUFFERTIMELOW = 0x00002000, /* The stream buffer has less than requested playout time buffered. */ DVPET_BUFFERTIMEHIGH = 0x00004000, /* The stream buffer has more than requested playout time buffered. */ DVPET_ALL = 0x00007FFF /* All event types. */ } DFBVideoProviderEventType; /* * Video Provider Event Types. * * Can also be used as flags for event filters. */ typedef enum { DVPEDST_UNKNOWN = 0x00000000, /* Event is valid for unknown data. */ DVPEDST_AUDIO = 0x00000001, /* Event is valid for audio. */ DVPEDST_VIDEO = 0x00000002, /* Event is valid for video. */ DVPEDST_DATA = 0x00000004, /* Event is valid for data. */ DVPEDST_ALL = 0x00000007 /* Event is valid for all data types. */ } DFBVideoProviderEventDataSubType; /* * Event from the video provider */ typedef struct { DFBEventClass clazz; /* clazz of event */ DFBVideoProviderEventType type; /* type of event */ DFBVideoProviderEventDataSubType data_type; /* data type that this event is applicable for */ int data[4]; /* custom data */ } DFBVideoProviderEvent; /* * Surface Event Types. * * Can also be used as flags for event filters. */ typedef enum { DSEVT_NONE = 0x00000000, /* None of these. */ DSEVT_DESTROYED = 0x00000001, /* Surface got destroyed by global deinitialization function or the application itself. */ DSEVT_UPDATE = 0x00000002, /* Update event. */ DSEVT_ALL = 0x00000003 /* All event types. */ } DFBSurfaceEventType; /* * Event from surface */ typedef struct { DFBEventClass clazz; /* clazz of event */ /* all types */ DFBSurfaceEventType type; /* type of event */ DFBSurfaceID surface_id; /* source of event */ long long time_stamp; /* time stamp */ /* DSEVT_UPDATE */ DFBRegion update; /* region update */ DFBRegion update_right; /* right region update */ unsigned int flip_count; /* serial number of frame, modulo number of buffers */ DFBSurfaceFlipFlags flip_flags; /* flipping flags */ } DFBSurfaceEvent; /* * General container for events. */ typedef union { DFBEventClass clazz; /* clazz of event */ DFBInputEvent input; /* field for input events */ DFBWindowEvent window; /* field for window events */ DFBUserEvent user; /* field for user-defined events */ DFBUniversalEvent universal; /* field for universal events */ DFBVideoProviderEvent videoprovider; /* field for video provider */ DFBSurfaceEvent surface; /* field for surface events */ } DFBEvent; #define DFB_EVENT(e) ((DFBEvent*) (e)) /* * Statistics about event buffer queue. */ typedef struct { unsigned int num_events; /* Total number of events in the queue. */ unsigned int DFEC_INPUT; /* Number of input events. */ unsigned int DFEC_WINDOW; /* Number of window events. */ unsigned int DFEC_USER; /* Number of user events. */ unsigned int DFEC_UNIVERSAL; /* Number of universal events. */ unsigned int DFEC_VIDEOPROVIDER; /* Number of video provider events. */ unsigned int DIET_KEYPRESS; unsigned int DIET_KEYRELEASE; unsigned int DIET_BUTTONPRESS; unsigned int DIET_BUTTONRELEASE; unsigned int DIET_AXISMOTION; unsigned int DWET_POSITION; unsigned int DWET_SIZE; unsigned int DWET_CLOSE; unsigned int DWET_DESTROYED; unsigned int DWET_GOTFOCUS; unsigned int DWET_LOSTFOCUS; unsigned int DWET_KEYDOWN; unsigned int DWET_KEYUP; unsigned int DWET_BUTTONDOWN; unsigned int DWET_BUTTONUP; unsigned int DWET_MOTION; unsigned int DWET_ENTER; unsigned int DWET_LEAVE; unsigned int DWET_WHEEL; unsigned int DWET_POSITION_SIZE; unsigned int DVPET_STARTED; unsigned int DVPET_STOPPED; unsigned int DVPET_SPEEDCHANGE; unsigned int DVPET_STREAMCHANGE; unsigned int DVPET_FATALERROR; unsigned int DVPET_FINISHED; unsigned int DVPET_SURFACECHANGE; unsigned int DVPET_FRAMEDECODED; unsigned int DVPET_FRAMEDISPLAYED; unsigned int DVPET_DATAEXHAUSTED; unsigned int DVPET_DATALOW; unsigned int DVPET_VIDEOACTION; unsigned int DVPET_DATAHIGH; unsigned int DVPET_BUFFERTIMELOW; unsigned int DVPET_BUFFERTIMEHIGH; } DFBEventBufferStats; /* * IDirectFBEventBuffer is the event buffer interface. */ D_DEFINE_INTERFACE( IDirectFBEventBuffer, /** Buffer handling **/ /* * Clear all events stored in this buffer. */ DFBResult (*Reset) ( IDirectFBEventBuffer *thiz ); /** Waiting for events **/ /* * Wait for the next event to occur. * * Thread is idle in the meantime. */ DFBResult (*WaitForEvent) ( IDirectFBEventBuffer *thiz ); /* * Block until next event to occur or timeout is reached. * * Thread is idle in the meantime. */ DFBResult (*WaitForEventWithTimeout) ( IDirectFBEventBuffer *thiz, unsigned int seconds, unsigned int milli_seconds ); /** Fetching events **/ /* * Get the next event and remove it from the FIFO. */ DFBResult (*GetEvent) ( IDirectFBEventBuffer *thiz, DFBEvent *ret_event ); /* * Get the next event but leave it there. */ DFBResult (*PeekEvent) ( IDirectFBEventBuffer *thiz, DFBEvent *ret_event ); /* * Check if there is a pending event in the queue. */ DFBResult (*HasEvent) ( IDirectFBEventBuffer *thiz ); /** Sending events **/ /* * Put an event into the FIFO. * * This function does not wait until the event got fetched. */ DFBResult (*PostEvent) ( IDirectFBEventBuffer *thiz, const DFBEvent *event ); /* * Wake up any thread waiting for events in this buffer. * * This method causes any WaitForEvent() or * WaitForEventWithTimeout() call to return with * DFB_INTERRUPTED. */ DFBResult (*WakeUp) ( IDirectFBEventBuffer *thiz ); /** Special handling **/ /* * Create a file descriptor for reading events. * * This method provides an alternative for reading events * from an event buffer. It creates a file descriptor which * can be used in select(), poll() or read(). * In general only non-threaded applications which already * use select() or poll() need it. * This method flushes the event buffer. After calling this * method all other methods except PostEvent() will return * DFB_UNSUPPORTED. * Calling this method again will return DFB_BUSY. */ DFBResult (*CreateFileDescriptor) ( IDirectFBEventBuffer *thiz, int *ret_fd ); /** Statistics **/ /* * Enable/disable collection of event buffer statistics. */ DFBResult (*EnableStatistics) ( IDirectFBEventBuffer *thiz, DFBBoolean enable ); /* * Query collected event buffer statistics. */ DFBResult (*GetStatistics) ( IDirectFBEventBuffer *thiz, DFBEventBufferStats *ret_stats ); ) /******************* * IDirectFBWindow * *******************/ /* * The key selection defines a mode for filtering keys while the * window is having the focus. */ typedef enum { DWKS_ALL = 0x00000000, /* Select all keys (default). */ DWKS_NONE = 0x00000001, /* Don't select any key. */ DWKS_LIST = 0x00000002 /* Select a list of keys. */ } DFBWindowKeySelection; /* * Window geometry mode. */ typedef enum { DWGM_DEFAULT = 0x00000000, /* Use default values. */ DWGM_FOLLOW = 0x00000001, /* Use values of parent window. */ DWGM_RECTANGLE = 0x00000002, /* Use pixel values as defined. */ DWGM_LOCATION = 0x00000003 /* Use relative values as defined. */ } DFBWindowGeometryMode; /* * Window geometry for positioning and scaling of windows * relative to their own bounds. */ typedef struct { DFBWindowGeometryMode mode; /* geometry mode */ DFBRectangle rectangle; /* rectangle */ DFBLocation location; /* location */ } DFBWindowGeometry; /* * Flags for window cursor. */ typedef enum { DWCF_NONE = 0x00000000, /* None of these. */ DWCF_RELATIVE = 0x00000001, /* Receive relative coordinates instead of absolute. */ DWCF_EXPLICIT = 0x00000002, /* If window has focus it's also the pointer window. */ DWCF_UNCLIPPED = 0x00000004, /* Pointer is not clipped against stack boundaries. */ DWCF_TRAPPED = 0x00000008, /* Pointer is clipped against the window boundaries. */ DWCF_FIXED = 0x00000010, /* Pointer does not move at all, but still may send relative motion. */ DWCF_INVISIBLE = 0x00000020, /* Window cursor is not visible. */ DWCF_ALL = 0x0000003F /* All of these. */ } DFBWindowCursorFlags; /* * These are hints for the window manager that indicate what * type of function the window has. The window manager can use * this when determining decoration and behaviour of the window. * The hint must be set before mapping the window. */ typedef enum { DWTH_NORMAL = 0x00000000, /* Normal toplevel window. */ DWTH_DIALOG = 0x00000001, /* Dialog window. */ DWTH_MENU = 0x00000002, /* Window used to implement a menu. */ DWTH_TOOLBAR = 0x00000003, /* Window used to implement toolbars. */ DWTH_SPLASHSCREEN = 0x00000004, /* Window used to display a splash screen during application startup. */ DWTH_UTLIITY = 0x00000005, /* Utility windows which are not detached toolbars or dialogs. */ DWTH_DOCK = 0x00000006, /* Used for creating dock or panel windows. */ DWTH_DESKTOP = 0x00000007, /* Used for creating the desktop background window. */ DWTH_DROPDOWN_MENU = 0x00000008, /* A menu that belongs to a menubar. */ DWTH_POPUP_MENU = 0x00000009, /* A menu that does not belong to a menubar, e.g. a context menu. */ DWTH_TOOLTIP = 0x0000000A, /* A tooltip. */ DWTH_NOTIFICATION = 0x0000000B, /* A notification, typically a bubble that belongs to a status icon. */ DWTH_COMBO = 0x0000000C, /* A popup from a combo box. */ DWTH_DND = 0x0000000D /* A window that is used to implement a DND cursor. */ } DFBWindowTypeHint; /* * Flags for window hint. */ typedef enum { DWHF_NONE = 0x00000000, /* None of these. */ DWHF_MODAL = 0x00000001, /* Set modal hint. */ DWHF_SKIP_TASKBAR = 0x00000002, /* Set skip taskbar hint. */ DWHF_SKIP_PAGER = 0x00000004, /* Set skip pager hint. */ DWHF_URGENCY = 0x00000008, /* Set urgency hint. */ DWHF_ALL = 0x0000000F /* All of these. */ } DFBWindowHintFlags; /* * Window surface swapping policy. */ typedef enum { DWSP_SYSTEMONLY = 0x00000000, /* Never try to swap into video memory. */ DWSP_VIDEOLOW = 0x00000001, /* Try to store in video memory, low priority. */ DWSP_VIDEOHIGH = 0x00000002, /* Try to store in video memory, high priority. */ DWSP_VIDEOONLY = 0x00000003 /* Always and only store in video memory. */ } DFBWindowSurfacePolicy; /* * IDirectFBWindow is the window interface. */ D_DEFINE_INTERFACE( IDirectFBWindow, /** Retrieving information **/ /* * Get the unique window ID. */ DFBResult (*GetID) ( IDirectFBWindow *thiz, DFBWindowID *ret_window_id ); /* * Get the current position of this window. */ DFBResult (*GetPosition) ( IDirectFBWindow *thiz, int *ret_x, int *ret_y ); /* * Get the size of the window in pixels. */ DFBResult (*GetSize) ( IDirectFBWindow *thiz, int *ret_width, int *ret_height ); /** Close & Destroy **/ /* * Send a close message to the window. * * This function sends a message of type DWET_CLOSE to the * window. It does not actually close window. */ DFBResult (*Close) ( IDirectFBWindow *thiz ); /* * Destroy the window and sends a destruction message. * * This function sends a message of type DWET_DESTROY to * the window after removing it from the window stack and * freeing its data. */ DFBResult (*Destroy) ( IDirectFBWindow *thiz ); /** Surface & Scaling **/ /* * Get an interface to the backing store surface. * * This surface has to be flipped to make previous drawing * commands visible, i.e. to repaint the windowstack for * that region. */ DFBResult (*GetSurface) ( IDirectFBWindow *thiz, IDirectFBSurface **ret_interface ); /* * Resize the surface of a scalable window. * * This requires the option DWOP_SCALE. */ DFBResult (*ResizeSurface) ( IDirectFBWindow *thiz, int width, int height ); /** Events **/ /* * Create an event buffer for this window and attach it. */ DFBResult (*CreateEventBuffer) ( IDirectFBWindow *thiz, IDirectFBEventBuffer **ret_interface ); /* * Attach an existing event buffer to this window. * * Note: attaching multiple times generates multiple * events. */ DFBResult (*AttachEventBuffer) ( IDirectFBWindow *thiz, IDirectFBEventBuffer *buffer ); /* * Detach an event buffer from this window. */ DFBResult (*DetachEventBuffer) ( IDirectFBWindow *thiz, IDirectFBEventBuffer *buffer ); /* * Enable specific events to be sent to the window. * * The argument is a mask of events that will be set in the * window's event mask. * The default event mask is DWET_ALL. */ DFBResult (*EnableEvents) ( IDirectFBWindow *thiz, DFBWindowEventType mask ); /* * Disable specific events from being sent to the window. * * The argument is a mask of events that will be cleared in * the window's event mask. * The default event mask is DWET_ALL. */ DFBResult (*DisableEvents) ( IDirectFBWindow *thiz, DFBWindowEventType mask ); /** Options **/ /* * Set options controlling appearance and behaviour of the * window. */ DFBResult (*SetOptions) ( IDirectFBWindow *thiz, DFBWindowOptions options ); /* * Get options controlling appearance and behaviour of the * window. */ DFBResult (*GetOptions) ( IDirectFBWindow *thiz, DFBWindowOptions *ret_options ); /* * Set the window color, or colorises the window. * * In case you specified DWCAPS_COLOR, this sets the window * draw color. In case you didn't, it colorises the window * with this color; this will darken the window. */ DFBResult (*SetColor) ( IDirectFBWindow *thiz, u8 r, u8 g, u8 b, u8 a ); /* * Set the window color key. * * If a pixel of the window matches this color the * underlying window or the background is visible at this * point. */ DFBResult (*SetColorKey) ( IDirectFBWindow *thiz, u8 r, u8 g, u8 b ); /* * Set the window color key (indexed). * * If a pixel (indexed format) of the window matches this * color index the underlying window or the background is * visible at this point. */ DFBResult (*SetColorKeyIndex) ( IDirectFBWindow *thiz, unsigned int index ); /* * Set the window's global opacity factor. * * Set it to 0 to hide a window. Setting it to 0xff makes * the window opaque if it has no alpha channel. */ DFBResult (*SetOpacity) ( IDirectFBWindow *thiz, u8 opacity ); /* * Disable alpha channel blending for one region of the * window. * * If DWOP_ALPHACHANNEL and DWOP_OPAQUE_REGION are set but * not DWOP_COLORKEYING and the opacity of the window is * 0xff, the window gets rendered without alpha blending * within the specified region. This is extremely useful * for alpha blended window decorations while the main * content stays opaque and gets rendered faster. */ DFBResult (*SetOpaqueRegion) ( IDirectFBWindow *thiz, int x1, int y1, int x2, int y2 ); /* * Get the current opacity factor of this window. */ DFBResult (*GetOpacity) ( IDirectFBWindow *thiz, u8 *ret_opacity ); /* * Bind a cursor shape to this window. * * This method will set a per-window cursor shape. * Everytime the cursor enters this window, the specified * shape is set. Passing NULL will unbind a set shape and * release its surface. */ DFBResult (*SetCursorShape) ( IDirectFBWindow *thiz, IDirectFBSurface *shape, int hot_x, int hot_y ); /** Position and Size **/ /* * Move the window by the specified distance. */ DFBResult (*Move) ( IDirectFBWindow *thiz, int dx, int dy ); /* * Move the window to the specified coordinates. */ DFBResult (*MoveTo) ( IDirectFBWindow *thiz, int x, int y ); /* * Resize the window. */ DFBResult (*Resize) ( IDirectFBWindow *thiz, int width, int height ); /* * Set position and size in one step. */ DFBResult (*SetBounds) ( IDirectFBWindow *thiz, int x, int y, int width, int height ); /** Stacking **/ /* * Put the window into a specific stacking class. */ DFBResult (*SetStackingClass) ( IDirectFBWindow *thiz, DFBWindowStackingClass stacking_class ); /* * Raise the window by one within the window stack. */ DFBResult (*Raise) ( IDirectFBWindow *thiz ); /* * Lower the window by one within the window stack. */ DFBResult (*Lower) ( IDirectFBWindow *thiz ); /* * Put the window on the top of the window stack. */ DFBResult (*RaiseToTop) ( IDirectFBWindow *thiz ); /* * Send a window to the bottom of the window stack. */ DFBResult (*LowerToBottom) ( IDirectFBWindow *thiz ); /* * Put a window on top of another window. */ DFBResult (*PutAtop) ( IDirectFBWindow *thiz, IDirectFBWindow *lower ); /* * Put a window below another window. */ DFBResult (*PutBelow) ( IDirectFBWindow *thiz, IDirectFBWindow *upper ); /** Binding **/ /* * Bind a window at the specified position of this window. * * After binding, bound window will be automatically moved * when this window moves to a new position. Binding the * same window to multiple windows is not supported. * Subsequent call to Bind() automatically unbounds the * bound window before binding it again. * To move the bound window to a new position call Bind() * again with the new coordinates. */ DFBResult (*Bind) ( IDirectFBWindow *thiz, IDirectFBWindow *window, int x, int y ); /* * Unbind a window from this window. */ DFBResult (*Unbind) ( IDirectFBWindow *thiz, IDirectFBWindow *window ); /** Focus handling **/ /* * Pass the focus to this window. */ DFBResult (*RequestFocus) ( IDirectFBWindow *thiz ); /* * Grab the keyboard, i.e. all following keyboard events * are sent to this window ignoring the focus. */ DFBResult (*GrabKeyboard) ( IDirectFBWindow *thiz ); /* * Ungrab the keyboard, i.e. switch to standard key event * dispatching. */ DFBResult (*UngrabKeyboard) ( IDirectFBWindow *thiz ); /* * Grab the pointer, i.e. all following mouse events are * sent to this window ignoring the focus. */ DFBResult (*GrabPointer) ( IDirectFBWindow *thiz ); /* * Ungrab the pointer, i.e. switch to standard mouse event * dispatching. */ DFBResult (*UngrabPointer) ( IDirectFBWindow *thiz ); /* * Grab a specific key, i.e. all following events of this * key are sent to this window ignoring the focus. */ DFBResult (*GrabKey) ( IDirectFBWindow *thiz, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ); /* * Ungrab a specific key, i.e. switch to standard key event * dispatching. */ DFBResult (*UngrabKey) ( IDirectFBWindow *thiz, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ); /** Key selection **/ /* * Selects a mode for filtering keys while being focused. * * The 'selection' defines whether all, none or a specific * set of keys is selected. In case of a specific set, the * 'keys' array with 'num_keys' has to be provided. */ DFBResult (*SetKeySelection) ( IDirectFBWindow *thiz, DFBWindowKeySelection selection, const DFBInputDeviceKeySymbol *keys, unsigned int num_keys ); /* * Grab all unselected (filtered out) keys. * * Unselected keys are those not selected by the focused * window. These keys won't be sent to that window. Instead * one window in the stack can collect them. */ DFBResult (*GrabUnselectedKeys) ( IDirectFBWindow *thiz ); /* * Release the grab of unselected (filtered out) keys. */ DFBResult (*UngrabUnselectedKeys) ( IDirectFBWindow *thiz ); /** Advanced Geometry **/ /* * Set area of surface to be shown in window. */ DFBResult (*SetSrcGeometry) ( IDirectFBWindow *thiz, const DFBWindowGeometry *geometry ); /* * Set destination location of window within its bounds. */ DFBResult (*SetDstGeometry) ( IDirectFBWindow *thiz, const DFBWindowGeometry *geometry ); /* * Get stereo depth. */ DFBResult (*GetStereoDepth) ( IDirectFBWindow *thiz, int *ret_z ); /* * Set stereo depth. * * The depth value specified will cause the left eye buffer * content to be shifted on the x-axis by +z and the right * eye buffer to be shifted by -z value. A positive z value * will cause the layer to appear closer than the TV plane * while a negative z value will make the layer appear * farther away. The depth is limited to a value between * +DLSO_FIXED_LIMIT and -DLSO_FIXED_LIMIT. */ DFBResult (*SetStereoDepth) ( IDirectFBWindow *thiz, int z ); /** Properties **/ /* * Set property controlling appearance and behaviour of the * window. */ DFBResult (*SetProperty) ( IDirectFBWindow *thiz, const char *key, void *value, void **ret_old_value ); /* * Get property controlling appearance and behaviour of the * window. */ DFBResult (*GetProperty) ( IDirectFBWindow *thiz, const char *key, void **ret_value ); /* * Remove property controlling appearance and behaviour of * the window. */ DFBResult (*RemoveProperty) ( IDirectFBWindow *thiz, const char *key, void **ret_value ); /* * Set window rotation. */ DFBResult (*SetRotation) ( IDirectFBWindow *thiz, int rotation ); /** Association **/ /* * Change the window association. * * If 'window_id' is 0, the window will be dissociated. */ DFBResult (*SetAssociation) ( IDirectFBWindow *thiz, DFBWindowID window_id ); /** Application ID **/ /* * Set application ID. * * The usage of the application ID is not imposed and can * be used at will by the application. Any change will be * notified, and as such, an application manager can be * used to act on any change. */ DFBResult (*SetApplicationID) ( IDirectFBWindow *thiz, unsigned long application_id ); /* * Get current application ID. */ DFBResult (*GetApplicationID) ( IDirectFBWindow *thiz, unsigned long *ret_application_id ); /** Updates **/ /* * Signal start of window content updates. */ DFBResult (*BeginUpdates) ( IDirectFBWindow *thiz, const DFBRegion *update ); /** Events **/ /* * Send event. */ DFBResult (*SendEvent) ( IDirectFBWindow *thiz, const DFBWindowEvent *event ); /** Cursor **/ /* * Set cursor flags (active when in focus). */ DFBResult (*SetCursorFlags) ( IDirectFBWindow *thiz, DFBWindowCursorFlags flags ); /* * Set cursor resolution. * * The default cursor resolution is the surface dimensions. */ DFBResult (*SetCursorResolution) ( IDirectFBWindow *thiz, const DFBDimension *resolution ); /* * Set cursor position within window coordinates. */ DFBResult (*SetCursorPosition) ( IDirectFBWindow *thiz, int x, int y ); /** Geometry **/ /* * Set area of surface to be shown in window. * Set destination location of window within its bounds. */ DFBResult (*SetGeometry) ( IDirectFBWindow *thiz, const DFBWindowGeometry *src, const DFBWindowGeometry *dst ); /** Extended **/ /* * Set the window type hint. */ DFBResult (*SetTypeHint) ( IDirectFBWindow *thiz, DFBWindowTypeHint type_hint ); /* * Change window hint flags. */ DFBResult (*ChangeHintFlags) ( IDirectFBWindow *thiz, DFBWindowHintFlags clear, DFBWindowHintFlags set ); /** Policy **/ /* * Get the window surface swapping policy. */ DFBResult (*GetPolicy) ( IDirectFBWindow *thiz, DFBWindowSurfacePolicy *ret_policy ); ) /***************** * IDirectFBFont * *****************/ /* * Called for each provided text encoding. */ typedef DFBEnumerationResult (*DFBTextEncodingCallback) ( DFBTextEncodingID encoding_id, const char *name, void *callbackdata ); /* * IDirectFBFont is the font interface. */ D_DEFINE_INTERFACE( IDirectFBFont, /** Retrieving information **/ /* * Get the distance from the baseline to the top of the * logical extents of this font. */ DFBResult (*GetAscender) ( IDirectFBFont *thiz, int *ret_ascender ); /* * Get the distance from the baseline to the bottom of the * logical extents of this font. */ DFBResult (*GetDescender) ( IDirectFBFont *thiz, int *ret_descender ); /* * Get the logical height of this font. * * This is the distance from one baseline to the next when * writing several lines of text. Note that this value does * not correspond the height value specified when loading * the font. */ DFBResult (*GetHeight) ( IDirectFBFont *thiz, int *ret_height ); /* * Get the maximum character width. * * Not all fonts specify it correcly. */ DFBResult (*GetMaxAdvance) ( IDirectFBFont *thiz, int *ret_maxadvance ); /* * Get the kerning to apply between two glyphs specified by * their character codes. */ DFBResult (*GetKerning) ( IDirectFBFont *thiz, unsigned int prev, unsigned int current, int *ret_kern_x, int *ret_kern_y ); /** Measurements **/ /* * Get the logical width of the specified string as if it * were drawn with this font. * * 'bytes' specifies the number of bytes to take from the * string or -1 for the complete NULL-terminated string. * The returned width may be different than the actual * drawn width of the 'text' since this function returns * the logical width that should be used to layout 'text'. * A negative width indicates right-to-left rendering. */ DFBResult (*GetStringWidth) ( IDirectFBFont *thiz, const char *text, int bytes, int *ret_width ); /* * Get the logical and real extents of the specified string * as if it were drawn with this font. * * 'bytes' specifies the number of bytes to take from the * string or -1 for the complete NULL-terminated string. * The logical rectangle describes the typographic extents * and should be used to layout 'text'. The ink rectangle * describes the smallest rectangle containing all pixels * that are touched when drawing the string. If you only * need one of the rectangles, pass NULL for the other one. * The ink rectangle is guaranteed to be a valid rectangle * with positive width and height, while the logical * rectangle may have negative width indicating * right-to-left layout. * The rectangle offsets are reported relative to the * baseline and refer to the text being drawn using * DSTF_LEFT. */ DFBResult (*GetStringExtents) ( IDirectFBFont *thiz, const char *text, int bytes, DFBRectangle *ret_logical_rect, DFBRectangle *ret_ink_rect ); /* * Get the extents of a glyph specified by its character * code. * * The rectangle describes the smallest rectangle * containing all pixels that are touched when drawing the * glyph. It is reported relative to the baseline. If you * only need the advance, pass NULL for the rectangle. * The advance describes the horizontal offset to the next * glyph (without kerning applied). It may be a negative * value indicating left-to-right rendering. If you don't * need this value, pass NULL for advance. */ DFBResult (*GetGlyphExtents) ( IDirectFBFont *thiz, unsigned int character, DFBRectangle *ret_rect, int *ret_advance ); /* * Get the next explicit or automatic break within a string * along with the logical width of the text, the string * length, and a pointer to the next text line. * * The 'bytes' specifies the maximum number of bytes to * take from the string or -1 for complete NULL-terminated * string. * The 'max_width' specifies logical width of column onto * which the 'text' will be drawn. Then the logical width * of fitted text is returned in 'ret_width'. The returned * width may overlap the max width specified if there's * only one character that fits. * The number of characters that fit into this column is * returned by the 'ret_str_length'. Note that you can not * use this value as the number of bytes to take when using * DrawString() as it represents the number of characters, * not the number of bytes. * In 'ret_next_line' a pointer to the next line of text is * returned. This will point to NULL or the end of the * string if there's no more break. */ DFBResult (*GetStringBreak) ( IDirectFBFont *thiz, const char *text, int bytes, int max_width, int *ret_width, int *ret_str_length, const char **ret_next_line ); /** Encodings **/ /* * Change the default encoding used when the font is set * at a surface. */ DFBResult (*SetEncoding) ( IDirectFBFont *thiz, DFBTextEncodingID encoding ); /* * Enumerate all provided text encodings. */ DFBResult (*EnumEncodings) ( IDirectFBFont *thiz, DFBTextEncodingCallback callback, void *callbackdata ); /* * Find an encoding by its name. */ DFBResult (*FindEncoding) ( IDirectFBFont *thiz, const char *name, DFBTextEncodingID *ret_encoding ); /** Resources **/ /* * Dispose resources used by the font. * * Keeps font usable, recreating resources as needed. */ DFBResult (*Dispose) ( IDirectFBFont *thiz ); /** Measurements **/ /* * Get the line spacing vector of this font. * * This is the displacement vector from one line to the * next when writing several lines of text. It differs * from the height only when the font is rotated. */ DFBResult (*GetLineSpacingVector) ( IDirectFBFont *thiz, int *ret_xspacing, int *ret_yspacing ); /* * Get the extents of a glyph specified by its character * code (extended version). * * The rectangle describes the smallest rectangle * containing all pixels that are touched when drawing the * glyph. It is reported relative to the baseline. If you * only need the advance, pass NULL for the rectangle. * The advance describes the horizontal offset to the next * glyph (without kerning applied). It may be a negative * value indicating left-to-right rendering. If you don't * need this value, pass NULL for advance. */ DFBResult (*GetGlyphExtentsXY) ( IDirectFBFont *thiz, unsigned int character, DFBRectangle *ret_rect, int *ret_xadvance, int *ret_yadvance ); /* * Get the position and thickness of the underline. */ DFBResult (*GetUnderline) ( IDirectFBFont *thiz, int *ret_underline_position, int *ret_underline_thichness ); /** Retrieving information **/ /* * Get the description of the font. */ DFBResult (*GetDescription) ( IDirectFBFont *thiz, DFBFontDescription *ret_desc ); ) /************************** * IDirectFBImageProvider * **************************/ /* * Capabilities of an image. */ typedef enum { DICAPS_NONE = 0x00000000, /* None of these. */ DICAPS_ALPHACHANNEL = 0x00000001, /* The image data contains an alphachannel. */ DICAPS_COLORKEY = 0x00000002 /* The image has a colorkey */ } DFBImageCapabilities; /* * Information about an image. */ typedef struct { DFBImageCapabilities caps; /* capabilities */ u8 colorkey_r; /* colorkey red channel */ u8 colorkey_g; /* colorkey green channel */ u8 colorkey_b; /* colorkey blue channel */ } DFBImageDescription; /* * Flags used by an image provider. */ typedef enum { DIRENDER_NONE = 0x00000000, /* None of these. */ DIRENDER_FAST = 0x00000001, /* Select fast rendering method. */ DIRENDER_ALL = 0x00000001 /* All of these. */ } DIRenderFlags; /* * Return value of progressive image loading callback. */ typedef enum { DIRCR_OK = 0x00000000, /* No error occurred. */ DIRCR_ABORT = 0x00000001 /* Abort error */ } DIRenderCallbackResult; /* * Called whenever a chunk of the image is decoded. */ typedef DIRenderCallbackResult (*DIRenderCallback) ( DFBRectangle *rect, void *ctx ); /* * IDirectFBImageProvider is the image provider interface. */ D_DEFINE_INTERFACE( IDirectFBImageProvider, /** Retrieving information **/ /* * Get a surface description that best matches the image * contained in the file. * * For opaque image formats the pixel format of the primary * layer is used. For images with alpha channel an ARGB * surface description is returned. */ DFBResult (*GetSurfaceDescription) ( IDirectFBImageProvider *thiz, DFBSurfaceDescription *ret_desc ); /* * Get a description of the image. * * This includes stuff that does not belong into the * surface description, e.g. a colorkey. */ DFBResult (*GetImageDescription) ( IDirectFBImageProvider *thiz, DFBImageDescription *ret_desc ); /** Rendering **/ /* * Render the file contents into the destination contents * doing automatic scaling and color format conversion. * * If the image file has an alpha channel, it is rendered * with alpha channel if the destination surface is of the * ARGB pixelformat. Otherwise, transparent areas are * blended over a black background. * If a destination rectangle is specified, the rectangle * is clipped to the destination surface. If NULL is passed * as destination rectangle, the whole destination surface * is taken. The image is stretched to fill the rectangle. */ DFBResult (*RenderTo) ( IDirectFBImageProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ); /* * Register a callback for progressive image loading. * * The function is called each time a chunk of the image is * decoded. */ DFBResult (*SetRenderCallback) ( IDirectFBImageProvider *thiz, DIRenderCallback callback, void *ctx ); /* * Set hint for preferred image decoding method. */ DFBResult (*SetRenderFlags) ( IDirectFBImageProvider *thiz, DIRenderFlags flags ); ) /************************** * IDirectFBVideoProvider * **************************/ /* * The video provider capabilities. */ typedef enum { DVCAPS_BASIC = 0x00000000, /* basic ops (play, stop) */ DVCAPS_SEEK = 0x00000001, /* supports seek to a position */ DVCAPS_SCALE = 0x00000002, /* can scale the video */ DVCAPS_INTERLACED = 0x00000004, /* supports interlaced surfaces */ DVCAPS_SPEED = 0x00000008, /* supports changing playback speed */ DVCAPS_BRIGHTNESS = 0x00000010, /* supports brightness adjustment */ DVCAPS_CONTRAST = 0x00000020, /* supports contrast adjustment */ DVCAPS_HUE = 0x00000040, /* supports hue adjustment */ DVCAPS_SATURATION = 0x00000080, /* supports saturation adjustment */ DVCAPS_INTERACTIVE = 0x00000100, /* supports sending an input or window event */ DVCAPS_VOLUME = 0x00000200 /* supports volume adjustment */ } DFBVideoProviderCapabilities; /* * Capabilities of an audio/video stream. */ typedef enum { DVSCAPS_NONE = 0x00000000, /* None of these. */ DVSCAPS_VIDEO = 0x00000001, /* Stream contains video. */ DVSCAPS_AUDIO = 0x00000002 /* Stream contains audio. */ } DFBStreamCapabilities; #define DFB_STREAM_DESC_ENCODING_LENGTH 30 #define DFB_STREAM_DESC_TITLE_LENGTH 255 #define DFB_STREAM_DESC_AUTHOR_LENGTH 255 #define DFB_STREAM_DESC_ALBUM_LENGTH 255 #define DFB_STREAM_DESC_GENRE_LENGTH 32 #define DFB_STREAM_DESC_COMMENT_LENGTH 255 /* * Information about an audio/video stream. */ typedef struct { DFBStreamCapabilities caps; /* capabilities */ struct { char encoding[DFB_STREAM_DESC_ENCODING_LENGTH]; /* encoding (e.g. "h264") */ double framerate; /* number of frames per second */ double aspect; /* frame aspect ratio */ int bitrate; /* amount of bits per second */ int afd; /* active format descriptor */ int width; /* width as reported by sequence header */ int height; /* height as reported by sequence header */ } video; /* struct containing encoding properties for video */ struct { char encoding[DFB_STREAM_DESC_ENCODING_LENGTH]; /* encoding (e.g. "aac") */ int samplerate; /* number of samples per second */ int channels; /* number of channels per sample */ int bitrate; /* amount of bits per second */ } audio; /* struct containing encoding properties for audio */ char title[DFB_STREAM_DESC_TITLE_LENGTH]; /* title */ char author[DFB_STREAM_DESC_AUTHOR_LENGTH]; /* author */ char album[DFB_STREAM_DESC_ALBUM_LENGTH]; /* album */ short year; /* year */ char genre[DFB_STREAM_DESC_GENRE_LENGTH]; /* genre */ char comment[DFB_STREAM_DESC_COMMENT_LENGTH]; /* comment */ } DFBStreamDescription; /* * Status of a video provider. */ typedef enum { DVSTATE_UNKNOWN = 0x00000000, /* unknown status */ DVSTATE_PLAY = 0x00000001, /* playing */ DVSTATE_STOP = 0x00000002, /* playback was stopped */ DVSTATE_FINISHED = 0x00000003, /* playback is finished */ DVSTATE_BUFFERING = 0x00000004 /* buffering, playback is running */ } DFBVideoProviderStatus; /* * Flags controlling playback mode of a video provider. */ typedef enum { DVPLAY_NOFX = 0x00000000, /* normal playback */ DVPLAY_REWIND = 0x00000001, /* reverse playback */ DVPLAY_LOOPING = 0x00000002 /* automatically restart playback when end-of-stream is reached */ } DFBVideoProviderPlaybackFlags; /* * Buffer levels and occupancy for audio/video input buffers. */ typedef struct { DFBStreamCapabilities valid; /* Validation of audio/video. */ struct { unsigned int buffer_size; /* Size in bytes of the input buffer to video decoder. */ unsigned int minimum_level; /* The level at which a DVPET_DATALOW event will be generated. */ unsigned int maximum_level; /* The level at which a DVPET_DATAHIGH event will be generated. */ unsigned int current_level; /* Current fill level of video input buffer. */ } video; /* Video buffer occupancy. */ struct { unsigned int buffer_size; /* Size in bytes of the input buffer to audio decoder. */ unsigned int minimum_level; /* The level at which a DVPET_DATALOW event will be generated. */ unsigned int maximum_level; /* The level at which a DVPET_DATAHIGH event will be generated. */ unsigned int current_level; /* Current fill level of audio input buffer.*/ } audio; /* Audio buffer occupancy. */ } DFBBufferOccupancy; /* * Buffer thresholds for audio/video. */ typedef struct { DFBStreamCapabilities selection; /* Validation of audio/video. */ struct { unsigned int minimum_level; /* The level at which a DVPET_DATALOW event will be generated. */ unsigned int maximum_level; /* The level at which a DVPET_DATAHIGH event will be generated. */ unsigned int minimum_time; /* The buffering time at which a DVPET_BUFFERTIMELOW event will be generated. */ unsigned int maximum_time; /* The buffering time at which a DVPET_BUFFERTIMEHIGH event will be generated. */ } video; /* Video buffer thresholds. */ struct { unsigned int minimum_level; /* The level at which a DVPET_DATALOW event will be generated. */ unsigned int maximum_level; /* The level at which a DVPET_DATAHIGH event will be generated. */ unsigned int minimum_time; /* The buffering time at which a DVPET_BUFFERTIMELOW event will be generated. */ unsigned int maximum_time; /* The buffering time at which a DVPET_BUFFERTIMEHIGH event will be generated. */ } audio; /* Audio buffer thresholds. */ } DFBBufferThresholds; /* * Called for each written frame. */ typedef void (*DVFrameCallback) ( void *ctx ); /* * IDirectFBVideoProvider is the video provider interface. */ D_DEFINE_INTERFACE( IDirectFBVideoProvider, /** Retrieving information **/ /* * Retrieve information about the video provider's * capabilities. */ DFBResult (*GetCapabilities) ( IDirectFBVideoProvider *thiz, DFBVideoProviderCapabilities *ret_caps ); /* * Get a surface description that best matches the video * contained in the file. */ DFBResult (*GetSurfaceDescription) ( IDirectFBVideoProvider *thiz, DFBSurfaceDescription *ret_desc ); /* * Get a description of the video stream. */ DFBResult (*GetStreamDescription) ( IDirectFBVideoProvider *thiz, DFBStreamDescription *ret_desc ); /** Playback **/ /* * Play the video rendering it into the specified rectangle * of the destination surface. * * Optionally a callback can be registered that is called * for each rendered frame. This is especially important if * you are playing to a flipping surface. In this case, you * should flip the destination surface in your callback. */ DFBResult (*PlayTo) ( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect, DVFrameCallback callback, void *ctx ); /* * Stop rendering into the destination surface. */ DFBResult (*Stop) ( IDirectFBVideoProvider *thiz ); /* * Get the status of the playback. */ DFBResult (*GetStatus) ( IDirectFBVideoProvider *thiz, DFBVideoProviderStatus *ret_status ); /** Media Control **/ /* * Seek to a position within the stream. */ DFBResult (*SeekTo) ( IDirectFBVideoProvider *thiz, double seconds ); /* * Get current position within the stream. */ DFBResult (*GetPos) ( IDirectFBVideoProvider *thiz, double *ret_seconds ); /* * Get the length of the stream. */ DFBResult (*GetLength) ( IDirectFBVideoProvider *thiz, double *ret_seconds ); /** Color Adjustment **/ /* * Get the current video color settings. */ DFBResult (*GetColorAdjustment) ( IDirectFBVideoProvider *thiz, DFBColorAdjustment *ret_adj ); /* * Adjust the video colors. */ DFBResult (*SetColorAdjustment) ( IDirectFBVideoProvider *thiz, const DFBColorAdjustment *adj ); /** Interactivity **/ /* * Send an input or window event. * * This method allows to redirect events to an interactive * video provider. Events must be relative to the specified * rectangle of the destination surface. */ DFBResult (*SendEvent) ( IDirectFBVideoProvider *thiz, const DFBEvent *event ); /** Advanced control **/ /* * Set the flags controlling playback mode. */ DFBResult (*SetPlaybackFlags) ( IDirectFBVideoProvider *thiz, DFBVideoProviderPlaybackFlags flags ); /* * Set the speed multiplier. * * Values below 1.0 reduce playback speed while values over * 1.0 increase it. * Specifying a value of 0.0 has the effect of putting the * playback in pause mode. */ DFBResult (*SetSpeed) ( IDirectFBVideoProvider *thiz, double multiplier ); /* * Get current speed multiplier. */ DFBResult (*GetSpeed) ( IDirectFBVideoProvider *thiz, double *ret_multiplier ); /* * Set volume level. * * Values between 0.0 and 1.0 adjust the volume level. * Values over 1.0 increase the amplification level. */ DFBResult (*SetVolume) ( IDirectFBVideoProvider *thiz, float level ); /* * Get volume level. */ DFBResult (*GetVolume) ( IDirectFBVideoProvider *thiz, float *ret_level ); /** Event buffers **/ /* * Create an event buffer for this video provider and * attach it. */ DFBResult (*CreateEventBuffer) ( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer **ret_interface ); /* * Attach an existing event buffer to this video provider. */ DFBResult (*AttachEventBuffer) ( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ); /* * Enable specific events to be sent from the video * provider. * * The argument is a mask of events that will be set in the * videoproviders's event mask. * The default event mask is DVPET_ALL. */ DFBResult (*EnableEvents) ( IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ); /* * Disable specific events from being sent from the video * provider. * * The argument is a mask of events that will be cleared in * the video providers's event mask. * The default event mask is DVPET_ALL. */ DFBResult (*DisableEvents) ( IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ); /* * Detach an event buffer from this video provider. */ DFBResult (*DetachEventBuffer) ( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ); /** Buffer control **/ /* * Get buffer occupancy (audio/video) when playing stream. */ DFBResult (*GetBufferOccupancy) ( IDirectFBVideoProvider *thiz, DFBBufferOccupancy *ret_occ ); /* * Set buffer thresholds for the audio/video playback. */ DFBResult (*SetBufferThresholds) ( IDirectFBVideoProvider *thiz, DFBBufferThresholds thresh ); /* * Get buffer thresholds for the audio/video playback. */ DFBResult (*GetBufferThresholds) ( IDirectFBVideoProvider *thiz, DFBBufferThresholds *ret_thresh ); /** Playback **/ /* * Update the video rendering into the specified rectangle * of the destination surface. */ DFBResult (*SetDestination) ( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ); ) /*********************** * IDirectFBDataBuffer * ***********************/ /* * IDirectFBDataBuffer is the data buffer interface. */ D_DEFINE_INTERFACE( IDirectFBDataBuffer, /** Buffer handling **/ /* * Flush all data in this buffer. * * This method only applies to streaming buffers. */ DFBResult (*Flush) ( IDirectFBDataBuffer *thiz ); /* * Finish writing into a streaming buffer. * * Subsequent calls to PutData() will fail, while attempts * to fetch data from the buffer will return EOF unless * there is still data available. */ DFBResult (*Finish) ( IDirectFBDataBuffer *thiz ); /* * Seek to a given byte position. * * This method only applies to static buffers. */ DFBResult (*SeekTo) ( IDirectFBDataBuffer *thiz, unsigned int offset ); /* * Get the current byte position within a static buffer. * * This method only applies to static buffers. */ DFBResult (*GetPosition) ( IDirectFBDataBuffer *thiz, unsigned int *ret_offset ); /* * Get the length of a static or streaming buffer in bytes. * * The length of a static buffer is its static size. * A streaming buffer has a variable length reflecting the * amount of buffered data. */ DFBResult (*GetLength) ( IDirectFBDataBuffer *thiz, unsigned int *ret_length ); /** Waiting for data **/ /* * Wait for data to be available. * * This method blocks until at least the specified number * of bytes is available. */ DFBResult (*WaitForData) ( IDirectFBDataBuffer *thiz, unsigned int length ); /* * Wait for data to be available within an amount of time. * * This method blocks until at least the specified number * of bytes is available or the timeout is reached. */ DFBResult (*WaitForDataWithTimeout) ( IDirectFBDataBuffer *thiz, unsigned int length, unsigned int seconds, unsigned int milli_seconds ); /** Retrieving data **/ /* * Fetch data from a streaming or static buffer. * * Static buffers will increase the data pointer. * Streaming buffers will flush the data portion. * The maximum number of bytes to fetch is specified by * 'length', the actual number of bytes fetched is returned * via 'ret_read'. */ DFBResult (*GetData) ( IDirectFBDataBuffer *thiz, unsigned int length, void *ret_data_ptr, unsigned int *ret_read ); /* * Peek data from a streaming or static buffer. * * Unlike GetData() this method won't increase the data * pointer or flush any portions of the data held. * * Additionally an offset relative to the current data * pointer or beginning of the streaming buffer can be * specified. * The maximum number of bytes to peek is specified by * 'length', the actual number of bytes peeked is returned * via 'ret_read'. */ DFBResult (*PeekData) ( IDirectFBDataBuffer *thiz, unsigned int length, int offset, void *ret_data_ptr, unsigned int *ret_read ); /* * Check if there is data available. */ DFBResult (*HasData) ( IDirectFBDataBuffer *thiz ); /** Providing data **/ /* * Append a block of data to a streaming buffer. * * This method does not wait until the data got fetched. * Static buffers don't support this method. */ DFBResult (*PutData) ( IDirectFBDataBuffer *thiz, const void *data_ptr, unsigned int length ); /** Media from data **/ /* * Create an image provider using the buffers data. */ DFBResult (*CreateImageProvider) ( IDirectFBDataBuffer *thiz, IDirectFBImageProvider **ret_interface ); /* * Create a video provider using the buffers data. */ DFBResult (*CreateVideoProvider) ( IDirectFBDataBuffer *thiz, IDirectFBVideoProvider **ret_interface ); /* * Load a font using the buffer's data, given a description * of how to load the glyphs. */ DFBResult (*CreateFont) ( IDirectFBDataBuffer *thiz, const DFBFontDescription *desc, IDirectFBFont **ret_interface ); ) #ifdef __cplusplus } #endif #endif ================================================ FILE: include/directfb_keyboard.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFB_KEYBOARD_H__ #define __DIRECTFB_KEYBOARD_H__ /* * DirectFB key types (for advanced mapping). */ typedef enum { DIKT_UNICODE = 0x0000, /* Unicode 3.x character (compatible to Latin-1) */ DIKT_SPECIAL = 0xF000, /* Special key (e.g. Cursor Up or Menu) */ DIKT_FUNCTION = 0xF100, /* Function key (F1 - Fn) */ DIKT_MODIFIER = 0xF200, /* Modifier key */ DIKT_LOCK = 0xF300, /* Lock key (e.g. CapsLock) */ DIKT_DEAD = 0xF400, /* Dead key (e.g. dead grave) */ DIKT_CUSTOM = 0xF500, /* Custom key (vendor specific) */ DIKT_IDENTIFIER = 0xF600 /* DirectFB key identifier */ } DFBInputDeviceKeyType; #define DFB_KEY(type,index) ((DIKT_##type) | (index)) #define DFB_KEY_TYPE(symbol) ((((symbol) & ~0xFFF) == 0xF000) ? (symbol) & 0xFF00 : DIKT_UNICODE) #define DFB_KEY_IS_ASCII(symbol) ((symbol) < 128) #define DFB_FUNCTION_KEY(n) (DFB_KEY( FUNCTION, n )) #define DFB_MODIFIER_KEY(i) (DFB_KEY( MODIFIER, (1 << i) )) #define DFB_CUSTOM_KEY(n) (DFB_KEY( CUSTOM, n )) #define DFB_LOWER_CASE(symbol) (((symbol) >= 'A' && (symbol) <= 'Z') ? ((symbol) | 0x20) : (symbol)) #define DFB_UPPER_CASE(symbol) (((symbol) >= 'a' && (symbol) <= 'z') ? ((symbol) & ~0x20) : (symbol)) /* * DirectFB modifier key identifiers (for advanced mapping). */ typedef enum { DIMKI_SHIFT, DIMKI_CONTROL, DIMKI_ALT, DIMKI_ALTGR, DIMKI_META, DIMKI_SUPER, DIMKI_HYPER, DIMKI_FIRST = DIMKI_SHIFT, DIMKI_LAST = DIMKI_HYPER } DFBInputDeviceModifierKeyIdentifier; /* * DirectFB key identifiers (for basic mapping). */ typedef enum { DIKI_UNKNOWN = DFB_KEY( IDENTIFIER, 0 ), DIKI_A, DIKI_B, DIKI_C, DIKI_D, DIKI_E, DIKI_F, DIKI_G, DIKI_H, DIKI_I, DIKI_J, DIKI_K, DIKI_L, DIKI_M, DIKI_N, DIKI_O, DIKI_P, DIKI_Q, DIKI_R, DIKI_S, DIKI_T, DIKI_U, DIKI_V, DIKI_W, DIKI_X, DIKI_Y, DIKI_Z, DIKI_0, DIKI_1, DIKI_2, DIKI_3, DIKI_4, DIKI_5, DIKI_6, DIKI_7, DIKI_8, DIKI_9, DIKI_F1, DIKI_F2, DIKI_F3, DIKI_F4, DIKI_F5, DIKI_F6, DIKI_F7, DIKI_F8, DIKI_F9, DIKI_F10, DIKI_F11, DIKI_F12, DIKI_SHIFT_L, DIKI_SHIFT_R, DIKI_CONTROL_L, DIKI_CONTROL_R, DIKI_ALT_L, DIKI_ALT_R, DIKI_META_L, DIKI_META_R, DIKI_SUPER_L, DIKI_SUPER_R, DIKI_HYPER_L, DIKI_HYPER_R, DIKI_CAPS_LOCK, DIKI_NUM_LOCK, DIKI_SCROLL_LOCK, DIKI_ESCAPE, DIKI_LEFT, DIKI_RIGHT, DIKI_UP, DIKI_DOWN, DIKI_TAB, DIKI_ENTER, DIKI_SPACE, DIKI_BACKSPACE, DIKI_INSERT, DIKI_DELETE, DIKI_HOME, DIKI_END, DIKI_PAGE_UP, DIKI_PAGE_DOWN, DIKI_PRINT, DIKI_PAUSE, /* * The labels on these keys depend on the type of keyboard. * We've choosen the names from a US keyboard layout. */ DIKI_QUOTE_LEFT, DIKI_MINUS_SIGN, DIKI_EQUALS_SIGN, DIKI_BRACKET_LEFT, DIKI_BRACKET_RIGHT, DIKI_BACKSLASH, DIKI_SEMICOLON, DIKI_QUOTE_RIGHT, DIKI_COMMA, DIKI_PERIOD, DIKI_SLASH, DIKI_LESS_SIGN, DIKI_KP_DIV, DIKI_KP_MULT, DIKI_KP_MINUS, DIKI_KP_PLUS, DIKI_KP_ENTER, DIKI_KP_SPACE, DIKI_KP_TAB, DIKI_KP_F1, DIKI_KP_F2, DIKI_KP_F3, DIKI_KP_F4, DIKI_KP_EQUAL, DIKI_KP_SEPARATOR, DIKI_KP_DECIMAL, DIKI_KP_0, DIKI_KP_1, DIKI_KP_2, DIKI_KP_3, DIKI_KP_4, DIKI_KP_5, DIKI_KP_6, DIKI_KP_7, DIKI_KP_8, DIKI_KP_9, DIKI_KEYDEF_END, DIKI_NUMBER_OF_KEYS = DIKI_KEYDEF_END - DFB_KEY( IDENTIFIER, 0 ) } DFBInputDeviceKeyIdentifier; /* * DirectFB key symbols (for advanced mapping). */ typedef enum { /* * Unicode excerpt - Controls and Basic Latin * Any Unicode 3.x character can be used as a key symbol. * The values of this enum are compatible with Unicode. */ DIKS_NULL = DFB_KEY( UNICODE, 0x00 ), DIKS_BACKSPACE = DFB_KEY( UNICODE, 0x08 ), DIKS_TAB = DFB_KEY( UNICODE, 0x09 ), DIKS_RETURN = DFB_KEY( UNICODE, 0x0D ), DIKS_CANCEL = DFB_KEY( UNICODE, 0x18 ), DIKS_ESCAPE = DFB_KEY( UNICODE, 0x1B ), DIKS_SPACE = DFB_KEY( UNICODE, 0x20 ), DIKS_EXCLAMATION_MARK = DFB_KEY( UNICODE, 0x21 ), DIKS_QUOTATION = DFB_KEY( UNICODE, 0x22 ), DIKS_NUMBER_SIGN = DFB_KEY( UNICODE, 0x23 ), DIKS_DOLLAR_SIGN = DFB_KEY( UNICODE, 0x24 ), DIKS_PERCENT_SIGN = DFB_KEY( UNICODE, 0x25 ), DIKS_AMPERSAND = DFB_KEY( UNICODE, 0x26 ), DIKS_APOSTROPHE = DFB_KEY( UNICODE, 0x27 ), DIKS_PARENTHESIS_LEFT = DFB_KEY( UNICODE, 0x28 ), DIKS_PARENTHESIS_RIGHT = DFB_KEY( UNICODE, 0x29 ), DIKS_ASTERISK = DFB_KEY( UNICODE, 0x2A ), DIKS_PLUS_SIGN = DFB_KEY( UNICODE, 0x2B ), DIKS_COMMA = DFB_KEY( UNICODE, 0x2C ), DIKS_MINUS_SIGN = DFB_KEY( UNICODE, 0x2D ), DIKS_PERIOD = DFB_KEY( UNICODE, 0x2E ), DIKS_SLASH = DFB_KEY( UNICODE, 0x2F ), DIKS_0 = DFB_KEY( UNICODE, 0x30 ), DIKS_1 = DFB_KEY( UNICODE, 0x31 ), DIKS_2 = DFB_KEY( UNICODE, 0x32 ), DIKS_3 = DFB_KEY( UNICODE, 0x33 ), DIKS_4 = DFB_KEY( UNICODE, 0x34 ), DIKS_5 = DFB_KEY( UNICODE, 0x35 ), DIKS_6 = DFB_KEY( UNICODE, 0x36 ), DIKS_7 = DFB_KEY( UNICODE, 0x37 ), DIKS_8 = DFB_KEY( UNICODE, 0x38 ), DIKS_9 = DFB_KEY( UNICODE, 0x39 ), DIKS_COLON = DFB_KEY( UNICODE, 0x3A ), DIKS_SEMICOLON = DFB_KEY( UNICODE, 0x3B ), DIKS_LESS_THAN_SIGN = DFB_KEY( UNICODE, 0x3C ), DIKS_EQUALS_SIGN = DFB_KEY( UNICODE, 0x3D ), DIKS_GREATER_THAN_SIGN = DFB_KEY( UNICODE, 0x3E ), DIKS_QUESTION_MARK = DFB_KEY( UNICODE, 0x3F ), DIKS_AT = DFB_KEY( UNICODE, 0x40 ), DIKS_CAPITAL_A = DFB_KEY( UNICODE, 0x41 ), DIKS_CAPITAL_B = DFB_KEY( UNICODE, 0x42 ), DIKS_CAPITAL_C = DFB_KEY( UNICODE, 0x43 ), DIKS_CAPITAL_D = DFB_KEY( UNICODE, 0x44 ), DIKS_CAPITAL_E = DFB_KEY( UNICODE, 0x45 ), DIKS_CAPITAL_F = DFB_KEY( UNICODE, 0x46 ), DIKS_CAPITAL_G = DFB_KEY( UNICODE, 0x47 ), DIKS_CAPITAL_H = DFB_KEY( UNICODE, 0x48 ), DIKS_CAPITAL_I = DFB_KEY( UNICODE, 0x49 ), DIKS_CAPITAL_J = DFB_KEY( UNICODE, 0x4A ), DIKS_CAPITAL_K = DFB_KEY( UNICODE, 0x4B ), DIKS_CAPITAL_L = DFB_KEY( UNICODE, 0x4C ), DIKS_CAPITAL_M = DFB_KEY( UNICODE, 0x4D ), DIKS_CAPITAL_N = DFB_KEY( UNICODE, 0x4E ), DIKS_CAPITAL_O = DFB_KEY( UNICODE, 0x4F ), DIKS_CAPITAL_P = DFB_KEY( UNICODE, 0x50 ), DIKS_CAPITAL_Q = DFB_KEY( UNICODE, 0x51 ), DIKS_CAPITAL_R = DFB_KEY( UNICODE, 0x52 ), DIKS_CAPITAL_S = DFB_KEY( UNICODE, 0x53 ), DIKS_CAPITAL_T = DFB_KEY( UNICODE, 0x54 ), DIKS_CAPITAL_U = DFB_KEY( UNICODE, 0x55 ), DIKS_CAPITAL_V = DFB_KEY( UNICODE, 0x56 ), DIKS_CAPITAL_W = DFB_KEY( UNICODE, 0x57 ), DIKS_CAPITAL_X = DFB_KEY( UNICODE, 0x58 ), DIKS_CAPITAL_Y = DFB_KEY( UNICODE, 0x59 ), DIKS_CAPITAL_Z = DFB_KEY( UNICODE, 0x5A ), DIKS_SQUARE_BRACKET_LEFT = DFB_KEY( UNICODE, 0x5B ), DIKS_BACKSLASH = DFB_KEY( UNICODE, 0x5C ), DIKS_SQUARE_BRACKET_RIGHT = DFB_KEY( UNICODE, 0x5D ), DIKS_CIRCUMFLEX_ACCENT = DFB_KEY( UNICODE, 0x5E ), DIKS_UNDERSCORE = DFB_KEY( UNICODE, 0x5F ), DIKS_GRAVE_ACCENT = DFB_KEY( UNICODE, 0x60 ), DIKS_SMALL_A = DFB_KEY( UNICODE, 0x61 ), DIKS_SMALL_B = DFB_KEY( UNICODE, 0x62 ), DIKS_SMALL_C = DFB_KEY( UNICODE, 0x63 ), DIKS_SMALL_D = DFB_KEY( UNICODE, 0x64 ), DIKS_SMALL_E = DFB_KEY( UNICODE, 0x65 ), DIKS_SMALL_F = DFB_KEY( UNICODE, 0x66 ), DIKS_SMALL_G = DFB_KEY( UNICODE, 0x67 ), DIKS_SMALL_H = DFB_KEY( UNICODE, 0x68 ), DIKS_SMALL_I = DFB_KEY( UNICODE, 0x69 ), DIKS_SMALL_J = DFB_KEY( UNICODE, 0x6A ), DIKS_SMALL_K = DFB_KEY( UNICODE, 0x6B ), DIKS_SMALL_L = DFB_KEY( UNICODE, 0x6C ), DIKS_SMALL_M = DFB_KEY( UNICODE, 0x6D ), DIKS_SMALL_N = DFB_KEY( UNICODE, 0x6E ), DIKS_SMALL_O = DFB_KEY( UNICODE, 0x6F ), DIKS_SMALL_P = DFB_KEY( UNICODE, 0x70 ), DIKS_SMALL_Q = DFB_KEY( UNICODE, 0x71 ), DIKS_SMALL_R = DFB_KEY( UNICODE, 0x72 ), DIKS_SMALL_S = DFB_KEY( UNICODE, 0x73 ), DIKS_SMALL_T = DFB_KEY( UNICODE, 0x74 ), DIKS_SMALL_U = DFB_KEY( UNICODE, 0x75 ), DIKS_SMALL_V = DFB_KEY( UNICODE, 0x76 ), DIKS_SMALL_W = DFB_KEY( UNICODE, 0x77 ), DIKS_SMALL_X = DFB_KEY( UNICODE, 0x78 ), DIKS_SMALL_Y = DFB_KEY( UNICODE, 0x79 ), DIKS_SMALL_Z = DFB_KEY( UNICODE, 0x7A ), DIKS_CURLY_BRACKET_LEFT = DFB_KEY( UNICODE, 0x7B ), DIKS_VERTICAL_BAR = DFB_KEY( UNICODE, 0x7C ), DIKS_CURLY_BRACKET_RIGHT = DFB_KEY( UNICODE, 0x7D ), DIKS_TILDE = DFB_KEY( UNICODE, 0x7E ), DIKS_DELETE = DFB_KEY( UNICODE, 0x7F ), DIKS_ENTER = DIKS_RETURN, /* * Unicode private area - DirectFB Special keys */ DIKS_CURSOR_LEFT = DFB_KEY( SPECIAL, 0x00 ), DIKS_CURSOR_RIGHT = DFB_KEY( SPECIAL, 0x01 ), DIKS_CURSOR_UP = DFB_KEY( SPECIAL, 0x02 ), DIKS_CURSOR_DOWN = DFB_KEY( SPECIAL, 0x03 ), DIKS_INSERT = DFB_KEY( SPECIAL, 0x04 ), DIKS_HOME = DFB_KEY( SPECIAL, 0x05 ), DIKS_END = DFB_KEY( SPECIAL, 0x06 ), DIKS_PAGE_UP = DFB_KEY( SPECIAL, 0x07 ), DIKS_PAGE_DOWN = DFB_KEY( SPECIAL, 0x08 ), DIKS_PRINT = DFB_KEY( SPECIAL, 0x09 ), DIKS_PAUSE = DFB_KEY( SPECIAL, 0x0A ), DIKS_OK = DFB_KEY( SPECIAL, 0x0B ), DIKS_SELECT = DFB_KEY( SPECIAL, 0x0C ), DIKS_GOTO = DFB_KEY( SPECIAL, 0x0D ), DIKS_CLEAR = DFB_KEY( SPECIAL, 0x0E ), DIKS_POWER = DFB_KEY( SPECIAL, 0x0F ), DIKS_POWER2 = DFB_KEY( SPECIAL, 0x10 ), DIKS_OPTION = DFB_KEY( SPECIAL, 0x11 ), DIKS_MENU = DFB_KEY( SPECIAL, 0x12 ), DIKS_HELP = DFB_KEY( SPECIAL, 0x13 ), DIKS_INFO = DFB_KEY( SPECIAL, 0x14 ), DIKS_TIME = DFB_KEY( SPECIAL, 0x15 ), DIKS_VENDOR = DFB_KEY( SPECIAL, 0x16 ), DIKS_ARCHIVE = DFB_KEY( SPECIAL, 0x17 ), DIKS_PROGRAM = DFB_KEY( SPECIAL, 0x18 ), DIKS_CHANNEL = DFB_KEY( SPECIAL, 0x19 ), DIKS_FAVORITES = DFB_KEY( SPECIAL, 0x1A ), DIKS_EPG = DFB_KEY( SPECIAL, 0x1B ), DIKS_PVR = DFB_KEY( SPECIAL, 0x1C ), DIKS_MHP = DFB_KEY( SPECIAL, 0x1D ), DIKS_LANGUAGE = DFB_KEY( SPECIAL, 0x1E ), DIKS_TITLE = DFB_KEY( SPECIAL, 0x1F ), DIKS_SUBTITLE = DFB_KEY( SPECIAL, 0x20 ), DIKS_ANGLE = DFB_KEY( SPECIAL, 0x21 ), DIKS_ZOOM = DFB_KEY( SPECIAL, 0x22 ), DIKS_MODE = DFB_KEY( SPECIAL, 0x23 ), DIKS_KEYBOARD = DFB_KEY( SPECIAL, 0x24 ), DIKS_PC = DFB_KEY( SPECIAL, 0x25 ), DIKS_SCREEN = DFB_KEY( SPECIAL, 0x26 ), DIKS_TV = DFB_KEY( SPECIAL, 0x27 ), DIKS_TV2 = DFB_KEY( SPECIAL, 0x28 ), DIKS_VCR = DFB_KEY( SPECIAL, 0x29 ), DIKS_VCR2 = DFB_KEY( SPECIAL, 0x2A ), DIKS_SAT = DFB_KEY( SPECIAL, 0x2B ), DIKS_SAT2 = DFB_KEY( SPECIAL, 0x2C ), DIKS_CD = DFB_KEY( SPECIAL, 0x2D ), DIKS_TAPE = DFB_KEY( SPECIAL, 0x2E ), DIKS_RADIO = DFB_KEY( SPECIAL, 0x2F ), DIKS_TUNER = DFB_KEY( SPECIAL, 0x30 ), DIKS_PLAYER = DFB_KEY( SPECIAL, 0x31 ), DIKS_TEXT = DFB_KEY( SPECIAL, 0x32 ), DIKS_DVD = DFB_KEY( SPECIAL, 0x33 ), DIKS_AUX = DFB_KEY( SPECIAL, 0x34 ), DIKS_MP3 = DFB_KEY( SPECIAL, 0x35 ), DIKS_PHONE = DFB_KEY( SPECIAL, 0x36 ), DIKS_AUDIO = DFB_KEY( SPECIAL, 0x37 ), DIKS_VIDEO = DFB_KEY( SPECIAL, 0x38 ), DIKS_INTERNET = DFB_KEY( SPECIAL, 0x39 ), DIKS_MAIL = DFB_KEY( SPECIAL, 0x3A ), DIKS_NEWS = DFB_KEY( SPECIAL, 0x3B ), DIKS_DIRECTORY = DFB_KEY( SPECIAL, 0x3C ), DIKS_LIST = DFB_KEY( SPECIAL, 0x3D ), DIKS_CALCULATOR = DFB_KEY( SPECIAL, 0x3E ), DIKS_MEMO = DFB_KEY( SPECIAL, 0x3F ), DIKS_CALENDAR = DFB_KEY( SPECIAL, 0x40 ), DIKS_EDITOR = DFB_KEY( SPECIAL, 0x41 ), DIKS_RED = DFB_KEY( SPECIAL, 0x42 ), DIKS_GREEN = DFB_KEY( SPECIAL, 0x43 ), DIKS_YELLOW = DFB_KEY( SPECIAL, 0x44 ), DIKS_BLUE = DFB_KEY( SPECIAL, 0x45 ), DIKS_CHANNEL_UP = DFB_KEY( SPECIAL, 0x46 ), DIKS_CHANNEL_DOWN = DFB_KEY( SPECIAL, 0x47 ), DIKS_BACK = DFB_KEY( SPECIAL, 0x48 ), DIKS_FORWARD = DFB_KEY( SPECIAL, 0x49 ), DIKS_FIRST = DFB_KEY( SPECIAL, 0x4A ), DIKS_LAST = DFB_KEY( SPECIAL, 0x4B ), DIKS_VOLUME_UP = DFB_KEY( SPECIAL, 0x4C ), DIKS_VOLUME_DOWN = DFB_KEY( SPECIAL, 0x4D ), DIKS_MUTE = DFB_KEY( SPECIAL, 0x4E ), DIKS_AB = DFB_KEY( SPECIAL, 0x4F ), DIKS_PLAYPAUSE = DFB_KEY( SPECIAL, 0x50 ), DIKS_PLAY = DFB_KEY( SPECIAL, 0x51 ), DIKS_STOP = DFB_KEY( SPECIAL, 0x52 ), DIKS_RESTART = DFB_KEY( SPECIAL, 0x53 ), DIKS_SLOW = DFB_KEY( SPECIAL, 0x54 ), DIKS_FAST = DFB_KEY( SPECIAL, 0x55 ), DIKS_RECORD = DFB_KEY( SPECIAL, 0x56 ), DIKS_EJECT = DFB_KEY( SPECIAL, 0x57 ), DIKS_SHUFFLE = DFB_KEY( SPECIAL, 0x58 ), DIKS_REWIND = DFB_KEY( SPECIAL, 0x59 ), DIKS_FASTFORWARD = DFB_KEY( SPECIAL, 0x5A ), DIKS_PREVIOUS = DFB_KEY( SPECIAL, 0x5B ), DIKS_NEXT = DFB_KEY( SPECIAL, 0x5C ), DIKS_BEGIN = DFB_KEY( SPECIAL, 0x5D ), DIKS_DIGITS = DFB_KEY( SPECIAL, 0x5E ), DIKS_TEEN = DFB_KEY( SPECIAL, 0x5F ), DIKS_TWEN = DFB_KEY( SPECIAL, 0x60 ), DIKS_BREAK = DFB_KEY( SPECIAL, 0x61 ), DIKS_EXIT = DFB_KEY( SPECIAL, 0x62 ), DIKS_SETUP = DFB_KEY( SPECIAL, 0x63 ), DIKS_CURSOR_LEFT_UP = DFB_KEY( SPECIAL, 0x64 ), DIKS_CURSOR_LEFT_DOWN = DFB_KEY( SPECIAL, 0x65 ), DIKS_CURSOR_UP_RIGHT = DFB_KEY( SPECIAL, 0x66 ), DIKS_CURSOR_DOWN_RIGHT = DFB_KEY( SPECIAL, 0x67 ), DIKS_PIP = DFB_KEY( SPECIAL, 0x68 ), DIKS_SWAP = DFB_KEY( SPECIAL, 0x69 ), DIKS_FREEZE = DFB_KEY( SPECIAL, 0x6A ), DIKS_MOVE = DFB_KEY( SPECIAL, 0x6B ), DIKS_CALL = DFB_KEY( SPECIAL, 0x6C ), DIKS_SPEAKER = DFB_KEY( SPECIAL, 0x6D ), DIKS_SAVE = DFB_KEY( SPECIAL, 0x6E ), DIKS_REDIAL = DFB_KEY( SPECIAL, 0x6F ), DIKS_FLASH = DFB_KEY( SPECIAL, 0x70 ), DIKS_HOLD = DFB_KEY( SPECIAL, 0x71 ), /* * Unicode private area - DirectFB Function keys */ DIKS_F1 = DFB_FUNCTION_KEY( 1 ), DIKS_F2 = DFB_FUNCTION_KEY( 2 ), DIKS_F3 = DFB_FUNCTION_KEY( 3 ), DIKS_F4 = DFB_FUNCTION_KEY( 4 ), DIKS_F5 = DFB_FUNCTION_KEY( 5 ), DIKS_F6 = DFB_FUNCTION_KEY( 6 ), DIKS_F7 = DFB_FUNCTION_KEY( 7 ), DIKS_F8 = DFB_FUNCTION_KEY( 8 ), DIKS_F9 = DFB_FUNCTION_KEY( 9 ), DIKS_F10 = DFB_FUNCTION_KEY( 10 ), DIKS_F11 = DFB_FUNCTION_KEY( 11 ), DIKS_F12 = DFB_FUNCTION_KEY( 12 ), /* * Unicode private area - DirectFB Modifier keys */ DIKS_SHIFT = DFB_MODIFIER_KEY( DIMKI_SHIFT ), DIKS_CONTROL = DFB_MODIFIER_KEY( DIMKI_CONTROL ), DIKS_ALT = DFB_MODIFIER_KEY( DIMKI_ALT ), DIKS_ALTGR = DFB_MODIFIER_KEY( DIMKI_ALTGR ), DIKS_META = DFB_MODIFIER_KEY( DIMKI_META ), DIKS_SUPER = DFB_MODIFIER_KEY( DIMKI_SUPER ), DIKS_HYPER = DFB_MODIFIER_KEY( DIMKI_HYPER ), /* * Unicode private area - DirectFB Lock keys */ DIKS_CAPS_LOCK = DFB_KEY( LOCK, 0x00 ), DIKS_NUM_LOCK = DFB_KEY( LOCK, 0x01 ), DIKS_SCROLL_LOCK = DFB_KEY( LOCK, 0x02 ), /* * Unicode private area - DirectFB Dead keys */ DIKS_DEAD_ABOVEDOT = DFB_KEY( DEAD, 0x00 ), DIKS_DEAD_ABOVERING = DFB_KEY( DEAD, 0x01 ), DIKS_DEAD_ACUTE = DFB_KEY( DEAD, 0x02 ), DIKS_DEAD_BREVE = DFB_KEY( DEAD, 0x03 ), DIKS_DEAD_CARON = DFB_KEY( DEAD, 0x04 ), DIKS_DEAD_CEDILLA = DFB_KEY( DEAD, 0x05 ), DIKS_DEAD_CIRCUMFLEX = DFB_KEY( DEAD, 0x06 ), DIKS_DEAD_DIAERESIS = DFB_KEY( DEAD, 0x07 ), DIKS_DEAD_DOUBLEACUTE = DFB_KEY( DEAD, 0x08 ), DIKS_DEAD_GRAVE = DFB_KEY( DEAD, 0x09 ), DIKS_DEAD_IOTA = DFB_KEY( DEAD, 0x0A ), DIKS_DEAD_MACRON = DFB_KEY( DEAD, 0x0B ), DIKS_DEAD_OGONEK = DFB_KEY( DEAD, 0x0C ), DIKS_DEAD_SEMIVOICED_SOUND = DFB_KEY( DEAD, 0x0D ), DIKS_DEAD_TILDE = DFB_KEY( DEAD, 0x0E ), DIKS_DEAD_VOICED_SOUND = DFB_KEY( DEAD, 0x0F ), /* * Unicode private area - DirectFB Custom keys */ DIKS_CUSTOM0 = DFB_CUSTOM_KEY( 0 ), DIKS_CUSTOM1 = DFB_CUSTOM_KEY( 1 ), DIKS_CUSTOM2 = DFB_CUSTOM_KEY( 2 ), DIKS_CUSTOM3 = DFB_CUSTOM_KEY( 3 ), DIKS_CUSTOM4 = DFB_CUSTOM_KEY( 4 ), DIKS_CUSTOM5 = DFB_CUSTOM_KEY( 5 ), DIKS_CUSTOM6 = DFB_CUSTOM_KEY( 6 ), DIKS_CUSTOM7 = DFB_CUSTOM_KEY( 7 ), DIKS_CUSTOM8 = DFB_CUSTOM_KEY( 8 ), DIKS_CUSTOM9 = DFB_CUSTOM_KEY( 9 ), DIKS_CUSTOM10 = DFB_CUSTOM_KEY( 10 ), DIKS_CUSTOM11 = DFB_CUSTOM_KEY( 11 ), DIKS_CUSTOM12 = DFB_CUSTOM_KEY( 12 ), DIKS_CUSTOM13 = DFB_CUSTOM_KEY( 13 ), DIKS_CUSTOM14 = DFB_CUSTOM_KEY( 14 ), DIKS_CUSTOM15 = DFB_CUSTOM_KEY( 15 ), DIKS_CUSTOM16 = DFB_CUSTOM_KEY( 16 ), DIKS_CUSTOM17 = DFB_CUSTOM_KEY( 17 ), DIKS_CUSTOM18 = DFB_CUSTOM_KEY( 18 ), DIKS_CUSTOM19 = DFB_CUSTOM_KEY( 19 ), DIKS_CUSTOM20 = DFB_CUSTOM_KEY( 20 ), DIKS_CUSTOM21 = DFB_CUSTOM_KEY( 21 ), DIKS_CUSTOM22 = DFB_CUSTOM_KEY( 22 ), DIKS_CUSTOM23 = DFB_CUSTOM_KEY( 23 ), DIKS_CUSTOM24 = DFB_CUSTOM_KEY( 24 ), DIKS_CUSTOM25 = DFB_CUSTOM_KEY( 25 ), DIKS_CUSTOM26 = DFB_CUSTOM_KEY( 26 ), DIKS_CUSTOM27 = DFB_CUSTOM_KEY( 27 ), DIKS_CUSTOM28 = DFB_CUSTOM_KEY( 28 ), DIKS_CUSTOM29 = DFB_CUSTOM_KEY( 29 ), DIKS_CUSTOM30 = DFB_CUSTOM_KEY( 30 ), DIKS_CUSTOM31 = DFB_CUSTOM_KEY( 31 ), DIKS_CUSTOM32 = DFB_CUSTOM_KEY( 32 ), DIKS_CUSTOM33 = DFB_CUSTOM_KEY( 33 ), DIKS_CUSTOM34 = DFB_CUSTOM_KEY( 34 ), DIKS_CUSTOM35 = DFB_CUSTOM_KEY( 35 ), DIKS_CUSTOM36 = DFB_CUSTOM_KEY( 36 ), DIKS_CUSTOM37 = DFB_CUSTOM_KEY( 37 ), DIKS_CUSTOM38 = DFB_CUSTOM_KEY( 38 ), DIKS_CUSTOM39 = DFB_CUSTOM_KEY( 39 ), DIKS_CUSTOM40 = DFB_CUSTOM_KEY( 40 ), DIKS_CUSTOM41 = DFB_CUSTOM_KEY( 41 ), DIKS_CUSTOM42 = DFB_CUSTOM_KEY( 42 ), DIKS_CUSTOM43 = DFB_CUSTOM_KEY( 43 ), DIKS_CUSTOM44 = DFB_CUSTOM_KEY( 44 ), DIKS_CUSTOM45 = DFB_CUSTOM_KEY( 45 ), DIKS_CUSTOM46 = DFB_CUSTOM_KEY( 46 ), DIKS_CUSTOM47 = DFB_CUSTOM_KEY( 47 ), DIKS_CUSTOM48 = DFB_CUSTOM_KEY( 48 ), DIKS_CUSTOM49 = DFB_CUSTOM_KEY( 49 ), DIKS_CUSTOM50 = DFB_CUSTOM_KEY( 50 ), DIKS_CUSTOM51 = DFB_CUSTOM_KEY( 51 ), DIKS_CUSTOM52 = DFB_CUSTOM_KEY( 52 ), DIKS_CUSTOM53 = DFB_CUSTOM_KEY( 53 ), DIKS_CUSTOM54 = DFB_CUSTOM_KEY( 54 ), DIKS_CUSTOM55 = DFB_CUSTOM_KEY( 55 ), DIKS_CUSTOM56 = DFB_CUSTOM_KEY( 56 ), DIKS_CUSTOM57 = DFB_CUSTOM_KEY( 57 ), DIKS_CUSTOM58 = DFB_CUSTOM_KEY( 58 ), DIKS_CUSTOM59 = DFB_CUSTOM_KEY( 59 ), DIKS_CUSTOM60 = DFB_CUSTOM_KEY( 60 ), DIKS_CUSTOM61 = DFB_CUSTOM_KEY( 61 ), DIKS_CUSTOM62 = DFB_CUSTOM_KEY( 62 ), DIKS_CUSTOM63 = DFB_CUSTOM_KEY( 63 ), DIKS_CUSTOM64 = DFB_CUSTOM_KEY( 64 ), DIKS_CUSTOM65 = DFB_CUSTOM_KEY( 65 ), DIKS_CUSTOM66 = DFB_CUSTOM_KEY( 66 ), DIKS_CUSTOM67 = DFB_CUSTOM_KEY( 67 ), DIKS_CUSTOM68 = DFB_CUSTOM_KEY( 68 ), DIKS_CUSTOM69 = DFB_CUSTOM_KEY( 69 ), DIKS_CUSTOM70 = DFB_CUSTOM_KEY( 70 ), DIKS_CUSTOM71 = DFB_CUSTOM_KEY( 71 ), DIKS_CUSTOM72 = DFB_CUSTOM_KEY( 72 ), DIKS_CUSTOM73 = DFB_CUSTOM_KEY( 73 ), DIKS_CUSTOM74 = DFB_CUSTOM_KEY( 74 ), DIKS_CUSTOM75 = DFB_CUSTOM_KEY( 75 ), DIKS_CUSTOM76 = DFB_CUSTOM_KEY( 76 ), DIKS_CUSTOM77 = DFB_CUSTOM_KEY( 77 ), DIKS_CUSTOM78 = DFB_CUSTOM_KEY( 78 ), DIKS_CUSTOM79 = DFB_CUSTOM_KEY( 79 ), DIKS_CUSTOM80 = DFB_CUSTOM_KEY( 80 ), DIKS_CUSTOM81 = DFB_CUSTOM_KEY( 81 ), DIKS_CUSTOM82 = DFB_CUSTOM_KEY( 82 ), DIKS_CUSTOM83 = DFB_CUSTOM_KEY( 83 ), DIKS_CUSTOM84 = DFB_CUSTOM_KEY( 84 ), DIKS_CUSTOM85 = DFB_CUSTOM_KEY( 85 ), DIKS_CUSTOM86 = DFB_CUSTOM_KEY( 86 ), DIKS_CUSTOM87 = DFB_CUSTOM_KEY( 87 ), DIKS_CUSTOM88 = DFB_CUSTOM_KEY( 88 ), DIKS_CUSTOM89 = DFB_CUSTOM_KEY( 89 ), DIKS_CUSTOM90 = DFB_CUSTOM_KEY( 90 ), DIKS_CUSTOM91 = DFB_CUSTOM_KEY( 91 ), DIKS_CUSTOM92 = DFB_CUSTOM_KEY( 92 ), DIKS_CUSTOM93 = DFB_CUSTOM_KEY( 93 ), DIKS_CUSTOM94 = DFB_CUSTOM_KEY( 94 ), DIKS_CUSTOM95 = DFB_CUSTOM_KEY( 95 ), DIKS_CUSTOM96 = DFB_CUSTOM_KEY( 96 ), DIKS_CUSTOM97 = DFB_CUSTOM_KEY( 97 ), DIKS_CUSTOM98 = DFB_CUSTOM_KEY( 98 ), DIKS_CUSTOM99 = DFB_CUSTOM_KEY( 99 ), DIKS_CUSTOM100 = DFB_CUSTOM_KEY( 100 ), DIKS_CUSTOM101 = DFB_CUSTOM_KEY( 101 ), DIKS_CUSTOM102 = DFB_CUSTOM_KEY( 102 ), DIKS_CUSTOM103 = DFB_CUSTOM_KEY( 103 ), DIKS_CUSTOM104 = DFB_CUSTOM_KEY( 104 ), DIKS_CUSTOM105 = DFB_CUSTOM_KEY( 105 ), DIKS_CUSTOM106 = DFB_CUSTOM_KEY( 106 ), DIKS_CUSTOM107 = DFB_CUSTOM_KEY( 107 ), DIKS_CUSTOM108 = DFB_CUSTOM_KEY( 108 ), DIKS_CUSTOM109 = DFB_CUSTOM_KEY( 109 ), DIKS_CUSTOM110 = DFB_CUSTOM_KEY( 110 ), DIKS_CUSTOM111 = DFB_CUSTOM_KEY( 111 ), DIKS_CUSTOM112 = DFB_CUSTOM_KEY( 112 ), DIKS_CUSTOM113 = DFB_CUSTOM_KEY( 113 ), DIKS_CUSTOM114 = DFB_CUSTOM_KEY( 114 ), DIKS_CUSTOM115 = DFB_CUSTOM_KEY( 115 ), DIKS_CUSTOM116 = DFB_CUSTOM_KEY( 116 ), DIKS_CUSTOM117 = DFB_CUSTOM_KEY( 117 ), DIKS_CUSTOM118 = DFB_CUSTOM_KEY( 118 ), DIKS_CUSTOM119 = DFB_CUSTOM_KEY( 119 ), DIKS_CUSTOM120 = DFB_CUSTOM_KEY( 120 ), DIKS_CUSTOM121 = DFB_CUSTOM_KEY( 121 ), DIKS_CUSTOM122 = DFB_CUSTOM_KEY( 122 ), DIKS_CUSTOM123 = DFB_CUSTOM_KEY( 123 ), DIKS_CUSTOM124 = DFB_CUSTOM_KEY( 124 ), DIKS_CUSTOM125 = DFB_CUSTOM_KEY( 125 ), DIKS_CUSTOM126 = DFB_CUSTOM_KEY( 126 ), DIKS_CUSTOM127 = DFB_CUSTOM_KEY( 127 ), DIKS_CUSTOM128 = DFB_CUSTOM_KEY( 128 ), DIKS_CUSTOM129 = DFB_CUSTOM_KEY( 129 ), DIKS_CUSTOM130 = DFB_CUSTOM_KEY( 130 ), DIKS_CUSTOM131 = DFB_CUSTOM_KEY( 131 ), DIKS_CUSTOM132 = DFB_CUSTOM_KEY( 132 ), DIKS_CUSTOM133 = DFB_CUSTOM_KEY( 133 ), DIKS_CUSTOM134 = DFB_CUSTOM_KEY( 134 ), DIKS_CUSTOM135 = DFB_CUSTOM_KEY( 135 ), DIKS_CUSTOM136 = DFB_CUSTOM_KEY( 136 ), DIKS_CUSTOM137 = DFB_CUSTOM_KEY( 137 ), DIKS_CUSTOM138 = DFB_CUSTOM_KEY( 138 ), DIKS_CUSTOM139 = DFB_CUSTOM_KEY( 139 ), DIKS_CUSTOM140 = DFB_CUSTOM_KEY( 140 ), DIKS_CUSTOM141 = DFB_CUSTOM_KEY( 141 ), DIKS_CUSTOM142 = DFB_CUSTOM_KEY( 142 ), DIKS_CUSTOM143 = DFB_CUSTOM_KEY( 143 ), DIKS_CUSTOM144 = DFB_CUSTOM_KEY( 144 ), DIKS_CUSTOM145 = DFB_CUSTOM_KEY( 145 ), DIKS_CUSTOM146 = DFB_CUSTOM_KEY( 146 ), DIKS_CUSTOM147 = DFB_CUSTOM_KEY( 147 ), DIKS_CUSTOM148 = DFB_CUSTOM_KEY( 148 ), DIKS_CUSTOM149 = DFB_CUSTOM_KEY( 149 ), DIKS_CUSTOM150 = DFB_CUSTOM_KEY( 150 ), DIKS_CUSTOM151 = DFB_CUSTOM_KEY( 151 ), DIKS_CUSTOM152 = DFB_CUSTOM_KEY( 152 ), DIKS_CUSTOM153 = DFB_CUSTOM_KEY( 153 ), DIKS_CUSTOM154 = DFB_CUSTOM_KEY( 154 ), DIKS_CUSTOM155 = DFB_CUSTOM_KEY( 155 ), DIKS_CUSTOM156 = DFB_CUSTOM_KEY( 156 ), DIKS_CUSTOM157 = DFB_CUSTOM_KEY( 157 ), DIKS_CUSTOM158 = DFB_CUSTOM_KEY( 158 ), DIKS_CUSTOM159 = DFB_CUSTOM_KEY( 159 ), DIKS_CUSTOM160 = DFB_CUSTOM_KEY( 160 ), DIKS_CUSTOM161 = DFB_CUSTOM_KEY( 161 ), DIKS_CUSTOM162 = DFB_CUSTOM_KEY( 162 ), DIKS_CUSTOM163 = DFB_CUSTOM_KEY( 163 ), DIKS_CUSTOM164 = DFB_CUSTOM_KEY( 164 ), DIKS_CUSTOM165 = DFB_CUSTOM_KEY( 165 ), DIKS_CUSTOM166 = DFB_CUSTOM_KEY( 166 ), DIKS_CUSTOM167 = DFB_CUSTOM_KEY( 167 ), DIKS_CUSTOM168 = DFB_CUSTOM_KEY( 168 ), DIKS_CUSTOM169 = DFB_CUSTOM_KEY( 169 ), DIKS_CUSTOM170 = DFB_CUSTOM_KEY( 170 ), DIKS_CUSTOM171 = DFB_CUSTOM_KEY( 171 ), DIKS_CUSTOM172 = DFB_CUSTOM_KEY( 172 ), DIKS_CUSTOM173 = DFB_CUSTOM_KEY( 173 ), DIKS_CUSTOM174 = DFB_CUSTOM_KEY( 174 ), DIKS_CUSTOM175 = DFB_CUSTOM_KEY( 175 ), DIKS_CUSTOM176 = DFB_CUSTOM_KEY( 176 ), DIKS_CUSTOM177 = DFB_CUSTOM_KEY( 177 ), DIKS_CUSTOM178 = DFB_CUSTOM_KEY( 178 ), DIKS_CUSTOM179 = DFB_CUSTOM_KEY( 179 ), DIKS_CUSTOM180 = DFB_CUSTOM_KEY( 180 ), DIKS_CUSTOM181 = DFB_CUSTOM_KEY( 181 ), DIKS_CUSTOM182 = DFB_CUSTOM_KEY( 182 ), DIKS_CUSTOM183 = DFB_CUSTOM_KEY( 183 ), DIKS_CUSTOM184 = DFB_CUSTOM_KEY( 184 ), DIKS_CUSTOM185 = DFB_CUSTOM_KEY( 185 ), DIKS_CUSTOM186 = DFB_CUSTOM_KEY( 186 ), DIKS_CUSTOM187 = DFB_CUSTOM_KEY( 187 ), DIKS_CUSTOM188 = DFB_CUSTOM_KEY( 188 ), DIKS_CUSTOM189 = DFB_CUSTOM_KEY( 189 ), DIKS_CUSTOM190 = DFB_CUSTOM_KEY( 190 ), DIKS_CUSTOM191 = DFB_CUSTOM_KEY( 191 ), DIKS_CUSTOM192 = DFB_CUSTOM_KEY( 192 ), DIKS_CUSTOM193 = DFB_CUSTOM_KEY( 193 ), DIKS_CUSTOM194 = DFB_CUSTOM_KEY( 194 ), DIKS_CUSTOM195 = DFB_CUSTOM_KEY( 195 ), DIKS_CUSTOM196 = DFB_CUSTOM_KEY( 196 ), DIKS_CUSTOM197 = DFB_CUSTOM_KEY( 197 ), DIKS_CUSTOM198 = DFB_CUSTOM_KEY( 198 ), DIKS_CUSTOM199 = DFB_CUSTOM_KEY( 199 ), DIKS_CUSTOM200 = DFB_CUSTOM_KEY( 200 ), DIKS_CUSTOM201 = DFB_CUSTOM_KEY( 201 ), DIKS_CUSTOM202 = DFB_CUSTOM_KEY( 202 ), DIKS_CUSTOM203 = DFB_CUSTOM_KEY( 203 ), DIKS_CUSTOM204 = DFB_CUSTOM_KEY( 204 ), DIKS_CUSTOM205 = DFB_CUSTOM_KEY( 205 ), DIKS_CUSTOM206 = DFB_CUSTOM_KEY( 206 ), DIKS_CUSTOM207 = DFB_CUSTOM_KEY( 207 ), DIKS_CUSTOM208 = DFB_CUSTOM_KEY( 208 ), DIKS_CUSTOM209 = DFB_CUSTOM_KEY( 209 ), DIKS_CUSTOM210 = DFB_CUSTOM_KEY( 210 ), DIKS_CUSTOM211 = DFB_CUSTOM_KEY( 211 ), DIKS_CUSTOM212 = DFB_CUSTOM_KEY( 212 ), DIKS_CUSTOM213 = DFB_CUSTOM_KEY( 213 ), DIKS_CUSTOM214 = DFB_CUSTOM_KEY( 214 ), DIKS_CUSTOM215 = DFB_CUSTOM_KEY( 215 ), DIKS_CUSTOM216 = DFB_CUSTOM_KEY( 216 ), DIKS_CUSTOM217 = DFB_CUSTOM_KEY( 217 ), DIKS_CUSTOM218 = DFB_CUSTOM_KEY( 218 ), DIKS_CUSTOM219 = DFB_CUSTOM_KEY( 219 ), DIKS_CUSTOM220 = DFB_CUSTOM_KEY( 220 ), DIKS_CUSTOM221 = DFB_CUSTOM_KEY( 221 ), DIKS_CUSTOM222 = DFB_CUSTOM_KEY( 222 ), DIKS_CUSTOM223 = DFB_CUSTOM_KEY( 223 ), DIKS_CUSTOM224 = DFB_CUSTOM_KEY( 224 ), DIKS_CUSTOM225 = DFB_CUSTOM_KEY( 225 ), DIKS_CUSTOM226 = DFB_CUSTOM_KEY( 226 ), DIKS_CUSTOM227 = DFB_CUSTOM_KEY( 227 ), DIKS_CUSTOM228 = DFB_CUSTOM_KEY( 228 ), DIKS_CUSTOM229 = DFB_CUSTOM_KEY( 229 ), DIKS_CUSTOM230 = DFB_CUSTOM_KEY( 230 ), DIKS_CUSTOM231 = DFB_CUSTOM_KEY( 231 ), DIKS_CUSTOM232 = DFB_CUSTOM_KEY( 232 ), DIKS_CUSTOM233 = DFB_CUSTOM_KEY( 233 ), DIKS_CUSTOM234 = DFB_CUSTOM_KEY( 234 ), DIKS_CUSTOM235 = DFB_CUSTOM_KEY( 235 ), DIKS_CUSTOM236 = DFB_CUSTOM_KEY( 236 ), DIKS_CUSTOM237 = DFB_CUSTOM_KEY( 237 ), DIKS_CUSTOM238 = DFB_CUSTOM_KEY( 238 ), DIKS_CUSTOM239 = DFB_CUSTOM_KEY( 239 ), DIKS_CUSTOM240 = DFB_CUSTOM_KEY( 240 ), DIKS_CUSTOM241 = DFB_CUSTOM_KEY( 241 ), DIKS_CUSTOM242 = DFB_CUSTOM_KEY( 242 ), DIKS_CUSTOM243 = DFB_CUSTOM_KEY( 243 ), DIKS_CUSTOM244 = DFB_CUSTOM_KEY( 244 ), DIKS_CUSTOM245 = DFB_CUSTOM_KEY( 245 ), DIKS_CUSTOM246 = DFB_CUSTOM_KEY( 246 ), DIKS_CUSTOM247 = DFB_CUSTOM_KEY( 247 ), DIKS_CUSTOM248 = DFB_CUSTOM_KEY( 248 ), DIKS_CUSTOM249 = DFB_CUSTOM_KEY( 249 ), DIKS_CUSTOM250 = DFB_CUSTOM_KEY( 250 ), DIKS_CUSTOM251 = DFB_CUSTOM_KEY( 251 ), DIKS_CUSTOM252 = DFB_CUSTOM_KEY( 252 ), DIKS_CUSTOM253 = DFB_CUSTOM_KEY( 253 ), DIKS_CUSTOM254 = DFB_CUSTOM_KEY( 254 ), DIKS_CUSTOM255 = DFB_CUSTOM_KEY( 255 ) } DFBInputDeviceKeySymbol; /* * Flags specifying the key locks that are currently active. */ typedef enum { DILS_SCROLL = 0x00000001, /* scroll-lock active? */ DILS_NUM = 0x00000002, /* num-lock active? */ DILS_CAPS = 0x00000004 /* caps-lock active? */ } DFBInputDeviceLockState; /* * Groups and levels as an index to the symbol array. */ typedef enum { DIKSI_BASE = 0x00000000, /* base group, base level (no modifier pressed) */ DIKSI_BASE_SHIFT = 0x00000001, /* base group, shifted level (with Shift pressed) */ DIKSI_ALT = 0x00000002, /* alternative group, base level (with AltGr pressed) */ DIKSI_ALT_SHIFT = 0x00000003, /* alternative group, shifted level (with AltGr and Shift pressed) */ DIKSI_LAST = DIKSI_ALT_SHIFT } DFBInputDeviceKeymapSymbolIndex; /* * One entry in the keymap of an input device. */ typedef struct { int code; /* hardware key code */ DFBInputDeviceLockState locks; /* locks activating shifted level */ DFBInputDeviceKeyIdentifier identifier; /* basic mapping */ DFBInputDeviceKeySymbol symbols[DIKSI_LAST+1]; /* advanced key mapping */ } DFBInputDeviceKeymapEntry; #endif ================================================ FILE: include/directfb_util.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFB_UTIL_H__ #define __DIRECTFB_UTIL_H__ #include #ifdef __cplusplus extern "C" { #endif /**********************************************************************************************************************/ /* * Adds the id to the bitmask of layer ids. */ #define DFB_DISPLAYLAYER_IDS_ADD(ids,id) (ids) |= (1 << (id)) /* * Removes the id from the bitmask of layer ids. */ #define DFB_DISPLAYLAYER_IDS_REMOVE(ids,id) (ids) &= ~(1 << (id)) /* * Checks if the bitmask of layer ids contains the id. */ #define DFB_DISPLAYLAYER_IDS_HAVE(ids,id) ((ids) & (1 << (id))) /* * Empties (clears) the bitmask of layer ids. */ #define DFB_DISPLAYLAYER_IDS_EMPTY(ids) (ids) = 0 /**********************************************************************************************************************/ /* * Macro to compare two points. */ #define DFB_POINT_EQUAL(a,b) ((a).x == (b).x && \ (a).y == (b).y) /* * Macro to compare two rectangles. */ #define DFB_RECTANGLE_EQUAL(a,b) ((a).x == (b).x && \ (a).y == (b).y && \ (a).w == (b).w && \ (a).h == (b).h) /* * Macro to compare two locations. */ #define DFB_LOCATION_EQUAL(a,b) ((a).x == (b).x && \ (a).y == (b).y && \ (a).w == (b).w && \ (a).h == (b).h) /* * Macro to compare two regions. */ #define DFB_REGION_EQUAL(a,b) ((a).x1 == (b).x1 && \ (a).y1 == (b).y1 && \ (a).x2 == (b).x2 && \ (a).y2 == (b).y2) /* * Macro to compare two colors. */ #define DFB_COLOR_EQUAL(x,y) ((x).a == (y).a && \ (x).r == (y).r && \ (x).g == (y).g && \ (x).b == (y).b) /* * Macro to compare two color keys. */ #define DFB_COLORKEY_EQUAL(x,y) ((x).index == (y).index && \ (x).r == (y).r && \ (x).g == (y).g && \ (x).b == (y).b) /**********************************************************************************************************************/ bool DIRECTFB_API dfb_region_rectangle_intersect ( DFBRegion *region, const DFBRectangle *rect ); bool DIRECTFB_API dfb_unsafe_region_intersect ( DFBRegion *region, int x1, int y1, int x2, int y2 ); bool DIRECTFB_API dfb_unsafe_region_rectangle_intersect ( DFBRegion *region, const DFBRectangle *rect ); bool DIRECTFB_API dfb_rectangle_intersect_by_unsafe_region( DFBRectangle *rectangle, DFBRegion *region ); bool DIRECTFB_API dfb_rectangle_intersect_by_region ( DFBRectangle *rectangle, const DFBRegion *region ); bool DIRECTFB_API dfb_rectangle_intersect ( DFBRectangle *rectangle, const DFBRectangle *clip ); void DIRECTFB_API dfb_rectangle_union ( DFBRectangle *rect1, const DFBRectangle *rect2 ); /**********************************************************************************************************************/ #define DFB_RECTANGLE_CHECK(r) \ ((r) != NULL && \ (r)->x1 <= (r)->x2 && \ (r)->y1 <= (r)->y2) #define DFB_RECTANGLE_CHECK_IF(r) \ ((r) == NULL || \ ((r)->w >= 0 && \ (r)->h >= 0)) #define DFB_RECT_FORMAT "%4d,%4d-%4dx%4d" #define DFB_RECTANGLE_VALS(r) (r)->x, (r)->y, (r)->w, (r)->h #define DFB_RECTANGLE_EMPTY(r) ((r)->w == 0 || (r)->h == 0) #define DFB_RECTANGLE_FULL(r) (!DFB_RECTANGLE_EMPTY(r)) #define DFB_RECTANGLE_VALS_FROM_DIMENSION(d) 0, 0, (d)->w, (d)->h #define DFB_RECTANGLE_INIT_FROM_DIMENSION(d) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_DIMENSION(d) } #define DFB_RECTANGLE_VALS_FROM_DIMENSION_VALS(w,h) 0, 0, (w), (h) #define DFB_RECTANGLE_INIT_FROM_DIMENSION_VALS(w,h) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_DIMENSION_VALS(w,h) } #define DFB_RECTANGLE_VALS_FROM_REGION(r) (r)->x1, (r)->y1, (r)->x2-(r)->x1+1, (r)->y2-(r)->y1+1 #define DFB_RECTANGLE_INIT_FROM_REGION(r) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_REGION(r) } #define DFB_RECTANGLE_VALS_FROM_REGION_TRANSLATED \ (r,x,y) (r)->x1+(x), (r)->y1+(y), (r)->x2-(r)->x1+1, (r)->y2-(r)->y1+1 #define DFB_RECTANGLE_INIT_FROM_REGION_TRANSLATED \ (r,x,y) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_REGION_TRANSLATED(r, \ x, \ y) } #define DFB_RECTANGLE_VALS_FROM_BOX(b) (b)->x1, (b)->y1, (b)->x2-(b)->x1, (b)->y2-(b)->y1 #define DFB_RECTANGLE_INIT_FROM_BOX(b) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_BOX(b) } #define DFB_RECTANGLE_VALS_FROM_BOX_TRANSLATED(b,x,y) (b)->x1+(x), (b)->y1+(y), (b)->x2-(b)->x1, (b)->y2-(b)->y1 #define DFB_RECTANGLE_INIT_FROM_BOX_TRANSLATED(b,x,y) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_BOX_TRANSLATED(b,x,y) } #define DFB_RECTANGLE_VALS_FROM_BOX_VALS(x1,y1,x2,y2) (b)->x1, (b)->y1, (b)->x2-(b)->x1, (b)->y2-(b)->y1 #define DFB_RECTANGLE_INIT_FROM_BOX_VALS(x1,y1,x2,y2) (DFBRectangle) { DFB_RECTANGLE_VALS_FROM_BOX_VALS(x1,y1,x2,y2) } #define DFB_RECTANGLE_CONTAINS_POINT(r,X,Y) (((X) >= (r)->x) && ((X) < (r)->x+(r)->w) && \ ((Y) >= (r)->y) && ((Y) < (r)->y+(r)->h)) /**********************************************************************************************************************/ #define DFB_REGION_CHECK(r) \ ((r) != NULL && \ (r)->x1 <= (r)->x2 && \ (r)->y1 <= (r)->y2) #define DFB_REGION_CHECK_IF(r) \ ((r) == NULL || \ ((r)->x1 <= (r)->x2 && \ (r)->y1 <= (r)->y2)) #define DFB_REGION_FORMAT "%4d,%4d-%4d,%4d" #define DFB_REGION_VALS(r) (r)->x1, (r)->y1, (r)->x2, (r)->y2 #define DFB_REGION_VALS_FROM_DIMENSION(d) 0, 0, (d)->w-1, (d)->h-1 #define DFB_REGION_INIT_FROM_DIMENSION(d) (DFBRegion) { DFB_REGION_VALS_FROM_DIMENSION(d) } #define DFB_REGION_VALS_FROM_RECTANGLE(r) (r)->x, (r)->y, (r)->x+(r)->w-1, (r)->y+(r)->h-1 #define DFB_REGION_INIT_FROM_RECTANGLE(r) (DFBRegion) { DFB_REGION_VALS_FROM_RECTANGLE(r) } #define DFB_REGION_VALS_FROM_RECTANGLE_VALS(x,y,w,h) (x), (y), (x)+(w)-1, (y)+(h)-1 #define DFB_REGION_INIT_FROM_RECTANGLE_VALS(x,y,w,h) (DFBRegion) { DFB_REGION_VALS_FROM_RECTANGLE_VALS(x,y,w,h) } #define DFB_REGION_VALS_FROM_BOX(b) (b)->x1, (b)->y1, (b)->x2-1, (b)->y2-1 #define DFB_REGION_INIT_FROM_BOX(b) (DFBRegion) { DFB_REGION_VALS_FROM_BOX(b) } #define DFB_REGION_VALS_TRANSLATED(r,x,y) (r)->x1+x, (r)->y1+y, (r)->x2+x, (r)->y2+y #define DFB_REGION_INIT_TRANSLATED(r,x,y) (DFBRegion) { DFB_REGION_VALS_TRANSLATED(r,x,y) } #define DFB_REGION_VALS_INTERSECTED(r,X1,Y1,X2,Y2) (r)->x1 > (X1) ? (r)->x1 : (X1), \ (r)->y1 > (Y1) ? (r)->y1 : (Y1), \ (r)->x2 < (X2) ? (r)->x2 : (X2), \ (r)->y2 < (Y2) ? (r)->y2 : (Y2) #define DFB_REGION_INIT_INTERSECTED(r,X1,Y1,X2,Y2) (DFBRegion) { DFB_REGION_VALS_INTERSECTED(r,X1,Y1,X2,Y2) } #define DFB_REGION_CONTAINS_POINT(r,X,Y) (((X) >= (r)->x1) && ((X) <= (r)->x2) && \ ((Y) >= (r)->y1) && ((Y) <= (r)->y2)) /**********************************************************************************************************************/ #define DFB_BOX_CHECK(b) \ ((b) != NULL && \ (b)->x1 <= (b)->x2 && \ (b)->y1 <= (b)->y2) #define DFB_BOX_CHECK_IF(r) \ ((b) == NULL || \ ((b)->x1 <= (b)->x2 && \ (b)->y1 <= (b)->y2)) #define DFB_BOX_VALS(b) (b)->x1, (b)->y1, (b)->x2, (b)->y2 #define DFB_BOX_INIT(x1,y1,x2,y2) (DFBBox) { x1, y1, x2, y2 } #define DFB_BOX_WIDTH(b) ((b)->x2 - (b)->x1) #define DFB_BOX_HEIGHT(b) ((b)->y2 - (b)->y1) #define DFB_BOX_SIZE(b) (DFB_BOX_WIDTH(b) * DFB_BOX_HEIGHT(b)) #define DFB_BOX_EQUAL(b1,b2) (((b1) == (b2)) || \ ((b1)->x1 == (b2)->x1 && \ (b1)->y1 == (b2)->y1 && (b1)->x2 == (b2)->x2 && \ (b1)->y2 == (b2)->y2)) #define DFB_BOX_EMPTY(b) ((b)->x1 == (b)->x2 || (b)->y1 == (b)->y2) #define DFB_BOX_FULL(b) (!DFB_BOX_EMPTY(b)) #define DFB_BOX_RESET(b) do { (b)->x2 = (b)->x1; (b)->y2 = (b)->y1; } while (0) #define DFB_BOX_VALS_FROM_DIMENSION(d) 0, 0, (d)->w, (d)->h #define DFB_BOX_INIT_FROM_DIMENSION(d) (DFBBox) { DFB_BOX_VALS_FROM_DIMENSION(d) } #define DFB_BOX_VALS_FROM_DIMENSION_VALS(w,h) 0, 0, (w), (h) #define DFB_BOX_INIT_FROM_DIMENSION_VALS(w,h) (DFBBox) { DFB_BOX_VALS_FROM_DIMENSION_VALS(w,h) } #define DFB_BOX_VALS_FROM_RECTANGLE(r) (r)->x, (r)->y, (r)->x+(r)->w, (r)->y+(r)->h #define DFB_BOX_INIT_FROM_RECTANGLE(r) (DFBBox) { DFB_BOX_VALS_FROM_RECTANGLE(r) } #define DFB_BOX_VALS_FROM_RECTANGLE_VALS(x,y,w,h) (x), (y), (x)+(w), (y)+(h) #define DFB_BOX_INIT_FROM_RECTANGLE_VALS(X,Y,W,H) (DFBBox) { DFB_BOX_VALS_FROM_RECTANGLE_VALS(X,Y,W,H) } #define DFB_BOX_VALS_FROM_REGION(r) (r)->x1, (r)->y1, (r)->x2+1, (r)->y2+1 #define DFB_BOX_INIT_FROM_REGION(r) (DFBBox) { DFB_BOX_VALS_FROM_REGION(r) } #define DFB_BOX_VALS_TRANSLATED(b,x,y) (b)->x1+x, (b)->y1+y, (b)->x2+x, (b)->y2+y #define DFB_BOX_INIT_TRANSLATED(b,x,y) (DFBBox) { DFB_BOX_VALS_TRANSLATED(b,x,y) } #define DFB_BOX_VALS_AT_ZERO(b) 0, 0, DFB_BOX_WIDTH(b), DFB_BOX_HEIGHT(b) #define DFB_BOX_INIT_AT_ZERO(b) (DFBBox) { DFB_BOX_VALS_AT_ZERO(b) } /**********************************************************************************************************************/ #define DFB_DIMENSION_VALS(d) (d)->w, (d)->h #define DFB_DIMENSION_INIT(w,h) (DFBDimension) { w, h } #define DFB_DIMENSION_VALS_FROM_BOX(b) DFB_BOX_WIDTH(b), DFB_BOX_HEIGHT(b) #define DFB_DIMENSION_INIT_FROM_BOX(b) (DFBDimension) { DFB_DIMENSION_VALS_FROM_BOX(b) } /**********************************************************************************************************************/ #define DFB_LINE_FORMAT "%4d,%4d-%4d,%4d" #define DFB_LINE_VALS(l) (l)->x1, (l)->y1, (l)->x2, (l)->y2 /**********************************************************************************************************************/ #define DFB_POINT_VALS(p) (p)->x, (p)->y #define DFB_POINT_INIT(x,y) (DFBPoint) { x, y } #define DFB_POINT_VALS_FROM_BOX(b) (b)->x1, (b)->y1 #define DFB_POINT_INIT_FROM_BOX(b) (DFBPoint) { DFB_POINT_VALS_FROM_BOX(b) } /**********************************************************************************************************************/ #define DFB_TRIANGLE_FORMAT "%4d,%4d-%4d,%4d-%4d,%4d" #define DFB_TRIANGLE_VALS(t) (t)->x1, (t)->y1, (t)->x2, (t)->y2, (t)->x3, (t)->y3 #define DFB_TRIANGLE_INIT(x1,y1,x2,y2,x3,y3) (DFBTriangle) { x1, y1, x2, y2, x3, y3 } /**********************************************************************************************************************/ #define DFB_SPAN_VALS(s) (s)->x, (s)->w #define DFB_SPAN_INIT(x,w) (DFBSpan) { x, w } #define DFB_SPAN_VALS_AT(s,y) (s)->x, y, (s)->w /**********************************************************************************************************************/ #define DFB_COLOR_FORMAT "%02x %02x %02x %02x" #define DFB_COLOR_VALS(c) (c)->a, (c)->r, (c)->g, (c)->b #define DFB_COLOR_INIT(a,r,g,b) (DFBColor) { a, r, g, b } /**********************************************************************************************************************/ #define DFB_COLORKEY_VALS(c) (c)->r, (c)->g, (c)->b, (c)->index #define DFB_COLORKEY_INIT(r,g,b,index) (DFBColorKey) { r, g, b, index } /**********************************************************************************************************************/ #if D_DEBUG_ENABLED #define DFB_RECTANGLE_ASSERT(r) \ do { \ D_ASSERT( (r) != NULL ); \ D_ASSERT( (r)->w >= 0 ); \ D_ASSERT( (r)->h >= 0 ); \ } while (0) #define DFB_RECTANGLE_ASSERT_IF(r) \ do { \ if ((r) != NULL) { \ D_ASSERT( (r)->w >= 0 ); \ D_ASSERT( (r)->h >= 0 ); \ } \ } while (0) #define DFB_REGION_ASSERT(r) \ do { \ D_ASSERT( (r) != NULL ); \ D_ASSERT( (r)->x1 <= (r)->x2 ); \ D_ASSERT( (r)->y1 <= (r)->y2 ); \ } while (0) #define DFB_REGION_ASSERT_IF(r) \ do { \ if ((r) != NULL) { \ D_ASSERT( (r)->x1 <= (r)->x2 ); \ D_ASSERT( (r)->y1 <= (r)->y2 ); \ } \ } while (0) #define DFB_BOX_ASSERT(b) \ do { \ D_ASSERT( (b) != NULL ); \ D_ASSERT( (b)->x1 <= (b)->x2 ); \ D_ASSERT( (b)->y1 <= (b)->y2 ); \ } while (0) #define DFB_BOX_ASSERT_IF(b) \ do { \ if ((b) != NULL) { \ D_ASSERT( (b)->x1 <= (b)->x2 ); \ D_ASSERT( (b)->y1 <= (b)->y2 ); \ } \ } while (0) #define DFB_RECTANGLES_DEBUG_AT(Domain,rects,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d\n", i, DFB_RECTANGLE_VALS(&(rects)[i]) ); \ } while (0) #define DFB_RECTANGLES2_DEBUG_AT(Domain,rects,rects2,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d <- %4d,%4d-%4dx%4d\n", i, \ DFB_RECTANGLE_VALS(&(rects)[i]), DFB_RECTANGLE_VALS(&(rects2)[i]) ); \ } while (0) #define DFB_RECTANGLES_POINTS_DEBUG_AT(Domain,rects,points,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d <- %4d,%4d\n", i, \ DFB_RECTANGLE_VALS(&(rects)[i]), DFB_POINT_VALS(&(points)[i]) ); \ } while (0) #define DFB_REGIONS_DEBUG_AT(Domain,regs,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d\n", i, \ DFB_RECTANGLE_VALS_FROM_REGION(&((regs)[i])) ); \ } while (0) #define DFB_BOXES_DEBUG_AT(Domain,boxes,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d\n", i, \ DFB_RECTANGLE_VALS_FROM_BOX(&(boxes)[i]) ); \ } while (0) #define DFB_BOXES2_DEBUG_AT(Domain,boxes,boxes2,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4dx%4d <- %4d,%4d-%4dx%4d\n", i, \ DFB_RECTANGLE_VALS_FROM_BOX(&(boxes)[i]), \ DFB_RECTANGLE_VALS_FROM_BOX(&(boxes2)[i]) ); \ } while (0) #define DFB_LINES_DEBUG_AT(Domain,lines,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4d,%4d\n", i, DFB_LINE_VALS(&(lines)[i]) ); \ } while (0) #define DFB_POINTS_DEBUG_AT(Domain,points,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d\n", i, DFB_POINT_VALS(&(points)[i]) ); \ } while (0) #define DFB_TRIANGLES_DEBUG_AT(Domain,tris,num) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4d,%4d-%4d,%4d\n", i, \ DFB_TRIANGLE_VALS(&(tris)[i]) );\ } while (0) #define DFB_SPANS_DEBUG_AT(Domain,spans,num,y) \ do { \ unsigned int i; \ \ for (i = 0; i < (num); i++) \ D_DEBUG_AT( Domain, " -> [%3u] %4d,%4d-%4d\n", i, DFB_SPAN_VALS_AT(&(spans)[i],y+i) ); \ } while (0) #else #define DFB_RECTANGLE_ASSERT(r) \ do { \ } while (0) #define DFB_RECTANGLE_ASSERT_IF(r) \ do { \ } while (0) #define DFB_REGION_ASSERT(r) \ do { \ } while (0) #define DFB_REGION_ASSERT_IF(r) \ do { \ } while (0) #define DFB_BOX_ASSERT(b) \ do { \ } while (0) #define DFB_BOX_ASSERT_IF(b) \ do { \ } while (0) #define DFB_RECTANGLES_DEBUG_AT(Domain,rects,num) \ do { \ } while (0) #define DFB_RECTANGLES2_DEBUG_AT(Domain,rects,rects2,num) \ do { \ } while (0) #define DFB_RECTANGLES_POINTS_DEBUG_AT(Domain,rects,points,num) \ do { \ } while (0) #define DFB_REGIONS_DEBUG_AT(Domain,regs,num) \ do { \ } while (0) #define DFB_BOXES_DEBUG_AT(Domain,boxes,num) \ do { \ } while (0) #define DFB_BOXES2_DEBUG_AT(Domain,boxes,boxes2,num) \ do { \ } while (0) #define DFB_LINES_DEBUG_AT(Domain,lines,num) \ do { \ } while (0) #define DFB_POINTS_DEBUG_AT(Domain,points,num) \ do { \ } while (0) #define DFB_TRIANGLES_DEBUG_AT(Domain,tris,num) \ do { \ } while (0) #define DFB_SPANS_DEBUG_AT(Domain,spans,num,y) \ do { \ } while (0) #endif /**********************************************************************************************************************/ static __inline__ void dfb_rectangle_from_region( DFBRectangle *rect, const DFBRegion *region ) { D_ASSERT( rect != NULL ); DFB_REGION_ASSERT( region ); rect->x = region->x1; rect->y = region->y1; rect->w = region->x2 - region->x1 + 1; rect->h = region->y2 - region->y1 + 1; } static __inline__ void dfb_rectangle_from_box( DFBRectangle *rect, const DFBBox *box ) { D_ASSERT( rect != NULL ); DFB_BOX_ASSERT( box ); rect->x = box->x1; rect->y = box->y1; rect->w = box->x2 - box->x1; rect->h = box->y2 - box->y1; } static __inline__ void dfb_rectangle_from_rectangle_plus_insets( DFBRectangle *rect, const DFBRectangle *inner, const DFBInsets *insets ) { D_ASSERT( rect != NULL ); DFB_RECTANGLE_ASSERT( inner ); D_ASSERT( insets != NULL ); rect->x = inner->x - insets->l; rect->y = inner->y - insets->t; rect->w = inner->w + insets->l + insets->r; rect->h = inner->h + insets->t + insets->b; } static __inline__ void dfb_rectangle_from_rotated( DFBRectangle *rectangle, const DFBRectangle *from, const DFBDimension *size, int rotation ) { D_ASSERT( rectangle != NULL ); DFB_RECTANGLE_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: *rectangle = *from; break; case 90: rectangle->x = from->y; rectangle->y = size->w - from->x - from->w; rectangle->w = from->h; rectangle->h = from->w; break; case 180: rectangle->x = size->w - from->x - from->w; rectangle->y = size->h - from->y - from->h; rectangle->w = from->w; rectangle->h = from->h; break; case 270: rectangle->x = size->h - from->y - from->h; rectangle->y = from->x; rectangle->w = from->h; rectangle->h = from->w; break; } } static __inline__ void dfb_rectangle_translate( DFBRectangle *rect, int dx, int dy ) { DFB_RECTANGLE_ASSERT( rect ); rect->x += dx; rect->y += dy; } static __inline__ void dfb_rectangle_resize( DFBRectangle *rect, int width, int height ) { DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( width >= 0 ); D_ASSERT( height >= 0 ); rect->w = width; rect->h = height; } static __inline__ bool dfb_rectangle_region_intersects( const DFBRectangle *rect, const DFBRegion *region ) { DFB_RECTANGLE_ASSERT( rect ); DFB_REGION_ASSERT( region ); return (rect->x <= region->x2 && rect->y <= region->y2 && rect->x + rect->w > region->x1 && rect->y + rect->h > region->y1); } static __inline__ bool dfb_rectangle_box_intersect( DFBRectangle *rect, const DFBBox *box ) { DFB_RECTANGLE_ASSERT( rect ); DFB_BOX_ASSERT( box ); if (DFB_BOX_EMPTY( box ) || box->x2 <= rect->x || box->y2 <= rect->y || box->x1 >= rect->x + rect->w || box->y1 >= rect->y + rect->h) { rect->w = rect->h = 0; return false; } if (rect->x < box->x1) { rect->w -= box->x1 - rect->x; rect->x = box->x1; } if (rect->y < box->y1) { rect->h -= box->y1 - rect->y; rect->y = box->y1; } if (rect->x + rect->w > box->x2) rect->w = box->x2 - rect->x; if (rect->y + rect->h > box->y2) rect->h = box->y2 - rect->y; return true; } static __inline__ void dfb_rectangle_subtract( DFBRectangle *rect, const DFBInsets *insets ) { D_ASSERT( rect != NULL ); D_ASSERT( insets != NULL ); rect->x += insets->l; rect->y += insets->t; rect->w -= insets->l + insets->r; rect->h -= insets->t + insets->b; if (rect->w <= 0 || rect->h <= 0) rect->w = rect->h = 0; } /**********************************************************************************************************************/ static __inline__ void dfb_region_from_rectangle( DFBRegion *region, const DFBRectangle *rect ) { D_ASSERT( region != NULL ); DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( rect->w > 0 ); D_ASSERT( rect->h > 0 ); region->x1 = rect->x; region->y1 = rect->y; region->x2 = rect->x + rect->w - 1; region->y2 = rect->y + rect->h - 1; } static __inline__ void dfb_region_from_rectangle_translated( DFBRegion *region, const DFBRectangle *rect, const DFBPoint *offset ) { D_ASSERT( region != NULL ); D_ASSERT( offset != NULL ); DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( rect->w > 0 ); D_ASSERT( rect->h > 0 ); region->x1 = offset->x + rect->x; region->y1 = offset->y + rect->y; region->x2 = offset->x + rect->x + rect->w - 1; region->y2 = offset->y + rect->y + rect->h - 1; } static __inline__ void dfb_region_from_rotated( DFBRegion *region, const DFBRegion *from, const DFBDimension *size, int rotation ) { D_ASSERT( region != NULL ); DFB_REGION_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: *region = *from; break; case 90: region->x1 = from->y1; region->y1 = size->w - from->x2 - 1; region->x2 = from->y2; region->y2 = size->w - from->x1 - 1; break; case 180: region->x1 = size->w - from->x2 - 1; region->y1 = size->h - from->y2 - 1; region->x2 = size->w - from->x1 - 1; region->y2 = size->h - from->y1 - 1; break; case 270: region->x1 = size->h - from->y2 - 1; region->y1 = from->x1; region->x2 = size->h - from->y1 - 1; region->y2 = from->x2; break; } } static __inline__ void dfb_region_translate( DFBRegion *region, int dx, int dy ) { D_ASSERT( region != NULL ); region->x1 += dx; region->y1 += dy; region->x2 += dx; region->y2 += dy; } static __inline__ void dfb_region_resize( DFBRegion *region, int width, int height ) { D_ASSERT( region != NULL ); D_ASSERT( width >= 0 ); D_ASSERT( height >= 0 ); region->x2 = region->x1 + width - 1; region->y2 = region->y1 + height - 1; } static __inline__ bool dfb_region_intersects( const DFBRegion *region, int x1, int y1, int x2, int y2 ) { D_ASSERT( region != NULL ); D_ASSERT( x1 <= x2 ); D_ASSERT( y1 <= y2 ); return (region->x1 <= x2 && region->y1 <= y2 && region->x2 >= x1 && region->y2 >= y1); } static __inline__ bool dfb_region_region_intersects( const DFBRegion *region, const DFBRegion *other ) { DFB_REGION_ASSERT( region ); DFB_REGION_ASSERT( other ); return (region->x1 <= other->x2 && region->y1 <= other->y2 && region->x2 >= other->x1 && region->y2 >= other->y1); } static __inline__ bool dfb_region_intersect( DFBRegion *region, int x1, int y1, int x2, int y2 ) { D_ASSERT( region != NULL ); if (region->x2 < x1 || region->y2 < y1 || region->x1 > x2 || region->y1 > y2) return false; if (region->x1 < x1) region->x1 = x1; if (region->y1 < y1) region->y1 = y1; if (region->x2 > x2) region->x2 = x2; if (region->y2 > y2) region->y2 = y2; return true; } static __inline__ bool dfb_region_region_intersect( DFBRegion *region, const DFBRegion *clip ) { D_ASSERT( region != NULL ); if (region->x2 < clip->x1 || region->y2 < clip->y1 || region->x1 > clip->x2 || region->y1 > clip->y2) return false; if (region->x1 < clip->x1) region->x1 = clip->x1; if (region->y1 < clip->y1) region->y1 = clip->y1; if (region->x2 > clip->x2) region->x2 = clip->x2; if (region->y2 > clip->y2) region->y2 = clip->y2; return true; } static __inline__ bool dfb_region_region_contains( const DFBRegion *a, const DFBRegion *b ) { D_ASSERT( a != NULL ); D_ASSERT( b != NULL ); if (a->x1 > b->x1) return false; if (a->y1 > b->y1) return false; if (a->x2 < b->x2) return false; if (a->y2 < b->y2) return false; return true; } static __inline__ bool dfb_region_region_extends( const DFBRegion *a, const DFBRegion *b ) { if (a->x1 == b->x1 && a->x2 == b->x2) return (a->y1 == b->y2 - 1) || (a->y2 == b->y1 - 1); if (a->y1 == b->y1 && a->y2 == b->y2) return (a->x1 == b->x2 - 1) || (a->x2 == b->x1 - 1); return false; } static __inline__ void dfb_region_region_union( DFBRegion *region, const DFBRegion *other ) { DFB_REGION_ASSERT( region ); DFB_REGION_ASSERT( other ); if (region->x1 > other->x1) region->x1 = other->x1; if (region->y1 > other->y1) region->y1 = other->y1; if (region->x2 < other->x2) region->x2 = other->x2; if (region->y2 < other->y2) region->y2 = other->y2; } static __inline__ void dfb_region_clip( DFBRegion *region, int x1, int y1, int x2, int y2 ) { DFB_REGION_ASSERT( region ); D_ASSERT( dfb_region_intersects( region, x1, y1, x2, y2 ) ); if (region->x1 < x1) region->x1 = x1; if (region->y1 < y1) region->y1 = y1; if (region->x2 > x2) region->x2 = x2; if (region->y2 > y2) region->y2 = y2; } static __inline__ void dfb_regions_unite( DFBRegion *united, const DFBRegion *regions, unsigned int num_regions ) { unsigned int i; D_ASSERT( united != NULL ); D_ASSERT( regions != NULL ); D_ASSERT( num_regions > 0 ); *united = regions[0]; for (i = 1; i < num_regions; i++) { DFB_REGION_ASSERT( ®ions[i] ); dfb_region_region_union( united, ®ions[i] ); } } /**********************************************************************************************************************/ static __inline__ void dfb_box_from_rectangle( DFBBox *box, const DFBRectangle *rect ) { D_ASSERT( box != NULL ); DFB_RECTANGLE_ASSERT( rect ); box->x1 = rect->x; box->y1 = rect->y; box->x2 = rect->x + rect->w; box->y2 = rect->y + rect->h; } static __inline__ void dfb_box_from_rectangle_translated( DFBBox *box, const DFBRectangle *rect, const DFBPoint *offset ) { D_ASSERT( box != NULL ); DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( offset != NULL ); box->x1 = offset->x + rect->x; box->y1 = offset->y + rect->y; box->x2 = offset->x + rect->x + rect->w; box->y2 = offset->y + rect->y + rect->h; } static __inline__ void dfb_box_from_rotated( DFBBox *box, const DFBBox *from, const DFBDimension *size, int rotation ) { D_ASSERT( box != NULL ); DFB_BOX_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: *box = *from; break; case 90: box->x1 = from->y1; box->y1 = size->w - from->x2; box->x2 = from->y2; box->y2 = size->w - from->x1; break; case 180: box->x1 = size->w - from->x2; box->y1 = size->h - from->y2; box->x2 = size->w - from->x1; box->y2 = size->h - from->y1; break; case 270: box->x1 = size->h - from->y2; box->y1 = from->x1; box->x2 = size->h - from->y1; box->y2 = from->x2; break; } } static __inline__ void dfb_box_translate( DFBBox *box, int dx, int dy ) { D_ASSERT( box != NULL ); box->x1 += dx; box->y1 += dy; box->x2 += dx; box->y2 += dy; } static __inline__ void dfb_box_resize( DFBBox *box, int width, int height ) { D_ASSERT( box != NULL ); D_ASSERT( width >= 0 ); D_ASSERT( height >= 0 ); box->x2 = box->x1 + width; box->y2 = box->y1 + height; } static __inline__ bool dfb_box_box_contains( const DFBBox *a, const DFBBox *b ) { D_ASSERT( a != NULL ); D_ASSERT( b != NULL ); if (a->x1 > b->x1) return false; if (a->y1 > b->y1) return false; if (a->x2 < b->x2) return false; if (a->y2 < b->y2) return false; return true; } static __inline__ bool dfb_box_intersects( const DFBBox *box, int x1, int y1, int x2, int y2 ) { DFB_BOX_ASSERT( box ); D_ASSERT( x1 <= x2 ); D_ASSERT( y1 <= y2 ); return (box->x1 < x2 && box->y1 < y2 && box->x2 > x1 && box->y2 > y1); } static __inline__ bool dfb_box_box_intersects( const DFBBox *box, const DFBBox *other ) { DFB_BOX_ASSERT( box ); DFB_BOX_ASSERT( other ); return (box->x1 < other->x2 && box->y1 < other->y2 && box->x2 > other->x1 && box->y2 > other->y1); } static __inline__ bool dfb_box_intersect( DFBBox *box, int x1, int y1, int x2, int y2 ) { DFB_BOX_ASSERT( box ); D_ASSERT( x1 <= x2 ); D_ASSERT( y1 <= y2 ); if (DFB_BOX_EMPTY( box )) return false; if (box->x2 <= x1 || box->y2 <= y1 || box->x1 >= x2 || box->y1 >= y2) return false; if (box->x1 < x1) box->x1 = x1; if (box->y1 < y1) box->y1 = y1; if (box->x2 > x2) box->x2 = x2; if (box->y2 > y2) box->y2 = y2; return true; } static __inline__ bool dfb_box_box_intersect( DFBBox *box, const DFBBox *clip ) { DFB_BOX_ASSERT( box ); DFB_BOX_ASSERT( clip ); if (DFB_BOX_EMPTY( box )) return false; if (DFB_BOX_EMPTY( clip ) || box->x2 <= clip->x1 || box->y2 <= clip->y1 || box->x1 >= clip->x2 || box->y1 >= clip->y2) { return false; } if (box->x1 < clip->x1) box->x1 = clip->x1; if (box->y1 < clip->y1) box->y1 = clip->y1; if (box->x2 > clip->x2) box->x2 = clip->x2; if (box->y2 > clip->y2) box->y2 = clip->y2; return true; } static __inline__ bool dfb_box_region_intersects( const DFBBox *box, const DFBRegion *clip ) { DFB_BOX_ASSERT( box ); D_ASSERT( clip != NULL ); if (DFB_BOX_EMPTY( box )) return false; if (clip->x1 > clip->x2 || clip->y1 > clip->y2 || box->x2 <= clip->x1 || box->y2 <= clip->y1 || box->x1 > clip->x2 || box->y1 > clip->y2) { return false; } return true; } static __inline__ bool dfb_box_region_intersect( DFBBox *box, const DFBRegion *clip ) { DFB_BOX_ASSERT( box ); D_ASSERT( clip != NULL ); if (DFB_BOX_EMPTY( box )) return false; if (clip->x1 > clip->x2 || clip->y1 > clip->y2 || box->x2 <= clip->x1 || box->y2 <= clip->y1 || box->x1 > clip->x2 || box->y1 > clip->y2) { box->x2 = box->x1; box->y2 = box->y1; return false; } if (box->x1 < clip->x1) box->x1 = clip->x1; if (box->y1 < clip->y1) box->y1 = clip->y1; if (box->x2 > clip->x2 + 1) box->x2 = clip->x2 + 1; if (box->y2 > clip->y2 + 1) box->y2 = clip->y2 + 1; return true; } static __inline__ bool dfb_box_box_extends( const DFBBox *a, const DFBBox *b ) { DFB_BOX_ASSERT( a ); DFB_BOX_ASSERT( b ); if (a->x1 == b->x1 && a->x2 == b->x2) return (a->y1 == b->y2) || (a->y2 == b->y1); if (a->y1 == b->y1 && a->y2 == b->y2) return (a->x1 == b->x2) || (a->x2 == b->x1); return false; } static __inline__ void dfb_box_box_union( DFBBox *box, const DFBBox *other ) { DFB_BOX_ASSERT( box ); DFB_BOX_ASSERT( other ); if (DFB_BOX_EMPTY( other )) return; if (DFB_BOX_EMPTY( box )) { *box = *other; } else { if (box->x1 > other->x1) box->x1 = other->x1; if (box->y1 > other->y1) box->y1 = other->y1; if (box->x2 < other->x2) box->x2 = other->x2; if (box->y2 < other->y2) box->y2 = other->y2; } } static __inline__ void dfb_box_region_union( DFBBox *box, const DFBRegion *region ) { DFB_BOX_ASSERT( box ); DFB_REGION_ASSERT( region ); if (DFB_BOX_EMPTY( box )) { box->x1 = region->x1; box->y1 = region->y1; box->x2 = region->x2 + 1; box->y2 = region->y2 + 1; } else { if (box->x1 > region->x1) box->x1 = region->x1; if (box->y1 > region->y1) box->y1 = region->y1; if (box->x2 < region->x2 + 1) box->x2 = region->x2 + 1; if (box->y2 < region->y2 + 1) box->y2 = region->y2 + 1; } } static __inline__ void dfb_box_clip( DFBBox *box, int x1, int y1, int x2, int y2 ) { DFB_BOX_ASSERT( box ); D_ASSERT( dfb_box_intersects( box, x1, y1, x2, y2 ) ); if (box->x1 < x1) box->x1 = x1; if (box->y1 < y1) box->y1 = y1; if (box->x2 > x2) box->x2 = x2; if (box->y2 > y2) box->y2 = y2; } /**********************************************************************************************************************/ /* * Compute line segment intersection. Return true if intersection point exists within the given segment. */ static __inline__ bool dfb_line_segment_intersect( const DFBRegion *line, const DFBRegion *seg, int *x, int *y ) { int x1, x2, x3, x4; int y1, y2, y3, y4; int num, den; D_ASSERT( line != NULL ); D_ASSERT( seg != NULL ); x1 = seg->x1; y1 = seg->y1; x2 = seg->y2; y2 = seg->y2; x3 = line->x1; y3 = line->y1; x4 = line->x2; y4 = line->y2; num = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); if (!den) /* parallel */ return false; if (num && ((num < 0) != (den < 0) || abs(num) > abs(den))) /* not within segment */ return false; if (x) *x = (s64) (x2 - x1) * num / den + x1; if (y) *y = (s64) (y2 - y1) * num / den + y1; return true; } /**********************************************************************************************************************/ static __inline__ void dfb_point_from_rotated_region( DFBPoint *point, const DFBRegion *from, const DFBDimension *size, int rotation ) { D_ASSERT( point != NULL ); DFB_REGION_ASSERT( from ); D_ASSERT( size != NULL ); D_ASSERT( size->w > 0 ); D_ASSERT( size->h > 0 ); D_ASSUME( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 ); switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: point->x = from->x1; point->y = from->y1; break; case 90: point->x = from->y1; point->y = size->w - from->x2 - 1; break; case 180: point->x = size->w - from->x2 - 1; point->y = size->h - from->y2 - 1; break; case 270: point->x = size->h - from->y2 - 1; point->y = from->x1; break; } D_ASSERT( point->x >= 0 ); D_ASSERT( point->y >= 0 ); D_ASSERT( point->x < size->w ); D_ASSERT( point->y < size->h ); } static __inline__ void dfb_point_translate( DFBPoint *point, int dx, int dy ) { D_ASSERT( point != NULL ); point->x += dx; point->y += dy; } /**********************************************************************************************************************/ typedef struct { int magic; DFBRegion *regions; int max_regions; int num_regions; DFBRegion bounding; } DFBUpdates; #define DFB_UPDATES_ASSERT(updates) \ do { \ D_MAGIC_ASSERT( updates, DFBUpdates ); \ D_ASSERT( (updates)->regions != NULL ); \ D_ASSERT( (updates)->max_regions > 0 ); \ D_ASSERT( (updates)->num_regions <= (updates)->max_regions ); \ } while (0) #define DFB_UPDATES_DEBUG_AT(d,updates) \ do { \ D_DEBUG_AT( d, " =--[ " #updates " has %d regions ]\n", (updates)->num_regions ); \ DFB_REGIONS_DEBUG_AT( d, (updates)->regions, (unsigned int) ((updates)->num_regions) ); \ } while (0) void DIRECTFB_API dfb_updates_init ( DFBUpdates *updates, DFBRegion *regions, int max_regions ); void DIRECTFB_API dfb_updates_deinit ( DFBUpdates *updates ); void DIRECTFB_API dfb_updates_add ( DFBUpdates *updates, const DFBRegion *region ); void DIRECTFB_API dfb_updates_add_rect ( DFBUpdates *updates, int x, int y, int w, int h ); void DIRECTFB_API dfb_updates_stat ( DFBUpdates *updates, int *ret_total, int *ret_bounding ); void DIRECTFB_API dfb_updates_get_rectangles( DFBUpdates *updates, DFBRectangle *ret_rects, int *ret_num ); void DIRECTFB_API dfb_updates_reset ( DFBUpdates *updates ); /**********************************************************************************************************************/ const char DIRECTFB_API *dfb_input_event_type_name ( DFBInputEventType type ); const char DIRECTFB_API *dfb_pixelformat_name ( DFBSurfacePixelFormat format ); const char DIRECTFB_API *dfb_colorspace_name ( DFBSurfaceColorSpace colorspace ); const char DIRECTFB_API *dfb_window_event_type_name( DFBWindowEventType type ); /**********************************************************************************************************************/ DFBSurfacePixelFormat DIRECTFB_API dfb_pixelformat_for_depth( int depth ); DFBSurfacePixelFormat DIRECTFB_API dfb_pixelformat_parse ( const char *format ); DFBSurfaceColorSpace DIRECTFB_API dfb_colorspace_parse ( const char *colorspace ); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/directfb_windows.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFB_WINDOWS_H__ #define __DIRECTFB_WINDOWS_H__ #include #ifdef __cplusplus extern "C" { #endif /* * Window stack interface. */ D_DECLARE_INTERFACE( IDirectFBWindows ) /******************** * IDirectFBWindows * ********************/ /* * Window configuration flags. */ typedef enum { DWCONF_NONE = 0x00000000, /* none of these flags */ DWCONF_POSITION = 0x00000001, /* position */ DWCONF_SIZE = 0x00000002, /* size */ DWCONF_OPACITY = 0x00000004, /* opacity */ DWCONF_STACKING = 0x00000008, /* stacking */ DWCONF_OPTIONS = 0x00000010, /* options */ DWCONF_EVENTS = 0x00000020, /* events */ DWCONF_ASSOCIATION = 0x00000040, /* association */ DWCONF_COLOR_KEY = 0x00000100, /* color key */ DWCONF_OPAQUE = 0x00000200, /* opaque */ DWCONF_COLOR = 0x00000400, /* color */ DWCONF_STEREO_DEPTH = 0x00000800, /* stereo depth */ DWCONF_KEY_SELECTION = 0x00001000, /* key selection */ DWCONF_CURSOR_FLAGS = 0x00002000, /* cursor flags */ DWCONF_CURSOR_RESOLUTION = 0x00004000, /* cursor resolution */ DWCONF_SRC_GEOMETRY = 0x00010000, /* source geometry */ DWCONF_DST_GEOMETRY = 0x00020000, /* destination geometry */ DWCONF_ROTATION = 0x00040000, /* rotation */ DWCONF_APPLICATION_ID = 0x00080000, /* application id */ DWCONF_TYPE_HINT = 0x00100000, /* type hint */ DWCONF_HINT_FLAGS = 0x00200000, /* hint flags */ DWCONF_ALL = 0x003F7F7F /* all of these */ } DFBWindowConfigFlags; /* * Window configuration. */ typedef struct { DFBRectangle bounds; /* position and size */ int opacity; /* global alpha factor */ DFBWindowStackingClass stacking; /* level boundaries */ DFBWindowOptions options; /* flags for appearance/behaviour */ DFBWindowEventType events; /* mask of enabled events */ DFBWindowID association; /* ID of window which this is associated to */ u32 color_key; /* transparent pixel */ DFBRegion opaque; /* region of the window forced to be opaque */ DFBColor color; /* constant color (no surface needed) */ DFBWindowKeySelection key_selection; /* how to filter keys in focus */ DFBWindowCursorFlags cursor_flags; /* cursor flags */ DFBDimension cursor_resolution; /* cursor resolution */ DFBWindowGeometry src_geometry; /* advanced source geometry */ DFBWindowGeometry dst_geometry; /* advanced destination geometry */ int rotation; /* rotation */ u64 application_id; /* application id */ int stereo_depth; /* stereo depth */ DFBWindowTypeHint type_hint; /* type hint */ DFBWindowHintFlags hint_flags; /* hint flags */ } DFBWindowConfig; /* * Window state flags. */ typedef enum { DWSTATE_NONE = 0x00000000, /* None of these. */ DWSTATE_INSERTED = 0x00000001, /* Window is inserted. */ DWSTATE_FOCUSED = 0x00000002, /* Window is focused. */ DWSTATE_ENTERED = 0x00000004, /* Window is entered. */ DWSTATE_ALL = 0x00000007 /* All of these. */ } DFBWindowStateFlags; /* * Window state. */ typedef struct { DFBWindowStateFlags flags; /* Window state flags. */ } DFBWindowState; /* * Window information. */ typedef struct { DFBWindowID window_id; /* Window ID */ DFBWindowCapabilities caps; /* Window capabilities */ u64 resource_id; /* Resource ID */ DFBWindowConfig config; /* Window configuration. */ DFBWindowState state; /* Window state */ u32 process_id; /* Fusion ID or other element identifying process. */ u32 instance_id; /* ID of the instance of an application. */ } DFBWindowInfo; /* * Windows watcher callbacks. */ typedef struct { /* * Add window, called for each window existing at watcher * registration and each added afterwards. */ void (*WindowAdd) ( void *context, const DFBWindowInfo *info ); /* * Remove window, called for each window being removed. */ void (*WindowRemove) ( void *context, DFBWindowID window_id ); /* * Change window configuration, called for each window * changing its configuration. The flags specify which * of the items have changed actually. */ void (*WindowConfig) ( void *context, DFBWindowID window_id, const DFBWindowConfig *config, DFBWindowConfigFlags flags ); /* * Update window state, called for each window changing its * state. In case of insertion of a window, prior to this, * the watcher will receive the WindowRestack() call, which * contains the z-position at which the window has been * inserted. */ void (*WindowState) ( void *context, DFBWindowID window_id, const DFBWindowState *state ); /* * Update window z-position, called for each window * changing its z-position. In case of insertion of a * window, after this call, the watcher will receive the * WindowState() call, which indicates insertion of the * window. Upon reinsertion, only this call will be * received. */ void (*WindowRestack) ( void *context, DFBWindowID window_id, unsigned int index ); /* * Switch window focus, called for each window getting the * focus. */ void (*WindowFocus) ( void *context, DFBWindowID window_id ); } DFBWindowsWatcher; /* * IDirectFBWindows is the window stack interface. */ D_DEFINE_INTERFACE( IDirectFBWindows, /** Watching **/ /* * Register a new windows watcher. */ DFBResult (*RegisterWatcher) ( IDirectFBWindows *thiz, const DFBWindowsWatcher *watcher, void *context ); /* * Unregister a windows watcher. */ DFBResult (*UnregisterWatcher) ( IDirectFBWindows *thiz, void *context ); ) #ifdef __cplusplus } #endif #endif ================================================ FILE: include/directfbgl.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFBGL_H__ #define __DIRECTFBGL_H__ #include #ifdef __cplusplus extern "C" { #endif /*************** * IDirectFBGL * ***************/ /* * The DirectFBGL interface version. */ #ifndef DIRECTFBGL_INTERFACE_VERSION #define DIRECTFBGL_INTERFACE_VERSION 2 #endif /* * Attributes of an OpenGL context. */ typedef struct { int buffer_size; /* depth of the color buffer */ int depth_size; /* number of bits in the depth buffer */ int stencil_size; /* number of bits in the stencil buffer */ int aux_buffers; /* number of auxiliary color buffers */ int red_size; /* number of bits of red in the framebuffer */ int green_size; /* number of bits of green in the framebuffer */ int blue_size; /* number of bits of blue in the framebuffer */ int alpha_size; /* number of bits of alpha in the framebuffer */ int accum_red_size; /* number of bits of red in the accumulation buffer */ int accum_green_size; /* number of bits of green in the accumulation buffer */ int accum_blue_size; /* number of bits of blue in the accumulation buffer */ int accum_alpha_size; /* number of bits of alpha in the accumulation buffer */ DFBBoolean double_buffer; /* true if color buffers have front/back buffer pairs */ DFBBoolean stereo; /* true if color buffers have left/right pairs */ } DFBGLAttributes; /* * IDirectFBGL is the OpenGL interface. */ D_DEFINE_INTERFACE( IDirectFBGL, /** Context handling **/ /* * Acquire the hardware lock. */ DFBResult (*Lock) ( IDirectFBGL *thiz ); /* * Release the lock. */ DFBResult (*Unlock) ( IDirectFBGL *thiz ); /* * Query the OpenGL attributes. */ DFBResult (*GetAttributes) ( IDirectFBGL *thiz, DFBGLAttributes *ret_attributes ); /* * Get the address of an OpenGL function. */ DFBResult (*GetProcAddress) ( IDirectFBGL *thiz, const char *name, void **ret_address ); #if DIRECTFBGL_INTERFACE_VERSION > 1 /* * Swap buffers. */ DFBResult (*SwapBuffers) ( IDirectFBGL *thiz ); #endif ) #ifdef __cplusplus } #endif #endif ================================================ FILE: include/gen_directfb_keynames.sh ================================================ #!/bin/sh # # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA mknames() { ENUM=$1 PREFIX=$2 NULL=$3 NAME=$4 VALUE=$5 HEADER=$6 cat << EOF struct DFB${NAME}Name { ${ENUM} ${VALUE}; const char *name; }; #define DirectFB${NAME}Names(Identifier) struct DFB${NAME}Name Identifier[] = { \\ EOF egrep "^ +${PREFIX}_[0-9A-Za-z_]+[ ,]" $HEADER | grep -v ${PREFIX}_${NULL} | perl -p -e "s/^\\s*(${PREFIX}_)([\\w_]+)[ ,].*/ \\{ \\1\\2, \\\"\\2\\\" \\}, \\\\/" cat << EOF { ($ENUM) ${PREFIX}_${NULL}, "${NULL}" } \\ }; EOF } echo \#ifndef __DIRECTFB_KEYNAMES_H__ echo \#define __DIRECTFB_KEYNAMES_H__ echo echo \#include \ mknames DFBInputDeviceKeySymbol DIKS NULL KeySymbol symbol $1 | grep -v DIKS_ENTER mknames DFBInputDeviceKeyIdentifier DIKI UNKNOWN KeyIdentifier identifier $1 | grep -v DIKI_NUMBER_OF_KEYS | grep -v DIKI_KEYDEF_END echo echo \#endif ================================================ FILE: include/gen_directfb_strings.sh ================================================ #!/bin/sh # # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA mknames() { ENUM=$1 PREFIX=$2 NULL=$3 NAME=$4 VALUE=$5 HEADER=$6 cat << EOF struct DFB${NAME}Name { ${ENUM} ${VALUE}; const char *name; }; #define DirectFB${NAME}Names(Identifier) struct DFB${NAME}Name Identifier[] = { \\ EOF egrep "^ +${PREFIX}_[0-9A-Za-z_]+[ ,]" $HEADER | grep -v ${PREFIX}_${NULL} | perl -p -e "s/^\\s*(${PREFIX}_)([\\w_]+)[ ,].*/ \\{ \\1\\2, \\\"\\2\\\" \\}, \\\\/" cat << EOF { ($ENUM) ${PREFIX}_${NULL}, "${NULL}" } \\ }; EOF } echo \#ifndef __DIRECTFB_STRINGS_H__ echo \#define __DIRECTFB_STRINGS_H__ echo echo \#include \ mknames DFBSurfacePixelFormat DSPF UNKNOWN PixelFormat format $1 mknames DFBSurfacePorterDuffRule DSPD NONE PorterDuffRule rule $1 mknames DFBSurfaceCapabilities DSCAPS NONE SurfaceCapabilities capability $1 | grep -v DSCAPS_FLIPPING | grep -v DSCAPS_ALL mknames DFBSurfaceColorSpace DSCS UNKNOWN ColorSpace colorspace $1 mknames DFBInputDeviceTypeFlags DIDTF NONE InputDeviceTypeFlags type $1 | grep -v DIDTF_ALL mknames DFBSurfaceDrawingFlags DSDRAW NOFX SurfaceDrawingFlags flag $1 | grep -v DSDRAW_ALL mknames DFBSurfaceBlittingFlags DSBLIT NOFX SurfaceBlittingFlags flag $1 | grep -v DSBLIT_ALL mknames DFBSurfaceFlipFlags DSFLIP NONE SurfaceFlipFlags flag $1 | grep -v DSFLIP_ALL mknames DFBSurfaceBlendFunction DSBF UNKNOWN SurfaceBlendFunction function $1 mknames DFBInputDeviceCapabilities DICAPS NONE InputDeviceCapabilities capability $1 | grep -v DICAPS_ALL | grep -v DICAPS_ALPHACHANNEL | grep -v DICAPS_COLORKEY mknames DFBDisplayLayerTypeFlags DLTF NONE DisplayLayerTypeFlags type $1 | grep -v DLTF_ALL mknames DFBDisplayLayerCapabilities DLCAPS NONE DisplayLayerCapabilities capability $1 | grep -v DLCAPS_ALL mknames DFBDisplayLayerBufferMode DLBM UNKNOWN DisplayLayerBufferMode mode $1 | grep -v DLBM_DONTCARE | grep -v DLBM_COLOR | grep -v DLBM_IMAGE | grep -v DLBM_TILE mknames DFBWindowCapabilities DWCAPS NONE WindowCapabilities capability $1 | grep -v DWCAPS_ALL mknames DFBDisplayLayerOptions DLOP NONE DisplayLayerOptions option $1 | grep -v DLOP_ALL mknames DFBWindowOptions DWOP NONE WindowOptions option $1 | grep -v DWOP_ALL mknames DFBScreenCapabilities DSCCAPS NONE ScreenCapabilities capability $1 | grep -v DSCCAPS_ALL mknames DFBScreenEncoderCapabilities DSECAPS NONE ScreenEncoderCapabilities capability $1 | grep -v DSECAPS_ALL mknames DFBScreenEncoderType DSET UNKNOWN ScreenEncoderType type $1 | grep -v DSET_ALL mknames DFBScreenEncoderTVStandards DSETV UNKNOWN ScreenEncoderTVStandards standard $1 | grep -v DSETV_ALL mknames DFBScreenOutputCapabilities DSOCAPS NONE ScreenOutputCapabilities capability $1 | grep -v DSOCAPS_ALL mknames DFBScreenOutputConnectors DSOC UNKNOWN ScreenOutputConnectors connector $1 | grep -v DSOC_ALL mknames DFBScreenOutputSignals DSOS NONE ScreenOutputSignals signal $1 | grep -v DSOS_ALL mknames DFBScreenOutputSlowBlankingSignals DSOSB OFF ScreenOutputSlowBlankingSignals slow_signal $1 | grep -v DSOSB_ALL mknames DFBScreenOutputResolution DSOR UNKNOWN ScreenOutputResolution resolution $1 | grep -v DSOR_ALL mknames DFBScreenMixerCapabilities DSMCAPS NONE ScreenMixerCapabilities capability $1 | grep -v DSMCAPS_ALL mknames DFBScreenMixerTree DSMT UNKNOWN ScreenMixerTree tree $1 | grep -v DSMT_ALL mknames DFBScreenEncoderTestPicture DSETP OFF ScreenEncoderTestPicture test_picture $1 | grep -v DSETP_ALL mknames DFBScreenEncoderScanMode DSESM UNKNOWN ScreenEncoderScanMode scan_mode $1 | grep -v DSESM_ALL mknames DFBScreenEncoderConfigFlags DSECONF UNKNOWN ScreenEncoderConfigFlags config_flags $1 | grep -v DSECONF_ALL mknames DFBScreenEncoderFrequency DSEF UNKNOWN ScreenEncoderFrequency frequency $1 | grep -v DSEF_ALL mknames DFBScreenEncoderPictureFraming DSEPF UNKNOWN ScreenEncoderPictureFraming framing $1 | grep -v DSEPF_ALL mknames DFBAccelerationMask DFXL NONE AccelerationMask mask $1 | grep -v DFXL_ALL echo echo \#endif ================================================ FILE: include/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA directfb_headers = [ 'dfiff.h', 'dfvff.h', 'dgiff.h', 'directfb.h', 'directfb_keyboard.h', 'directfb_util.h', 'directfb_windows.h', 'directfbgl.h', ] directfb_version_conf = configuration_data() directfb_version_conf.set('DIRECTFB_MAJOR_VERSION', directfb_major_version) directfb_version_conf.set('DIRECTFB_MINOR_VERSION', directfb_minor_version) directfb_version_conf.set('DIRECTFB_MICRO_VERSION', directfb_micro_version) configure_file(configuration: directfb_version_conf, output: 'directfb_version.h', install: true, install_dir: get_option('includedir') / 'directfb') directfb_build_conf = configuration_data() directfb_build_conf.set('FLUXED_ARGS_BYTES', get_option('args-size')) configure_file(configuration: directfb_build_conf, output: 'directfb_build.h', install: true, install_dir: get_option('includedir') / 'directfb') directfb_keynames = custom_target('directfb_keynames', command: ['gen_directfb_keynames.sh', '@INPUT@'], input: 'directfb_keyboard.h', output: 'directfb_keynames.h', capture: true, install: true, install_dir: get_option('includedir') / 'directfb') directfb_strings = custom_target('directfb_strings', command: ['gen_directfb_strings.sh', '@INPUT@'], input: 'directfb.h', output: 'directfb_strings.h', capture: true, install: true, install_dir: get_option('includedir') / 'directfb') install_headers(directfb_headers, subdir: 'directfb') ================================================ FILE: inputdrivers/linux_input/linux_input.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define DFB_INPUTDRIVER_HAS_AXIS_INFO #define DFB_INPUTDRIVER_HAS_SET_CONFIGURATION #include #if DIRECT_BUILD_NETWORK #define DISABLE_INPUT_HOTPLUG_FUNCTION_STUB #endif /* DIRECT_BUILD_NETWORK */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Linux_Input, "Input/Linux", "Linux Input Driver" ); DFB_INPUT_DRIVER( linux_input ) /**********************************************************************************************************************/ #define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1) typedef struct { CoreInputDevice *device; int index; int fd; bool grab; bool has_keys; bool has_leds; unsigned long led_state[NBITS(LED_CNT)]; DFBInputDeviceLockState locks; bool touchpad; bool touch_abs; int sensitivity; int dx; int dy; int vt_fd; DirectThread *thread; int quitpipe[2]; } LinuxInputData; /* The maximum amount of evdev devices with static minors, from 13:64 to 13:95 */ #define MAX_LINUX_INPUT_DEVICES 32 /* Input devices are stored in the device_names and device_nums arrays: entries with the same index in device_names and device_nums are the same in two different forms (one is /dev/input/eventX, the other is X. */ static char *device_names[MAX_LINUX_INPUT_DEVICES]; static int device_nums[MAX_LINUX_INPUT_DEVICES] = { 0 }; /* Number of entries in the device_names and device_nums arrays. */ static int num_devices = 0; #define MAX_LINUX_INPUT_EVENTS 64 /* Input events filled on read. */ struct input_event input_events[MAX_LINUX_INPUT_EVENTS]; #if !defined(input_event_sec) && !defined(input_event_usec) #define input_event_sec time.tv_sec #define input_event_usec time.tv_usec #endif /**********************************************************************************************************************/ #define OFF(x) ((x) % (sizeof(long) * 8)) #define LONG(x) ((x) / (sizeof(long) * 8)) #define test_bit(bit,array) ((array[LONG(bit)] >> OFF(bit)) & 1) static const int basic_keycodes[] = { DIKI_UNKNOWN, DIKI_ESCAPE, DIKI_1, DIKI_2, DIKI_3, DIKI_4, DIKI_5, DIKI_6, DIKI_7, DIKI_8, DIKI_9, DIKI_0, DIKI_MINUS_SIGN, DIKI_EQUALS_SIGN, DIKI_BACKSPACE, DIKI_TAB, DIKI_Q, DIKI_W, DIKI_E, DIKI_R, DIKI_T, DIKI_Y, DIKI_U, DIKI_I, DIKI_O, DIKI_P, DIKI_BRACKET_LEFT, DIKI_BRACKET_RIGHT, DIKI_ENTER, DIKI_CONTROL_L, DIKI_A, DIKI_S, DIKI_D, DIKI_F, DIKI_G, DIKI_H, DIKI_J, DIKI_K, DIKI_L, DIKI_SEMICOLON, DIKI_QUOTE_RIGHT, DIKI_QUOTE_LEFT, DIKI_SHIFT_L, DIKI_BACKSLASH, DIKI_Z, DIKI_X, DIKI_C, DIKI_V, DIKI_B, DIKI_N, DIKI_M, DIKI_COMMA, DIKI_PERIOD, DIKI_SLASH, DIKI_SHIFT_R, DIKI_KP_MULT, DIKI_ALT_L, DIKI_SPACE, DIKI_CAPS_LOCK, DIKI_F1, DIKI_F2, DIKI_F3, DIKI_F4, DIKI_F5, DIKI_F6, DIKI_F7, DIKI_F8, DIKI_F9, DIKI_F10, DIKI_NUM_LOCK, DIKI_SCROLL_LOCK, DIKI_KP_7, DIKI_KP_8, DIKI_KP_9, DIKI_KP_MINUS, DIKI_KP_4, DIKI_KP_5, DIKI_KP_6, DIKI_KP_PLUS, DIKI_KP_1, DIKI_KP_2, DIKI_KP_3, DIKI_KP_0, DIKI_KP_DECIMAL, DIKI_BACKSLASH, DFB_FUNCTION_KEY(13), DIKI_LESS_SIGN, DIKI_F11, DIKI_F12, DFB_FUNCTION_KEY(14), DFB_FUNCTION_KEY(15), DFB_FUNCTION_KEY(16), DFB_FUNCTION_KEY(17), DFB_FUNCTION_KEY(18), DFB_FUNCTION_KEY(19), DFB_FUNCTION_KEY(20), DIKI_KP_ENTER, DIKI_CONTROL_R, DIKI_KP_DIV, DIKI_PRINT, DIKS_ALTGR, DIKI_UNKNOWN, DIKI_HOME, DIKI_UP, DIKI_PAGE_UP, DIKI_LEFT, DIKI_RIGHT, DIKI_END, DIKI_DOWN, DIKI_PAGE_DOWN, DIKI_INSERT, DIKI_DELETE, DIKI_UNKNOWN, DIKS_MUTE, DIKS_VOLUME_DOWN, DIKS_VOLUME_UP, DIKS_POWER, DIKI_KP_EQUAL, DIKI_UNKNOWN, DIKS_PAUSE, DFB_FUNCTION_KEY(21), DFB_FUNCTION_KEY(22), DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24), DIKI_KP_SEPARATOR, DIKI_META_L, DIKI_META_R, DIKI_SUPER_L, DIKS_STOP, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_HELP, DIKS_MENU, DIKS_CALCULATOR, DIKS_SETUP, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_CUSTOM1, DIKS_CUSTOM2, DIKS_INTERNET, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_MAIL, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_BACK, DIKS_FORWARD, DIKS_EJECT, DIKS_EJECT, DIKS_EJECT, DIKS_NEXT, DIKS_PLAYPAUSE, DIKS_PREVIOUS, DIKS_STOP, DIKS_RECORD, DIKS_REWIND, DIKS_PHONE, DIKI_UNKNOWN, DIKS_SETUP, DIKI_UNKNOWN, DIKS_SHUFFLE, DIKS_EXIT, DIKI_UNKNOWN, DIKS_EDITOR, DIKS_PAGE_UP, DIKS_PAGE_DOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DFB_FUNCTION_KEY(13), DFB_FUNCTION_KEY(14), DFB_FUNCTION_KEY(15), DFB_FUNCTION_KEY(16), DFB_FUNCTION_KEY(17), DFB_FUNCTION_KEY(18), DFB_FUNCTION_KEY(19), DFB_FUNCTION_KEY(20), DFB_FUNCTION_KEY(21), DFB_FUNCTION_KEY(22), DFB_FUNCTION_KEY(23), DFB_FUNCTION_KEY(24), DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_PLAY, DIKS_PAUSE, DIKS_CUSTOM3, DIKS_CUSTOM4, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_PLAY, DIKS_FASTFORWARD, DIKI_UNKNOWN, DIKS_PRINT, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_AUDIO, DIKS_HELP, DIKS_MAIL, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKS_CANCEL, DIKI_UNKNOWN, DIKI_UNKNOWN, DIKI_UNKNOWN }; static const int ext_keycodes[] = { DIKS_OK, DIKS_SELECT, DIKS_GOTO, DIKS_CLEAR, DIKS_POWER2, DIKS_OPTION, DIKS_INFO, DIKS_TIME, DIKS_VENDOR, DIKS_ARCHIVE, DIKS_PROGRAM, DIKS_CHANNEL, DIKS_FAVORITES, DIKS_EPG, DIKS_PVR, DIKS_MHP, DIKS_LANGUAGE, DIKS_TITLE, DIKS_SUBTITLE, DIKS_ANGLE, DIKS_ZOOM, DIKS_MODE, DIKS_KEYBOARD, DIKS_SCREEN, DIKS_PC, DIKS_TV, DIKS_TV2, DIKS_VCR, DIKS_VCR2, DIKS_SAT, DIKS_SAT2, DIKS_CD, DIKS_TAPE, DIKS_RADIO, DIKS_TUNER, DIKS_PLAYER, DIKS_TEXT, DIKS_DVD, DIKS_AUX, DIKS_MP3, DIKS_AUDIO, DIKS_VIDEO, DIKS_DIRECTORY, DIKS_LIST, DIKS_MEMO, DIKS_CALENDAR, DIKS_RED, DIKS_GREEN, DIKS_YELLOW, DIKS_BLUE, DIKS_CHANNEL_UP, DIKS_CHANNEL_DOWN, DIKS_FIRST, DIKS_LAST, DIKS_AB, DIKS_NEXT, DIKS_RESTART, DIKS_SLOW, DIKS_SHUFFLE, DIKS_BREAK, DIKS_PREVIOUS, DIKS_DIGITS, DIKS_TEEN, DIKS_TWEN }; /**********************************************************************************************************************/ static void config_values_parse( FusionVector *vector, const char *arg ) { char *values = D_STRDUP( arg ); char *s = values; char *r, *p = NULL; if (!values) { D_OOM(); return; } while ((r = direct_strtok_r( s, ",", &p ))) { direct_trim( &r ); r = D_STRDUP( r ); if (!r) D_OOM(); else fusion_vector_add( vector, r ); s = NULL; } D_FREE( values ); } static void config_values_free( FusionVector *vector ) { char *value; int i; fusion_vector_foreach (value, i, *vector) D_FREE( value ); fusion_vector_destroy( vector ); } /**********************************************************************************************************************/ enum { TOUCHPAD_FSM_START, TOUCHPAD_FSM_MAIN, TOUCHPAD_FSM_DRAG_START, TOUCHPAD_FSM_DRAG_MAIN, }; struct touchpad_axis { int old, min, max; }; struct touchpad_fsm_state { int fsm_state; struct touchpad_axis x; struct touchpad_axis y; struct timeval timeout; }; #define ACCEL_THRESHOLD 25 #define ACCEL_NUM 3 #define ACCEL_DENOM 1 static bool timeout_is_set( const struct timeval *timeout ) { return timeout->tv_sec || timeout->tv_usec; } static bool timeout_passed( const struct timeval *timeout, const struct timeval *current ) { return !timeout_is_set( timeout ) || current->tv_sec > timeout->tv_sec || (current->tv_sec == timeout->tv_sec && current->tv_usec > timeout->tv_usec); } static void timeout_clear( struct timeval *timeout ) { timeout->tv_sec = 0; timeout->tv_usec = 0; } static void timeout_add( struct timeval *timeout, const struct timeval *add ) { timeout->tv_sec += add->tv_sec; timeout->tv_usec += add->tv_usec; while (timeout->tv_usec >= 1000000) { timeout->tv_sec++; timeout->tv_usec -= 1000000; } } static void timeout_sub( struct timeval *timeout, const struct timeval *sub ) { timeout->tv_sec -= sub->tv_sec; timeout->tv_usec -= sub->tv_usec; while (timeout->tv_usec < 0) { timeout->tv_sec--; timeout->tv_usec += 1000000; } } static void touchpad_fsm_init( struct touchpad_fsm_state *state ) { state->x.old = -1; state->y.old = -1; state->fsm_state = TOUCHPAD_FSM_START; timeout_clear( &state->timeout ); } static int touchpad_normalize( const struct touchpad_axis *axis, int value ) { return ((value - axis->min) << 9) / (axis->max - axis->min); } static int touchpad_translate( struct touchpad_fsm_state *state, bool touch_abs, const struct input_event *levt, DFBInputEvent *devt ) { struct touchpad_axis *axis = NULL; int abs, rel; devt->flags = DIEF_TIMESTAMP | (touch_abs ? DIEF_AXISABS : DIEF_AXISREL); devt->timestamp.tv_sec = levt->input_event_sec; devt->timestamp.tv_usec = levt->input_event_usec; devt->type = DIET_AXISMOTION; switch (levt->code) { case ABS_X: axis = &state->x; devt->axis = DIAI_X; break; case ABS_Y: axis = &state->y; devt->axis = DIAI_Y; break; default: return 0; } abs = touchpad_normalize( axis, levt->value ); if (axis->old == -1) axis->old = abs; rel = abs - axis->old; if (rel > ACCEL_THRESHOLD) rel += (rel - ACCEL_THRESHOLD) * ACCEL_NUM / ACCEL_DENOM; else if (rel < -ACCEL_THRESHOLD) rel += (rel + ACCEL_THRESHOLD) * ACCEL_NUM / ACCEL_DENOM; axis->old = abs; devt->axisrel = rel; devt->axisabs = levt->value; return 1; } static bool touchpad_finger_landing( const struct input_event *levt ) { return levt->type == EV_KEY && levt->code == BTN_TOUCH && levt->value == 1; } static bool touchpad_finger_leaving( const struct input_event *levt ) { return levt->type == EV_KEY && levt->code == BTN_TOUCH && levt->value == 0; } static bool touchpad_finger_moving( const struct input_event *levt ) { return levt->type == EV_ABS && (levt->code == ABS_X || levt->code == ABS_Y); } static int touchpad_fsm( struct touchpad_fsm_state *state, bool touch_abs, const struct input_event *levt, DFBInputEvent *devt ) { struct timeval levt_time; struct timeval timeout = { 0, 125000 }; if (!levt) { if (state->fsm_state == TOUCHPAD_FSM_DRAG_START) { devt->flags = DIEF_TIMESTAMP; devt->timestamp = state->timeout; devt->type = DIET_BUTTONRELEASE; devt->button = DIBI_FIRST; touchpad_fsm_init( state ); return 1; } timeout_clear( &state->timeout ); return 0; } levt_time.tv_sec = levt->input_event_sec; levt_time.tv_usec = levt->input_event_usec; if ((levt->type == EV_SYN && levt->code == SYN_REPORT) || (levt->type == EV_ABS && levt->code == ABS_PRESSURE) || (levt->type == EV_ABS && levt->code == ABS_TOOL_WIDTH) || (levt->type == EV_KEY && levt->code == BTN_TOOL_FINGER) || (levt->type == EV_KEY && levt->code == BTN_TOOL_DOUBLETAP) || (levt->type == EV_KEY && levt->code == BTN_TOOL_TRIPLETAP)) { if (state->fsm_state == TOUCHPAD_FSM_DRAG_START && timeout_passed( &state->timeout, &levt_time )) { devt->flags = DIEF_TIMESTAMP; devt->timestamp = state->timeout; devt->type = DIET_BUTTONRELEASE; devt->button = DIBI_FIRST; touchpad_fsm_init( state ); return 1; } return 0; } /* Use translate_event() for other events. */ if (!(levt->type == EV_KEY && levt->code == BTN_TOUCH) && !(levt->type == EV_ABS && (levt->code == ABS_X || levt->code == ABS_Y))) return -1; switch (state->fsm_state) { case TOUCHPAD_FSM_START: if (touchpad_finger_landing( levt )) { state->fsm_state = TOUCHPAD_FSM_MAIN; state->timeout = levt_time; timeout_add( &state->timeout, &timeout ); } return 0; case TOUCHPAD_FSM_MAIN: if (touchpad_finger_moving( levt )) { return touchpad_translate( state, touch_abs, levt, devt ); } else if (touchpad_finger_leaving( levt )) { if (!timeout_passed( &state->timeout, &levt_time )) { devt->flags = DIEF_TIMESTAMP; devt->timestamp = levt_time; devt->type = DIET_BUTTONPRESS; devt->button = DIBI_FIRST; touchpad_fsm_init( state ); state->fsm_state = TOUCHPAD_FSM_DRAG_START; state->timeout = levt_time; timeout_add( &state->timeout, &timeout ); return 1; } else { touchpad_fsm_init( state ); } } return 0; case TOUCHPAD_FSM_DRAG_START: if (timeout_passed( &state->timeout, &levt_time )) { devt->flags = DIEF_TIMESTAMP; devt->timestamp = state->timeout; devt->type = DIET_BUTTONRELEASE; devt->button = DIBI_FIRST; touchpad_fsm_init( state ); return 1; } else { if (touchpad_finger_landing( levt )) { state->fsm_state = TOUCHPAD_FSM_DRAG_MAIN; state->timeout = levt_time; timeout_add( &state->timeout, &timeout ); } } return 0; case TOUCHPAD_FSM_DRAG_MAIN: if (touchpad_finger_moving( levt )) { return touchpad_translate( state, touch_abs, levt, devt ); } else if (touchpad_finger_leaving( levt )) { devt->flags = DIEF_TIMESTAMP; devt->timestamp = levt_time; devt->type = DIET_BUTTONRELEASE; devt->button = DIBI_FIRST; touchpad_fsm_init( state ); return 1; } return 0; default: return 0; } return 0; } /**********************************************************************************************************************/ static DFBInputDeviceKeySymbol keyboard_get_symbol( int code, unsigned short value, DFBInputDeviceKeymapSymbolIndex level ) { unsigned char type = KTYP( value ); unsigned char index = KVAL( value ); int base = (level == DIKSI_BASE); switch (type) { case KT_FN: if (index < 20) return DFB_FUNCTION_KEY(index + 1); break; case KT_LETTER: case KT_LATIN: switch (index) { case 0x1c: return DIKS_PRINT; case 0x7f: return DIKS_BACKSPACE; case 0xa4: return 0x20ac; /* euro currency sign */ default: return index; } break; case KT_DEAD: switch (value) { case K_DGRAVE: return DIKS_DEAD_GRAVE; case K_DACUTE: return DIKS_DEAD_ACUTE; case K_DCIRCM: return DIKS_DEAD_CIRCUMFLEX; case K_DTILDE: return DIKS_DEAD_TILDE; case K_DDIERE: return DIKS_DEAD_DIAERESIS; case K_DCEDIL: return DIKS_DEAD_CEDILLA; default: break; } break; case KT_PAD: if (index <= 9 && level != DIKSI_BASE) return DIKS_0 + index; break; } switch (value) { case K_LEFT: return DIKS_CURSOR_LEFT; case K_RIGHT: return DIKS_CURSOR_RIGHT; case K_UP: return DIKS_CURSOR_UP; case K_DOWN: return DIKS_CURSOR_DOWN; case K_ENTER: return DIKS_ENTER; case K_CTRL: return DIKS_CONTROL; case K_SHIFT: return DIKS_SHIFT; case K_ALT: return DIKS_ALT; case K_ALTGR: return DIKS_ALTGR; case K_INSERT: return DIKS_INSERT; case K_REMOVE: return DIKS_DELETE; case K_FIND: return DIKS_HOME; case K_SELECT: return DIKS_END; case K_PGUP: return DIKS_PAGE_UP; case K_PGDN: return DIKS_PAGE_DOWN; case K_NUM: return DIKS_NUM_LOCK; case K_HOLD: return DIKS_SCROLL_LOCK; case K_PAUSE: return DIKS_PAUSE; case K_BREAK: return DIKS_BREAK; case K_CAPS: return DIKS_CAPS_LOCK; case K_P0: return DIKS_INSERT; case K_P1: return DIKS_END; case K_P2: return DIKS_CURSOR_DOWN; case K_P3: return DIKS_PAGE_DOWN; case K_P4: return DIKS_CURSOR_LEFT; case K_P5: return DIKS_BEGIN; case K_P6: return DIKS_CURSOR_RIGHT; case K_P7: return DIKS_HOME; case K_P8: return DIKS_CURSOR_UP; case K_P9: return DIKS_PAGE_UP; case K_PPLUS: return DIKS_PLUS_SIGN; case K_PMINUS: return DIKS_MINUS_SIGN; case K_PSTAR: return DIKS_ASTERISK; case K_PSLASH: return DIKS_SLASH; case K_PENTER: return DIKS_ENTER; case K_PCOMMA: return base ? DIKS_DELETE : DIKS_COMMA; case K_PDOT: return base ? DIKS_DELETE : DIKS_PERIOD; case K_PPARENL: return DIKS_PARENTHESIS_LEFT; case K_PPARENR: return DIKS_PARENTHESIS_RIGHT; } /* Special keys not in the map. */ if (code == 99) /* print key */ return DIKS_PRINT; if (code == 124) /* keypad equal key */ return DIKS_EQUALS_SIGN; if (code == 125) /* left windows key */ return DIKS_META; if (code == 126) /* right windows key */ return DIKS_META; if (code == 127) /* context menu key */ return DIKS_SUPER; return DIKS_NULL; } static DFBInputDeviceKeyIdentifier keyboard_get_identifier( int code, unsigned short value ) { unsigned char type = KTYP( value ); unsigned char index = KVAL( value ); if (type == KT_PAD) { if (index <= 9) return DIKI_KP_0 + index; switch (value) { case K_PSLASH: return DIKI_KP_DIV; case K_PSTAR: return DIKI_KP_MULT; case K_PMINUS: return DIKI_KP_MINUS; case K_PPLUS: return DIKI_KP_PLUS; case K_PENTER: return DIKI_KP_ENTER; case K_PCOMMA: case K_PDOT: return DIKI_KP_DECIMAL; } } switch (code) { case 12: return DIKI_MINUS_SIGN; case 13: return DIKI_EQUALS_SIGN; case 26: return DIKI_BRACKET_LEFT; case 27: return DIKI_BRACKET_RIGHT; case 39: return DIKI_SEMICOLON; case 40: return DIKI_QUOTE_RIGHT; case 41: return DIKI_QUOTE_LEFT; case 43: return DIKI_BACKSLASH; case 51: return DIKI_COMMA; case 52: return DIKI_PERIOD; case 53: return DIKI_SLASH; case 54: return DIKI_SHIFT_R; case 97: return DIKI_CONTROL_R; case 100: return DIKI_ALT_R; case 124: return DIKI_KP_EQUAL; case 125: return DIKI_META_L; case 126: return DIKI_META_R; case 127: return DIKI_SUPER_R; } return DIKI_UNKNOWN; } static unsigned short keyboard_read_value( const LinuxInputData *data, unsigned char table, unsigned char index ) { struct kbentry entry; entry.kb_table = table; entry.kb_index = index; entry.kb_value = 0; if (ioctl( data->vt_fd, KDGKBENT, &entry )) { D_PERROR( "Input/Linux: KDGKBENT( table %d, index %d ) failed!\n", table, index ); return 0; } return entry.kb_value; } /**********************************************************************************************************************/ /* * Translate a Linux input keycode into a DirectFB keycode. */ static int key_translate( unsigned short code ) { if (code < D_ARRAY_SIZE(basic_keycodes)) return basic_keycodes[code]; if (code >= KEY_OK) if (code - KEY_OK < D_ARRAY_SIZE(ext_keycodes)) return ext_keycodes[code-KEY_OK]; return DIKI_UNKNOWN; } /* * Translate key and button events. */ static bool key_event( const struct input_event *levt, DFBInputEvent *devt ) { int code = levt->code; /* Map touchscreen events to button mouse. */ if (code == BTN_TOUCH || code == BTN_TOOL_FINGER) code = BTN_MOUSE; if ((code >= BTN_MOUSE && code < BTN_JOYSTICK) || code == BTN_TOUCH) { /* Ignore repeat events for buttons. */ if (levt->value == 2) return false; devt->type = levt->value ? DIET_BUTTONPRESS : DIET_BUTTONRELEASE; devt->button = DIBI_FIRST + code - BTN_MOUSE; } else { int key = key_translate( code ); if (key == DIKI_UNKNOWN) return false; devt->type = levt->value ? DIET_KEYPRESS : DIET_KEYRELEASE; if (DFB_KEY_TYPE( key ) == DIKT_IDENTIFIER) { devt->key_id = key; devt->flags |= DIEF_KEYID; } else { devt->key_symbol = key; devt->flags |= DIEF_KEYSYMBOL; } devt->key_code = code; devt->flags |= DIEF_KEYCODE; } if (levt->value == 2) devt->flags |= DIEF_REPEAT; return true; } /* * Translate relative axis events. */ static bool rel_event( const LinuxInputData *data, const struct input_event *levt, DFBInputEvent *devt ) { switch (levt->code) { case REL_X: devt->axis = DIAI_X; devt->axisrel = levt->value * data->sensitivity / 0x100; break; case REL_Y: devt->axis = DIAI_Y; devt->axisrel = levt->value * data->sensitivity / 0x100; break; case REL_Z: case REL_WHEEL: devt->axis = DIAI_Z; devt->axisrel = -levt->value; break; default: if (levt->code > REL_MAX || levt->code > DIAI_LAST) return false; devt->axis = levt->code; devt->axisrel = levt->value; } devt->type = DIET_AXISMOTION; devt->flags |= DIEF_AXISREL; return true; } /* * Translate absolute axis events. */ static bool abs_event( const struct input_event *levt, DFBInputEvent *devt ) { switch (levt->code) { case ABS_X: devt->axis = DIAI_X; break; case ABS_Y: devt->axis = DIAI_Y; break; case ABS_Z: case ABS_WHEEL: devt->axis = DIAI_Z; break; default: if (levt->code >= ABS_PRESSURE || levt->code > DIAI_LAST) return false; devt->axis = levt->code; } devt->type = DIET_AXISMOTION; devt->flags |= DIEF_AXISABS; devt->axisabs = levt->value; return true; } /* * Translate a Linux input event into a DirectFB input event. */ static bool translate_event( const LinuxInputData *data, const struct input_event *levt, DFBInputEvent *devt ) { devt->flags = DIEF_TIMESTAMP; devt->timestamp.tv_sec = levt->input_event_sec; devt->timestamp.tv_usec = levt->input_event_usec; switch (levt->type) { case EV_KEY: return key_event( levt, devt ); case EV_REL: return rel_event( data, levt, devt ); case EV_ABS: return abs_event( levt, devt ); default: ; } return false; } /**********************************************************************************************************************/ static void set_led( const LinuxInputData *data, int led, int state ) { struct input_event levt; int res; D_UNUSED_P( res ); memset( &levt, 0, sizeof(levt) ); levt.type = EV_LED; levt.code = led; levt.value = state; res = write( data->fd, &levt, sizeof(levt) ); } static void flush_xy( LinuxInputData *data, bool last ) { DFBInputEvent devt = { .type = DIET_UNKNOWN }; if (data->dx) { devt.type = DIET_AXISMOTION; devt.flags = DIEF_AXISREL; devt.axis = DIAI_X; devt.axisrel = data->dx; /* Signal immediately following event. */ if (!last || data->dy) devt.flags |= DIEF_FOLLOW; dfb_input_dispatch( data->device, &devt ); data->dx = 0; } if (data->dy) { devt.type = DIET_AXISMOTION; devt.flags = DIEF_AXISREL; devt.axis = DIAI_Y; devt.axisrel = data->dy; /* Signal immediately following event. */ if (!last) devt.flags |= DIEF_FOLLOW; dfb_input_dispatch( data->device, &devt ); data->dy = 0; } } /**********************************************************************************************************************/ static void * devinput_event_thread( DirectThread *thread, void *arg ) { LinuxInputData *data = arg; int status; int fdmax; unsigned int i; bool mouse_motion_compression; struct touchpad_fsm_state fsm_state; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); /* Mouse motion event compression. */ if (direct_config_has_name( "motion-compression" ) && !direct_config_has_name( "no-motion-compression" )) mouse_motion_compression = true; else mouse_motion_compression = false; fdmax = MAX( data->fd, data->quitpipe[0] ); /* Query the touchpad min/max coordinates. */ if (data->touchpad) { struct input_absinfo absinfo; touchpad_fsm_init( &fsm_state ); ioctl( data->fd, EVIOCGABS( ABS_X ), &absinfo ); fsm_state.x.min = absinfo.minimum; fsm_state.x.max = absinfo.maximum; ioctl( data->fd, EVIOCGABS( ABS_Y ), &absinfo ); fsm_state.y.min = absinfo.minimum; fsm_state.y.max = absinfo.maximum; } /* Query the keys. */ if (data->has_keys) { unsigned long keybit[NBITS(KEY_CNT)]; unsigned long keystate[NBITS(KEY_CNT)]; /* Get key bits. */ ioctl( data->fd, EVIOCGBIT( EV_KEY, sizeof(keybit) ), keybit ); /* Get key states. */ ioctl( data->fd, EVIOCGKEY( sizeof(keystate) ), keystate ); /* For each key, synthetize a press or release event depending on the key state. */ for (i = 0; i <= KEY_CNT; i++) { if (test_bit( i, keybit )) { const int key = key_translate( i ); if (DFB_KEY_TYPE( key ) == DIKT_IDENTIFIER) { DFBInputEvent devt; devt.type = test_bit( i, keystate ) ? DIET_KEYPRESS : DIET_KEYRELEASE; devt.flags = DIEF_KEYID | DIEF_KEYCODE; devt.key_id = key; devt.key_code = i; dfb_input_dispatch( data->device, &devt ); } } } } while (1) { DFBInputEvent devt = { .type = DIET_UNKNOWN }; fd_set set; ssize_t len; /* Get input event. */ FD_ZERO( &set ); FD_SET( data->fd, &set ); FD_SET( data->quitpipe[0], &set ); if (data->touchpad && timeout_is_set( &fsm_state.timeout )) { struct timeval time; gettimeofday( &time, NULL ); if (!timeout_passed( &fsm_state.timeout, &time )) { struct timeval timeout = fsm_state.timeout; timeout_sub( &timeout, &time ); status = select( fdmax + 1, &set, NULL, NULL, &timeout ); } else status = 0; } else status = select( fdmax + 1, &set, NULL, NULL, NULL ); if (status < 0 && errno != EINTR) break; if (status > 0 && FD_ISSET( data->quitpipe[0], &set )) break; if (status < 0) continue; /* Check timeout. */ if (status == 0) { if (data->touchpad && touchpad_fsm( &fsm_state, data->touch_abs, NULL, &devt ) > 0) dfb_input_dispatch( data->device, &devt ); continue; } len = read( data->fd, input_events, sizeof(input_events) ); if (len < 0 && errno != EINTR) break; if (len <= 0) continue; for (i = 0; i < len / sizeof(input_events[0]); i++) { DFBInputEvent evt = { .type = DIET_UNKNOWN }; if (data->touchpad) { status = touchpad_fsm( &fsm_state, data->touch_abs, &input_events[i], &evt ); if (status < 0) { /* Not handled. Try the direct approach. */ if (!translate_event( data, &input_events[i], &evt )) continue; } else if (status == 0) { /* Handled but no further processing is necessary. */ continue; } } else { if (!translate_event( data, &input_events[i], &evt )) continue; } /* Flush previous event with DIEF_FOLLOW. */ if (devt.type != DIET_UNKNOWN) { flush_xy( data, false ); /* Signal immediately following event. */ devt.flags |= DIEF_FOLLOW; dfb_input_dispatch( data->device, &devt ); if (data->has_leds && (devt.locks != data->locks)) { set_led( data, LED_SCROLLL, devt.locks & DILS_SCROLL ); set_led( data, LED_NUML, devt.locks & DILS_NUM ); set_led( data, LED_CAPSL, devt.locks & DILS_CAPS ); data->locks = devt.locks; } devt.type = DIET_UNKNOWN; devt.flags = DIEF_NONE; } devt = evt; if (D_FLAGS_IS_SET( devt.flags, DIEF_AXISREL ) && devt.type == DIET_AXISMOTION && mouse_motion_compression) { switch (devt.axis) { case DIAI_X: data->dx += devt.axisrel; continue; case DIAI_Y: data->dy += devt.axisrel; continue; default: break; } } } /* Flush last event without DIEF_FOLLOW. */ if (devt.type != DIET_UNKNOWN) { flush_xy( data, false ); /* Event is dispatched. */ dfb_input_dispatch( data->device, &devt ); if (data->has_leds && (devt.locks != data->locks)) { set_led( data, LED_SCROLLL, devt.locks & DILS_SCROLL ); set_led( data, LED_NUML, devt.locks & DILS_NUM ); set_led( data, LED_CAPSL, devt.locks & DILS_CAPS ); data->locks = devt.locks; } } else flush_xy( data, true ); } D_DEBUG_AT( Linux_Input, "DevInput Event thread terminated\n" ); return NULL; } static void get_device_info( int fd, InputDeviceInfo *device_info, bool *touchpad ) { int i; unsigned int num_keys = 0; unsigned int num_ext_keys = 0; unsigned int num_buttons = 0; unsigned int num_rels = 0; unsigned int num_abs = 0; unsigned long evbit[NBITS(EV_CNT)]; unsigned long keybit[NBITS(KEY_CNT)]; unsigned long relbit[NBITS(REL_CNT)]; unsigned long absbit[NBITS(ABS_CNT)]; struct input_id devinfo; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); /* Get device name. */ ioctl( fd, EVIOCGNAME( DFB_INPUT_DEVICE_DESC_NAME_LENGTH - 1 ), device_info->desc.name ); D_DEBUG_AT( Linux_Input, " -> name '%s'\n", device_info->desc.name ); /* Set device vendor. */ snprintf( device_info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "Linux" ); /* Get event type bits. */ ioctl( fd, EVIOCGBIT( 0, sizeof(evbit) ), evbit ); if (test_bit( EV_KEY, evbit )) { /* Get keyboard bits. */ ioctl( fd, EVIOCGBIT( EV_KEY, sizeof(keybit) ), keybit ); /* Count typical keyboard keys only. */ for (i = KEY_Q; i <= KEY_M; i++) if (test_bit( i, keybit )) num_keys++; /* This might be a keyboard with just cursor keys (typically on front panels), handle as remote control. */ if (!num_keys) for (i = KEY_HOME; i <= KEY_PAGEDOWN; i++) if (test_bit( i, keybit )) num_ext_keys++; for (i = KEY_OK; i < KEY_CNT; i++) if (test_bit( i, keybit )) num_ext_keys++; for (i = BTN_MOUSE; i < BTN_JOYSTICK; i++) if (test_bit( i, keybit )) num_buttons++; if (num_keys || num_ext_keys) device_info->desc.caps |= DICAPS_KEYS; } if (test_bit( EV_REL, evbit )) { /* Get bits for relative axes. */ ioctl( fd, EVIOCGBIT( EV_REL, sizeof(relbit) ), relbit ); for (i = 0; i < REL_CNT; i++) if (test_bit( i, relbit )) num_rels++; } if (test_bit( EV_ABS, evbit )) { /* Get bits for absolute axes. */ ioctl( fd, EVIOCGBIT( EV_ABS, sizeof(absbit) ), absbit ); for (i = 0; i < ABS_PRESSURE; i++) if (test_bit( i, absbit )) num_abs++; } /* Touchpad */ if (test_bit( EV_KEY, evbit ) && test_bit( BTN_TOUCH, keybit ) && test_bit( BTN_TOOL_FINGER, keybit) && test_bit( EV_ABS, evbit ) && test_bit( ABS_X, absbit ) && test_bit( ABS_Y, absbit ) && test_bit( ABS_PRESSURE, absbit )) *touchpad = true; else *touchpad = false; /* Mouse, Touchscreen or Joystick */ if ((test_bit( EV_KEY, evbit ) && (test_bit( BTN_TOUCH, keybit ) || test_bit( BTN_TOOL_FINGER, keybit ))) || ((num_rels >= 2 && num_buttons) || (num_abs == 2 && num_buttons == 1))) device_info->desc.type |= DIDTF_MOUSE; else if (num_abs && num_buttons) device_info->desc.type |= DIDTF_JOYSTICK; /* Keyboard */ if (num_keys > 20) { device_info->desc.type |= DIDTF_KEYBOARD; device_info->desc.min_keycode = 0; device_info->desc.max_keycode = 127; } /* Remote Control */ if (num_ext_keys) { device_info->desc.type |= DIDTF_REMOTE; } /* Buttons */ if (num_buttons) { device_info->desc.caps |= DICAPS_BUTTONS; device_info->desc.max_button = DIBI_FIRST + num_buttons - 1; } /* Axes */ if (num_rels || num_abs) { device_info->desc.caps |= DICAPS_AXES; device_info->desc.max_axis = DIAI_FIRST + MAX( num_rels, num_abs ) - 1; } /* Primary input device */ if (device_info->desc.type & DIDTF_KEYBOARD) device_info->prefered_id = DIDID_KEYBOARD; else if (device_info->desc.type & DIDTF_REMOTE) device_info->prefered_id = DIDID_REMOTE; else if (device_info->desc.type & DIDTF_JOYSTICK) device_info->prefered_id = DIDID_JOYSTICK; else if (device_info->desc.type & DIDTF_MOUSE) device_info->prefered_id = DIDID_MOUSE; else device_info->prefered_id = DIDID_ANY; /* Get VID and PID information. */ ioctl( fd, EVIOCGID, &devinfo ); device_info->desc.vendor_id = devinfo.vendor; device_info->desc.product_id = devinfo.product; D_DEBUG_AT( Linux_Input, " -> ids %d/%d\n", device_info->desc.vendor_id, device_info->desc.product_id ); } static bool check_device( const char *device ) { int err; int fd; InputDeviceInfo device_info; bool touchpad; bool linux_input_grab; bool linux_input_ir_only; D_DEBUG_AT( Linux_Input, "%s( '%s' )\n", __FUNCTION__, device ); /* Check if we are able to open the device. */ fd = open( device, O_RDWR ); if (fd < 0) { D_DEBUG_AT( Linux_Input, " -> open failed!\n" ); return false; } /* Grab device. */ if (direct_config_has_name( "linux-input-grab" ) && !direct_config_has_name( "no-linux-input-grab" )) linux_input_grab = true; else linux_input_grab = false; /* Ignore non-IR device. */ if (direct_config_has_name( "linux-input-ir-only" ) && !direct_config_has_name( "no-linux-input-ir-only" )) linux_input_ir_only = true; else linux_input_ir_only = false; if (linux_input_grab) { err = ioctl( fd, EVIOCGRAB, 1 ); if (err) { D_PERROR( "Input/Linux: Could not grab device!\n" ); close( fd ); return false; } } /* Get device information. */ memset( &device_info, 0, sizeof(InputDeviceInfo) ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; get_device_info( fd, &device_info, &touchpad ); if (linux_input_grab) ioctl( fd, EVIOCGRAB, 0 ); close( fd ); if (!device_info.desc.caps) { D_DEBUG_AT( Linux_Input, " -> no caps!\n" ); return false; } if (!linux_input_ir_only || (device_info.desc.type & DIDTF_REMOTE)) return true; return false; } /**********************************************************************************************************************/ static int driver_get_available() { const char *value; FusionVector linux_input_devices; int i; char *skipdev; char buf[32]; if (num_devices) { for (i = 0; i < num_devices; i++) { D_FREE( device_names[i] ); device_names[i] = NULL; } num_devices = 0; return 0; } /* Use the devices specified in the configuration. */ if ((value = direct_config_get_value( "linux-input-devices" ))) { const char *device; fusion_vector_init( &linux_input_devices, 2, NULL ); config_values_parse( &linux_input_devices, value ); fusion_vector_foreach (device, i, linux_input_devices) { if (num_devices >= MAX_LINUX_INPUT_DEVICES) break; /* Update the device_names and device_nums array entries too. */ if (check_device( device )) { D_ASSERT( device_names[num_devices] == NULL ); device_names[num_devices] = D_STRDUP( device ); device_nums[num_devices] = i; num_devices++; } } config_values_free( &linux_input_devices ); return num_devices; } /* No devices specified. Try to guess some, set SKIP_INPUT_DEVICE to skip checking the specified input device. */ skipdev = getenv( "SKIP_INPUT_DEVICE" ); for (i = 0; i < MAX_LINUX_INPUT_DEVICES; i++) { snprintf( buf, sizeof(buf), "/dev/input/event%d", i ); /* Initialize device_names and device_nums array entries. */ device_names[i] = NULL; device_nums[i] = MAX_LINUX_INPUT_DEVICES; if (skipdev && !strcmp( skipdev, buf )) continue; /* Update the device_names and device_nums array entries too. */ if (check_device( buf )) { D_ASSERT( device_names[num_devices] == NULL ); device_names[num_devices] = D_STRDUP( buf ); device_nums[num_devices] = i; num_devices++; } } return num_devices; } static void driver_get_info( InputDriverInfo *driver_info ) { driver_info->version.major = 0; driver_info->version.minor = 1; snprintf( driver_info->name, DFB_INPUT_DRIVER_INFO_NAME_LENGTH, "Linux Input" ); snprintf( driver_info->vendor, DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH, "DirectFB" ); } static DFBResult driver_open_device( CoreInputDevice *device, unsigned int number, InputDeviceInfo *device_info, void **driver_data ) { LinuxInputData *data; int err; int fd; bool linux_input_grab; unsigned long ledbit[NBITS(LED_CNT)]; bool touchpad; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); /* Open device. */ fd = open( device_names[number], O_RDWR ); if (fd < 0) { D_PERROR( "Input/Linux: Could not open device '%s'!\n", device_names[number] ); return DFB_INIT; } /* Grab device. */ if (direct_config_has_name( "linux-input-grab" ) && !direct_config_has_name( "no-linux-input-grab" )) linux_input_grab = true; else linux_input_grab = false; if (linux_input_grab) { err = ioctl( fd, EVIOCGRAB, 1 ); if (err) { D_PERROR( "Input/Linux: Could not grab device!\n" ); close( fd ); return DFB_INIT; } } /* Fill device information. */ get_device_info( fd, device_info, &touchpad ); /* Allocate and fill private data. */ data = D_CALLOC( 1, sizeof(LinuxInputData) ); if (!data) { if (linux_input_grab) ioctl( fd, EVIOCGRAB, 0 ); close( fd ); return D_OOM(); } data->device = device; data->index = number; data->fd = fd; data->grab = linux_input_grab; data->has_keys = (device_info->desc.caps & DICAPS_KEYS) != 0; /* Check if the device has LEDs. */ err = ioctl( fd, EVIOCGBIT( EV_LED, sizeof(ledbit) ), ledbit ); if (err < 0) D_PERROR( "Input/Linux: Could not get LEDs bits!" ); else data->has_leds = test_bit( LED_SCROLLL, ledbit ) || test_bit( LED_NUML, ledbit ) || test_bit( LED_CAPSL, ledbit ); if (data->has_leds) { /* Get LEDs state. */ err = ioctl( fd, EVIOCGLED( sizeof(data->led_state) ), data->led_state ); if (err < 0) { D_PERROR( "Input/Linux: Could not get LEDs state!" ); goto error; } /* Turn off LEDs. */ set_led( data, LED_SCROLLL, 0 ); set_led( data, LED_NUML, 0 ); set_led( data, LED_CAPSL, 0 ); } data->touchpad = touchpad; if (data->touchpad) { if (direct_config_has_name( "linux-input-touch-abs" ) && !direct_config_has_name( "no-linux-input-touch-abs" )) data->touch_abs = true; } data->sensitivity = 0x100; if (device_info->desc.min_keycode >= 0 && device_info->desc.max_keycode > device_info->desc.min_keycode) { data->vt_fd = open( "/dev/tty0", O_RDWR | O_NOCTTY ); if (data->vt_fd < 0) D_WARN( "no keymap support" ); } /* Open a pipe to awake the devinput event thread when we want to quit. */ err = pipe( data->quitpipe ); if (err < 0) { D_PERROR( "Input/Linux: Could not open quit pipe!" ); goto error; } /* Start devinput event thread. */ data->thread = direct_thread_create( DTT_INPUT, devinput_event_thread, data, "DevInput Event" ); *driver_data = data; return DFB_OK; error: if (data->grab) ioctl( fd, EVIOCGRAB, 0 ); if (data->vt_fd >= 0) close( data->vt_fd ); close( fd ); D_FREE( data ); return DFB_INIT; } static DFBResult driver_get_keymap_entry( CoreInputDevice *device, void *driver_data, DFBInputDeviceKeymapEntry *entry ) { LinuxInputData *data = driver_data; int orig_mode; int code = entry->code; unsigned short value; DFBInputDeviceKeyIdentifier identifier; if (data->vt_fd < 0) return DFB_UNSUPPORTED; /* Save keyboard mode in order to restore it later. */ if (ioctl( data->vt_fd, KDGKBMODE, &orig_mode ) < 0) { D_PERROR( "Input/Linux: KDGKBMODE failed!\n" ); return DFB_INIT; } /* Switch to unicode mode to get the full keymap. */ if (ioctl( data->vt_fd, KDSKBMODE, K_UNICODE ) < 0) { D_PERROR( "Input/Linux: K_UNICODE failed!\n" ); return DFB_INIT; } /* Fetch the base level. */ value = keyboard_read_value( driver_data, K_NORMTAB, code ); /* Get the identifier for basic mapping. */ identifier = keyboard_get_identifier( code, value ); /* CapsLock is effective. */ if (KTYP( value ) == KT_LETTER) entry->locks |= DILS_CAPS; /* NumLock is effective. */ if (identifier >= DIKI_KP_DECIMAL && identifier <= DIKI_KP_9) entry->locks |= DILS_NUM; /* Write identifier to entry. */ entry->identifier = identifier; /* Write base level symbol to entry. */ entry->symbols[DIKSI_BASE] = keyboard_get_symbol( code, value, DIKSI_BASE ); /* Fetch the shifted base level. */ value = keyboard_read_value( driver_data, K_SHIFTTAB, entry->code ); /* Write shifted base level symbol to entry. */ entry->symbols[DIKSI_BASE_SHIFT] = keyboard_get_symbol( code, value, DIKSI_BASE_SHIFT ); /* Fetch the alternative level. */ value = keyboard_read_value( driver_data, K_ALTTAB, entry->code ); /* Write alternative level symbol to entry. */ entry->symbols[DIKSI_ALT] = keyboard_get_symbol( code, value, DIKSI_ALT ); /* Fetch the shifted alternative level. */ value = keyboard_read_value( driver_data, K_ALTSHIFTTAB, entry->code ); /* Write shifted alternative level symbol to entry. */ entry->symbols[DIKSI_ALT_SHIFT] = keyboard_get_symbol( code, value, DIKSI_ALT_SHIFT ); /* Switch back to original keyboard mode. */ if (ioctl( data->vt_fd, KDSKBMODE, orig_mode ) < 0) { D_PERROR( "Input/Linux: KDSKBMODE failed!\n" ); return DFB_INIT; } return DFB_OK; } static void driver_close_device( void *driver_data ) { LinuxInputData *data = driver_data; ssize_t res; D_UNUSED_P( res ); D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( data != NULL ); /* Write to the quit pipe to terminate the devinput event thread. */ res = write( data->quitpipe[1], " ", 1 ); direct_thread_join( data->thread ); direct_thread_destroy( data->thread ); close( data->quitpipe[0] ); close( data->quitpipe[1] ); /* Restore LEDs state. */ if (data->has_leds) { set_led( data, LED_SCROLLL, test_bit( LED_SCROLLL, data->led_state ) ); set_led( data, LED_NUML, test_bit( LED_NUML, data->led_state ) ); set_led( data, LED_CAPSL, test_bit( LED_CAPSL, data->led_state ) ); } if (data->grab) ioctl( data->fd, EVIOCGRAB, 0 ); if (data->vt_fd >= 0) close( data->vt_fd ); close( data->fd ); D_FREE( data ); } #if DIRECT_BUILD_NETWORK /********************************************************************************************************************** ********************************* Hot-plug functions ***************************************************************** **********************************************************************************************************************/ typedef struct { CoreDFB *core; void *driver; } HotplugThreadData; /* Socket file descriptor for getting udev events. */ static int socket_fd = 0; /* Thread for managing devinput hot-plug. */ static DirectThread *hotplug_thread = NULL; /* Pipe file descriptor for terminating the devinput hot-plug thread. */ static int hotplug_quitpipe[2]; /* Mutex for handling the driver suspended. */ static pthread_mutex_t driver_suspended_lock; /* Flag for indicating that the driver is suspended. */ static bool driver_suspended = false; /* * Register /dev/input/eventX device node into the driver. Called when a new device node is created. */ static DFBResult register_device_node( int event_num, int *index ) { int i; char buf[32]; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( index != NULL ); for (i = 0; i < MAX_LINUX_INPUT_DEVICES; i++) { if (device_nums[i] == MAX_LINUX_INPUT_DEVICES) { device_nums[i] = event_num; *index = i; num_devices++; snprintf( buf, sizeof(buf), "/dev/input/event%d", event_num ); D_ASSERT( device_names[i] == NULL ); device_names[i] = D_STRDUP( buf ); return DFB_OK; } } /* Too many input devices plugged in to be handled. */ D_DEBUG_AT( Linux_Input, " -> the amount of devices registered exceeds the limit %d\n", MAX_LINUX_INPUT_DEVICES ); return DFB_UNSUPPORTED; } /* * Unregister /dev/input/eventX device node from the driver. Called when a new device node is removed. */ static DFBResult unregister_device_node( int event_num, int *index ) { int i; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( index != NULL ); for (i = 0; i < num_devices; i++) { if (device_nums[i] == event_num) { device_nums[i] = MAX_LINUX_INPUT_DEVICES; num_devices--; *index = i; D_FREE( device_names[i] ); device_names[i] = NULL; return DFB_OK; } } return DFB_UNSUPPORTED; } static void * devinput_hotplug_thread( DirectThread *thread, void *arg ) { HotplugThreadData *data = arg; int status; int fdmax; struct sockaddr_un sock_addr; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( data != NULL ); D_ASSERT( data->core != NULL ); D_ASSERT( data->driver != NULL ); /* Open and bind the socket /org/kernel/udev/monitor */ socket_fd = socket( AF_UNIX, SOCK_DGRAM, 0 ); if (socket_fd == -1) goto error; memset( &sock_addr, 0, sizeof(sock_addr) ); sock_addr.sun_family = AF_UNIX; strncpy( &sock_addr.sun_path[1], "/org/kernel/udev/monitor", sizeof(sock_addr.sun_path) - 1 ); status = bind( socket_fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr.sun_family) + 1 + strlen( &sock_addr.sun_path[1] ) ); if (status < 0) goto error; fdmax = MAX( socket_fd, hotplug_quitpipe[0] ); while (1) { DFBResult ret; fd_set set; char udev_event[1024]; ssize_t len; char *pos; char *event_content; int device_num, index; /* Get udev event. */ FD_ZERO( &set ); FD_SET( socket_fd, &set ); FD_SET( hotplug_quitpipe[0], &set ); status = select( fdmax + 1, &set, NULL, NULL, NULL ); if (status < 0 && errno != EINTR) break; if (FD_ISSET( hotplug_quitpipe[0], &set )) break; if (FD_ISSET( socket_fd, &set )) { len = recv( socket_fd, udev_event, sizeof(udev_event), 0 ); if (len <= 0) { D_DEBUG_AT( Linux_Input, "Error receiving uevent message\n" ); continue; } } /* Analyze udev event. */ pos = strchr( udev_event, '@' ); if (pos == NULL) continue; /* Replace '@' with '\0' to separate event type and event content. */ *pos = '\0'; event_content = pos + 1; pos = strstr( event_content, "/event" ); if (pos == NULL) continue; /* Get input device number. */ device_num = atoi( pos + 6 ); /* Attempt to lock the driver suspended mutex. */ pthread_mutex_lock( &driver_suspended_lock ); if (driver_suspended) { /* Release the lock and stop udev event handling. */ D_DEBUG_AT( Linux_Input, "Driver is suspended, no udev processing\n" ); pthread_mutex_unlock( &driver_suspended_lock ); continue; } /* Handle udev event since the driver is not suspended. */ if (!strcmp( udev_event, "add" )) { D_DEBUG_AT( Linux_Input, "Device node /dev/input/event%d is created by udev\n", device_num ); ret = register_device_node( device_num, &index ); if (ret == DFB_OK) { /* Handle the input device node creation. */ ret = dfb_input_create_device( index, data->core, data->driver ); if (ret != DFB_OK) { D_DEBUG_AT( Linux_Input, "Failed to create the device for /dev/input/event%d\n", device_num ); } } } else if (!strcmp( udev_event, "remove" )) { D_DEBUG_AT( Linux_Input, "Device node /dev/input/event%d is removed by udev\n", device_num ); ret = unregister_device_node( device_num, &index ); if (ret == DFB_OK) { /* Handle the input device node removal. */ ret = dfb_input_remove_device( index, data->driver ); if (ret != DFB_OK) { D_DEBUG_AT( Linux_Input, "Failed to remove the device for /dev/input/event%d\n", device_num ); } } } /* udev event handling is complete so release the lock. */ pthread_mutex_unlock( &driver_suspended_lock ); } D_FREE( data ); D_DEBUG_AT( Linux_Input, "DevInput Hotplug thread terminated\n" ); return NULL; error: D_DEBUG_AT( Linux_Input, "Failed to open/bind udev socket\n" ); if (socket_fd > 0) { close( socket_fd ); socket_fd = 0; } return NULL; } static DFBResult driver_suspend() { D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); if (pthread_mutex_lock( &driver_suspended_lock )) return DFB_FAILURE; /* Enter the suspended state by setting the driver_suspended flag to prevent handling of hot-plug events. */ driver_suspended = true; pthread_mutex_unlock( &driver_suspended_lock ); return DFB_OK; } static DFBResult driver_resume() { D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); if (pthread_mutex_lock( &driver_suspended_lock) ) return DFB_FAILURE; /* Leave the suspended state by clearing the driver_suspended flag which will allow hot-plug events to be handled again. */ driver_suspended = false; pthread_mutex_unlock( &driver_suspended_lock ); return DFB_OK; } static DFBResult is_created( int index, void *driver_data ) { LinuxInputData *data = driver_data; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( data != NULL ); if (index < 0 || index >= MAX_LINUX_INPUT_DEVICES) { return DFB_UNSUPPORTED; } /* Check if the index is associated with an entry in the device_nums and device_names arrays. */ if (index != data->index) { return DFB_UNSUPPORTED; } return DFB_OK; } static InputDriverCapability get_capability() { InputDriverCapability capabilities = IDC_NONE; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( Linux_Input, " -> returning HOTPLUG\n" ); capabilities |= IDC_HOTPLUG; return capabilities; } static DFBResult launch_hotplug( CoreDFB *core, void *input_driver ) { DFBResult ret; HotplugThreadData *data; int err; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( core != NULL ); D_ASSERT( input_driver != NULL ); D_ASSERT( hotplug_thread == NULL ); data = D_CALLOC( 1, sizeof(HotplugThreadData) ); if (!data) { ret = D_OOM(); goto error; } data->core = core; data->driver = input_driver; /* Open a pipe to awake the devinput hot-plug thread when we want to quit. */ err = pipe( hotplug_quitpipe ); if (err < 0) { D_PERROR( "Input/Linux: Could not open quit pipe for hot-plug!" ); D_FREE( data ); ret = DFB_INIT; goto error; } /* Initialize a mutex used to communicate with the devinput hot-plug thread when the driver is suspended. */ pthread_mutex_init( &driver_suspended_lock, NULL ); /* Start devinput hot-plug thread. */ hotplug_thread = direct_thread_create( DTT_INPUT, devinput_hotplug_thread, data, "DevInput Hotplug" ); if (!hotplug_thread) { pthread_mutex_destroy( &driver_suspended_lock ); D_FREE( data ); ret = DFB_UNSUPPORTED; goto error; } D_DEBUG_AT( Linux_Input, " -> hot-plug detection enabled\n" ); return DFB_OK; error: D_DEBUG_AT( Linux_Input, " -> failed to enable hot-plug detection\n" ); return ret; } static DFBResult stop_hotplug() { int err; ssize_t res; D_UNUSED_P( res ); D_ASSERT( hotplug_thread != NULL ); D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); /* The devinput hot-plug thread is not created. */ if (!hotplug_thread) return DFB_OK; /* Write to the hot-plug quit pipe to terminate the devinput hot-plug thread. */ res = write( hotplug_quitpipe[1], " ", 1 ); direct_thread_join( hotplug_thread ); direct_thread_destroy( hotplug_thread ); close( hotplug_quitpipe[0] ); close( hotplug_quitpipe[1] ); hotplug_thread = NULL; /* Destroy the suspended mutex. */ pthread_mutex_destroy( &driver_suspended_lock ); /* Shutdown the connection of the socket. */ if (socket_fd > 0) { err = shutdown( socket_fd, SHUT_RDWR ); if (err < 0) { D_PERROR( "Input/Linux: Failed to shutdown socket!\n" ); return DFB_FAILURE; } close( socket_fd ); socket_fd = 0; } return DFB_OK; } #endif /* DIRECT_BUILD_NETWORK */ /********************************************************************************************************************** ********************************* Axis info function ***************************************************************** **********************************************************************************************************************/ static DFBResult driver_get_axis_info( CoreInputDevice *device, void *driver_data, DFBInputDeviceAxisIdentifier axis, InputDeviceAxisInfo *ret_info ) { LinuxInputData *data = driver_data; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); if (data->touchpad && !data->touch_abs) return DFB_OK; if (axis <= ABS_PRESSURE && axis < DIAI_LAST) { unsigned long absbit[NBITS(ABS_CNT)]; /* Check if we have an absolute axis. */ ioctl( data->fd, EVIOCGBIT( EV_ABS, sizeof(absbit) ), absbit ); if (test_bit( axis, absbit )) { struct input_absinfo absinfo; if (ioctl( data->fd, EVIOCGABS( axis ), &absinfo ) == 0 && (absinfo.minimum || absinfo.maximum)) { ret_info->flags = IDAIF_ABS_MIN | IDAIF_ABS_MAX; ret_info->abs_min = absinfo.minimum; ret_info->abs_max = absinfo.maximum; } } } return DFB_OK; } /********************************************************************************************************************** ********************************* Set configuration function ********************************************************* **********************************************************************************************************************/ static DFBResult driver_set_configuration( CoreInputDevice *device, void *driver_data, const DFBInputDeviceConfig *config ) { LinuxInputData *data = driver_data; D_DEBUG_AT( Linux_Input, "%s()\n", __FUNCTION__ ); if (config->flags & DIDCONF_SENSITIVITY) data->sensitivity = config->sensitivity; return DFB_OK; } ================================================ FILE: inputdrivers/linux_input/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA if not cc.has_header('linux/input.h') warning('Building without Linux Input support.') subdir_done() endif library('directfb_linux_input', 'linux_input.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'inputdrivers', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-inputdriver-linux_input', variables: 'moduledir=' + moduledir, name: 'DirectFB-inputdriver-linux_input', description: 'Linux input driver', libraries_private: ['-L${moduledir}/inputdrivers', '-Wl,--whole-archive -ldirectfb_linux_input -Wl,--no-whole-archive']) endif ================================================ FILE: inputdrivers/nuttx_input/nuttx_input.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( NuttX_Input, "Input/NuttX", "NuttX Input Driver" ); DFB_INPUT_DRIVER( nuttx_input ) /**********************************************************************************************************************/ typedef struct { CoreInputDevice *device; int fd; unsigned int id; int16_t last_x; int16_t last_y; DirectThread *thread; } NuttXData; #define MAX_NUTTX_INPUT_DEVICES 3 /* Input devices are stored in the device_names array. */ static char *device_names[MAX_NUTTX_INPUT_DEVICES]; /* Number of entries in the device_names array. */ static int num_devices = 0; /**********************************************************************************************************************/ static void * devinput_event_thread( DirectThread *thread, void *arg ) { NuttXData *data = arg; int offsetx = 0; int offsety = 0; int threshx = 1; int threshy = 1; D_DEBUG_AT( NuttX_Input, "%s()\n", __FUNCTION__ ); /* Query the touchscreen X/Y offsets and thresholds. */ if (data->id == DIDID_MOUSE) { #if defined(TSIOC_GETOFFSETX) && defined(TSIOC_GETOFFSETY) ioctl( data->fd, TSIOC_GETOFFSETX, &offsetx ); ioctl( data->fd, TSIOC_GETOFFSETY, &offsety ); #endif #if defined(TSIOC_GETTHRESHX) && defined(TSIOC_GETTHRESHY) ioctl( data->fd, TSIOC_GETTHRESHX, &threshx ); ioctl( data->fd, TSIOC_GETTHRESHY, &threshy ); #endif } while (1) { DFBInputEvent evt = { .type = DIET_UNKNOWN }; fd_set set; int status; ssize_t len; FD_ZERO( &set ); FD_SET( data->fd, &set ); status = select( data->fd + 1, &set, NULL, NULL, NULL ); if (status < 0 && errno != EINTR) break; if (status < 0) continue; if (data->id == DIDID_BUTTONS) { btn_buttonset_t buttonset; len = read( data->fd, &buttonset, sizeof(buttonset) ); if (len < 1) continue; evt.type = buttonset ? DIET_BUTTONRELEASE : DIET_BUTTONPRESS; evt.flags = DIEF_NONE; evt.button = DIBI_FIRST; dfb_input_dispatch( data->device, &evt ); } else if (data->id == DIDID_KEYBOARD) { struct keyboard_event_s keyboard_event; len = read( data->fd, &keyboard_event, sizeof(keyboard_event) ); if (len < 1) continue; evt.type = keyboard_event.type ? DIET_KEYRELEASE : DIET_KEYPRESS; evt.flags = DIEF_KEYSYMBOL; evt.key_symbol = keyboard_event.code; dfb_input_dispatch( data->device, &evt ); } else if (data->id == DIDID_MOUSE) { struct touch_sample_s touch_sample; len = read( data->fd, &touch_sample, sizeof(touch_sample) ); if (len < 1) continue; if (touch_sample.point[0].flags & TOUCH_DOWN) { evt.type = DIET_BUTTONPRESS; evt.flags = DIEF_NONE; evt.button = DIBI_LEFT; dfb_input_dispatch( data->device, &evt ); } if (touch_sample.point[0].flags & TOUCH_DOWN || touch_sample.point[0].flags & TOUCH_MOVE) { if (touch_sample.point[0].x != data->last_x) { evt.type = DIET_AXISMOTION; evt.flags = DIEF_AXISABS | DIEF_BUTTONS; evt.axis = DIAI_X; evt.axisabs = (touch_sample.point[0].x - offsetx) / threshx; evt.buttons = DIBM_LEFT; dfb_input_dispatch( data->device, &evt ); } if (touch_sample.point[0].y != data->last_y) { evt.type = DIET_AXISMOTION; evt.flags = DIEF_AXISABS | DIEF_BUTTONS; evt.axis = DIAI_Y; evt.axisabs = touch_sample.point[0].y; evt.axisabs = (touch_sample.point[0].y - offsety) / threshy; evt.buttons = DIBM_LEFT; dfb_input_dispatch( data->device, &evt ); } } if (touch_sample.point[0].flags & TOUCH_UP) { evt.type = DIET_BUTTONRELEASE; evt.flags = DIEF_NONE; evt.button = DIBI_LEFT; dfb_input_dispatch( data->device, &evt ); } data->last_x = touch_sample.point[0].x; data->last_y = touch_sample.point[0].y; } } D_DEBUG_AT( NuttX_Input, "DevInput Event thread terminated\n" ); return NULL; } static bool check_device( const char *device ) { int fd; D_DEBUG_AT( NuttX_Input, "%s( '%s' )\n", __FUNCTION__, device ); /* Check if we are able to open the device. */ fd = open( device, O_RDONLY ); if (fd < 0) { D_DEBUG_AT( NuttX_Input, " -> open failed!\n" ); return false; } close( fd ); return true; } /**********************************************************************************************************************/ static int driver_get_available() { char buf[32]; int i; if (num_devices) { for (i = 0; i < num_devices; i++) { D_FREE( device_names[i] ); device_names[i] = NULL; } num_devices = 0; return 0; } /* Buttons device */ snprintf( buf, sizeof(buf), "/dev/buttons" ); if (check_device( buf )) { D_ASSERT( device_names[num_devices] == NULL ); device_names[num_devices++] = D_STRDUP( buf ); } /* Keyboard device */ snprintf( buf, sizeof(buf), "/dev/kbd" ); if (check_device( buf )) { D_ASSERT( device_names[num_devices] == NULL ); device_names[num_devices++] = D_STRDUP( buf ); } /* Touchscreen device */ snprintf( buf, sizeof(buf), "/dev/input0" ); if (check_device( buf )) { D_ASSERT( device_names[num_devices] == NULL ); device_names[num_devices++] = D_STRDUP( buf ); } return num_devices; } static void driver_get_info( InputDriverInfo *driver_info ) { driver_info->version.major = 0; driver_info->version.minor = 1; snprintf( driver_info->name, DFB_INPUT_DRIVER_INFO_NAME_LENGTH, "NuttX Input" ); snprintf( driver_info->vendor, DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH, "DirectFB" ); } static DFBResult driver_open_device( CoreInputDevice *device, unsigned int number, InputDeviceInfo *device_info, void **driver_data ) { NuttXData *data; int fd; D_DEBUG_AT( NuttX_Input, "%s()\n", __FUNCTION__ ); /* Open device. */ fd = open( device_names[number], O_RDONLY ); if (fd < 0) { D_PERROR( "Input/NuttX: Could not open device!\n" ); return DFB_INIT; } /* Fill device information. */ if (!strcmp( device_names[number], "/dev/buttons" )) { device_info->prefered_id = DIDID_BUTTONS; device_info->desc.type = DIDTF_BUTTONS; device_info->desc.caps = DICAPS_BUTTONS; snprintf( device_info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH, "Buttons" ); snprintf( device_info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "NuttX" ); } else if (!strcmp( device_names[number], "/dev/kbd" )) { device_info->prefered_id = DIDID_KEYBOARD; device_info->desc.type = DIDTF_KEYBOARD; device_info->desc.caps = DICAPS_KEYS; snprintf( device_info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH, "Keyboard" ); snprintf( device_info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "NuttX" ); } else if (!strcmp( device_names[number], "/dev/input0" )) { device_info->prefered_id = DIDID_MOUSE; device_info->desc.type = DIDTF_MOUSE; device_info->desc.caps = DICAPS_AXES | DICAPS_BUTTONS; device_info->desc.max_axis = DIAI_Y; device_info->desc.max_button = DIBI_LEFT; snprintf( device_info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH, "Touchscreen" ); snprintf( device_info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "NuttX" ); } /* Allocate and fill private data. */ data = D_CALLOC( 1, sizeof(NuttXData) ); if (!data) { close( fd ); return D_OOM(); } data->device = device; data->fd = fd; data->id = device_info->prefered_id; /* Start devinput event thread. */ data->thread = direct_thread_create( DTT_INPUT, devinput_event_thread, data, "DevInput Event" ); *driver_data = data; return DFB_OK; } static DFBResult driver_get_keymap_entry( CoreInputDevice *device, void *driver_data, DFBInputDeviceKeymapEntry *entry ) { return DFB_UNSUPPORTED; } static void driver_close_device( void *driver_data ) { NuttXData *data = driver_data; D_DEBUG_AT( NuttX_Input, "%s()\n", __FUNCTION__ ); /* Terminate the devinput event thread. */ direct_thread_cancel( data->thread ); direct_thread_join( data->thread ); direct_thread_destroy( data->thread ); close( data->fd ); D_FREE( data ); } ================================================ FILE: interfaces/ICoreResourceManager/icoreresourcemanager_default.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( ICoreResourceManager_default, "ICoreResourceManager/default", "Default Resource Manager" ); D_DEBUG_DOMAIN( ICoreResourceClient_default, "ICoreResourceClient/default", "Default Resource Client" ); static DirectResult Probe ( void *ctx ); static DirectResult Construct( ICoreResourceManager *thiz, CoreDFB *core ); #include DIRECT_INTERFACE_IMPLEMENTATION( ICoreResourceManager, default ) /**********************************************************************************************************************/ typedef struct { int ref; /* reference counter */ FusionID identity; unsigned int surface_mem; } ICoreResourceClient_data; /**********************************************************************************************************************/ static void ICoreResourceClient_Destruct( ICoreResourceClient *thiz ) { D_DEBUG_AT( ICoreResourceClient_default, "%s( %p )\n", __FUNCTION__, thiz ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult ICoreResourceClient_AddRef( ICoreResourceClient *thiz ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult ICoreResourceClient_Release( ICoreResourceClient *thiz ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_LOG( ICoreResourceClient_default, 1, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) { D_LOG( ICoreResourceClient_default, INFO, "Removing ID %lu\n", data->identity ); ICoreResourceClient_Destruct( thiz ); } return DFB_OK; } static __inline__ unsigned int surface_mem( const CoreSurfaceConfig *config ) { unsigned int mem; mem = DFB_PLANE_MULTIPLY( config->format, config->size.h ) * DFB_BYTES_PER_LINE( config->format, config->size.w ); if (config->caps & DSCAPS_TRIPLE) mem *= 3; else if (config->caps & DSCAPS_DOUBLE) mem *= 2; return mem; } static DFBResult ICoreResourceClient_CheckSurface( ICoreResourceClient *thiz, const CoreSurfaceConfig *config, u64 resource_id ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p [%lu] )\n", __FUNCTION__, thiz, data->identity ); D_DEBUG_AT( ICoreResourceClient_default, " -> %dx%d %s %uk at %uk, resource id %llu\n", config->size.w, config->size.h, dfb_pixelformat_name( config->format ), surface_mem( config ) / 1024, data->surface_mem / 1024, (unsigned long long) resource_id ); return DFB_OK; } static DFBResult ICoreResourceClient_CheckSurfaceUpdate( ICoreResourceClient *thiz, CoreSurface *surface, const CoreSurfaceConfig *config ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p [%lu] )\n", __FUNCTION__, thiz, data->identity ); D_DEBUG_AT( ICoreResourceClient_default, " -> %u bytes\n", surface_mem( &surface->config ) ); return DFB_OK; } static DFBResult ICoreResourceClient_AddSurface( ICoreResourceClient *thiz, CoreSurface *surface ) { unsigned int mem; DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p [%lu] )\n", __FUNCTION__, thiz, data->identity ); mem = surface_mem( &surface->config ); D_DEBUG_AT( ICoreResourceClient_default, " -> %u bytes\n", mem ); data->surface_mem += mem; return DFB_OK; } static DFBResult ICoreResourceClient_RemoveSurface( ICoreResourceClient *thiz, CoreSurface *surface ) { unsigned int mem; DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p [%lu] )\n", __FUNCTION__, thiz, data->identity ); mem = surface_mem( &surface->config ); D_DEBUG_AT( ICoreResourceClient_default, " -> %u bytes\n", mem ); data->surface_mem -= mem; return DFB_OK; } static DFBResult ICoreResourceClient_UpdateSurface( ICoreResourceClient *thiz, CoreSurface *surface, const CoreSurfaceConfig *config ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceClient ) D_DEBUG_AT( ICoreResourceClient_default, "%s( %p [%lu] )\n", __FUNCTION__, thiz, data->identity ); data->surface_mem -= surface_mem( &surface->config ); data->surface_mem += surface_mem( config ); return DFB_OK; } DirectResult ICoreResourceClient_Construct( ICoreResourceClient *thiz, CoreDFB *core, FusionID identity ) { char buf[512]; size_t len; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, ICoreResourceClient ) D_DEBUG_LOG( ICoreResourceClient_default, 1, "%s( %p )\n", __FUNCTION__, thiz ); fusion_get_fusionee_path( core->world, identity, buf, sizeof(buf), &len ); D_LOG( ICoreResourceClient_default, INFO, "Adding ID %lu - '%s'\n", identity, buf ); data->ref = 1; data->identity = identity; thiz->AddRef = ICoreResourceClient_AddRef; thiz->Release = ICoreResourceClient_Release; thiz->CheckSurface = ICoreResourceClient_CheckSurface; thiz->CheckSurfaceUpdate = ICoreResourceClient_CheckSurfaceUpdate; thiz->AddSurface = ICoreResourceClient_AddSurface; thiz->RemoveSurface = ICoreResourceClient_RemoveSurface; thiz->UpdateSurface = ICoreResourceClient_UpdateSurface; return DFB_OK; } /**********************************************************************************************************************/ typedef struct { int ref; /* reference counter */ CoreDFB *core; } ICoreResourceManager_data; /**********************************************************************************************************************/ static void ICoreResourceManager_Destruct( ICoreResourceManager *thiz ) { D_DEBUG_AT( ICoreResourceManager_default, "%s( %p )\n", __FUNCTION__, thiz ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult ICoreResourceManager_AddRef( ICoreResourceManager *thiz ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceManager ) D_DEBUG_AT( ICoreResourceManager_default, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult ICoreResourceManager_Release( ICoreResourceManager *thiz ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceManager ) D_DEBUG_AT( ICoreResourceManager_default, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) ICoreResourceManager_Destruct( thiz ); return DFB_OK; } static DFBResult ICoreResourceManager_CreateClient( ICoreResourceManager *thiz, FusionID identity, ICoreResourceClient **ret_interface ) { DIRECT_INTERFACE_GET_DATA( ICoreResourceManager ) D_DEBUG_LOG( ICoreResourceManager_default, 1, "%s( %p )\n", __FUNCTION__, thiz ); DIRECT_ALLOCATE_INTERFACE( *ret_interface, ICoreResourceClient ); return ICoreResourceClient_Construct( *ret_interface, data->core, identity ); } /**********************************************************************************************************************/ static DirectResult Probe( void *ctx ) { return DFB_OK; } static DirectResult Construct( ICoreResourceManager *thiz, CoreDFB *core ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, ICoreResourceManager ) D_DEBUG_AT( ICoreResourceManager_default, "%s( %p )\n", __FUNCTION__, thiz ); D_LOG( ICoreResourceManager_default, NOTICE, "Initializing resource manager 'default'\n" ); data->ref = 1; data->core = core; thiz->AddRef = ICoreResourceManager_AddRef; thiz->Release = ICoreResourceManager_Release; thiz->CreateClient = ICoreResourceManager_CreateClient; return DFB_OK; } ================================================ FILE: interfaces/ICoreResourceManager/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA library('icoreresourcemanager_default', 'icoreresourcemanager_default.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'interfaces/ICoreResourceManager', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-interface-resourcemanager_default', variables: 'moduledir=' + moduledir, name: 'DirectFB-interface-resourcemanager_default', description: 'Default resource manager', libraries_private: ['-L${moduledir}/interfaces/ICoreResourceManager', '-Wl,--whole-archive -licoreresourcemanager_default -Wl,--no-whole-archive']) endif ================================================ FILE: interfaces/IDirectFBFont/idirectfbfont_dgiff.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Font_DGIFF, "Font/DGIFF", "DGIFF Font Provider" ); static DFBResult Probe ( IDirectFBFont_ProbeContext *ctx ); static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, DGIFF ) /**********************************************************************************************************************/ typedef struct { CoreSurface **rows; /* bitmaps of loaded glyphs */ int num_rows; } DGIFFImplData; /**********************************************************************************************************************/ static void IDirectFBFont_DGIFF_Destruct( IDirectFBFont *thiz ) { DGIFFImplData *data = ((IDirectFBFont_data*) thiz->priv)->font->impl_data; D_DEBUG_AT( Font_DGIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (data->rows) { int i; for (i = 0; i < data->num_rows; i++) { if (data->rows[i]) dfb_surface_unref( data->rows[i] ); } D_FREE( data->rows ); } D_FREE( data ); IDirectFBFont_Destruct( thiz ); } static DirectResult IDirectFBFont_DGIFF_Release( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font_DGIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBFont_DGIFF_Destruct( thiz ); return DFB_OK; } /**********************************************************************************************************************/ static DFBResult Probe( IDirectFBFont_ProbeContext *ctx ) { /* Check the magic. */ if (!strncmp( (const char*) ctx->content, "DGIFF", 5 )) return DFB_OK; return DFB_UNSUPPORTED; } static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ) { DFBResult ret; int i; const DGIFFHeader *header; const DGIFFFaceHeader *faceheader; DGIFFGlyphInfo *glyphs; DGIFFGlyphRow *row; CoreFont *font = NULL; DGIFFImplData *data = NULL; D_DEBUG_AT( Font_DGIFF, "%s( %p )\n", __FUNCTION__, thiz ); /* Check for valid description. */ if (!(desc->flags & DFDESC_HEIGHT)) return DFB_INVARG; if (desc->flags & DFDESC_ROTATION) return DFB_UNSUPPORTED; D_DEBUG_AT( Font_DGIFF, " -> font at pixel height %d\n", desc->height ); header = (void*) ctx->content; faceheader = (void*) ctx->content + sizeof(DGIFFHeader); /* Lookup requested face. */ for (i = 0; i < header->num_faces; i++) { if (faceheader->size == desc->height) break; faceheader = (void*) faceheader + faceheader->next_face; } if (i == header->num_faces) { D_ERROR( "Font/DGIFF: Requested size %d not found!\n", desc->height ); ret = DFB_UNSUPPORTED; goto error; } glyphs = (void*) (faceheader + 1); row = (void*) (glyphs + faceheader->num_glyphs); /* Create the font object. */ ret = dfb_font_create( core, desc, &font ); if (ret) goto error; /* Fill font information. */ if (faceheader->blittingflags) font->blittingflags = faceheader->blittingflags; font->pixel_format = faceheader->pixelformat; font->surface_caps = DSCAPS_NONE; font->ascender = faceheader->ascender; font->descender = faceheader->descender; font->height = faceheader->height; font->maxadvance = faceheader->max_advance; font->up_unit_x = 0.0; font->up_unit_y = -1.0; font->flags = CFF_SUBPIXEL_ADVANCE; CORE_FONT_DEBUG_AT( Font_DGIFF, font ); /* Allocate implementation data. */ data = D_CALLOC( 1, sizeof(DGIFFImplData) ); if (!data) { ret = D_OOM(); goto error; } data->num_rows = faceheader->num_rows; /* Allocate array for glyph cache rows. */ data->rows = D_CALLOC( data->num_rows, sizeof(void*) ); if (!data->rows) { ret = D_OOM(); goto error; } /* Build glyph cache rows. */ for (i = 0; i < data->num_rows; i++) { ret = dfb_surface_create_simple( core, row->width, row->height, faceheader->pixelformat, DFB_COLORSPACE_DEFAULT( faceheader->pixelformat ), DSCAPS_NONE, CSTF_NONE, 0, NULL, &data->rows[i] ); if (ret) { D_DERROR( ret, "DGIFF/Font: Could not create %s %dx%d glyph row surface!\n", dfb_pixelformat_name( faceheader->pixelformat ), row->width, row->height ); goto error; } dfb_surface_write_buffer( data->rows[i], DSBR_BACK, row + 1, row->pitch, NULL ); /* Jump to next row. */ row = (void*) (row + 1) + row->pitch * row->height; } /* Build glyph info. */ for (i = 0; i < faceheader->num_glyphs; i++) { CoreGlyphData *glyph_data; DGIFFGlyphInfo *glyph = &glyphs[i]; glyph_data = D_CALLOC( 1, sizeof(CoreGlyphData) ); if (!glyph_data) { ret = D_OOM(); goto error; } glyph_data->surface = data->rows[glyph->row]; glyph_data->start = glyph->offset; glyph_data->width = glyph->width; glyph_data->height = glyph->height; glyph_data->left = glyph->left; glyph_data->top = glyph->top; glyph_data->xadvance = glyph->advance << 8; glyph_data->yadvance = 0; D_MAGIC_SET( glyph_data, CoreGlyphData ); direct_hash_insert( font->layers[0].glyph_hash, glyph->unicode, glyph_data ); if (glyph->unicode < 128) font->layers[0].glyph_data[glyph->unicode] = glyph_data; } font->impl_data = data; IDirectFBFont_Construct( thiz, font ); thiz->Release = IDirectFBFont_DGIFF_Release; return DFB_OK; error: if (font) { if (data) { if (data->rows) { for (i = 0; i < data->num_rows; i++) { if (data->rows[i]) dfb_surface_unref( data->rows[i] ); } D_FREE( data->rows ); } D_FREE( data ); } dfb_font_destroy( font ); } return ret; } ================================================ FILE: interfaces/IDirectFBFont/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA library('idirectfbfont_dgiff', 'idirectfbfont_dgiff.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'interfaces/IDirectFBFont', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-interface-font_dgiff', variables: 'moduledir=' + moduledir, name: 'DirectFB-interface-font_dgiff', description: 'DGIFF font provider', libraries_private: ['-L${moduledir}/interfaces/IDirectFBFont', '-Wl,--whole-archive -lidirectfbfont_dgiff -Wl,--no-whole-archive']) endif ================================================ FILE: interfaces/IDirectFBImageProvider/idirectfbimageprovider_dfiff.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( ImageProvider_DFIFF, "ImageProvider/DFIFF", "DFIFF Image Provider" ); static DFBResult Probe ( IDirectFBImageProvider_ProbeContext *ctx ); static DFBResult Construct( IDirectFBImageProvider *thiz, IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBImageProvider, DFIFF ) /**********************************************************************************************************************/ typedef struct { int ref; /* reference counter */ IDirectFB *idirectfb; void *ptr; /* pointer to raw file data (mapped) */ int len; /* data length, i.e. file size */ int pitch; bool premultiplied; DFBSurfaceDescription desc; DIRenderCallback render_callback; void *render_callback_context; } IDirectFBImageProvider_DFIFF_data; #define DFIFF_FLAG_PREMULTIPLIED 0x02 /**********************************************************************************************************************/ static void IDirectFBImageProvider_DFIFF_Destruct( IDirectFBImageProvider *thiz ) { IDirectFBImageProvider_DFIFF_data *data = thiz->priv; D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->len) D_FREE( data->ptr ); else if (data->len > 0) direct_file_unmap( data->ptr, data->len ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBImageProvider_DFIFF_AddRef( IDirectFBImageProvider *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBImageProvider_DFIFF_Release( IDirectFBImageProvider *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBImageProvider_DFIFF_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBImageProvider_DFIFF_GetSurfaceDescription( IDirectFBImageProvider *thiz, DFBSurfaceDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->desc; return DFB_OK; } static DFBResult IDirectFBImageProvider_DFIFF_GetImageDescription( IDirectFBImageProvider *thiz, DFBImageDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; ret_desc->caps = DFB_PIXELFORMAT_HAS_ALPHA( data->desc.pixelformat ) ? DICAPS_ALPHACHANNEL : DICAPS_NONE; return DFB_OK; } static DFBResult IDirectFBImageProvider_DFIFF_RenderTo( IDirectFBImageProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ) { DFBResult ret; IDirectFBSurface_data *dst_data; DFBRectangle rect; DFBRectangle clipped; DFBSurfaceCapabilities caps; DFBSurfacePixelFormat pixelformat; bool dest_premultiplied = false; DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!destination) return DFB_INVARG; dst_data = destination->priv; if (!dst_data) return DFB_DEAD; if (dest_rect) { if (dest_rect->w < 1 || dest_rect->h < 1) return DFB_INVARG; rect = *dest_rect; rect.x += dst_data->area.wanted.x; rect.y += dst_data->area.wanted.y; } else rect = dst_data->area.wanted; clipped = rect; D_DEBUG_AT( ImageProvider_DFIFF, " -> clip "DFB_RECT_FORMAT"\n", DFB_RECTANGLE_VALS( &dst_data->area.current ) ); if (!dfb_rectangle_intersect( &clipped, &dst_data->area.current )) return DFB_INVAREA; D_DEBUG_AT( ImageProvider_DFIFF, " -> clipped "DFB_RECT_FORMAT"\n", DFB_RECTANGLE_VALS( &clipped ) ); ret = destination->GetCapabilities( destination, &caps ); if (ret) return ret; if (caps & DSCAPS_PREMULTIPLIED) dest_premultiplied = true; ret = destination->GetPixelFormat( destination, &pixelformat ); if (ret) return ret; if (DFB_RECTANGLE_EQUAL( rect, clipped ) && rect.w == data->desc.width && rect.h == data->desc.height && pixelformat == data->desc.pixelformat && data->premultiplied == dest_premultiplied) { ret = destination->Write( destination, &rect, data->ptr + sizeof(DFIFFHeader), data->pitch ); if (ret) return ret; } else { DFBRegion clip = DFB_REGION_INIT_FROM_RECTANGLE( &clipped ); DFBRegion old_clip; DFBSurfaceDescription desc; IDirectFBSurface *source; desc = data->desc; desc.flags |= DSDESC_PREALLOCATED; desc.preallocated[0].data = data->ptr + sizeof(DFIFFHeader); desc.preallocated[0].pitch = data->pitch; ret = data->idirectfb->CreateSurface( data->idirectfb, &desc, &source ); if (ret) return ret; if (DFB_PIXELFORMAT_HAS_ALPHA( desc.pixelformat )) { if (dest_premultiplied && !data->premultiplied) destination->SetBlittingFlags( destination, DSBLIT_SRC_PREMULTIPLY ); else if (!dest_premultiplied && data->premultiplied) destination->SetBlittingFlags( destination, DSBLIT_DEMULTIPLY ); } destination->GetClip( destination, &old_clip ); destination->SetClip( destination, &clip ); destination->StretchBlit( destination, source, NULL, &rect ); destination->SetClip( destination, &old_clip ); destination->SetBlittingFlags( destination, DSBLIT_NOFX ); destination->ReleaseSource( destination ); source->Release( source ); } if (data->render_callback) { DFBRectangle r = { 0, 0, data->desc.width, data->desc.height }; data->render_callback( &r, data->render_callback_context ); } return DFB_OK; } static DFBResult IDirectFBImageProvider_DFIFF_SetRenderCallback( IDirectFBImageProvider *thiz, DIRenderCallback callback, void *ctx ) { DIRECT_INTERFACE_GET_DATA( IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); data->render_callback = callback; data->render_callback_context = ctx; return DFB_OK; } /**********************************************************************************************************************/ static DFBResult Probe( IDirectFBImageProvider_ProbeContext *ctx ) { /* Check the magic. */ if (!strncmp( (const char*) ctx->header, "DFIFF", 5 )) return DFB_OK; return DFB_UNSUPPORTED; } static DFBResult Construct( IDirectFBImageProvider *thiz, IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb ) { DFBResult ret; DirectFile fd; int len; const DFIFFHeader *header; void *ptr; void *chunk = NULL; IDirectFBDataBuffer_data *buffer_data = buffer->priv; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBImageProvider_DFIFF ) D_DEBUG_AT( ImageProvider_DFIFF, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->idirectfb = idirectfb; if (buffer_data->buffer) { len = -1; ptr = buffer_data->buffer; } else if (buffer_data->filename) { DirectFileInfo info; /* Open the file. */ ret = direct_file_open( &fd, buffer_data->filename, O_RDONLY, 0 ); if (ret) { D_DERROR( ret, "ImageProvider/DFIFF: Failed to open file '%s'!\n", buffer_data->filename ); len = 0; goto error; } /* Query file size. */ ret = direct_file_get_info( &fd, &info ); if (ret) { D_DERROR( ret, "ImageProvider/DFIFF: Failed during get_info() of '%s'!\n", buffer_data->filename ); len = -1; goto error; } else len = info.size; /* Memory-mapped file. */ ret = direct_file_map( &fd, NULL, 0, len, DFP_READ, &ptr ); if (ret) { D_DERROR( ret, "ImageProvider/DFIFF: Failed during mmap() of '%s'!\n", buffer_data->filename ); goto error; } direct_file_close( &fd ); } else { unsigned int size = 0; len = 0; while (1) { unsigned int bytes; chunk = D_REALLOC( chunk, size + 4096 ); if (!chunk) { ret = D_OOM(); goto error; } buffer->WaitForData( buffer, 4096 ); if (buffer->GetData( buffer, 4096, chunk + size, &bytes )) break; size += bytes; } if (!size) { ret = DFB_IO; goto error; } ptr = chunk; } header = ptr; data->ptr = ptr; data->len = len; data->pitch = header->pitch; data->premultiplied = header->flags & DFIFF_FLAG_PREMULTIPLIED ? true : false; data->desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT; data->desc.width = header->width; data->desc.height = header->height; data->desc.pixelformat = header->format; thiz->AddRef = IDirectFBImageProvider_DFIFF_AddRef; thiz->Release = IDirectFBImageProvider_DFIFF_Release; thiz->GetSurfaceDescription = IDirectFBImageProvider_DFIFF_GetSurfaceDescription; thiz->GetImageDescription = IDirectFBImageProvider_DFIFF_GetImageDescription; thiz->RenderTo = IDirectFBImageProvider_DFIFF_RenderTo; thiz->SetRenderCallback = IDirectFBImageProvider_DFIFF_SetRenderCallback; return DFB_OK; error: if (len) direct_file_close( &fd ); if (chunk) D_FREE( chunk ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ================================================ FILE: interfaces/IDirectFBImageProvider/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA library('idirectfbimageprovider_dfiff', 'idirectfbimageprovider_dfiff.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'interfaces/IDirectFBImageProvider', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-interface-imageprovider_dfiff', variables: 'moduledir=' + moduledir, name: 'DirectFB-interface-imageprovider_dfiff', description: 'DFIFF image provider', libraries_private: ['-L${moduledir}/interfaces/IDirectFBImageProvider', '-Wl,--whole-archive -lidirectfbimageprovider_dfiff -Wl,--no-whole-archive']) endif ================================================ FILE: interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_dfvff.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( VideoProvider_DFVFF, "VideoProvider/DFVFF", "DFVFF Video Provider" ); static DFBResult Probe ( IDirectFBVideoProvider_ProbeContext *ctx ); static DFBResult Construct( IDirectFBVideoProvider *thiz, IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBVideoProvider, DFVFF ) /**********************************************************************************************************************/ typedef struct { DirectLink link; IDirectFBEventBuffer *buffer; } EventLink; typedef struct { int ref; /* reference counter */ IDirectFB *idirectfb; void *ptr; /* pointer to raw file data (mapped) */ int len; /* data length, i.e. file size */ DFBSurfaceDescription desc; double rate; DFBVideoProviderStatus status; double speed; DFBVideoProviderPlaybackFlags flags; int frame_size; long nb_frames; long frame; DirectThread *thread; DirectMutex lock; DirectWaitQueue cond; bool seeked; IDirectFBSurface *dest; DFBRectangle rect; DVFrameCallback frame_callback; void *frame_callback_context; DirectLink *events; DFBVideoProviderEventType events_mask; DirectMutex events_lock; } IDirectFBVideoProvider_DFVFF_data; /**********************************************************************************************************************/ static void dispatch_event( IDirectFBVideoProvider_DFVFF_data *data, DFBVideoProviderEventType type ) { EventLink *link; DFBVideoProviderEvent event; if (!data->events || !(data->events_mask & type)) return; event.clazz = DFEC_VIDEOPROVIDER; event.type = type; direct_mutex_lock( &data->events_lock ); direct_list_foreach (link, data->events) { link->buffer->PostEvent( link->buffer, DFB_EVENT(&event) ); } direct_mutex_unlock( &data->events_lock ); } static void * DFVFFVideo( DirectThread *thread, void *arg ) { DFBResult ret; int pitch; void *ptr; IDirectFBSurface *source; void *frame_ptr; int drop = 0; IDirectFBVideoProvider_DFVFF_data *data = arg; ret = data->idirectfb->CreateSurface( data->idirectfb, &data->desc, &source ); if (ret) return NULL; source->Lock( source, DSLF_WRITE, &ptr, &pitch ); source->Unlock( source ); frame_ptr = data->ptr + sizeof(DFVFFHeader); dispatch_event( data, DVPET_STARTED ); while (data->status != DVSTATE_STOP) { long long time; time = direct_clock_get_abs_micros(); direct_mutex_lock( &data->lock ); if (drop) { data->frame += drop; data->frame = MIN( data->frame, data->nb_frames - 1 ); drop = 0; if (data->seeked) { direct_mutex_unlock( &data->lock ); continue; } } else { if (data->seeked) { frame_ptr = data->ptr + sizeof(DFVFFHeader) + data->frame * data->frame_size; if (data->status == DVSTATE_FINISHED) data->status = DVSTATE_PLAY; data->seeked = false; } direct_memcpy( ptr, frame_ptr, data->frame_size ); data->dest->StretchBlit( data->dest, source, NULL, &data->rect ); if (data->frame_callback) data->frame_callback( data->frame_callback_context ); } if (!data->speed) { direct_waitqueue_wait( &data->cond, &data->lock ); if (data->seeked || data->status == DVSTATE_STOP) { direct_mutex_unlock( &data->lock ); continue; } } else { long duration, delay; duration = 1000000 / (data->rate * data->speed); delay = direct_clock_get_abs_micros() - time; if (delay > duration) { drop = delay / duration; direct_mutex_unlock( &data->lock ); continue; } direct_waitqueue_wait_timeout( &data->cond, &data->lock, duration - delay ); if (data->seeked) { direct_mutex_unlock( &data->lock ); continue; } } data->frame++; if (data->frame == data->nb_frames) { if (data->flags & DVPLAY_LOOPING) { data->frame = 0; frame_ptr = data->ptr + sizeof(DFVFFHeader); } else { data->status = DVSTATE_FINISHED; dispatch_event( data, DVPET_FINISHED ); direct_waitqueue_wait( &data->cond, &data->lock ); } } else frame_ptr = data->ptr + sizeof(DFVFFHeader) + data->frame * data->frame_size; direct_mutex_unlock( &data->lock ); } source->Release( source ); return NULL; } /**********************************************************************************************************************/ static void IDirectFBVideoProvider_DFVFF_Destruct( IDirectFBVideoProvider *thiz ) { EventLink *link, *tmp; IDirectFBVideoProvider_DFVFF_data *data = thiz->priv; D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); thiz->Stop( thiz ); direct_waitqueue_deinit( &data->cond ); direct_mutex_deinit( &data->lock ); direct_list_foreach_safe (link, tmp, data->events) { direct_list_remove( &data->events, &link->link ); link->buffer->Release( link->buffer ); D_FREE( link ); } direct_mutex_deinit( &data->events_lock ); if (!data->len) D_FREE( data->ptr ); else if (data->len > 0) direct_file_unmap( data->ptr, data->len ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBVideoProvider_DFVFF_AddRef( IDirectFBVideoProvider *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBVideoProvider_DFVFF_Release( IDirectFBVideoProvider *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBVideoProvider_DFVFF_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetCapabilities( IDirectFBVideoProvider *thiz, DFBVideoProviderCapabilities *ret_caps ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_caps) return DFB_INVARG; *ret_caps = DVCAPS_BASIC | DVCAPS_SEEK | DVCAPS_SCALE | DVCAPS_SPEED; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetSurfaceDescription( IDirectFBVideoProvider *thiz, DFBSurfaceDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->desc; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetStreamDescription( IDirectFBVideoProvider *thiz, DFBStreamDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; memset( ret_desc, 0, sizeof(DFBStreamDescription) ); ret_desc->caps = DVSCAPS_VIDEO; snprintf( ret_desc->video.encoding, DFB_STREAM_DESC_ENCODING_LENGTH, "rawvideo" ); ret_desc->video.framerate = data->rate; ret_desc->video.aspect = (double) data->desc.width / data->desc.height; ret_desc->video.bitrate = data->rate * data->frame_size; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_PlayTo( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect, DVFrameCallback callback, void *ctx ) { IDirectFBSurface_data *dst_data; DFBRectangle rect; DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!destination) return DFB_INVARG; dst_data = destination->priv; if (!dst_data) return DFB_DEAD; if (dest_rect) { if (dest_rect->w < 1 || dest_rect->h < 1) return DFB_INVARG; rect = *dest_rect; } else rect = dst_data->area.wanted; if (data->thread) return DFB_OK; direct_mutex_lock( &data->lock ); data->dest = destination; data->rect = rect; data->frame_callback = callback; data->frame_callback_context = ctx; data->status = DVSTATE_PLAY; data->thread = direct_thread_create( DTT_DEFAULT, DFVFFVideo, data, "DFVFF Video" ); direct_mutex_unlock( &data->lock ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_Stop( IDirectFBVideoProvider *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (data->status == DVSTATE_STOP) return DFB_OK; data->status = DVSTATE_STOP; if (data->thread) { direct_waitqueue_signal( &data->cond ); direct_thread_join( data->thread ); direct_thread_destroy( data->thread ); data->thread = NULL; } data->frame = 0; dispatch_event( data, DVPET_STOPPED ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetStatus( IDirectFBVideoProvider *thiz, DFBVideoProviderStatus *ret_status ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_status) return DFB_INVARG; *ret_status = data->status; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_SeekTo( IDirectFBVideoProvider *thiz, double seconds ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (seconds < 0.0) return DFB_INVARG; direct_mutex_lock( &data->lock ); data->frame = data->rate * seconds; data->frame = MIN( data->frame, data->nb_frames - 1 ); data->seeked = true; direct_waitqueue_signal( &data->cond ); direct_mutex_unlock( &data->lock ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetPos( IDirectFBVideoProvider *thiz, double *ret_seconds ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_seconds) return DFB_INVARG; direct_mutex_lock( &data->lock ); *ret_seconds = data->frame / data->rate; direct_mutex_unlock( &data->lock ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetLength( IDirectFBVideoProvider *thiz, double *ret_seconds ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_seconds) return DFB_INVARG; *ret_seconds = data->nb_frames / data->rate; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_SetPlaybackFlags( IDirectFBVideoProvider *thiz, DFBVideoProviderPlaybackFlags flags ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (flags & ~DVPLAY_LOOPING) return DFB_UNSUPPORTED; data->flags = flags; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_SetSpeed( IDirectFBVideoProvider *thiz, double multiplier ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (multiplier < 0.0 || multiplier > 64.0) return DFB_UNSUPPORTED; if (multiplier == data->speed) return DFB_OK; direct_mutex_lock( &data->lock ); if (multiplier > data->speed && data->status != DVSTATE_FINISHED) direct_waitqueue_signal( &data->cond ); data->speed = multiplier; dispatch_event( data, DVPET_SPEEDCHANGE ); direct_mutex_unlock( &data->lock ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_GetSpeed( IDirectFBVideoProvider *thiz, double *ret_multiplier ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_multiplier) return DFB_INVARG; *ret_multiplier = data->speed; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_CreateEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer **ret_interface ) { DFBResult ret; IDirectFBEventBuffer *buffer; DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; ret = data->idirectfb->CreateEventBuffer( data->idirectfb, &buffer ); if (ret) return ret; ret = thiz->AttachEventBuffer( thiz, buffer ); buffer->Release( buffer ); *ret_interface = (ret == DFB_OK) ? buffer : NULL; return ret; } static DFBResult IDirectFBVideoProvider_DFVFF_AttachEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ) { DFBResult ret; EventLink *link; DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!buffer) return DFB_INVARG; ret = buffer->AddRef( buffer ); if (ret) return ret; link = D_MALLOC( sizeof(EventLink) ); if (!link) { buffer->Release( buffer ); return D_OOM(); } link->buffer = buffer; direct_mutex_lock( &data->events_lock ); direct_list_append( &data->events, &link->link ); direct_mutex_unlock( &data->events_lock ); return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_EnableEvents( IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (mask & ~DVPET_ALL) return DFB_INVARG; data->events_mask |= mask; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_DisableEvents( IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (mask & ~DVPET_ALL) return DFB_INVARG; data->events_mask &= ~mask; return DFB_OK; } static DFBResult IDirectFBVideoProvider_DFVFF_DetachEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ) { DFBResult ret = DFB_ITEMNOTFOUND; EventLink *link; DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); if (!buffer) return DFB_INVARG; direct_mutex_lock( &data->events_lock ); direct_list_foreach (link, data->events) { if (link->buffer == buffer) { direct_list_remove( &data->events, &link->link ); link->buffer->Release( link->buffer ); D_FREE( link ); ret = DFB_OK; break; } } direct_mutex_unlock( &data->events_lock ); return ret; } static DFBResult IDirectFBVideoProvider_DFVFF_SetDestination( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ) { DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, thiz, dest_rect->x, dest_rect->y, dest_rect->w, dest_rect->h ); if (!dest_rect) return DFB_INVARG; if (dest_rect->w < 1 || dest_rect->h < 1) return DFB_INVARG; data->rect = *dest_rect; return DFB_OK; } /**********************************************************************************************************************/ static DFBResult Probe( IDirectFBVideoProvider_ProbeContext *ctx ) { /* Check the magic. */ if (!strncmp( (const char*) ctx->header, "DFVFF", 5 )) return DFB_OK; return DFB_UNSUPPORTED; } static DFBResult Construct( IDirectFBVideoProvider *thiz, IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb ) { DFBResult ret; DirectFile fd; int len; const DFVFFHeader *header; void *ptr; void *chunk = NULL; IDirectFBDataBuffer_data *buffer_data = buffer->priv; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBVideoProvider_DFVFF ) D_DEBUG_AT( VideoProvider_DFVFF, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->idirectfb = idirectfb; if (buffer_data->buffer) { len = -1; ptr = buffer_data->buffer; } else if (buffer_data->filename) { DirectFileInfo info; /* Open the file. */ ret = direct_file_open( &fd, buffer_data->filename, O_RDONLY, 0 ); if (ret) { D_DERROR( ret, "VideoProvider/DFVFF: Failed to open file '%s'!\n", buffer_data->filename ); len = 0; goto error; } /* Query file size. */ ret = direct_file_get_info( &fd, &info ); if (ret) { D_DERROR( ret, "VideoProvider/DFVFF: Failed during get_info() of '%s'!\n", buffer_data->filename ); len = -1; goto error; } else len = info.size; /* Memory-mapped file. */ ret = direct_file_map( &fd, NULL, 0, len, DFP_READ, &ptr ); if (ret) { D_DERROR( ret, "VideoProvider/DFVFF: Failed during mmap() of '%s'!\n", buffer_data->filename ); goto error; } direct_file_close( &fd ); } else { unsigned int size = 0; len = 0; while (1) { unsigned int bytes; chunk = D_REALLOC( chunk, size + 4096 ); if (!chunk) { ret = D_OOM(); goto error; } buffer->WaitForData( buffer, 4096 ); if (buffer->GetData( buffer, 4096, chunk + size, &bytes )) break; size += bytes; } if (!size) { ret = DFB_IO; goto error; } ptr = chunk; } header = ptr; data->ptr = ptr; data->len = len; data->desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_COLORSPACE; data->desc.width = header->width; data->desc.height = header->height; data->desc.pixelformat = header->format; data->desc.colorspace = header->colorspace; data->rate = (double) header->framerate_num / header->framerate_den; data->status = DVSTATE_STOP; data->speed = 1.0; data->frame_size = DFB_BYTES_PER_LINE( data->desc.pixelformat, data->desc.width ) * DFB_PLANE_MULTIPLY( data->desc.pixelformat, data->desc.height ); data->nb_frames = (data->len - sizeof(DFVFFHeader)) / data->frame_size; data->events_mask = DVPET_ALL; direct_mutex_init( &data->events_lock ); direct_mutex_init( &data->lock ); direct_waitqueue_init( &data->cond ); thiz->AddRef = IDirectFBVideoProvider_DFVFF_AddRef; thiz->Release = IDirectFBVideoProvider_DFVFF_Release; thiz->GetCapabilities = IDirectFBVideoProvider_DFVFF_GetCapabilities; thiz->GetSurfaceDescription = IDirectFBVideoProvider_DFVFF_GetSurfaceDescription; thiz->GetStreamDescription = IDirectFBVideoProvider_DFVFF_GetStreamDescription; thiz->PlayTo = IDirectFBVideoProvider_DFVFF_PlayTo; thiz->Stop = IDirectFBVideoProvider_DFVFF_Stop; thiz->GetStatus = IDirectFBVideoProvider_DFVFF_GetStatus; thiz->SeekTo = IDirectFBVideoProvider_DFVFF_SeekTo; thiz->GetPos = IDirectFBVideoProvider_DFVFF_GetPos; thiz->GetLength = IDirectFBVideoProvider_DFVFF_GetLength; thiz->SetPlaybackFlags = IDirectFBVideoProvider_DFVFF_SetPlaybackFlags; thiz->SetSpeed = IDirectFBVideoProvider_DFVFF_SetSpeed; thiz->GetSpeed = IDirectFBVideoProvider_DFVFF_GetSpeed; thiz->CreateEventBuffer = IDirectFBVideoProvider_DFVFF_CreateEventBuffer; thiz->AttachEventBuffer = IDirectFBVideoProvider_DFVFF_AttachEventBuffer; thiz->EnableEvents = IDirectFBVideoProvider_DFVFF_EnableEvents; thiz->DisableEvents = IDirectFBVideoProvider_DFVFF_DisableEvents; thiz->DetachEventBuffer = IDirectFBVideoProvider_DFVFF_DetachEventBuffer; thiz->SetDestination = IDirectFBVideoProvider_DFVFF_SetDestination; return DFB_OK; error: if (len) direct_file_close( &fd ); if (chunk) D_FREE( chunk ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ================================================ FILE: interfaces/IDirectFBVideoProvider/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA library('idirectfbvideoprovider_dfvff', 'idirectfbvideoprovider_dfvff.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'interfaces/IDirectFBVideoProvider', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-interface-videoprovider_dfvff', variables: 'moduledir=' + moduledir, name: 'DirectFB-interface-videoprovider_dfvff', description: 'DFVFF video provider', libraries_private: ['-L${moduledir}/interfaces/IDirectFBVideoProvider', '-Wl,--whole-archive -lidirectfbvideoprovider_dfvff -Wl,--no-whole-archive']) endif ================================================ FILE: interfaces/IDirectFBWindows/idirectfbwindows_default.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include D_DEBUG_DOMAIN( IDirectFBWindows_default, "IDirectFBWindows/Default", "Default Windows Watcher" ); static DirectResult Probe ( void *ctx ); static DirectResult Construct( IDirectFBWindows *thiz, CoreDFB *core ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBWindows, default ) /**********************************************************************************************************************/ typedef struct { DirectLink link; DFBWindowsWatcher watcher; void *context; Reaction reactions[CORE_WM_NUM_CHANNELS]; } RegisteredWatcher; typedef struct { int ref; /* reference counter */ CoreDFB *core; DirectLink *watchers; } IDirectFBWindows_data; #define WM_ATTACH( Func, CHANNEL ) \ do { \ if (watcher->Func) { \ ret = dfb_wm_attach( data->core, CORE_WM_##CHANNEL, IDirectFBWindows_WM_Reaction_##Func, registered, \ ®istered->reactions[CORE_WM_##CHANNEL] ); \ if (ret) { \ D_DERROR( ret, "IDirectFBWindows/Default: Failed to attach CORE_WM_" #CHANNEL "!\n" ); \ goto error; \ } \ } \ } while (0) #define WM_DETACH() \ do { \ int i; \ for (i = CORE_WM_NUM_CHANNELS - 1; i >= 0 ; i--) { \ if (registered->reactions[i].func) \ dfb_wm_detach( data->core, ®istered->reactions[i] ); \ } \ } while (0) /**********************************************************************************************************************/ static ReactionResult IDirectFBWindows_WM_Reaction_WindowAdd( const void *msg_data, void *ctx ) { const CoreWM_WindowAdd *add = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, add, registered ); D_ASSERT( registered->watcher.WindowAdd != NULL ); registered->watcher.WindowAdd( registered->context, &add->info ); return RS_OK; } static ReactionResult IDirectFBWindows_WM_Reaction_WindowRemove( const void *msg_data, void *ctx ) { const CoreWM_WindowRemove *remove = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, remove, registered ); D_ASSERT( registered->watcher.WindowRemove != NULL ); registered->watcher.WindowRemove( registered->context, remove->window_id ); return RS_OK; } static ReactionResult IDirectFBWindows_WM_Reaction_WindowConfig( const void *msg_data, void *ctx ) { const CoreWM_WindowConfig *config = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, config, registered ); D_ASSERT( registered->watcher.WindowConfig != NULL ); registered->watcher.WindowConfig( registered->context, config->window_id, &config->config, config->flags ); return RS_OK; } static ReactionResult IDirectFBWindows_WM_Reaction_WindowState( const void *msg_data, void *ctx ) { const CoreWM_WindowState *state = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, state, registered ); D_ASSERT( registered->watcher.WindowState != NULL ); registered->watcher.WindowState( registered->context, state->window_id, &state->state ); return RS_OK; } static ReactionResult IDirectFBWindows_WM_Reaction_WindowRestack( const void *msg_data, void *ctx ) { const CoreWM_WindowRestack *restack = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, restack, registered ); D_ASSERT( registered->watcher.WindowRestack != NULL ); registered->watcher.WindowRestack( registered->context, restack->window_id, restack->index ); return RS_OK; } static ReactionResult IDirectFBWindows_WM_Reaction_WindowFocus( const void *msg_data, void *ctx ) { const CoreWM_WindowFocus *focus = msg_data; RegisteredWatcher *registered = ctx; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p, %p )\n", __FUNCTION__, focus, registered ); D_ASSERT( registered->watcher.WindowFocus != NULL ); registered->watcher.WindowFocus( registered->context, focus->window_id ); return RS_OK; } static void IDirectFBWindows_Destruct( IDirectFBWindows *thiz ) { IDirectFBWindows_data *data = thiz->priv; RegisteredWatcher *registered, *next; D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); direct_list_foreach_safe (registered, next, data->watchers) { WM_DETACH(); D_FREE( registered ); } DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBWindows_AddRef( IDirectFBWindows *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBWindows ) D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBWindows_Release( IDirectFBWindows *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBWindows ) D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBWindows_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBWindows_RegisterWatcher( IDirectFBWindows *thiz, const DFBWindowsWatcher *watcher, void *context ) { DFBResult ret; RegisteredWatcher *registered; DIRECT_INTERFACE_GET_DATA( IDirectFBWindows ) D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); if (!watcher) return DFB_INVARG; if (!watcher->WindowAdd && !watcher->WindowRemove && !watcher->WindowConfig && !watcher->WindowState && !watcher->WindowRestack && !watcher->WindowFocus) return DFB_INVARG; registered = D_CALLOC( 1, sizeof(RegisteredWatcher) ); if (!registered) return D_OOM(); registered->watcher = *watcher; registered->context = context; WM_ATTACH( WindowAdd, WINDOW_ADD ); WM_ATTACH( WindowRemove, WINDOW_REMOVE ); WM_ATTACH( WindowConfig, WINDOW_CONFIG ); WM_ATTACH( WindowState, WINDOW_STATE ); WM_ATTACH( WindowRestack, WINDOW_RESTACK ); WM_ATTACH( WindowFocus, WINDOW_FOCUS ); direct_list_append( &data->watchers, ®istered->link ); return DFB_OK; error: WM_DETACH(); D_FREE( registered ); return ret; } static DFBResult IDirectFBWindows_UnregisterWatcher( IDirectFBWindows *thiz, void *context ) { RegisteredWatcher *registered; DIRECT_INTERFACE_GET_DATA( IDirectFBWindows ) D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); direct_list_foreach (registered, data->watchers) { if (registered->context == context) { WM_DETACH(); direct_list_remove( &data->watchers, ®istered->link ); D_FREE( registered ); return DFB_OK; } } return DFB_ITEMNOTFOUND; } /**********************************************************************************************************************/ static DirectResult Probe( void *ctx ) { return DFB_OK; } static DirectResult Construct( IDirectFBWindows *thiz, CoreDFB *core ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBWindows ) D_DEBUG_AT( IDirectFBWindows_default, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->core = core; thiz->AddRef = IDirectFBWindows_AddRef; thiz->Release = IDirectFBWindows_Release; thiz->RegisterWatcher = IDirectFBWindows_RegisterWatcher; thiz->UnregisterWatcher = IDirectFBWindows_UnregisterWatcher; return DFB_OK; } ================================================ FILE: interfaces/IDirectFBWindows/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA library('idirectfbwindows_default', 'idirectfbwindows_default.c', build_rpath: get_option('prefix') / get_option('libdir'), dependencies: directfb_dep, install: true, install_dir: moduledir / 'interfaces/IDirectFBWindows', install_rpath: get_option('prefix') / get_option('libdir')) if get_option('default_library') == 'static' pkgconfig.generate(filebase: 'directfb-interface-windows_default', variables: 'moduledir=' + moduledir, name: 'DirectFB-interface-windows_default', description: 'Default windows watcher', libraries_private: ['-L${moduledir}/interfaces/IDirectFBWindows', '-Wl,--whole-archive -lidirectfbwindows_default -Wl,--no-whole-archive']) endif ================================================ FILE: lib/direct/atomic.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__ATOMIC_H__ #define __DIRECT__ATOMIC_H__ /**********************************************************************************************************************/ #define D_SYNC_ADD_AND_FETCH(ptr,value) \ __sync_add_and_fetch( ptr, value ) #endif ================================================ FILE: lib/direct/clock.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( Direct_Clock, "Direct/Clock", "Direct Clock time measurement" ); /**********************************************************************************************************************/ __dfb_no_instrument_function__ long long direct_clock_get_micros() { return direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); } __dfb_no_instrument_function__ long long direct_clock_get_millis() { return direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ) / 1000LL; } __dfb_no_instrument_function__ long long direct_clock_get_abs_micros() { return direct_clock_get_time( DIRECT_CLOCK_REALTIME ); } __dfb_no_instrument_function__ long long direct_clock_get_abs_millis() { return direct_clock_get_time( DIRECT_CLOCK_REALTIME ) / 1000LL; } ================================================ FILE: lib/direct/clock.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__CLOCK_H__ #define __DIRECT__CLOCK_H__ #include /**********************************************************************************************************************/ long long DIRECT_API direct_clock_get_abs_micros( void ); long long DIRECT_API direct_clock_get_abs_millis( void ); long long DIRECT_API direct_clock_get_micros ( void ); long long DIRECT_API direct_clock_get_millis ( void ); #endif ================================================ FILE: lib/direct/compiler.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__COMPILER_H__ #define __DIRECT__COMPILER_H__ #include /**********************************************************************************************************************/ #define D_FORMAT_PRINTF(n) __attribute__((__format__(__printf__,n,n+1))) #define D_FORMAT_VPRINTF(n) __attribute__((__format__(__printf__,n,0))) #define D_UNUSED __attribute__((unused)) #define __dfb_no_instrument_function__ __attribute__((no_instrument_function)) #if DIRECT_BUILD_CTORS #define __dfb_constructor__ __attribute__((constructor)) #define __dfb_destructor__ __attribute__((destructor)) #else #define __dfb_constructor__ #define __dfb_destructor__ #endif #endif ================================================ FILE: lib/direct/conf.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Config, "Direct/Config", "Direct Runtime Configuration options" ); /**********************************************************************************************************************/ static DirectConfig conf = { 0 }; DirectConfig *direct_config = &conf; const char *direct_config_usage = "libdirect options:\n" " disable-module= Suppress loading of this module\n" " module-dir= Override default module search directory\n" " memcpy= Skip memcpy() probing (help = show list)\n" " [no-]quiet Disable text output except debug/oom/ooshm messages or direct logs\n" " [no-]quiet= Only quiet certain message types (cumulative with 'quiet')\n" " [ info | warning | error | once | unimplemented | banner | bug ]\n" " [no-]fatal-messages Enable trap for all message types except banner and info\n" " [no-]fatal-messages= Enable trap for certain message types (cumulative with 'fatal-messages')\n" " [ warning | error | once | unimplemented | bug | oom | ooshm ]\n" " [no-]debug= Configure debug messages domain (if no debug level is specified, default = 8)\n" " debug-level= Set global debug messages level used by domains (default = 0 for no debug)\n" " Overload 'log-level', the maximum debug messages level is 9\n" " log= Configure direct logs domain (if no log level is specified, default = 6)\n" " log-level= Set global direct logs level used by domains (default = 6 for verbose)\n" " [ 0: none, 1: fatal, 2: error, 3: warning, 4: notice, 5: info, 6: verbose ]\n" " Overload 'debug-level'\n" " log-all Enable all debug messages and direct logs output\n" " log-none Disable all debug messages and direct logs output\n" " [no-]debugmem Enable memory allocation tracking\n" " [no-]trace Enable stack trace support\n" " [no-]nm-for-trace Enable running nm in a child process to retrieve symbols\n" " log-file= Write all messages to the specified file\n" " log-udp=: Send all messages via UDP to the specified host and port\n" " fatal-level= Abort on NONE, ASSERT (default) or ASSUME (incl. ASSERT)\n" " [no-]sighandler Enable signal handling (default enabled)\n" " [no-]sighandler-thread Enable signal handler thread (default enabled)\n" " dont-catch=[,...] Don't catch these signals\n" " [no-]thread-block-signals Block all signals in new threads (default enabled)\n" " thread-priority-scale=<100th> Apply scaling factor on thread type based priorities\n" " thread-priority= Set priority for the default thread type (default = 100)\n" " thread-scheduler= Select thread scheduler\n" " thread-stacksize= Set thread stack size (default = auto)\n" " default-interface-implementation=\n" " Probe interface_type/implementation_name first\n" " log-delay-rand-loops= Add random loops (of max loops) to central logging code for testing purpose\n" " log-delay-rand-us= Add random sleep (of max us) to central logging code for testing purpose\n" " log-delay-min-loops= Set minimum busy loops after each log message\n" " log-delay-min-us= Set minimum sleep after each log message\n" " delay-trap-ms= Set period to wait instead of raising\n" "\n"; static DirectMap *config_options = NULL; static bool config_option_compare( DirectMap *map, const void *key, void *object, void *ctx ); static unsigned int config_option_hash ( DirectMap *map, const void *key, void *ctx ); static DirectEnumerationResult config_option_free ( DirectMap *map, void *object, void *ctx ); /**********************************************************************************************************************/ void __D_conf_init() { direct_map_create( 123, config_option_compare, config_option_hash, NULL, &config_options ); direct_config->log_level = DIRECT_LOG_DEBUG_0; direct_config->trace = true; direct_config->fatal = DCFL_ASSERT; direct_config->sighandler = true; direct_config->sighandler_thread = true; direct_config->thread_block_signals = true; direct_config->thread_priority_scale = 100; char *args = direct_getenv( "D_ARGS" ); if (args) { args = D_STRDUP( args ); char *p = NULL, *r, *s = args; while ((r = direct_strtok_r( s, ",", &p ))) { char *v; direct_trim( &r ); v = strchr( r, '=' ); if (v) *v++ = 0; direct_config_set( r, v ); s = NULL; } D_FREE( args ); } } void __D_conf_deinit() { if (config_options) { direct_map_iterate( config_options, config_option_free, NULL ); direct_map_destroy( config_options ); config_options = NULL; } } /**********************************************************************************************************************/ #define OPTION_NAME_LENGTH 128 typedef struct { char name[OPTION_NAME_LENGTH]; DirectLink *values; } ConfigOption; typedef struct { DirectLink link; char *value; } ConfigOptionValue; static void config_option_value_add( ConfigOption *option, const char *name ) { ConfigOptionValue *value; if (!name) return; value = D_CALLOC( 1, sizeof(ConfigOptionValue) + strlen( name ) + 1 ); if (!value) { D_OOM(); return; } value->value = direct_snputs( (char*) (value + 1), name, OPTION_NAME_LENGTH ); direct_list_append( &option->values, &value->link ); } static ConfigOption* config_option_create( const char *name, const char *value ) { ConfigOption *option; option = D_CALLOC( 1, sizeof(ConfigOption) ); if (!option) { D_OOM(); return NULL; } direct_snputs( option->name, name, OPTION_NAME_LENGTH ); config_option_value_add( option, value ); direct_map_insert( config_options, name, option ); return option; } static bool config_option_compare( DirectMap *map, const void *key, void *object, void *ctx ) { const char *map_key = key; ConfigOption *map_entry = object; return strcmp( map_key, map_entry->name ) == 0; } static unsigned int config_option_hash( DirectMap *map, const void *key, void *ctx ) { size_t i = 0; unsigned int hash = 0; const char *map_key = key; while (map_key[i]) { hash = hash * 131 + map_key[i]; i++; } return hash; } static DirectEnumerationResult config_option_free( DirectMap *map, void *object, void *ctx ) { ConfigOption *option = object; ConfigOptionValue *value, *next; direct_list_foreach_safe (value, next, option->values) { D_FREE( value ); } D_FREE( option ); return DENUM_OK; } /**********************************************************************************************************************/ DirectResult direct_config_set( const char *name, const char *value ) { if (strcmp( name, "disable-module" ) == 0) { if (value) { int n = 0; while (direct_config->disable_module && direct_config->disable_module[n]) n++; direct_config->disable_module = D_REALLOC( direct_config->disable_module, sizeof(char*) * (n + 2) ); direct_config->disable_module[n] = D_STRDUP( value ); direct_config->disable_module[n+1] = NULL; } else { D_ERROR( "Direct/Config: '%s': No module name specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "module-dir" ) == 0) { if (value) { if (direct_config->module_dir) D_FREE( direct_config->module_dir ); direct_config->module_dir = D_STRDUP( value ); } else { D_ERROR( "Direct/Config: '%s': No directory name specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "memcpy" ) == 0) { if (value) { if (direct_config->memcpy) D_FREE( direct_config->memcpy ); direct_config->memcpy = D_STRDUP( value ); } else { D_ERROR( "Direct/Config: '%s': No method specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "quiet" ) == 0 || strcmp( name, "no-quiet" ) == 0) { /* Enable/disable all at once by default. */ DirectMessageType type = DMT_ALL; /* Find out the specific message type being configured. */ if (value) { if (!strcmp( value, "info" )) type = DMT_INFO; else if (!strcmp( value, "warning" )) type = DMT_WARNING; else if (!strcmp( value, "error" )) type = DMT_ERROR; else if (!strcmp( value, "once" )) type = DMT_ONCE; else if (!strcmp( value, "unimplemented" )) type = DMT_UNIMPLEMENTED; else if (!strcmp( value, "banner" )) type = DMT_BANNER; else if (!strcmp( value, "bug" )) type = DMT_BUG; else { D_ERROR( "Direct/Config: '%s': Unknown message type '%s'!\n", name, value ); return DR_INVARG; } } /* Set/clear the corresponding flag in the configuration. */ if (name[0] == 'q') D_FLAGS_SET( direct_config->quiet, type ); else D_FLAGS_CLEAR( direct_config->quiet, type ); } else if (strcmp( name, "fatal-messages" ) == 0 || strcmp( name, "no-fatal-messages" ) == 0) { /* Enable/disable all at once by default. */ DirectMessageType type = DMT_ALL & ~(DMT_BANNER | DMT_INFO); /* Find out the specific message type being configured. */ if (value) { if (!strcmp( value, "warning" )) type = DMT_WARNING; else if (!strcmp( value, "error" )) type = DMT_ERROR; else if (!strcmp( value, "once" )) type = DMT_ONCE; else if (!strcmp( value, "unimplemented" )) type = DMT_UNIMPLEMENTED; else if (!strcmp( value, "bug" )) type = DMT_BUG; else if (!strcmp( value, "oom" )) type = DMT_OOM; else if (!strcmp( value, "ooshm" )) type = DMT_OOSHM; else { D_ERROR( "Direct/Config: '%s': Unknown message type '%s'!\n", name, value ); return DR_INVARG; } } /* Set/clear the corresponding flag in the configuration. */ if (name[0] == 'f') D_FLAGS_SET( direct_config->fatal_messages, type ); else D_FLAGS_CLEAR( direct_config->fatal_messages, type ); } else if (strcmp( name, "no-fatal-messages" ) == 0) { direct_config->fatal_messages = DMT_NONE; } else if (strcmp( name, "debug" ) == 0) { if (value) { DirectLogDomainConfig config = { 0 }; if (value[0] && value[1] == ':') { config.level = value[0] - '0' + DIRECT_LOG_DEBUG_0; value += 2; } else config.level = DIRECT_LOG_DEBUG; direct_log_domain_configure( value, &config ); } else { D_ERROR( "Direct/Config: '%s': No domain specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "no-debug" ) == 0) { if (value) { DirectLogDomainConfig config = { 0 }; config.level = DIRECT_LOG_DEBUG_0; direct_log_domain_configure( value, &config ); } else { D_ERROR( "Direct/Config: '%s': No domain specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "debug-level" ) == 0) { if (value) { char level; if (sscanf( value, "%c", &level ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_level = level - '0' + DIRECT_LOG_DEBUG_0; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log" ) == 0) { if (value) { DirectLogDomainConfig config = { 0 }; if (value[0] && value[1] == ':') { config.level = value[0] - '0'; value += 2; } else config.level = DIRECT_LOG_VERBOSE; direct_log_domain_configure( value, &config ); } else { D_ERROR( "Direct/Config: '%s': No domain specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-level" ) == 0) { if (value) { char level; if (sscanf( value, "%c", &level ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_level = level - '0'; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-all" ) == 0) { direct_config->log_all = true; } else if (strcmp( name, "log-none" ) == 0) { direct_config->log_none = true; } else if (strcmp( name, "debugmem" ) == 0) { direct_config->debugmem = true; } else if (strcmp( name, "no-debugmem" ) == 0) { direct_config->debugmem = false; } else if (strcmp( name, "trace" ) == 0) { direct_config->trace = true; } else if (strcmp( name, "no-trace" ) == 0) { direct_config->trace = false; } else if (strcmp( name, "nm-for-trace" ) == 0) { direct_config->nm_for_trace = true; } else if (strcmp( name, "no-nm-for-trace" ) == 0) { direct_config->nm_for_trace = false; } else if (strcmp( name, "log-file" ) == 0 || strcmp( name, "log-udp" ) == 0) { if (value) { DirectResult ret; DirectLog *log; ret = direct_log_create( strcmp( name, "log-udp" ) ? DLT_FILE : DLT_UDP, value, &log ); if (ret) return ret; if (direct_config->log) direct_log_destroy( direct_config->log ); direct_config->log = log; direct_log_set_default( log ); } else { if (strcmp( name, "log-udp" )) D_ERROR( "Direct/Config: '%s': No file name specified!\n", name ); else D_ERROR( "Direct/Config: '%s': No host and port specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "fatal-level" ) == 0) { if (value) { if (!strcasecmp( value, "none" )) direct_config->fatal = DCFL_NONE; else if (!strcasecmp( value, "assert" )) direct_config->fatal = DCFL_ASSERT; else if (!strcasecmp( value, "assume" )) direct_config->fatal = DCFL_ASSUME; else { D_ERROR( "Direct/Config: '%s': Unknown level specified (use 'none', 'assert', 'assume')!\n", name ); return DR_INVARG; } } else { D_ERROR( "Direct/Config: '%s': No fatal level specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "sighandler" ) == 0) { direct_config->sighandler = true; } else if (strcmp( name, "no-sighandler" ) == 0) { direct_config->sighandler = false; } else if (strcmp( name, "sighandler-thread" ) == 0) { direct_config->sighandler_thread = true; } else if (strcmp( name, "no-sighandler-thread" ) == 0) { direct_config->sighandler_thread = false; } else if (strcmp( name, "dont-catch" ) == 0) { if (value) { char *signals = D_STRDUP( value ); char *p = NULL, *r, *s = signals; while ((r = direct_strtok_r( s, ",", &p ))) { char *error; unsigned long signum; direct_trim( &r ); signum = strtoul( r, &error, 10 ); if (*error) { D_ERROR( "Direct/Config: '%s': Error in number at '%s'!\n", name, error ); D_FREE( signals ); return DR_INVARG; } sigaddset( &direct_config->dont_catch, signum ); s = NULL; } D_FREE( signals ); } else { D_ERROR( "Direct/Config: '%s': No signals specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "thread_block_signals" ) == 0) { direct_config->thread_block_signals = true; } else if (strcmp( name, "no-thread_block_signals" ) == 0) { direct_config->thread_block_signals = false; } else if (strcmp( name, "thread-priority-scale" ) == 0) { if (value) { int scale; if (sscanf( value, "%d", &scale ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->thread_priority_scale = scale; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "thread-priority" ) == 0) { if (value) { int priority; if (sscanf( value, "%d", &priority ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->thread_priority = priority; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "thread-scheduler" ) == 0) { if (value) { if (!strcmp( value, "other" )) direct_config->thread_scheduler = DCTS_OTHER; else if (!strcmp( value, "fifo" )) direct_config->thread_scheduler = DCTS_FIFO; else if (!strcmp( value, "rr" )) direct_config->thread_scheduler = DCTS_RR; else if (!strcmp( value, "sporadic" )) direct_config->thread_scheduler = DCTS_SPORADIC; else { D_ERROR( "Direct/Config: '%s': Unknown scheduler '%s'!\n", name, value ); return DR_INVARG; } } else { D_ERROR( "Direct/Config: '%s': No thread scheduler specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "thread-stacksize" ) == 0) { if (value) { int size; if (sscanf( value, "%d", &size ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->thread_stack_size = size; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "default-interface-implementation" ) == 0) { if (value) { char itype[255]; char *iname = 0; int n = 0; while (direct_config->default_interface_implementation_types && direct_config->default_interface_implementation_types[n]) n++; direct_config->default_interface_implementation_types = D_REALLOC( direct_config->default_interface_implementation_types, sizeof(char*) * (n + 2) ); direct_config->default_interface_implementation_names = D_REALLOC( direct_config->default_interface_implementation_names, sizeof(char*) * (n + 2) ); iname = strstr( value, "/" ); if (!iname) { D_ERROR( "Direct/Config: '%s': No interface/implementation specified!\n", name ); return DR_INVARG; } if (iname <= value) { D_ERROR( "Direct/Config: '%s': No interface specified!\n", name ); return DR_INVARG; } if (strlen( iname ) < 2) { D_ERROR( "Direct/Config: '%s': No implementation specified!\n", name ); return DR_INVARG; } direct_snputs( itype, value, iname - value + 1 ); direct_config->default_interface_implementation_types[n] = D_STRDUP( itype ); direct_config->default_interface_implementation_types[n+1] = NULL; direct_config->default_interface_implementation_names[n] = D_STRDUP( iname + 1 ); direct_config->default_interface_implementation_names[n+1] = NULL; } else { D_ERROR( "Direct/Config: '%s': No interface/implementation specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-delay-rand-loops" ) == 0) { if (value) { int max; if (sscanf( value, "%d", &max ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_delay_rand_loops = max; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-delay-rand-us" ) == 0) { if (value) { int max; if (sscanf( value, "%d", &max ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_delay_rand_us = max; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-delay-min-loops" ) == 0) { if (value) { int min; if (sscanf( value, "%d", &min ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_delay_min_loops = min; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "log-delay-min-us" ) == 0) { if (value) { int min; if (sscanf( value, "%d", &min ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->log_delay_min_us = min; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "delay-trap-ms" ) == 0) { if (value) { int ms; if (sscanf( value, "%d", &ms ) < 1) { D_ERROR( "Direct/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } direct_config->delay_trap_ms = ms; } else { D_ERROR( "Direct/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else { ConfigOption *option = direct_map_lookup( config_options, name ); if (option) config_option_value_add( option, value ); else config_option_create( name, value ); } D_DEBUG_AT( Direct_Config, "Set %s '%s'\n", name, value ?: "" ); return DR_OK; } DirectResult direct_config_get( const char *name, char **values, const int values_len, int *ret_num ) { ConfigOption *option; ConfigOptionValue *value; int num = 0; option = direct_map_lookup( config_options, name ); if (!option) return DR_ITEMNOTFOUND; *ret_num = 0; if (!option->values) return DR_OK; direct_list_foreach (value, option->values) { if (num >= values_len) break; values[num++] = value->value; } *ret_num = num; return DR_OK; } bool direct_config_has_name( const char *name ) { ConfigOption *option; option = direct_map_lookup( config_options, name ); if (!option) return false; return true; } const char * direct_config_get_value( const char *name ) { ConfigOption *option; ConfigOptionValue *value; option = direct_map_lookup( config_options, name ); if (!option || !option->values) return NULL; value = direct_list_get_last( option->values ); D_ASSERT( value != NULL ); return value->value; } long long direct_config_get_int_value( const char *name ) { return direct_config_get_int_value_with_default( name, 0 ); } long long direct_config_get_int_value_with_default( const char *name, long long def ) { ConfigOption *option; ConfigOptionValue *value; option = direct_map_lookup( config_options, name ); if (!option || !option->values) return def; value = direct_list_get_last( option->values ); D_ASSERT( value != NULL ); return atoll( value->value ); } ================================================ FILE: lib/direct/conf.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__CONF_H__ #define __DIRECT__CONF_H__ #include /**********************************************************************************************************************/ typedef enum { DCFL_NONE = 0x00000000, /* None is fatal. */ DCFL_ASSERT = 0x00000001, /* ASSERT is fatal. */ DCFL_ASSUME = 0x00000002 /* ASSERT and ASSUME are fatal. */ } DirectConfigFatalLevel; typedef enum { DCTS_OTHER = 0x00000000, /* Other scheduling. */ DCTS_FIFO = 0x00000001, /* First in, first out scheduling. */ DCTS_RR = 0x00000002, /* Round-robin scheduling. */ DCTS_SPORADIC = 0x00000003 /* Sporadic scheduling. */ } DirectConfigThreadScheduler; typedef enum { DMT_NONE = 0x00000000, /* No message type. */ DMT_BANNER = 0x00000001, /* Startup banner. */ DMT_INFO = 0x00000002, /* Info messages. */ DMT_WARNING = 0x00000004, /* Warnings. */ DMT_ERROR = 0x00000008, /* Error messages: regular, bugs, system call errors, dlopen errors. */ DMT_UNIMPLEMENTED = 0x00000010, /* Messages notifying unimplemented functionality. */ DMT_ONCE = 0x00000020, /* One-shot messages. */ DMT_BUG = 0x00000080, /* A bug occurred. */ DMT_OOM = 0x00000100, /* Out of memory. */ DMT_OOSHM = 0x00000200, /* Out of shared memory. */ DMT_ALL = 0x000003BF /* All types. */ } DirectMessageType; typedef struct { char **disable_module; char *module_dir; char *memcpy; DirectMessageType quiet; DirectMessageType fatal_messages; DirectLogLevel log_level; bool log_all; bool log_none; bool debugmem; bool trace; bool nm_for_trace; DirectLog *log; DirectConfigFatalLevel fatal; bool sighandler; bool sighandler_thread; sigset_t dont_catch; bool thread_block_signals; int thread_priority_scale; int thread_priority; DirectConfigThreadScheduler thread_scheduler; int thread_stack_size; char **default_interface_implementation_types; char **default_interface_implementation_names; int log_delay_rand_loops; int log_delay_rand_us; int log_delay_min_loops; int log_delay_min_us; int delay_trap_ms; } DirectConfig; /**********************************************************************************************************************/ extern DirectConfig DIRECT_API *direct_config; extern const char DIRECT_API *direct_config_usage; /* * Set indiviual option. */ DirectResult DIRECT_API direct_config_set ( const char *name, const char *value ); /* * Retrieve all values set on option 'name'. * Pass an array of char* pointers in 'values' and number of pointers in 'values_len'. * The actual returned number of values gets returned in 'ret_num'. * The returned pointers are not extra allocated so do not free them. */ DirectResult DIRECT_API direct_config_get ( const char *name, char **values, const int values_len, int *ret_num ); /* * Check for an occurrence of the passed option. */ bool DIRECT_API direct_config_has_name ( const char *name ); /* * Return the value for the last occurrence of the passed option's setting. */ const char DIRECT_API *direct_config_get_value ( const char *name ); /* * Return the integer value for the last occurrence of the passed option's setting. */ long long DIRECT_API direct_config_get_int_value ( const char *name ); long long DIRECT_API direct_config_get_int_value_with_default( const char *name, long long def ); /**********************************************************************************************************************/ void __D_conf_init ( void ); void __D_conf_deinit( void ); #endif ================================================ FILE: lib/direct/debug.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_TEXT #include #if DIRECT_BUILD_DEBUGS #include #include #include #include #endif /* DIRECT_BUILD_DEBUGS */ #endif /* DIRECT_BUILD_TEXT */ /**********************************************************************************************************************/ #if DIRECT_BUILD_TEXT __dfb_no_instrument_function__ void direct_debug_at_always( DirectLogDomain *domain, const char *format, ... ) { if (direct_config->log_level >= DIRECT_LOG_DEBUG) { va_list ap; va_start( ap, format ); direct_log_domain_vprintf( domain, DIRECT_LOG_NONE, format, ap ); va_end( ap ); } } #if DIRECT_BUILD_DEBUGS __dfb_no_instrument_function__ void direct_debug_log( DirectLogDomain *domain, unsigned int debug_level, const char *format, ... ) { va_list ap; debug_level += DIRECT_LOG_DEBUG_0; va_start( ap, format ); direct_log_domain_vprintf( domain, debug_level > DIRECT_LOG_DEBUG_9 ? DIRECT_LOG_DEBUG_9 : debug_level, format, ap ); va_end( ap ); } __dfb_no_instrument_function__ void direct_debug_at( DirectLogDomain *domain, const char *format, ... ) { va_list ap; va_start( ap, format ); direct_log_domain_vprintf( domain, DIRECT_LOG_DEBUG, format, ap ); va_end( ap ); } __dfb_no_instrument_function__ void direct_assertion( const char *exp, const char *func, const char *file, int line ) { long long millis = direct_clock_get_millis(); const char *name = direct_thread_self_name(); direct_log_printf( NULL, "(!) [%-15s %3lld.%03lld] (%5d) *** Assertion [%s] failed *** [%s:%d in %s()]\n", name ?: " NO NAME ", millis / 1000LL, millis % 1000LL, direct_gettid(), exp, file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal >= DCFL_ASSERT) direct_trap( "Assertion", SIGTRAP ); } __dfb_no_instrument_function__ void direct_assumption( const char *exp, const char *func, const char *file, int line ) { long long millis = direct_clock_get_millis(); const char *name = direct_thread_self_name(); direct_log_printf( NULL, "(!) [%-15s %3lld.%03lld] (%5d) *** Assumption [%s] failed *** [%s:%d in %s()]\n", name ?: " NO NAME ", millis / 1000LL, millis % 1000LL, direct_gettid(), exp, file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal >= DCFL_ASSUME) direct_trap( "Assumption", SIGTRAP ); } #else /* DIRECT_BUILD_DEBUGS */ void direct_debug_log( DirectLogDomain *domain, unsigned int debug_level, const char *format, ... ) { } void direct_debug_at( DirectLogDomain *domain, const char *format, ... ) { } void direct_assertion( const char *exp, const char *func, const char *file, int line ) { } void direct_assumption( const char *exp, const char *func, const char *file, int line ) { } #endif /* DIRECT_BUILD_DEBUGS */ #endif /* DIRECT_BUILD_TEXT */ ================================================ FILE: lib/direct/debug.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__DEBUG_H__ #define __DIRECT__DEBUG_H__ #include #if DIRECT_BUILD_TEXT #if !DIRECT_BUILD_DEBUGS #ifdef DIRECT_ENABLE_DEBUG #define DIRECT_MINI_DEBUG #endif #undef DIRECT_ENABLE_DEBUG #endif /* DIRECT_BUILD_DEBUGS */ #ifdef DIRECT_MINI_DEBUG #include #include #include #include #include #endif /* DIRECT_MINI_DEBUG */ #endif /* DIRECT_BUILD_TEXT */ /**********************************************************************************************************************/ #define D_DEBUG_DOMAIN(_identifier,_name,_description) \ static DirectLogDomain _identifier D_UNUSED = { \ _description, _name, sizeof(_name) - 1, 0, false, { DIRECT_LOG_NONE, 0 } \ } static __inline__ void direct_debug_config_domain( const char *name, bool enable ) { direct_log_domain_config_level( name, enable ? DIRECT_LOG_ALL : DIRECT_LOG_NONE ); } #if DIRECT_BUILD_TEXT void DIRECT_API direct_debug_at_always( DirectLogDomain *domain, const char *format, ... ) D_FORMAT_PRINTF(2); /* * debug level 1-9 (0 = verbose) */ void DIRECT_API direct_debug_log ( DirectLogDomain *domain, unsigned int debug_level, const char *format, ... ) D_FORMAT_PRINTF(3); void DIRECT_API direct_debug_at ( DirectLogDomain *domain, const char *format, ... ) D_FORMAT_PRINTF(2); void DIRECT_API direct_assertion ( const char *exp, const char *func, const char *file, int line ); void DIRECT_API direct_assumption ( const char *exp, const char *func, const char *file, int line ); #if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) #define D_DEBUG_ENABLED 1 #define D_DEBUG_LOG(d,l,...) \ do { \ direct_debug_log( &d, l, __VA_ARGS__ ); \ } while (0) #define D_DEBUG_AT(d,...) \ do { \ direct_debug_at( &d, __VA_ARGS__ ); \ } while (0) #define D_ASSERT(exp) \ do { \ if (!(exp)) \ direct_assertion( #exp, __FUNCTION__, __FILE__, __LINE__ ); \ } while (0) #define D_ASSUME(exp) \ do { \ if (!(exp)) \ direct_assumption( #exp, __FUNCTION__, __FILE__, __LINE__ ); \ } while (0) #elif defined(DIRECT_MINI_DEBUG) /* * mini debug mode */ #define D_DEBUG_ENABLED 2 #define D_DEBUG_LOG(d,l,...) \ do { \ if (direct_config->log_level >= DIRECT_LOG_DEBUG) \ direct_debug_at_always( &d, __VA_ARGS__ ); \ } while (0) #define D_DEBUG_AT(d,...) \ do { \ if (direct_config->log_level >= DIRECT_LOG_DEBUG) \ direct_debug_at_always( &d, __VA_ARGS__ ); \ } while (0) #define D_CHECK(exp,aa) \ do { \ if (!(exp)) { \ long long millis = direct_clock_get_millis(); \ const char *name = direct_thread_self_name(); \ \ direct_log_printf( NULL, \ "(!) [%-15s %3lld.%03lld] (%5d) *** " #aa " [%s] failed *** [%s:%d in %s()]\n", \ name ?: " NO NAME ", millis / 1000LL, millis % 1000LL, direct_gettid(), #exp, \ __FILE__, __LINE__, __FUNCTION__ ); \ \ direct_trace_print_stack( NULL ); \ } \ } while (0) #define D_ASSERT(exp) \ D_CHECK( exp, Assertion ) #define D_ASSUME(exp) \ D_CHECK( exp, Assumption ) #endif #endif /* DIRECT_BUILD_TEXT */ /* * Fallback definitions, e.g. without DIRECT_BUILD_TEXT or DIRECT_BUILD_DEBUG or DIRECT_ENABLE_DEBUG */ #ifndef D_DEBUG_ENABLED #define D_DEBUG_ENABLED 0 #endif #ifndef D_DEBUG_LOG #define D_DEBUG_LOG(d,l,...) do {} while (0) #endif #ifndef D_DEBUG_AT #define D_DEBUG_AT(d,...) do {} while (0) #endif #ifndef D_ASSERT #define D_ASSERT(exp) do {} while (0) #endif #ifndef D_ASSUME #define D_ASSUME(exp) do {} while (0) #endif /* * Magic Assertions & Utilities */ #if DIRECT_BUILD_DEBUGS #define D_MAGIC(spell) ( ( ((spell)[sizeof(spell)*8/9] << 24) | \ ((spell)[sizeof(spell)*7/9] << 16) | \ ((spell)[sizeof(spell)*6/9] << 8) | \ ((spell)[sizeof(spell)*5/9] ) ) ^ \ ( ((spell)[sizeof(spell)*4/9] << 24) | \ ((spell)[sizeof(spell)*3/9] << 16) | \ ((spell)[sizeof(spell)*2/9] << 8) | \ ((spell)[sizeof(spell)*1/9] ) ) ) #define D_MAGIC_CHECK(o,m) ((o) != NULL && (o)->magic == D_MAGIC(#m)) #define D_MAGIC_SET(o,m) do { \ D_ASSERT( (o) != NULL ); \ D_ASSUME( (o)->magic != D_MAGIC(#m) ); \ \ (o)->magic = D_MAGIC(#m); \ } while (0) #define D_MAGIC_SET_ONLY(o,m) do { \ D_ASSERT( (o) != NULL ); \ \ (o)->magic = D_MAGIC(#m); \ } while (0) #define D_MAGIC_ASSERT(o,m) do { \ D_ASSERT( (o) != NULL ); \ D_ASSERT( (o)->magic == D_MAGIC(#m) ); \ } while (0) #define D_MAGIC_ASSUME(o,m) do { \ D_ASSUME( (o) != NULL ); \ if (o) \ D_ASSUME( (o)->magic == D_MAGIC(#m) ); \ } while (0) #define D_MAGIC_ASSERT_IF(o,m) do { \ if (o) \ D_ASSERT( (o)->magic == D_MAGIC(#m) ); \ } while (0) #define D_MAGIC_CLEAR(o) do { \ D_ASSERT( (o) != NULL ); \ D_ASSUME( (o)->magic != 0 ); \ \ (o)->magic = 0; \ } while (0) #else /* DIRECT_BUILD_DEBUGS */ #define D_MAGIC_CHECK(o,m) ((o) != NULL) #define D_MAGIC_SET(o,m) do {} while (0) #define D_MAGIC_SET_ONLY(o,m) do {} while (0) #define D_MAGIC_ASSERT(o,m) do {} while (0) #define D_MAGIC_ASSUME(o,m) do {} while (0) #define D_MAGIC_ASSERT_IF(o,m) do {} while (0) #define D_MAGIC_CLEAR(o) do {} while (0) #endif /* DIRECT_BUILD_DEBUGS */ #define D_FLAGS_ASSERT(flags,f) D_ASSERT( D_FLAGS_ARE_IN( flags, f ) ) #endif ================================================ FILE: lib/direct/direct.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Main, "Direct/Main", "Direct Main initialization and shutdown" ); /**********************************************************************************************************************/ struct __D_DirectCleanupHandler { DirectLink link; int magic; DirectCleanupHandlerFunc func; void *ctx; }; /**********************************************************************************************************************/ static int refs; static DirectLink *handlers; static DirectMutex main_lock; /**********************************************************************************************************************/ void __D_direct_init() { direct_mutex_init( &main_lock ); } void __D_direct_deinit() { direct_print_memleaks(); direct_print_interface_leaks(); direct_mutex_deinit( &main_lock ); } /**********************************************************************************************************************/ DirectResult direct_initialize() { direct_clock_set_time( DIRECT_CLOCK_SESSION, 0 ); direct_mutex_lock( &main_lock ); D_DEBUG_AT( Direct_Main, "%s() called... (from %s)\n", __FUNCTION__, direct_trace_lookup_symbol_at( direct_trace_get_caller() ) ); if (refs++) { D_DEBUG_AT( Direct_Main, "...%d references now\n", refs ); direct_mutex_unlock( &main_lock ); return DR_OK; } else if (!direct_thread_self_name()) direct_thread_set_name( "Main Thread" ); D_DEBUG_AT( Direct_Main, "...first reference, initializing now\n" ); direct_signals_initialize(); direct_mutex_unlock( &main_lock ); return DR_OK; } DirectResult direct_shutdown() { direct_mutex_lock( &main_lock ); D_DEBUG_AT( Direct_Main, "%s() called... (from %s)\n", __FUNCTION__, direct_trace_lookup_symbol_at( direct_trace_get_caller() ) ); if (refs == 1) { D_DEBUG_AT( Direct_Main, "...shutting down now\n" ); direct_signals_shutdown(); D_DEBUG_AT( Direct_Main, " -> done\n" ); } else D_DEBUG_AT( Direct_Main, "...%d references left\n", refs - 1 ); refs--; direct_mutex_unlock( &main_lock ); return DR_OK; } static void direct_atexit_handler( void ) { DirectCleanupHandler *handler, *temp; direct_list_foreach_safe (handler, temp, handlers) { D_DEBUG_AT( Direct_Main, "Calling cleanup func %p( %p )...\n", handler->func, handler->ctx ); direct_list_remove( &handlers, &handler->link ); handler->func( handler->ctx ); D_MAGIC_CLEAR( handler ); D_FREE( handler ); } } DirectResult direct_cleanup_handler_add( DirectCleanupHandlerFunc func, void *ctx, DirectCleanupHandler **ret_handler ) { DirectCleanupHandler *handler; D_ASSERT( func != NULL ); D_ASSERT( ret_handler != NULL ); D_DEBUG_AT( Direct_Main, "Adding cleanup handler %p with context %p...\n", func, ctx ); handler = D_CALLOC( 1, sizeof(DirectCleanupHandler) ); if (!handler) { return DR_NOLOCALMEMORY; } handler->func = func; handler->ctx = ctx; D_MAGIC_SET( handler, DirectCleanupHandler ); direct_mutex_lock( &main_lock ); if (handlers == NULL) atexit( direct_atexit_handler ); direct_list_append( &handlers, &handler->link ); direct_mutex_unlock( &main_lock ); *ret_handler = handler; return DR_OK; } DirectResult direct_cleanup_handler_remove( DirectCleanupHandler *handler ) { D_MAGIC_ASSERT( handler, DirectCleanupHandler ); D_DEBUG_AT( Direct_Main, "Removing cleanup handler %p with context %p...\n", handler->func, handler->ctx ); /* Safety check, in case handler is removed from within itself being invoked. */ if (handler->link.prev) { direct_mutex_lock( &main_lock ); direct_list_remove( &handlers, &handler->link ); direct_mutex_unlock( &main_lock ); D_MAGIC_CLEAR( handler ); D_FREE( handler ); } return DR_OK; } ================================================ FILE: lib/direct/direct.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__DIRECT_H__ #define __DIRECT__DIRECT_H__ #include /**********************************************************************************************************************/ typedef void (*DirectCleanupHandlerFunc)( void *ctx ); /**********************************************************************************************************************/ DirectResult DIRECT_API direct_initialize ( void ); DirectResult DIRECT_API direct_shutdown ( void ); DirectResult DIRECT_API direct_cleanup_handler_add ( DirectCleanupHandlerFunc func, void *ctx, DirectCleanupHandler **ret_handler ); DirectResult DIRECT_API direct_cleanup_handler_remove( DirectCleanupHandler *handler ); /**********************************************************************************************************************/ void __D_direct_init ( void ); void __D_direct_deinit( void ); #endif ================================================ FILE: lib/direct/direct_result.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static const char *DirectResult__strings[DR__RESULT_END - DR__RESULT_BASE]; static DirectResultType DirectResult__type = { 0, 0, DR__RESULT_BASE, DirectResult__strings, D_ARRAY_SIZE(DirectResult__strings) }; /**********************************************************************************************************************/ void __D_direct_result_init() { DirectResult__strings[0] = "DirectResult"; DirectResult__strings[D_RESULT_INDEX(DR_FAILURE)] = "A general or unknown error occurred"; DirectResult__strings[D_RESULT_INDEX(DR_INIT)] = "A general initialization error occurred"; DirectResult__strings[D_RESULT_INDEX(DR_BUG)] = "Internal bug or inconsistency has been detected"; DirectResult__strings[D_RESULT_INDEX(DR_DEAD)] = "Interface has a zero reference counter (available in debug mode)"; DirectResult__strings[D_RESULT_INDEX(DR_UNSUPPORTED)] = "The requested operation or an argument is (currently) not supported"; DirectResult__strings[D_RESULT_INDEX(DR_UNIMPLEMENTED)] = "The requested operation is not implemented, yet"; DirectResult__strings[D_RESULT_INDEX(DR_ACCESSDENIED)] = "Access to the resource is denied"; DirectResult__strings[D_RESULT_INDEX(DR_INVAREA)] = "An invalid area has been specified or detected"; DirectResult__strings[D_RESULT_INDEX(DR_INVARG)] = "An invalid argument has been specified"; DirectResult__strings[D_RESULT_INDEX(DR_NOLOCALMEMORY)] = "There's not enough local system memory"; DirectResult__strings[D_RESULT_INDEX(DR_NOSHAREDMEMORY)] = "There's not enough shared system memory"; DirectResult__strings[D_RESULT_INDEX(DR_LOCKED)] = "The resource is (already) locked"; DirectResult__strings[D_RESULT_INDEX(DR_BUFFEREMPTY)] = "The buffer is empty"; DirectResult__strings[D_RESULT_INDEX(DR_FILENOTFOUND)] = "The specified file has not been found"; DirectResult__strings[D_RESULT_INDEX(DR_IO)] = "A general I/O error occurred"; DirectResult__strings[D_RESULT_INDEX(DR_BUSY)] = "The resource or device is busy"; DirectResult__strings[D_RESULT_INDEX(DR_NOIMPL)] = "No implementation for this interface or content type has been found"; DirectResult__strings[D_RESULT_INDEX(DR_TIMEOUT)] = "The operation timed out"; DirectResult__strings[D_RESULT_INDEX(DR_THIZNULL)] = "'thiz' pointer is NULL"; DirectResult__strings[D_RESULT_INDEX(DR_IDNOTFOUND)] = "No resource has been found by the specified id"; DirectResult__strings[D_RESULT_INDEX(DR_DESTROYED)] = "The requested object has been destroyed"; DirectResult__strings[D_RESULT_INDEX(DR_FUSION)] = "Internal fusion error detected, most likely related to IPC resources"; DirectResult__strings[D_RESULT_INDEX(DR_BUFFERTOOLARGE)] = "Buffer is too large"; DirectResult__strings[D_RESULT_INDEX(DR_INTERRUPTED)] = "The operation has been interrupted"; DirectResult__strings[D_RESULT_INDEX(DR_NOCONTEXT)] = "No context available"; DirectResult__strings[D_RESULT_INDEX(DR_TEMPUNAVAIL)] = "Temporarily unavailable"; DirectResult__strings[D_RESULT_INDEX(DR_LIMITEXCEEDED)] = "Attempted to exceed limit, i.e. any kind of maximum size, count etc"; DirectResult__strings[D_RESULT_INDEX(DR_NOSUCHMETHOD)] = "Requested method is not known"; DirectResult__strings[D_RESULT_INDEX(DR_NOSUCHINSTANCE)] = "Requested instance is not known"; DirectResult__strings[D_RESULT_INDEX(DR_ITEMNOTFOUND)] = "No such item found"; DirectResult__strings[D_RESULT_INDEX(DR_VERSIONMISMATCH)] = "Some versions didn't match"; DirectResult__strings[D_RESULT_INDEX(DR_EOF)] = "Reached end of file"; DirectResult__strings[D_RESULT_INDEX(DR_SUSPENDED)] = "The requested object is suspended"; DirectResult__strings[D_RESULT_INDEX(DR_INCOMPLETE)] = "The operation has been executed, but not completely"; DirectResult__strings[D_RESULT_INDEX(DR_NOCORE)] = "Core part not available"; DirectResult__strings[D_RESULT_INDEX(DR_SIGNALLED)] = "Received a signal, e.g. while waiting"; DirectResult__strings[D_RESULT_INDEX(DR_TASK_NOT_FOUND)] = "The corresponding task has not been found"; DirectResultTypeRegister( &DirectResult__type ); } void __D_direct_result_deinit() { DirectResultTypeUnregister( &DirectResult__type ); } ================================================ FILE: lib/direct/direct_result.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__DIRECT_RESULT_H__ #define __DIRECT__DIRECT_RESULT_H__ /**********************************************************************************************************************/ void __D_direct_result_init ( void ); void __D_direct_result_deinit( void ); #endif ================================================ FILE: lib/direct/filesystem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__FILESYSTEM_H__ #define __DIRECT__FILESYSTEM_H__ #include /**********************************************************************************************************************/ #endif ================================================ FILE: lib/direct/hash.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Hash, "Direct/Hash", "Direct Hash table" ); /**********************************************************************************************************************/ static const unsigned int primes[] = { 11, 19, 37, 73, 109, 163, 251, 367, 557, 823, 1237, 1861, 2777, 4177, 6247, 9371, 14057, 21089, 31627, 47431, 71143, 106721, 160073, 240101, 360163, 540217, 810343, 1215497, 1823231, 2734867, 4102283, 6153409, 9230113, 13845163, }; static const unsigned int nprimes = D_ARRAY_SIZE(primes); static unsigned int spaced_primes_closest( unsigned int num ) { unsigned int i; for (i = 0; i < nprimes; i++) if (primes[i] > num) return primes[i]; return primes[nprimes-1]; } #define DIRECT_HASH_MIN_SIZE 11 #define DIRECT_HASH_MAX_SIZE 13845163 /**********************************************************************************************************************/ static __inline__ int locate_key( const DirectHash *hash, unsigned long key ) { int pos; const DirectHashElement *element; D_MAGIC_ASSERT( hash, DirectHash ); D_ASSERT( hash->size > 0 ); D_ASSERT( hash->Elements != NULL ); pos = key % hash->size; element = &hash->Elements[pos]; while (element->value) { if (element->value != DIRECT_HASH_ELEMENT_REMOVED && element->key == key) return pos; if (++pos == hash->size) pos = 0; element = &hash->Elements[pos]; } return -1; } /**********************************************************************************************************************/ DirectResult direct_hash_create( int size, DirectHash **ret_hash ) { DirectHash *hash; hash = D_CALLOC( 1, sizeof(DirectHash) ); if (!hash) return D_OOM(); direct_hash_init( hash, size ); *ret_hash = hash; return DR_OK; } void direct_hash_destroy( DirectHash *hash ) { D_MAGIC_ASSERT( hash, DirectHash ); direct_hash_deinit( hash ); D_FREE( hash ); } void direct_hash_init( DirectHash *hash, int size ) { if (size < DIRECT_HASH_MIN_SIZE) size = DIRECT_HASH_MIN_SIZE; D_DEBUG_AT( Direct_Hash, "Creating hash table with initial capacity of %d...\n", size ); hash->size = size; hash->Elements = NULL; D_MAGIC_SET( hash, DirectHash ); } void direct_hash_deinit( DirectHash *hash ) { D_MAGIC_ASSERT( hash, DirectHash ); D_MAGIC_CLEAR( hash ); if (hash->Elements) { if (hash->disable_debugging_alloc) direct_free( hash->Elements ); else D_FREE( hash->Elements ); hash->Elements = NULL; } } int direct_hash_count( DirectHash *hash ) { D_MAGIC_ASSERT( hash, DirectHash ); return hash->count; } DirectResult direct_hash_insert( DirectHash *hash, unsigned long key, void *value ) { int pos; DirectHashElement *element; D_MAGIC_ASSERT( hash, DirectHash ); D_ASSERT( hash->size > 0 ); D_ASSERT( value != NULL ); if (!hash->Elements) { if (hash->disable_debugging_alloc) hash->Elements = direct_calloc( hash->size, sizeof(DirectHashElement) ); else hash->Elements = D_CALLOC( hash->size, sizeof(DirectHashElement) ); if (!hash->Elements) return D_OOM(); } if ((hash->count + hash->removed) > hash->size / 2) { int i, size; DirectHashElement *elements; size = spaced_primes_closest( hash->size ); if (size > DIRECT_HASH_MAX_SIZE) size = DIRECT_HASH_MAX_SIZE; if (size < DIRECT_HASH_MIN_SIZE) size = DIRECT_HASH_MIN_SIZE; D_DEBUG_AT( Direct_Hash, "Resizing from %d to %d... (count %d, removed %d)\n", hash->size, size, hash->count, hash->removed ); if (hash->disable_debugging_alloc) elements = direct_calloc( size, sizeof(DirectHashElement) ); else elements = D_CALLOC( size, sizeof(DirectHashElement) ); if (!elements) { D_WARN( "out of memory" ); return DR_NOLOCALMEMORY; } for (i = 0; i < hash->size; i++) { DirectHashElement *insertElement; element = &hash->Elements[i]; if (element->value && element->value != DIRECT_HASH_ELEMENT_REMOVED) { pos = element->key % size; insertElement = &elements[pos]; while (insertElement->value && insertElement->value != DIRECT_HASH_ELEMENT_REMOVED) { if (++pos == size) pos = 0; insertElement = &elements[pos]; } elements[pos] = *element; } } if (hash->disable_debugging_alloc) direct_free( hash->Elements ); else D_FREE( hash->Elements ); hash->size = size; hash->Elements = elements; hash->removed = 0; } pos = key % hash->size; D_DEBUG_AT( Direct_Hash, "Attempting to insert key 0x%08lx at position %d\n", key, pos ); element = &hash->Elements[pos]; while (element->value && element->value != DIRECT_HASH_ELEMENT_REMOVED) { if (element->key == key) { D_BUG( "key already exists" ); return DR_BUG; } if (++pos == hash->size) pos = 0; element = &hash->Elements[pos]; } if (element->value == DIRECT_HASH_ELEMENT_REMOVED) hash->removed--; element->key = key; element->value = value; hash->count++; D_DEBUG_AT( Direct_Hash, " -> inserted, count = %d, removed = %d, size = %d\n", hash->count, hash->removed, hash->size ); return DR_OK; } DirectResult direct_hash_remove( DirectHash *hash, unsigned long key ) { int pos; D_MAGIC_ASSERT( hash, DirectHash ); if (!hash->Elements) return DR_BUFFEREMPTY; pos = locate_key( hash, key ); if (pos == -1) { D_WARN( "key not found" ); return DR_ITEMNOTFOUND; } hash->Elements[pos].value = DIRECT_HASH_ELEMENT_REMOVED; hash->count--; hash->removed++; D_DEBUG_AT( Direct_Hash, "Removed key 0x%08lx at %d, count = %d, removed = %d, size = %d\n", key, pos, hash->count, hash->removed, hash->size ); return DR_OK; } void * direct_hash_lookup( const DirectHash *hash, unsigned long key ) { int pos; D_MAGIC_ASSERT( hash, DirectHash ); if (!hash->Elements) return NULL; pos = locate_key( hash, key ); return (pos != -1) ? hash->Elements[pos].value : NULL; } void direct_hash_iterate( DirectHash *hash, DirectHashIteratorFunc func, void *ctx ) { int i; D_MAGIC_ASSERT( hash, DirectHash ); if (!hash->Elements) return; for (i = 0; i < hash->size; i++) { DirectHashElement *element = &hash->Elements[i]; if (!element->value || element->value == DIRECT_HASH_ELEMENT_REMOVED) continue; if (!func( hash, element->key, element->value, ctx ) ) return; } } ================================================ FILE: lib/direct/hash.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__HASH_H__ #define __DIRECT__HASH_H__ #include /**********************************************************************************************************************/ typedef struct { unsigned long key; void *value; } DirectHashElement; struct __D_DirectHash { int magic; int size; int count; int removed; DirectHashElement *Elements; bool disable_debugging_alloc; }; /**********************************************************************************************************************/ #define DIRECT_HASH_INIT(__size,__disable_debugging_alloc) \ { \ 0x0b161321, \ (__size < 17 ? 17 : __size), \ 0, \ 0, \ NULL, \ __disable_debugging_alloc \ } #define DIRECT_HASH_ELEMENT_REMOVED ((void*) -1) #define DIRECT_HASH_ASSERT(hash) \ do { \ D_MAGIC_ASSERT( hash, DirectHash ); \ D_ASSERT( (hash)->size > 0 ); \ D_ASSERT( (hash)->Elements != NULL || (hash)->count == 0 ); \ D_ASSERT( (hash)->Elements != NULL || (hash)->removed == 0 ); \ D_ASSERT( (hash)->count + (hash)->removed < (hash)->size ); \ } while (0) typedef bool (*DirectHashIteratorFunc)( DirectHash *hash, unsigned long key, void *value, void *ctx ); /**********************************************************************************************************************/ /* * Full create including allocation ... */ DirectResult DIRECT_API direct_hash_create ( int size, DirectHash **ret_hash ); void DIRECT_API direct_hash_destroy( DirectHash *hash ); /* * ... or just initialization of static data. */ void DIRECT_API direct_hash_init ( DirectHash *hash, int size ); void DIRECT_API direct_hash_deinit ( DirectHash *hash ); int DIRECT_API direct_hash_count ( DirectHash *hash ); DirectResult DIRECT_API direct_hash_insert ( DirectHash *hash, unsigned long key, void *value ); DirectResult DIRECT_API direct_hash_remove ( DirectHash *hash, unsigned long key ); void DIRECT_API *direct_hash_lookup ( const DirectHash *hash, unsigned long key ); void DIRECT_API direct_hash_iterate( DirectHash *hash, DirectHashIteratorFunc func, void *ctx ); #endif ================================================ FILE: lib/direct/init.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include /**********************************************************************************************************************/ typedef void (*Func)( void ); static Func init_funcs[] = { __D_conf_init, __D_direct_init, __D_util_init, __D_result_init, __D_direct_result_init, __D_mem_init, __D_thread_init, __D_log_init, __D_log_domain_init, __D_interface_init, __D_interface_dbg_init, }; static Func deinit_funcs[] = { __D_interface_dbg_deinit, __D_interface_deinit, __D_log_domain_deinit, __D_thread_deinit, __D_mem_deinit, __D_direct_result_deinit, __D_result_deinit, __D_util_deinit, __D_direct_deinit, __D_log_deinit, __D_conf_deinit, }; /**********************************************************************************************************************/ __dfb_constructor__ void __D_init_all( void ) { size_t i; for (i = 0; i < D_ARRAY_SIZE(init_funcs); i++) init_funcs[i](); } __dfb_destructor__ void __D_deinit_all( void ) { size_t i; for (i = 0; i < D_ARRAY_SIZE(deinit_funcs); i++) deinit_funcs[i](); } ================================================ FILE: lib/direct/interface.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #if DIRECT_BUILD_DEBUGS #include #include #include #endif /* DIRECT_BUILD_DEBUGS */ D_DEBUG_DOMAIN( Direct_Interface, "Direct/Interface", "Direct Interface" ); /**********************************************************************************************************************/ typedef struct { DirectLink link; int magic; char *filename; void *module_handle; DirectInterfaceFuncs *funcs; const char *type; const char *implementation; int references; } DirectInterfaceImplementation; static DirectMutex implementations_mutex; static DirectLink *implementations; #if DIRECT_BUILD_DEBUGS typedef struct { const void *interface_ptr; char *name; char *what; const char *func; const char *file; int line; DirectTraceBuffer *trace; } InterfaceDesc; static int alloc_count; static int alloc_capacity; static InterfaceDesc *alloc_list; static DirectMutex alloc_lock; #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ void __D_interface_init() { direct_recursive_mutex_init( &implementations_mutex ); } void __D_interface_deinit() { direct_mutex_deinit( &implementations_mutex ); } #if DIRECT_BUILD_DEBUGS void __D_interface_dbg_init() { direct_mutex_init( &alloc_lock ); } void __D_interface_dbg_deinit() { direct_mutex_deinit( &alloc_lock ); } #else /* DIRECT_BUILD_DEBUGS */ void __D_interface_dbg_init() { } void __D_interface_dbg_deinit() { } #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ __attribute__((noinline)) void workaround_func( void ) { } static __inline__ int probe_interface( DirectInterfaceImplementation *impl, DirectInterfaceFuncs **funcs, const char *type, const char *implementation, DirectInterfaceProbeFunc probe, void *probe_ctx ) { if (type && strcmp( type, impl->type )) return 0; if (implementation && strcmp( implementation, impl->implementation )) return 0; D_DEBUG_AT( Direct_Interface, " -> probing '%s'...\n", impl->implementation ); if (probe && !probe( impl->funcs, probe_ctx )) return 0; *funcs = impl->funcs; impl->references++; return 1; } /**********************************************************************************************************************/ void DirectRegisterInterface( DirectInterfaceFuncs *funcs ) { DirectInterfaceImplementation *impl; D_DEBUG_AT( Direct_Interface, "%s( %p )\n", __FUNCTION__, funcs ); impl = D_CALLOC( 1, sizeof(DirectInterfaceImplementation) ); D_DEBUG_AT( Direct_Interface, " -> %p\n", impl ); impl->funcs = funcs; impl->type = funcs->GetType(); impl->implementation = funcs->GetImplementation(); D_MAGIC_SET( impl, DirectInterfaceImplementation ); D_DEBUG_AT( Direct_Interface, " -> %s | %s\n", impl->type, impl->implementation ); direct_mutex_lock( &implementations_mutex ); direct_list_prepend( &implementations, &impl->link ); direct_mutex_unlock( &implementations_mutex ); } void DirectUnregisterInterface( DirectInterfaceFuncs *funcs ) { DirectInterfaceImplementation *impl; D_DEBUG_AT( Direct_Interface, "%s( %p )\n", __FUNCTION__, funcs ); direct_mutex_lock( &implementations_mutex ); direct_list_foreach (impl, implementations) { D_MAGIC_ASSERT( impl, DirectInterfaceImplementation ); if (impl->funcs == funcs) { D_FREE( impl->filename ); direct_list_remove( &implementations, &impl->link ); break; } } direct_mutex_unlock( &implementations_mutex ); if (!impl) { D_BUG( "implementation not found" ); return; } D_DEBUG_AT( Direct_Interface, " -> %s | %s\n", impl->type, impl->implementation ); D_DEBUG_AT( Direct_Interface, " -> %p\n", impl ); D_MAGIC_CLEAR( impl ); D_FREE( impl ); } DirectResult DirectProbeInterface( DirectInterfaceFuncs *funcs, void *ctx ) { return (funcs->Probe( ctx ) == DR_OK); } DirectResult DirectGetInterface( DirectInterfaceFuncs **funcs, const char *type, const char *implementation, DirectInterfaceProbeFunc probe, void *probe_ctx ) { int n = 0; int idx = -1; #if DIRECT_BUILD_DYNLOAD DirectResult ret; int len; DirectDir dir; char *interface_dir; DirectEntry entry; const char *path; #endif /* DIRECT_BUILD_DYNLOAD */ DirectInterfaceImplementation *impl; D_DEBUG_AT( Direct_Interface, "%s( %p, '%s', '%s', %p, %p )\n", __FUNCTION__, funcs, type, implementation, probe, probe_ctx ); direct_mutex_lock( &implementations_mutex ); /* Check whether there is a default existing implementation set for the type in config. */ if (type && !implementation && direct_config->default_interface_implementation_types) { while (direct_config->default_interface_implementation_types[n]) { idx = -1; while (direct_config->default_interface_implementation_types[n]) { if (!strcmp( direct_config->default_interface_implementation_types[n++], type )) { idx = n - 1; break; } } if (idx < 0 && !direct_config->default_interface_implementation_types[n]) break; /* Check whether we have to check for a default implementation for the selected type. */ if (idx >= 0) { direct_list_foreach (impl, implementations) { if (probe_interface( impl, funcs, NULL, direct_config->default_interface_implementation_names[idx], probe, probe_ctx )) { D_INFO( "Direct/Interface: Using '%s' cached default implementation of '%s'\n", impl->implementation, impl->type ); direct_mutex_unlock( &implementations_mutex ); return DR_OK; } } } else break; } /* Check existing implementations without default. */ direct_list_foreach (impl, implementations) { if (probe_interface( impl, funcs, type, implementation, probe, probe_ctx )) { if (impl->references == 1) { D_INFO( "Direct/Interface: Using '%s' implementation of '%s'\n", impl->implementation, impl->type ); } direct_mutex_unlock( &implementations_mutex ); return DR_OK; } } } else { /* Check existing implementations without default. */ direct_list_foreach (impl, implementations) { if (probe_interface( impl, funcs, type, implementation, probe, probe_ctx )) { if (impl->references == 1) { D_INFO( "Direct/Interface: Using '%s' implementation of '%s'\n", impl->implementation, impl->type ); } direct_mutex_unlock( &implementations_mutex ); return DR_OK; } } } #if DIRECT_BUILD_DYNLOAD /* Try to load it dynamically. */ /* NULL type means we can't find plugin, so stop immediately. */ if (type == NULL) { direct_mutex_unlock( &implementations_mutex ); return DR_NOIMPL; } path = direct_config->module_dir; if (!path) path = MODULEDIR; len = strlen( path ) + strlen( "/interfaces/" ) + strlen( type ) + 1; interface_dir = alloca( len ); snprintf( interface_dir, len, "%s%sinterfaces/%s", path, path[strlen( path )-1] == '/' ? "" : "/", type ); ret = direct_dir_open( &dir, interface_dir ); if (ret) { D_DERROR( ret, "Direct/Interface: Could not open interface directory '%s'!\n", interface_dir ); direct_mutex_unlock( &implementations_mutex ); return ret; } if (direct_config->default_interface_implementation_types) { n = 0; while (direct_config->default_interface_implementation_types[n]) { idx = -1; while (direct_config->default_interface_implementation_types[n]) { if (!strcmp( direct_config->default_interface_implementation_types[n++], type )) { idx = n - 1; break; } } if (idx < 0 && !direct_config->default_interface_implementation_types[n]) break; /* Iterate directory. */ while (idx >= 0 && direct_dir_read( &dir, &entry ) == DR_OK) { char buf[PATH_MAX]; int entry_len = strlen( entry.name ); void *handle = NULL; DirectInterfaceImplementation *old_impl = (DirectInterfaceImplementation*) implementations; DirectInterfaceImplementation *test_impl; if (entry_len < 4 || entry.name[entry_len-2] != 's' || entry.name[entry_len-1] != 'o') continue; snprintf( buf, sizeof(buf), "%s/%s", interface_dir, entry.name ); /* Check if it got already loaded. */ direct_list_foreach (test_impl, implementations) { if (test_impl->filename && !strcmp( test_impl->filename, buf )) { impl = test_impl; handle = impl->module_handle; break; } } workaround_func(); /* Open it if needed and check. */ if (!handle) { handle = dlopen( buf, RTLD_NOW ); /* Check if it registered itself. */ if (handle) { impl = (DirectInterfaceImplementation*) implementations; if (old_impl == impl) { dlclose( handle ); continue; } /* Keep filename and module handle. */ impl->filename = D_STRDUP( buf ); impl->module_handle = handle; } } if (handle) { /* Check whether the dlopen'ed interface supports the required implementation. */ if (!strcasecmp( impl->implementation, direct_config->default_interface_implementation_names[idx] )) { if (probe_interface( impl, funcs, type, impl->implementation, probe, probe_ctx )) { if (impl->references == 1) D_INFO( "Direct/Interface: Loaded '%s' implementation of '%s'\n", impl->implementation, impl->type ); direct_dir_close( &dir ); direct_mutex_unlock( &implementations_mutex ); return DR_OK; } else continue; } else continue; } else D_DLERROR( "Direct/Interface: Unable to dlopen '%s'!\n", buf ); } direct_dir_rewind( &dir ); } } /* Iterate directory. */ while (direct_dir_read( &dir, &entry ) == DR_OK) { char buf[PATH_MAX]; int entry_len = strlen( entry.name ); void *handle = NULL; DirectInterfaceImplementation *old_impl = (DirectInterfaceImplementation*) implementations; DirectInterfaceImplementation *test_impl; if (entry_len < 4 || entry.name[entry_len-2] != 's' || entry.name[entry_len-1] != 'o') continue; snprintf( buf, sizeof(buf), "%s/%s", interface_dir, entry.name ); /* Check if it got already loaded. */ direct_list_foreach (test_impl, implementations) { if (test_impl->filename && !strcmp( test_impl->filename, buf )) { impl = test_impl; handle = impl->module_handle; break; } } workaround_func(); /* Open it if needed and check. */ if (!handle) { handle = dlopen( buf, RTLD_NOW ); /* Check if it registered itself. */ if (handle) { impl = (DirectInterfaceImplementation*) implementations; if (old_impl == impl) { dlclose( handle ); continue; } /* Keep filename and module handle. */ impl->filename = D_STRDUP( buf ); impl->module_handle = handle; } } if (handle) { if (probe_interface( impl, funcs, type, implementation, probe, probe_ctx )) { if (impl->references == 1) D_INFO( "Direct/Interface: Loaded '%s' implementation of '%s'\n", impl->implementation, impl->type ); direct_dir_close( &dir ); direct_mutex_unlock( &implementations_mutex ); return DR_OK; } else continue; } else D_DLERROR( "Direct/Interface: Unable to dlopen '%s'!\n", buf ); } direct_dir_close( &dir ); #endif /* DIRECT_BUILD_DYNLOAD */ direct_mutex_unlock( &implementations_mutex ); return DR_NOIMPL; } /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUGS void direct_print_interface_leaks() { int i; direct_mutex_lock( &alloc_lock ); if (alloc_count) { direct_log_printf( NULL, "Interface instances remaining (%d): \n", alloc_count ); for (i = 0; i < alloc_count; i++) { InterfaceDesc *desc = &alloc_list[i]; direct_log_printf( NULL, " - '%s' at %p (%s) allocated in %s (%s: %d)\n", desc->name, desc->interface_ptr, desc->what, desc->func, desc->file, desc->line ); if (desc->trace) direct_trace_print_stack( desc->trace ); } } direct_mutex_unlock( &alloc_lock ); } __dfb_no_instrument_function__ static InterfaceDesc * allocate_interface_desc( void ) { int cap = alloc_capacity; if (!cap) cap = 64; else if (cap == alloc_count) cap <<= 1; if (cap != alloc_capacity) { alloc_capacity = cap; alloc_list = D_REALLOC( alloc_list, sizeof(InterfaceDesc) * cap ); D_ASSERT( alloc_list != NULL ); } return &alloc_list[alloc_count++]; } __dfb_no_instrument_function__ static __inline__ void fill_interface_desc( InterfaceDesc *desc, const void *interface_ptr, const char *name, const char *func, const char *file, int line, const char *what, DirectTraceBuffer *trace ) { desc->interface_ptr = interface_ptr; desc->name = D_STRDUP( name ); desc->what = D_STRDUP( what ); desc->func = func; desc->file = file; desc->line = line; desc->trace = trace; } __dfb_no_instrument_function__ void direct_dbg_interface_add( const char *func, const char *file, int line, const char *what, const void *interface_ptr, const char *name ) { InterfaceDesc *desc; direct_mutex_lock( &alloc_lock ); desc = allocate_interface_desc(); fill_interface_desc( desc, interface_ptr, name, func, file, line, what, direct_trace_copy_buffer( NULL ) ); direct_mutex_unlock( &alloc_lock ); } __dfb_no_instrument_function__ void direct_dbg_interface_remove( const char *func, const char *file, int line, const char *what, const void *interface_ptr ) { int i; direct_mutex_lock( &alloc_lock ); for (i = 0; i < alloc_count; i++) { InterfaceDesc *desc = &alloc_list[i]; if (desc->interface_ptr == interface_ptr) { if (desc->trace) direct_trace_free_buffer( desc->trace ); D_FREE( desc->what ); D_FREE( desc->name ); if (i < --alloc_count) direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(InterfaceDesc) ); direct_mutex_unlock( &alloc_lock ); return; } } direct_mutex_unlock( &alloc_lock ); D_ERROR( "Direct/Interface: Unknown instance %p (%s) from [%s:%d in %s()]!\n", interface_ptr, what, file, line, func ); } #else /* DIRECT_BUILD_DEBUGS */ void direct_print_interface_leaks() { } __dfb_no_instrument_function__ void direct_dbg_interface_add( const char *func, const char *file, int line, const char *what, const void *interface_ptr, const char *name ) { } __dfb_no_instrument_function__ void direct_dbg_interface_remove( const char *func, const char *file, int line, const char *what, const void *interface_ptr ) { } #endif /* DIRECT_BUILD_DEBUGS */ ================================================ FILE: lib/direct/interface.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__INTERFACE_H__ #define __DIRECT__INTERFACE_H__ #include #include #include /**********************************************************************************************************************/ /* * Forward declaration macro for interfaces. */ #define D_DECLARE_INTERFACE(IFACE) \ typedef struct _##IFACE IFACE; /* * Macro for an interface definition. */ #define D_DEFINE_INTERFACE(IFACE,...) \ struct _##IFACE { \ void *priv; \ int magic; \ int refs; \ \ DirectResult (*AddRef) ( IFACE *thiz ); \ DirectResult (*Release)( IFACE *thiz ); \ \ __VA_ARGS__ \ }; /* * Declare base interface. */ D_DECLARE_INTERFACE( IAny ) /* * Define base interface. */ D_DEFINE_INTERFACE( IAny ) /* * Function type for probing of interface implementations. */ typedef DirectResult (*DirectInterfaceGenericProbeFunc) ( void *ctx, ... ); /* * Function type for initialization of interface instances. */ typedef DirectResult (*DirectInterfaceGenericConstructFunc)( void *interface_ptr, ... ); /* * Function table for interface implementations. */ typedef struct { const char *(*GetType) ( void ); const char *(*GetImplementation)( void ); DirectResult (*Allocate) ( void **interface_ptr ); DirectResult (*Deallocate) ( void *interface_ptr ); DirectInterfaceGenericProbeFunc Probe; DirectInterfaceGenericConstructFunc Construct; } DirectInterfaceFuncs; /* * Callback type for user probing interface implementations */ typedef DirectResult (*DirectInterfaceProbeFunc)( DirectInterfaceFuncs *impl, void *ctx ); /**********************************************************************************************************************/ /* * Called by implementation modules during 'dlopen'ing or at startup if linked into the executable. */ void DIRECT_API DirectRegisterInterface ( DirectInterfaceFuncs *funcs ); /* * Called at the executable termination. */ void DIRECT_API DirectUnregisterInterface ( DirectInterfaceFuncs *funcs ); /* * Default probe function. Calls "funcs->Probe(ctx)". * Can be used as the 'probe' argument to DirectGetInterface. * 'probe_ctx' should then be set to the interface specific probe context. */ DirectResult DIRECT_API DirectProbeInterface ( DirectInterfaceFuncs *funcs, void *ctx ); /* * Loads an interface of a specific 'type'. * Optionally an 'implementation' can be chosen. * A 'probe' function can be used to check available implementations. * After success 'funcs' is set. */ DirectResult DIRECT_API DirectGetInterface ( DirectInterfaceFuncs **funcs, const char *type, const char *implementation, DirectInterfaceProbeFunc probe, void *probe_ctx ); void DIRECT_API direct_print_interface_leaks( void ); void DIRECT_API direct_dbg_interface_add ( const char *func, const char *file, int line, const char *what, const void *interface_ptr, const char *name ); void DIRECT_API direct_dbg_interface_remove ( const char *func, const char *file, int line, const char *what, const void *interface_ptr ); /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) #define DIRECT_DBG_INTERFACE_ADD direct_dbg_interface_add #define DIRECT_DBG_INTERFACE_REMOVE direct_dbg_interface_remove #else /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ #define DIRECT_DBG_INTERFACE_ADD(func,file,line,what,interface,name) do {} while (0) #define DIRECT_DBG_INTERFACE_REMOVE(func,file,line,what,interface) do {} while (0) #endif /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ #define DIRECT_ALLOCATE_INTERFACE(p,i) \ do { \ (p) = (__typeof__(p)) D_CALLOC( 1, sizeof(i) ); \ if (p) { \ D_MAGIC_SET( (IAny*) (p), DirectInterface ); \ \ DIRECT_DBG_INTERFACE_ADD( __FUNCTION__, __FILE__, __LINE__, #p, p, #i ); \ } \ else \ D_OOM(); \ } while (0) #define DIRECT_ALLOCATE_INTERFACE_DATA(p,i) \ i##_data *data; \ \ D_MAGIC_ASSERT( (IAny*) (p), DirectInterface ); \ \ if (!(p)->priv) \ (p)->priv = D_CALLOC( 1, sizeof(i##_data) ); \ \ data = (i##_data*) ((p)->priv); #define DIRECT_DEALLOCATE_INTERFACE(p) \ D_MAGIC_ASSERT( (IAny*) (p), DirectInterface ); \ \ DIRECT_DBG_INTERFACE_REMOVE( __FUNCTION__, __FILE__, __LINE__, #p, p ); \ \ if ((p)->priv) { \ D_FREE( (p)->priv ); \ (p)->priv = NULL; \ } \ \ D_MAGIC_CLEAR( (IAny*) (p) ); \ \ D_FREE( (p) ); #define DIRECT_INTERFACE_GET_DATA(i) \ i##_data *data; \ \ if (!thiz) \ return DR_THIZNULL; \ \ D_MAGIC_ASSERT( (IAny*) thiz, DirectInterface ); \ \ data = (i##_data*) thiz->priv; \ \ if (!data) \ return DR_DEAD; /**********************************************************************************************************************/ void __D_interface_init ( void ); void __D_interface_deinit ( void ); void __D_interface_dbg_init ( void ); void __D_interface_dbg_deinit( void ); #endif ================================================ FILE: lib/direct/interface_implementation.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__INTERFACE_IMPLEMENTATION_H__ #define __DIRECT__INTERFACE_IMPLEMENTATION_H__ #include /**********************************************************************************************************************/ static const char *GetType ( void ); static const char *GetImplementation( void ); static DirectResult Allocate ( void **ret_interface ); static DirectResult Deallocate ( void *interface_ptr ); static DirectInterfaceFuncs interface_funcs = { GetType, GetImplementation, Allocate, Deallocate, (void*) Probe, (void*) Construct }; #define DIRECT_INTERFACE_IMPLEMENTATION(type,impl) \ \ static const char * \ GetType() \ { \ return #type; \ } \ \ static const char * \ GetImplementation() \ { \ return #impl; \ } \ \ static DirectResult \ Allocate( void **ret_interface ) \ { \ DIRECT_ALLOCATE_INTERFACE( *ret_interface, type ); \ return DR_OK; \ } \ \ static DirectResult \ Deallocate( void *interface_ptr ) \ { \ DIRECT_DEALLOCATE_INTERFACE( (IAny*) (interface_ptr) ); \ return DR_OK; \ } \ \ __dfb_constructor__ \ void \ type##_##impl##_ctor( void ) \ { \ DirectRegisterInterface( &interface_funcs ); \ } \ \ __dfb_destructor__ \ void \ type##_##impl##_dtor( void ) \ { \ DirectUnregisterInterface( &interface_funcs ); \ } #endif ================================================ FILE: lib/direct/list.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__LIST_H__ #define __DIRECT__LIST_H__ #include /**********************************************************************************************************************/ struct __D_DirectLink { int magic; DirectLink *next; DirectLink *prev; /* The prev pointer of the first element always points to the last element of the list, for fast appending. */ }; /**********************************************************************************************************************/ static __inline__ void direct_list_prepend( DirectLink **list, DirectLink *link ) { DirectLink *first; D_ASSERT( list != NULL ); D_ASSERT( link != NULL ); first = *list; link->next = first; if (first) { D_MAGIC_ASSERT( first, DirectLink ); link->prev = first->prev; first->prev = link; } else link->prev = link; *list = link; D_MAGIC_SET( link, DirectLink ); } static __inline__ void direct_list_append( DirectLink **list, DirectLink *link ) { DirectLink *first; D_ASSERT( list != NULL ); D_ASSERT( link != NULL ); first = *list; link->next = NULL; if (first) { DirectLink *last = first->prev; D_MAGIC_ASSERT( first, DirectLink ); D_MAGIC_ASSERT( last, DirectLink ); link->prev = last; last->next = first->prev = link; } else *list = link->prev = link; D_MAGIC_SET( link, DirectLink ); } static __inline__ void direct_list_insert( DirectLink **list, DirectLink *link, DirectLink *before ) { DirectLink *first; D_ASSERT( list != NULL ); D_ASSERT( link != NULL ); first = *list; D_MAGIC_ASSERT_IF( first, DirectLink ); D_MAGIC_ASSERT_IF( before, DirectLink ); if (first == before) { direct_list_prepend( list, link ); } else if (first == NULL || before == NULL) { direct_list_append( list, link ); } else { DirectLink *prev = before->prev; D_MAGIC_ASSERT( prev, DirectLink ); prev->next = link; link->prev = prev; link->next = before; before->prev = link; D_MAGIC_SET( link, DirectLink ); } } static __inline__ bool direct_list_contains_element_EXPENSIVE( DirectLink *list, DirectLink *link ) { D_MAGIC_ASSERT_IF( list, DirectLink ); while (list) { if (list == link) return true; list = list->next; } return false; } static __inline__ int direct_list_count_elements_EXPENSIVE( DirectLink *list ) { int count = 0; while (list) { D_MAGIC_ASSERT( list, DirectLink ); count++; list = list->next; } return count; } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" #endif static __inline__ bool direct_list_remove( DirectLink **list, DirectLink *link ) { DirectLink *next; DirectLink *prev; D_ASSERT( list != NULL ); D_ASSERT( direct_list_contains_element_EXPENSIVE( *list, link ) ); D_MAGIC_ASSERT( *list, DirectLink ); D_MAGIC_ASSERT( link, DirectLink ); next = link->next; prev = link->prev; if (next) { D_MAGIC_ASSERT( next, DirectLink ); next->prev = prev; } else (*list)->prev = prev; if (link == *list) *list = next; else { D_MAGIC_ASSERT( prev, DirectLink ); prev->next = next; } link->next = link->prev = NULL; D_MAGIC_CLEAR( link ); return true; } static __inline__ void direct_list_move_to_front( DirectLink **list, DirectLink *link ) { DirectLink *next; DirectLink *prev; DirectLink *first; D_ASSERT( list != NULL ); first = *list; D_ASSERT( direct_list_contains_element_EXPENSIVE( first, link ) ); D_MAGIC_ASSERT( first, DirectLink ); D_MAGIC_ASSERT( link, DirectLink ); if (first == link) return; next = link->next; prev = link->prev; D_MAGIC_ASSERT_IF( next, DirectLink ); D_MAGIC_ASSERT( prev, DirectLink ); if (next) { next->prev = prev; link->prev = first->prev; } else link->prev = prev; prev->next = next; link->next = first; first->prev = link; *list = link; } static __inline__ void * direct_list_get_last( DirectLink *list ) { D_MAGIC_ASSERT_IF( list, DirectLink ); if (list) { D_MAGIC_ASSERT( list->prev, DirectLink ); return list->prev; } return NULL; } static __inline__ void * direct_list_get_next( DirectLink *list ) { D_MAGIC_ASSERT_IF( list, DirectLink ); if (list) { D_MAGIC_ASSERT( list->prev, DirectLink ); return list->next; } return NULL; } #if defined __GNUC__ && __GNUC__ >= 10 #pragma GCC diagnostic pop #endif /**********************************************************************************************************************/ #define direct_list_check_link(link) \ ({ \ D_MAGIC_ASSERT_IF( link, DirectLink ); \ link != NULL; \ }) #define direct_list_foreach(elem,list) \ for (elem = (__typeof__(elem)) (list); \ direct_list_check_link( (DirectLink*) (elem) ); \ elem = (__typeof__(elem)) (((DirectLink*) (elem))->next)) #define direct_list_foreach_safe(elem,temp,list) \ for (elem = (__typeof__(elem)) (list), \ temp = ((__typeof__(temp)) direct_list_get_next( (DirectLink*) (elem) )); \ direct_list_check_link( (DirectLink*) (elem) ); \ elem = (__typeof__(elem)) (temp), \ temp = ((__typeof__(temp)) direct_list_get_next( (DirectLink*) (elem) ))) #endif ================================================ FILE: lib/direct/log.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include /**********************************************************************************************************************/ static DirectLog fallback_log; static DirectLog *default_log; /**********************************************************************************************************************/ void __D_log_init() { DirectLog *fb = &fallback_log; fb->type = DLT_STDERR; direct_recursive_mutex_init( &fb->lock ); direct_log_init( fb, NULL ); D_MAGIC_SET( fb, DirectLog ); } void __D_log_deinit() { DirectLog *fb = &fallback_log; direct_log_deinit( fb ); direct_mutex_deinit( &fb->lock ); D_MAGIC_CLEAR( fb ); default_log = NULL; } /**********************************************************************************************************************/ DirectResult direct_log_create( DirectLogType type, const char *param, DirectLog **ret_log ) { DirectResult ret; DirectLog *log; log = direct_calloc( 1, sizeof(DirectLog) ); if (!log) return D_OOM(); log->type = type; direct_recursive_mutex_init( &log->lock ); ret = direct_log_init( log, param ); if (ret) { direct_mutex_deinit( &log->lock ); direct_free( log ); return ret; } D_ASSERT( log->write != NULL ); D_MAGIC_SET( log, DirectLog ); *ret_log = log; return DR_OK; } DirectResult direct_log_destroy( DirectLog *log ) { D_MAGIC_ASSERT( log, DirectLog ); D_ASSERT( &fallback_log != log ); if (log == default_log) default_log = NULL; direct_log_deinit( log ); direct_mutex_deinit( &log->lock ); D_MAGIC_CLEAR( log ); direct_free( log ); return DR_OK; } __dfb_no_instrument_function__ DirectResult direct_log_printf( DirectLog *log, const char *format, ... ) { DirectResult ret = 0; va_list args; int len; char buf[2000]; char *ptr = buf; /* Don't use D_MAGIC_ASSERT or any other macros/functions that might cause an endless loop. */ /* Use the default log if passed log is invalid. */ if (!D_MAGIC_CHECK( log, DirectLog )) log = direct_log_default(); if (!D_MAGIC_CHECK( log, DirectLog )) return DR_BUG; va_start( args, format ); len = vsnprintf( buf, sizeof(buf), format, args ); va_end( args ); if (len < 0) return DR_FAILURE; if (len >= sizeof(buf)) { ptr = direct_malloc( len + 1 ); if (!ptr) return DR_NOLOCALMEMORY; va_start( args, format ); len = vsnprintf( ptr, len + 1, format, args ); va_end( args ); if (len < 0) { direct_free( ptr ); return DR_FAILURE; } } ret = log->write( log, ptr, len ); if (ptr != buf) direct_free( ptr ); direct_log_debug_delay( true ); return ret; } DirectResult direct_log_set_default( DirectLog *log ) { D_MAGIC_ASSERT_IF( log, DirectLog ); default_log = log; return DR_OK; } __dfb_no_instrument_function__ void direct_log_lock( DirectLog *log ) { D_MAGIC_ASSERT( log, DirectLog ); direct_mutex_lock( &log->lock ); } __dfb_no_instrument_function__ void direct_log_unlock( DirectLog *log ) { D_MAGIC_ASSERT( log, DirectLog ); direct_mutex_unlock( &log->lock ); } DirectResult direct_log_flush( DirectLog *log ) { /* Don't use D_MAGIC_ASSERT or any other macros/functions that might cause an endless loop. */ /* Use the default log if passed log is invalid. */ if (!D_MAGIC_CHECK( log, DirectLog )) log = direct_log_default(); if (!D_MAGIC_CHECK( log, DirectLog )) return DR_BUG; if (!log->flush) return DR_UNSUPPORTED; return log->flush( log ); } __dfb_no_instrument_function__ DirectLog * direct_log_default() { return default_log ?: &fallback_log; } __dfb_no_instrument_function__ void direct_log_debug_delay( bool min ) { unsigned int us = min ? direct_config->log_delay_min_us : 0; if (direct_config->log_delay_rand_us) { unsigned int r = rand() % direct_config->log_delay_rand_us; if (us < r) us = r; } if (us) direct_thread_sleep( us ); unsigned int loops = min ? direct_config->log_delay_min_loops : 0; if (direct_config->log_delay_rand_loops) { unsigned int r = rand() % direct_config->log_delay_rand_loops; if (loops < r) loops = r; } if (loops) { volatile long val = 0; unsigned int loop; for (loop = 0; loop < loops; loop++) val++; } } ================================================ FILE: lib/direct/log.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__LOG_H__ #define __DIRECT__LOG_H__ #include #include /**********************************************************************************************************************/ /* * Creates a logging facility. * * For each 'type' the 'param' has a different meaning: * DLT_STDERR ignored (leave NULL) * DLT_FILE file name * DLT_UDP : */ DirectResult DIRECT_API direct_log_create ( DirectLogType type, const char *param, DirectLog **ret_log ); /* * Destroys a logging facility. */ DirectResult DIRECT_API direct_log_destroy ( DirectLog *log ); /* * Write to the log in a printf fashion. * * If log is NULL, the default log is used if it's valid, otherwise stderr is used as a fallback until now. */ DirectResult DIRECT_API direct_log_printf ( DirectLog *log, const char *format, ... ) D_FORMAT_PRINTF(2); /* * Set the default log that is used when no valid log is passed. */ DirectResult DIRECT_API direct_log_set_default( DirectLog *log ); /* * Locks a logging facility for non-intermixed output of multiple calls in multiple threads. */ void DIRECT_API direct_log_lock ( DirectLog *log ); /* * Unlocks a logging facility. */ void DIRECT_API direct_log_unlock ( DirectLog *log ); /* * Flush the log data. */ DirectResult DIRECT_API direct_log_flush ( DirectLog *log ); /* * Returns the default log. */ DirectLog DIRECT_API *direct_log_default ( void ); /* * Enable delay between log messages. */ void DIRECT_API direct_log_debug_delay( bool min ); /**********************************************************************************************************************/ void __D_log_init ( void ); void __D_log_deinit( void ); #endif ================================================ FILE: lib/direct/log_domain.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_TEXT #include #include #include #include #include #include #include #endif /* DIRECT_BUILD_TEXT */ /**********************************************************************************************************************/ #if DIRECT_BUILD_TEXT typedef struct { DirectLink link; char *name; DirectLogDomainConfig config; } LogDomainEntry; static DirectMutex domains_lock; static unsigned int domains_age; static DirectLink *domains; #endif /* DIRECT_BUILD_TEXT */ /**********************************************************************************************************************/ #if DIRECT_BUILD_TEXT void __D_log_domain_init() { domains_age = 1; direct_mutex_init( &domains_lock ); } void __D_log_domain_deinit() { direct_mutex_deinit( &domains_lock ); } #else /* DIRECT_BUILD_TEXT */ void __D_log_domain_init() { } void __D_log_domain_deinit() { } #endif /* DIRECT_BUILD_TEXT */ /**********************************************************************************************************************/ #if DIRECT_BUILD_TEXT __dfb_no_instrument_function__ static __inline__ LogDomainEntry * lookup_domain( const char *name, bool sub ) { LogDomainEntry *entry; direct_list_foreach (entry, domains) { if (!strcasecmp( entry->name, name )) return entry; } /* If the domain being registered contains a slash, but didn't exactly match an entry in directfbrc, check to see if the domain is descended from an entry in directfbrc. */ if (sub && strchr(name, '/')) { int passed_name_len = strlen( name ); direct_list_foreach (entry, domains) { int entry_len = strlen( entry->name ); if ((passed_name_len > entry_len) && (name[entry_len] == '/') && (!strncasecmp( entry->name, name, entry_len ))) { return entry; } } } return NULL; } __dfb_no_instrument_function__ static DirectLogLevel check_domain( DirectLogDomain *domain ) { if (direct_config->log_none) return DIRECT_LOG_NONE; if (direct_config->log_all) return DIRECT_LOG_ALL; if (domain->age != domains_age) { LogDomainEntry *entry; if (direct_mutex_lock( &domains_lock )) return DIRECT_LOG_ALL; entry = lookup_domain( domain->name, true ); domain->age = domains_age; if (entry) { domain->registered = true; domain->config = entry->config; } else { domain->config.level = direct_config->log_level; } direct_mutex_unlock( &domains_lock ); } return domain->config.level; } void direct_log_domain_configure( const char *name, const DirectLogDomainConfig *config ) { LogDomainEntry *entry; if (direct_mutex_lock( &domains_lock )) return; entry = lookup_domain( name, false ); if (!entry) { direct_mutex_unlock( &domains_lock ); entry = (LogDomainEntry*) direct_calloc( 1, sizeof(LogDomainEntry) ); if (!entry) { return; } entry->name = direct_strdup( name ); if (!entry->name) { direct_free( entry ); return; } if (direct_mutex_lock( &domains_lock )) { direct_free( entry->name ); direct_free( entry ); return; } direct_list_prepend( &domains, &entry->link ); } entry->config = *config; if (!++domains_age) domains_age++; direct_mutex_unlock( &domains_lock ); } bool direct_log_domain_check( DirectLogDomain *domain ) { return check_domain( domain ) >= DIRECT_LOG_DEBUG; } bool direct_log_domain_check_level( DirectLogDomain *domain, DirectLogLevel level ) { return check_domain( domain ) >= level; } __dfb_no_instrument_function__ DirectResult direct_log_domain_vprintf( DirectLogDomain *domain, DirectLogLevel level, const char *format, va_list ap ) { if (check_domain( domain ) >= level) { char buf[200]; char *ptr = buf; long long micros = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); long long millis = micros / 1000LL; int indent = direct_trace_debug_indent() * 4; int len; va_list ap2; /* Prepare user message. */ va_copy( ap2, ap ); len = vsnprintf( buf, sizeof(buf), format, ap2 ); va_end( ap2 ); if (len < 0) return DR_FAILURE; if (len >= sizeof(buf)) { ptr = direct_malloc( len + 1 ); if (!ptr) return DR_NOLOCALMEMORY; len = vsnprintf( ptr, len + 1, format, ap ); if (len < 0) { direct_free( ptr ); return DR_FAILURE; } } /* Wrap around when too high. */ indent &= 0x7f; /* Fill up domain name column after the colon, prepending remaining space (excl. ': ') to indent. */ indent += (domain->name_len < 34 ? 34 : 50) - domain->name_len - 2; /* Print full message. */ direct_log_printf( domain->config.log, "(-) [%-16.16s %3lld.%03lld,%03lld] (%5d) %s: %*s%s", direct_thread_self_name() ?: " NO NAME", millis / 1000LL, millis % 1000LL, micros % 1000LL, direct_gettid(), domain->name, indent, "", ptr ); direct_log_flush( domain->config.log ); if (ptr != buf) direct_free( ptr ); } else direct_log_debug_delay( false ); return DR_OK; } __dfb_no_instrument_function__ DirectResult direct_log_domain_log( DirectLogDomain *domain, DirectLogLevel level, const char *func, const char *file, int line, const char *format, ... ) { if (check_domain( domain ) >= level) { char buf[200]; char *ptr = buf; long long micros = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); long long millis = micros / 1000LL; int indent = direct_trace_debug_indent() * 4; int len; va_list ap; /* Prepare user message. */ va_start( ap, format ); len = vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); if (len < 0) return DR_FAILURE; if (len >= sizeof(buf)) { ptr = direct_malloc( len + 1 ); if (!ptr) return DR_NOLOCALMEMORY; va_start( ap, format ); len = vsnprintf( ptr, len + 1, format, ap ); va_end( ap ); if (len < 0) { direct_free( ptr ); return DR_FAILURE; } } /* Wrap around when too high. */ indent &= 0x7f; /* Fill up domain name column after the colon, prepending remaining space (excl. ': ') to indent. */ indent += (domain->name_len < 27 ? 27 : 42) - domain->name_len - 2; /* Print full message. */ direct_log_printf( domain->config.log, "(%c) [%-16.16s %3lld.%03lld,%03lld] (%5d) %s: %*s [%s:%d in %s()] %s", level > DIRECT_LOG_INFO ? '-' : level > DIRECT_LOG_NOTICE ? '*' : level > DIRECT_LOG_WARNING ? '+' : level > DIRECT_LOG_ERROR ? '#' : level > DIRECT_LOG_FATAL ? '!' : level > DIRECT_LOG_NONE ? '=' : ' ', direct_thread_self_name() ?: " NO NAME", millis / 1000LL, millis % 1000LL, micros % 1000LL, direct_gettid(), domain->name, indent, "", file, line, func, ptr ); direct_log_flush( domain->config.log ); if (ptr != buf) direct_free( ptr ); } else direct_log_debug_delay( false ); return DR_OK; } #else /* DIRECT_BUILD_TEXT */ void direct_log_domain_configure( const char *name, const DirectLogDomainConfig *config ) { } bool direct_log_domain_check( DirectLogDomain *domain ) { return false; } bool direct_log_domain_check_level( DirectLogDomain *domain, DirectLogLevel level ) { return false; } DirectResult direct_log_domain_vprintf( DirectLogDomain *domain, DirectLogLevel level, const char *format, va_list ap ) { return DR_OK; } DirectResult direct_log_domain_log( DirectLogDomain *domain, DirectLogLevel level, const char *func, const char *file, int line, const char *format, ... ) { return DR_OK; } #endif /* DIRECT_BUILD_TEXT */ ================================================ FILE: lib/direct/log_domain.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__LOG_DOMAIN_H__ #define __DIRECT__LOG_DOMAIN_H__ #include #include /**********************************************************************************************************************/ typedef enum { DIRECT_LOG_NONE = 0x00000000, DIRECT_LOG_FATAL = 0x00000001, DIRECT_LOG_ERROR = 0x00000002, DIRECT_LOG_WARNING = 0x00000003, DIRECT_LOG_NOTICE = 0x00000004, DIRECT_LOG_INFO = 0x00000005, DIRECT_LOG_VERBOSE = 0x00000006, DIRECT_LOG_DEBUG_0 = DIRECT_LOG_VERBOSE, DIRECT_LOG_DEBUG_1 = 0x00000007, DIRECT_LOG_DEBUG_2 = 0x00000008, DIRECT_LOG_DEBUG_3 = 0x00000009, DIRECT_LOG_DEBUG_4 = 0x0000000A, DIRECT_LOG_DEBUG_5 = 0x0000000B, DIRECT_LOG_DEBUG_6 = 0x0000000C, DIRECT_LOG_DEBUG_7 = 0x0000000D, DIRECT_LOG_DEBUG_8 = 0x0000000E, DIRECT_LOG_DEBUG_9 = 0x0000000F, DIRECT_LOG_ALL = 0x00000010, DIRECT_LOG_DEBUG = DIRECT_LOG_DEBUG_8, /* Default debug level */ } DirectLogLevel; typedef struct { DirectLogLevel level; DirectLog *log; } DirectLogDomainConfig; typedef struct { const char *description; const char *name; int name_len; unsigned int age; bool registered; DirectLogDomainConfig config; } DirectLogDomain; /**********************************************************************************************************************/ void DIRECT_API direct_log_domain_configure ( const char *name, const DirectLogDomainConfig *config ); bool DIRECT_API direct_log_domain_check ( DirectLogDomain *domain ); bool DIRECT_API direct_log_domain_check_level( DirectLogDomain *domain, DirectLogLevel level ); DirectResult DIRECT_API direct_log_domain_vprintf ( DirectLogDomain *domain, DirectLogLevel level, const char *format, va_list ap ) D_FORMAT_VPRINTF(3); DirectResult DIRECT_API direct_log_domain_log ( DirectLogDomain *domain, DirectLogLevel level, const char *func, const char *file, int line, const char *format, ... ) D_FORMAT_PRINTF(6); /**********************************************************************************************************************/ static __inline__ void direct_log_domain_config_level( const char *name, DirectLogLevel level ) { DirectLogDomainConfig config; config.level = level; config.log = NULL; direct_log_domain_configure( name, &config ); } #define D_LOG(d,l,...) \ do { \ direct_log_domain_log( &(d), DIRECT_LOG_##l, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__ ); \ } while (0) /**********************************************************************************************************************/ void __D_log_domain_init ( void ); void __D_log_domain_deinit( void ); #endif ================================================ FILE: lib/direct/map.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Direct_Map, "Direct/Map", "Direct Map implementation" ); /**********************************************************************************************************************/ #define REMOVED ((void*) -1) typedef struct { unsigned int hash; void *object; } MapEntry; struct __D_DirectMap { int magic; unsigned int size; unsigned int count; unsigned int removed; MapEntry *entries; DirectMapCompareFunc compare; DirectMapHashFunc hash; void *ctx; }; #define DIRECT_MAP_ASSERT(map) \ do { \ D_MAGIC_ASSERT( map, DirectMap ); \ } while (0) /**********************************************************************************************************************/ static int locate_entry( DirectMap *map, unsigned int hash, const void *key ) { int pos; const MapEntry *entry; D_DEBUG_AT( Direct_Map, "%s( hash %u )\n", __FUNCTION__, hash ); DIRECT_MAP_ASSERT( map ); D_ASSERT( key != NULL ); pos = hash % map->size; entry = &map->entries[pos]; while (entry->object) { if (entry->object != REMOVED && entry->hash == hash && map->compare( map, key, entry->object, map->ctx )) return pos; if (++pos == map->size) pos = 0; entry = &map->entries[pos]; } return -1; } static DirectResult resize_map( DirectMap *map, unsigned int size ) { unsigned int i, pos; MapEntry *entries; D_DEBUG_AT( Direct_Map, "%s( size %u )\n", __FUNCTION__, size ); DIRECT_MAP_ASSERT( map ); D_ASSERT( size > 3 ); entries = D_CALLOC( size, sizeof(MapEntry) ); if (!entries) return D_OOM(); for (i = 0; i < map->size; i++) { MapEntry *entry = &map->entries[i]; MapEntry *insertElement; if (entry->object && entry->object != REMOVED) { pos = entry->hash % size; insertElement = &entries[pos]; while (insertElement->object && insertElement->object != REMOVED) { if (++pos == size) pos = 0; insertElement = &entries[pos]; } entries[pos] = *entry; } } D_FREE( map->entries ); map->size = size; map->entries = entries; map->removed = 0; return DR_OK; } /**********************************************************************************************************************/ DirectResult direct_map_create( unsigned int initial_size, DirectMapCompareFunc compare_func, DirectMapHashFunc hash_func, void *ctx, DirectMap **ret_map ) { DirectMap *map; D_DEBUG_AT( Direct_Map, "%s( size %u, compare %p, hash %p )\n", __FUNCTION__, initial_size, compare_func, hash_func ); D_ASSERT( compare_func != NULL ); D_ASSERT( hash_func != NULL ); D_ASSERT( ret_map != NULL ); if (initial_size < 3) initial_size = 3; map = D_CALLOC( 1, sizeof(DirectMap) ); if (!map) return D_OOM(); map->entries = D_CALLOC( initial_size, sizeof(MapEntry) ); if (!map->entries) { D_FREE( map ); return D_OOM(); } map->size = initial_size; map->compare = compare_func; map->hash = hash_func; map->ctx = ctx; D_MAGIC_SET( map, DirectMap ); *ret_map = map; return DR_OK; } void direct_map_destroy( DirectMap *map ) { D_DEBUG_AT( Direct_Map, "%s()\n", __FUNCTION__ ); DIRECT_MAP_ASSERT( map ); D_MAGIC_CLEAR( map ); D_FREE( map->entries ); D_FREE( map ); } DirectResult direct_map_insert( DirectMap *map, const void *key, void *object ) { unsigned int hash; int pos; MapEntry *entry; D_DEBUG_AT( Direct_Map, "%s( key %p, object %p )\n", __FUNCTION__, key, object ); DIRECT_MAP_ASSERT( map ); D_ASSERT( key != NULL ); D_ASSERT( object != NULL ); if ((map->count + map->removed) > map->size / 4) resize_map( map, map->size * 3 ); hash = map->hash( map, key, map->ctx ); pos = hash % map->size; D_DEBUG_AT( Direct_Map, " -> hash %u, pos %d\n", hash, pos ); entry = &map->entries[pos]; while (entry->object && entry->object != REMOVED) { if (entry->hash == hash && map->compare( map, key, entry->object, map->ctx )) { if (entry->object == object) { D_DEBUG_AT( Direct_Map, " -> same object with matching key already exists\n" ); return DR_BUSY; } else { D_DEBUG_AT( Direct_Map, " -> different object with matching key already exists\n" ); D_BUG( "different object with matching key already exists" ); return DR_BUG; } } if (++pos == map->size) pos = 0; entry = &map->entries[pos]; } if (entry->object == REMOVED) map->removed--; entry->hash = hash; entry->object = object; map->count++; D_DEBUG_AT( Direct_Map, " -> new count = %u, removed = %u, size = %u\n", map->count, map->removed, map->size ); return DR_OK; } DirectResult direct_map_remove( DirectMap *map, const void *key ) { unsigned int hash; int pos; D_DEBUG_AT( Direct_Map, "%s( key %p )\n", __FUNCTION__, key ); DIRECT_MAP_ASSERT( map ); D_ASSERT( key != NULL ); hash = map->hash( map, key, map->ctx ); pos = locate_entry( map, hash, key ); if (pos == -1) { D_WARN( "object to remove not found" ); return DR_ITEMNOTFOUND; } map->entries[pos].object = REMOVED; map->count--; map->removed++; D_DEBUG_AT( Direct_Map, " -> new count = %u, removed = %u, size = %u\n", map->count, map->removed, map->size ); return DR_OK; } void * direct_map_lookup( DirectMap *map, const void *key ) { unsigned int hash; int pos; D_DEBUG_AT( Direct_Map, "%s( key %p )\n", __FUNCTION__, key ); DIRECT_MAP_ASSERT( map ); D_ASSERT( key != NULL ); hash = map->hash( map, key, map->ctx ); pos = locate_entry( map, hash, key ); return (pos != -1) ? map->entries[pos].object : NULL; } void direct_map_iterate( DirectMap *map, DirectMapIteratorFunc func, void *ctx ) { unsigned int i; D_DEBUG_AT( Direct_Map, "%s( func %p )\n", __FUNCTION__, func ); DIRECT_MAP_ASSERT( map ); D_ASSERT( func != NULL ); for (i = 0; i < map->size; i++) { MapEntry *entry = &map->entries[i]; if (entry->object && entry->object != REMOVED) { switch (func( map, entry->object, ctx )) { case DENUM_OK: break; case DENUM_CANCEL: return; case DENUM_REMOVE: entry->object = REMOVED; map->count--; map->removed++; } } } } ================================================ FILE: lib/direct/map.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MAP_H__ #define __DIRECT__MAP_H__ #include /**********************************************************************************************************************/ typedef bool (*DirectMapCompareFunc) ( DirectMap *map, const void *key, void *object, void *ctx ); typedef unsigned int (*DirectMapHashFunc) ( DirectMap *map, const void *key, void *ctx ); typedef DirectEnumerationResult (*DirectMapIteratorFunc)( DirectMap *map, void *object, void *ctx ); /**********************************************************************************************************************/ DirectResult DIRECT_API direct_map_create ( unsigned int initial_size, DirectMapCompareFunc compare_func, DirectMapHashFunc hash_func, void *ctx, DirectMap **ret_map ); void DIRECT_API direct_map_destroy( DirectMap *map ); DirectResult DIRECT_API direct_map_insert ( DirectMap *map, const void *key, void *object ); DirectResult DIRECT_API direct_map_remove ( DirectMap *map, const void *key ); void DIRECT_API *direct_map_lookup ( DirectMap *map, const void *key ); void DIRECT_API direct_map_iterate( DirectMap *map, DirectMapIteratorFunc func, void *ctx ); #endif ================================================ FILE: lib/direct/mem.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_DEBUGS #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Mem, "Direct/Mem", "Direct Memory allocation" ); #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUGS #define DISABLED_OFFSET 8 typedef struct { void *mem; size_t bytes; const char *func; const char *file; int line; DirectTraceBuffer *trace; } MemDesc; static DirectHash alloc_hash = DIRECT_HASH_INIT( 523, true ); static DirectMutex alloc_lock; #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUGS void __D_mem_init() { direct_mutex_init( &alloc_lock ); } void __D_mem_deinit() { direct_mutex_deinit( &alloc_lock ); } #else /* DIRECT_BUILD_DEBUGS */ void __D_mem_init() { } void __D_mem_deinit() { } #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUGS static bool local_alloc_hash_iterator( DirectHash *hash, unsigned long key, void *value, void *ctx ) { MemDesc *desc = value; unsigned long *total = ctx; direct_log_printf( NULL, ""_ZUn(7)" bytes at %p allocated in %s (%s: %d)\n", desc->bytes, desc->mem, desc->func, desc->file, desc->line ); if (desc->trace) direct_trace_print_stack( desc->trace ); *total += desc->bytes; return true; } void direct_print_memleaks() { unsigned long total = 0; /* Debug only. */ direct_mutex_lock( &alloc_lock ); if (alloc_hash.count) { direct_log_printf( NULL, "Local memory allocations remaining (%d): \n", alloc_hash.count ); direct_hash_iterate( &alloc_hash, local_alloc_hash_iterator, &total ); } direct_mutex_unlock( &alloc_lock ); if (total) direct_log_printf( NULL, "%7lu bytes in total\n", total ); } __dfb_no_instrument_function__ static __inline__ MemDesc * fill_mem_desc( MemDesc *desc, int bytes, const char *func, const char *file, int line, DirectTraceBuffer *trace ) { D_ASSERT( desc != NULL ); desc->mem = desc + 1; desc->bytes = bytes; desc->func = func; desc->file = file; desc->line = line; desc->trace = trace; return desc; } void * direct_dbg_malloc( const char *file, int line, const char *func, size_t bytes ) { void *mem; unsigned long *val; D_DEBUG_AT( Direct_Mem, " +"_ZUn(6)" bytes [%s:%d in %s()]\n", bytes, file, line, func ); if (direct_config->debugmem) { MemDesc *desc; mem = direct_malloc( bytes + sizeof(MemDesc) ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); if (!mem) return NULL; desc = fill_mem_desc( mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) ); direct_mutex_lock( &alloc_lock ); direct_hash_insert( &alloc_hash, (unsigned long) desc->mem, desc ); direct_mutex_unlock( &alloc_lock ); return desc->mem; } mem = direct_malloc( bytes + DISABLED_OFFSET ); if (!mem) return NULL; D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); val = mem; val[0] = ~0; return (char*) mem + DISABLED_OFFSET; } void * direct_dbg_calloc( const char *file, int line, const char *func, size_t count, size_t bytes ) { void *mem; unsigned long *val; D_DEBUG_AT( Direct_Mem, " +"_ZUn(6)" bytes [%s:%d in %s()]\n", count * bytes, file, line, func ); if (direct_config->debugmem) { MemDesc *desc; mem = direct_calloc( 1, count * bytes + sizeof(MemDesc) ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); if (!mem) return NULL; desc = fill_mem_desc( mem, count * bytes, func, file, line, direct_trace_copy_buffer(NULL) ); direct_mutex_lock( &alloc_lock ); direct_hash_insert( &alloc_hash, (unsigned long) desc->mem, desc ); direct_mutex_unlock( &alloc_lock ); return desc->mem; } mem = direct_calloc( 1, count * bytes + DISABLED_OFFSET ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); if (!mem) return NULL; val = mem; val[0] = ~0; return (char*) mem + DISABLED_OFFSET; } void * direct_dbg_realloc( const char *file, int line, const char *func, const char *what, void *mem, size_t bytes ) { unsigned long *val; MemDesc *desc; D_DEBUG_AT( Direct_Mem, " *"_ZUn(6)" bytes [%s:%d in %s()] '%s' <- %p\n", bytes, file, line, func, what, mem ); if (!mem) return direct_dbg_malloc( file, line, func, bytes ); if (!bytes) { direct_dbg_free( file, line, func, what, mem ); return NULL; } val = (unsigned long*) ((char*) mem - DISABLED_OFFSET); if (val[0] == ~0) { D_DEBUG_AT( Direct_Mem, " *"_ZUn(6)" bytes [%s:%d in %s()] '%s'\n", bytes, file, line, func, what ); val = direct_realloc( val, bytes + DISABLED_OFFSET ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", val ); if (val) { mem = val; return (char*) mem + DISABLED_OFFSET; } return NULL; } direct_mutex_lock( &alloc_lock ); desc = (MemDesc*) ((char*) mem - sizeof(MemDesc)); D_ASSERT( desc->mem == mem ); if (direct_hash_remove( &alloc_hash, (unsigned long) mem )) { D_ERROR( "Direct/Mem: Not reallocating unknown %p ('%s') from [%s:%d in %s()] (corrupt/incomplete list)!\n", mem, what, file, line, func ); mem = direct_dbg_malloc( file, line, func, bytes ); } else { void *new_mem = direct_realloc( desc, bytes + sizeof(MemDesc) ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", new_mem ); D_DEBUG_AT( Direct_Mem, " %c"_ZUn(6)" bytes [%s:%d in %s()] (%s"_ZU") <- %p -> %p '%s'\n", (bytes > desc->bytes) ? '>' : '<', bytes, file, line, func, (bytes > desc->bytes) ? "+" : "", bytes - desc->bytes, mem, new_mem, what ); if (desc->trace) { direct_trace_free_buffer( desc->trace ); desc->trace = NULL; } if (!new_mem) D_WARN( "could not reallocate memory (%p: "_ZU"->"_ZU")", mem, desc->bytes, bytes ); else desc = fill_mem_desc( new_mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) ); mem = desc->mem; } direct_mutex_unlock( &alloc_lock ); return mem; } char * direct_dbg_strdup( const char *file, int line, const char *func, const char *string ) { void *mem; unsigned long *val; size_t bytes = string ? strlen( string ) + 1 : 1; D_DEBUG_AT( Direct_Mem, " +"_ZUn(6)" bytes [%s:%d in %s()] <- \"%30s\"\n", bytes, file, line, func, string ); if (direct_config->debugmem) { MemDesc *desc; mem = direct_malloc( bytes + sizeof(MemDesc) ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); if (!mem) return NULL; desc = fill_mem_desc( mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) ); direct_mutex_lock( &alloc_lock ); direct_hash_insert( &alloc_hash, (unsigned long) desc->mem, desc ); direct_mutex_unlock( &alloc_lock ); if (string) direct_memcpy( desc->mem, string, bytes ); else *(u8*) desc->mem = 0; return desc->mem; } mem = direct_malloc( bytes + DISABLED_OFFSET ); D_DEBUG_AT( Direct_Mem, " '-> %p\n", mem ); if (!mem) return NULL; val = mem; val[0] = ~0; if (string) direct_memcpy( (char*) mem + DISABLED_OFFSET, string, bytes ); else *((u8*) mem + DISABLED_OFFSET) = 0; return (char*) mem + DISABLED_OFFSET; } void direct_dbg_free( const char *file, int line, const char *func, const char *what, void *mem ) { unsigned long *val; MemDesc *desc; if (!mem) { return; } val = (unsigned long*) ((char*) mem - DISABLED_OFFSET); if (val[0] == ~0) { D_DEBUG_AT( Direct_Mem, " - number of bytes of '%s' [%s:%d in %s()] -> %p\n", what, file, line, func, mem ); val[0] = 0; direct_free( val ); return; } direct_mutex_lock( &alloc_lock ); desc = (MemDesc*) ((char*) mem - sizeof(MemDesc)); D_ASSERT( desc->mem == mem ); if (direct_hash_remove( &alloc_hash, (unsigned long) mem )) { D_ERROR( "Direct/Mem: Not freeing unknown %p ('%s') from [%s:%d in %s()] (corrupt/incomplete list)!\n", mem, what, file, line, func ); } else { D_DEBUG_AT( Direct_Mem, " -"_ZUn(6)" bytes [%s:%d in %s()] -> %p '%s'\n", desc->bytes, file, line, func, mem, what ); if (desc->trace) direct_trace_free_buffer( desc->trace ); direct_free( desc ); } direct_mutex_unlock( &alloc_lock ); } #else /* DIRECT_BUILD_DEBUGS */ void direct_print_memleaks() { } void * direct_dbg_malloc( const char *file, int line, const char *func, size_t bytes ) { return direct_malloc( bytes ); } void * direct_dbg_calloc( const char *file, int line, const char *func, size_t count, size_t bytes ) { return direct_calloc( 1, count * bytes ); } void * direct_dbg_realloc( const char *file, int line, const char *func, const char *what, void *mem, size_t bytes ) { return direct_realloc( mem, bytes ); } char * direct_dbg_strdup( const char *file, int line, const char *func, const char *string ) { return direct_strdup( string ); } void direct_dbg_free( const char *file, int line, const char *func, const char *what, void *mem ) { return direct_free( mem ); } #endif /* DIRECT_BUILD_DEBUGS */ ================================================ FILE: lib/direct/mem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MEM_H__ #define __DIRECT__MEM_H__ #include /**********************************************************************************************************************/ void DIRECT_API direct_print_memleaks( void ); void DIRECT_API *direct_dbg_malloc ( const char *file, int line, const char *func, size_t bytes ); void DIRECT_API *direct_dbg_calloc ( const char *file, int line, const char *func, size_t count, size_t bytes ); void DIRECT_API *direct_dbg_realloc ( const char *file, int line, const char *func, const char *what, void *mem, size_t bytes ); char DIRECT_API *direct_dbg_strdup ( const char *file, int line, const char *func, const char *str ); void DIRECT_API direct_dbg_free ( const char *file, int line, const char *func, const char *what, void *mem ); /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) #define D_MALLOC(bytes) direct_dbg_malloc ( __FILE__, __LINE__, __FUNCTION__, bytes ) #define D_CALLOC(count,bytes) direct_dbg_calloc ( __FILE__, __LINE__, __FUNCTION__, count, bytes ) #define D_REALLOC(mem,bytes) direct_dbg_realloc( __FILE__, __LINE__, __FUNCTION__, #mem, mem, bytes ) #define D_STRDUP(str) direct_dbg_strdup ( __FILE__, __LINE__, __FUNCTION__, str ) #define D_FREE(mem) direct_dbg_free ( __FILE__, __LINE__, __FUNCTION__, #mem, mem ) #else /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ #define D_MALLOC direct_malloc #define D_CALLOC direct_calloc #define D_REALLOC direct_realloc #define D_STRDUP direct_strdup #define D_FREE direct_free #endif /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ void __D_mem_init ( void ); void __D_mem_deinit( void ); #endif ================================================ FILE: lib/direct/memcpy.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #if DIRECT_BUILD_MEMCPY_PROBING #include #include #include D_DEBUG_DOMAIN( Direct_Memcpy, "Direct/Memcpy", "Direct Memcpy routines" ); #endif /**********************************************************************************************************************/ #if SIZEOF_LONG == 8 static void * generic64_memcpy( void *to, const void *from, size_t len ) { u8 *d = (u8*) to; const u8 *s = (const u8*) from; size_t n; if (len >= 128) { unsigned long delta; /* Align destination to 8-byte boundary. */ delta = (unsigned long) d & 7; if (delta) { len -= 8 - delta; if ((unsigned long) d & 1) { *d++ = *s++; } if ((unsigned long) d & 2) { *((u16*)d) = *((const u16*) s); d += 2; s += 2; } if ((unsigned long) d & 4) { *((u32*)d) = *((const u32*) s); d += 4; s += 4; } } n = len >> 6; len &= 63; for (; n; n--) { ((u64*) d)[0] = ((const u64*) s)[0]; ((u64*) d)[1] = ((const u64*) s)[1]; ((u64*) d)[2] = ((const u64*) s)[2]; ((u64*) d)[3] = ((const u64*) s)[3]; ((u64*) d)[4] = ((const u64*) s)[4]; ((u64*) d)[5] = ((const u64*) s)[5]; ((u64*) d)[6] = ((const u64*) s)[6]; ((u64*) d)[7] = ((const u64*) s)[7]; d += 64; s += 64; } } /* Now do the tail of the block. */ if (len) { n = len >> 3; for (; n; n--) { *((u64*) d) = *((const u64*) s); d += 8; s += 8; } if (len & 4) { *((u32*) d) = *((const u32*) s); d += 4; s += 4; } if (len & 2) { *((u16*) d) = *((const u16*) s); d += 2; s += 2; } if (len & 1) *d = *s; } return to; } #endif /* SIZEOF_LONG == 8 */ static void * std_memcpy( void *to, const void *from, size_t len ) { return memcpy( to, from, len ); } typedef void *(*memcpy_func)( void *to, const void *from, size_t len ); static struct { char *name; char *desc; memcpy_func function; unsigned long long time; } memcpy_method[] = { { NULL, NULL, NULL, 0 }, { "libc", "libc memcpy()", std_memcpy, 0 }, #if SIZEOF_LONG == 8 { "generic64", "Generic 64bit memcpy()", generic64_memcpy, 0 }, #endif { NULL, NULL, NULL, 0 } }; memcpy_func direct_memcpy = std_memcpy; void direct_find_best_memcpy() { int i; #if DIRECT_BUILD_MEMCPY_PROBING #define BUFSIZE 1024 #define ITERS 256 unsigned long long t; char *buf1, *buf2; int iter, j, best = 0; #endif if (direct_config->memcpy) { for (i = 1; memcpy_method[i].name; i++) { if (!strcmp( direct_config->memcpy, memcpy_method[i].name )) { direct_memcpy = memcpy_method[i].function; D_INFO( "Direct/Memcpy: Forced to use %s\n", memcpy_method[i].desc ); return; } } } /* Skipping the memcpy() probing saves library size and startup time. */ #if DIRECT_BUILD_MEMCPY_PROBING if (!(buf1 = D_MALLOC( BUFSIZE * 500 ))) return; if (!(buf2 = D_MALLOC( BUFSIZE * 500 ))) { D_FREE( buf1 ); return; } D_DEBUG_AT( Direct_Memcpy, "Benchmarking memcpy methods (smaller is better):\n" ); for (i = 1; memcpy_method[i].name; i++) { t = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); for (iter = 0; iter < ITERS; iter++) for (j = 0; j < 500; j++) memcpy_method[i].function( buf1 + j * BUFSIZE, buf2 + j * BUFSIZE, BUFSIZE ); t = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ) - t; memcpy_method[i].time = t; D_DEBUG_AT( Direct_Memcpy, "\t%-10s %20lld\n", memcpy_method[i].name, t ); if (best == 0 || t < memcpy_method[best].time) best = i; } if (best) { direct_memcpy = memcpy_method[best].function; D_INFO( "Direct/Memcpy: Using %s\n", memcpy_method[best].desc ); } D_FREE( buf1 ); D_FREE( buf2 ); #endif } void direct_print_memcpy_routines() { int i; direct_log_printf( NULL, "\nPossible values for memcpy option are:\n\n" ); for (i = 1; memcpy_method[i].name; i++) { direct_log_printf( NULL, " %-10s %-27s\n", memcpy_method[i].name, memcpy_method[i].desc ); } direct_log_printf( NULL, "\n" ); } ================================================ FILE: lib/direct/memcpy.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MEMCPY_H__ #define __DIRECT__MEMCPY_H__ #include /**********************************************************************************************************************/ void DIRECT_API direct_find_best_memcpy ( void ); void DIRECT_API direct_print_memcpy_routines( void ); extern void DIRECT_API *(*direct_memcpy) ( void *to, const void *from, size_t len ); /**********************************************************************************************************************/ static __inline__ void * direct_memmove( void *to, const void *from, size_t len ) { if ((from < to && ((const char*) from + len) < ((char*) to)) || (((char*) to + len) < ((const char*) from))) return direct_memcpy( to, from, len ); else return memmove( to, from, len ); } #endif ================================================ FILE: lib/direct/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA direct_sources = [ 'clock.c', 'conf.c', 'debug.c', 'direct.c', 'direct_result.c', 'hash.c', 'init.c', 'interface.c', 'log.c', 'log_domain.c', 'map.c', 'mem.c', 'memcpy.c', 'messages.c', 'modules.c', 'result.c', 'stream.c', 'system.c', 'thread.c', 'trace.c', 'util.c' ] direct_headers = [ 'atomic.h', 'clock.h', 'compiler.h', 'conf.h', 'debug.h', 'direct.h', 'filesystem.h', 'hash.h', 'interface.h', 'interface_implementation.h', 'list.h', 'log.h', 'log_domain.h', 'map.h', 'mem.h', 'memcpy.h', 'messages.h', 'modules.h', 'mutex.h', 'result.h', 'serial.h', 'signals.h', 'stream.h', 'system.h', 'thread.h', 'trace.h', 'types.h', 'utf8.h', 'util.h', 'waitqueue.h' ] os_headers = [ 'os/clock.h', 'os/filesystem.h', 'os/log.h', 'os/mem.h', 'os/mutex.h', 'os/signals.h', 'os/system.h', 'os/thread.h', 'os/types.h', 'os/waitqueue.h' ] build_conf = configuration_data() build_conf.set10('DIRECT_BUILD_CTORS', get_option('constructors')) build_conf.set10('DIRECT_BUILD_DEBUG', get_option('debug')) if get_option('debug') build_conf.set10('DIRECT_BUILD_DEBUGS', true) else build_conf.set10('DIRECT_BUILD_DEBUGS', get_option('debug-support')) endif build_conf.set10('DIRECT_BUILD_DYNLOAD', get_option('default_library') == 'shared') build_conf.set10('DIRECT_BUILD_MEMCPY_PROBING', get_option('memcpy-probing')) build_conf.set10('DIRECT_BUILD_NETWORK', get_option('network')) build_conf.set10('DIRECT_BUILD_PIPED_STREAM', get_option('piped-stream')) build_conf.set10('DIRECT_BUILD_SENTINELS', get_option('sentinels')) if get_option('os') == 'linux' os_sources = [ 'os/linux/clock.c', 'os/linux/filesystem.c', 'os/linux/log.c', 'os/linux/mem.c', 'os/linux/mutex.c', 'os/linux/signals.c', 'os/linux/system.c', 'os/linux/thread.c', ] os_linux_headers = [ 'os/linux/filesystem.h', 'os/linux/mutex.h', 'os/linux/thread.h', 'os/linux/types.h', 'os/linux/waitqueue.h' ] build_conf.set('DIRECT_BUILD_OS_LINUX', true) else error('Unsupported OS') endif build_conf.set10('DIRECT_BUILD_TEXT', get_option('text')) if get_option('trace') add_global_arguments('-finstrument-functions', language: 'c') endif build_conf.set10('DIRECT_BUILD_TRACE', get_option('trace')) configure_file(configuration: build_conf, output: 'build.h', install: true, install_dir: get_option('includedir') / 'directfb/direct') libdl_dep = [] moduledir_def = [] if get_option('default_library') == 'shared' libdl_dep = cc.find_library('dl') moduledir_def = '-DMODULEDIR="@0@"'.format(moduledir) endif libdirect_private = [] if get_option('default_library') == 'static' and get_option('constructors') libdirect_private = ['-Wl,-u,__D_init_all'] endif librt_dep = [] if not cc.has_function('clock_gettime') librt_dep = cc.find_library('rt') if get_option('default_library') == 'static' libdirect_private += ['-lrt'] endif endif threads_dep = dependency('threads') if get_option('default_library') == 'static' libdirect_private += ['-pthread'] endif libdirect = library('direct-@0@.@1@'.format(directfb_major_version, directfb_minor_version), direct_sources, os_sources, include_directories: [config_inc, lib_inc], c_args: moduledir_def, dependencies: [libdl_dep, librt_dep, threads_dep], version: '0.@0@.0'.format(directfb_micro_version), install: true) install_symlink('libdirect' + libsuffix, pointing_to: 'libdirect-@0@.@1@'.format(directfb_major_version, directfb_minor_version) + libsuffix, install_dir: get_option('prefix') / get_option('libdir')) install_headers(direct_headers, subdir: 'directfb/direct') install_headers(os_headers, subdir: 'directfb/direct/os') if get_option('os') == 'linux' install_headers(os_linux_headers, subdir: 'directfb/direct/os/linux') endif pkgconfig.generate(filebase: 'direct', name: 'Direct', description: 'DirectFB low-level library', libraries: '-L${libdir} -ldirect', libraries_private: libdirect_private, subdirs: 'directfb') direct_dep = declare_dependency(include_directories: lib_inc, link_with: libdirect) ================================================ FILE: lib/direct/messages.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include /**********************************************************************************************************************/ #if DIRECT_BUILD_TEXT #include #include #include #include #include #include __dfb_no_instrument_function__ void direct_messages_info( const char *format, ... ) { char buf[512]; char *ptr = buf; int len; va_list ap; va_start( ap, format ); len = vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); if (len < 0) return; if (len >= sizeof(buf)) { ptr = direct_malloc( len + 1 ); if (!ptr) return; va_start( ap, format ); len = vsnprintf( ptr, len + 1, format, ap ); va_end( ap ); if (len < 0) { direct_free( ptr ); return; } } direct_log_printf( NULL, "(*) %s", ptr ); if (ptr != buf) direct_free( ptr ); } __dfb_no_instrument_function__ void direct_messages_error( const char *format, ... ) { char buf[512]; char *ptr = buf; int len; va_list ap; va_start( ap, format ); len = vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); if (len < 0) return; if (len >= sizeof(buf)) { ptr = direct_malloc( len + 1 ); if (!ptr) return; va_start( ap, format ); len = vsnprintf( ptr, len + 1, format, ap ); va_end( ap ); if (len < 0) { direct_free( ptr ); return; } } direct_log_printf( NULL, "(!) %s", ptr ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_ERROR) direct_trap( "Error", SIGABRT ); if (ptr != buf) direct_free( ptr ); } __dfb_no_instrument_function__ void direct_messages_derror( DirectResult result, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(!) %s --> %s\n", buf, DirectResultString( result ) ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_ERROR) direct_trap( "DError", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_perror( int erno, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(!) %s --> %s\n", buf, direct_strerror( erno ) ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_ERROR) direct_trap( "PError", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_dlerror( const char *dlerr, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(!) %s --> %s\n", buf, dlerr ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_ERROR) direct_trap( "DlError", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_once( const char *func, const char *file, int line, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(!) *** ONCE [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_ONCE) direct_trap( "Once", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_unimplemented( const char *func, const char *file, int line ) { direct_log_printf( NULL, "(+) *** UNIMPLEMENTED [%s] *** [%s:%d]\n", func, file, line ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_UNIMPLEMENTED) direct_trap( "Unimplemented", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_bug( const char *func, const char *file, int line, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(+) *** BUG [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_BUG) direct_trap( "Bug", SIGABRT ); } __dfb_no_instrument_function__ void direct_messages_warn( const char *func, const char *file, int line, const char *format, ... ) { char buf[512]; va_list ap; va_start( ap, format ); vsnprintf( buf, sizeof(buf), format, ap ); va_end( ap ); direct_log_printf( NULL, "(#) *** WARNING [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_WARNING) direct_trap( "Warning", SIGABRT ); } __dfb_no_instrument_function__ int direct_messages_oom( const char *func, const char *file, int line ) { direct_log_printf( NULL, "(=) *** OOM [out of memory] *** [%s:%d in %s()]\n", file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_OOM) direct_trap( "OOM", SIGABRT ); return DR_NOLOCALMEMORY; } __dfb_no_instrument_function__ int direct_messages_ooshm( const char *func, const char *file, int line ) { direct_log_printf( NULL, "(=) *** OOSHM [out of shared memory] *** [%s:%d in %s()]\n", file, line, func ); direct_trace_print_stack( NULL ); if (direct_config->fatal_messages & DMT_OOSHM) direct_trap( "OOSHM", SIGABRT ); return DR_NOSHAREDMEMORY; } #else /* DIRECT_BUILD_TEXT */ void direct_messages_info( const char *format, ... ) { } void direct_messages_error( const char *format, ... ) { } void direct_messages_derror( DirectResult result, const char *format, ... ) { } void direct_messages_perror( int erno, const char *format, ... ) { } void direct_messages_dlerror( const char *dlerr, const char *format, ... ) { } void direct_messages_once( const char *func, const char *file, int line, const char *format, ... ) { } void direct_messages_unimplemented( const char *func, const char *file, int line ) { } void direct_messages_bug( const char *func, const char *file, int line, const char *format, ... ) { } void direct_messages_warn( const char *func, const char *file, int line, const char *format, ... ) { } int direct_messages_oom( const char *func, const char *file, int line ) { return DR_NOLOCALMEMORY; } int direct_messages_ooshm( const char *func, const char *file, int line ) { return DR_NOSHAREDMEMORY; } #endif /* DIRECT_BUILD_TEXT */ ================================================ FILE: lib/direct/messages.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MESSAGES_H__ #define __DIRECT__MESSAGES_H__ #include /**********************************************************************************************************************/ void DIRECT_API direct_messages_info ( const char *format, ... ) D_FORMAT_PRINTF(1); void DIRECT_API direct_messages_error ( const char *format, ... ) D_FORMAT_PRINTF(1); void DIRECT_API direct_messages_derror ( DirectResult result, const char *format, ... ) D_FORMAT_PRINTF(2); void DIRECT_API direct_messages_perror ( int erno, const char *format, ... ) D_FORMAT_PRINTF(2); void DIRECT_API direct_messages_dlerror ( const char *dlerr, const char *format, ... ) D_FORMAT_PRINTF(2); void DIRECT_API direct_messages_once ( const char *func, const char *file, int line, const char *format, ... ) D_FORMAT_PRINTF(4); void DIRECT_API direct_messages_unimplemented( const char *func, const char *file, int line ); void DIRECT_API direct_messages_bug ( const char *func, const char *file, int line, const char *format, ... ) D_FORMAT_PRINTF(4); void DIRECT_API direct_messages_warn ( const char *func, const char *file, int line, const char *format, ... ) D_FORMAT_PRINTF(4); int DIRECT_API direct_messages_oom ( const char *func, const char *file, int line ); int DIRECT_API direct_messages_ooshm ( const char *func, const char *file, int line ); #define D_INFO(...) do { \ if (!(direct_config->quiet & DMT_INFO)) \ direct_messages_info( __VA_ARGS__ ); \ } while (0) #define D_ERROR(...) do { \ if (!(direct_config->quiet & DMT_ERROR)) \ direct_messages_error( __VA_ARGS__ ); \ } while (0) #define D_DERROR(r,...) do { \ if (!(direct_config->quiet & DMT_ERROR)) \ direct_messages_derror( (DirectResult) r, __VA_ARGS__ ); \ } while (0) #define D_PERROR(...) do { \ if (!(direct_config->quiet & DMT_ERROR)) \ direct_messages_perror( errno, __VA_ARGS__ ); \ } while (0) #define D_DLERROR(...) do { \ if (!(direct_config->quiet & DMT_ERROR)) \ direct_messages_dlerror( dlerror(), __VA_ARGS__ ); \ } while (0) #define D_ONCE(...) do { \ if (!(direct_config->quiet & DMT_ONCE)) { \ static bool first = true; \ if (first) { \ direct_messages_once( __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__ ); \ first = false; \ } \ } \ } while (0) #define D_UNIMPLEMENTED() do { \ if (!(direct_config->quiet & DMT_UNIMPLEMENTED)) { \ static bool first = true; \ if (first) { \ direct_messages_unimplemented( __FUNCTION__, __FILE__, __LINE__ ); \ first = false; \ } \ } \ } while (0) #define D_BUG(...) do { \ if (!(direct_config->quiet & DMT_BUG)) \ direct_messages_bug( __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__ ); \ } while (0) #define D_BREAK D_BUG #define D_WARN(...) do { \ if (!(direct_config->quiet & DMT_WARNING)) \ direct_messages_warn( __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__ ); \ } while (0) #define D_OOM() direct_messages_oom( __FUNCTION__, __FILE__, __LINE__ ) #endif ================================================ FILE: lib/direct/modules.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Direct_Modules, "Direct/Modules", "Direct Modules loading and registration" ); /**********************************************************************************************************************/ #if DIRECT_BUILD_DYNLOAD static DirectModuleEntry *lookup_by_name( const DirectModuleDir *directory, const char *name ); static DirectModuleEntry *lookup_by_file( const DirectModuleDir *directory, const char *file ); static void *open_module ( DirectModuleEntry *module ); static bool load_module ( DirectModuleEntry *module ); static void unload_module( DirectModuleEntry *module ); #endif /* DIRECT_BUILD_DYNLOAD */ /**********************************************************************************************************************/ static int suppress_module( const char *name ) { int i = 0; if (!direct_config || !direct_config->disable_module) return 0; while (direct_config->disable_module[i]) { if (strcmp( direct_config->disable_module[i], name ) == 0) { D_INFO( "Direct/Modules: Suppress module '%s'\n", direct_config->disable_module[i] ); return 1; } i++; } return 0; } void direct_modules_register( DirectModuleDir *directory, unsigned int abi_version, const char *name, const void *funcs ) { DirectModuleEntry *entry; D_ASSERT( directory != NULL ); D_ASSERT( name != NULL ); D_ASSERT( funcs != NULL ); D_DEBUG_AT( Direct_Modules, "Registering '%s' ('%s')...\n", name, directory->path ); #if DIRECT_BUILD_DYNLOAD if ((entry = lookup_by_name( directory, name )) != NULL) { D_DEBUG_AT( Direct_Modules, " -> found entry %p\n", entry ); D_MAGIC_ASSERT( entry, DirectModuleEntry ); entry->loaded = true; entry->funcs = funcs; return; } #endif /* DIRECT_BUILD_DYNLOAD */ if (directory->loading) { entry = directory->loading; D_MAGIC_ASSERT( entry, DirectModuleEntry ); directory->loading = NULL; } else { entry = D_CALLOC( 1, sizeof(DirectModuleEntry) ); if (!entry) { D_OOM(); return; } D_DEBUG_AT( Direct_Modules, " -> allocated entry %p\n", entry ); D_MAGIC_SET( entry, DirectModuleEntry ); } entry->directory = directory; entry->loaded = true; entry->name = D_STRDUP( name ); entry->funcs = funcs; entry->disabled = suppress_module( name ); if (abi_version != directory->abi_version) { D_ERROR( "Direct/Modules: ABI version of '%s' (%u) does not match %u!\n", entry->file ?: entry->name, abi_version, directory->abi_version ); entry->disabled = true; } direct_list_prepend( &directory->entries, &entry->link ); D_DEBUG_AT( Direct_Modules, "...registered as %p\n", entry ); } void direct_modules_unregister( DirectModuleDir *directory, const char *name ) { #if DIRECT_BUILD_DYNLOAD DirectModuleEntry *entry; #endif /* DIRECT_BUILD_DYNLOAD */ D_DEBUG_AT( Direct_Modules, "Unregistering '%s' ('%s')...\n", name, directory->path ); #if DIRECT_BUILD_DYNLOAD entry = lookup_by_name( directory, name ); if (!entry) { D_ERROR( "Direct/Modules: Unregister failed, could not find '%s' module!\n", name ); return; } D_MAGIC_ASSERT( entry, DirectModuleEntry ); D_FREE( entry->name ); D_FREE( entry->file ); direct_list_remove( &directory->entries, &entry->link ); D_MAGIC_CLEAR( entry ); D_FREE( entry ); #endif /* DIRECT_BUILD_DYNLOAD */ D_DEBUG_AT( Direct_Modules, "...unregistered\n" ); } int direct_modules_explore_directory( DirectModuleDir *directory ) { #if DIRECT_BUILD_DYNLOAD DirectResult ret; DirectDir dir; DirectEntry entry; int count = 0; const char *pathfront = ""; const char *path; char *buf; D_ASSERT( directory != NULL ); D_ASSERT( directory->path != NULL ); D_DEBUG_AT( Direct_Modules, "%s( '%s' )\n", __FUNCTION__, directory->path ); path = directory->path; if (path[0] != '/') { pathfront = direct_config->module_dir; if (!pathfront) pathfront = MODULEDIR; } buf = alloca( strlen( pathfront ) + 1 + strlen( path ) + 1 ); /* pre, slash, post, 0 */ sprintf( buf, "%s/%s", pathfront, path ); ret = direct_dir_open( &dir, buf ); if (ret) { D_DEBUG_AT( Direct_Modules, " -> error opening directory '%s'!\n", buf ); return 0; } while (direct_dir_read( &dir, &entry ) == DR_OK) { void *handle; DirectModuleEntry *module; int entry_len = strlen( entry.name ); if (entry_len < 4 || entry.name[entry_len-2] != 's' || entry.name[entry_len-1] != 'o') continue; if (lookup_by_file( directory, entry.name )) continue; module = D_CALLOC( 1, sizeof(DirectModuleEntry) ); if (!module) continue; D_DEBUG_AT( Direct_Modules, " -> allocated entry %p\n", module ); D_MAGIC_SET( module, DirectModuleEntry ); module->directory = directory; module->dynamic = true; module->file = D_STRDUP( entry.name ); if (!module->file) { D_MAGIC_CLEAR( module ); D_FREE( module ); continue; } directory->loading = module; if ((handle = open_module( module )) != NULL) { if (!module->loaded) { dlclose( handle ); D_ERROR( "Direct/Modules: Module '%s' did not register itself after loading!\n", entry.name ); module->disabled = true; direct_list_prepend( &directory->entries, &module->link ); } else if (module->disabled) { module->loaded = false; dlclose( handle ); } else { module->handle = handle; count++; } } else { module->disabled = true; direct_list_prepend( &directory->entries, &module->link ); } directory->loading = NULL; } direct_dir_close( &dir ); return count; #else /* DIRECT_BUILD_DYNLOAD */ return 0; #endif /* DIRECT_BUILD_DYNLOAD */ } const void * direct_module_ref( DirectModuleEntry *module ) { D_MAGIC_ASSERT( module, DirectModuleEntry ); D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs, loaded %d, dynamic %d, disabled %d )\n", __FUNCTION__, module, module->name, module->refs, module->loaded, module->dynamic, module->disabled ); if (module->disabled) return NULL; #if DIRECT_BUILD_DYNLOAD if (!module->loaded && !load_module( module )) { D_DEBUG_AT( Direct_Modules, " -> load_module failed, returning NULL\n" ); return NULL; } #endif /* DIRECT_BUILD_DYNLOAD */ module->refs++; D_DEBUG_AT( Direct_Modules, " -> refs %d, funcs %p\n", module->refs, module->funcs ); return module->funcs; } void direct_module_unref( DirectModuleEntry *module ) { D_MAGIC_ASSERT( module, DirectModuleEntry ); D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs, loaded %d, dynamic %d, disabled %d )\n", __FUNCTION__, module, module->name, module->refs, module->loaded, module->dynamic, module->disabled ); D_ASSERT( module->refs > 0 ); if (--module->refs) return; #if DIRECT_BUILD_DYNLOAD if (module->dynamic) unload_module( module ); #endif /* DIRECT_BUILD_DYNLOAD */ } /**********************************************************************************************************************/ #if DIRECT_BUILD_DYNLOAD static DirectModuleEntry * lookup_by_name( const DirectModuleDir *directory, const char *name ) { DirectModuleEntry *entry; D_ASSERT( directory != NULL ); D_ASSERT( name != NULL ); direct_list_foreach (entry, directory->entries) { D_MAGIC_ASSERT( entry, DirectModuleEntry ); if (!entry->name) continue; if (!strcmp( entry->name, name )) return entry; } return NULL; } static DirectModuleEntry * lookup_by_file( const DirectModuleDir *directory, const char *file ) { DirectModuleEntry *entry; D_DEBUG_AT( Direct_Modules, "%s()\n", __FUNCTION__ ); D_ASSERT( directory != NULL ); D_ASSERT( file != NULL ); direct_list_foreach (entry, directory->entries) { D_MAGIC_ASSERT( entry, DirectModuleEntry ); if (!entry->file) continue; if (!strcmp( entry->file, file )) return entry; } return NULL; } static bool load_module( DirectModuleEntry *module ) { D_MAGIC_ASSERT( module, DirectModuleEntry ); D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs ); D_ASSERT( module->dynamic == true ); D_ASSERT( module->file != NULL ); D_ASSERT( module->loaded == false ); D_ASSERT( module->disabled == false ); module->handle = open_module( module ); if (module->handle) module->loaded = true; return module->loaded; } static void unload_module( DirectModuleEntry *module ) { void *handle; D_MAGIC_ASSERT( module, DirectModuleEntry ); D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs ); D_ASSERT( module->dynamic == true ); D_ASSERT( module->loaded == true ); D_ASSUME( module->handle != NULL ); handle = module->handle; if (handle) { module->handle = NULL; module->loaded = false; dlclose( handle ); } } static void * open_module( DirectModuleEntry *module ) { DirectModuleDir *directory; const char *pathfront = ""; const char *path; char *buf; void *handle; D_MAGIC_ASSERT( module, DirectModuleEntry ); D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs ); D_ASSERT( module->file != NULL ); D_ASSERT( module->directory != NULL ); D_ASSERT( module->directory->path != NULL ); directory = module->directory; path = directory->path; if (path[0] != '/') { pathfront = direct_config->module_dir; if (!pathfront) pathfront = MODULEDIR; } buf = alloca( strlen( pathfront ) + 1 + strlen( path ) + 1 + strlen( module->file ) + 1 ); sprintf( buf, "%s/%s/%s", pathfront, path, module->file ); D_DEBUG_AT( Direct_Modules, "Loading '%s'...\n", buf ); handle = dlopen( buf, RTLD_NOW ); D_DEBUG_AT( Direct_Modules, " -> dlopen() returned %p\n", handle ); if (!handle) D_DLERROR( "Direct/Modules: Unable to dlopen '%s'!\n", buf ); return handle; } #endif /* DIRECT_BUILD_DYNLOAD */ ================================================ FILE: lib/direct/modules.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MODULES_H__ #define __DIRECT__MODULES_H__ #include #include /**********************************************************************************************************************/ struct __D_DirectModuleEntry { DirectLink link; int magic; DirectModuleDir *directory; bool loaded; bool dynamic; bool disabled; char *name; const void *funcs; int refs; char *file; void *handle; }; struct __D_DirectModuleDir { const char *path; unsigned int abi_version; DirectLink *entries; DirectModuleEntry *loading; }; #define DECLARE_MODULE_DIRECTORY(d) \ extern DirectModuleDir d #define DEFINE_MODULE_DIRECTORY(d,p,n) \ DirectModuleDir d = { \ p, \ n, \ NULL, \ NULL, \ } /**********************************************************************************************************************/ void DIRECT_API direct_modules_register ( DirectModuleDir *directory, unsigned int abi_version, const char *name, const void *funcs ); void DIRECT_API direct_modules_unregister ( DirectModuleDir *directory, const char *name ); int DIRECT_API direct_modules_explore_directory( DirectModuleDir *directory ); const void DIRECT_API *direct_module_ref ( DirectModuleEntry *module ); void DIRECT_API direct_module_unref ( DirectModuleEntry *module ); #endif ================================================ FILE: lib/direct/mutex.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__MUTEX_H__ #define __DIRECT__MUTEX_H__ #include /**********************************************************************************************************************/ #endif ================================================ FILE: lib/direct/os/clock.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__CLOCK_H__ #define __DIRECT__OS__CLOCK_H__ #include /**********************************************************************************************************************/ typedef enum { DIRECT_CLOCK_SESSION = 0x53551011, /* Derived from monotonic clock. */ DIRECT_CLOCK_REALTIME = 0x00000000, DIRECT_CLOCK_MONOTONIC = 0x00000001, DIRECT_CLOCK_PROCESS_CPUTIME_ID = 0x00000002, DIRECT_CLOCK_THREAD_CPUTIME_ID = 0x00000003 } DirectClockType; long long DIRECT_API direct_clock_get_time ( DirectClockType type ); DirectResult DIRECT_API direct_clock_set_time ( DirectClockType type, long long micros ); long long DIRECT_API direct_clock_resolution( DirectClockType type ); #endif ================================================ FILE: lib/direct/os/filesystem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__FILESYSTEM_H__ #define __DIRECT__OS__FILESYSTEM_H__ #include /**********************************************************************************************************************/ typedef struct { char name[256]; } DirectEntry; typedef enum { DFP_NONE = 0x00000000, DFP_READ = 0x00000001, DFP_WRITE = 0x00000002, DFP_ALL = 0x00000003 } DirectFilePermission; typedef enum { DFIF_NONE = 0x00000000, DFIF_SIZE = 0x00000001, DFIF_ALL = 0x00000001 } DirectFileInfoFlags; typedef struct { DirectFileInfoFlags flags; size_t size; } DirectFileInfo; #define R_OK 4 #define W_OK 2 #define F_OK 0 /**********************************************************************************************************************/ DirectResult DIRECT_API direct_dir_get_current( char *buf, size_t length ); DirectResult DIRECT_API direct_dir_change ( const char *name ); DirectResult DIRECT_API direct_dir_create ( const char *name, mode_t mode ); DirectResult DIRECT_API direct_dir_open ( DirectDir *dir, const char *name ); DirectResult DIRECT_API direct_dir_read ( DirectDir *dir, DirectEntry *entry ); DirectResult DIRECT_API direct_dir_rewind ( DirectDir *dir ); DirectResult DIRECT_API direct_dir_close ( DirectDir *dir ); DirectResult DIRECT_API direct_dir_remove ( const char *name ); DirectResult DIRECT_API direct_file_open ( DirectFile *file, const char *name, int flags, mode_t mode ); DirectResult DIRECT_API direct_file_read ( DirectFile *file, void *buffer, size_t bytes, size_t *ret_bytes ); DirectResult DIRECT_API direct_file_write ( DirectFile *file, const void *buffer, size_t bytes, size_t *ret_bytes ); DirectResult DIRECT_API direct_file_seek ( DirectFile *file, off_t offset ); DirectResult DIRECT_API direct_file_seek_to ( DirectFile *file, off_t offset ); DirectResult DIRECT_API direct_file_close ( DirectFile *file ); DirectResult DIRECT_API direct_file_map ( DirectFile *file, void *addr, size_t offset, size_t bytes, DirectFilePermission perms, void **ret_addr ); DirectResult DIRECT_API direct_file_unmap ( void *addr, size_t bytes ); DirectResult DIRECT_API direct_file_get_info ( DirectFile *file, DirectFileInfo *ret_info ); DirectResult DIRECT_API direct_file_chmod ( DirectFile *file, mode_t mode ); DirectResult DIRECT_API direct_file_chown ( DirectFile *file, uid_t owner, gid_t group ); DirectResult DIRECT_API direct_file_truncate ( DirectFile *file, off_t length ); DirectResult DIRECT_API direct_file_get_string( DirectFile *file, char *buf, size_t length ); DirectResult DIRECT_API direct_popen ( DirectFile *file, const char *name, int flags ); DirectResult DIRECT_API direct_pclose ( DirectFile *file ); DirectResult DIRECT_API direct_access ( const char *name, int flags ); DirectResult DIRECT_API direct_chmod ( const char *name, mode_t mode ); DirectResult DIRECT_API direct_chown ( const char *name, uid_t owner, gid_t group ); DirectResult DIRECT_API direct_readlink ( const char *name, char *buf, size_t length, ssize_t *ret_length ); DirectResult DIRECT_API direct_unlink ( const char *name ); DirectResult DIRECT_API direct_filesystem_size( const char *name, size_t *size ); #endif ================================================ FILE: lib/direct/os/linux/clock.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static long long session_clock_offset; /**********************************************************************************************************************/ __attribute__((no_instrument_function)) long long direct_clock_get_time( DirectClockType type ) { long long micros; struct timespec spec; clockid_t clock_id; switch (type) { case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_SESSION: case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } if (clock_gettime( clock_id, &spec ) < 0) { if (clock_id != CLOCK_REALTIME) { D_WARN( "clock with id %d not supported by system", clock_id ); return direct_clock_get_time( DIRECT_CLOCK_REALTIME ); } D_PERROR( "Direct/Clock: Could not get real time clock!\n" ); return 0; } micros = spec.tv_sec * 1000000LL + spec.tv_nsec / 1000LL; if (type == DIRECT_CLOCK_SESSION) micros -= session_clock_offset; return micros; } __attribute__((no_instrument_function)) DirectResult direct_clock_set_time( DirectClockType type, long long micros ) { DirectResult ret; clockid_t clock_id; struct timespec spec; switch (type) { case DIRECT_CLOCK_SESSION: session_clock_offset = micros; return DR_OK; case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } spec.tv_sec = micros / 1000000LL; spec.tv_nsec = micros % 1000000LL * 1000LL; if (clock_settime( clock_id, &spec ) < 0) { ret = errno2result( errno ); D_PERROR( "Direct/Clock: Could not set clock with id %d!\n", clock_id ); return ret; } return DR_OK; } __attribute__((no_instrument_function)) long long direct_clock_resolution( DirectClockType type ) { struct timespec spec; clockid_t clock_id; switch (type) { case DIRECT_CLOCK_SESSION: case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } if (clock_getres( clock_id, &spec ) < 0) { if (clock_id != CLOCK_REALTIME) { D_WARN( "clock with id %d not supported by system", clock_id ); return direct_clock_resolution( DIRECT_CLOCK_REALTIME ); } D_PERROR( "Direct/Clock: Could not get real time clock resolution!\n" ); return 0; } return spec.tv_sec * 1000000LL + spec.tv_nsec / 1000LL; } ================================================ FILE: lib/direct/os/linux/filesystem.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ DirectResult direct_dir_get_current( char *buf, size_t length ) { D_ASSERT( buf != NULL ); if (!getcwd( buf, length )) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_change( const char *name ) { D_ASSERT( name != NULL ); if (chdir( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_create( const char *name, mode_t mode ) { D_ASSERT( name != NULL ); if (mkdir( name, mode ) < 0) { if (errno == EEXIST) return DR_BUSY; else return errno2result( errno ); } return DR_OK; } DirectResult direct_dir_open( DirectDir *dir, const char *name ) { D_ASSERT( dir != NULL ); D_ASSERT( name != NULL ); dir->dir = opendir( name ); if (!dir->dir) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_read( DirectDir *dir, DirectEntry *entry ) { struct dirent *ent; D_ASSERT( dir != NULL ); D_ASSERT( entry != NULL ); ent = readdir( dir->dir ); if (!ent) return errno ? errno2result( errno ) : DR_ITEMNOTFOUND; else strcpy( entry->name, ent->d_name ); return DR_OK; } DirectResult direct_dir_rewind( DirectDir *dir ) { D_ASSERT( dir != NULL ); rewinddir( dir->dir ); return DR_OK; } DirectResult direct_dir_close( DirectDir *dir ) { int err; D_ASSERT( dir != NULL ); err = closedir( dir->dir ); dir->dir = NULL; if (err < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_remove( const char *name ) { D_ASSERT( name != NULL ); if (rmdir( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_open( DirectFile *file, const char *name, int flags, mode_t mode ) { D_ASSERT( file != NULL ); D_ASSERT( name != NULL ); file->file = NULL; file->fd = open( name, flags, mode ); if (file->fd < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_read( DirectFile *file, void *buffer, size_t bytes, size_t *ret_bytes ) { ssize_t num; D_ASSERT( file != NULL ); D_ASSERT( buffer != NULL ); num = read( file->fd, buffer, bytes ); if (num < 0) return errno2result( errno ); if (ret_bytes) *ret_bytes = num; return DR_OK; } DirectResult direct_file_write( DirectFile *file, const void *buffer, size_t bytes, size_t *ret_bytes ) { ssize_t num; D_ASSERT( file != NULL ); D_ASSERT( buffer != NULL ); num = write( file->fd, buffer, bytes ); if (num < 0) return errno2result( errno ); if (ret_bytes) *ret_bytes = num; return DR_OK; } DirectResult direct_file_seek( DirectFile *file, off_t offset ) { D_ASSERT( file != NULL ); if (lseek( file->fd, offset, SEEK_CUR ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_seek_to( DirectFile *file, off_t offset ) { D_ASSERT( file != NULL ); if (lseek( file->fd, offset, SEEK_SET ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_close( DirectFile *file ) { int err; D_ASSERT( file != NULL ); if (file->file) { err = fclose( file->file ); file->file = NULL; } else err = close( file->fd ); file->fd = -1; if (err < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_map( DirectFile *file, void *addr, size_t offset, size_t bytes, DirectFilePermission perms, void **ret_addr ) { void *map; int prot = 0; int flags = MAP_SHARED; D_ASSERT( file != NULL ); D_ASSERT( ret_addr != NULL ); if (perms & DFP_READ) prot |= PROT_READ; if (perms & DFP_WRITE) prot |= PROT_WRITE; if (addr) flags |= MAP_FIXED; map = mmap( addr, bytes, prot, flags, file->fd, offset ); if (map == MAP_FAILED) return errno2result( errno ); *ret_addr = map; return DR_OK; } DirectResult direct_file_unmap( void *addr, size_t bytes ) { if (munmap( addr, bytes ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_get_info( DirectFile *file, DirectFileInfo *ret_info ) { struct stat st; D_ASSERT( file != NULL ); D_ASSERT( ret_info != NULL ); if (fstat( file->fd, &st ) < 0) return errno2result( errno ); ret_info->flags = DFIF_SIZE; ret_info->size = st.st_size; return DR_OK; } DirectResult direct_file_chmod( DirectFile *file, mode_t mode ) { D_ASSERT( file != NULL ); if (fchmod( file->fd, mode ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_chown( DirectFile *file, uid_t owner, gid_t group ) { D_ASSERT( file != NULL ); if (fchown( file->fd, owner, group ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_truncate( DirectFile *file, off_t length ) { D_ASSERT( file != NULL ); if (ftruncate( file->fd, length ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_get_string( DirectFile *file, char *buf, size_t length ) { D_ASSERT( file != NULL ); D_ASSERT( buf != NULL ); if (!file->file) { file->file = fdopen( file->fd, "r" ); if (!file->file) return errno2result( errno ); } if (!fgets( buf, length, file->file )) { if (feof( file->file )) return DR_EOF; return DR_FAILURE; } return DR_OK; } DirectResult direct_popen( DirectFile *file, const char *name, int flags ) { D_ASSERT( file != NULL ); D_ASSERT( name != NULL ); file->file = popen( name, (flags & O_WRONLY) ? "w" : (flags & O_RDWR) ? "rw" : "r" ); if (!file->file) return errno2result( errno ); file->fd = fileno( file->file ); return DR_OK; } DirectResult direct_pclose( DirectFile *file ) { D_ASSERT( file != NULL ); D_ASSERT( file->file != NULL ); if (pclose( file->file ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_access( const char *name, int flags ) { D_ASSERT( name != NULL ); if (access( name, flags ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_chmod( const char *name, mode_t mode ) { D_ASSERT( name != NULL ); if (chmod( name, mode ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_chown( const char *name, uid_t owner, gid_t group ) { D_ASSERT( name != NULL ); if (chown( name, owner, group ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_readlink( const char *name, char *buf, size_t length, ssize_t *ret_length ) { ssize_t len; D_ASSERT( name != NULL ); len = readlink( name, buf, length ); if (len < 0) return errno2result( errno ); if (ret_length) *ret_length = len; return DR_OK; } DirectResult direct_unlink( const char *name ) { D_ASSERT( name != NULL ); if (unlink( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_filesystem_size( const char *name, size_t *size ) { struct statfs stat; D_ASSERT( name != NULL ); if (statfs( name, &stat ) < 0) return errno2result( errno ); *size = stat.f_blocks * stat.f_bsize; return DR_OK; } ================================================ FILE: lib/direct/os/linux/filesystem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LINUX__FILESYSTEM_H__ #define __DIRECT__OS__LINUX__FILESYSTEM_H__ #include /**********************************************************************************************************************/ typedef struct { DIR *dir; } DirectDir; typedef struct { int fd; FILE *file; } DirectFile; #endif ================================================ FILE: lib/direct/os/linux/log.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_NETWORK #define _GNU_SOURCE /* To get EAI_ADDRFAMILY and EAI_NODATA definition. */ #endif /* DIRECT_BUILD_NETWORK */ #include #include #include /**********************************************************************************************************************/ static DirectResult init_stderr( DirectLog *log ); static DirectResult init_file ( DirectLog *log, const char *filename ); static DirectResult init_udp ( DirectLog *log, const char *hostport ); /**********************************************************************************************************************/ DirectResult direct_log_init( DirectLog *log, const char *param ) { switch (log->type) { case DLT_STDERR: return init_stderr( log ); case DLT_FILE: return init_file( log, param ); case DLT_UDP: return init_udp( log, param ); default: break; } return DR_UNSUPPORTED; } DirectResult direct_log_deinit( DirectLog *log ) { close( (long) log->data ); return DR_OK; } /**********************************************************************************************************************/ __attribute__((no_instrument_function)) static DirectResult common_log_write( DirectLog *log, const char *buffer, size_t bytes ) { ssize_t sz; sz = write( (long) log->data, buffer, bytes ); if (sz < 0) D_PERROR( "Direct/Log: Could not write to log!\n" ); return DR_OK; } __attribute__((no_instrument_function)) static DirectResult common_log_flush( DirectLog *log ) { if (log->type == DLT_STDERR && fflush( stderr )) return errno2result( errno ); return DR_OK; } __attribute__((no_instrument_function)) static DirectResult stderr_log_write( DirectLog *log, const char *buffer, size_t bytes ) { fwrite( buffer, bytes, 1, stderr ); return DR_OK; } static DirectResult init_stderr( DirectLog *log ) { log->data = (void*)(long) dup( fileno( stderr ) ); log->write = stderr_log_write; log->flush = common_log_flush; return DR_OK; } static DirectResult init_file( DirectLog *log, const char *filename ) { DirectResult ret; int fd; fd = open( filename, O_WRONLY | O_CREAT | O_APPEND, 0664 ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "Direct/Log: Could not open '%s' for writing!\n", filename ); return ret; } log->data = (void*)(long) fd; log->write = common_log_write; log->flush = common_log_flush; return DR_OK; } #if DIRECT_BUILD_NETWORK static DirectResult parse_host_addr( const char *hostport, struct addrinfo **ret_addr ) { int err, i; int size = strlen( hostport ) + 1; char buf[size]; char *hoststr = buf; char *portstr = NULL; char *end; struct addrinfo hints; memcpy( buf, hostport, size ); for (i = 0; i < size; i++) { if (buf[i] == ':') { buf[i] = 0; portstr = &buf[i+1]; break; } } if (!portstr) { D_ERROR( "Direct/Log: Parse error in '%s' that should be ':'!\n", hostport ); return DR_INVARG; } strtoul( portstr, &end, 10 ); if (end && *end) { D_ERROR( "Direct/Log: Parse error in port number '%s'!\n", portstr ); return DR_INVARG; } memset( &hints, 0, sizeof(hints) ); hints.ai_socktype = SOCK_DGRAM; hints.ai_family = PF_UNSPEC; err = getaddrinfo( hoststr, portstr, &hints, ret_addr ); if (err) { switch (err) { case EAI_FAMILY: D_ERROR( "Direct/Log: Unsupported address family!\n" ); return DR_UNSUPPORTED; case EAI_SOCKTYPE: D_ERROR( "Direct/Log: Unsupported socket type!\n" ); return DR_UNSUPPORTED; case EAI_NONAME: D_ERROR( "Direct/Log: Host not found!\n" ); return DR_FAILURE; case EAI_SERVICE: D_ERROR( "Direct/Log: Port %s is unreachable!\n", portstr ); return DR_FAILURE; case EAI_ADDRFAMILY: case EAI_NODATA: D_ERROR( "Direct/Log: Host found, but has no address!\n" ); return DR_FAILURE; case EAI_MEMORY: return D_OOM(); case EAI_FAIL: D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); return DR_FAILURE; case EAI_AGAIN: D_ERROR( "Direct/Log: Temporary error, try again!\n" ); return DR_TEMPUNAVAIL; default: D_ERROR( "Direct/Log: Unknown error occurred!\n" ); return DR_FAILURE; } } return DR_OK; } static DirectResult init_udp( DirectLog *log, const char *hostport ) { DirectResult ret; int fd; struct addrinfo *addr; ret = parse_host_addr( hostport, &addr ); if (ret) return ret; fd = socket( addr->ai_family, SOCK_DGRAM, 0 ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "Direct/Log: Could not create a UDP socket!\n" ); freeaddrinfo( addr ); return ret; } ret = connect( fd, addr->ai_addr, addr->ai_addrlen ); if (ret) { ret = errno2result( errno ); D_PERROR( "Direct/Log: Could not connect UDP socket to '%s'!\n", hostport ); freeaddrinfo( addr ); close( fd ); return ret; } freeaddrinfo( addr ); log->data = (void*)(long) fd; log->write = common_log_write; log->flush = common_log_flush; return DR_OK; } #else /* DIRECT_BUILD_NETWORK */ static DirectResult init_udp( DirectLog *log, const char *hostport ) { return DR_UNSUPPORTED; } #endif /* DIRECT_BUILD_NETWORK */ ================================================ FILE: lib/direct/os/linux/mem.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_SENTINELS #include D_DEBUG_DOMAIN( Direct_Sentinels, "Direct/Sentinels", "Direct Sentinels" ); #endif /* DIRECT_BUILD_SENTINELS */ /**********************************************************************************************************************/ #if DIRECT_BUILD_SENTINELS #define PREFIX_SENTINEL 8 #define SUFFIX_SENTINEL 8 #define TOTAL_SENTINEL ((PREFIX_SENTINEL) + (SUFFIX_SENTINEL)) __attribute__((no_instrument_function)) static inline void install_sentinels( void *p, size_t size ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + size; D_DEBUG_AT( Direct_Sentinels, "%s( %p, "_ZU" )\n", __FUNCTION__, p, size ); *ps = size; for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) prefix[i] = i; for (i = 0; i < SUFFIX_SENTINEL; i++) suffix[i] = i; } __attribute__((no_instrument_function)) static inline void remove_sentinels( void *p ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + *ps; D_DEBUG_AT( Direct_Sentinels, "%s( %p )\n", __FUNCTION__, p ); for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) prefix[i] = 0; for (i = 0; i < SUFFIX_SENTINEL; i++) suffix[i] = 0; } __attribute__((no_instrument_function)) static inline void check_sentinels( void *p ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + *ps; for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) { if (prefix[i] != i) D_DEBUG_AT( Direct_Sentinels, "Sentinel error at prefix["_ZU"] (%u) of "_ZU" bytes allocation!\n", i, prefix[i], *ps ); } for (i = 0; i < SUFFIX_SENTINEL; i++) { if (suffix[i] != i) D_DEBUG_AT( Direct_Sentinels, "Sentinel error at suffix["_ZU"] (%u) of "_ZU" bytes allocation!\n", i, suffix[i], *ps ); } } __attribute__((no_instrument_function)) void * direct_malloc( size_t bytes ) { void *p = bytes ? malloc( bytes + TOTAL_SENTINEL ) : NULL; if (!p) return NULL; install_sentinels( p, bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void * direct_calloc( size_t count, size_t bytes) { void *p = (count && bytes) ? calloc( 1, count * bytes + TOTAL_SENTINEL ) : NULL; if (!p) return NULL; install_sentinels( p, count * bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void * direct_realloc( void *mem, size_t bytes ) { void *p = mem ? mem - PREFIX_SENTINEL : NULL; if (!mem) return direct_malloc( bytes ); check_sentinels( p ); if (!bytes) { direct_free( mem ); return NULL; } p = realloc( p, bytes + TOTAL_SENTINEL ); if (!p) return NULL; install_sentinels( p, bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) char * direct_strdup( const char *str ) { int n = strlen( str ); void *p = malloc( n+1 + TOTAL_SENTINEL ); if (!p) return NULL; memcpy( p + PREFIX_SENTINEL, str, n + 1 ); install_sentinels( p, n + 1 ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void direct_free( void *mem ) { void *p = mem ? mem - PREFIX_SENTINEL : NULL; if (p) { check_sentinels( p ); remove_sentinels( p ); free( p ); } } #else /* DIRECT_BUILD_SENTINELS */ __attribute__((no_instrument_function)) void * direct_malloc( size_t bytes ) { return malloc( bytes ); } __attribute__((no_instrument_function)) void * direct_calloc( size_t count, size_t bytes) { return calloc( count, bytes ); } __attribute__((no_instrument_function)) void * direct_realloc( void *mem, size_t bytes ) { return realloc( mem, bytes ); } __attribute__((no_instrument_function)) char * direct_strdup( const char *str ) { return strdup( str ); } __attribute__((no_instrument_function)) void direct_free( void *mem ) { free( mem ); } #endif /* DIRECT_BUILD_SENTINELS */ ================================================ FILE: lib/direct/os/linux/mutex.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ DirectResult direct_mutex_init( DirectMutex *mutex ) { int erno = pthread_mutex_init( &mutex->lock, NULL ); return errno2result( erno ); } DirectResult direct_recursive_mutex_init( DirectMutex *mutex ) { DirectResult ret = DR_OK; int erno; pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); erno = pthread_mutex_init( &mutex->lock, &attr ); if (erno) { ret = errno2result( erno ); D_PERROR( "Direct/Mutex: Could not initialize recursive mutex!\n" ); } pthread_mutexattr_destroy( &attr ); return ret; } __attribute__((no_instrument_function)) DirectResult direct_mutex_lock( DirectMutex *mutex ) { int erno = pthread_mutex_lock( &mutex->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_mutex_unlock( DirectMutex *mutex ) { int erno = pthread_mutex_unlock( &mutex->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_mutex_trylock( DirectMutex *mutex ) { int erno = pthread_mutex_trylock( &mutex->lock ); return errno2result( erno ); } DirectResult direct_mutex_deinit( DirectMutex *mutex ) { int erno = pthread_mutex_destroy( &mutex->lock ); return errno2result( erno ); } DirectResult direct_rwlock_init( DirectRWLock *rwlock ) { int erno = pthread_rwlock_init( &rwlock->lock, NULL ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_rdlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_rdlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_wrlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_wrlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_unlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_unlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_trywrlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_trywrlock( &rwlock->lock ); return errno2result( erno ); } DirectResult direct_rwlock_deinit( DirectRWLock *rwlock ) { int erno = pthread_rwlock_destroy( &rwlock->lock ); return errno2result( erno ); } ================================================ FILE: lib/direct/os/linux/mutex.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LINUX__MUTEX_H__ #define __DIRECT__OS__LINUX__MUTEX_H__ #include /**********************************************************************************************************************/ typedef struct { pthread_mutex_t lock; } DirectMutex; #define DIRECT_MUTEX_INITIALIZER() { PTHREAD_MUTEX_INITIALIZER } typedef struct { pthread_rwlock_t lock; } DirectRWLock; #endif ================================================ FILE: lib/direct/os/linux/signals.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Signals, "Direct/Signals", "Direct Signals handling" ); /**********************************************************************************************************************/ struct __D_DirectSignalHandler { DirectLink link; int magic; int num; DirectSignalHandlerFunc func; void *ctx; bool removed; }; /**********************************************************************************************************************/ typedef struct { int signum; struct sigaction old_action; struct sigaction new_action; } SigHandled; static int sigs_to_handle[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, SIGXCPU, SIGXFSZ, SIGSYS }; #define NUM_SIGS_TO_HANDLE (D_ARRAY_SIZE(sigs_to_handle)) static SigHandled sigs_handled[NUM_SIGS_TO_HANDLE]; static DirectLink *handlers = NULL; static DirectMutex handlers_lock; static DirectThread *sighandler_thread = NULL; static void *handle_signals( DirectThread *thread, void *arg ); static void install_handlers( void ); static void remove_handlers ( void ); /**********************************************************************************************************************/ DirectResult direct_signals_initialize() { sigset_t mask; int i; D_DEBUG_AT( Direct_Signals, "%s() initializing...\n", __FUNCTION__ ); direct_recursive_mutex_init( &handlers_lock ); if (direct_config->sighandler) { if (direct_config->sighandler_thread) { sigemptyset( &mask ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) sigaddset( &mask, sigs_to_handle[i] ); sigprocmask( SIG_BLOCK, &mask, NULL ); sighandler_thread = direct_thread_create( DTT_CRITICAL, handle_signals, NULL, "SigHandler" ); D_ASSERT( sighandler_thread != NULL ); } else install_handlers(); } return DR_OK; } DirectResult direct_signals_shutdown() { D_DEBUG_AT( Direct_Signals, "%s() shutting down...\n", __FUNCTION__ ); if (direct_config->sighandler_thread) { if (sighandler_thread) { direct_thread_kill( sighandler_thread, SIGSYS ); direct_thread_join( sighandler_thread ); direct_thread_destroy( sighandler_thread ); sighandler_thread = NULL; } } else remove_handlers(); direct_mutex_deinit( &handlers_lock ); return DR_OK; } void direct_signals_block_all() { sigset_t signals; D_DEBUG_AT( Direct_Signals, "Blocking all signals from now on\n" ); sigfillset( &signals ); sigprocmask( SIG_BLOCK, &signals, NULL ); } DirectResult direct_signal_handler_add( int num, DirectSignalHandlerFunc func, void *ctx, DirectSignalHandler **ret_handler ) { DirectSignalHandler *handler; D_ASSERT( func != NULL ); D_ASSERT( ret_handler != NULL ); D_DEBUG_AT( Direct_Signals, "Adding handler %p for signal %d with context %p...\n", func, num, ctx ); handler = D_CALLOC( 1, sizeof(DirectSignalHandler) ); if (!handler) { return DR_NOLOCALMEMORY; } handler->num = num; handler->func = func; handler->ctx = ctx; D_MAGIC_SET( handler, DirectSignalHandler ); direct_mutex_lock( &handlers_lock ); direct_list_append( &handlers, &handler->link ); direct_mutex_unlock( &handlers_lock ); *ret_handler = handler; return DR_OK; } DirectResult direct_signal_handler_remove( DirectSignalHandler *handler ) { D_MAGIC_ASSERT( handler, DirectSignalHandler ); D_DEBUG_AT( Direct_Signals, "Removing handler %p for signal %d with context %p...\n", handler->func, handler->num, handler->ctx ); /* Mark the handler for removal, freeing will actually come later. */ handler->removed = true; return DR_OK; } /**********************************************************************************************************************/ static bool show_segv( const siginfo_t *info ) { switch (info->si_code) { case SEGV_MAPERR: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, invalid address) <--\n", info->si_signo, info->si_addr ); return true; case SEGV_ACCERR: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, invalid permissions) <--\n", info->si_signo, info->si_addr ); return true; } return false; } static bool show_bus( const siginfo_t *info ) { switch (info->si_code) { case BUS_ADRALN: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, invalid address alignment) <--\n", info->si_signo, info->si_addr ); return true; case BUS_ADRERR: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, non-existent physical address) <--\n", info->si_signo, info->si_addr ); return true; case BUS_OBJERR: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, object specific hardware error) <--\n", info->si_signo, info->si_addr ); return true; } return false; } static bool show_ill( const siginfo_t *info ) { switch (info->si_code) { case ILL_ILLOPC: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, illegal opcode) <--\n", info->si_signo, info->si_addr ); return true; case ILL_ILLOPN: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, illegal operand) <--\n", info->si_signo, info->si_addr ); return true; case ILL_ILLADR: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, illegal addressing mode) <--\n", info->si_signo, info->si_addr ); return true; case ILL_ILLTRP: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, illegal trap) <--\n", info->si_signo, info->si_addr ); return true; case ILL_PRVOPC: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, privileged opcode) <--\n", info->si_signo, info->si_addr ); return true; case ILL_PRVREG: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, privileged register) <--\n", info->si_signo, info->si_addr ); return true; case ILL_COPROC: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, coprocessor error) <--\n", info->si_signo, info->si_addr ); return true; case ILL_BADSTK: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, internal stack error) <--\n", info->si_signo, info->si_addr ); return true; } return false; } static bool show_fpe( const siginfo_t *info ) { switch (info->si_code) { case FPE_INTDIV: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, integer divide by zero) <--\n", info->si_signo, info->si_addr ); return true; case FPE_FLTDIV: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p, floating point divide by zero) <--\n", info->si_signo, info->si_addr ); return true; } D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (at %p) <--\n", info->si_signo, info->si_addr ); return true; } static bool show_any( const siginfo_t *info ) { switch (info->si_code) { case SI_USER: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (sent by pid %d, uid %u) <--\n", info->si_signo, info->si_pid, info->si_uid ); return true; case SI_QUEUE: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (queued by pid %d, uid %u, val %d) <--\n", info->si_signo, info->si_pid, info->si_uid, info->si_int ); return true; case SI_KERNEL: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (sent by the kernel) <--\n", info->si_signo ); return true; } return false; } static void call_handlers( int num, void *addr ) { DirectSignalHandler *handler, *temp; DirectLink *garbage = NULL; if (num == SIGPIPE) num = DIRECT_SIGNAL_DUMP_STACK; /* Loop through all handlers. */ direct_mutex_lock( &handlers_lock ); direct_list_foreach_safe (handler, temp, handlers) { if (handler->removed) { direct_list_remove( &handlers, &handler->link ); direct_list_append( &garbage, &handler->link ); continue; } D_LOG( Direct_Signals, FATAL, " --> %d\n", handler->num ); if (handler->num != num && handler->num != DIRECT_SIGNAL_ANY) continue; if (handler->num == DIRECT_SIGNAL_ANY && num == DIRECT_SIGNAL_DUMP_STACK) continue; switch (handler->func( num, addr, handler->ctx )) { case DSHR_OK: break; case DSHR_REMOVE: direct_list_remove( &handlers, &handler->link ); direct_list_append( &garbage, &handler->link ); break; case DSHR_RESUME: D_LOG( Direct_Signals, FATAL, " '-> cured!\n" ); direct_mutex_unlock( &handlers_lock ); return; default: D_BUG( "unknown result" ); break; } } direct_list_foreach_safe (handler, temp, handlers) { D_MAGIC_CLEAR( handler ); D_FREE( handler ); } direct_mutex_unlock( &handlers_lock ); } static void signal_handler( int num, siginfo_t *info, void *uctx ) { void *addr = NULL; sigset_t mask; if (info && info > (siginfo_t*) 0x100) { bool shown = false; /* Kernel generated signal. */ if (info->si_code > 0 && info->si_code < 0x80) { addr = info->si_addr; switch (num) { case SIGSEGV: shown = show_segv( info ); break; case SIGBUS: shown = show_bus( info ); break; case SIGILL: shown = show_ill( info ); break; case SIGFPE: shown = show_fpe( info ); break; default: D_LOG( Direct_Signals, FATAL, " --> Caught signal %d <--\n", info->si_signo ); addr = NULL; shown = true; break; } } else shown = show_any( info ); if (!shown) D_LOG( Direct_Signals, FATAL, " --> Caught signal %d (unknown origin) <--\n", info->si_signo ); } else D_LOG( Direct_Signals, FATAL, " --> Caught signal %d, no siginfo available <--\n", num ); direct_trace_print_stacks(); call_handlers( num, addr ); sigemptyset( &mask ); sigaddset( &mask, num ); sigprocmask( SIG_UNBLOCK, &mask, NULL ); direct_trap( "SigHandler", num ); sigprocmask( SIG_BLOCK, &mask, NULL ); } /**********************************************************************************************************************/ static void * handle_signals( DirectThread *thread, void *arg ) { int i; int res; siginfo_t info; sigset_t mask; D_DEBUG_AT( Direct_Signals, "%s()\n", __FUNCTION__ ); sigemptyset( &mask ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) { if (direct_config->sighandler && !sigismember( &direct_config->dont_catch, sigs_to_handle[i] )) sigaddset( &mask, sigs_to_handle[i] ); } sigaddset( &mask, SIGSYS ); sigaddset( &mask, SIGPIPE ); sigprocmask( SIG_BLOCK, &mask, NULL ); while (1) { D_DEBUG_AT( Direct_Signals, "%s() -> waiting for a signal...\n", __FUNCTION__ ); res = sigwaitinfo( &mask, &info ); if (res == -1) { D_DEBUG_AT( Direct_Signals, "%s() -> got error %s\n", __FUNCTION__, direct_strerror( errno ) ); } else { if (SIGSYS == info.si_signo) { D_DEBUG_AT( Direct_Signals, " -> got close signal %d (me %d, from %d)\n", SIGSYS, direct_getpid(), info.si_pid ); if (direct_getpid() == info.si_pid) break; D_DEBUG_AT( Direct_Signals, " -> not stopping signal handler from other process signal\n" ); } else if (SIGPIPE == info.si_signo) { D_DEBUG_AT( Direct_Signals, " -> got dump signal %d (me %d, from %d)\n", SIGPIPE, direct_getpid(), info.si_pid ); direct_trace_print_stacks(); direct_print_interface_leaks(); direct_print_memleaks(); call_handlers( info.si_signo, NULL ); } else { signal_handler( info.si_signo, &info, NULL ); } } } D_DEBUG_AT( Direct_Signals, "Returning from signal handler thread\n" ); return NULL; } static void install_handlers() { int i; D_DEBUG_AT( Direct_Signals, "%s()\n", __FUNCTION__ ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) { sigs_handled[i].signum = -1; if (direct_config->sighandler && !sigismember( &direct_config->dont_catch, sigs_to_handle[i] )) { struct sigaction action; int signum = sigs_to_handle[i]; action.sa_sigaction = signal_handler; action.sa_flags = SA_SIGINFO; if (signum != SIGSEGV) action.sa_flags |= SA_NODEFER; sigemptyset( &action.sa_mask ); if (sigaction( signum, &action, &sigs_handled[i].old_action )) { D_PERROR( "Direct/Signals: Unable to install signal handler for signal %d!\n", signum ); continue; } sigs_handled[i].signum = signum; } } } static void remove_handlers() { int i; D_DEBUG_AT( Direct_Signals, "%s()\n", __FUNCTION__ ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) { if (sigs_handled[i].signum != -1) { int signum = sigs_handled[i].signum; if (sigaction( signum, &sigs_handled[i].old_action, NULL )) { D_PERROR( "Direct/Signals: Unable to restore previous handler for signal %d!\n", signum ); } sigs_handled[i].signum = -1; } } } ================================================ FILE: lib/direct/os/linux/system.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #if D_DEBUG_ENABLED #include #endif #include #include #include #if !defined(__NR_futex) && defined(__NR_futex_time64) #define __NR_futex __NR_futex_time64 #endif D_DEBUG_DOMAIN( Direct_Futex, "Direct/Futex", "Direct Futex" ); D_DEBUG_DOMAIN( Direct_Trap, "Direct/Trap", "Direct Trap" ); /**********************************************************************************************************************/ __attribute__((no_instrument_function)) void direct_sched_yield() { sched_yield(); } long direct_pagesize() { return sysconf( _SC_PAGESIZE ); } unsigned long direct_page_align( unsigned long value ) { unsigned long mask = sysconf( _SC_PAGESIZE ) - 1; return (value + mask) & ~mask; } __attribute__((no_instrument_function)) pid_t direct_getpid() { return getpid(); } __attribute__((no_instrument_function)) pid_t direct_gettid() { return syscall( __NR_gettid ); } void direct_trap( const char *domain, int sig ) { union sigval val; if (direct_config->delay_trap_ms) { D_DEBUG_AT( Direct_Trap, "Not raising signal %d from %s, waiting for %dms... attach gdb --pid=%d\n", sig, domain, direct_config->delay_trap_ms, getpid() ); direct_thread_sleep( direct_config->delay_trap_ms * 1000LL ); return; } D_DEBUG_AT( Direct_Trap, "Raising signal %d from %s...\n", sig, domain ); val.sival_int = direct_gettid(); sigqueue( direct_gettid(), sig, val ); abort(); D_DEBUG_AT( Direct_Trap, "...abort() returned as well, calling exit_group()\n" ); syscall( __NR_exit_group, DR_BUG ); } DirectResult direct_kill( pid_t pid, int sig ) { if (kill( pid, sig ) < 0) { if (errno == ESRCH) return DR_NOSUCHINSTANCE; else return errno2result( errno ); } return DR_OK; } void direct_sync() { sync(); } uid_t direct_geteuid() { return geteuid(); } char * direct_getenv( const char *name ) { return getenv( name ); } DirectResult direct_futex( int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3 ) { #if D_DEBUG_ENABLED unsigned int count; switch (op) { case FUTEX_WAIT: count = D_SYNC_ADD_AND_FETCH( &__Direct_Futex_Wait_Count, 1 ); D_DEBUG_AT( Direct_Futex, "## ## WAIT FOR --> %p <-- %d (<-%d) ## ## ## ## * %u\n", uaddr, *uaddr, val, count ); break; case FUTEX_WAKE: count = D_SYNC_ADD_AND_FETCH( &__Direct_Futex_Wake_Count, 1 ); D_DEBUG_AT( Direct_Futex, "### WAKE UP =--> %p <--= %d (->%d) ### ### ### * %u\n", uaddr, *uaddr, val, count ); break; default: D_DEBUG_AT( Direct_Futex, "# # UNKNOWN FUTEX OP # #\n" ); } #endif if (syscall( __NR_futex, uaddr, op, val, timeout, uaddr2, val3 ) < 0) return errno2result( errno ); return DR_OK; } bool direct_madvise() { struct utsname uts; int i, j, k, l; if (uname( &uts ) < 0) { D_PERROR( "Direct/System: uname() failed!\n" ); return false; } switch (sscanf( uts.release, "%d.%d.%d.%d", &i, &j, &k, &l )) { case 3: l = 0; case 4: if (((i << 24) | (j << 16) | (k << 8) | l) >= 0x02061302) return true; break; default: D_WARN( "could not parse kernel version '%s'", uts.release ); } return false; } ================================================ FILE: lib/direct/os/linux/thread.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define _GNU_SOURCE /* To get pthread_getattr_np() declaration. */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Thread, "Direct/Thread", "Direct Thread Management" ); D_DEBUG_DOMAIN( Direct_ThreadInit, "Direct/Thread/Init", "Direct Thread Init" ); /**********************************************************************************************************************/ static pthread_key_t thread_key; static DirectOnce thread_init_once = DIRECT_ONCE_INIT(); /* * Wrapper around pthread's main routine to pass additional arguments * and setup things like signal masks and scheduling priorities. */ __attribute__((no_instrument_function)) static void *direct_thread_main( void *arg ); /**********************************************************************************************************************/ __attribute__((no_instrument_function)) DirectResult direct_once( DirectOnce *once, DirectOnceInitHandler handler ) { int erno = pthread_once( &once->once, handler ); return errno2result( erno ); } __attribute__((no_instrument_function)) static void init_once( void ) { /* Create the key for the TSD (thread specific data). */ pthread_key_create( &thread_key, NULL ); } DirectResult direct_thread_init( DirectThread *thread ) { int erno; pthread_attr_t attr; struct sched_param param; int policy; int priority; D_DEBUG_AT( Direct_ThreadInit, "%s( %p, '%s' )\n", __FUNCTION__, thread->main, thread->name ); direct_once( &thread_init_once, init_once ); /* Initialize scheduling and other parameters. */ pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); /* Select scheduler. */ switch (direct_config->thread_scheduler) { case DCTS_FIFO: policy = SCHED_FIFO; break; case DCTS_RR: policy = SCHED_RR; break; default: policy = SCHED_OTHER; break; } if (pthread_attr_setschedpolicy( &attr, policy )) D_PERROR( "Direct/Thread/Init: Could not set scheduling policy to %s!\n", direct_thread_policy_name( policy ) ); /* Read (back) value. */ pthread_attr_getschedpolicy( &attr, &policy ); thread->policy = policy; /* Select priority. */ switch (thread->type) { case DTT_CLEANUP: case DTT_INPUT: case DTT_OUTPUT: case DTT_MESSAGING: case DTT_CRITICAL: priority = thread->type * direct_config->thread_priority_scale / 100; break; default: priority = direct_config->thread_priority; break; } D_DEBUG_AT( Direct_ThreadInit, " -> priority %d [%d;%d]\n", priority, sched_get_priority_min( policy ), sched_get_priority_max( policy ) ); if (priority < sched_get_priority_min( policy )) priority = sched_get_priority_min( policy ); if (priority > sched_get_priority_max( policy )) priority = sched_get_priority_max( policy ); D_DEBUG_AT( Direct_ThreadInit, " -> policy %s with priority set to %d\n", direct_thread_policy_name( policy ), priority ); param.sched_priority = priority; if (pthread_attr_setschedparam( &attr, ¶m )) D_PERROR( "Direct/Thread/Init: Could not set scheduling priority to %d!\n", priority ); /* Select stack size. */ if (direct_config->thread_stack_size > 0) { if (pthread_attr_setstacksize( &attr, direct_config->thread_stack_size )) D_PERROR( "Direct/Thread/Init: Could not set stack size to %d!\n", direct_config->thread_stack_size ); } erno = pthread_create( &thread->handle, &attr, direct_thread_main, thread ); if (erno) return errno2result( erno ); pthread_attr_destroy( &attr ); /* Read (back) value. */ pthread_getattr_np( thread->handle, &attr ); pthread_attr_getstacksize( &attr, &thread->stack_size ); pthread_attr_getschedparam( &attr, ¶m ); thread->priority = param.sched_priority; pthread_attr_destroy( &attr ); return DR_OK; } void direct_thread_deinit( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSUME( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->detached ); D_DEBUG_AT( Direct_ThreadInit, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (!thread->joined && !pthread_equal( thread->handle, pthread_self() )) { if (thread->canceled) D_DEBUG_AT( Direct_ThreadInit, " -> canceled but not joined!\n" ); else { D_DEBUG_AT( Direct_ThreadInit, " -> still running!\n" ); if (thread->name) D_ERROR( "Direct/Thread/Init: Canceling '%s' (%d)!\n", thread->name, thread->tid ); else D_ERROR( "Direct/Thread/Init: Canceling %d!\n", thread->tid ); pthread_cancel( thread->handle ); } pthread_join( thread->handle, NULL ); } } __attribute__((no_instrument_function)) void direct_thread_setcancelstate( DirectThreadCancelState state ) { switch (state) { case DIRECT_THREAD_CANCEL_ENABLE: pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); case DIRECT_THREAD_CANCEL_DISABLE: pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); } } __attribute__((no_instrument_function)) DirectThread * direct_thread_self() { DirectThread *thread; direct_once( &thread_init_once, init_once ); thread = pthread_getspecific( thread_key ); /* Support this function for non-direct threads. */ if (!thread) { thread = calloc( 1, sizeof(DirectThread) ); if (!thread) { D_OOM(); return NULL; } thread->handle = pthread_self(); thread->tid = direct_gettid(); D_MAGIC_SET( thread, DirectThread ); pthread_setspecific( thread_key, thread ); } return thread; } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" #endif __attribute__((no_instrument_function)) const char * direct_thread_self_name() { DirectThread *thread = direct_thread_self(); char name[16]; /* This function is called by debugging functions, e.g. debug messages, assertions etc. Therefore no assertions are made here, because they would loop forever if they fail. */ if (!thread) return NULL; if (!thread->name) { prctl( PR_GET_NAME, name, 0, 0, 0 ); thread->name = strdup( name ); } return thread->name; } void direct_thread_set_name( const char *name ) { char *copy; DirectThread *thread; D_DEBUG_AT( Direct_Thread, "%s( '%s' )\n", __FUNCTION__, name ); thread = direct_thread_self(); if (!thread) return; /* Duplicate string. */ copy = strdup( name ); if (!copy) { D_OOM(); return; } /* Free old string. */ if (thread->name) free( thread->name ); /* Keep the copy. */ thread->name = copy; } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic pop #endif void direct_thread_cancel( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); thread->canceled = true; pthread_cancel( thread->handle ); } void direct_thread_detach( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); thread->detached = true; pthread_detach( thread->handle ); } void direct_thread_testcancel( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( pthread_equal( thread->handle, pthread_self() ) ); /* Quick check before calling the pthread function. */ if (thread->canceled) pthread_testcancel(); } void direct_thread_join( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSUME( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->joining ); D_ASSUME( !thread->joined ); D_ASSUME( !thread->detached ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (thread->detached) { D_DEBUG_AT( Direct_Thread, " -> detached\n" ); return; } if (!thread->joining && !pthread_equal( thread->handle, pthread_self() )) { thread->joining = true; D_DEBUG_AT( Direct_Thread, " -> joining...\n" ); pthread_join( thread->handle, NULL ); thread->joined = true; D_DEBUG_AT( Direct_Thread, " -> joined\n" ); } } void direct_thread_kill( DirectThread *thread, int signal ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d, signal %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid, signal ); pthread_kill( thread->handle, signal ); } void direct_thread_sleep( long long micros ) { usleep( micros ); } void direct_thread_atfork( DirectThreadPrepareHandler prepare, DirectThreadParentHandler parent, DirectThreadChildHandler child ) { pthread_atfork( prepare, parent, child ); } /**********************************************************************************************************************/ const char * direct_thread_type_name( DirectThreadType type ) { switch (type) { case DTT_DEFAULT: return "DEFAULT"; case DTT_CLEANUP: return "CLEANUP"; case DTT_INPUT: return "INPUT"; case DTT_OUTPUT: return "OUTPUT"; case DTT_MESSAGING: return "MESSAGING"; case DTT_CRITICAL: return "CRITICAL"; } return ""; } const char * direct_thread_policy_name( int policy ) { switch (policy) { case SCHED_OTHER: return "OTHER"; case SCHED_FIFO: return "FIFO"; case SCHED_RR: return "RR"; } return ""; } /**********************************************************************************************************************/ __attribute__((no_instrument_function)) DirectResult direct_tls_register( DirectTLS *tls, DirectTLSDestructor destructor ) { int erno = pthread_key_create( &tls->key, destructor ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_tls_unregister( DirectTLS *tls ) { int erno; erno = pthread_key_delete( tls->key ); if (erno) return errno2result( erno ); tls->key = (pthread_key_t) -1; return DR_OK; } __attribute__((no_instrument_function)) void * direct_tls_get( DirectTLS *tls ) { void *value; value = pthread_getspecific( tls->key ); return value; } __attribute__((no_instrument_function)) DirectResult direct_tls_set( DirectTLS *tls, void *value ) { int erno = pthread_setspecific( tls->key, value ); return errno2result( erno ); } /**********************************************************************************************************************/ static void direct_thread_cleanup( void *arg ) { DirectThread *thread = arg; D_MAGIC_ASSERT( thread, DirectThread ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (thread->trace_buffer) direct_trace_free_buffer( thread->trace_buffer ); if (thread->detached) { D_MAGIC_CLEAR( thread ); if (thread->name) free( thread->name ); free( thread ); } } __attribute__((no_instrument_function)) static void * direct_thread_main( void *arg ) { void *res; DirectThread *thread = arg; prctl( PR_SET_NAME, thread->name, 0, 0, 0 ); pthread_setspecific( thread_key, thread ); D_DEBUG_AT( Direct_ThreadInit, "%s( %p )\n", __FUNCTION__, arg ); D_DEBUG_AT( Direct_ThreadInit, " -> starting...\n" ); D_MAGIC_ASSERT( thread, DirectThread ); pthread_cleanup_push( direct_thread_cleanup, thread ); thread->tid = direct_gettid(); D_DEBUG_AT( Direct_ThreadInit, " -> tid %d\n", thread->tid ); _direct_thread_call_init_handlers( thread ); /* Have all signals handled by the main thread. */ if (direct_config->thread_block_signals) { sigset_t signals; sigfillset( &signals ); sigprocmask( SIG_BLOCK, &signals, NULL ); } /* Lock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> locking...\n" ); direct_mutex_lock( &thread->lock ); /* Indicate that our initialization has completed. */ thread->init = true; D_DEBUG_AT( Direct_ThreadInit, " -> signalling...\n" ); direct_waitqueue_signal( &thread->cond ); /* Unlock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> unlocking...\n" ); direct_mutex_unlock( &thread->lock ); if (thread->joining) { D_DEBUG_AT( Direct_ThreadInit, " -> being joined before entering main routine!\n" ); return NULL; } /* Call main routine. */ D_DEBUG_AT( Direct_ThreadInit, " -> running...\n" ); res = thread->main( thread, thread->arg ); D_DEBUG_AT( Direct_Thread, " -> returning %p from '%s' (%s, %d)...\n", res, thread->name, direct_thread_type_name( thread->type ), thread->tid ); pthread_cleanup_pop( 1 ); return res; } ================================================ FILE: lib/direct/os/linux/thread.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LINUX__THREAD_H__ #define __DIRECT__OS__LINUX__THREAD_H__ #include /**********************************************************************************************************************/ typedef pthread_t DirectThreadHandle; typedef struct { pthread_once_t once; } DirectOnce; #define DIRECT_ONCE_INIT() { PTHREAD_ONCE_INIT } typedef struct { pthread_key_t key; } DirectTLS; #endif ================================================ FILE: lib/direct/os/linux/types.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LINUX__TYPES_H__ #define __DIRECT__OS__LINUX__TYPES_H__ #include #if DIRECT_BUILD_DYNLOAD #include #endif #include #include #include #include #include #if DIRECT_BUILD_NETWORK #include #endif #include #include #include #include #include #include #include #include #if defined(__i386__) || defined(__x86_64__) #include #endif #include #include #include #include #include #include #include #include #include typedef unsigned int unichar; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; #define _ZD "%zd" #define _ZU "%zu" #define _ZUn(x) "%" #x "zu" #endif ================================================ FILE: lib/direct/os/linux/waitqueue.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LINUX__WAITQUEUE_H__ #define __DIRECT__OS__LINUX__WAITQUEUE_H__ #include #include /**********************************************************************************************************************/ typedef struct { pthread_cond_t cond; } DirectWaitQueue; static inline DirectResult direct_waitqueue_init( DirectWaitQueue *queue ) { int erno = pthread_cond_init( &queue->cond, NULL ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_wait( DirectWaitQueue *queue, DirectMutex *mutex ) { int erno = pthread_cond_wait( &queue->cond, &mutex->lock ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_wait_timeout( DirectWaitQueue *queue, DirectMutex *mutex, unsigned long micros ) { struct timeval now; struct timespec timeout; long seconds = micros / 1000000; long nano_seconds = (micros % 1000000) * 1000; gettimeofday( &now, NULL ); timeout.tv_sec = now.tv_sec + seconds; timeout.tv_nsec = (now.tv_usec * 1000) + nano_seconds; timeout.tv_sec += timeout.tv_nsec / 1000000000; timeout.tv_nsec %= 1000000000; if (pthread_cond_timedwait( &queue->cond, &mutex->lock, &timeout ) == ETIMEDOUT) return DR_TIMEOUT; return DR_OK; } static inline DirectResult direct_waitqueue_signal( DirectWaitQueue *queue ) { int erno = pthread_cond_signal( &queue->cond ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_broadcast( DirectWaitQueue *queue ) { int erno = pthread_cond_broadcast( &queue->cond ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_deinit( DirectWaitQueue *queue ) { int erno = pthread_cond_destroy( &queue->cond ); return errno2result( erno ); } #endif ================================================ FILE: lib/direct/os/log.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__LOG_H__ #define __DIRECT__OS__LOG_H__ #include /**********************************************************************************************************************/ typedef enum { DLT_STDERR = 0x00000000, /* Simply print out log on stderr. */ DLT_FILE = 0x00000001, /* Write log into a file. */ DLT_UDP = 0x00000002 /* Send out log via UDP. */ } DirectLogType; typedef DirectResult (*DirectLogWriteFunc)( DirectLog *log, const char *buffer, size_t bytes ); typedef DirectResult (*DirectLogFlushFunc)( DirectLog *log ); struct __D_DirectLog { int magic; DirectLogType type; DirectMutex lock; void *data; DirectLogWriteFunc write; DirectLogFlushFunc flush; }; /**********************************************************************************************************************/ /* * Initializes a logging facility. * * For each 'log->type' the 'param' has a different meaning: * DLT_STDERR ignored (leave NULL) * DLT_FILE file name * DLT_UDP : */ DirectResult DIRECT_API direct_log_init ( DirectLog *log, const char *param ); /* * Destroys a logging facility. */ DirectResult DIRECT_API direct_log_deinit( DirectLog *log ); #endif ================================================ FILE: lib/direct/os/mem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__MEM_H__ #define __DIRECT__OS__MEM_H__ #include /**********************************************************************************************************************/ void DIRECT_API *direct_malloc ( size_t bytes ); void DIRECT_API *direct_calloc ( size_t count, size_t bytes ); void DIRECT_API *direct_realloc( void *mem, size_t bytes ); char DIRECT_API *direct_strdup ( const char *string ); void DIRECT_API direct_free ( void *mem ); #endif ================================================ FILE: lib/direct/os/mutex.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__MUTEX_H__ #define __DIRECT__OS__MUTEX_H__ #include /**********************************************************************************************************************/ DirectResult DIRECT_API direct_mutex_init ( DirectMutex *mutex ); DirectResult DIRECT_API direct_recursive_mutex_init( DirectMutex *mutex ); DirectResult DIRECT_API direct_mutex_lock ( DirectMutex *mutex ); DirectResult DIRECT_API direct_mutex_unlock ( DirectMutex *mutex ); DirectResult DIRECT_API direct_mutex_trylock ( DirectMutex *mutex ); DirectResult DIRECT_API direct_mutex_deinit ( DirectMutex *mutex ); DirectResult DIRECT_API direct_rwlock_init ( DirectRWLock *rwlock ); DirectResult DIRECT_API direct_rwlock_rdlock ( DirectRWLock *rwlock ); DirectResult DIRECT_API direct_rwlock_wrlock ( DirectRWLock *rwlock ); DirectResult DIRECT_API direct_rwlock_unlock ( DirectRWLock *rwlock ); DirectResult DIRECT_API direct_rwlock_trywrlock ( DirectRWLock *rwlock ); DirectResult DIRECT_API direct_rwlock_deinit ( DirectRWLock *rwlock ); #endif ================================================ FILE: lib/direct/os/nuttx/clock.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static long long session_clock_offset; /**********************************************************************************************************************/ __attribute__((no_instrument_function)) long long direct_clock_get_time( DirectClockType type ) { long long micros; struct timespec spec; clockid_t clock_id; switch (type) { case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_SESSION: case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } if (clock_gettime( clock_id, &spec ) < 0) { if (clock_id != CLOCK_REALTIME) { D_WARN( "clock with id %d not supported by system", clock_id ); return direct_clock_get_time( DIRECT_CLOCK_REALTIME ); } D_PERROR( "Direct/Clock: Could not get real time clock!\n" ); return 0; } micros = spec.tv_sec * 1000000LL + spec.tv_nsec / 1000LL; if (type == DIRECT_CLOCK_SESSION) micros -= session_clock_offset; usleep( 1 ); return micros; } __attribute__((no_instrument_function)) DirectResult direct_clock_set_time( DirectClockType type, long long micros ) { DirectResult ret; clockid_t clock_id; struct timespec spec; switch (type) { case DIRECT_CLOCK_SESSION: session_clock_offset = micros; return DR_OK; case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } spec.tv_sec = micros / 1000000LL; spec.tv_nsec = micros % 1000000LL * 1000LL; if (clock_settime( clock_id, &spec ) < 0) { ret = errno2result( errno ); D_PERROR( "Direct/Clock: Could not set clock with id %d!\n", clock_id ); return ret; } return DR_OK; } __attribute__((no_instrument_function)) long long direct_clock_resolution( DirectClockType type ) { struct timespec spec; clockid_t clock_id; switch (type) { case DIRECT_CLOCK_SESSION: case DIRECT_CLOCK_REALTIME: clock_id = CLOCK_REALTIME; break; case DIRECT_CLOCK_MONOTONIC: clock_id = CLOCK_MONOTONIC; break; case DIRECT_CLOCK_PROCESS_CPUTIME_ID: clock_id = CLOCK_PROCESS_CPUTIME_ID; break; case DIRECT_CLOCK_THREAD_CPUTIME_ID: clock_id = CLOCK_THREAD_CPUTIME_ID; break; default: D_BUG( "invalid clock type %u", type ); return DR_INVARG; } if (clock_getres( clock_id, &spec ) < 0) { if (clock_id != CLOCK_REALTIME) { D_WARN( "clock with id %d not supported by system", clock_id ); return direct_clock_resolution( DIRECT_CLOCK_REALTIME ); } D_PERROR( "Direct/Clock: Could not get real time clock resolution!\n" ); return 0; } return spec.tv_sec * 1000000LL + spec.tv_nsec / 1000LL; } ================================================ FILE: lib/direct/os/nuttx/configs/sim/defconfig ================================================ CONFIG_ARCH="sim" CONFIG_ARCH_BOARD="sim" CONFIG_ARCH_BOARD_SIM=y CONFIG_ARCH_CHIP="sim" CONFIG_ARCH_SIM=y CONFIG_BOARD_LATE_INITIALIZE=y CONFIG_DRIVERS_VIDEO=y CONFIG_EXAMPLES_DIRECTFB=y CONFIG_GRAPHICS_DIRECTFB2=y CONFIG_INIT_ENTRYPOINT="directfb_main" CONFIG_INPUT=y CONFIG_PIPES=y CONFIG_PTHREAD_CLEANUP_STACKSIZE=1 CONFIG_PTHREAD_MUTEX_TYPES=y CONFIG_SIM_FBHEIGHT=480 CONFIG_SIM_FBWIDTH=640 CONFIG_SIM_KEYBOARD=y CONFIG_SIM_TOUCHSCREEN=y CONFIG_SIM_X11FB=y CONFIG_VIDEO_FB=y ================================================ FILE: lib/direct/os/nuttx/configs/stm32f429i-disco/defconfig ================================================ # CONFIG_STM32_FB_CMAP is not set CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="stm32f429i-disco" CONFIG_ARCH_BOARD_STM32F429I_DISCO=y CONFIG_ARCH_BUTTONS=y CONFIG_ARCH_CHIP="stm32" CONFIG_ARCH_CHIP_STM32F429Z=y CONFIG_ARCH_IRQBUTTONS=y CONFIG_BUILTIN=y CONFIG_DRIVERS_VIDEO=y CONFIG_EXAMPLES_DIRECTFB=y CONFIG_EXAMPLES_DIRECTFB_FONT_EXTENSION="ttf" CONFIG_EXAMPLES_DIRECTFB_FONT_PROVIDER="STB" CONFIG_EXAMPLES_DIRECTFB_IMAGE_EXTENSION="png" CONFIG_EXAMPLES_DIRECTFB_IMAGE_PROVIDER="STB" CONFIG_EXAMPLES_DIRECTFB_VIDEO_EXTENSION="mpg" CONFIG_EXAMPLES_DIRECTFB_VIDEO_PROVIDER="PLM" CONFIG_GRAPHICS_DIRECTFB2=y CONFIG_GRAPHICS_DIRECTFB2_MEDIA_PL_MPEG=y CONFIG_GRAPHICS_DIRECTFB2_MEDIA_STB=y CONFIG_HEAP2_BASE=0xD0000000 CONFIG_HEAP2_SIZE=7774208 CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INPUT=y CONFIG_INPUT_BUTTONS=y CONFIG_INPUT_BUTTONS_LOWER=y CONFIG_INPUT_STMPE811=y CONFIG_MM_REGIONS=2 CONFIG_NSH_ARCHINIT=y CONFIG_NSH_BUILTIN_APPS=y CONFIG_PIPES=y CONFIG_PTHREAD_CLEANUP_STACKSIZE=1 CONFIG_PTHREAD_MUTEX_TYPES=y CONFIG_RAW_BINARY=y CONFIG_SCHED_HPWORK=y CONFIG_STM32F429I_DISCO_ILI9341=y CONFIG_STM32_CCMEXCLUDE=y CONFIG_STM32_EXTERNAL_RAM=y CONFIG_STM32_FMC=y CONFIG_STM32_I2C3=y CONFIG_STM32_LTDC=y CONFIG_STM32_LTDC_FB_BASE=0xD076A000 CONFIG_STM32_LTDC_FB_SIZE=307200 CONFIG_STM32_USART1=y CONFIG_STMPE811_ACTIVELOW=y CONFIG_STMPE811_EDGE=y CONFIG_STMPE811_OFFSETX=300 CONFIG_STMPE811_OFFSETY=242 CONFIG_STMPE811_THRESHX=15 CONFIG_STMPE811_THRESHY=11 CONFIG_STMPE811_SWAPXY=y CONFIG_SYSTEM_NSH=y CONFIG_USART1_SERIAL_CONSOLE=y CONFIG_VIDEO_FB=y ================================================ FILE: lib/direct/os/nuttx/filesystem.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ DirectResult direct_dir_get_current( char *buf, size_t length ) { D_ASSERT( buf != NULL ); if (!getcwd( buf, length )) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_change( const char *name ) { D_ASSERT( name != NULL ); if (chdir( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_create( const char *name, mode_t mode ) { D_ASSERT( name != NULL ); if (mkdir( name, mode ) < 0) { if (errno == EEXIST) return DR_BUSY; else return errno2result( errno ); } return DR_OK; } DirectResult direct_dir_open( DirectDir *dir, const char *name ) { D_ASSERT( dir != NULL ); D_ASSERT( name != NULL ); dir->dir = opendir( name ); if (!dir->dir) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_read( DirectDir *dir, DirectEntry *entry ) { struct dirent *ent; D_ASSERT( dir != NULL ); D_ASSERT( entry != NULL ); ent = readdir( dir->dir ); if (!ent) return errno ? errno2result( errno ) : DR_ITEMNOTFOUND; else strcpy( entry->name, ent->d_name ); return DR_OK; } DirectResult direct_dir_rewind( DirectDir *dir ) { D_ASSERT( dir != NULL ); rewinddir( dir->dir ); return DR_OK; } DirectResult direct_dir_close( DirectDir *dir ) { int err; D_ASSERT( dir != NULL ); err = closedir( dir->dir ); dir->dir = NULL; if (err < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_dir_remove( const char *name ) { D_ASSERT( name != NULL ); if (rmdir( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_open( DirectFile *file, const char *name, int flags, mode_t mode ) { D_ASSERT( file != NULL ); D_ASSERT( name != NULL ); file->file = NULL; file->fd = open( name, flags, mode ); if (file->fd < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_read( DirectFile *file, void *buffer, size_t bytes, size_t *ret_bytes ) { ssize_t num; D_ASSERT( file != NULL ); D_ASSERT( buffer != NULL ); num = read( file->fd, buffer, bytes ); if (num < 0) return errno2result( errno ); if (ret_bytes) *ret_bytes = num; return DR_OK; } DirectResult direct_file_write( DirectFile *file, const void *buffer, size_t bytes, size_t *ret_bytes ) { ssize_t num; D_ASSERT( file != NULL ); D_ASSERT( buffer != NULL ); num = write( file->fd, buffer, bytes ); if (num < 0) return errno2result( errno ); if (ret_bytes) *ret_bytes = num; return DR_OK; } DirectResult direct_file_seek( DirectFile *file, off_t offset ) { D_ASSERT( file != NULL ); if (lseek( file->fd, offset, SEEK_CUR ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_seek_to( DirectFile *file, off_t offset ) { D_ASSERT( file != NULL ); if (lseek( file->fd, offset, SEEK_SET ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_close( DirectFile *file ) { int err; D_ASSERT( file != NULL ); if (file->file) { err = fclose( file->file ); file->file = NULL; } else err = close( file->fd ); file->fd = -1; if (err < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_map( DirectFile *file, void *addr, size_t offset, size_t bytes, DirectFilePermission perms, void **ret_addr ) { void *map; int prot = 0; int flags = MAP_SHARED; D_ASSERT( file != NULL ); D_ASSERT( ret_addr != NULL ); if (perms & DFP_READ) prot |= PROT_READ; if (perms & DFP_WRITE) prot |= PROT_WRITE; if (addr) flags |= MAP_FIXED; map = mmap( addr, bytes, prot, flags, file->fd, offset ); if (map == MAP_FAILED) return errno2result( errno ); *ret_addr = map; return DR_OK; } DirectResult direct_file_unmap( void *addr, size_t bytes ) { if (munmap( addr, bytes ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_get_info( DirectFile *file, DirectFileInfo *ret_info ) { struct stat st; D_ASSERT( file != NULL ); D_ASSERT( ret_info != NULL ); if (fstat( file->fd, &st ) < 0) return errno2result( errno ); ret_info->flags = DFIF_SIZE; ret_info->size = st.st_size; return DR_OK; } DirectResult direct_file_chmod( DirectFile *file, mode_t mode ) { D_ASSERT( file != NULL ); if (fchmod( file->fd, mode ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_chown( DirectFile *file, uid_t owner, gid_t group ) { D_ASSERT( file != NULL ); if (fchown( file->fd, owner, group ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_truncate( DirectFile *file, off_t length ) { D_ASSERT( file != NULL ); if (ftruncate( file->fd, length ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_file_get_string( DirectFile *file, char *buf, size_t length ) { D_ASSERT( file != NULL ); D_ASSERT( buf != NULL ); if (!file->file) { file->file = fdopen( file->fd, "r" ); if (!file->file) return errno2result( errno ); } if (!fgets( buf, length, file->file )) { if (feof( file->file )) return DR_EOF; return DR_FAILURE; } return DR_OK; } DirectResult direct_popen( DirectFile *file, const char *name, int flags ) { D_ASSERT( file != NULL ); D_ASSERT( name != NULL ); file->file = popen( name, (flags & O_WRONLY) ? "w" : (flags & O_RDWR) ? "rw" : "r" ); if (!file->file) return errno2result( errno ); file->fd = fileno( file->file ); return DR_OK; } DirectResult direct_pclose( DirectFile *file ) { D_ASSERT( file != NULL ); D_ASSERT( file->file != NULL ); if (pclose( file->file ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_access( const char *name, int flags ) { D_ASSERT( name != NULL ); if (access( name, flags ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_chmod( const char *name, mode_t mode ) { D_ASSERT( name != NULL ); if (chmod( name, mode ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_chown( const char *name, uid_t owner, gid_t group ) { D_ASSERT( name != NULL ); if (chown( name, owner, group ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_readlink( const char *name, char *buf, size_t length, ssize_t *ret_length ) { ssize_t len; D_ASSERT( name != NULL ); len = readlink( name, buf, length ); if (len < 0) return errno2result( errno ); if (ret_length) *ret_length = len; return DR_OK; } DirectResult direct_unlink( const char *name ) { D_ASSERT( name != NULL ); if (unlink( name ) < 0) return errno2result( errno ); return DR_OK; } DirectResult direct_filesystem_size( const char *name, size_t *size ) { struct statfs stat; D_ASSERT( name != NULL ); if (statfs( name, &stat ) < 0) return errno2result( errno ); *size = stat.f_blocks * stat.f_bsize; return DR_OK; } ================================================ FILE: lib/direct/os/nuttx/filesystem.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__NUTTX__FILESYSTEM_H__ #define __DIRECT__OS__NUTTX__FILESYSTEM_H__ #include /**********************************************************************************************************************/ typedef struct { DIR *dir; } DirectDir; typedef struct { int fd; FILE *file; } DirectFile; #endif ================================================ FILE: lib/direct/os/nuttx/log.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static DirectResult init_stderr( DirectLog *log ); static DirectResult init_file ( DirectLog *log, const char *filename ); /**********************************************************************************************************************/ DirectResult direct_log_init( DirectLog *log, const char *param ) { switch (log->type) { case DLT_STDERR: return init_stderr( log ); case DLT_FILE: return init_file( log, param ); case DLT_UDP: default: break; } return DR_UNSUPPORTED; } DirectResult direct_log_deinit( DirectLog *log ) { close( (long) log->data ); return DR_OK; } /**********************************************************************************************************************/ __attribute__((no_instrument_function)) static DirectResult common_log_write( DirectLog *log, const char *buffer, size_t bytes ) { ssize_t sz; sz = write( (long) log->data, buffer, bytes ); if (sz < 0) D_PERROR( "Direct/Log: Could not write to log!\n" ); return DR_OK; } __attribute__((no_instrument_function)) static DirectResult common_log_flush( DirectLog *log ) { if (log->type == DLT_STDERR && fflush( stderr )) return errno2result( errno ); return DR_OK; } __attribute__((no_instrument_function)) static DirectResult stderr_log_write( DirectLog *log, const char *buffer, size_t bytes ) { fwrite( buffer, bytes, 1, stderr ); return DR_OK; } static DirectResult init_stderr( DirectLog *log ) { log->data = (void*)(long) dup( fileno( stderr ) ); log->write = stderr_log_write; log->flush = common_log_flush; return DR_OK; } static DirectResult init_file( DirectLog *log, const char *filename ) { DirectResult ret; int fd; fd = open( filename, O_WRONLY | O_CREAT | O_APPEND, 0664 ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "Direct/Log: Could not open '%s' for writing!\n", filename ); return ret; } log->data = (void*)(long) fd; log->write = common_log_write; log->flush = common_log_flush; return DR_OK; } ================================================ FILE: lib/direct/os/nuttx/mem.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_SENTINELS #include D_DEBUG_DOMAIN( Direct_Sentinels, "Direct/Sentinels", "Direct Sentinels" ); #endif /* DIRECT_BUILD_SENTINELS */ /**********************************************************************************************************************/ #if DIRECT_BUILD_SENTINELS #define PREFIX_SENTINEL 8 #define SUFFIX_SENTINEL 8 #define TOTAL_SENTINEL ((PREFIX_SENTINEL) + (SUFFIX_SENTINEL)) __attribute__((no_instrument_function)) static inline void install_sentinels( void *p, size_t size ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + size; D_DEBUG_AT( Direct_Sentinels, "%s( %p, "_ZU" )\n", __FUNCTION__, p, size ); *ps = size; for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) prefix[i] = i; for (i = 0; i < SUFFIX_SENTINEL; i++) suffix[i] = i; } __attribute__((no_instrument_function)) static inline void remove_sentinels( void *p ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + *ps; D_DEBUG_AT( Direct_Sentinels, "%s( %p )\n", __FUNCTION__, p ); for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) prefix[i] = 0; for (i = 0; i < SUFFIX_SENTINEL; i++) suffix[i] = 0; } __attribute__((no_instrument_function)) static inline void check_sentinels( void *p ) { size_t i; size_t *ps = p; u8 *prefix = p; u8 *suffix = p + PREFIX_SENTINEL + *ps; for (i = sizeof(size_t); i < PREFIX_SENTINEL; i++) { if (prefix[i] != i) D_DEBUG_AT( Direct_Sentinels, "Sentinel error at prefix["_ZU"] (%u) of "_ZU" bytes allocation!\n", i, prefix[i], *ps ); } for (i = 0; i < SUFFIX_SENTINEL; i++) { if (suffix[i] != i) D_DEBUG_AT( Direct_Sentinels, "Sentinel error at suffix["_ZU"] (%u) of "_ZU" bytes allocation!\n", i, suffix[i], *ps ); } } __attribute__((no_instrument_function)) void * direct_malloc( size_t bytes ) { void *p = bytes ? malloc( bytes + TOTAL_SENTINEL ) : NULL; if (!p) return NULL; install_sentinels( p, bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void * direct_calloc( size_t count, size_t bytes) { void *p = (count && bytes) ? calloc( 1, count * bytes + TOTAL_SENTINEL ) : NULL; if (!p) return NULL; install_sentinels( p, count * bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void * direct_realloc( void *mem, size_t bytes ) { void *p = mem ? mem - PREFIX_SENTINEL : NULL; if (!mem) return direct_malloc( bytes ); check_sentinels( p ); if (!bytes) { direct_free( mem ); return NULL; } p = realloc( p, bytes + TOTAL_SENTINEL ); if (!p) return NULL; install_sentinels( p, bytes ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) char * direct_strdup( const char *str ) { int n = strlen( str ); void *p = malloc( n+1 + TOTAL_SENTINEL ); if (!p) return NULL; memcpy( p + PREFIX_SENTINEL, str, n + 1 ); install_sentinels( p, n + 1 ); return p + PREFIX_SENTINEL; } __attribute__((no_instrument_function)) void direct_free( void *mem ) { void *p = mem ? mem - PREFIX_SENTINEL : NULL; if (p) { check_sentinels( p ); remove_sentinels( p ); free( p ); } } #else /* DIRECT_BUILD_SENTINELS */ __attribute__((no_instrument_function)) void * direct_malloc( size_t bytes ) { return malloc( bytes ); } __attribute__((no_instrument_function)) void * direct_calloc( size_t count, size_t bytes) { return calloc( count, bytes ); } __attribute__((no_instrument_function)) void * direct_realloc( void *mem, size_t bytes ) { return realloc( mem, bytes ); } __attribute__((no_instrument_function)) char * direct_strdup( const char *str ) { return strdup( str ); } __attribute__((no_instrument_function)) void direct_free( void *mem ) { free( mem ); } #endif /* DIRECT_BUILD_SENTINELS */ ================================================ FILE: lib/direct/os/nuttx/mutex.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ DirectResult direct_mutex_init( DirectMutex *mutex ) { int erno = pthread_mutex_init( &mutex->lock, NULL ); return errno2result( erno ); } DirectResult direct_recursive_mutex_init( DirectMutex *mutex ) { DirectResult ret = DR_OK; int erno; pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); erno = pthread_mutex_init( &mutex->lock, &attr ); if (erno) { ret = errno2result( erno ); D_PERROR( "Direct/Mutex: Could not initialize recursive mutex!\n" ); } pthread_mutexattr_destroy( &attr ); return ret; } __attribute__((no_instrument_function)) DirectResult direct_mutex_lock( DirectMutex *mutex ) { int erno = pthread_mutex_lock( &mutex->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_mutex_unlock( DirectMutex *mutex ) { int erno = pthread_mutex_unlock( &mutex->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_mutex_trylock( DirectMutex *mutex ) { int erno = pthread_mutex_trylock( &mutex->lock ); return errno2result( erno ); } DirectResult direct_mutex_deinit( DirectMutex *mutex ) { int erno = pthread_mutex_destroy( &mutex->lock ); return errno2result( erno ); } DirectResult direct_rwlock_init( DirectRWLock *rwlock ) { int erno = pthread_rwlock_init( &rwlock->lock, NULL ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_rdlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_rdlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_wrlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_wrlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_unlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_unlock( &rwlock->lock ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_rwlock_trywrlock( DirectRWLock *rwlock ) { int erno = pthread_rwlock_trywrlock( &rwlock->lock ); return errno2result( erno ); } DirectResult direct_rwlock_deinit( DirectRWLock *rwlock ) { int erno = pthread_rwlock_destroy( &rwlock->lock ); return errno2result( erno ); } ================================================ FILE: lib/direct/os/nuttx/mutex.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__NUTTX__MUTEX_H__ #define __DIRECT__OS__NUTTX__MUTEX_H__ #include /**********************************************************************************************************************/ typedef struct { pthread_mutex_t lock; } DirectMutex; #define DIRECT_MUTEX_INITIALIZER() { PTHREAD_MUTEX_INITIALIZER } typedef struct { pthread_rwlock_t lock; } DirectRWLock; #endif ================================================ FILE: lib/direct/os/nuttx/signals.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Signals, "Direct/Signals", "Direct Signals handling" ); /**********************************************************************************************************************/ struct __D_DirectSignalHandler { DirectLink link; int magic; int num; DirectSignalHandlerFunc func; void *ctx; bool removed; }; /**********************************************************************************************************************/ typedef struct { int signum; struct sigaction old_action; struct sigaction new_action; } SigHandled; static int sigs_to_handle[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, SIGXCPU, SIGXFSZ, SIGSYS }; #define NUM_SIGS_TO_HANDLE (D_ARRAY_SIZE(sigs_to_handle)) static SigHandled sigs_handled[NUM_SIGS_TO_HANDLE]; static DirectLink *handlers = NULL; static DirectMutex handlers_lock; static void install_handlers( void ); static void remove_handlers ( void ); /**********************************************************************************************************************/ DirectResult direct_signals_initialize() { D_DEBUG_AT( Direct_Signals, "%s() initializing...\n", __FUNCTION__ ); direct_recursive_mutex_init( &handlers_lock ); install_handlers(); return DR_OK; } DirectResult direct_signals_shutdown() { D_DEBUG_AT( Direct_Signals, "%s() shutting down...\n", __FUNCTION__ ); remove_handlers(); direct_mutex_deinit( &handlers_lock ); return DR_OK; } void direct_signals_block_all() { sigset_t signals; D_DEBUG_AT( Direct_Signals, "Blocking all signals from now on\n" ); sigfillset( &signals ); sigprocmask( SIG_BLOCK, &signals, NULL ); } DirectResult direct_signal_handler_add( int num, DirectSignalHandlerFunc func, void *ctx, DirectSignalHandler **ret_handler ) { DirectSignalHandler *handler; D_ASSERT( func != NULL ); D_ASSERT( ret_handler != NULL ); D_DEBUG_AT( Direct_Signals, "Adding handler %p for signal %d with context %p...\n", func, num, ctx ); handler = D_CALLOC( 1, sizeof(DirectSignalHandler) ); if (!handler) { return DR_NOLOCALMEMORY; } handler->num = num; handler->func = func; handler->ctx = ctx; D_MAGIC_SET( handler, DirectSignalHandler ); direct_mutex_lock( &handlers_lock ); direct_list_append( &handlers, &handler->link ); direct_mutex_unlock( &handlers_lock ); *ret_handler = handler; return DR_OK; } DirectResult direct_signal_handler_remove( DirectSignalHandler *handler ) { D_MAGIC_ASSERT( handler, DirectSignalHandler ); D_DEBUG_AT( Direct_Signals, "Removing handler %p for signal %d with context %p...\n", handler->func, handler->num, handler->ctx ); /* Mark the handler for removal, freeing will actually come later. */ handler->removed = true; return DR_OK; } /**********************************************************************************************************************/ static void call_handlers( int num, void *addr ) { DirectSignalHandler *handler, *temp; DirectLink *garbage = NULL; if (num == SIGPIPE) num = DIRECT_SIGNAL_DUMP_STACK; /* Loop through all handlers. */ direct_mutex_lock( &handlers_lock ); direct_list_foreach_safe (handler, temp, handlers) { if (handler->removed) { direct_list_remove( &handlers, &handler->link ); direct_list_append( &garbage, &handler->link ); continue; } D_LOG( Direct_Signals, FATAL, " --> %d\n", handler->num ); if (handler->num != num && handler->num != DIRECT_SIGNAL_ANY) continue; if (handler->num == DIRECT_SIGNAL_ANY && num == DIRECT_SIGNAL_DUMP_STACK) continue; switch (handler->func( num, addr, handler->ctx )) { case DSHR_OK: break; case DSHR_REMOVE: direct_list_remove( &handlers, &handler->link ); direct_list_append( &garbage, &handler->link ); break; case DSHR_RESUME: D_LOG( Direct_Signals, FATAL, " '-> cured!\n" ); direct_mutex_unlock( &handlers_lock ); return; default: D_BUG( "unknown result" ); break; } } direct_list_foreach_safe (handler, temp, handlers) { D_MAGIC_CLEAR( handler ); D_FREE( handler ); } direct_mutex_unlock( &handlers_lock ); } static void signal_handler( int num, siginfo_t *info, void *uctx ) { if (info && info > (siginfo_t*) 0x100) D_LOG( Direct_Signals, FATAL, " --> Caught signal %d <--\n", info->si_signo ); else D_LOG( Direct_Signals, FATAL, " --> Caught signal %d, no siginfo available <--\n", num ); direct_trace_print_stacks(); call_handlers( num, NULL ); remove_handlers(); exit( -num ); } /**********************************************************************************************************************/ static void install_handlers() { int i; D_DEBUG_AT( Direct_Signals, "%s()\n", __FUNCTION__ ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) { sigs_handled[i].signum = -1; if (direct_config->sighandler && !sigismember( &direct_config->dont_catch, sigs_to_handle[i] )) { struct sigaction action; int signum = sigs_to_handle[i]; action.sa_sigaction = signal_handler; action.sa_flags = SA_SIGINFO; if (signum != SIGSEGV) action.sa_flags |= SA_NODEFER; sigemptyset( &action.sa_mask ); if (sigaction( signum, &action, &sigs_handled[i].old_action )) { D_PERROR( "Direct/Signals: Unable to install signal handler for signal %d!\n", signum ); continue; } sigs_handled[i].signum = signum; } } } static void remove_handlers() { int i; D_DEBUG_AT( Direct_Signals, "%s()\n", __FUNCTION__ ); for (i = 0; i < NUM_SIGS_TO_HANDLE; i++) { if (sigs_handled[i].signum != -1) { int signum = sigs_handled[i].signum; if (sigaction( signum, &sigs_handled[i].old_action, NULL )) { D_PERROR( "Direct/Signals: Unable to restore previous handler for signal %d!\n", signum ); } sigs_handled[i].signum = -1; } } } ================================================ FILE: lib/direct/os/nuttx/system.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include /**********************************************************************************************************************/ __attribute__((no_instrument_function)) void direct_sched_yield() { sched_yield(); } long direct_pagesize() { return sysconf( _SC_PAGESIZE ); } unsigned long direct_page_align( unsigned long value ) { unsigned long mask = sysconf( _SC_PAGESIZE ) - 1; return (value + mask) & ~mask; } __attribute__((no_instrument_function)) pid_t direct_getpid() { return getpid(); } __attribute__((no_instrument_function)) pid_t direct_gettid() { return gettid(); } void direct_trap( const char *domain, int sig ) { exit(0); } DirectResult direct_kill( pid_t pid, int sig ) { if (kill( pid, sig ) < 0) { if (errno == ESRCH) return DR_NOSUCHINSTANCE; else return errno2result( errno ); } return DR_OK; } void direct_sync() { } uid_t direct_geteuid() { return geteuid(); } char * direct_getenv( const char *name ) { return getenv( name ); } DirectResult direct_futex( int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3 ) { return DR_UNIMPLEMENTED; } bool direct_madvise() { return false; } ================================================ FILE: lib/direct/os/nuttx/thread.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Thread, "Direct/Thread", "Direct Thread Management" ); D_DEBUG_DOMAIN( Direct_ThreadInit, "Direct/Thread/Init", "Direct Thread Init" ); /**********************************************************************************************************************/ static pthread_key_t thread_key; static DirectOnce thread_init_once = DIRECT_ONCE_INIT(); /* * Wrapper around pthread's main routine to pass additional arguments * and setup things like signal masks and scheduling priorities. */ __attribute__((no_instrument_function)) static void *direct_thread_main( void *arg ); /**********************************************************************************************************************/ __attribute__((no_instrument_function)) DirectResult direct_once( DirectOnce *once, DirectOnceInitHandler handler ) { int erno = pthread_once( &once->once, handler ); return errno2result( erno ); } __attribute__((no_instrument_function)) static void init_once( void ) { /* Create the key for the TSD (thread specific data). */ pthread_key_create( &thread_key, NULL ); } DirectResult direct_thread_init( DirectThread *thread ) { int erno; pthread_attr_t attr; struct sched_param param; int policy; int priority; D_DEBUG_AT( Direct_ThreadInit, "%s( %p, '%s' )\n", __FUNCTION__, thread->main, thread->name ); direct_once( &thread_init_once, init_once ); /* Initialize scheduling and other parameters. */ pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); /* Select scheduler. */ switch (direct_config->thread_scheduler) { case DCTS_FIFO: policy = SCHED_FIFO; break; case DCTS_RR: policy = SCHED_RR; break; case DCTS_SPORADIC: policy = SCHED_SPORADIC; break; default: policy = SCHED_OTHER; break; } if (pthread_attr_setschedpolicy( &attr, policy )) D_PERROR( "Direct/Thread/Init: Could not set scheduling policy to %s!\n", direct_thread_policy_name( policy ) ); /* Read (back) value. */ pthread_attr_getschedpolicy( &attr, &policy ); thread->policy = policy; /* Select priority. */ switch (thread->type) { case DTT_CLEANUP: case DTT_INPUT: case DTT_OUTPUT: case DTT_MESSAGING: case DTT_CRITICAL: priority = thread->type * direct_config->thread_priority_scale / 100; break; default: priority = direct_config->thread_priority; break; } D_DEBUG_AT( Direct_ThreadInit, " -> priority %d [%d;%d]\n", priority, sched_get_priority_min( policy ), sched_get_priority_max( policy ) ); if (priority < sched_get_priority_min( policy )) priority = sched_get_priority_min( policy ); if (priority > sched_get_priority_max( policy )) priority = sched_get_priority_max( policy ); D_DEBUG_AT( Direct_ThreadInit, " -> policy %s with priority set to %d\n", direct_thread_policy_name( policy ), priority ); param.sched_priority = priority; if (pthread_attr_setschedparam( &attr, ¶m )) D_PERROR( "Direct/Thread/Init: Could not set scheduling priority to %d!\n", priority ); /* Select stack size. */ if (direct_config->thread_stack_size > 0) { if (pthread_attr_setstacksize( &attr, direct_config->thread_stack_size )) D_PERROR( "Direct/Thread/Init: Could not set stack size to %d!\n", direct_config->thread_stack_size ); } erno = pthread_create( &thread->handle, &attr, direct_thread_main, thread ); if (erno) return errno2result( erno ); /* Read (back) value. */ pthread_attr_getstacksize( &attr, &thread->stack_size ); pthread_attr_getschedparam( &attr, ¶m ); thread->priority = param.sched_priority; pthread_attr_destroy( &attr ); return DR_OK; } void direct_thread_deinit( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSUME( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->detached ); D_DEBUG_AT( Direct_ThreadInit, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (!thread->joined && !pthread_equal( thread->handle, pthread_self() )) { if (thread->canceled) D_DEBUG_AT( Direct_ThreadInit, " -> canceled but not joined!\n" ); else { D_DEBUG_AT( Direct_ThreadInit, " -> still running!\n" ); if (thread->name) D_ERROR( "Direct/Thread/Init: Canceling '%s' (%d)!\n", thread->name, thread->tid ); else D_ERROR( "Direct/Thread/Init: Canceling %d!\n", thread->tid ); pthread_cancel( thread->handle ); } pthread_join( thread->handle, NULL ); } } __attribute__((no_instrument_function)) void direct_thread_setcancelstate( DirectThreadCancelState state ) { switch (state) { case DIRECT_THREAD_CANCEL_ENABLE: pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); case DIRECT_THREAD_CANCEL_DISABLE: pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); } } __attribute__((no_instrument_function)) DirectThread * direct_thread_self() { DirectThread *thread; direct_once( &thread_init_once, init_once ); thread = pthread_getspecific( thread_key ); /* Support this function for non-direct threads. */ if (!thread) { thread = calloc( 1, sizeof(DirectThread) ); if (!thread) { D_OOM(); return NULL; } thread->handle = pthread_self(); thread->tid = direct_gettid(); D_MAGIC_SET( thread, DirectThread ); pthread_setspecific( thread_key, thread ); } return thread; } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" #endif __attribute__((no_instrument_function)) const char * direct_thread_self_name() { DirectThread *thread = direct_thread_self(); char name[CONFIG_TASK_NAME_SIZE]; /* This function is called by debugging functions, e.g. debug messages, assertions etc. Therefore no assertions are made here, because they would loop forever if they fail. */ if (!thread) return NULL; if (!thread->name) { prctl( PR_GET_NAME, name, 0, 0, 0 ); thread->name = strdup( name ); } return thread->name; } void direct_thread_set_name( const char *name ) { char *copy; DirectThread *thread; D_DEBUG_AT( Direct_Thread, "%s( '%s' )\n", __FUNCTION__, name ); thread = direct_thread_self(); if (!thread) return; /* Duplicate string. */ copy = strdup( name ); if (!copy) { D_OOM(); return; } /* Free old string. */ if (thread->name) free( thread->name ); /* Keep the copy. */ thread->name = copy; } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic pop #endif void direct_thread_cancel( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); thread->canceled = true; pthread_cancel( thread->handle ); } void direct_thread_detach( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); thread->detached = true; pthread_detach( thread->handle ); } void direct_thread_testcancel( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSERT( pthread_equal( thread->handle, pthread_self() ) ); /* Quick check before calling the pthread function. */ if (thread->canceled) pthread_testcancel(); } void direct_thread_join( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_ASSUME( !pthread_equal( thread->handle, pthread_self() ) ); D_ASSUME( !thread->joining ); D_ASSUME( !thread->joined ); D_ASSUME( !thread->detached ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (thread->detached) { D_DEBUG_AT( Direct_Thread, " -> detached\n" ); return; } if (!thread->joining && !pthread_equal( thread->handle, pthread_self() )) { thread->joining = true; D_DEBUG_AT( Direct_Thread, " -> joining...\n" ); pthread_join( thread->handle, NULL ); thread->joined = true; D_DEBUG_AT( Direct_Thread, " -> joined\n" ); } } void direct_thread_kill( DirectThread *thread, int signal ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->handle != -1 ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d, signal %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid, signal ); pthread_kill( thread->handle, signal ); } void direct_thread_sleep( long long micros ) { usleep( micros ); } void direct_thread_atfork( DirectThreadPrepareHandler prepare, DirectThreadParentHandler parent, DirectThreadChildHandler child ) { pthread_atfork( prepare, parent, child ); } /**********************************************************************************************************************/ const char * direct_thread_type_name( DirectThreadType type ) { switch (type) { case DTT_DEFAULT: return "DEFAULT"; case DTT_CLEANUP: return "CLEANUP"; case DTT_INPUT: return "INPUT"; case DTT_OUTPUT: return "OUTPUT"; case DTT_MESSAGING: return "MESSAGING"; case DTT_CRITICAL: return "CRITICAL"; } return ""; } const char * direct_thread_policy_name( int policy ) { switch (policy) { case SCHED_OTHER: return "OTHER"; case SCHED_FIFO: return "FIFO"; case SCHED_RR: return "RR"; case SCHED_SPORADIC: return "SPORADIC"; } return ""; } /**********************************************************************************************************************/ __attribute__((no_instrument_function)) DirectResult direct_tls_register( DirectTLS *tls, DirectTLSDestructor destructor ) { int erno = pthread_key_create( &tls->key, destructor ); return errno2result( erno ); } __attribute__((no_instrument_function)) DirectResult direct_tls_unregister( DirectTLS *tls ) { int erno; erno = pthread_key_delete( tls->key ); if (erno) return errno2result( erno ); tls->key = (pthread_key_t) -1; return DR_OK; } __attribute__((no_instrument_function)) void * direct_tls_get( DirectTLS *tls ) { void *value; value = pthread_getspecific( tls->key ); return value; } __attribute__((no_instrument_function)) DirectResult direct_tls_set( DirectTLS *tls, void *value ) { int erno = pthread_setspecific( tls->key, value ); return errno2result( erno ); } /**********************************************************************************************************************/ static void direct_thread_cleanup( void *arg ) { DirectThread *thread = arg; D_MAGIC_ASSERT( thread, DirectThread ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (thread->trace_buffer) direct_trace_free_buffer( thread->trace_buffer ); if (thread->detached) { D_MAGIC_CLEAR( thread ); if (thread->name) free( thread->name ); free( thread ); } } __attribute__((no_instrument_function)) static void * direct_thread_main( void *arg ) { void *res; DirectThread *thread = arg; prctl( PR_SET_NAME, thread->name, 0, 0, 0 ); pthread_setspecific( thread_key, thread ); D_DEBUG_AT( Direct_ThreadInit, "%s( %p )\n", __FUNCTION__, arg ); D_DEBUG_AT( Direct_ThreadInit, " -> starting...\n" ); D_MAGIC_ASSERT( thread, DirectThread ); pthread_cleanup_push( direct_thread_cleanup, thread ); thread->tid = direct_gettid(); D_DEBUG_AT( Direct_ThreadInit, " -> tid %d\n", thread->tid ); _direct_thread_call_init_handlers( thread ); /* Have all signals handled by the main thread. */ if (direct_config->thread_block_signals) { sigset_t signals; sigfillset( &signals ); sigprocmask( SIG_BLOCK, &signals, NULL ); } /* Lock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> locking...\n" ); direct_mutex_lock( &thread->lock ); /* Indicate that our initialization has completed. */ thread->init = true; D_DEBUG_AT( Direct_ThreadInit, " -> signalling...\n" ); direct_waitqueue_signal( &thread->cond ); /* Unlock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> unlocking...\n" ); direct_mutex_unlock( &thread->lock ); if (thread->joining) { D_DEBUG_AT( Direct_ThreadInit, " -> being joined before entering main routine!\n" ); return NULL; } /* Call main routine. */ D_DEBUG_AT( Direct_ThreadInit, " -> running...\n" ); res = thread->main( thread, thread->arg ); D_DEBUG_AT( Direct_Thread, " -> returning %p from '%s' (%s, %d)...\n", res, thread->name, direct_thread_type_name( thread->type ), thread->tid ); pthread_cleanup_pop( 1 ); return res; } ================================================ FILE: lib/direct/os/nuttx/thread.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__NUTTX__THREAD_H__ #define __DIRECT__OS__NUTTX__THREAD_H__ #include /**********************************************************************************************************************/ typedef pthread_t DirectThreadHandle; typedef struct { pthread_once_t once; } DirectOnce; #define DIRECT_ONCE_INIT() { PTHREAD_ONCE_INIT } typedef struct { pthread_key_t key; } DirectTLS; #endif ================================================ FILE: lib/direct/os/nuttx/types.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__NUTTX__TYPES_H__ #define __DIRECT__OS__NUTTX__TYPES_H__ #include #include #include #include #include #include #include #include #include #include #include typedef unsigned int unichar; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long int u64; typedef signed char s8; typedef short int s16; typedef int s32; typedef long long int s64; #define _ZD "%zd" #define _ZU "%zu" #define _ZUn(x) "%" #x "zu" #endif ================================================ FILE: lib/direct/os/nuttx/waitqueue.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__NUTTX__WAITQUEUE_H__ #define __DIRECT__OS__NUTTX__WAITQUEUE_H__ #include #include /**********************************************************************************************************************/ typedef struct { pthread_cond_t cond; } DirectWaitQueue; static inline DirectResult direct_waitqueue_init( DirectWaitQueue *queue ) { int erno = pthread_cond_init( &queue->cond, NULL ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_wait( DirectWaitQueue *queue, DirectMutex *mutex ) { int erno = pthread_cond_wait( &queue->cond, &mutex->lock ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_wait_timeout( DirectWaitQueue *queue, DirectMutex *mutex, unsigned long micros ) { struct timeval now; struct timespec timeout; long seconds = micros / 1000000; long nano_seconds = (micros % 1000000) * 1000; gettimeofday( &now, NULL ); timeout.tv_sec = now.tv_sec + seconds; timeout.tv_nsec = (now.tv_usec * 1000) + nano_seconds; timeout.tv_sec += timeout.tv_nsec / 1000000000; timeout.tv_nsec %= 1000000000; if (pthread_cond_timedwait( &queue->cond, &mutex->lock, &timeout ) == ETIMEDOUT) return DR_TIMEOUT; return DR_OK; } static inline DirectResult direct_waitqueue_signal( DirectWaitQueue *queue ) { int erno = pthread_cond_signal( &queue->cond ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_broadcast( DirectWaitQueue *queue ) { int erno = pthread_cond_broadcast( &queue->cond ); return errno2result( erno ); } static inline DirectResult direct_waitqueue_deinit( DirectWaitQueue *queue ) { int erno = pthread_cond_destroy( &queue->cond ); return errno2result( erno ); } #endif ================================================ FILE: lib/direct/os/signals.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__SIGNALS_H__ #define __DIRECT__OS__SIGNALS_H__ #include /**********************************************************************************************************************/ typedef enum { DSHR_OK = 0x00000000, DSHR_REMOVE = 0x00000001, DSHR_RESUME = 0x00000002 } DirectSignalHandlerResult; typedef DirectSignalHandlerResult (*DirectSignalHandlerFunc)( int num, void *addr, void *ctx ); /* * Signal number to use when registering a handler for any interrupt. */ #define DIRECT_SIGNAL_ANY -1 #define DIRECT_SIGNAL_DUMP_STACK -2 /**********************************************************************************************************************/ DirectResult DIRECT_API direct_signals_initialize ( void ); DirectResult DIRECT_API direct_signals_shutdown ( void ); /* * Modifies the current thread's signal mask to block everything. */ void DIRECT_API direct_signals_block_all ( void ); DirectResult DIRECT_API direct_signal_handler_add ( int num, DirectSignalHandlerFunc func, void *ctx, DirectSignalHandler **ret_handler ); DirectResult DIRECT_API direct_signal_handler_remove( DirectSignalHandler *handler ); #endif ================================================ FILE: lib/direct/os/system.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__SYSTEM_H__ #define __DIRECT__OS__SYSTEM_H__ #include /**********************************************************************************************************************/ void DIRECT_API direct_sched_yield( void ); long DIRECT_API direct_pagesize ( void ); unsigned long DIRECT_API direct_page_align ( unsigned long value ); pid_t DIRECT_API direct_getpid ( void ); pid_t DIRECT_API direct_gettid ( void ); void DIRECT_API direct_trap ( const char *domain, int sig ); DirectResult DIRECT_API direct_kill ( pid_t pid, int sig ); void DIRECT_API direct_sync ( void ); uid_t DIRECT_API direct_geteuid ( void ); char DIRECT_API *direct_getenv ( const char *name ); DirectResult DIRECT_API direct_futex ( int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3 ); bool DIRECT_API direct_madvise ( void ); /**********************************************************************************************************************/ #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 extern unsigned int DIRECT_API __Direct_Futex_Wait_Count; extern unsigned int DIRECT_API __Direct_Futex_Wake_Count; #endif ================================================ FILE: lib/direct/os/thread.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__THREAD_H__ #define __DIRECT__OS__THREAD_H__ #include #include /**********************************************************************************************************************/ typedef enum { DTT_DEFAULT = 0, DTT_CLEANUP = -5, DTT_INPUT = -10, DTT_OUTPUT = -12, DTT_MESSAGING = -15, DTT_CRITICAL = -20 } DirectThreadType; typedef void *(*DirectThreadMainFunc)( DirectThread *thread, void *arg ); struct __D_DirectThread { int magic; char *name; DirectThreadType type; /* The thread's type. */ DirectThreadMainFunc main; /* The thread's main routine (or entry point). */ void *arg; /* Custom argument passed to the main routine. */ DirectThreadHandle handle; /* The thread's handle. */ pid_t tid; /* The thread's ID. */ bool canceled; /* Set when direct_thread_cancel() is called. */ bool joining; /* Set when direct_thread_join() is called. */ bool joined; /* Set when direct_thread_join() has finished. */ bool detached; /* Set when direct_thread_detach() is called. */ bool terminated; /* Set when direct_thread_terminate() is called. */ bool init; /* Set to true before the main routine is called. */ DirectMutex lock; DirectWaitQueue cond; unsigned int counter; int policy; int priority; size_t stack_size; void *trace_buffer; }; /**********************************************************************************************************************/ typedef enum { DIRECT_THREAD_CANCEL_ENABLE = 0x00000000, DIRECT_THREAD_CANCEL_DISABLE = 0x00000001 } DirectThreadCancelState; typedef void (*DirectOnceInitHandler)( void ); typedef void (*DirectThreadPrepareHandler)( void ); typedef void (*DirectThreadParentHandler) ( void ); typedef void (*DirectThreadChildHandler) ( void ); typedef void (*DirectTLSDestructor)( void *arg ); /**********************************************************************************************************************/ /* * Thread initialization/deinitialization. */ DirectResult DIRECT_API direct_once ( DirectOnce *once, DirectOnceInitHandler handler ); DirectResult DIRECT_API direct_thread_init ( DirectThread *thread ); void DIRECT_API direct_thread_deinit ( DirectThread *thread ); /* * Sets the cancelability state of the calling thread. */ void DIRECT_API direct_thread_setcancelstate ( DirectThreadCancelState state ); /* * Returns the thread of the caller. */ DirectThread DIRECT_API *direct_thread_self ( void ); /* * Returns the name of the calling thread. */ const char DIRECT_API *direct_thread_self_name ( void ); /* * Changes the name of the calling thread. */ void DIRECT_API direct_thread_set_name ( const char *name ); /* * Cancel a running thread. */ void DIRECT_API direct_thread_cancel ( DirectThread *thread ); /* * Detach a thread. */ void DIRECT_API direct_thread_detach ( DirectThread *thread ); /* * Check if the calling thread is canceled. */ void DIRECT_API direct_thread_testcancel ( DirectThread *thread ); /* * Wait until a running thread is terminated. */ void DIRECT_API direct_thread_join ( DirectThread *thread ); /* * Send a signal to a thread. */ void DIRECT_API direct_thread_kill ( DirectThread *thread, int signal ); /* * Sleep a thread. */ void DIRECT_API direct_thread_sleep ( long long micros ); /* * Register fork handlers. */ void DIRECT_API direct_thread_atfork ( DirectThreadPrepareHandler prepare, DirectThreadParentHandler parent, DirectThreadChildHandler child ); /* * Utilities for stringification. */ const char DIRECT_API *direct_thread_type_name ( DirectThreadType type ); const char DIRECT_API *direct_thread_policy_name ( int policy ); /* * Thread-specific data. */ DirectResult DIRECT_API direct_tls_register ( DirectTLS *tls, DirectTLSDestructor destructor ); DirectResult DIRECT_API direct_tls_unregister ( DirectTLS *tls ); void DIRECT_API *direct_tls_get ( DirectTLS *tls ); DirectResult DIRECT_API direct_tls_set ( DirectTLS *tls, void *value); /* * Call all init handlers. */ void DIRECT_API _direct_thread_call_init_handlers( DirectThread *thread ); #endif ================================================ FILE: lib/direct/os/types.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__TYPES_H__ #define __DIRECT__OS__TYPES_H__ #include #endif #if defined(DIRECT_BUILD_OS_LINUX) #include #ifdef __DIRECT__OS__FILESYSTEM_H__ #include #endif #ifdef __DIRECT__OS__MUTEX_H__ #include #endif #ifdef __DIRECT__OS__THREAD_H__ #include #endif #ifdef __DIRECT__OS__WAITQUEUE_H__ #include #endif #elif defined(DIRECT_BUILD_OS_NUTTX) #include #ifdef __DIRECT__OS__FILESYSTEM_H__ #include #endif #ifdef __DIRECT__OS__MUTEX_H__ #include #endif #ifdef __DIRECT__OS__THREAD_H__ #include #endif #ifdef __DIRECT__OS__WAITQUEUE_H__ #include #endif #else #error Unsupported OS! #endif #ifndef __DIRECT__TYPES_H__ #include #endif ================================================ FILE: lib/direct/os/waitqueue.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__OS__WAITQUEUE_H__ #define __DIRECT__OS__WAITQUEUE_H__ #include /**********************************************************************************************************************/ DirectResult DIRECT_API direct_waitqueue_init ( DirectWaitQueue *queue ); DirectResult DIRECT_API direct_waitqueue_wait ( DirectWaitQueue *queue, DirectMutex *mutex ); DirectResult DIRECT_API direct_waitqueue_wait_timeout( DirectWaitQueue *queue, DirectMutex *mutex, unsigned long micros ); DirectResult DIRECT_API direct_waitqueue_signal ( DirectWaitQueue *queue ); DirectResult DIRECT_API direct_waitqueue_broadcast ( DirectWaitQueue *queue ); DirectResult DIRECT_API direct_waitqueue_deinit ( DirectWaitQueue *queue ); #endif ================================================ FILE: lib/direct/result.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Direct_Result, "Direct/Result", "Direct Result types" ); /**********************************************************************************************************************/ static DirectHash result_types = DIRECT_HASH_INIT( 7, false ); static DirectMutex result_mutex; /**********************************************************************************************************************/ void __D_result_init() { direct_mutex_init( &result_mutex ); } void __D_result_deinit() { direct_mutex_deinit( &result_mutex ); } /**********************************************************************************************************************/ DirectResult DirectResultTypeRegister( DirectResultType *type ) { DirectResult ret; D_DEBUG_AT( Direct_Result, "%s( %p )\n", __FUNCTION__, type ); D_ASSERT( type != NULL ); D_DEBUG_AT( Direct_Result, " -> refs %d\n", type->refs ); D_DEBUG_AT( Direct_Result, " -> base 0x%08x\n", type->base ); D_DEBUG_AT( Direct_Result, " -> strings %p\n", type->result_strings ); D_DEBUG_AT( Direct_Result, " -> count %u\n", type->result_count ); D_ASSERT( type->result_count > 0 ); D_ASSERT( type->result_count <= D_RESULT_TYPE_SPACE ); D_DEBUG_AT( Direct_Result, " => %s\n", type->result_strings[0] ); ret = direct_mutex_lock( &result_mutex ); if (ret) return ret; if (direct_hash_lookup( &result_types, type->base )) { D_ASSERT( direct_hash_lookup( &result_types, type->base ) == type ); D_MAGIC_ASSERT( type, DirectResultType ); D_ASSERT( type->refs > 0 ); type->refs++; } else { D_ASSERT( type->refs == 0 ); D_MAGIC_SET( type, DirectResultType ); ret = direct_hash_insert( &result_types, type->base, type ); if (ret) D_MAGIC_CLEAR( type ); else type->refs = 1; } direct_mutex_unlock( &result_mutex ); return ret; } DirectResult DirectResultTypeUnregister( DirectResultType *type ) { DirectResult ret; D_DEBUG_AT( Direct_Result, "%s( %p )\n", __FUNCTION__, type ); D_MAGIC_ASSERT( type, DirectResultType ); D_DEBUG_AT( Direct_Result, " -> refs %d\n", type->refs ); D_DEBUG_AT( Direct_Result, " -> base 0x%08x\n", type->base ); D_DEBUG_AT( Direct_Result, " -> strings %p\n", type->result_strings ); D_DEBUG_AT( Direct_Result, " -> count %u\n", type->result_count ); D_ASSERT( type->result_count > 0 ); D_ASSERT( type->result_count <= D_RESULT_TYPE_SPACE ); D_DEBUG_AT( Direct_Result, " => %s\n", type->result_strings[0] ); ret = direct_mutex_lock( &result_mutex ); if (ret) return ret; D_ASSERT( type->refs > 0 ); D_ASSERT( direct_hash_lookup( &result_types, type->base ) == type ); if (!--type->refs) { D_MAGIC_CLEAR( type ); ret = direct_hash_remove( &result_types, type->base ); } direct_mutex_unlock( &result_mutex ); return ret; } const char * DirectResultString( DirectResult result ) { DirectResult ret; DirectResultType *type; if (result) { ret = direct_mutex_lock( &result_mutex ); if (ret) return NULL; type = direct_hash_lookup( &result_types, D_RESULT_TYPE( result ) ); direct_mutex_unlock( &result_mutex ); if (type) { unsigned int index = D_RESULT_INDEX( result ); D_MAGIC_ASSERT( type, DirectResultType ); D_ASSERT( type->refs > 0 ); if (index < type->result_count) return type->result_strings[index]; return type->result_strings[0]; } return "UNKNOWN RESULT TYPE"; } return "OK"; } ================================================ FILE: lib/direct/result.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__RESULT_H__ #define __DIRECT__RESULT_H__ #include /**********************************************************************************************************************/ typedef struct { int magic; int refs; unsigned int base; const char **result_strings; unsigned int result_count; } DirectResultType; /**********************************************************************************************************************/ DirectResult DIRECT_API DirectResultTypeRegister ( DirectResultType *type ); DirectResult DIRECT_API DirectResultTypeUnregister( DirectResultType *type ); const char DIRECT_API *DirectResultString ( DirectResult result ); /**********************************************************************************************************************/ void __D_result_init ( void ); void __D_result_deinit( void ); #endif ================================================ FILE: lib/direct/serial.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__SERIAL_H__ #define __DIRECT__SERIAL_H__ #include D_DEBUG_DOMAIN( Direct_Serial, "Direct/Serial", "Direct Serial" ); /**********************************************************************************************************************/ typedef struct { int magic; u32 overflow; unsigned long value; int waiting; int wakeup; } DirectSerial; /**********************************************************************************************************************/ static __inline__ void direct_serial_init( DirectSerial *serial ) { D_DEBUG_AT( Direct_Serial, "%s( %p )\n", __FUNCTION__, serial ); D_ASSERT( serial != NULL ); serial->value = 0; serial->overflow = 0; serial->waiting = 0; D_MAGIC_SET( serial, DirectSerial ); } static __inline__ void direct_serial_deinit( DirectSerial *serial ) { D_MAGIC_ASSERT( serial, DirectSerial ); D_DEBUG_AT( Direct_Serial, "%s( %p ) <- %lu\n", __FUNCTION__, serial, serial->value ); D_ASSUME( serial->waiting == 0 ); D_MAGIC_CLEAR( serial ); } static __inline__ void direct_serial_increase( DirectSerial *serial ) { D_MAGIC_ASSERT( serial, DirectSerial ); D_DEBUG_AT( Direct_Serial, "%s( %p ) <- %lu ++\n", __FUNCTION__, serial, serial->value ); if (!++serial->value) serial->overflow++; D_DEBUG_AT( Direct_Serial, " -> %lu\n", serial->value ); } static __inline__ void direct_serial_copy( DirectSerial *serial, const DirectSerial *source ) { D_MAGIC_ASSERT( serial, DirectSerial ); D_MAGIC_ASSERT( source, DirectSerial ); D_DEBUG_AT( Direct_Serial, "%s( %p, %p ) <- %lu = %lu\n", __FUNCTION__, serial, source, source->value, serial->value ); serial->value = source->value; serial->overflow = source->overflow; } static __inline__ bool direct_serial_check( const DirectSerial *serial, const DirectSerial *source ) { D_MAGIC_ASSERT( serial, DirectSerial ); D_MAGIC_ASSERT( source, DirectSerial ); D_DEBUG_AT( Direct_Serial, "%s( %p, %p ) <- %lu == %lu\n", __FUNCTION__, serial, source, serial->value, source->value ); if (serial->overflow < source->overflow) return false; else if (serial->overflow == source->overflow && serial->value < source->value) return false; return true; } static __inline__ bool direct_serial_update( DirectSerial *serial, const DirectSerial *source ) { D_MAGIC_ASSERT( serial, DirectSerial ); D_MAGIC_ASSERT( source, DirectSerial ); D_DEBUG_AT( Direct_Serial, "%s( %p, %p ) <- %lu <-= %lu\n", __FUNCTION__, serial, source, serial->value, source->value ); if (serial->overflow < source->overflow) { serial->overflow = source->overflow; serial->value = source->value; return true; } else if (serial->overflow == source->overflow && serial->value < source->value) { serial->value = source->value; return true; } return false; } #endif ================================================ FILE: lib/direct/signals.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__SIGNALS_H__ #define __DIRECT__SIGNALS_H__ #include /**********************************************************************************************************************/ #endif ================================================ FILE: lib/direct/stream.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Stream, "Direct/Stream", "Direct Stream wrapper" ); /**********************************************************************************************************************/ struct __D_DirectStream { int magic; int ref; int fd; DirectFile file; off_t offset; ssize_t length; char *mime; #if DIRECT_BUILD_PIPED_STREAM /* Cache for piped streams. */ void *cache; unsigned int cache_size; #endif /* DIRECT_BUILD_PIPED_STREAM */ #if DIRECT_BUILD_NETWORK /* Remote streams data. */ struct { int sd; char *host; int port; struct addrinfo *addr; char *user; char *pass; char *auth; char *path; int redirects; void *data; } remote; #endif /* DIRECT_BUILD_NETWORK */ DirectResult (*wait)( DirectStream *stream, unsigned int length, struct timeval *timeout ); DirectResult (*peek)( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ); DirectResult (*read)( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ); DirectResult (*seek)( DirectStream *stream, unsigned int offset ); }; /**********************************************************************************************************************/ static void direct_stream_close( DirectStream *stream ) { #if DIRECT_BUILD_NETWORK if (stream->remote.host) { D_FREE( stream->remote.host ); stream->remote.host = NULL; } if (stream->remote.user) { D_FREE( stream->remote.user ); stream->remote.user = NULL; } if (stream->remote.pass) { D_FREE( stream->remote.pass ); stream->remote.pass = NULL; } if (stream->remote.auth) { D_FREE( stream->remote.auth ); stream->remote.auth = NULL; } if (stream->remote.path) { D_FREE( stream->remote.path ); stream->remote.path = NULL; } if (stream->remote.addr) { freeaddrinfo( stream->remote.addr ); stream->remote.addr = NULL; } if (stream->remote.data) { D_FREE( stream->remote.data ); stream->remote.data = NULL; } if (stream->remote.sd > 0) { close( stream->remote.sd ); stream->remote.sd = -1; } #endif /* DIRECT_BUILD_NETWORK */ #if DIRECT_BUILD_PIPED_STREAM if (stream->cache) { D_FREE( stream->cache ); stream->cache = NULL; stream->cache_size = 0; } #endif /* DIRECT_BUILD_PIPED_STREAM */ #if DIRECT_BUILD_NETWORK || DIRECT_BUILD_PIPED_STREAM if (stream->fd >= 0) { fcntl( stream->fd, F_SETFL, fcntl( stream->fd, F_GETFL ) & ~O_NONBLOCK ); close( stream->fd ); stream->fd = -1; } else #endif /* DIRECT_BUILD_NETWORK || DIRECT_BUILD_PIPED_STREAM */ direct_file_close( &stream->file ); if (stream->mime) { D_FREE( stream->mime ); stream->mime = NULL; } } /**********************************************************************************************************************/ #if DIRECT_BUILD_NETWORK static __inline__ char * trim( char *s ) { char *e; #define space(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n' || (c) == '"' || (c) == '\'') for (; space(*s); s++); e = s + strlen( s ) - 1; for (; e > s && space(*e); *e-- = '\0'); #undef space return s; } static void parse_url( const char *url, char **ret_host, int *ret_port, char **ret_user, char **ret_pass, char **ret_path ) { char *path; char *tmp; char *host; char *user = NULL; char *pass = NULL; int port = 0; tmp = strchr( url, '/' ); if (tmp) { host = alloca( tmp - url + 1 ); direct_memcpy( host, url, tmp - url ); host[tmp-url] = '\0'; path = tmp; } else { host = alloca( strlen( url ) + 1 ); direct_memcpy( host, url, strlen( url ) + 1 ); path = "/"; } tmp = strrchr( host, '@' ); if (tmp) { *tmp = '\0'; pass = strchr( host, ':' ); if (pass) { *pass = '\0'; pass++; } user = host; host = tmp + 1; } tmp = strchr( host, ':' ); if (tmp) { port = strtol( tmp + 1, NULL, 10 ); *tmp = '\0'; } /* Host within brackets. */ if (*host == '[') { host++; tmp = strchr( host, ']' ); if (tmp) *tmp = '\0'; } if (ret_host) *ret_host = D_STRDUP( host ); if (ret_port && port) *ret_port = port; if (ret_user && user) *ret_user = D_STRDUP( user ); if (ret_pass && pass) *ret_pass = D_STRDUP( pass ); if (ret_path) *ret_path = D_STRDUP( path ); } /**********************************************************************************************************************/ #define NET_TIMEOUT 15 static int net_response( DirectStream *stream, char *buf, size_t size ) { int i; fd_set set; struct timeval timeout; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); FD_ZERO( &set ); FD_SET( stream->remote.sd, &set ); for (i = 0; i < size - 1; i++) { timeout.tv_sec = NET_TIMEOUT; timeout.tv_usec = 0; select( stream->remote.sd + 1, &set, NULL, NULL, &timeout ); if (recv( stream->remote.sd, buf + i, 1, 0 ) != 1) break; if (buf[i] == '\n') { if (i > 0 && buf[i-1] == '\r') i--; break; } } buf[i] = '\0'; D_DEBUG_AT( Direct_Stream, " -> got [%s]\n", buf ); return i; } static int net_command( DirectStream *stream, char *buf, size_t size ) { fd_set set; struct timeval timeout; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); FD_ZERO( &set ); FD_SET( stream->remote.sd, &set ); timeout.tv_sec = NET_TIMEOUT; timeout.tv_usec = 0; switch (select( stream->remote.sd + 1, NULL, &set, NULL, &timeout )) { case 0: D_DEBUG_AT( Direct_Stream, " -> timeout\n" ); case -1: return -1; } send( stream->remote.sd, buf, strlen( buf ), 0 ); send( stream->remote.sd, "\r\n", 2, 0 ); D_DEBUG_AT( Direct_Stream, " -> sent [%s]\n", buf ); while (net_response( stream, buf, size ) > 0) { int status; int version; char space; if (sscanf( buf, "HTTP/1.%d %3d", &version, &status ) == 2 || sscanf( buf, "RTSP/1.%d %3d", &version, &status ) == 2 || sscanf( buf, "%3d%[ ]", &status, &space ) == 2) return status; } return 0; } static DirectResult net_connect( struct addrinfo *addr, int sock, int proto, int *ret_fd ) { DirectResult ret = DR_OK; int fd = -1; struct addrinfo *tmp; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); D_ASSERT( addr != NULL ); D_ASSERT( ret_fd != NULL ); for (tmp = addr; tmp; tmp = tmp->ai_next) { int err; fd = socket( tmp->ai_family, sock, proto ); if (fd < 0) { ret = errno2result( errno ); D_DEBUG_AT( Direct_Stream, " -> failed to create socket!\n" ); continue; } fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK ); D_DEBUG_AT( Direct_Stream, " -> connecting to %s...\n", tmp->ai_canonname ); if (proto == IPPROTO_UDP) err = bind( fd, tmp->ai_addr, tmp->ai_addrlen ); else err = connect( fd, tmp->ai_addr, tmp->ai_addrlen ); if (err == 0 || errno == EINPROGRESS) { fd_set set; struct timeval timeout = { NET_TIMEOUT, 0 }; /* Join multicast group. */ if (tmp->ai_addr->sa_family == AF_INET) { struct sockaddr_in *saddr = (struct sockaddr_in*) tmp->ai_addr; if (IN_MULTICAST( ntohl(saddr->sin_addr.s_addr) )) { struct ip_mreq req; D_DEBUG_AT( Direct_Stream, " -> joining multicast group (%d.%d.%d.%d)...\n", tmp->ai_addr->sa_data[2], tmp->ai_addr->sa_data[3], tmp->ai_addr->sa_data[4], tmp->ai_addr->sa_data[5] ); req.imr_multiaddr.s_addr = saddr->sin_addr.s_addr; req.imr_interface.s_addr = 0; err = setsockopt( fd, SOL_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req) ); if (err < 0) { ret = errno2result( errno ); D_DEBUG_AT( Direct_Stream, " -> could not join multicast group (%d.%d.%d.%d)\n", tmp->ai_addr->sa_data[2], tmp->ai_addr->sa_data[3], tmp->ai_addr->sa_data[4], tmp->ai_addr->sa_data[5] ); close( fd ); continue; } setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, saddr, sizeof(*saddr) ); } } FD_ZERO( &set ); FD_SET( fd, &set ); err = select( fd + 1, NULL, &set, NULL, &timeout ); if (err < 1) { D_DEBUG_AT( Direct_Stream, " -> ...connection failed\n" ); close( fd ); fd = -1; if (err == 0) { ret = DR_TIMEOUT; continue; } else { ret = errno2result( errno ); break; } } D_DEBUG_AT( Direct_Stream, " -> ...connected\n" ); ret = DR_OK; break; } } *ret_fd = fd; return ret; } static DirectResult net_stream_wait( DirectStream *stream, unsigned int length, struct timeval *timeout ) { fd_set set; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (stream->fd == -1) return DR_EOF; FD_ZERO( &set ); FD_SET( stream->fd, &set ); switch (select( stream->fd + 1, &set, NULL, NULL, timeout )) { case 0: if (!timeout) return DR_EOF; return DR_TIMEOUT; case -1: return errno2result( errno ); } return DR_OK; } static DirectResult net_stream_peek( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ) { ssize_t size; char *tmp; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (offset < 0) return DR_UNSUPPORTED; tmp = alloca( length + offset ); size = recv( stream->fd, tmp, length + offset, MSG_PEEK ); switch (size) { case 0: return DR_EOF; case -1: if (errno == EAGAIN || errno == EWOULDBLOCK) return DR_BUFFEREMPTY; return errno2result( errno ); default: if (size < offset) return DR_BUFFEREMPTY; size -= offset; break; } direct_memcpy( buf, tmp + offset, size ); if (read_out) *read_out = size; return DR_OK; } static DirectResult net_stream_read( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ) { ssize_t size; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); size = recv( stream->fd, buf, length, 0 ); switch (size) { case 0: return DR_EOF; case -1: if (errno == EAGAIN || errno == EWOULDBLOCK) return DR_BUFFEREMPTY; return errno2result( errno ); } stream->offset += size; if (read_out) *read_out = size; return DR_OK; } static DirectResult net_stream_open( DirectStream *stream, const char *filename, int proto ) { DirectResult ret; struct addrinfo hints; char port[16]; int sock = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); parse_url( filename, &stream->remote.host, &stream->remote.port, &stream->remote.user, &stream->remote.pass, &stream->remote.path ); snprintf( port, sizeof(port), "%d", stream->remote.port ); memset( &hints, 0, sizeof(hints) ); hints.ai_flags = AI_CANONNAME; hints.ai_socktype = sock; hints.ai_family = PF_UNSPEC; if (getaddrinfo( stream->remote.host, port, &hints, &stream->remote.addr )) { D_ERROR( "Direct/Stream: Failed to resolve host '%s'\n", stream->remote.host ); return DR_FAILURE; } ret = net_connect( stream->remote.addr, sock, proto, &stream->remote.sd ); if (ret) return ret; stream->fd = stream->remote.sd; stream->length = -1; stream->wait = net_stream_wait; stream->peek = net_stream_peek; stream->read = net_stream_read; return DR_OK; } /**********************************************************************************************************************/ #define FTP_PORT 21 static DirectResult ftp_open_pasv( DirectStream *stream, char *buf, size_t size ) { DirectResult ret; int i; int len; snprintf( buf, size, "PASV" ); if (net_command( stream, buf, size ) != 227) return DR_FAILURE; for (i = 4; buf[i]; i++) { unsigned int d[6]; if (sscanf( &buf[i], "%u,%u,%u,%u,%u,%u", &d[0], &d[1], &d[2], &d[3], &d[4], &d[5] ) == 6) { struct addrinfo hints, *addr; /* Address */ len = snprintf( buf, size, "%u.%u.%u.%u", d[0], d[1], d[2], d[3] ); /* Port */ snprintf( buf + len + 1, size - len - 1, "%u", ((d[4] & 0xff) << 8) | (d[5] & 0xff) ); memset( &hints, 0, sizeof(hints) ); hints.ai_flags = AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; if (getaddrinfo( buf, buf + len + 1, &hints, &addr )) { D_ERROR( "Direct/Stream: Failed to resolve host '%s'\n", buf ); return DR_FAILURE; } ret = net_connect( addr, SOCK_STREAM, IPPROTO_TCP, &stream->fd ); freeaddrinfo( addr ); return ret; } } return DR_FAILURE; } static DirectResult ftp_stream_seek( DirectStream *stream, unsigned int offset ) { DirectResult ret; char buf[512]; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (stream->fd > 0) { close( stream->fd ); stream->fd = -1; /* Ignore response. */ while (net_response( stream, buf, sizeof(buf) ) > 0) { int status; if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2) break; } } ret = ftp_open_pasv( stream, buf, sizeof(buf) ); if (ret) return ret; snprintf( buf, sizeof(buf), "REST %u", offset ); if (net_command( stream, buf, sizeof(buf) ) != 350) goto error; snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path ); switch (net_command( stream, buf, sizeof(buf) )) { case 150: case 125: break; default: goto error; } stream->offset = offset; return DR_OK; error: close( stream->fd ); stream->fd = -1; return DR_FAILURE; } static DirectResult ftp_stream_open( DirectStream *stream, const char *filename ) { DirectResult ret; int status = 0; char buf[512]; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); stream->remote.port = FTP_PORT; ret = net_stream_open( stream, filename, IPPROTO_TCP ); if (ret) return ret; while (net_response( stream, buf, sizeof(buf) ) > 0) { if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2) break; } if (status != 220) return DR_FAILURE; /* Login. */ snprintf( buf, sizeof(buf), "USER %s", stream->remote.user ?: "anonymous" ); switch (net_command( stream, buf, sizeof(buf) )) { case 230: case 331: break; default: return DR_FAILURE; } if (stream->remote.pass) { snprintf( buf, sizeof(buf), "PASS %s", stream->remote.pass ); if (net_command( stream, buf, sizeof(buf) ) != 230) return DR_FAILURE; } /* Enter binary mode. */ snprintf( buf, sizeof(buf), "TYPE I" ); if (net_command( stream, buf, sizeof(buf) ) != 200) return DR_FAILURE; /* Get file size. */ snprintf( buf, sizeof(buf), "SIZE %s", stream->remote.path ); if (net_command( stream, buf, sizeof(buf) ) == 213) stream->length = strtol( buf + 4, NULL, 10 ); /* Enter passive mode by default. */ ret = ftp_open_pasv( stream, buf, sizeof(buf) ); if (ret) return ret; /* Retrieve file. */ snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path ); switch (net_command( stream, buf, sizeof(buf) )) { case 125: case 150: break; default: return DR_FAILURE; } stream->seek = ftp_stream_seek; return DR_OK; } /**********************************************************************************************************************/ #define RTSP_PORT 554 typedef struct { s8 pt; const char *mime; } RTPPayload; static const RTPPayload payloads[] = { { 32, "video/mpeg", }, { 33, "video/mpegts" }, { 34, "video/h263", }, }; #define NUM_PAYLOADS D_ARRAY_SIZE(payloads) typedef struct { s8 pt; char control[128]; } SDPMedia; static DirectResult sdp_parse( DirectStream *stream, int length, SDPMedia *media ) { fd_set set; struct timeval timeout; char *buf, *tmp; buf = D_CALLOC( 1, length + 1 ); if (!buf) return D_OOM(); FD_ZERO( &set ); FD_SET( stream->remote.sd, &set ); timeout.tv_sec = NET_TIMEOUT; timeout.tv_usec = 0; select( stream->remote.sd + 1, &set, NULL, NULL, &timeout ); if (recv( stream->remote.sd, buf, length, MSG_WAITALL ) < 1) return DR_EOF; for (tmp = buf; tmp && *tmp;) { char *end; end = strchr( tmp, '\n' ); if (end) { if (end > tmp && *(end - 1) == '\r') *(end - 1) = '\0'; *end = '\0'; } switch (*tmp) { case 'm': if (*(tmp + 1) == '=') { int i, pt; tmp += 2; if (sscanf( tmp, "video %d RTP/AVP %d", &i, &pt ) == 2) { for (i = 0; i < NUM_PAYLOADS; i++) { if (pt == payloads[i].pt) { media->pt = pt; if (stream->mime) D_FREE( stream->mime ); stream->mime = D_STRDUP( payloads[i].mime ); break; } } } } break; case 'a': if (*(tmp + 1) == '=' && media->pt) { tmp += 2; if (!strncmp( tmp, "control:", 8 )) snprintf( media->control, sizeof(media->control), "%s", trim( tmp + 8 ) ); } break; default: break; } tmp = end; if (tmp) tmp++; } D_FREE( buf ); return media->pt ? DR_OK : DR_FAILURE; } static DirectResult rtp_read_packet( DirectStream *stream ) { int len; unsigned char buf[12]; s8 pt = *(s8*) stream->remote.data; int skip = 0; do { if (recv( stream->fd, buf, 1, MSG_WAITALL ) < 1) return DR_EOF; } while (buf[0] != '$'); if (recv( stream->fd, buf, 3, MSG_WAITALL ) < 3) return DR_EOF; len = (buf[1] << 8) | buf[2]; if (len < 12) return DR_FAILURE; if (recv( stream->fd, buf, 12, MSG_WAITALL ) < 12) return DR_EOF; len -= 12; if ((buf[0] & 0xc0) != (2 << 6)) { D_ERROR( "Direct/Stream: Bad RTP version %d!\n", buf[0] ); return DR_FAILURE; } if ((buf[1] & 0x7f) == 72) { while (len) { ssize_t size; size = recv( stream->fd, buf, MIN( len, 12 ), MSG_WAITALL ); if (size < 1) return DR_EOF; len -= size; } return DR_OK; } else if ((buf[1] & 0x7f) != pt) { D_ERROR( "Direct/Stream: Bad Payload type %d!\n", buf[1] & 0x7f ); return DR_FAILURE; } switch (pt) { case 32: /* MPEG Video */ if (recv( stream->fd, buf, 1, MSG_WAITALL ) < 1) return DR_EOF; len--; skip = 3; if (buf[0] & (1 << 2)) skip += 4; break; case 34: /* H263 */ if ( recv( stream->fd, buf, 1, MSG_WAITALL ) < 1) return DR_EOF; len--; skip = 3; if (buf[0] & (1 << 7)) skip += 4; if (buf[0] & (1 << 6)) skip += 4; break; case 33: /* MPEG Transport stream */ default: break; } if (skip) { if (recv( stream->fd, buf, skip, MSG_WAITALL ) < 1) return DR_EOF; len -= skip; } if (len > 0) { stream->cache = D_REALLOC( stream->cache, stream->cache_size + len ); if (!stream->cache) return D_OOM(); if (recv( stream->fd, stream->cache + stream->cache_size, len, MSG_WAITALL ) < 1) return DR_EOF; stream->cache_size += len; } return DR_OK; } static DirectResult rtsp_peek( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ) { DirectResult ret; unsigned int len; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (offset < 0) return DR_UNSUPPORTED; len = length + offset; while (len > stream->cache_size) { ret = rtp_read_packet( stream ); if (ret) { if (stream->cache_size < offset) return ret; break; } } len = MIN( stream->cache_size - offset, length ); direct_memcpy( buf, stream->cache + offset, len ); if (read_out) *read_out = len; return DR_OK; } static DirectResult rtsp_read( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ) { DirectResult ret; unsigned int size = 0; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); while (size < length || stream->cache_size < length) { if (stream->cache_size && length - size) { unsigned int len = MIN( stream->cache_size, length - size ); direct_memcpy( buf + size, stream->cache, len ); size += len; stream->cache_size -= len; direct_memcpy( stream->cache, stream->cache + len, stream->cache_size ); } if (size < length || stream->cache_size < length) { ret = rtp_read_packet( stream ); if (ret) { if (!size) return ret; break; } } } stream->offset += size; if (read_out) *read_out = size; return DR_OK; } static DirectResult rtsp_stream_open( DirectStream *stream, const char *filename ) { DirectResult ret; SDPMedia media; int len; char buf[1280]; int cseq = 0; char session[32] = { 0 }; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); stream->remote.port = RTSP_PORT; ret = net_stream_open( stream, filename, IPPROTO_TCP ); if (ret) return ret; snprintf( buf, sizeof(buf), "OPTIONS rtsp://%s:%d RTSP/1.0\r\n" "CSeq: %d\r\n" "User-Agent: DirectFB\r\n", stream->remote.host, stream->remote.port, ++cseq ); if (net_command( stream, buf, sizeof(buf) ) != 200) return DR_FAILURE; /* Discard remaining response. */ while (net_response( stream, buf, sizeof(buf) ) > 0); snprintf( buf, sizeof(buf), "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n" "CSeq: %d\r\n" "User-Agent: DirectFB\r\n" "Accept: application/sdp\r\n", stream->remote.host, stream->remote.port, stream->remote.path, ++cseq ); if (net_command( stream, buf, sizeof(buf) ) != 200) return DR_FAILURE; len = 0; while (net_response( stream, buf, sizeof(buf) ) > 0) { if (!strncasecmp( buf, "Content-Length:", 15 )) { char *tmp = trim( buf + 15 ); if (sscanf( tmp, "%d", &len ) != 1) sscanf( tmp, "bytes=%d", &len ); } } if (!len) { D_ERROR( "Direct/Stream: Couldn't get SDP length!\n" ); return DR_FAILURE; } memset( &media, 0, sizeof(SDPMedia) ); ret = sdp_parse( stream, len, &media ); if (ret) return ret; snprintf( buf, sizeof(buf), "SETUP rtsp://%s:%d%s/%s RTSP/1.0\r\n" "CSeq: %d\r\n" "User-Agent: DirectFB\r\n" "Transport: RTP/AVP/TCP;unicast\r\n", stream->remote.host, stream->remote.port, stream->remote.path, media.control, ++cseq ); if (net_command( stream, buf, sizeof(buf) ) != 200) return DR_FAILURE; while (net_response( stream, buf, sizeof(buf) ) > 0) { if (!*session && !strncmp( buf, "Session:", 8 )) snprintf( session, sizeof(session), "%s", trim( buf + 8 ) ); } len = snprintf( buf, sizeof(buf), "PLAY rtsp://%s:%d%s RTSP/1.0\r\n" "CSeq: %d\r\n" "User-Agent: DirectFB\r\n" "Range: npt=0-\r\n", stream->remote.host, stream->remote.port, stream->remote.path, ++cseq ); if (*session) { snprintf( buf + len, sizeof(buf) - len, "Session: %s\r\n", session ); } if (net_command( stream, buf, sizeof(buf) ) != 200) return DR_FAILURE; /* Discard remaining response. */ while (net_response( stream, buf, sizeof(buf) ) > 0); /* Payload type data. */ stream->remote.data = D_CALLOC( 1, sizeof(s8) ); if (!stream->remote.data) return D_OOM(); *(s8*) stream->remote.data = media.pt; stream->peek = rtsp_peek; stream->read = rtsp_read; return DR_OK; } /**********************************************************************************************************************/ #define HTTP_PORT 80 #define HTTP_MAX_REDIRECTS 15 static DirectResult http_stream_seek( DirectStream *stream, unsigned int offset ) { DirectResult ret; int status; int len; char buf[1280]; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); close( stream->remote.sd ); stream->remote.sd = -1; ret = net_connect( stream->remote.addr, SOCK_STREAM, IPPROTO_TCP, &stream->remote.sd ); if (ret) return ret; stream->fd = stream->remote.sd; len = snprintf( buf, sizeof(buf), "GET %s HTTP/1.0\r\n" "Host: %s:%d\r\n", stream->remote.path, stream->remote.host, stream->remote.port ); if (stream->remote.auth) { len += snprintf( buf + len, sizeof(buf) - len, "Authorization: Basic %s\r\n", stream->remote.auth ); } snprintf( buf + len, sizeof(buf) - len, "User-Agent: DirectFB\r\n" "Accept: */*\r\n" "Range: bytes=%u-\r\n" "Connection: Close\r\n", offset ); status = net_command( stream, buf, sizeof(buf) ); switch (status) { case 200 ... 299: stream->offset = offset; break; default: if (status) D_ERROR( "Direct/Stream: Server returned status %d\n", status ); return DR_FAILURE; } /* Discard remaining response. */ while (net_response( stream, buf, sizeof(buf) ) > 0); return DR_OK; } static DirectResult http_stream_open( DirectStream *stream, const char *filename ) { DirectResult ret; int status; int len; char buf[1280]; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); stream->remote.port = HTTP_PORT; ret = net_stream_open( stream, filename, IPPROTO_TCP ); if (ret) return ret; if (stream->remote.user) { char *tmp; if (stream->remote.pass) { tmp = alloca( strlen( stream->remote.user ) + strlen( stream->remote.pass ) + 2 ); len = sprintf( tmp, "%s:%s", stream->remote.user, stream->remote.pass ); } else { tmp = alloca( strlen( stream->remote.user ) + 2 ); len = sprintf( tmp, "%s:", stream->remote.user ); } stream->remote.auth = direct_base64_encode( tmp, len ); } len = snprintf( buf, sizeof(buf), "GET %s HTTP/1.0\r\n" "Host: %s:%d\r\n", stream->remote.path, stream->remote.host, stream->remote.port ); if (stream->remote.auth) { len += snprintf( buf + len, sizeof(buf) - len, "Authorization: Basic %s\r\n", stream->remote.auth ); } snprintf( buf + len, sizeof(buf) - len, "User-Agent: DirectFB\r\n" "Accept: */*\r\n" "Connection: Close\r\n" ); status = net_command( stream, buf, sizeof(buf) ); while (net_response( stream, buf, sizeof(buf) ) > 0) { if (!strncasecmp( buf, "Accept-Ranges:", 14 )) { if (strcmp( trim( buf + 14 ), "none" )) stream->seek = http_stream_seek; } else if (!strncasecmp( buf, "Content-Type:", 13 )) { char *mime = trim( buf + 13 ); char *tmp = strchr( mime, ';' ); if (tmp) *tmp = '\0'; if (stream->mime) D_FREE( stream->mime ); stream->mime = D_STRDUP( mime ); } else if (!strncasecmp( buf, "Content-Length:", 15 )) { char *tmp = trim( buf + 15 ); if (sscanf( tmp, ""_ZD"", &stream->length ) < 1) sscanf( tmp, "bytes="_ZD"", &stream->length ); } else if (!strncasecmp( buf, "Location:", 9 )) { direct_stream_close( stream ); stream->seek = NULL; if (++stream->remote.redirects > HTTP_MAX_REDIRECTS) { D_ERROR( "Direct/Stream: Reached maximum number of redirects (%d)\n", HTTP_MAX_REDIRECTS ); return DR_LIMITEXCEEDED; } filename = trim( buf + 9 ); if (!strncmp( filename, "ftp://", 6 )) return ftp_stream_open( stream, filename + 6 ); if (!strncmp( filename, "http://", 7 )) return http_stream_open( stream, filename + 7 ); if (!strncmp( filename, "rtsp://", 7 )) return rtsp_stream_open( stream, filename+7 ); return DR_UNSUPPORTED; } } switch (status) { case 200 ... 299: break; default: if (status) D_ERROR( "Direct/Stream: Server returned status %d\n", status ); return (status == 404) ? DR_FILENOTFOUND : DR_FAILURE; } return DR_OK; } #endif /* DIRECT_BUILD_NETWORK */ /**********************************************************************************************************************/ #if DIRECT_BUILD_PIPED_STREAM static DirectResult pipe_stream_wait( DirectStream *stream, unsigned int length, struct timeval *timeout ) { fd_set set; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (stream->cache_size >= length) return DR_OK; FD_ZERO( &set ); FD_SET( stream->fd, &set ); switch (select( stream->fd + 1, &set, NULL, NULL, timeout )) { case 0: if (!timeout && !stream->cache_size) return DR_EOF; return DR_TIMEOUT; case -1: return errno2result( errno ); } return DR_OK; } static DirectResult pipe_stream_peek( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ) { int len; unsigned int size = length; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (offset < 0) return DR_UNSUPPORTED; len = length + offset; if (len > stream->cache_size) { ssize_t sz; stream->cache = D_REALLOC( stream->cache, len ); if (!stream->cache) { stream->cache_size = 0; return D_OOM(); } sz = read( stream->fd, stream->cache + stream->cache_size, len - stream->cache_size ); if (sz < 0) { if (errno != EAGAIN || stream->cache_size == 0) return errno2result( errno ); sz = 0; } stream->cache_size += sz; if (stream->cache_size <= offset) return DR_BUFFEREMPTY; size = stream->cache_size - offset; } direct_memcpy( buf, stream->cache + offset, size ); if (read_out) *read_out = size; return DR_OK; } static DirectResult pipe_stream_read( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ) { unsigned int size = 0; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (stream->cache_size) { size = MIN( stream->cache_size, length ); direct_memcpy( buf, stream->cache, size ); length -= size; stream->cache_size -= size; if (stream->cache_size) { direct_memcpy( stream->cache, stream->cache + size, stream->cache_size ); } else { D_FREE( stream->cache ); stream->cache = NULL; } } if (length) { ssize_t sz; sz = read( stream->fd, buf + size, length - size ); switch (sz) { case 0: if (!size) return DR_EOF; break; case -1: if (!size) { return (errno == EAGAIN) ? DR_BUFFEREMPTY : errno2result( errno ); } break; default: size += sz; break; } } stream->offset += size; if (read_out) *read_out = size; return DR_OK; } #endif /* DIRECT_BUILD_PIPED_STREAM */ static DirectResult file_stream_wait( DirectStream *stream, unsigned int length, struct timeval *timeout ) { D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); if (stream->offset >= stream->length) return DR_EOF; return DR_OK; } static DirectResult file_stream_peek( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ) { DirectResult ret; size_t size; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); ret = direct_file_seek( &stream->file, offset ); if (ret) return ret; ret = direct_file_read( &stream->file, buf, length, &size ); if (ret) return ret; ret = direct_file_seek( &stream->file, -offset - (off_t) size ); if (ret) return ret; if (read_out) *read_out = size; return DR_OK; } static DirectResult file_stream_read( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ) { DirectResult ret; size_t size; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); ret = direct_file_read( &stream->file, buf, length, &size ); if (ret) return ret; stream->offset += size; if (read_out) *read_out = size; return DR_OK; } static DirectResult file_stream_seek( DirectStream *stream, unsigned int offset ) { DirectResult ret; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); ret = direct_file_seek_to( &stream->file, offset ); if (ret) return ret; stream->offset = offset; return DR_OK; } static DirectResult file_stream_open( DirectStream *stream, const char *filename ) { DirectResult ret; DirectFileInfo info; D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); ret = direct_file_open( &stream->file, filename, O_RDONLY | O_NONBLOCK, 0644 ); if (ret) return ret; #if DIRECT_BUILD_PIPED_STREAM stream->fd = stream->file.fd; if (lseek( stream->fd, 0, SEEK_CUR ) < 0 && errno == ESPIPE) { stream->length = -1; stream->wait = pipe_stream_wait; stream->peek = pipe_stream_peek; stream->read = pipe_stream_read; return DR_OK; } #endif /* DIRECT_BUILD_PIPED_STREAM */ ret = direct_file_get_info( &stream->file, &info ); if (ret) { direct_file_close( &stream->file ); return ret; } stream->length = info.size; stream->wait = file_stream_wait; stream->peek = file_stream_peek; stream->read = file_stream_read; stream->seek = file_stream_seek; return DR_OK; } /**********************************************************************************************************************/ DirectResult direct_stream_create( const char *filename, DirectStream **ret_stream ) { DirectResult ret; DirectStream *stream; D_ASSERT( filename != NULL ); D_ASSERT( ret_stream != NULL ); D_DEBUG_AT( Direct_Stream, "%s( '%s' )\n", __FUNCTION__, filename ); stream = D_CALLOC( 1, sizeof(DirectStream) ); if (!stream) return D_OOM(); D_MAGIC_SET( stream, DirectStream ); stream->ref = 1; stream->fd = -1; if (direct_getenv( "D_STREAM_BYPASS" )) { ret = DR_OK; } else if (!strncmp( filename, "file://", 7 )) { ret = file_stream_open( stream, filename + 7 ); } #if DIRECT_BUILD_NETWORK else if (!strncmp( filename, "ftp://", 6 )) { ret = ftp_stream_open( stream, filename + 6 ); } else if (!strncmp( filename, "http://", 7 )) { ret = http_stream_open( stream, filename + 7 ); } else if (!strncmp( filename, "rtsp://", 7 )) { ret = rtsp_stream_open( stream, filename + 7 ); } else if (!strncmp( filename, "tcp://", 6 )) { ret = net_stream_open( stream, filename + 6, IPPROTO_TCP ); } else if (!strncmp( filename, "udp://", 6 )) { ret = net_stream_open( stream, filename + 6, IPPROTO_UDP ); } #endif /* DIRECT_BUILD_NETWORK */ else { ret = file_stream_open( stream, filename ); } if (ret) { direct_stream_close( stream ); D_FREE( stream ); return ret; } *ret_stream = stream; return DR_OK; } DirectStream * direct_stream_dup( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); stream->ref++; return stream; } int direct_stream_fileno( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); return stream->fd; } bool direct_stream_seekable( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); return stream->seek ? true : false; } bool direct_stream_remote( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); #if DIRECT_BUILD_NETWORK if (stream->remote.host) return true; #endif /* DIRECT_BUILD_NETWORK */ return false; } const char * direct_stream_mime( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); return stream->mime; } unsigned int direct_stream_offset( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); return stream->offset; } unsigned int direct_stream_length( DirectStream *stream ) { D_MAGIC_ASSERT( stream, DirectStream ); return (unsigned int) ((stream->length >= 0) ? stream->length : stream->offset); } DirectResult direct_stream_wait( DirectStream *stream, unsigned int length, struct timeval *timeout ) { D_MAGIC_ASSERT( stream, DirectStream ); if (length && stream->wait) return stream->wait( stream, length, timeout ); return DR_OK; } DirectResult direct_stream_peek( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ) { D_MAGIC_ASSERT( stream, DirectStream ); D_ASSERT( length != 0 ); D_ASSERT( buf != NULL ); if (stream->length >= 0 && (stream->offset + offset) >= stream->length) return DR_EOF; if (stream->peek) return stream->peek( stream, length, offset, buf, read_out ); return DR_UNSUPPORTED; } DirectResult direct_stream_read( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ) { D_MAGIC_ASSERT( stream, DirectStream ); D_ASSERT( length != 0 ); D_ASSERT( buf != NULL ); if (stream->length >= 0 && stream->offset >= stream->length) return DR_EOF; if (stream->read) return stream->read( stream, length, buf, read_out ); return DR_UNSUPPORTED; } DirectResult direct_stream_seek( DirectStream *stream, unsigned int offset ) { D_MAGIC_ASSERT( stream, DirectStream ); if (stream->offset == offset) return DR_OK; if (stream->length >= 0 && offset > stream->length) offset = (unsigned int) stream->length; if (stream->seek) return stream->seek( stream, offset ); return DR_UNSUPPORTED; } void direct_stream_destroy( DirectStream *stream ) { D_DEBUG_AT( Direct_Stream, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( stream, DirectStream ); if (--stream->ref == 0) { direct_stream_close( stream ); D_MAGIC_CLEAR( stream ); D_FREE( stream ); } } ================================================ FILE: lib/direct/stream.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__STREAM_H__ #define __DIRECT__STREAM_H__ #include /**********************************************************************************************************************/ /* * Create a stream wrapper. * * 'filename' can be a plain file name or one of the following: * file:// * http://[:]/ * ftp://[:]/ * tcp://: * udp://: */ DirectResult DIRECT_API direct_stream_create ( const char *filename, DirectStream **ret_stream ); /* * Duplicate the stream. */ DirectStream DIRECT_API *direct_stream_dup ( DirectStream *stream ); /* * Return the file descriptor associated to the stream. */ int DIRECT_API direct_stream_filenoi ( DirectStream *stream ); /* * True if stream is seekable. */ bool DIRECT_API direct_stream_seekable( DirectStream *stream ); /* * True if stream originates from a remote host. */ bool DIRECT_API direct_stream_remote ( DirectStream *stream ); /* * Get the mime description of the stream. */ const char DIRECT_API *direct_stream_mime ( DirectStream *stream ); /* * Get stream position. */ unsigned int DIRECT_API direct_stream_offset ( DirectStream *stream ); /* * Get stream length. */ unsigned int DIRECT_API direct_stream_length ( DirectStream *stream ); /* * Wait for data to be available. * If 'timeout' is NULL, the function blocks indefinitely. * Set the 'timeout' value to 0 to make the function return immediatly. */ DirectResult DIRECT_API direct_stream_wait ( DirectStream *stream, unsigned int length, struct timeval *timeout ); /* * Peek 'length' bytes of data at offset 'offset' from the stream. */ DirectResult DIRECT_API direct_stream_peek ( DirectStream *stream, unsigned int length, int offset, void *buf, unsigned int *read_out ); /* * Fetch 'length' bytes of data from the stream. */ DirectResult DIRECT_API direct_stream_read ( DirectStream *stream, unsigned int length, void *buf, unsigned int *read_out ); /* * Seek to the specified absolute offset within the stream. */ DirectResult DIRECT_API direct_stream_seek ( DirectStream *stream, unsigned int offset ); /* * Destroy the stream wrapper. */ void DIRECT_API direct_stream_destroy ( DirectStream *stream ); #endif ================================================ FILE: lib/direct/system.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Direct_Futex, "Direct/Futex", "Direct Futex" ); /**********************************************************************************************************************/ DirectResult direct_futex_wait( int *uaddr, int val ) { DirectResult ret; D_ASSERT( uaddr != NULL ); D_DEBUG_AT( Direct_Futex, "%s( %p, %d ) <- %d\n", __FUNCTION__, uaddr, val, *uaddr ); if (*uaddr != val) { D_DEBUG_AT( Direct_Futex, " -> value changed!\n" ); return DR_OK; } while ((ret = direct_futex( uaddr, FUTEX_WAIT, val, NULL, NULL, 0 ))) { switch (ret) { case DR_SIGNALLED: continue; case DR_BUSY: return DR_OK; default: D_DERROR( ret, "Direct/Futex: FUTEX_WAIT( %p, %d ) failed!\n", uaddr, val ); return ret; } } return DR_OK; } DirectResult direct_futex_wait_timed( int *uaddr, int val, int ms ) { DirectResult ret; struct timespec timeout; D_ASSERT( uaddr != NULL ); D_DEBUG_AT( Direct_Futex, "%s( %p, %d, %d ) <- %d\n", __FUNCTION__, uaddr, val, ms, *uaddr ); if (*uaddr != val) { D_DEBUG_AT( Direct_Futex, " -> value changed!\n" ); return DR_OK; } timeout.tv_sec = ms / 1000; timeout.tv_nsec = (ms % 1000) * 1000000; while ((ret = direct_futex( uaddr, FUTEX_WAIT, val, &timeout, NULL, 0 ))) { switch (ret) { case DR_SIGNALLED: continue; case DR_BUSY: return DR_OK; default: D_DERROR( ret, "Direct/Futex: FUTEX_WAIT( %p, %d ) failed!\n", uaddr, val ); case DR_TIMEOUT: return ret; } } return DR_OK; } DirectResult direct_futex_wake( int *uaddr, int num ) { DirectResult ret; D_ASSERT( uaddr != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Direct_Futex, "%s( %p, %d ) <- %d\n", __FUNCTION__, uaddr, num, *uaddr ); while ((ret = direct_futex( uaddr, FUTEX_WAKE, num, NULL, NULL, 0 ))) { switch (ret) { case DR_BUSY: continue; default: D_DERROR( ret, "Direct/Futex: FUTEX_WAKE( %p, %d ) failed!\n", uaddr, num ); return ret; } } return DR_OK; } unsigned int __Direct_Futex_Wait_Count = 0; unsigned int __Direct_Futex_Wake_Count = 0; ================================================ FILE: lib/direct/system.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__SYSTEM_H__ #define __DIRECT__SYSTEM_H__ #include /**********************************************************************************************************************/ DirectResult DIRECT_API direct_futex_wait ( int *uaddr, int val ); DirectResult DIRECT_API direct_futex_wait_timed( int *uaddr, int val, int ms ); DirectResult DIRECT_API direct_futex_wake ( int *uaddr, int num ); #endif ================================================ FILE: lib/direct/thread.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #if D_DEBUG_ENABLED #include #endif #include D_DEBUG_DOMAIN( Direct_Thread, "Direct/Thread", "Direct Thread Management" ); D_DEBUG_DOMAIN( Direct_ThreadInit, "Direct/Thread/Init", "Direct Thread Init" ); /**********************************************************************************************************************/ struct __D_DirectThreadInitHandler { DirectLink link; int magic; DirectThreadInitFunc func; void *arg; }; /**********************************************************************************************************************/ static DirectMutex handler_lock; static DirectLink *handlers; /**********************************************************************************************************************/ void __D_thread_init() { direct_mutex_init( &handler_lock ); } void __D_thread_deinit() { direct_mutex_deinit( &handler_lock ); } /**********************************************************************************************************************/ DirectThreadInitHandler * direct_thread_add_init_handler( DirectThreadInitFunc func, void *arg ) { DirectThreadInitHandler *handler; D_DEBUG_AT( Direct_Thread, "Adding thread init handler %p...\n", func ); handler = D_CALLOC( 1, sizeof(DirectThreadInitHandler) ); if (!handler) { return NULL; } handler->func = func; handler->arg = arg; D_MAGIC_SET( handler, DirectThreadInitHandler ); direct_mutex_lock( &handler_lock ); direct_list_append( &handlers, &handler->link ); direct_mutex_unlock( &handler_lock ); return handler; } void direct_thread_remove_init_handler( DirectThreadInitHandler *handler ) { D_MAGIC_ASSERT( handler, DirectThreadInitHandler ); D_DEBUG_AT( Direct_Thread, "Removing thread init handler %p...\n", handler->func ); direct_mutex_lock( &handler_lock ); direct_list_remove( &handlers, &handler->link ); direct_mutex_unlock( &handler_lock ); D_MAGIC_CLEAR( handler ); D_FREE( handler ); } DirectThread * direct_thread_create( DirectThreadType thread_type, DirectThreadMainFunc thread_main, void *arg, const char *name ) { DirectThread *thread; D_ASSERT( thread_main != NULL ); D_ASSERT( name != NULL ); D_DEBUG_AT( Direct_ThreadInit, "%s( %s, %p( %p ), '%s' )\n", __FUNCTION__, direct_thread_type_name( thread_type ), thread_main, arg, name ); /* Allocate thread structure. */ thread = D_CALLOC( 1, sizeof(DirectThread) ); if (!thread) { D_OOM(); return NULL; } /* Write thread information to structure. */ thread->name = D_STRDUP( name ); thread->type = thread_type; thread->main = thread_main; thread->arg = arg; /* Initialize to -1 for synchronization. */ thread->tid = (pid_t) -1; /* Initialize mutex and condition. */ direct_recursive_mutex_init( &thread->lock ); direct_waitqueue_init( &thread->cond ); D_MAGIC_SET( thread, DirectThread ); /* Lock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> locking...\n" ); direct_mutex_lock( &thread->lock ); /* Create and run the thread. */ D_DEBUG_AT( Direct_ThreadInit, " -> creating handle...\n" ); direct_thread_init( thread ); /* Wait for completion of the thread's initialization. */ while (!thread->init) { D_DEBUG_AT( Direct_ThreadInit, " -> waiting...\n" ); direct_waitqueue_wait( &thread->cond, &thread->lock ); } D_DEBUG_AT( Direct_ThreadInit, " -> started '%s' (%d) [%s - %s/%d] <"_ZU">...\n", thread->name, thread->tid, direct_thread_type_name( thread->type ), direct_thread_policy_name( thread->policy ), thread->priority, thread->stack_size ); D_DEBUG_AT( Direct_ThreadInit, " -> ...thread is running\n" ); /* Unlock the thread mutex. */ D_DEBUG_AT( Direct_ThreadInit, " -> unlocking...\n" ); direct_mutex_unlock( &thread->lock ); D_DEBUG_AT( Direct_ThreadInit, " -> returning %p\n", thread ); return thread; } DirectResult direct_thread_wait( DirectThread *thread, int timeout_ms ) { DirectResult ret; unsigned int old_counter = thread->counter; D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->tid != -1 ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d, %dms )\n", __FUNCTION__, thread->main, thread->name, thread->tid, timeout_ms ); while (old_counter == thread->counter && !thread->terminated) { if (timeout_ms <= 0) ret = direct_waitqueue_wait( &thread->cond, &thread->lock ); else ret = direct_waitqueue_wait_timeout( &thread->cond, &thread->lock, timeout_ms * 1000 ); if (ret) return ret; } if (thread->terminated) return DR_DEAD; return DR_OK; } DirectResult direct_thread_notify( DirectThread *thread ) { DirectResult ret; D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->tid != -1 ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); ret = direct_mutex_lock( &thread->lock ); if (ret) return ret; thread->counter++; direct_mutex_unlock( &thread->lock ); return direct_waitqueue_broadcast( &thread->cond ); } DirectResult direct_thread_lock( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->tid != -1 ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); return direct_mutex_lock( &thread->lock ); } DirectResult direct_thread_unlock( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->tid != -1 ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); return direct_mutex_unlock( &thread->lock ); } DirectResult direct_thread_terminate( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSERT( thread->tid != -1 ); D_ASSUME( thread->tid != direct_gettid() ); D_ASSUME( !thread->canceled ); D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); thread->terminated = true; return direct_thread_notify( thread ); } void direct_thread_destroy( DirectThread *thread ) { D_MAGIC_ASSERT( thread, DirectThread ); D_ASSUME( thread->tid != direct_gettid() ); D_ASSUME( !thread->detached ); D_DEBUG_AT( Direct_ThreadInit, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); if (thread->detached) { D_DEBUG_AT( Direct_ThreadInit, " -> detached\n" ); return; } direct_thread_deinit( thread ); D_MAGIC_CLEAR( thread ); D_FREE( thread->name ); D_FREE( thread ); } pid_t direct_thread_get_tid( const DirectThread *thread ) { return thread->tid; } bool direct_thread_is_canceled( const DirectThread *thread ) { return thread->canceled; } bool direct_thread_is_joined( const DirectThread *thread ) { return thread->joined; } /**********************************************************************************************************************/ void _direct_thread_call_init_handlers( DirectThread *thread ) { DirectThreadInitHandler *handler; direct_mutex_lock( &handler_lock ); direct_list_foreach (handler, handlers) { handler->func( thread, handler->arg ); } direct_mutex_unlock( &handler_lock ); } ================================================ FILE: lib/direct/thread.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__THREAD_H__ #define __DIRECT__THREAD_H__ #include /**********************************************************************************************************************/ typedef void (*DirectThreadInitFunc)( DirectThread *thread, void *arg ); /**********************************************************************************************************************/ /* * Add a handler being called at the beginning of new threads. */ DirectThreadInitHandler DIRECT_API *direct_thread_add_init_handler ( DirectThreadInitFunc func, void *arg ); /* * Remove the specified handler. */ void DIRECT_API direct_thread_remove_init_handler( DirectThreadInitHandler *handler ); /* * Create a new thread and start it. The thread type is relevant for the scheduling priority. */ DirectThread DIRECT_API *direct_thread_create ( DirectThreadType thread_type, DirectThreadMainFunc thread_main, void *arg, const char *name ); /* * Wait on the thread object to be notified via direct_thread_notify(). */ DirectResult DIRECT_API direct_thread_wait ( DirectThread *thread, int timeout_ms ); /* * Notify the thread object waking up callers of direct_thread_wait(). */ DirectResult DIRECT_API direct_thread_notify ( DirectThread *thread ); /* * The thread acquires the lock. */ DirectResult DIRECT_API direct_thread_lock ( DirectThread *thread ); /* * The thread releases the lock. */ DirectResult DIRECT_API direct_thread_unlock ( DirectThread *thread ); /* * Kindly ask the thread to terminate (for joining without thread cancellation). */ DirectResult DIRECT_API direct_thread_terminate ( DirectThread *thread ); /* * Free resources allocated by direct_thread_create. If the thread is still running it will be killed. */ void DIRECT_API direct_thread_destroy ( DirectThread *thread ); /* * Return the thread's ID. */ pid_t DIRECT_API direct_thread_get_tid ( const DirectThread *thread ); /* * True if the thread is canceled. */ bool DIRECT_API direct_thread_is_canceled ( const DirectThread *thread ); /* * True if the thread is joined. */ bool DIRECT_API direct_thread_is_joined ( const DirectThread *thread ); /**********************************************************************************************************************/ void __D_thread_init ( void ); void __D_thread_deinit( void ); #endif ================================================ FILE: lib/direct/trace.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if DIRECT_BUILD_TRACE #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Direct_Trace, "Direct/Trace", "Direct Trace support" ); #endif /* DIRECT_BUILD_TRACE */ /**********************************************************************************************************************/ #if DIRECT_BUILD_TRACE #define MAX_LEVEL 200 typedef enum { TF_NONE = 0x00000000, TF_DEBUG = 0x00000001 } TraceFlags; typedef struct { void *addr; TraceFlags flags; } Trace; struct __D_DirectTraceBuffer { DirectLink link; int magic; pid_t tid; char *name; DirectThread *thread; int level; bool in_trace; Trace trace[MAX_LEVEL]; }; /**********************************************************************************************************************/ static DirectLink *buffers; static DirectMutex buffers_lock = DIRECT_MUTEX_INITIALIZER(); __dfb_no_instrument_function__ static __inline__ DirectTraceBuffer * get_trace_buffer() { DirectTraceBuffer *buffer; DirectThread *self = direct_thread_self(); buffer = self->trace_buffer; if (!buffer) { buffer = direct_calloc( 1, sizeof(DirectTraceBuffer) ); if (!buffer) return NULL; buffer->tid = direct_gettid(); buffer->thread = direct_thread_self(); D_MAGIC_SET( buffer, DirectTraceBuffer ); self->trace_buffer = buffer; direct_mutex_lock( &buffers_lock ); direct_list_append( &buffers, &buffer->link ); direct_mutex_unlock( &buffers_lock ); } return buffer; } #define NAME_LEN 92 typedef struct { long offset; char name[NAME_LEN]; } Symbol; typedef struct { DirectLink link; char *filename; Symbol *symbols; int capacity; int num_symbols; } SymbolTable; static DirectLink *tables = NULL; static DirectMutex tables_lock = DIRECT_MUTEX_INITIALIZER(); __dfb_no_instrument_function__ static void add_symbol( SymbolTable *table, long offset, const char *name ) { Symbol *symbol; if (table->num_symbols == table->capacity) { Symbol *symbols; int capacity = table->capacity * 2; if (!capacity) capacity = 256; symbols = direct_malloc( capacity * sizeof(Symbol) ); if (!symbols) { D_WARN( "out of memory" ); return; } direct_memcpy( symbols, table->symbols, table->num_symbols * sizeof(Symbol) ); direct_free( table->symbols ); table->symbols = symbols; table->capacity = capacity; } symbol = &table->symbols[table->num_symbols++]; symbol->offset = offset; direct_snputs( symbol->name, name, NAME_LEN ); } __dfb_no_instrument_function__ static SymbolTable * load_symbols( const char *filename ) { DirectResult ret; SymbolTable *table; DirectFile f; bool is_pipe = false; char file[1024]; char line[1024]; int command_len; const char *full_path = filename; char *tmp; D_DEBUG_AT( Direct_Trace, "%s( %s )\n", __FUNCTION__, filename ); if (filename) { ret = direct_access( filename, R_OK ); if (ret && ret == DR_FILENOTFOUND) { ssize_t len = 0; ret = direct_readlink( "/proc/self/exe", file, sizeof(file) - 1, &len ); if (ret) { D_DERROR( ret, "Direct/Trace: direct_readlink( '/proc/self/exe' ) failed!\n" ); return NULL; } file[len] = 0; tmp = strrchr( file, '/' ); if (!tmp) return NULL; if (strcmp( filename, tmp + 1 )) return NULL; full_path = file; } } else { ssize_t len = 0; ret = direct_readlink( "/proc/self/exe", file, sizeof(file) - 1, &len ); if (ret) { D_DERROR( ret, "Direct/Trace: direct_readlink( '/proc/self/exe' ) failed!\n" ); return NULL; } file[len] = 0; full_path = file; } command_len = strlen( full_path ) + 32; char command[command_len+1]; /* First check if there's a "nm-n" file. */ tmp = strrchr( full_path, '/' ); if (!tmp) return NULL; *tmp = 0; snprintf( command, command_len, "%s/nm-n.%s", full_path, tmp + 1 ); *tmp = '/'; ret = direct_access( command, R_OK ); if (ret == DR_OK) { ret = direct_file_open( &f, command, O_RDONLY, 0 ); if (ret) D_DERROR( ret, "Direct/Trace: direct_file_open( '%s' ) failed!\n", command ); } else { snprintf( command, command_len, "%s.nm", full_path ); ret = direct_access( command, R_OK ); if (ret == DR_OK) { ret = direct_file_open( &f, command, O_RDONLY, 0 ); if (ret) D_DERROR( ret, "Direct/Trace: direct_file_open( '%s' ) failed!\n", command ); } } /* Fallback to live mode. */ if (ret) { snprintf( command, command_len, "nm -nC %s", full_path ); if (!direct_config->nm_for_trace) { D_DEBUG_AT( Direct_Trace, " -> not running '%s', enable via 'nm-for-trace' option\n", command ); return NULL; } D_DEBUG_AT( Direct_Trace, " -> running '%s'...\n", command ); ret = direct_popen( &f, command, O_RDONLY ); if (ret) { D_DERROR( ret, "Direct/Trace: direct_popen( '%s' ) failed!\n", command ); return NULL; } is_pipe = true; } table = direct_calloc( 1, sizeof(SymbolTable) ); if (!table) { D_OOM(); goto out; } if (filename) table->filename = direct_strdup( filename ); while (direct_file_get_string( &f, line, sizeof(line) ) == DR_OK) { int n; int digits = sizeof(long) * 2; long offset = 0; int length = strlen( line ); if (line[0] == ' ' || length < (digits + 5) || line[length-1] != '\n') continue; if (line[digits+1] != 't' && line[digits+1] != 'T' && line[digits+1] != 'W') continue; if (line[digits] != ' ' || line[digits+2] != ' ' || line[digits+3] == '.') continue; for (n = 0; n < digits; n++) { char c = line[n]; offset <<= 4; if (c >= '0' && c <= '9') offset |= c - '0'; else offset |= c - 'a' + 10; } line[length-1] = 0; add_symbol( table, offset, line + digits + 3 ); } out: if (is_pipe) direct_pclose( &f ); else direct_file_close( &f ); return table; } __dfb_no_instrument_function__ static int compare_symbols( const void *x, const void *y ) { return *((const long*) x) - *((const long*) y); } __dfb_no_instrument_function__ static SymbolTable * find_table( const char *filename ) { SymbolTable *table; if (filename) { direct_list_foreach (table, tables) { if (table->filename && !strcmp( filename, table->filename )) return table; } } else { direct_list_foreach (table, tables) { if (!table->filename) return table; } } return NULL; } /**********************************************************************************************************************/ __dfb_no_instrument_function__ const char * direct_trace_lookup_symbol( const char *filename, long offset ) { Symbol *symbol; SymbolTable *table; direct_mutex_lock( &tables_lock ); table = find_table( filename ); if (!table) { table = load_symbols( filename ); if (!table) { direct_mutex_unlock( &tables_lock ); return false; } direct_list_prepend( &tables, &table->link ); } direct_mutex_unlock( &tables_lock ); symbol = direct_bsearch( &offset, table->symbols, table->num_symbols, sizeof(Symbol), compare_symbols ); return symbol ? symbol->name : NULL; } __dfb_no_instrument_function__ const char * direct_trace_lookup_file( void *address, void **ret_base ) { Dl_info info; if (dladdr( address, &info )) { if (ret_base) *ret_base = info.dli_fbase; return info.dli_fname; } else { if (ret_base) *ret_base = NULL; } return NULL; } __dfb_no_instrument_function__ void direct_trace_print_stack( DirectTraceBuffer *buffer ) { Dl_info info; int i; int level; if (!direct_config->trace) return; if (!buffer) { buffer = get_trace_buffer(); if (!buffer) return; } if (buffer->in_trace) return; buffer->in_trace = true; level = buffer->level; if (level > MAX_LEVEL) { D_WARN( "only showing %d of %d items", MAX_LEVEL, level ); level = MAX_LEVEL; } else if (level == 0) { buffer->in_trace = false; return; } direct_log_printf( NULL, "(-) [%5d: -STACK- '%s']\n", buffer->tid, buffer->thread ? buffer->thread->name : buffer->name ); for (i = level - 1; i >= 0; i--) { void *fn = buffer->trace[i].addr; if (dladdr( fn, &info )) { if (info.dli_fname) { const char *symbol = direct_trace_lookup_symbol( info.dli_fname, (long) (fn - info.dli_fbase) ); if (!symbol) { symbol = direct_trace_lookup_symbol( info.dli_fname, (long) fn ); if (!symbol) { if (info.dli_sname) symbol = info.dli_sname; else symbol = "??"; } } direct_log_printf( NULL, " #%-2d 0x%08lx in %s () from %s [%p]\n", level - i - 1, (unsigned long) fn, symbol, info.dli_fname, info.dli_fbase ); } else if (info.dli_sname) { direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", level - i - 1, (unsigned long) fn, info.dli_sname ); } else direct_log_printf( NULL, " #%-2d 0x%08lx in ?? ()\n", level - i - 1, (unsigned long) fn ); } else { const char *symbol = direct_trace_lookup_symbol( NULL, (long) fn ); direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", level - i - 1, (unsigned long) fn, symbol ?: "??" ); } } direct_log_printf( NULL, "\n" ); buffer->in_trace = false; } __dfb_no_instrument_function__ void direct_trace_print_stacks() { DirectTraceBuffer *b; DirectTraceBuffer *buffer = get_trace_buffer(); direct_mutex_lock( &buffers_lock ); if (buffer && buffer->level) direct_trace_print_stack( buffer ); direct_list_foreach (b, buffers) { if (b != buffer && b->level) direct_trace_print_stack( b ); } direct_mutex_unlock( &buffers_lock ); } __dfb_no_instrument_function__ int direct_trace_debug_indent() { int in = 0; DirectTraceBuffer *buffer = get_trace_buffer(); if (buffer) { int level = buffer->level - 1; if (level < 0) return 0; buffer->trace[level--].flags |= TF_DEBUG; for (in = 0; level >= 0; level--) { if (buffer->trace[level].flags & TF_DEBUG) in++; } } return in; } __dfb_no_instrument_function__ void * direct_trace_get_caller() { void *caller = NULL; DirectTraceBuffer *buffer = get_trace_buffer(); if (buffer) { int level = buffer->level - 2; if (level >= 0) caller = buffer->trace[level].addr; } return caller; } __dfb_no_instrument_function__ DirectTraceBuffer * direct_trace_copy_buffer( DirectTraceBuffer *buffer ) { int level; DirectTraceBuffer *copy; if (!buffer) { buffer = get_trace_buffer(); if (!buffer) return NULL; } level = buffer->level; if (level > MAX_LEVEL) { D_WARN( "only copying %d of %d items", MAX_LEVEL, level ); level = MAX_LEVEL; } copy = direct_calloc( 1, sizeof(DirectTraceBuffer) - sizeof(Trace) * (MAX_LEVEL - level) ); if (!copy) return NULL; if (buffer->thread && buffer->thread->name) copy->name = direct_strdup( buffer->thread->name ); copy->tid = buffer->tid; copy->level = buffer->level; direct_memcpy( ©->trace[0], &buffer->trace[0], level * sizeof(Trace) ); D_MAGIC_SET( copy, DirectTraceBuffer ); return copy; } __dfb_no_instrument_function__ void direct_trace_free_buffer( DirectTraceBuffer *buffer ) { D_MAGIC_ASSERT( buffer, DirectTraceBuffer ); if (buffer->thread) { direct_mutex_lock( &buffers_lock ); direct_list_remove( &buffers, &buffer->link ); direct_mutex_unlock( &buffers_lock ); buffer->thread = NULL; } if (buffer->name) direct_free( buffer->name ); D_MAGIC_CLEAR( buffer ); direct_free( buffer ); } /**********************************************************************************************************************/ __dfb_no_instrument_function__ void __cyg_profile_func_enter( void *this_fn, void *call_site ) { if (direct_config->trace) { DirectTraceBuffer *buffer = get_trace_buffer(); if (buffer) { int level = buffer->level++; Trace *trace = &buffer->trace[level]; if (level < MAX_LEVEL) { trace->addr = this_fn; trace->flags = TF_NONE; } } } } __dfb_no_instrument_function__ void __cyg_profile_func_exit( void *this_fn, void *call_site ) { if (direct_config->trace) { DirectTraceBuffer *buffer = get_trace_buffer(); if (buffer) { if (buffer->level > 0) buffer->level--; } } } #else /* DIRECT_BUILD_TRACE */ const char * direct_trace_lookup_symbol( const char *filename, long offset ) { return NULL; } const char * direct_trace_lookup_file( void *address, void **ret_base ) { if (ret_base) *ret_base = NULL; return NULL; } void direct_trace_print_stack( DirectTraceBuffer *buffer ) { } void direct_trace_print_stacks() { } int direct_trace_debug_indent() { return 0; } void * direct_trace_get_caller() { return NULL; } DirectTraceBuffer * direct_trace_copy_buffer( DirectTraceBuffer *buffer ) { return NULL; } void direct_trace_free_buffer( DirectTraceBuffer *buffer ) { } #endif /* DIRECT_BUILD_TRACE */ ================================================ FILE: lib/direct/trace.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__TRACE_H__ #define __DIRECT__TRACE_H__ #include /**********************************************************************************************************************/ /* * Look up a symbol by filename and offset. * * Returns symbol name on success or NULL. */ const char DIRECT_API *direct_trace_lookup_symbol( const char *filename, long offset ); /* * Returns filename on success or NULL. * * Stores load address of object in 'ret_base' on success. */ const char DIRECT_API *direct_trace_lookup_file ( void *address, void **ret_base ); /* * Print stack in 'buffer' or current if NULL. */ void DIRECT_API direct_trace_print_stack ( DirectTraceBuffer *buffer ); /* * Print stack of each known thread. */ void DIRECT_API direct_trace_print_stacks ( void ); /* * Returns indent level for debug output. */ int DIRECT_API direct_trace_debug_indent ( void ); /* * Retrieve pointer to calling function if present, otherwise NULL. */ void DIRECT_API *direct_trace_get_caller ( void ); /* * Create a copy of a stack in 'buffer' or of current if NULL. */ DirectTraceBuffer DIRECT_API *direct_trace_copy_buffer ( DirectTraceBuffer *buffer ); /* * Free a (copied) stack buffer. */ void DIRECT_API direct_trace_free_buffer ( DirectTraceBuffer *buffer ); /**********************************************************************************************************************/ /* * Convenience function combining direct_trace_lookup_file() and direct_trace_lookup_symbol(). */ static __inline__ const char * direct_trace_lookup_symbol_at( void *address ) { void *base; const char *filename; filename = direct_trace_lookup_file( address, &base ); return direct_trace_lookup_symbol( filename, (unsigned long) address - (unsigned long) base ); } #endif ================================================ FILE: lib/direct/types.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__TYPES_H__ #define __DIRECT__TYPES_H__ #ifndef __DIRECT__OS__TYPES_H__ #include #endif /**********************************************************************************************************************/ #define DIRECT_API #define D_RESULT_TYPE_CHAR_MASK ((unsigned int) 0x2F) #define D_RESULT_TYPE_CHAR_MIN ((unsigned int) 0x30) #define D_RESULT_TYPE_CHAR_MAX (D_RESULT_TYPE_CHAR_MIN + D_RESULT_TYPE_CHAR_MASK) #define D_RESULT_TYPE_CHAR_MUL_0 ((unsigned int) 1) #define D_RESULT_TYPE_CHAR_MUL_1 ((unsigned int) (D_RESULT_TYPE_CHAR_MASK + 1)) #define D_RESULT_TYPE_CHAR_MUL_2 (D_RESULT_TYPE_CHAR_MUL_1 * D_RESULT_TYPE_CHAR_MUL_1) #define D_RESULT_TYPE_CHAR_MUL_3 (D_RESULT_TYPE_CHAR_MUL_1 * D_RESULT_TYPE_CHAR_MUL_2) #define D_RESULT_TYPE_CHAR(C) (((unsigned int) (C) - D_RESULT_TYPE_CHAR_MIN) & D_RESULT_TYPE_CHAR_MASK) #define D_RESULT_TYPE_SPACE ((unsigned int) (0xFFFFFFFF / (D_RESULT_TYPE_CHAR_MASK * D_RESULT_TYPE_CHAR_MUL_3 + \ D_RESULT_TYPE_CHAR_MASK * D_RESULT_TYPE_CHAR_MUL_2 + \ D_RESULT_TYPE_CHAR_MASK * D_RESULT_TYPE_CHAR_MUL_1 + \ D_RESULT_TYPE_CHAR_MASK * D_RESULT_TYPE_CHAR_MUL_0) \ - 1)) /**********************************************************************************************************************/ /* * Generate result code base for API * * Allowed are ASCII values between (inclusive) D_RESULT_TYPE_CHAR_MIN (0x30) and D_RESULT_TYPE_CHAR_MAX (0x5F) * * 0 1 2 3 4 5 6 7 8 9 : ; < = > ? * * @ A B C D E F G H I J K L M N O * * P Q R S T U V W X Y Z [ \ ] ^ _ * */ #define D_RESULT_TYPE_CODE_BASE(a,b,c,d) ((D_RESULT_TYPE_CHAR( a ) * (D_RESULT_TYPE_CHAR_MUL_3) + \ D_RESULT_TYPE_CHAR( b ) * (D_RESULT_TYPE_CHAR_MUL_2) + \ D_RESULT_TYPE_CHAR( c ) * (D_RESULT_TYPE_CHAR_MUL_1) + \ D_RESULT_TYPE_CHAR( d ) * (D_RESULT_TYPE_CHAR_MUL_0)) * D_RESULT_TYPE_SPACE) #define D_RESULT_TYPE(code) ((code) - ((code) % D_RESULT_TYPE_SPACE)) #define D_RESULT_INDEX(code) ((code) % D_RESULT_TYPE_SPACE) /**********************************************************************************************************************/ typedef enum { DR_OK, /* No error occurred */ DR__RESULT_BASE = D_RESULT_TYPE_CODE_BASE( 'D','R','_', '1' ), DR_FAILURE, /* A general or unknown error occurred */ DR_INIT, /* A general initialization error occurred */ DR_BUG, /* Internal bug or inconsistency has been detected */ DR_DEAD, /* Interface has a zero reference counter (available in debug mode) */ DR_UNSUPPORTED, /* The requested operation or an argument is (currently) not supported */ DR_UNIMPLEMENTED, /* The requested operation is not implemented, yet */ DR_ACCESSDENIED, /* Access to the resource is denied */ DR_INVAREA, /* An invalid area has been specified or detected */ DR_INVARG, /* An invalid argument has been specified */ DR_NOLOCALMEMORY, /* There's not enough local system memory */ DR_NOSHAREDMEMORY, /* There's not enough shared system memory */ DR_LOCKED, /* The resource is (already) locked */ DR_BUFFEREMPTY, /* The buffer is empty */ DR_FILENOTFOUND, /* The specified file has not been found */ DR_IO, /* A general I/O error occurred */ DR_BUSY, /* The resource or device is busy */ DR_NOIMPL, /* No implementation for this interface or content type has been found */ DR_TIMEOUT, /* The operation timed out */ DR_THIZNULL, /* 'thiz' pointer is NULL */ DR_IDNOTFOUND, /* No resource has been found by the specified id */ DR_DESTROYED, /* The requested object has been destroyed */ DR_FUSION, /* Internal fusion error detected, most likely related to IPC resources */ DR_BUFFERTOOLARGE, /* Buffer is too large */ DR_INTERRUPTED, /* The operation has been interrupted */ DR_NOCONTEXT, /* No context available */ DR_TEMPUNAVAIL, /* Temporarily unavailable */ DR_LIMITEXCEEDED, /* Attempted to exceed limit, i.e. any kind of maximum size, count etc */ DR_NOSUCHMETHOD, /* Requested method is not known */ DR_NOSUCHINSTANCE, /* Requested instance is not known */ DR_ITEMNOTFOUND, /* No such item found */ DR_VERSIONMISMATCH, /* Some versions didn't match */ DR_EOF, /* Reached end of file */ DR_SUSPENDED, /* The requested object is suspended */ DR_INCOMPLETE, /* The operation has been executed, but not completely */ DR_NOCORE, /* Core part not available */ DR_SIGNALLED, /* Received a signal, e.g. while waiting */ DR_TASK_NOT_FOUND, /* The corresponding task has not been found */ DR__RESULT_END } DirectResult; typedef enum { DENUM_OK = 0, /* Proceed with enumeration */ DENUM_CANCEL = 1, /* Cancel enumeration */ DENUM_REMOVE = 2 /* Remove item */ } DirectEnumerationResult; /**********************************************************************************************************************/ typedef struct __D_DirectCleanupHandler DirectCleanupHandler; typedef struct __D_DirectHash DirectHash; typedef struct __D_DirectLink DirectLink; typedef struct __D_DirectLog DirectLog; typedef struct __D_DirectMap DirectMap; typedef struct __D_DirectModuleDir DirectModuleDir; typedef struct __D_DirectModuleEntry DirectModuleEntry; typedef struct __D_DirectSignalHandler DirectSignalHandler; typedef struct __D_DirectStream DirectStream; typedef struct __D_DirectTraceBuffer DirectTraceBuffer; typedef struct __D_DirectThread DirectThread; typedef struct __D_DirectThreadInitHandler DirectThreadInitHandler; #endif ================================================ FILE: lib/direct/utf8.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__UTF8_H__ #define __DIRECT__UTF8_H__ #include /**********************************************************************************************************************/ #define DIRECT_UTF8_SKIP(c) (((u8) (c) < 0xc0) ? 1 : __direct_utf8_skip[(u8) (c) & 0x3f]) #define DIRECT_UTF8_GET_CHAR(p) (*(const u8*) (p) < 0xc0 ? *(const u8*) (p) : __direct_utf8_get_char((const u8*) (p))) /* * Actually the last two fields used to be zero since they indicate an invalid UTF-8 string. * Changed it to 1 to avoid endless looping on invalid input. */ static const char __direct_utf8_skip[64] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 }; static __inline__ unichar __direct_utf8_get_char( const u8 *p ) { int len; unichar result = p[0]; if (result < 0xc0) return result; if (result > 0xfd) return (unichar) -1; len = __direct_utf8_skip[result & 0x3f]; result &= 0x7c >> len; while (--len) { int c = *(++p); if ((c & 0xc0) != 0x80) return (unichar) -1; result = (result << 6) | (c & 0x3f); } return result; } #endif ================================================ FILE: lib/direct/util.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Direct_Util, "Direct/Util", "Direct Util" ); /**********************************************************************************************************************/ static const char *strings_base[150]; #define STRINGS_ADD(index,string) \ do { \ D_ASSERT( index < D_ARRAY_SIZE(strings_base) ); \ strings_base[index] = string; \ } while (0) /**********************************************************************************************************************/ void __D_util_init() { STRINGS_ADD( EPERM, "Operation not permitted" ); STRINGS_ADD( ENOENT, "No such file or directory" ); STRINGS_ADD( ESRCH, "No such process" ); STRINGS_ADD( EINTR, "Interrupted system call" ); STRINGS_ADD( EIO, "I/O error" ); STRINGS_ADD( ENXIO, "No such device or address" ); STRINGS_ADD( E2BIG, "Argument list too long" ); STRINGS_ADD( ENOEXEC, "Exec format error" ); STRINGS_ADD( EBADF, "Bad file number" ); STRINGS_ADD( ECHILD, "No child processes" ); STRINGS_ADD( EAGAIN, "Try again" ); STRINGS_ADD( ENOMEM, "Out of memory" ); STRINGS_ADD( EACCES, "Permission denied" ); STRINGS_ADD( EFAULT, "Bad address" ); STRINGS_ADD( ENOTBLK, "Block device required" ); STRINGS_ADD( EBUSY, "Device or resource busy" ); STRINGS_ADD( EEXIST, "File exists" ); STRINGS_ADD( EXDEV, "Cross-device link" ); STRINGS_ADD( ENODEV, "No such device" ); STRINGS_ADD( ENOTDIR, "Not a directory" ); STRINGS_ADD( EISDIR, "Is a directory" ); STRINGS_ADD( EINVAL, "Invalid argument" ); STRINGS_ADD( ENFILE, "File table overflow" ); STRINGS_ADD( EMFILE, "Too many open files" ); STRINGS_ADD( ENOTTY, "Not a typewriter" ); STRINGS_ADD( ETXTBSY, "Text file busy" ); STRINGS_ADD( EFBIG, "File too large" ); STRINGS_ADD( ENOSPC, "No space left on device" ); STRINGS_ADD( ESPIPE, "Illegal seek" ); STRINGS_ADD( EROFS, "Read-only file system" ); STRINGS_ADD( EMLINK, "Too many links" ); STRINGS_ADD( EPIPE, "Broken pipe" ); STRINGS_ADD( EDOM, "Math argument out of domain of func" ); STRINGS_ADD( ERANGE, "Math result not representable" ); STRINGS_ADD( ETIMEDOUT, "Timed out" ); } void __D_util_deinit() { } /**********************************************************************************************************************/ const char * direct_strerror( int erno ) { if (erno < 0) return "negative errno"; if (erno >= D_ARRAY_SIZE(strings_base)) return "too high errno"; return strings_base[erno]; } __dfb_no_instrument_function__ DirectResult errno2result( int erno ) { switch (erno) { case 0: return DR_OK; case ENOENT: return DR_FILENOTFOUND; case EACCES: case EPERM: return DR_ACCESSDENIED; case EBUSY: case EAGAIN: return DR_BUSY; case ETIMEDOUT: return DR_TIMEOUT; case ECONNREFUSED: return DR_ACCESSDENIED; case EINTR: return DR_SIGNALLED; case ENOSYS: return DR_NOSUCHMETHOD; case EINVAL: return DR_INVARG; case ENODEV: case ENXIO: case ENOTSUP: return DR_UNSUPPORTED; } return DR_FAILURE; } void direct_trim( char **s ) { int i; int len = strlen( *s ); for (i = len - 1; i >= 0; i--) if ((*s)[i] <= ' ') (*s)[i] = 0; else break; while (**s) if (**s <= ' ') (*s)++; else return; } static __inline__ char * __D_strtok_r( char *s, const char *delim, char **save_ptr ) { char *token; if (s == NULL) s = *save_ptr; /* Scan leading delimiters. */ s += strspn( s, delim ); if (*s == '\0') { *save_ptr = s; return NULL; } /* Find the end of the token. */ token = s; s = strpbrk( token, delim ); if (s == NULL) { /* This token finishes the string. */ *save_ptr = strchr( token, '\0' ); } else { /* Terminate the token and make *save_ptr point past it. */ *s = '\0'; *save_ptr = s + 1; } return token; } static __inline__ char * __D_strtok_r_1c( char *__s, char __sep, char **__nextp ) { char *__result; if (__s == NULL) __s = *__nextp; while (*__s == __sep) ++__s; __result = NULL; if (*__s != '\0') { __result = __s++; while (*__s != '\0') if (*__s++ == __sep) { __s[-1] = '\0'; break; } *__nextp = __s; } return __result; } #define __D_string2_1bptr_p(__x) \ ((size_t)(const void*) ((__x) + 1) - (size_t)(const void*) (__x) == 1) #define __D_strtok_r(s,sep,nextp) \ __builtin_constant_p( sep ) && __D_string2_1bptr_p( sep ) ? \ (((__const char*) (sep))[0] != '\0' && ((__const char*) (sep))[1] == '\0' ? \ __D_strtok_r_1c( s, ((__const char*) (sep))[0], nextp ) : \ __D_strtok_r( s, sep, nextp )) : \ __D_strtok_r( s, sep, nextp ) char * direct_strtok_r( char *str, const char *delim, char **saveptr ) { return __D_strtok_r( str, delim, saveptr ); } char * direct_snputs( char *dest, const char *src, size_t n ) { char *start = dest; D_ASSERT( dest != NULL ); D_ASSERT( src != NULL ); if (!n) return NULL; for (; n > 1 && *src; n--) *dest++ = *src++; *dest = 0; return start; } char * direct_base64_encode( const void *data, int size ) { static const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/="; const unsigned char *src = (const unsigned char*) data; char *res; char *buf; D_ASSERT( data != NULL ); buf = res = D_MALLOC( (size + 2) / 3 * 4 + 1 ); if (!res) return NULL; for (; size >= 3; size -= 3) { buf[0] = enc[((src[0] & 0xfc) >> 2)]; buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; buf[2] = enc[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)]; buf[3] = enc[((src[2] & 0x3f))]; buf += 4; src += 3; } if (size > 0) { buf[0] = enc[(src[0] & 0xfc) >> 2]; if (size > 1) { buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; buf[2] = enc[((src[1] & 0x0f) << 2)]; } else { buf[1] = enc[(src[0] & 0x03) << 4]; buf[2] = '='; } buf[3] = '='; buf += 4; } *buf = '\0'; return res; } void * direct_base64_decode( const char *string, int *ret_size ) { unsigned char dec[256]; unsigned char *res; unsigned char *buf; int len; int i, j; D_ASSERT( string != NULL ); len = strlen( string ); buf = res = D_MALLOC( len * 3 / 4 + 3 ); if (!res) return NULL; /* Generate decode table. */ for (i = 0; i < 255; i++) dec[i] = 0x80; for (i = 'A'; i <= 'Z'; i++) dec[i] = 0 + (i - 'A'); for (i = 'a'; i <= 'z'; i++) dec[i] = 26 + (i - 'a'); for (i = '0'; i <= '9'; i++) dec[i] = 52 + (i - '0'); dec['+'] = 62; dec['/'] = 63; dec['='] = 0; /* Decode. */ for (j = 0; j < len; j += 4) { unsigned char a[4], b[4]; for (i = 0; i < 4; i++) { int c = string[i+j]; a[i] = c; b[i] = dec[c]; } *buf++ = (b[0] << 2) | (b[1] >> 4); *buf++ = (b[1] << 4) | (b[2] >> 2); *buf++ = (b[2] << 6) | (b[3] ); if (a[2] == '=' || a[3] == '=') break; } *buf = '\0'; if (ret_size) *ret_size = buf - res; return res; } static const u8 S[4][4] = { { 7, 12, 17, 22}, /* Round 1 */ { 5, 9, 14, 20}, /* Round 2 */ { 4, 11, 16, 23}, /* Round 3 */ { 6, 10, 15, 21} /* Round 4 */ }; static const u32 T[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, }; static void md5_hash( u32 ABCD[4], u32 X[16] ) { u32 a = ABCD[3]; u32 b = ABCD[2]; u32 c = ABCD[1]; u32 d = ABCD[0]; int t; int i; #ifdef WORDS_BIGENDIAN for (i = 0; i < 16; i++) X[i] = BSWAP32(X[i]); #endif for (i = 0; i < 64; i++) { t = S[i>>4][i&3]; a += T[i]; switch (i>>4) { case 0: a += (d ^ (b&(c^d))) + X[( i) & 15]; break; case 1: a += (c ^ (d&(c^b))) + X[(1 + 5 * i) & 15]; break; case 2: a += (b^c^d) + X[(5 + 3 * i) & 15]; break; case 3: a += (c ^ (b | ~d)) + X[( 7 * i) & 15]; break; } a = b + ((a << t) | (a >> (32 - t))); t = d; d = c; c = b; b = a; a = t; } ABCD[0] += d; ABCD[1] += c; ABCD[2] += b; ABCD[3] += a; } void direct_md5_sum( void *dst, const void *src, const int len ) { u8 block[64]; u32 ABCD[4]; int i, j; D_ASSERT( dst != NULL ); D_ASSERT( src != NULL ); ABCD[0] = 0x10325476; ABCD[1] = 0x98badcfe; ABCD[2] = 0xefcdab89; ABCD[3] = 0x67452301; for (i = 0, j = 0; i < len; i++) { block[j++] = ((const u8*) src)[i]; if (j == 64) { md5_hash( ABCD, (u32*) block ); j = 0; } } block[j++] = 0x80; memset( &block[j], 0, 64 - j ); if (j > 56) { md5_hash( ABCD, (u32*) block ); memset( block, 0, 64 ); } for (i = 0; i < 8; i++) block[56+i] = (u8) (((u64) len << 3) >> (i << 3)); md5_hash( ABCD, (u32*) block ); for (i = 0; i < 4; i++) #ifdef WORDS_BIGENDIAN ((u32*) dst)[i] = BSWAP32(ABCD[3-i]); #else ((u32*) dst)[i] = ABCD[3-i]; #endif } void * direct_bsearch( const void *key, const void *base, size_t nmemb, size_t size, void *func ) { return bsearch( key, base, nmemb, size, func ); } ================================================ FILE: lib/direct/util.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__UTIL_H__ #define __DIRECT__UTIL_H__ #include /**********************************************************************************************************************/ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef SIGN #define SIGN(x) (((x) < 0) ? -1 : (((x) > 0) ? 1 : 0)) #endif #ifndef ABS #define ABS(x) ((x) > 0 ? (x) : -(x)) #endif #ifndef CLAMP #define CLAMP(x,min,max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) #endif #ifndef BSWAP16 #define BSWAP16(x) (((u16) (x)>>8) | ((u16) (x)<<8)) #endif #ifndef BSWAP32 #define BSWAP32(x) ((((u32) (x)>>24) & 0x000000ff) | (((u32) (x)>> 8) & 0x0000ff00) | \ (((u32) (x)<< 8) & 0x00ff0000) | (((u32) (x)<<24) & 0xff000000)) #endif #define D_FLAGS_SET(flags,f) do { (flags) = (__typeof__(flags))((flags) | (f)); } while (0) #define D_FLAGS_CLEAR(flags,f) do { (flags) = (__typeof__(flags))((flags) & ~(f)); } while (0) #define D_FLAGS_IS_SET(flags,f) (((flags) & (f)) != 0) #define D_FLAGS_ARE_SET(flags,f) (((flags) & (f)) == (f)) #define D_FLAGS_ARE_IN(flags,f) (((flags) & ~(f)) == 0) #define D_FLAGS_INVALID(flags,f) (((flags) & ~(f)) != 0) #define D_ARRAY_SIZE(array) ((int) (sizeof(array) / sizeof((array)[0]))) #define D_UTIL_SWAP(a,b) \ do { \ const __typeof__(a) __swap_x = (a); (a) = (b); (b) = __swap_x; \ } while (0) #define D_BITn32(f) (((f) & 0x00000001) ? 0 : \ ((f) & 0x00000002) ? 1 : \ ((f) & 0x00000004) ? 2 : \ ((f) & 0x00000008) ? 3 : \ ((f) & 0x00000010) ? 4 : \ ((f) & 0x00000020) ? 5 : \ ((f) & 0x00000040) ? 6 : \ ((f) & 0x00000080) ? 7 : \ ((f) & 0x00000100) ? 8 : \ ((f) & 0x00000200) ? 9 : \ ((f) & 0x00000400) ? 10 : \ ((f) & 0x00000800) ? 11 : \ ((f) & 0x00001000) ? 12 : \ ((f) & 0x00002000) ? 13 : \ ((f) & 0x00004000) ? 14 : \ ((f) & 0x00008000) ? 15 : \ ((f) & 0x00010000) ? 16 : \ ((f) & 0x00020000) ? 17 : \ ((f) & 0x00040000) ? 18 : \ ((f) & 0x00080000) ? 19 : \ ((f) & 0x00100000) ? 20 : \ ((f) & 0x00200000) ? 21 : \ ((f) & 0x00400000) ? 22 : \ ((f) & 0x00800000) ? 23 : \ ((f) & 0x01000000) ? 24 : \ ((f) & 0x02000000) ? 25 : \ ((f) & 0x04000000) ? 26 : \ ((f) & 0x08000000) ? 27 : \ ((f) & 0x10000000) ? 28 : \ ((f) & 0x20000000) ? 29 : \ ((f) & 0x40000000) ? 30 : \ ((f) & 0x80000000) ? 31 : -1) #define D_UNUSED_P(x) (void) x /**********************************************************************************************************************/ /* * Return a string describing errno. */ const char DIRECT_API *direct_strerror ( int erno ); /* * Translate errno to DirectResult. */ DirectResult DIRECT_API errno2result ( int erno ); /* * Remove whitespace from both sides of a string. */ void DIRECT_API direct_trim ( char **s ); /* * Extract tokens from a string. */ char DIRECT_API *direct_strtok_r ( char *str, const char *delim, char **saveptr ); /* * Set a string with a maximum size including the zero termination. * This acts like a strncpy( d, s, n ), but always terminates the string like direct_snprintf( d, n, "%s", s ). * Returns dest or NULL if n is zero. */ char DIRECT_API *direct_snputs ( char *dest, const char *src, size_t n ); /* * Encode Base-64 strings. */ char DIRECT_API *direct_base64_encode( const void *data, int size ); /* * Decode Base-64 strings. */ void DIRECT_API *direct_base64_decode( const char *string, int *ret_size ); /* * Compute MD5 sum (store 16-bytes long result in 'dst'). */ void DIRECT_API direct_md5_sum ( void *dst, const void *src, const int len ); /* * Search 'key' in 'base' and return a pointer to a matching element if found. */ void DIRECT_API *direct_bsearch ( const void *key, const void *base, size_t nmemb, size_t size, void *func ); /**********************************************************************************************************************/ /* * Slow implementation, but quite fast if only low bits are set. */ static __inline__ int direct_util_count_bits( unsigned int mask ) { int res = 0; while (mask) { res += mask & 1; mask >>= 1; } return res; } /* * Generic alignment routine. */ static __inline__ int direct_util_align( int value, int alignment ) { if (alignment > 1) { int tail = value % alignment; if (tail) value += alignment - tail; } return value; } /* * This floor operation is done by "(iround(f + .5) + iround(f - .5)) >> 1", * but uses some IEEE specific tricks for better speed. * 'f' must be between -4194304 and 4194303. */ static __inline__ int D_IFLOOR( float f ) { int ai, bi; double af, bf; af = (3 << 22) + 0.5 + (double) f; bf = (3 << 22) + 0.5 - (double) f; union { int i; float f; } u; u.f = (float) af; ai = u.i; u.f = (float) bf; bi = u.i; return (ai - bi) >> 1; } /* * This ceil operation is done by "(iround(f + .5) + iround(f - .5) + 1) >> 1", * but uses some IEEE specific tricks for better speed. * 'f' must be between -4194304 and 4194303. */ static __inline__ int D_ICEIL( float f ) { int ai, bi; double af, bf; af = (3 << 22) + 0.5 + (double) f; bf = (3 << 22) + 0.5 - (double) f; union { int i; float f; } u; u.f = (float) af; ai = u.i; u.f = (float) bf; bi = u.i; return (ai - bi + 1) >> 1; } static __inline__ int direct_log2( int val ) { int res = 0; while (val >> ++res); if ((1 << --res) < val) res++; return res; } typedef struct { long long start; long long stop; } DirectClock; static __inline__ void direct_clock_start( DirectClock *clock ) { clock->start = direct_clock_get_micros(); } static __inline__ void direct_clock_stop( DirectClock *clock ) { clock->stop = direct_clock_get_micros(); } static __inline__ long long direct_clock_diff( DirectClock *clock ) { return clock->stop - clock->start; } #define DIRECT_CLOCK_DIFF_SEC_MS(clock) \ (direct_clock_diff( clock ) / 1000000), (direct_clock_diff( clock ) / 1000 % 1000) /**********************************************************************************************************************/ void __D_util_init ( void ); void __D_util_deinit( void ); #endif ================================================ FILE: lib/direct/waitqueue.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECT__WAITQUEUE_H__ #define __DIRECT__WAITQUEUE_H__ #include /**********************************************************************************************************************/ #endif ================================================ FILE: lib/fusion/arena.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Fusion_Arena, "Fusion/Arena", "Fusion Arena" ); /**********************************************************************************************************************/ struct __Fusion_FusionArena { DirectLink link; int magic; FusionWorldShared *shared; FusionSkirmish lock; FusionRef ref; char *name; FusionHash *field_hash; }; /**********************************************************************************************************************/ static FusionArena *lock_arena ( FusionWorld *world, const char *name, bool add ); static void unlock_arena( FusionArena *arena ); /**********************************************************************************************************************/ DirectResult fusion_arena_enter( FusionWorld *world, const char *name, ArenaEnterFunc initialize, ArenaEnterFunc join, void *ctx, FusionArena **ret_arena, int *ret_error ) { FusionArena *arena; ArenaEnterFunc func; int error = 0; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( name != NULL ); D_ASSERT( ret_arena != NULL ); D_DEBUG_AT( Fusion_Arena, "%s( '%s' )\n", __FUNCTION__, name ); /* Lookup arena and lock it. If it doesn't exist create it. */ arena = lock_arena( world, name, true ); if (!arena) return DR_FAILURE; /* Check if we are the first. */ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) { D_DEBUG_AT( Fusion_Arena, " -> entering arena '%s' (establishing)\n", name ); /* Call 'initialize' later. */ func = initialize; /* Unlock the reference counter. */ fusion_ref_unlock( &arena->ref ); } else { D_DEBUG_AT( Fusion_Arena, " -> entering arena '%s' (joining)\n", name ); /* Call 'join' later. */ func = join; } /* Increase reference counter. */ fusion_ref_up( &arena->ref, false ); /* Return the arena. */ *ret_arena = arena; /* Call 'initialize' or 'join'. */ if (func) error = func( arena, ctx ); /* Return the return value of the callback. */ if (ret_error) *ret_error = error; if (error) { fusion_ref_down( &arena->ref, false ); if (func == initialize) { /* Destroy fields. */ fusion_hash_destroy( arena->field_hash ); /* Destroy reference counter. */ fusion_ref_destroy( &arena->ref ); /* Destroy the arena lock. This has to happen before locking the list. Otherwise a dead lock with lock_arena() below could occur. */ fusion_skirmish_destroy( &arena->lock ); /* Lock the list and remove the arena. */ fusion_skirmish_prevail( &world->shared->arenas_lock ); direct_list_remove( &world->shared->arenas, &arena->link ); fusion_skirmish_dismiss( &world->shared->arenas_lock ); D_MAGIC_CLEAR( arena ); /* Free allocated memory. */ SHFREE( world->shared->main_pool, arena->name ); SHFREE( world->shared->main_pool, arena ); return DR_OK; } } /* Unlock the arena. */ unlock_arena( arena ); return DR_OK; } DirectResult fusion_arena_add_shared_field( FusionArena *arena, const char *name, void *data ) { DirectResult ret; char *shname; D_MAGIC_ASSERT( arena, FusionArena ); D_MAGIC_ASSERT( arena->shared, FusionWorldShared ); D_ASSERT( data != NULL ); D_ASSERT( name != NULL ); D_DEBUG_AT( Fusion_Arena, "%s( '%s', '%s' -> %p )\n", __FUNCTION__, arena->name, name, data ); /* Lock the arena. */ ret = fusion_skirmish_prevail( &arena->lock ); if (ret) return ret; /* Give it the requested name. */ shname = SHSTRDUP( arena->shared->main_pool, name ); if (shname) ret = fusion_hash_replace( arena->field_hash, shname, data, NULL, NULL ); else ret = D_OOSHM(); /* Unlock the arena. */ fusion_skirmish_dismiss( &arena->lock ); return ret; } DirectResult fusion_arena_get_shared_field( FusionArena *arena, const char *name, void **data ) { void *ptr; D_ASSERT( arena != NULL ); D_ASSERT( name != NULL ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( arena, FusionArena ); D_DEBUG_AT( Fusion_Arena, "%s( '%s', '%s' )\n", __FUNCTION__, arena->name, name ); /* Lock the arena. */ if (fusion_skirmish_prevail( &arena->lock )) return DR_FAILURE; /* Lookup entry. */ ptr = fusion_hash_lookup( arena->field_hash, name ); D_DEBUG_AT( Fusion_Arena, " -> %p\n", ptr ); /* Unlock the arena. */ fusion_skirmish_dismiss( &arena->lock ); if (!ptr) return DR_ITEMNOTFOUND; *data = ptr; return DR_OK; } DirectResult fusion_arena_exit( FusionArena *arena, ArenaExitFunc shutdown, ArenaExitFunc leave, void *ctx, bool emergency, int *ret_error ) { int error = 0; D_MAGIC_ASSERT( arena, FusionArena ); D_MAGIC_ASSERT( arena->shared, FusionWorldShared ); D_ASSERT( shutdown != NULL ); D_DEBUG_AT( Fusion_Arena, "%s( '%s' )\n", __FUNCTION__, arena->name ); /* Lock the arena. */ if (fusion_skirmish_prevail( &arena->lock )) return DR_FAILURE; /* Decrease reference counter. */ fusion_ref_down( &arena->ref, false ); /* If we are the last... */ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) { /* Deinitialize everything. */ error = shutdown( arena, ctx, emergency ); /* Destroy fields. */ fusion_hash_destroy( arena->field_hash ); /* Destroy reference counter. */ fusion_ref_destroy( &arena->ref ); /* Destroy the arena lock. This has to happen before locking the list. Otherwise a dead lock with lock_arena() below could occur. */ fusion_skirmish_destroy( &arena->lock ); /* Lock the list and remove the arena. */ fusion_skirmish_prevail( &arena->shared->arenas_lock ); direct_list_remove( &arena->shared->arenas, &arena->link ); fusion_skirmish_dismiss( &arena->shared->arenas_lock ); D_MAGIC_CLEAR( arena ); /* Free allocated memory. */ SHFREE( arena->shared->main_pool, arena->name ); SHFREE( arena->shared->main_pool, arena ); } else { if (!leave) { fusion_ref_up( &arena->ref, false ); fusion_skirmish_dismiss( &arena->lock ); return DR_BUSY; } /* Simply leave the arena. */ error = leave( arena, ctx, emergency ); /* Unlock the arena. */ fusion_skirmish_dismiss( &arena->lock ); } /* Return the return value of the callback. */ if (ret_error) *ret_error = error; return DR_OK; } /**********************************************************************************************************************/ static FusionArena * create_arena( FusionWorld *world, const char *name ) { DirectResult ret; char buf[64]; FusionArena *arena; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( name != NULL ); arena = SHCALLOC( world->shared->main_pool, 1, sizeof(FusionArena) ); if (!arena) { D_OOSHM(); return NULL; } arena->shared = world->shared; snprintf( buf, sizeof(buf), "Arena '%s'", name ); /* Initialize lock and reference counter. */ ret = fusion_skirmish_init( &arena->lock, buf, world ); if (ret) goto error; fusion_skirmish_add_permissions( &arena->lock, 0, FUSION_SKIRMISH_PERMIT_PREVAIL | FUSION_SKIRMISH_PERMIT_DISMISS ); ret = fusion_ref_init( &arena->ref, buf, world ); if (ret) goto error_ref; fusion_ref_add_permissions( &arena->ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_ZERO_LOCK_UNLOCK ); /* Give it the requested name. */ arena->name = SHSTRDUP( world->shared->main_pool, name ); if (!arena->name) { D_OOSHM(); goto error_prevail; } ret = fusion_hash_create( world->shared->main_pool, HASH_STRING, HASH_PTR, 7, &arena->field_hash ); if (ret) goto error_hash; fusion_hash_set_autofree( arena->field_hash, true, false ); /* Add it to the list. */ direct_list_prepend( &world->shared->arenas, &arena->link ); /* Lock the newly created arena. */ ret = fusion_skirmish_prevail( &arena->lock ); if (ret) goto error_prevail; D_MAGIC_SET( arena, FusionArena ); /* Returned locked new arena. */ return arena; error_prevail: fusion_hash_destroy( arena->field_hash ); error_hash: if (arena->name) SHFREE( world->shared->main_pool, arena->name ); fusion_ref_destroy( &arena->ref ); error_ref: fusion_skirmish_destroy( &arena->lock ); error: SHFREE( world->shared->main_pool, arena ); return NULL; } static FusionArena * lock_arena( FusionWorld *world, const char *name, bool add ) { FusionArena *arena; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( name != NULL ); /* Lock the list. */ if (fusion_skirmish_prevail( &world->shared->arenas_lock )) return NULL; /* For each existing arena... */ direct_list_foreach (arena, world->shared->arenas) { /* Lock the arena. */ if (fusion_skirmish_prevail( &arena->lock )) continue; D_MAGIC_ASSERT( arena, FusionArena ); /* Check if the name matches. */ if (!strcmp( arena->name, name )) { /* Check for an orphaned arena. */ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) { D_ERROR( "Fusion/Arena: Orphaned arena '%s'!\n", name ); fusion_ref_unlock( &arena->ref ); } /* Unlock the list. */ fusion_skirmish_dismiss( &world->shared->arenas_lock ); /* Return locked arena. */ return arena; } /* Unlock mismatched arena. */ fusion_skirmish_dismiss( &arena->lock ); } /* If no arena name matched, create a new arena before unlocking the list again. */ arena = add ? create_arena( world, name ) : NULL; /* Unlock the list. */ fusion_skirmish_dismiss( &world->shared->arenas_lock ); return arena; } static void unlock_arena( FusionArena *arena ) { D_MAGIC_ASSERT( arena, FusionArena ); /* Unlock the arena. */ fusion_skirmish_dismiss( &arena->lock ); } ================================================ FILE: lib/fusion/arena.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__ARENA_H__ #define __FUSION__ARENA_H__ #include /**********************************************************************************************************************/ typedef int (*ArenaEnterFunc)( FusionArena *arena, void *ctx ); typedef int (*ArenaExitFunc) ( FusionArena *arena, void *ctx, bool emergency ); /**********************************************************************************************************************/ DirectResult FUSION_API fusion_arena_enter ( FusionWorld *world, const char *name, ArenaEnterFunc initialize, ArenaEnterFunc join, void *ctx, FusionArena **ret_arena, int *ret_error ); DirectResult FUSION_API fusion_arena_add_shared_field( FusionArena *arena, const char *name, void *data ); DirectResult FUSION_API fusion_arena_get_shared_field( FusionArena *arena, const char *name, void **data ); DirectResult FUSION_API fusion_arena_exit ( FusionArena *arena, ArenaExitFunc shutdown, ArenaExitFunc leave, void *ctx, bool emergency, int *ret_error ); #endif ================================================ FILE: lib/fusion/call.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #if FUSION_BUILD_MULTI #include #include #if FUSION_BUILD_KERNEL #include #if D_DEBUG_ENABLED #include #endif #else /* FUSION_BUILD_KERNEL */ #include #include #include #endif /* FUSION_BUILD_KERNEL */ #endif /* FUSION_BUILD_MULTI */ D_DEBUG_DOMAIN( Fusion_Call, "Fusion/Call", "Fusion Call" ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #if FUSION_BUILD_KERNEL #define FUSION_CALL_RETURN_DATA_MAX 32*1024*1024 #define FUSION_CALL_RETURN_DATA_MAX_ON_STACK 1024 typedef struct { int magic; DirectThread *thread; bool dispatcher; FusionWorld *world; FusionCallExecute3 *bins; int bins_num; char *bins_data; int bins_data_len; long long bins_create_ts; } CallTLS; static DirectTLS call_tls_key; #else /* FUSION_BUILD_KERNEL */ typedef struct { int call_id; FusionID fusion_id; void *handler; void *handler3; void *ctx; } CallInfo; #endif /* FUSION_BUILD_KERNEL */ #endif /* FUSION_BUILD_MULTI */ /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL static void call_tls_destroy( void *arg ) { CallTLS *call_tls = arg; D_MAGIC_ASSERT( call_tls, CallTLS ); fusion_world_flush_calls( call_tls->world, 0 ); D_ASSUME( call_tls->bins_num == 0 ); D_MAGIC_CLEAR( call_tls ); D_FREE( call_tls ); } void __Fusion_call_init() { direct_tls_register( &call_tls_key, call_tls_destroy ); } void __Fusion_call_deinit() { direct_tls_unregister( &call_tls_key ); } #else /* FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL */ void __Fusion_call_init() { } void __Fusion_call_deinit() { } #endif /* FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL */ /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #if FUSION_BUILD_KERNEL static CallTLS * Call_GetTLS( FusionWorld *world ) { CallTLS *call_tls; call_tls = direct_tls_get( &call_tls_key ); if (!call_tls) { call_tls = D_CALLOC( 1, sizeof(CallTLS) + sizeof(FusionCallExecute3) * fusion_config->call_bin_max_num + fusion_config->call_bin_max_data ); if (!call_tls) { D_OOM(); return NULL; } DirectThread *self = direct_thread_self(); if (self) call_tls->dispatcher = fusion_dispatcher_tid( world ) == direct_thread_get_tid( self ); call_tls->thread = self; call_tls->world = world; call_tls->bins = (FusionCallExecute3*) (call_tls + 1); call_tls->bins_data = (char*) (call_tls->bins + fusion_config->call_bin_max_num); D_MAGIC_SET( call_tls, CallTLS ); direct_tls_set( &call_tls_key, call_tls ); } D_MAGIC_ASSERT( call_tls, CallTLS ); return call_tls; } DirectResult fusion_call_init( FusionCall *call, FusionCallHandler handler, void *ctx, const FusionWorld *world ) { FusionCallNew call_new; if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, "%s( %p, %p <%s>, %p, %p )\n", __FUNCTION__, call, handler, direct_trace_lookup_symbol_at( handler ), ctx, world ); D_ASSERT( call != NULL ); D_ASSERT( handler != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); /* Called from others. */ call_new.handler = handler; call_new.ctx = ctx; while (ioctl( world->fusion_fd, FUSION_CALL_NEW, &call_new )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_NEW" ); return DR_FAILURE; } memset( call, 0, sizeof(FusionCall) ); /* Store handler, called directly when called by ourself. */ call->handler = handler; call->ctx = ctx; /* Store call and own fusion id. */ call->call_id = call_new.call_id; call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; } DirectResult fusion_call_init3( FusionCall *call, FusionCallHandler3 handler3, void *ctx, const FusionWorld *world ) { FusionCallNew call_new; if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, "%s( %p, %p <%s>, %p, %p )\n", __FUNCTION__, call, handler3, direct_trace_lookup_symbol_at( handler3 ), ctx, world ); D_ASSERT( call != NULL ); D_ASSERT( handler3 != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); /* Called from others. */ call_new.handler = handler3; call_new.ctx = ctx; while (ioctl( world->fusion_fd, FUSION_CALL_NEW, &call_new )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_NEW" ); return DR_FAILURE; } memset( call, 0, sizeof(FusionCall) ); /* Store handler, called directly when called by ourself. */ call->handler3 = handler3; call->ctx = ctx; /* Store call and own fusion id. */ call->call_id = call_new.call_id; call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; } DirectResult fusion_call_init_from( FusionCall *call, int call_id, const FusionWorld *world ) { D_DEBUG_AT( Fusion_Call, "%s( %p, %d, %p )\n", __FUNCTION__, call, call_id, world ); D_ASSERT( call != NULL ); D_ASSERT( call_id != 0 ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); memset( call, 0, sizeof(FusionCall) ); /* Store call id. */ call->call_id = call_id; /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; } DirectResult fusion_call_set_name( FusionCall *call, const char *name ) { FusionEntryInfo info; D_ASSERT( call != NULL ); D_ASSERT( name != NULL ); info.type = FT_CALL; info.id = call->call_id; direct_snputs( info.name, name, sizeof(info.name) ); while (ioctl( _fusion_fd( call->shared ), FUSION_ENTRY_SET_INFO, &info )) { switch (errno) { case EINTR: continue; case EAGAIN: return DR_LOCKED; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_ENTRY_SET_INFO" ); return DR_FAILURE; } return DR_OK; } DirectResult fusion_call_execute( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val ) { FusionWorld *world; CallTLS *call_tls; D_DEBUG_AT( Fusion_Call, "%s( %p, flags 0x%x, arg %d, ptr %p )\n", __FUNCTION__, call, flags, call_arg, call_ptr ); D_ASSERT( call != NULL ); if (!call->handler) return DR_DESTROYED; world = _fusion_world( call->shared ); if (call->fusion_id == _fusion_id( call->shared ) && direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) ); call_tls = Call_GetTLS( world ); if (call->fusion_id == fusion_id( world ) && (!(flags & FCEF_NODIRECT) || (call_tls->dispatcher))) { int res; FusionCallHandlerResult result; result = call->handler( call->fusion_id, call_arg, call_ptr, call->ctx, 0, &res ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_val) *ret_val = res; } else { FusionCallExecute execute; execute.call_id = call->call_id; execute.call_arg = call_arg; execute.call_ptr = call_ptr; execute.flags = flags | FCEF_RESUMABLE; execute.serial = 0; fusion_world_flush_calls( world, 1 ); while (ioctl( world->fusion_fd, FUSION_CALL_EXECUTE, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_INVARG; case EIDRM: D_ERROR( "Fusion/Call: Call got destroyed (id %d)!\n", call->call_id ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_EXECUTE( id %d, creator %lu )", call->call_id, call->fusion_id ); return DR_FAILURE; } if (ret_val) *ret_val = execute.ret_val; } return DR_OK; } DirectResult fusion_call_execute2( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, int *ret_val ) { D_DEBUG_AT( Fusion_Call, "%s( %p, flags 0x%x, arg %d, ptr %p, length %u )\n", __FUNCTION__, call, flags, call_arg, ptr, length ); D_ASSERT( call != NULL ); if (call->fusion_id == _fusion_id( call->shared ) && direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) ); if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) { int res; FusionCallHandlerResult result; result = call->handler( call->fusion_id, call_arg, ptr, call->ctx, 0, &res ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_val) *ret_val = res; } else { FusionCallExecute2 execute; execute.call_id = call->call_id; execute.call_arg = call_arg; execute.ptr = ptr; execute.length = length; execute.flags = flags | FCEF_RESUMABLE; execute.serial = 0; fusion_world_flush_calls( _fusion_world( call->shared ), 1 ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_EXECUTE2, &execute )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_INVARG; case EIDRM: D_ERROR( "Fusion/Call: Call got destroyed (id %d)!\n", call->call_id ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_EXECUTE2( id %d, creator %lu )", call->call_id, call->fusion_id ); return DR_FAILURE; } if (ret_val) *ret_val = execute.ret_val; } return DR_OK; } DirectResult fusion_call_execute3( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { FusionWorld *world; CallTLS *call_tls; D_DEBUG_AT( Fusion_Call, "%s( %p, flags 0x%x, arg %d, ptr %p, length %u, ret_ptr %p, ret_size %u )\n", __FUNCTION__, call, flags, call_arg, ptr, length, ret_ptr, ret_size ); if (ret_size > FUSION_CALL_RETURN_DATA_MAX) return DR_LIMITEXCEEDED; D_ASSERT( call != NULL ); world = _fusion_world( call->shared ); if (call->fusion_id == fusion_id( world ) && direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> handler is %s()\n", direct_trace_lookup_symbol_at( call->handler3 ) ); call_tls = Call_GetTLS( world ); if (call->fusion_id == fusion_id( world ) && (!(flags & FCEF_NODIRECT) || (call_tls->dispatcher))) { FusionCallHandlerResult result; unsigned int execute_length; result = call->handler3( call->fusion_id, call_arg, ptr, length, call->ctx, 0, ret_ptr, ret_size, &execute_length ); if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); if (ret_length) *ret_length = execute_length; } else { FusionCallExecute3 execute; DirectResult ret = DR_OK; /* Check whether we can cache this call. */ if (flags & FCEF_QUEUE && fusion_config->call_bin_max_num > 0 && length < 10000) { if (call_tls->bins_data_len + length > fusion_config->call_bin_max_data) { ret = fusion_world_flush_calls( world, 0 ); if (ret) return ret; } call_tls->bins[call_tls->bins_num].call_id = call->call_id; call_tls->bins[call_tls->bins_num].call_arg = call_arg; call_tls->bins[call_tls->bins_num].ptr = NULL; call_tls->bins[call_tls->bins_num].length = length; call_tls->bins[call_tls->bins_num].ret_ptr = ret_ptr; call_tls->bins[call_tls->bins_num].ret_length = ret_size; call_tls->bins[call_tls->bins_num].flags = flags | FCEF_FOLLOW | FCEF_RESUMABLE; call_tls->bins[call_tls->bins_num].serial = 0; D_DEBUG_AT( Fusion_Call, " -> buffered length %u, flags 0x%x\n", length, call_tls->bins[call_tls->bins_num].flags ); if (length > 0) { call_tls->bins[call_tls->bins_num].ptr = &call_tls->bins_data[call_tls->bins_data_len]; direct_memcpy( &call_tls->bins_data[call_tls->bins_data_len], ptr, length ); call_tls->bins_data_len += length; } call_tls->bins_num++; if (call_tls->bins_num == 1) { call_tls->bins_create_ts = direct_clock_get_millis(); } else if (call_tls->bins_num >= fusion_config->call_bin_max_num || direct_clock_get_millis() - call_tls->bins_create_ts >= EXECUTE3_BIN_FLUSH_MILLIS) { ret = fusion_world_flush_calls( world, 0 ); } return ret; } ret = fusion_world_flush_calls( world, 1 ); execute.call_id = call->call_id; execute.call_arg = call_arg; execute.ptr = ptr; execute.length = length; execute.ret_ptr = ret_ptr; execute.ret_length = ret_size; execute.flags = flags | FCEF_RESUMABLE; execute.serial = 0; D_DEBUG_AT( Fusion_Call, " -> ptr %p, length %u, flags 0x%x\n", ptr, length, execute.flags ); while (ioctl( world->fusion_fd, FUSION_CALL_EXECUTE3, &execute )) { switch (errno) { case EINTR: D_DEBUG_AT( Fusion_Call, " -> EINTR (flags 0x%x, serial %u)\n", execute.flags, execute.serial ); continue; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_INVARG; case EIDRM: D_ERROR( "Fusion/Call: Call got destroyed (id %d)!\n", call->call_id ); return DR_DESTROYED; default: D_DEBUG_AT( Fusion_Call, " -> OK (flags 0x%x)\n", execute.flags ); break; } D_PERROR( "Fusion/Call: FUSION_CALL_EXECUTE3( id %d, creator %lu )", call->call_id, call->fusion_id ); return DR_FAILURE; } if (ret_length) *ret_length = execute.ret_length; } return DR_OK; } DirectResult fusion_world_flush_calls( FusionWorld *world, int lock ) { DirectResult ret = DR_OK; CallTLS *call_tls; call_tls = Call_GetTLS( world ); D_DEBUG_AT( Fusion_Call, "%s( %p, lock %d )\n", __FUNCTION__, world, lock ); if (call_tls->bins_num > 0) { D_DEBUG_AT( Fusion_Call, " -> num %d, length %d\n", call_tls->bins_num, call_tls->bins_data_len ); if (direct_log_domain_check( &Fusion_Call )) { int i; for (i = 0; i < call_tls->bins_num; i++) { D_DEBUG_AT( Fusion_Call, " -> [%2d] id %d, flags 0x%x, arg %d, length %u\n", i, call_tls->bins[i].call_id, call_tls->bins[i].flags, call_tls->bins[i].call_arg, call_tls->bins[i].length ); } } if (call_tls->dispatcher) { D_DEBUG_AT( Fusion_Call, " -> dispatcher, not flushing\n" ); return DR_OK; } call_tls->bins[call_tls->bins_num-1].flags &= ~(FCEF_FOLLOW | FCEF_QUEUE); while (ioctl( world->fusion_fd, FUSION_CALL_EXECUTE3, call_tls->bins )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call_tls->bins[0].call_id ); ret = DR_INVARG; break; case EIDRM: D_ERROR( "Fusion/Call: Call got destroyed (id %d)!\n", call_tls->bins[0].call_id ); ret = DR_DESTROYED; break; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_EXECUTE3( num %d, len %d )", call_tls->bins_num, call_tls->bins_data_len ); ret = DR_FAILURE; break; } call_tls->bins_num = 0; call_tls->bins_data_len = 0; } return ret; } DirectResult fusion_call_return( FusionCall *call, unsigned int serial, int val ) { FusionCallReturn call_ret; D_DEBUG_AT( Fusion_Call, "%s( %p, %u, %d )\n", __FUNCTION__, call, serial, val ); D_ASSERT( call != NULL ); D_ASSUME( serial != 0 ); if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) ); if (!serial) return DR_UNSUPPORTED; call_ret.call_id = call->call_id; call_ret.val = val; call_ret.serial = serial; fusion_world_flush_calls( _fusion_world( call->shared ), 1 ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_RETURN, &call_ret )) { switch (errno) { case EINTR: continue; case EIDRM: D_WARN( "caller withdrawn" ); return DR_NOCONTEXT; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_RETURN" ); return DR_FAILURE; } return DR_OK; } DirectResult fusion_call_return3( FusionCall *call, unsigned int serial, void *ptr, unsigned int length ) { FusionCallReturn3 call_ret; D_DEBUG_AT( Fusion_Call, "%s( %p, serial %u, ptr %p, length %u )\n", __FUNCTION__, call, serial, ptr, length ); D_ASSERT( call != NULL ); D_ASSUME( serial != 0 ); if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) ); if (!serial) return DR_UNSUPPORTED; call_ret.call_id = call->call_id; call_ret.serial = serial; call_ret.ptr = ptr; call_ret.length = length; fusion_world_flush_calls( _fusion_world( call->shared ), 1 ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_RETURN3, &call_ret )) { switch (errno) { case EINTR: continue; case EIDRM: D_WARN( "caller withdrawn" ); return DR_NOCONTEXT; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call->call_id ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_RETURN3" ); return DR_FAILURE; } return DR_OK; } DirectResult fusion_call_get_owner( FusionCall *call, FusionID *ret_fusion_id ) { FusionCallGetOwner get_owner; D_DEBUG_AT( Fusion_Call, "%s( %p )\n", __FUNCTION__, call ); D_ASSERT( call != NULL ); D_ASSERT( ret_fusion_id != NULL ); get_owner.call_id = call->call_id; while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_GET_OWNER, &get_owner )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_GET_OWNER" ); return DR_FAILURE; } *ret_fusion_id = get_owner.fusion_id; return DR_OK; } DirectResult fusion_call_set_quota( FusionCall *call, FusionID fusion_id, unsigned int limit ) { FusionCallSetQuota set_quota; D_DEBUG_AT( Fusion_Call, "%s( %p, fusion_id %lu, limit %u )\n", __FUNCTION__, call, fusion_id, limit ); D_ASSERT( call != NULL ); set_quota.call_id = call->call_id; set_quota.fusion_id = fusion_id; set_quota.limit = limit; while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_SET_QUOTA, &set_quota )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_SET_QUOTA" ); return DR_FAILURE; } return DR_OK; } DirectResult fusion_call_destroy( FusionCall *call ) { D_DEBUG_AT( Fusion_Call, "%s( %p )\n", __FUNCTION__, call ); D_ASSERT( call != NULL ); D_ASSERT( call->handler != NULL || call->handler3 != NULL ); D_DEBUG_AT( Fusion_Call, " -> call_id %d\n", call->call_id ); if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ?: (FusionCallHandler) call->handler3 ) ); while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_DESTROY, &call->call_id )) { switch (errno) { case EINTR: continue; case EINVAL: return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Call: FUSION_CALL_DESTROY" ); return DR_FAILURE; } call->handler = NULL; return DR_OK; } DirectResult fusion_call_add_permissions( FusionCall *call, FusionID fusion_id, FusionCallPermissions call_permissions ) { FusionEntryPermissions permissions; permissions.type = FT_CALL; permissions.id = call->call_id; permissions.fusion_id = fusion_id; permissions.permissions = 0; if (call_permissions & FUSION_CALL_PERMIT_EXECUTE) { FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_CALL_EXECUTE ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_CALL_EXECUTE2 ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_CALL_EXECUTE3 ); } while (ioctl( _fusion_fd( call->shared ), FUSION_ENTRY_ADD_PERMISSIONS, &permissions ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion/Call: FUSION_ENTRY_ADD_PERMISSIONS( id %d )\n", call->call_id ); return DR_FAILURE; } } return DR_OK; } void _fusion_call_process( FusionWorld *world, int call_id, FusionCallMessage *msg, void *ptr ) { FusionCallHandlerResult result = FCHR_RETURN; FusionCallHandler call_handler; FusionCallReturn call_ret = { .val = 0 }; D_DEBUG_AT( Fusion_Call, "%s( call_id %d, msg %p, ptr %p)\n", __FUNCTION__, call_id, msg, ptr ); D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( msg != NULL ); D_ASSERT( msg->handler != NULL ); call_handler = msg->handler; if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call_handler ) ); result = call_handler( msg->caller, msg->call_arg, ptr ?: msg->call_ptr, msg->ctx, msg->serial, &call_ret.val ); switch (result) { case FCHR_RETURN: if (msg->serial) { call_ret.serial = msg->serial; call_ret.call_id = call_id; while (ioctl( world->fusion_fd, FUSION_CALL_RETURN, &call_ret )) { switch (errno) { case EINTR: continue; case EIDRM: D_WARN( "caller withdrawn" ); return; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call_id ); return; default: D_PERROR( "Fusion/Call: FUSION_CALL_RETURN" ); return; } } } break; case FCHR_RETAIN: break; default: D_BUG( "unknown result %u from call handler", result ); } } void _fusion_call_process3( FusionWorld *world, int call_id, FusionCallMessage3 *msg, void *ptr ) { FusionCallHandlerResult result = FCHR_RETURN; FusionCallHandler3 call_handler; FusionCallReturn3 call_ret; char *ret_ptr = NULL; unsigned int ret_length = 0; D_DEBUG_AT( Fusion_Call, "%s( call_id %d, msg %p, ptr %p)\n", __FUNCTION__, call_id, msg, ptr ); D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( msg != NULL ); D_ASSERT( msg->handler != NULL ); call_handler = msg->handler; if (direct_log_domain_check( &Fusion_Call )) D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call_handler ) ); if (msg->ret_length > FUSION_CALL_RETURN_DATA_MAX) { D_ERROR( "Fusion/Call: Maximum return data length (%d) exceeded (%u)!\n", FUSION_CALL_RETURN_DATA_MAX, msg->ret_length ); } else { if (msg->ret_length > FUSION_CALL_RETURN_DATA_MAX_ON_STACK) { ret_ptr = D_MALLOC( msg->ret_length ); if (!ret_ptr) D_OOM(); } else ret_ptr = alloca( msg->ret_length ); } if (ret_ptr) result = call_handler( msg->caller, msg->call_arg, ptr ?: msg->call_ptr, msg->call_length, msg->ctx, msg->serial, ret_ptr, msg->ret_length, &ret_length ); switch (result) { case FCHR_RETURN: if (msg->serial) { call_ret.call_id = call_id; call_ret.serial = msg->serial; call_ret.ptr = ret_ptr; call_ret.length = ret_length; while (ioctl( world->fusion_fd, FUSION_CALL_RETURN3, &call_ret )) { switch (errno) { case EINTR: continue; case EIDRM: D_DEBUG_AT( Fusion_Call, " -> caller withdrawn\n" ); goto out; case EINVAL: D_ERROR( "Fusion/Call: Invalid call (id %d)!\n", call_id ); goto out; default: D_PERROR( "Fusion/Call: FUSION_CALL_RETURN3" ); goto out; } } } break; case FCHR_RETAIN: break; default: D_BUG( "unknown result %u from call handler", result ); } out: if (msg->ret_length > FUSION_CALL_RETURN_DATA_MAX_ON_STACK) D_FREE( ret_ptr ); } #else /* FUSION_BUILD_KERNEL */ DirectResult fusion_call_init( FusionCall *call, FusionCallHandler handler, void *ctx, const FusionWorld *world ) { D_ASSERT( call != NULL ); D_ASSERT( handler != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); memset( call, 0, sizeof(FusionCall) ); call->call_id = ++world->shared->call_ids; /* Store handler, called directly when called by ourself. */ call->handler = handler; call->ctx = ctx; /* Store own fusion id. */ call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; CallInfo *info = SHCALLOC( world->shared->main_pool, 1, sizeof(CallInfo) ); if (!info) return D_OOSHM(); info->call_id = call->call_id; info->fusion_id = call->fusion_id; info->handler = call->handler; info->handler3 = call->handler3; info->ctx = call->ctx; fusion_hash_insert( world->shared->call_hash, (void*)(long) call->call_id, info ); return DR_OK; } DirectResult fusion_call_init3( FusionCall *call, FusionCallHandler3 handler3, void *ctx, const FusionWorld *world ) { D_ASSERT( call != NULL ); D_ASSERT( handler3 != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); memset( call, 0, sizeof(FusionCall) ); call->call_id = ++world->shared->call_ids; /* Store handler, called directly when called by ourself. */ call->handler3 = handler3; call->ctx = ctx; /* Store own fusion id. */ call->fusion_id = fusion_id( world ); /* Keep back pointer to shared world data. */ call->shared = world->shared; CallInfo *info = SHCALLOC( world->shared->main_pool, 1, sizeof(CallInfo) ); if (!info) return D_OOSHM(); info->call_id = call->call_id; info->fusion_id = call->fusion_id; info->handler = call->handler; info->handler3 = call->handler3; info->ctx = call->ctx; fusion_hash_insert( world->shared->call_hash, (void*)(long) call->call_id, info ); return DR_OK; } DirectResult fusion_call_init_from( FusionCall *call, int call_id, const FusionWorld *world ) { D_DEBUG_AT( Fusion_Call, "%s( %p, %d, %p )\n", __FUNCTION__, call, call_id, world ); D_ASSERT( call != NULL ); D_ASSERT( call_id != 0 ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); CallInfo *info = fusion_hash_lookup( world->shared->call_hash, (void*)(long) call_id ); D_ASSERT( info != NULL ); D_ASSERT( info->call_id == call_id ); memset( call, 0, sizeof(FusionCall) ); /* Store call id. */ call->call_id = call_id; /* Store handlers, called directly when called by ourself. */ call->handler = info->handler; call->handler3 = info->handler3; call->ctx = info->ctx; /* Store own fusion id. */ call->fusion_id = info->fusion_id; /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; } DirectResult fusion_call_set_name( FusionCall *call, const char *name ) { D_ASSERT( call != NULL ); D_ASSERT( name != NULL ); return DR_OK; } static DirectResult fusion_call_execute_internal( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { DirectResult ret = DR_OK; FusionWorld *world; struct sockaddr_un addr; char msg_buf[sizeof(FusionCallMessage) + length]; FusionCallMessage *msg = (FusionCallMessage*) msg_buf; D_ASSERT( call != NULL ); if (!call->handler && !call->handler3) return DR_DESTROYED; world = _fusion_world( call->shared ); if (call->fusion_id == fusion_id( world ) && (!(flags & FCEF_NODIRECT) || (call->handler3 && (direct_thread_self() == world->dispatch_loop)))) { FusionCallHandlerResult result; if (call->handler) { D_ASSERT( length == sizeof(void*) ); result = call->handler( _fusion_id( call->shared ), call_arg, *(void**) call_ptr, call->ctx, 0, ret_ptr ); } else { D_ASSERT( call->handler3 != NULL ); result = call->handler3( _fusion_id( call->shared ), call_arg, call_ptr, length, call->ctx, 0, ret_ptr, ret_size, ret_length ); } if (result != FCHR_RETURN) D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" ); return DR_OK; } msg->type = FMT_CALL; msg->caller = world->fusion_id; msg->call_id = call->call_id; msg->call_arg = call_arg; msg->call_length = length; msg->ret_length = ret_size; msg->handler = call->handler; msg->handler3 = call->handler3; msg->ctx = call->ctx; msg->flags = flags; direct_memcpy( msg + 1, call_ptr, length ); if (flags & FCEF_ONEWAY) { /* Invalidate serial. */ msg->serial = -1; /* Send message. */ addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id ); ret = _fusion_send_message( world->fusion_fd, msg, sizeof(FusionCallMessage) + length, &addr ); } else { int fd; int err; int len; fd = socket( PF_LOCAL, SOCK_RAW, 0 ); if (fd < 0) { D_PERROR( "Fusion/Call: Error creating local socket!\n" ) ; return DR_IO; } /* Set close-on-exec flag. */ fcntl( fd, F_SETFD, FD_CLOEXEC ); addr.sun_family = AF_UNIX; len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/call.%x.", fusion_world_index( world ), (unsigned int) call->call_id ); /* Generate call serial (socket address is based on it). */ for (msg->serial = 0; msg->serial <= 0xffffff; msg->serial++) { snprintf( addr.sun_path + len, sizeof(addr.sun_path) - len, "%x", msg->serial ); err = bind( fd, (struct sockaddr*) &addr, sizeof(addr) ); if (err == 0) { direct_chmod( addr.sun_path, 0660 ); /* Change group, if requested. */ if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); break; } } if (err < 0) { D_PERROR( "Fusion/Call: Error binding local socket!\n" ); close( fd ); return DR_IO; } /* Send message. */ snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id ); ret = _fusion_send_message( fd, msg, sizeof(FusionCallMessage) + length, &addr ); if (ret == DR_OK) { char buf[sizeof(FusionCallReturn) + ret_size]; FusionCallReturn *callret = (FusionCallReturn*) buf; /* Wait for reply. */ ret = _fusion_recv_message( fd, buf, sizeof(FusionCallReturn) + ret_size, NULL ); if (ret == DR_OK) { D_ASSERT( callret->length <= ret_size ); if (callret->length) { D_ASSERT( ret_ptr != NULL ); direct_memcpy( ret_ptr, callret + 1, callret->length ); } if (ret_length) *ret_length = callret->length; } } socklen_t addrlen = sizeof(addr); if (getsockname( fd, (struct sockaddr*) &addr, &addrlen ) == 0) direct_unlink( addr.sun_path ); close( fd ); } return ret; } DirectResult fusion_call_execute( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val ) { return fusion_call_execute_internal( call, flags, call_arg, &call_ptr, sizeof(call_ptr), ret_val, sizeof(*ret_val), NULL ); } DirectResult fusion_call_execute2( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, unsigned int length, int *ret_val ) { return fusion_call_execute_internal( call, flags, call_arg, call_ptr, length, ret_val, 4, NULL ); } DirectResult fusion_call_execute3( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute_internal( call, flags, call_arg, call_ptr, length, ret_ptr, ret_size, ret_length ); } DirectResult fusion_world_flush_calls( FusionWorld *world, int lock ) { return DR_OK; } static DirectResult fusion_call_return_internal( FusionCall *call, unsigned int serial, const void *ptr, unsigned int length ) { struct sockaddr_un addr; char buf[sizeof(FusionCallReturn) + length]; FusionCallReturn *callret = (FusionCallReturn*) buf; D_ASSERT( call != NULL ); addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/call.%x.%x", call->shared->world_index, (unsigned int) call->call_id, serial ); callret->type = FMT_CALLRET; callret->length = length; if (length) { D_ASSERT( ptr != NULL ); direct_memcpy( callret + 1, ptr, length ); } return _fusion_send_message( _fusion_fd( call->shared ), callret, sizeof(FusionCallReturn) + length, &addr ); } DirectResult fusion_call_return( FusionCall *call, unsigned int serial, int val ) { return fusion_call_return_internal( call, serial, &val, sizeof(int) ); } DirectResult fusion_call_return3( FusionCall *call, unsigned int serial, void *ptr, unsigned int length ) { return fusion_call_return_internal( call, serial, ptr, length ); } DirectResult fusion_call_get_owner( FusionCall *call, FusionID *ret_fusion_id ) { D_DEBUG_AT( Fusion_Call, "%s( %p )\n", __FUNCTION__, call ); D_ASSERT( call != NULL ); D_ASSERT( ret_fusion_id != NULL ); *ret_fusion_id = call->fusion_id; return DR_OK; } DirectResult fusion_call_set_quota( FusionCall *call, FusionID fusion_id, unsigned int limit ) { D_DEBUG_AT( Fusion_Call, "%s( %p, fusion_id %lu, limit %u )\n", __FUNCTION__, call, fusion_id, limit ); D_ASSERT( call != NULL ); return DR_OK; } DirectResult fusion_call_destroy( FusionCall *call ) { D_ASSERT( call != NULL ); D_ASSERT( call->handler != NULL || call->handler3 != NULL ); CallInfo *info = fusion_hash_lookup( call->shared->call_hash, (void*)(long) call->call_id ); D_ASSERT( info != NULL ); D_ASSERT( info->call_id == call->call_id ); fusion_hash_remove( call->shared->call_hash, (void*)(long) call->call_id, NULL, NULL ); SHFREE( call->shared->main_pool, info ); call->handler = NULL; call->handler3 = NULL; return DR_OK; } DirectResult fusion_call_add_permissions( FusionCall *call, FusionID fusion_id, FusionCallPermissions call_permissions ) { return DR_OK; } void _fusion_call_process( FusionWorld *world, int call_id, FusionCallMessage *msg, void *ptr ) { FusionCallHandlerResult result; char buf[sizeof(FusionCallReturn) + msg->ret_length]; FusionCallReturn *callret = (FusionCallReturn*) buf; D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( msg != NULL ); if (msg->handler) { FusionCallHandler call_handler = msg->handler; D_ASSERT( call_handler != NULL ); callret->type = FMT_CALLRET; callret->length = sizeof(int); D_ASSERT( msg->call_length == sizeof(void*) ); result = call_handler( msg->caller, msg->call_arg, ptr, msg->ctx, msg->serial, (int*) (callret + 1) ); switch (result) { case FCHR_RETURN: if (!(msg->flags & FCEF_ONEWAY)) { struct sockaddr_un addr; addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/call.%x.%x", fusion_world_index( world ), (unsigned int) call_id, msg->serial ); if (_fusion_send_message( world->fusion_fd, callret, sizeof(FusionCallMessage) + callret->length, &addr )) D_ERROR( "Fusion/Call: Could not send call return (serial %u)!\n", msg->serial ); } break; case FCHR_RETAIN: break; default: D_BUG( "unknown result %u from call handler", result ); break; } } else { FusionCallHandler3 call_handler3 = msg->handler3; D_ASSERT( call_handler3 != NULL ); callret->type = FMT_CALLRET; callret->length = 0; result = call_handler3( msg->caller, msg->call_arg, ptr, msg->call_length, msg->ctx, msg->serial, callret + 1, msg->ret_length, &callret->length ); switch (result) { case FCHR_RETURN: if (!(msg->flags & FCEF_ONEWAY)) { struct sockaddr_un addr; addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/call.%x.%x", fusion_world_index( world ), (unsigned int) call_id, msg->serial ); if (_fusion_send_message( world->fusion_fd, callret, sizeof(FusionCallMessage) + callret->length, &addr )) D_ERROR( "Fusion/Call: Could not send call return (serial %u)!\n", msg->serial ); } break; case FCHR_RETAIN: break; default: D_BUG( "unknown result %u from call handler", result ); break; } } } #endif /* FUSION_BUILD_KERNEL */ #else /* FUSION_BUILD_MULTI */ DirectResult fusion_call_init( FusionCall *call, FusionCallHandler handler, void *ctx, const FusionWorld *world ) { D_ASSERT( call != NULL ); D_ASSERT( handler != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); /* Called locally. */ call->handler = handler; call->ctx = ctx; call->shared = world->shared; return DR_OK; } DirectResult fusion_call_init3( FusionCall *call, FusionCallHandler3 handler3, void *ctx, const FusionWorld *world ) { D_ASSERT( call != NULL ); D_ASSERT( handler3 != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); /* Called locally. */ call->handler3 = handler3; call->ctx = ctx; call->shared = world->shared; return DR_OK; } DirectResult fusion_call_init_from( FusionCall *call, int call_id, const FusionWorld *world ) { D_DEBUG_AT( Fusion_Call, "%s( %p, %d, %p )\n", __FUNCTION__, call, call_id, world ); D_ASSERT( call != NULL ); D_ASSERT( call_id != 0 ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); memset( call, 0, sizeof(FusionCall) ); /* Store call id. */ call->call_id = call_id; /* Keep back pointer to shared world data. */ call->shared = world->shared; D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id ); return DR_OK; } DirectResult fusion_call_set_name( FusionCall *call, const char *name ) { D_ASSERT( call != NULL ); D_ASSERT( name != NULL ); return DR_OK; } DirectResult fusion_call_execute( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val ) { DirectResult ret; FusionEventDispatcherCall msg; FusionEventDispatcherCall *ret_msg = &msg; D_ASSERT( call != NULL ); if (!call->handler) return DR_DESTROYED; if (!(flags & FCEF_NODIRECT) || direct_thread_self() == call->shared->world->event_dispatcher_thread) return call->handler( 1, call_arg, call_ptr, call->ctx, 0, ret_val ); msg.processed = 0; msg.reaction = 0; msg.call_handler = call->handler; msg.call_handler3 = 0; msg.call_ctx = call->ctx; msg.flags = flags; msg.call_arg = call_arg; msg.ptr = call_ptr; msg.length = 0; msg.ret_val = 0; msg.ret_ptr = 0; msg.ret_size = 0; msg.ret_length = 0; ret = _fusion_event_dispatcher_process( call->shared->world, &msg, &ret_msg ); if (!(flags & FCEF_ONEWAY) && ret_val) *ret_val = ret_msg->ret_val; return ret; } DirectResult fusion_call_execute2( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, int *ret_val ) { DirectResult ret; FusionEventDispatcherCall msg; FusionEventDispatcherCall *ret_msg = &msg; D_ASSERT( call != NULL ); if (!call->handler) return DR_DESTROYED; if (!(flags & FCEF_NODIRECT) || direct_thread_self() == call->shared->world->event_dispatcher_thread) return call->handler( 1, call_arg, ptr, call->ctx, 0, ret_val ); msg.processed = 0; msg.reaction = 0; msg.call_handler = call->handler; msg.call_handler3 = 0; msg.call_ctx = call->ctx; msg.flags = flags; msg.call_arg = call_arg; msg.ptr = ptr; msg.length = length; msg.ret_val = 0; msg.ret_ptr = 0; msg.ret_size = 0; msg.ret_length = 0; ret = _fusion_event_dispatcher_process( call->shared->world, &msg, &ret_msg ); if (!(flags & FCEF_ONEWAY) && ret_val) *ret_val = ret_msg->ret_val; return ret; } DirectResult fusion_call_execute3( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { DirectResult ret; FusionEventDispatcherCall msg; FusionEventDispatcherCall *ret_msg = &msg; D_ASSERT( call != NULL ); if (!call->handler3) return DR_DESTROYED; if (!(flags & FCEF_NODIRECT) || direct_thread_self() == call->shared->world->event_dispatcher_thread) { unsigned int ret_len; ret = call->handler3( 1, call_arg, ptr, length, call->ctx, 0, ret_ptr, ret_size, &ret_len ); if (ret_length) *ret_length = ret_len; return ret; } msg.processed = 0; msg.reaction = 0; msg.call_handler = 0; msg.call_handler3 = call->handler3; msg.call_ctx = call->ctx; msg.flags = flags; msg.call_arg = call_arg; msg.ptr = ptr; msg.length = length; msg.ret_val = 0; msg.ret_ptr = ret_ptr; msg.ret_size = ret_size; msg.ret_length = 0; ret = _fusion_event_dispatcher_process( call->shared->world, &msg, &ret_msg ); if (!(flags & FCEF_ONEWAY) && ret_length) *ret_length = ret_msg->ret_length; return ret; } DirectResult fusion_world_flush_calls( FusionWorld *world, int lock ) { return DR_OK; } DirectResult fusion_call_return( FusionCall *call, unsigned int serial, int val ) { return DR_UNIMPLEMENTED; } DirectResult fusion_call_return3( FusionCall *call, unsigned int serial, void *ptr, unsigned int length ) { return DR_UNIMPLEMENTED; } DirectResult fusion_call_get_owner( FusionCall *call, FusionID *ret_fusion_id ) { *ret_fusion_id = FUSION_ID_MASTER; return DR_OK; } DirectResult fusion_call_set_quota( FusionCall *call, FusionID fusion_id, unsigned int limit ) { return DR_OK; } DirectResult fusion_call_destroy( FusionCall *call ) { D_ASSERT( call != NULL ); D_ASSERT( call->handler != NULL || call->handler3 != NULL ); call->handler = NULL; call->handler3 = NULL; return DR_OK; } DirectResult fusion_call_add_permissions( FusionCall *call, FusionID fusion_id, FusionCallPermissions call_permissions ) { return DR_OK; } #endif /* FUSION_BUILD_MULTI */ ================================================ FILE: lib/fusion/call.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__CALL_H__ #define __FUSION__CALL_H__ #include /**********************************************************************************************************************/ typedef enum { FCHR_RETURN = 0x00000000, FCHR_RETAIN = 0x00000001 } FusionCallHandlerResult; typedef FusionCallHandlerResult (*FusionCallHandler) ( int caller, /* Fusion id of the caller. */ int call_arg, /* Optional call parameter. */ void *call_ptr, /* Optional call parameter. */ void *ctx, /* Optional handler context. */ unsigned int serial, int *ret_val ); typedef FusionCallHandlerResult (*FusionCallHandler3)( int caller, /* Fusion id of the caller. */ int call_arg, /* Optional call parameter. */ void *ptr, /* Optional call parameter. */ unsigned int length, /* Length. */ void *ctx, /* Optional handler context. */ unsigned int serial, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ); struct __Fusion_FusionCall { FusionWorldShared *shared; int call_id; FusionID fusion_id; FusionCallHandler handler; FusionCallHandler3 handler3; void *ctx; }; /**********************************************************************************************************************/ typedef enum { FUSION_CALL_PERMIT_NONE = 0x00000000, FUSION_CALL_PERMIT_EXECUTE = 0x00000001, FUSION_CALL_PERMIT_ALL = 0x00000001 } FusionCallPermissions; /**********************************************************************************************************************/ DirectResult FUSION_API fusion_call_init ( FusionCall *call, FusionCallHandler handler, void *ctx, const FusionWorld *world ); DirectResult FUSION_API fusion_call_init3 ( FusionCall *call, FusionCallHandler3 handler3, void *ctx, const FusionWorld *world ); DirectResult FUSION_API fusion_call_init_from ( FusionCall *call, int call_id, const FusionWorld *world ); DirectResult FUSION_API fusion_call_set_name ( FusionCall *call, const char *name ); DirectResult FUSION_API fusion_call_execute ( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *call_ptr, int *ret_val ); DirectResult FUSION_API fusion_call_execute2 ( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, int *ret_val ); DirectResult FUSION_API fusion_call_execute3 ( FusionCall *call, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ); DirectResult FUSION_API fusion_world_flush_calls ( FusionWorld *world, int lock ); DirectResult FUSION_API fusion_call_return ( FusionCall *call, unsigned int serial, int val ); DirectResult FUSION_API fusion_call_return3 ( FusionCall *call, unsigned int serial, void *ptr, unsigned int length ); DirectResult FUSION_API fusion_call_get_owner ( FusionCall *call, FusionID *ret_fusion_id ); DirectResult FUSION_API fusion_call_set_quota ( FusionCall *call, FusionID fusion_id, unsigned int limit ); DirectResult FUSION_API fusion_call_destroy ( FusionCall *call ); /* * Give permissions to another fusionee to use the call. */ DirectResult FUSION_API fusion_call_add_permissions( FusionCall *call, FusionID fusion_id, FusionCallPermissions permissions ); /**********************************************************************************************************************/ void __Fusion_call_init ( void ); void __Fusion_call_deinit( void ); #endif ================================================ FILE: lib/fusion/conf.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Fusion_Config, "Fusion/Config", "Fusion Runtime Configuration options" ); /**********************************************************************************************************************/ static FusionConfig conf = { 0 }; FusionConfig *fusion_config = &conf; const char *fusion_config_usage = "libfusion options:\n" " tmpfs= Location of the shared memory file in multi application mode (default = auto)\n" " shmfile-group= Group that owns shared memory files\n" " [no-]force-slave Always enter as a slave, waiting for the master, if not there\n" " [no-]fork-handler Register fork handlers\n" " [no-]debugshm Enable shared memory allocation tracking\n" " [no-]madv-remove Enable usage of MADV_REMOVE (default = auto)\n" " [no-]secure-fusion Use secure fusion, e.g. read-only shm (default enabled)\n" " [no-]defer-destructors Handle destructor calls in separate thread\n" " trace-ref= Trace FusionRef up/down ('all' traces all)\n" " call-bin-max-num= Set maximum call number for async call buffer (default = 512, 0 = disable)\n" " call-bin-max-data= Set maximum call data size for async call buffer (default = 65536)\n" " [no-]shutdown-info Dump objects from all pools if some objects remain alive\n" "\n"; /**********************************************************************************************************************/ void __Fusion_conf_init() { fusion_config->shmfile_gid = -1; fusion_config->secure_fusion = true; fusion_config->call_bin_max_num = 512; fusion_config->call_bin_max_data = 65536; } void __Fusion_conf_deinit() { } /**********************************************************************************************************************/ DirectResult fusion_config_set( const char *name, const char *value ) { if (strcmp( name, "tmpfs" ) == 0) { if (value) { if (fusion_config->tmpfs) D_FREE( fusion_config->tmpfs ); fusion_config->tmpfs = D_STRDUP( value ); } else { D_ERROR( "Fusion/Config: '%s': No directory name specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "shmfile-group" ) == 0) { if (value) { struct group *group_info; group_info = getgrnam( value ); if (group_info) fusion_config->shmfile_gid = group_info->gr_gid; else D_PERROR( "Fusion/Config: 'shmfile-group': Group '%s' not found!\n", value ); } else { D_ERROR( "Fusion/Config: '%s': No file group name specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "force-slave" ) == 0) { fusion_config->force_slave = true; } else if (strcmp( name, "no-force-slave" ) == 0) { fusion_config->force_slave = false; } else if (strcmp( name, "fork-handler" ) == 0) { fusion_config->fork_handler = true; } else if (strcmp( name, "no-fork-handler" ) == 0) { fusion_config->fork_handler = false; } else if (strcmp( name, "debugshm" ) == 0) { fusion_config->debugshm = true; } else if (strcmp( name, "no-debugshm" ) == 0) { fusion_config->debugshm = false; } else if (strcmp( name, "madv-remove" ) == 0) { fusion_config->madv_remove = true; fusion_config->madv_remove_force = true; } else if (strcmp( name, "no-madv-remove" ) == 0) { fusion_config->madv_remove = false; fusion_config->madv_remove_force = true; } else if (strcmp( name, "secure-fusion" ) == 0) { fusion_config->secure_fusion = true; } else if (strcmp( name, "no-secure-fusion" ) == 0) { fusion_config->secure_fusion = false; } else if (strcmp( name, "defer-destructors" ) == 0) { fusion_config->defer_destructors = true; } else if (strcmp( name, "no-defer-destructors" ) == 0) { fusion_config->defer_destructors = false; } else if (strcmp( name, "trace-ref" ) == 0) { if (value) { if (!strcmp( value, "all" )) { fusion_config->trace_ref = -1; } else if (sscanf( value, "%x", (unsigned int *) &fusion_config->trace_ref ) != 1) { D_ERROR( "Fusion/Config: '%s': Invalid value!\n", name ); return DR_INVARG; } } else { D_ERROR( "Fusion/Config: '%s': No ID specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "call-bin-max-num" ) == 0) { if (value) { unsigned int max; if (sscanf( value, "%u", &max ) < 1) { D_ERROR( "Fusion/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } if (max < 1) { D_ERROR( "Fusion/Config: '%s': Error in value '%s' (min 1)!\n", name, value ); return DR_INVARG; } if (max > 16384) { D_ERROR( "Fusion/Config: '%s': Error in value '%s' (max 16384)!\n", name, value ); return DR_INVARG; } fusion_config->call_bin_max_num = max; } else { D_ERROR( "Fusion/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "call-bin-max-data" ) == 0) { if (value) { unsigned int max; if (sscanf( value, "%u", &max ) < 1) { D_ERROR( "Fusion/Config: '%s': Could not parse value!\n", name ); return DR_INVARG; } if (max < 4096) { D_ERROR( "Fusion/Config: '%s': Error in value '%s' (min 4096)!\n", name, value ); return DR_INVARG; } if (max > 16777216) { D_ERROR( "Fusion/Config: '%s': Error in value '%s' (max 16777216)!\n", name, value ); return DR_INVARG; } fusion_config->call_bin_max_data = max; } else { D_ERROR( "Fusion/Config: '%s': No value specified!\n", name ); return DR_INVARG; } } else if (strcmp( name, "shutdown-info" ) == 0) { fusion_config->shutdown_info = true; } else if (strcmp( name, "no-shutdown-info" ) == 0) { fusion_config->shutdown_info = false; } else return DR_INVARG; D_DEBUG_AT( Fusion_Config, "Set %s '%s'\n", name, value ?: "" ); return DR_OK; } ================================================ FILE: lib/fusion/conf.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__CONF_H__ #define __FUSION__CONF_H__ #include /**********************************************************************************************************************/ typedef struct { char *tmpfs; gid_t shmfile_gid; bool force_slave; bool fork_handler; bool debugshm; bool madv_remove; bool madv_remove_force; bool secure_fusion; bool defer_destructors; int trace_ref; unsigned int call_bin_max_num; unsigned int call_bin_max_data; bool shutdown_info; } FusionConfig; /**********************************************************************************************************************/ extern FusionConfig FUSION_API *fusion_config; extern const char FUSION_API *fusion_config_usage; /* * Set indiviual option. */ DirectResult FUSION_API fusion_config_set( const char *name, const char *value ); /**********************************************************************************************************************/ void __Fusion_conf_init ( void ); void __Fusion_conf_deinit( void ); #endif ================================================ FILE: lib/fusion/fusion.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #if FUSION_BUILD_MULTI #include #include #include #if D_DEBUG_ENABLED #include #endif #include #include #if FUSION_BUILD_KERNEL #include #else /* FUSION_BUILD_KERNEL */ #include #endif /* FUSION_BUILD_KERNEL */ #else /* FUSION_BUILD_MULTI */ #include #include #endif /* FUSION_BUILD_MULTI */ D_DEBUG_DOMAIN( Fusion_Main, "Fusion/Main", "Fusion High level IPC" ); D_DEBUG_DOMAIN( Fusion_Main_Dispatch, "Fusion/Main/Dispatch", "Fusion High level IPC Dispatch" ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI static FusionWorld *fusion_worlds[FUSION_MAX_WORLDS]; static DirectMutex fusion_worlds_lock = DIRECT_MUTEX_INITIALIZER(); int _fusion_fd( const FusionWorldShared *shared ) { int index; FusionWorld *world; D_MAGIC_ASSERT( shared, FusionWorldShared ); index = shared->world_index; D_ASSERT( index >= 0 ); D_ASSERT( index < FUSION_MAX_WORLDS ); world = fusion_worlds[index]; D_MAGIC_ASSERT( world, FusionWorld ); return world->fusion_fd; } FusionID _fusion_id( const FusionWorldShared *shared ) { int index; FusionWorld *world; D_MAGIC_ASSERT( shared, FusionWorldShared ); index = shared->world_index; D_ASSERT( index >= 0 ); D_ASSERT( index < FUSION_MAX_WORLDS ); world = fusion_worlds[index]; D_MAGIC_ASSERT( world, FusionWorld ); return world->fusion_id; } FusionWorld * _fusion_world( const FusionWorldShared *shared ) { int index; FusionWorld *world; D_MAGIC_ASSERT( shared, FusionWorldShared ); index = shared->world_index; D_ASSERT( index >= 0 ); D_ASSERT( index < FUSION_MAX_WORLDS ); world = fusion_worlds[index]; D_MAGIC_ASSERT( world, FusionWorld ); return world; } static void fusion_fork_handler_prepare( void ); static void fusion_fork_handler_parent ( void ); static void fusion_fork_handler_child ( void ); static void init_once( void ) { if (fusion_config->fork_handler) direct_thread_atfork( fusion_fork_handler_prepare, fusion_fork_handler_parent, fusion_fork_handler_child ); fusion_print_madvise(); } static bool refs_map_compare( DirectMap *map, const void *key, void *object, void *ctx ) { const FusionRefSlaveKey *map_key = key; FusionRefSlaveEntry *map_entry = object; return map_key->fusion_id == map_entry->key.fusion_id && map_key->ref_id == map_entry->key.ref_id; } static unsigned int refs_map_hash( DirectMap *map, const void *key, void *ctx ) { const FusionRefSlaveKey *map_key = key; return map_key->ref_id * 131 + map_key->fusion_id; } static bool refs_map_slave_compare( DirectMap *map, const void *key, void *object, void *ctx ) { const int *map_key = key; FusionRef *map_entry = object; return *map_key == map_entry->multi.id; } static unsigned int refs_map_slave_hash( DirectMap *map, const void *key, void *ctx ) { const int *map_key = key; return *map_key; } static FusionCallHandlerResult world_refs_call( int caller, /* Fusion id of the caller. */ int call_arg, /* Optional call parameter. */ void *call_ptr, /* Optional call parameter. */ void *ctx, /* Optional handler context. */ unsigned int serial, int *ret_val ) { FusionWorld *world = ctx; FusionRefSlaveKey key; FusionRefSlaveEntry *slave; key.fusion_id = caller; key.ref_id = call_arg; direct_mutex_lock( &world->refs_lock ); slave = direct_map_lookup( world->refs_map, &key ); direct_mutex_unlock( &world->refs_lock ); if (!slave) { D_WARN( "slave (%d) ref (%d) not found", caller, call_arg ); return FCHR_RETURN; } fusion_ref_down( slave->ref, false ); direct_mutex_lock( &world->refs_lock ); if (!--slave->refs) { direct_map_remove( world->refs_map, &key ); D_FREE( slave ); } direct_mutex_unlock( &world->refs_lock ); return FCHR_RETURN; } static void *fusion_dispatch_loop( DirectThread *thread, void *arg ); static DirectOnce fusion_init_once = DIRECT_ONCE_INIT(); #if FUSION_BUILD_KERNEL static int fusion_try_open( const char *name1, const char *name2, int flags, bool error_msg ) { int fd; fd = open( name1, flags, 660 ); if (fd < 0) { if (errno != ENOENT) { if (error_msg) D_PERROR( "Fusion/Main: Opening '%s' failed!\n", name1 ); return -1; } fd = open( name2, flags, 660 ); if (fd < 0 && error_msg) { if (errno == ENOENT) D_PERROR( "Fusion/Main: Opening '%s' and '%s' failed!\n", name1, name2 ); else D_PERROR( "Fusion/Main: Opening '%s' failed!\n", name2 ); } } return (fd < 0) ? -1 : fd; } static void fusion_world_fork( FusionWorld *world ) { int fd; char buf1[20]; char buf2[20]; FusionEnter enter; FusionFork fork; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); snprintf( buf1, sizeof(buf1), "/dev/fusion%d", world->shared->world_index ); snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", world->shared->world_index ); /* Open Fusion Kernel Device. */ fd = fusion_try_open( buf1, buf2, O_RDWR, true ); if (fd < 0) { D_ERROR( "Fusion/Main: Reopening fusion device (world %d) failed!\n", world->shared->world_index ); raise( SIGTRAP ); } /* Drop "identity" when running another program. */ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0) D_PERROR( "Fusion/Main: Setting FD_CLOEXEC flag failed!\n" ); /* Fill enter information. */ enter.api.major = 9; enter.api.minor = 0; enter.fusion_id = 0; /* Enter the fusion world. */ while (ioctl( fd, FUSION_ENTER, &enter )) { if (errno != EINTR) { D_PERROR( "Fusion/Main: Could not reenter world '%d'!\n", world->shared->world_index ); raise( SIGTRAP ); } } /* Check for valid Fusion ID. */ if (!enter.fusion_id) { D_ERROR( "Fusion/Main: Got no ID from FUSION_ENTER!\n" ); raise( SIGTRAP ); } D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", enter.fusion_id ); /* Fill fork information. */ fork.fusion_id = world->fusion_id; fusion_world_flush_calls( world, 1 ); /* Fork within the fusion world. */ while (ioctl( fd, FUSION_FORK, &fork )) { if (errno != EINTR) { D_PERROR( "Fusion/Main: Could not fork in world '%d'!\n", world->shared->world_index ); raise( SIGTRAP ); } } D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", fork.fusion_id ); /* Get new fusion id back. */ world->fusion_id = fork.fusion_id; /* Close old file descriptor. */ close( world->fusion_fd ); /* Write back new file descriptor. */ world->fusion_fd = fd; D_DEBUG_AT( Fusion_Main, " -> restarting dispatcher loop...\n" ); /* Restart the dispatcher thread. */ world->dispatch_loop = direct_thread_create( DTT_MESSAGING, fusion_dispatch_loop, world, "Fusion Dispatch" ); if (!world->dispatch_loop) raise( SIGTRAP ); } static void fusion_fork_handler_prepare() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_PREPARE ); } } static void fusion_fork_handler_parent() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_PARENT ); if (world->fork_action == FFA_FORK) { /* Increase the shared reference counter. */ if (fusion_master( world )) world->shared->refs++; } } } static void fusion_fork_handler_child() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_CHILD ); switch (world->fork_action) { default: D_BUG( "unknown fork action %u", world->fork_action ); case FFA_CLOSE: D_DEBUG_AT( Fusion_Main, " -> closing world %d\n", i ); /* Remove world from global list. */ fusion_worlds[i] = NULL; /* Unmap shared area. */ direct_file_unmap( world->shared, sizeof(FusionWorldShared) ); /* Close Fusion Kernel Device. */ close( world->fusion_fd ); /* Free local world data. */ D_MAGIC_CLEAR( world ); D_FREE( world ); break; case FFA_FORK: D_DEBUG_AT( Fusion_Main, " -> forking in world %d\n", i ); fusion_world_fork( world ); break; } } } static DirectResult map_shared_root( void *shm_base, int world_index, bool master, FusionWorldShared **ret_shared ) { DirectResult ret = DR_OK; DirectFile fd; void *map; char tmpfs[FUSION_SHM_TMPFS_PATH_NAME_LEN]; char root_file[FUSION_SHM_TMPFS_PATH_NAME_LEN+32]; int flags = O_RDONLY; int perms = DFP_READ; unsigned long size = direct_page_align( sizeof(FusionWorldShared) ); unsigned long base = (unsigned long) shm_base + (size + direct_pagesize()) * world_index; if (master || !fusion_config->secure_fusion) { perms |= DFP_WRITE; flags = O_RDWR; } if (master) flags |= O_CREAT | O_TRUNC; if (fusion_config->tmpfs) { direct_snputs( tmpfs, fusion_config->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN ); } else if (!fusion_find_tmpfs( tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN )) { D_ERROR( "Fusion/Main: Could not find tmpfs mount point, falling back to /dev/shm!\n" ); snprintf( tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN, "/dev/shm" ); } snprintf( root_file, sizeof(root_file), "%s/fusion.%d", tmpfs, world_index ); /* Open the virtual file. */ ret = direct_file_open( &fd, root_file, flags, 0660 ); if (ret) { D_DERROR( ret, "Fusion/Main: Could not open virtual file '%s'!\n", root_file ); return ret; } if (fusion_config->shmfile_gid != -1) { if (direct_file_chown( &fd, -1, fusion_config->shmfile_gid )) D_WARN( "changing owner on %s failed", root_file ); } if (master) { direct_file_chmod( &fd, fusion_config->secure_fusion ? 0640 : 0660 ); if (direct_file_truncate( &fd, size )) { D_DERROR( ret, "Fusion/Main: Could not truncate shared memory file '%s'!\n", root_file ); goto out; } } D_DEBUG_AT( Fusion_Main, " -> mapping shared memory file ("_ZU" bytes)\n", sizeof(FusionWorldShared) ); /* Map shared area. */ D_INFO( "Fusion/Main: Shared root (%d) is "_ZU" bytes, 0x%lx at 0x%lx\n", world_index, sizeof(FusionWorldShared), size, base ); ret = direct_file_map( &fd, (void*) base, 0, size, perms, &map ); if (ret) { D_DERROR( ret, "Fusion/Main: Mapping shared area failed!\n" ); goto out; } *ret_shared = map; out: direct_file_close( &fd ); return ret; } static void * fusion_deferred_loop( DirectThread *thread, void *arg ) { FusionWorld *world = arg; D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ ); D_MAGIC_ASSERT( world, FusionWorld ); direct_mutex_lock( &world->deferred.lock ); while (world->refs) { DeferredCall *deferred; deferred = (DeferredCall*) world->deferred.list; if (!deferred) { direct_waitqueue_wait( &world->deferred.queue, &world->deferred.lock ); continue; } direct_list_remove( &world->deferred.list, &deferred->link ); direct_mutex_unlock( &world->deferred.lock ); FusionReadMessage *header = &deferred->header; void *data = header + 1; switch (header->msg_type) { case FMT_SEND: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND!\n" ); break; case FMT_CALL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" ); _fusion_call_process( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage)) ? data + sizeof(FusionCallMessage) : NULL ); break; case FMT_REACTOR: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" ); _fusion_reactor_process_message( world, header->msg_id, header->msg_channel, data ); break; case FMT_SHMPOOL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SHMPOOL...\n" ); _fusion_shmpool_process( world, header->msg_id, data ); break; case FMT_CALL3: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL3...\n" ); _fusion_call_process3( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage3)) ? data + sizeof(FusionCallMessage3) : NULL ); break; default: D_DEBUG_AT( Fusion_Main_Dispatch, " -> discarding message of unknown type '%u'\n", header->msg_type ); break; } D_FREE( deferred ); direct_mutex_lock( &world->deferred.lock ); } direct_mutex_unlock( &world->deferred.lock ); return NULL; } DirectResult fusion_enter( int world_index, int abi_version, FusionEnterRole role, FusionWorld **ret_world ) { DirectResult ret = DR_OK; int fd = -1; FusionWorld *world = NULL; FusionWorldShared *shared = NULL; FusionEnter enter; char buf1[20]; char buf2[20]; unsigned long shm_base; D_DEBUG_AT( Fusion_Main, "%s( %d, %d, %p )\n", __FUNCTION__, world_index, abi_version, ret_world ); D_ASSERT( ret_world != NULL ); if (world_index >= FUSION_MAX_WORLDS) { D_ERROR( "Fusion/Main: World index %d exceeds maximum index %d!\n", world_index, FUSION_MAX_WORLDS - 1 ); return DR_INVARG; } direct_once( &fusion_init_once, init_once ); if (fusion_config->force_slave) role = FER_SLAVE; direct_initialize(); direct_mutex_lock( &fusion_worlds_lock ); if (world_index < 0) { if (role == FER_SLAVE) { D_ERROR( "Fusion/Main: Slave role and a new world (index -1) was requested!\n" ); direct_mutex_unlock( &fusion_worlds_lock ); return DR_INVARG; } for (world_index = 0; world_index < FUSION_MAX_WORLDS; world_index++) { world = fusion_worlds[world_index]; if (world) break; snprintf( buf1, sizeof(buf1), "/dev/fusion%d", world_index ); snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", world_index ); /* Open Fusion Kernel Device. */ fd = fusion_try_open( buf1, buf2, O_RDWR | O_EXCL, false ); if (fd < 0) { if (errno != EBUSY) D_ERROR( "Fusion/Main: Error opening '%s' and/or '%s'!\n", buf1, buf2 ); } else break; } } else { world = fusion_worlds[world_index]; if (!world) { int flags = O_RDWR; snprintf( buf1, sizeof(buf1), "/dev/fusion%d", world_index ); snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", world_index ); if (role == FER_MASTER) flags |= O_EXCL; else if (role == FER_SLAVE) flags |= O_APPEND; /* Open Fusion Kernel Device. */ fd = fusion_try_open( buf1, buf2, flags, true ); } } /* Enter a world again. */ if (world) { D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( world->refs > 0 ); /* Check the role again. */ switch (role) { case FER_MASTER: if (world->fusion_id != FUSION_ID_MASTER) { D_ERROR( "Fusion/Main: Master role requested for a world (%d), but we are already slave in!\n", world_index ); ret = DR_UNSUPPORTED; goto error; } break; case FER_SLAVE: if (world->fusion_id == FUSION_ID_MASTER) { D_ERROR( "Fusion/Main: Slave role requested for a world (%d), but we are already master in!\n", world_index ); ret = DR_UNSUPPORTED; goto error; } break; case FER_ANY: break; } shared = world->shared; D_MAGIC_ASSERT( shared, FusionWorldShared ); if (shared->world_abi != abi_version) { D_ERROR( "Fusion/Main: World ABI (%d) of world '%d' doesn't match own (%d)!\n", shared->world_abi, world_index, abi_version ); ret = DR_VERSIONMISMATCH; goto error; } world->refs++; direct_mutex_unlock( &fusion_worlds_lock ); D_DEBUG_AT( Fusion_Main, " -> using existing world %p [%d]\n", world, world_index ); /* Return the world. */ *ret_world = world; return DR_OK; } if (fd < 0) { D_ERROR( "Fusion/Main: Opening fusion device (world %d) as '%s' failed!\n", world_index, role == FER_ANY ? "any" : (role == FER_MASTER ? "master" : "slave") ); ret = DR_INIT; goto error; } /* Drop "identity" when running another program. */ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0) D_PERROR( "Fusion/Main: Setting FD_CLOEXEC flag failed!\n" ); /* Fill enter information. */ enter.api.major = 9; enter.api.minor = 0; enter.fusion_id = 0; enter.secure = fusion_config->secure_fusion; /* Enter the fusion world. */ while (ioctl( fd, FUSION_ENTER, &enter )) { if (errno != EINTR) { D_PERROR( "Fusion/Main: Could not enter world '%d'!\n", world_index ); ret = DR_INIT; goto error; } } /* Check for valid Fusion ID. */ if (!enter.fusion_id) { D_ERROR( "Fusion/Main: Got no ID from FUSION_ENTER!\n" ); ret = DR_INIT; goto error; } D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", enter.fusion_id ); /* Check slave role only, master is handled by O_EXCL earlier. */ if (role == FER_SLAVE && enter.fusion_id == FUSION_ID_MASTER) { D_ERROR( "Fusion/Main: Entering world '%d' as a slave failed!\n", world_index ); ret = DR_UNSUPPORTED; goto error; } if (ioctl( fd, FUSION_SHM_GET_BASE, &shm_base )) { ret = errno2result( errno ); D_PERROR( "Fusion/Main: FUSION_SHM_GET_BASE" ); goto error; } /* Map shared area. */ ret = map_shared_root( (void*) shm_base, world_index, enter.fusion_id == FUSION_ID_MASTER, &shared ); if (ret) goto error; D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size "_ZU"\n", shared, sizeof(FusionWorldShared) ); /* Initialize shared data. */ if (enter.fusion_id == FUSION_ID_MASTER) { /* Initialize reference counter. */ shared->refs = 1; /* Set ABI version. */ shared->world_abi = abi_version; /* Set the world index. */ shared->world_index = world_index; /* Set start time of world clock. */ shared->start_time = direct_clock_get_time( DIRECT_CLOCK_SESSION ); D_MAGIC_SET( shared, FusionWorldShared ); } else { D_MAGIC_ASSERT( shared, FusionWorldShared ); /* Check ABI version. */ if (shared->world_abi != abi_version) { D_ERROR( "Fusion/Main: World ABI (%d) doesn't match own (%d)!\n", shared->world_abi, abi_version ); ret = DR_VERSIONMISMATCH; goto error; } } /* Synchronize to world clock. */ direct_clock_set_time( DIRECT_CLOCK_SESSION, shared->start_time ); /* Allocate local data. */ world = D_CALLOC( 1, sizeof(FusionWorld) ); if (!world) { ret = D_OOM(); goto error; } /* Initialize local data. */ world->refs = 1; world->shared = shared; world->fusion_fd = fd; world->fusion_id = enter.fusion_id; direct_mutex_init( &world->reactor_nodes_lock ); D_MAGIC_SET( world, FusionWorld ); fusion_worlds[world_index] = world; /* Initialize shared memory part. */ ret = fusion_shm_init( world ); if (ret) goto error2; D_DEBUG_AT( Fusion_Main, " -> initializing other parts...\n" ); direct_mutex_init( &world->refs_lock ); /* Initialize other parts. */ if (enter.fusion_id == FUSION_ID_MASTER) { fusion_skirmish_init2( &shared->reactor_globals, "Fusion Reactor Globals", world,fusion_config->secure_fusion ); fusion_skirmish_init2( &shared->arenas_lock, "Fusion Arenas", world, fusion_config->secure_fusion ); if (!fusion_config->secure_fusion) { fusion_skirmish_add_permissions( &shared->reactor_globals, 0, FUSION_SKIRMISH_PERMIT_PREVAIL | FUSION_SKIRMISH_PERMIT_DISMISS ); fusion_skirmish_add_permissions( &shared->arenas_lock, 0, FUSION_SKIRMISH_PERMIT_PREVAIL | FUSION_SKIRMISH_PERMIT_DISMISS ); } /* Create the main pool. */ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x1000000, fusion_config->debugshm, &shared->main_pool ); if (ret) goto error3; fusion_call_init( &shared->refs_call, world_refs_call, world, world ); fusion_call_set_name( &shared->refs_call, "world_refs" ); fusion_call_add_permissions( &shared->refs_call, 0, FUSION_CALL_PERMIT_EXECUTE ); direct_map_create( 37, refs_map_compare, refs_map_hash, world, &world->refs_map ); } else direct_map_create( 37, refs_map_slave_compare, refs_map_slave_hash, world, &world->refs_map ); D_DEBUG_AT( Fusion_Main, " -> starting dispatcher loop...\n" ); /* Start the dispatcher thread. */ world->dispatch_loop = direct_thread_create( DTT_MESSAGING, fusion_dispatch_loop, world, "Fusion Dispatch" ); if (!world->dispatch_loop) { ret = DR_FAILURE; goto error4; } direct_waitqueue_init( &world->deferred.queue ); direct_mutex_init( &world->deferred.lock ); /* Start the deferred thread. */ world->deferred.thread = direct_thread_create( DTT_MESSAGING, fusion_deferred_loop, world, "Fusion Deferred" ); if (!world->deferred.thread) { ret = DR_FAILURE; goto error4; } D_DEBUG_AT( Fusion_Main, " -> done (%p)\n", world ); direct_mutex_unlock( &fusion_worlds_lock ); /* Return the fusion world. */ *ret_world = world; return DR_OK; error4: if (world->deferred.thread) direct_thread_destroy( world->deferred.thread ); if (world->dispatch_loop) direct_thread_destroy( world->dispatch_loop ); if (enter.fusion_id == FUSION_ID_MASTER) fusion_shm_pool_destroy( world, shared->main_pool ); error3: if (enter.fusion_id == FUSION_ID_MASTER) { fusion_skirmish_destroy( &shared->arenas_lock ); fusion_skirmish_destroy( &shared->reactor_globals ); } fusion_shm_deinit( world ); error2: fusion_worlds[world_index] = world; D_MAGIC_CLEAR( world ); D_FREE( world ); error: if (shared && shared != MAP_FAILED) { if (enter.fusion_id == FUSION_ID_MASTER) D_MAGIC_CLEAR( shared ); direct_file_unmap( shared, sizeof(FusionWorldShared) ); } if (fd != -1) close( fd ); direct_mutex_unlock( &fusion_worlds_lock ); direct_shutdown(); return ret; } DirectResult fusion_world_activate( FusionWorld *world ) { D_DEBUG_AT( Fusion_Main, " -> unblocking world...\n" ); while (ioctl( world->fusion_fd, FUSION_UNBLOCK )) { if (errno != EINTR) { D_PERROR( "Fusion/Main: Could not unblock world!\n" ); return DR_FUSION; } } return DR_OK; } DirectResult fusion_stop_dispatcher( FusionWorld *world, bool emergency ) { D_DEBUG_AT( Fusion_Main_Dispatch, "%s( %semergency )\n", __FUNCTION__, emergency ? "" : "no " ); if (!world->dispatch_loop) return DR_OK; if (!emergency) { fusion_sync( world ); D_DEBUG_AT( Fusion_Main_Dispatch, " -> locking thread...\n" ); direct_thread_lock( world->dispatch_loop ); } D_DEBUG_AT( Fusion_Main_Dispatch, " -> locked\n" ); world->dispatch_stop = true; if (!emergency) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> unlocking thread...\n" ); direct_thread_unlock( world->dispatch_loop ); fusion_sync( world ); } fcntl( world->fusion_fd, F_SETFL, O_NONBLOCK ); D_DEBUG_AT( Fusion_Main_Dispatch, " -> finished stopping\n" ); return DR_OK; } DirectResult fusion_exit( FusionWorld *world, bool emergency ) { DirectResult ret; D_DEBUG_AT( Fusion_Main, "%s( %p, %semergency )\n", __FUNCTION__, world, emergency ? "" : "no " ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( world->refs > 0 ); direct_mutex_lock( &fusion_worlds_lock ); if (--world->refs) { direct_mutex_unlock( &fusion_worlds_lock ); return DR_OK; } D_ASSUME( direct_thread_self() != world->dispatch_loop ); if (direct_thread_self() != world->dispatch_loop) { int foo; FusionSendMessage msg; /* Wake up the read loop thread. */ msg.fusion_id = world->fusion_id; msg.msg_id = 0; msg.msg_data = &foo; msg.msg_size = sizeof(foo); fusion_world_flush_calls( world, 1 ); while (ioctl( world->fusion_fd, FUSION_SEND_MESSAGE, &msg ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion/Main: FUSION_SEND_MESSAGE" ); direct_thread_cancel( world->dispatch_loop ); break; } } /* Wait for its termination. */ direct_thread_join( world->dispatch_loop ); } D_ASSUME( direct_thread_self() != world->deferred.thread ); /* Wake up the deferred call thread. */ direct_waitqueue_signal( &world->deferred.queue ); /* Wait for its termination. */ direct_thread_join( world->deferred.thread ); direct_thread_destroy( world->dispatch_loop ); direct_thread_destroy( world->deferred.thread ); direct_mutex_deinit( &world->deferred.lock ); direct_waitqueue_deinit( &world->deferred.queue ); direct_mutex_deinit( &world->refs_lock ); direct_map_destroy( world->refs_map ); /* Master has to deinitialize shared data. */ if (fusion_master( world )) { fusion_call_destroy( &world->shared->refs_call ); world->shared->refs--; if (world->shared->refs == 0) { fusion_skirmish_destroy( &world->shared->reactor_globals ); fusion_skirmish_destroy( &world->shared->arenas_lock ); fusion_shm_pool_destroy( world, world->shared->main_pool ); /* Deinitialize shared memory. */ fusion_shm_deinit( world ); } } else { /* Leave shared memory. */ fusion_shm_deinit( world ); } /* Reset local dispatch nodes. */ _fusion_reactor_free_all( world ); /* Remove world from global list. */ fusion_worlds[world->shared->world_index] = NULL; /* Unmap shared area. */ if (fusion_master( world ) && world->shared->refs == 0) { char tmpfs[FUSION_SHM_TMPFS_PATH_NAME_LEN]; char root_file[FUSION_SHM_TMPFS_PATH_NAME_LEN+32]; if (fusion_config->tmpfs) direct_snputs( tmpfs, fusion_config->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN ); else if (!fusion_find_tmpfs( tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN )) snprintf( tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN, "/dev/shm" ); snprintf( root_file, sizeof(root_file), "%s/fusion.%d", tmpfs, world->shared->world_index ); ret = direct_unlink( root_file ); if (ret) D_DERROR( ret, "Fusion/Main: Could not unlink shared memory file '%s'!\n", root_file ); D_MAGIC_CLEAR( world->shared ); } direct_file_unmap( world->shared, sizeof(FusionWorldShared) ); /* Close Fusion Kernel Device. */ close( world->fusion_fd ); /* Free local world data. */ D_MAGIC_CLEAR( world ); D_FREE( world ); direct_mutex_unlock( &fusion_worlds_lock ); direct_shutdown(); return DR_OK; } DirectResult fusion_kill( FusionWorld *world, FusionID fusion_id, int signal, int timeout_ms ) { FusionKill param; D_MAGIC_ASSERT( world, FusionWorld ); param.fusion_id = fusion_id; param.signal = signal; param.timeout_ms = timeout_ms; fusion_world_flush_calls( world, 1 ); while (ioctl( world->fusion_fd, FUSION_KILL, ¶m )) { switch (errno) { case EINTR: continue; case ETIMEDOUT: return DR_TIMEOUT; default: break; } D_PERROR( "Fusion/Main: FUSION_KILL" ); return DR_FAILURE; } return DR_OK; } const char * fusion_get_tmpfs( FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); return world->shared->shm.tmpfs; } static DirectResult defer_message( FusionWorld *world, FusionReadMessage *header, void *data ) { DeferredCall *deferred; deferred = D_CALLOC( 1, sizeof(DeferredCall) + header->msg_size ); if (!deferred) return D_OOM(); deferred->header = *header; direct_memcpy( deferred + 1, data, header->msg_size ); direct_mutex_lock( &world->deferred.lock ); direct_list_append( &world->deferred.list, &deferred->link ); direct_mutex_unlock( &world->deferred.lock ); direct_waitqueue_signal( &world->deferred.queue ); return DR_OK; } DirectResult fusion_dispatch_cleanup_add( FusionWorld *world, FusionDispatchCleanupFunc func, void *ctx, FusionDispatchCleanup **ret_cleanup ) { FusionDispatchCleanup *cleanup; cleanup = D_CALLOC( 1, sizeof(FusionDispatchCleanup) ); if (!cleanup) return D_OOM(); cleanup->func = func; cleanup->ctx = ctx; direct_list_append( &world->dispatch_cleanups, &cleanup->link ); *ret_cleanup = cleanup; return DR_OK; } DirectResult fusion_dispatch_cleanup_remove( FusionWorld *world, FusionDispatchCleanup *cleanup ) { direct_list_remove( &world->dispatch_cleanups, &cleanup->link ); D_FREE( cleanup ); return DR_OK; } static void handle_dispatch_cleanups( FusionWorld *world ) { FusionDispatchCleanup *cleanup, *next; D_DEBUG_AT( Fusion_Main_Dispatch, "%s( %p )\n", __FUNCTION__, world ); direct_list_foreach_safe (cleanup, next, world->dispatch_cleanups) { if (direct_log_domain_check( &Fusion_Main_Dispatch )) D_DEBUG_AT( Fusion_Main_Dispatch, " -> %s (%p)\n", direct_trace_lookup_symbol_at( cleanup->func ), cleanup->ctx ); cleanup->func( cleanup->ctx ); D_FREE( cleanup ); } D_DEBUG_AT( Fusion_Main_Dispatch, " -> cleanups done\n" ); world->dispatch_cleanups = NULL; } static DirectEnumerationResult refs_iterate( DirectMap *map, void *object, void *ctx ) { FusionRefSlaveEntry *entry = object; if (entry->key.fusion_id == *((FusionID*) ctx)) { int i; for (i = 0; i < entry->refs; i++) fusion_ref_down( entry->ref, false ); D_FREE( entry ); return DENUM_REMOVE; } return DENUM_OK; } static void * fusion_dispatch_loop( DirectThread *thread, void *arg ) { ssize_t len = 0; size_t buf_size = FUSION_MESSAGE_SIZE * 4; char *buf = D_MALLOC( buf_size ); FusionWorld *world = arg; D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ ); D_MAGIC_ASSERT( world, FusionWorld ); direct_thread_lock( thread ); while (true) { char *buf_p = buf; if (world->dispatch_stop) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> ignoring (dispatch_stop)\n" ); goto out; } else { D_DEBUG_AT( Fusion_Main_Dispatch, "%s( world %p ) => read( "_ZU" )...\n", __FUNCTION__, world, buf_size ); direct_thread_unlock( thread ); len = read( world->fusion_fd, buf, buf_size ); direct_thread_lock( thread ); if (len < 0) { if (errno == EINTR) continue; break; } D_DEBUG_AT( Fusion_Main_Dispatch, "%s( world %p ) => got "_ZD" (of up to "_ZU")\n", __FUNCTION__, world, len, buf_size ); while (buf_p < buf + len) { FusionReadMessage *header = (FusionReadMessage*) buf_p; void *data = buf_p + sizeof(FusionReadMessage); D_DEBUG_AT( Fusion_Main_Dispatch, "%s( world %p ) => %p [%ld]\n", __FUNCTION__, world, header, (long) buf_p - (long) buf ); D_ASSERT( (buf + len - buf_p) >= sizeof(FusionReadMessage) ); switch (header->msg_type) { case FMT_SEND: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND!\n" ); break; case FMT_CALL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" ); if (((FusionCallMessage*) data)->caller == 0) handle_dispatch_cleanups( world ); /* If the call comes from kernel space it is most likely a destructor call, defer it. */ if (fusion_config->defer_destructors && ((FusionCallMessage*) data)->caller == 0) { defer_message( world, header, data ); } else { _fusion_call_process( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage)) ? data + sizeof(FusionCallMessage) : NULL ); } break; case FMT_REACTOR: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" ); _fusion_reactor_process_message( world, header->msg_id, header->msg_channel, data ); break; case FMT_SHMPOOL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SHMPOOL...\n" ); _fusion_shmpool_process( world, header->msg_id, data ); break; case FMT_CALL3: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL3...\n" ); _fusion_call_process3( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage3)) ? data + sizeof(FusionCallMessage3) : NULL ); break; case FMT_LEAVE: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_LEAVE...\n" ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &world->refs_lock ); direct_map_iterate( world->refs_map, refs_iterate, data ); direct_mutex_unlock( &world->refs_lock ); } if (world->leave_callback) world->leave_callback( world, *((FusionID*) data), world->leave_ctx ); break; default: D_DEBUG_AT( Fusion_Main_Dispatch, " -> discarding message of unknown type %u\n", header->msg_type ); break; } D_DEBUG_AT( Fusion_Main_Dispatch, " -> done\n" ); buf_p = data + ((header->msg_size + 3) & ~3); } } handle_dispatch_cleanups( world ); if (!world->refs) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" ); goto out; } } D_PERROR( "Fusion/Main: Reading from fusion device failed!\n" ); out: direct_thread_unlock( thread ); D_FREE( buf ); return NULL; } DirectResult fusion_dispatch( FusionWorld *world, size_t buf_size ) { ssize_t len = 0; char *buf; char *buf_p; D_DEBUG_AT( Fusion_Main_Dispatch, "%s( world %p, buf_size "_ZU" )\n", __FUNCTION__, world, buf_size ); D_MAGIC_ASSERT( world, FusionWorld ); if (buf_size == 0) buf_size = FUSION_MESSAGE_SIZE * 4; else D_ASSUME( buf_size >= FUSION_MESSAGE_SIZE ); buf = buf_p = D_MALLOC( buf_size ); D_DEBUG_AT( Fusion_Main_Dispatch, " -> dispatch => reading up to "_ZU" bytes...\n", buf_size ); while (true) { len = read( world->fusion_fd, buf, buf_size ); if (len < 0) { if (errno == EINTR) continue; if (errno != EAGAIN) D_PERROR( "Fusion/Main: Reading from fusion device failed!\n" ); D_FREE( buf ); return DR_IO; } break; } D_DEBUG_AT( Fusion_Main_Dispatch, " -> dispatch => got "_ZD" bytes (of up to "_ZU")\n", len, buf_size ); if (world->dispatch_loop) direct_thread_lock( world->dispatch_loop ); while (buf_p < buf + len) { FusionReadMessage *header = (FusionReadMessage*) buf_p; void *data = buf_p + sizeof(FusionReadMessage); D_DEBUG_AT( Fusion_Main_Dispatch, " -> dispatch => %p [%ld]\n", header, (long) buf_p - (long) buf ); D_ASSERT( (buf + len - buf_p) >= sizeof(FusionReadMessage) ); switch (header->msg_type) { case FMT_SEND: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND!\n" ); break; case FMT_CALL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" ); if (((FusionCallMessage*) data)->caller == 0) handle_dispatch_cleanups( world ); /* If the call comes from kernel space it is most likely a destructor call, defer it. */ if (fusion_config->defer_destructors && ((FusionCallMessage*) data)->caller == 0) { defer_message( world, header, data ); } else _fusion_call_process( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage)) ? data + sizeof(FusionCallMessage) : NULL ); break; case FMT_REACTOR: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" ); _fusion_reactor_process_message( world, header->msg_id, header->msg_channel, data ); break; case FMT_SHMPOOL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SHMPOOL...\n" ); _fusion_shmpool_process( world, header->msg_id, data ); break; case FMT_CALL3: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL3...\n" ); _fusion_call_process3( world, header->msg_id, data, (header->msg_size != sizeof(FusionCallMessage3)) ? data + sizeof(FusionCallMessage3) : NULL ); break; case FMT_LEAVE: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_LEAVE...\n" ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &world->refs_lock ); direct_map_iterate( world->refs_map, refs_iterate, data ); direct_mutex_unlock( &world->refs_lock ); } if (world->leave_callback) world->leave_callback( world, *((FusionID*) data), world->leave_ctx ); break; default: D_DEBUG_AT( Fusion_Main_Dispatch, " -> discarding message of unknown type '%u'\n", header->msg_type ); break; } D_DEBUG_AT( Fusion_Main_Dispatch, " -> done\n" ); buf_p = data + ((header->msg_size + 3) & ~3); } handle_dispatch_cleanups( world ); if (world->dispatch_loop) direct_thread_unlock( world->dispatch_loop ); D_FREE( buf ); return DR_OK; } DirectResult fusion_get_fusionee_path( const FusionWorld *world, FusionID fusion_id, char *buf, size_t buf_size, size_t *ret_size ) { FusionGetFusioneeInfo info; size_t len; D_ASSERT( world != NULL ); D_ASSERT( buf != NULL ); D_ASSERT( ret_size != NULL ); info.fusion_id = fusion_id; while (ioctl( world->fusion_fd, FUSION_GET_FUSIONEE_INFO, &info ) < 0) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Main: FUSION_GET_FUSIONEE_INFO" ); return DR_FUSION; } len = strlen( info.exe_file ) + 1; if (len > buf_size) { *ret_size = len; return DR_LIMITEXCEEDED; } direct_memcpy( buf, info.exe_file, len ); *ret_size = len; return DR_OK; } DirectResult fusion_get_fusionee_pid( const FusionWorld *world, FusionID fusion_id, pid_t *ret_pid ) { FusionGetFusioneeInfo info; D_ASSERT( world != NULL ); D_ASSERT( ret_pid != NULL ); info.fusion_id = fusion_id; while (ioctl( world->fusion_fd, FUSION_GET_FUSIONEE_INFO, &info ) < 0) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/main: FUSION_GET_FUSIONEE_INFO" ); return DR_FUSION; } *ret_pid = info.pid; return DR_OK; } DirectResult fusion_world_set_root( FusionWorld *world, void *root ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); if (world->fusion_id != FUSION_ID_MASTER) return DR_ACCESSDENIED; world->shared->world_root = root; return DR_OK; } void * fusion_world_get_root( FusionWorld *world ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); return world->shared->world_root; } DirectResult fusion_sync( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Main, "%s( %p )\n", __FUNCTION__, world ); D_DEBUG_AT( Fusion_Main, " -> syncing with fusion device...\n" ); while (ioctl( world->fusion_fd, FUSION_SYNC )) { switch (errno) { case EINTR: continue; default: break; } D_PERROR( "Fusion/Main: FUSION_SYNC" ); return DR_FAILURE; } D_DEBUG_AT( Fusion_Main, " -> synced\n" ); return DR_OK; } #else /* FUSION_BUILD_KERNEL */ typedef struct { DirectLink link; FusionRef *ref; int count; } FusioneeRef; typedef struct { DirectLink link; FusionID id; pid_t pid; DirectLink *refs; } Fusionee; static DirectResult _fusion_add_fusionee( FusionWorld *world, FusionID fusion_id ) { DirectResult ret; Fusionee *fusionee; D_DEBUG_AT( Fusion_Main, "%s( %p, %lu )\n", __FUNCTION__, world, fusion_id ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); fusionee = SHCALLOC( world->shared->main_pool, 1, sizeof(Fusionee) ); if (!fusionee) return D_OOSHM(); fusionee->id = fusion_id; fusionee->pid = direct_gettid(); ret = fusion_skirmish_prevail( &world->shared->fusionees_lock ); if (ret) { SHFREE( world->shared->main_pool, fusionee ); return ret; } direct_list_append( &world->shared->fusionees, &fusionee->link ); fusion_skirmish_dismiss( &world->shared->fusionees_lock ); /* Set local pointer. */ world->fusionee = fusionee; return DR_OK; } void _fusion_add_local( FusionWorld *world, FusionRef *ref, int add ) { Fusionee *fusionee; FusioneeRef *fusionee_ref; D_DEBUG_AT( Fusion_Main, "%s( %p, %p, %d )\n", __FUNCTION__, world, ref, add ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( world->fusionee != NULL ); D_ASSERT( ref != NULL ); fusionee = world->fusionee; direct_list_foreach (fusionee_ref, fusionee->refs) { if (fusionee_ref->ref == ref) break; } if (fusionee_ref) { fusionee_ref->count += add; D_DEBUG_AT( Fusion_Main, " -> refs = %d\n", fusionee_ref->count ); if (fusionee_ref->count == 0) { direct_list_remove( &fusionee->refs, &fusionee_ref->link ); SHFREE( world->shared->main_pool, fusionee_ref ); } } else { /* Check whether we are called from _fusion_remove_fusionee(). */ if (add <= 0) return; D_DEBUG_AT( Fusion_Main, " -> new ref\n" ); fusionee_ref = SHCALLOC( world->shared->main_pool, 1, sizeof(FusioneeRef) ); if (!fusionee_ref) { D_OOSHM(); return; } fusionee_ref->ref = ref; fusionee_ref->count = add; direct_list_prepend( &fusionee->refs, &fusionee_ref->link ); } } void _fusion_check_locals( FusionWorld *world, FusionRef *ref ) { DirectResult ret; Fusionee *fusionee; FusioneeRef *fusionee_ref, *next; DirectLink *list = NULL; D_DEBUG_AT( Fusion_Main, "%s( %p, %p )\n", __FUNCTION__, world, ref ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( ref != NULL ); if (fusion_skirmish_prevail( &world->shared->fusionees_lock )) return; direct_list_foreach (fusionee, world->shared->fusionees) { if (fusionee->id == world->fusion_id) continue; direct_list_foreach (fusionee_ref, fusionee->refs) { if (fusionee_ref->ref == ref) { ret = direct_kill( fusionee->pid, 0 ); if (ret == DR_NOSUCHINSTANCE) { direct_list_remove( &fusionee->refs, &fusionee_ref->link ); direct_list_append( &list, &fusionee_ref->link ); } break; } } } fusion_skirmish_dismiss( &world->shared->fusionees_lock ); direct_list_foreach_safe (fusionee_ref, next, list) { _fusion_ref_change( ref, -fusionee_ref->count, false ); SHFREE( world->shared->main_pool, fusionee_ref ); } } void _fusion_remove_all_locals( FusionWorld *world, const FusionRef *ref ) { Fusionee *fusionee; FusioneeRef *fusionee_ref, *next; D_DEBUG_AT( Fusion_Main, "%s( %p, %p )\n", __FUNCTION__, world, ref ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( ref != NULL ); if (fusion_skirmish_prevail( &world->shared->fusionees_lock )) return; direct_list_foreach (fusionee, world->shared->fusionees) { direct_list_foreach_safe (fusionee_ref, next, fusionee->refs) { if (fusionee_ref->ref == ref) { direct_list_remove( &fusionee->refs, &fusionee_ref->link ); SHFREE( world->shared->main_pool, fusionee_ref ); } } } fusion_skirmish_dismiss( &world->shared->fusionees_lock ); } static void _fusion_remove_fusionee( FusionWorld *world, FusionID fusion_id ) { Fusionee *fusionee; FusioneeRef *fusionee_ref, *next; D_DEBUG_AT( Fusion_Main, "%s( %p, %lu )\n", __FUNCTION__, world, fusion_id ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); fusion_skirmish_prevail( &world->shared->fusionees_lock ); if (fusion_id == world->fusion_id) { fusionee = world->fusionee; } else { direct_list_foreach (fusionee, world->shared->fusionees) { if (fusionee->id == fusion_id) break; } } if (!fusionee) { D_DEBUG_AT( Fusion_Main, " -> fusionee %lu not found!\n", fusion_id ); fusion_skirmish_dismiss( &world->shared->fusionees_lock ); return; } direct_list_remove( &world->shared->fusionees, &fusionee->link ); fusion_skirmish_dismiss( &world->shared->fusionees_lock ); direct_list_foreach_safe (fusionee_ref, next, fusionee->refs) { direct_list_remove( &fusionee->refs, &fusionee_ref->link ); _fusion_ref_change( fusionee_ref->ref, -fusionee_ref->count, false ); SHFREE( world->shared->main_pool, fusionee_ref ); } SHFREE( world->shared->main_pool, fusionee ); } DirectResult _fusion_send_message( int fd, const void *msg, size_t msg_size, struct sockaddr_un *addr ) { socklen_t addrlen = sizeof(struct sockaddr_un); D_ASSERT( msg != NULL ); if (!addr) { addr = alloca( sizeof(struct sockaddr_un) ); getsockname( fd, (struct sockaddr*) addr, &addrlen ); } while (sendto( fd, msg, msg_size, 0, (struct sockaddr*) addr, addrlen ) < 0) { switch (errno) { case EINTR: continue; case ECONNREFUSED: return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Main: sendto() failed!\n" ); return DR_IO; } return DR_OK; } DirectResult _fusion_recv_message( int fd, void *msg, size_t msg_size, struct sockaddr_un *addr ) { socklen_t addrlen = addr ? sizeof(struct sockaddr_un) : 0; D_ASSERT( msg != NULL ); while (recvfrom( fd, msg, msg_size, 0, (struct sockaddr*) addr, &addrlen ) < 0) { switch (errno) { case EINTR: continue; case ECONNREFUSED: return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Main: recvfrom() failed!\n" ); return DR_IO; } return DR_OK; } static void fusion_fork_handler_prepare() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_PREPARE ); } } static void fusion_fork_handler_parent() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_PARENT ); if (world->fork_action == FFA_FORK) { /* Increase the shared reference counter. */ if (fusion_master( world )) world->shared->refs++; /* Cancel the dispatcher to prevent conflicts. */ direct_thread_cancel( world->dispatch_loop ); } } } static void fusion_fork_handler_child() { int i; D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ ); for (i = 0; i < FUSION_MAX_WORLDS; i++) { FusionWorld *world = fusion_worlds[i]; if (!world) continue; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); if (world->fork_callback) world->fork_callback( world->fork_action, FFS_CHILD ); switch (world->fork_action) { default: D_BUG( "unknown fork action %u", world->fork_action ); case FFA_CLOSE: D_DEBUG_AT( Fusion_Main, " -> closing world %d\n", i ); /* Remove world from global list. */ fusion_worlds[i] = NULL; /* Unmap shared area. */ direct_file_unmap( world->shared, sizeof(FusionWorldShared) ); /* Close socket. */ close( world->fusion_fd ); /* Free local world data. */ D_MAGIC_CLEAR( world ); D_FREE( world ); break; case FFA_FORK: { Fusionee *fusionee; FusioneeRef *fusionee_ref; D_DEBUG_AT( Fusion_Main, " -> forking in world %d\n", i ); fusionee = world->fusionee; D_DEBUG_AT( Fusion_Main, " -> duplicating fusion id %lu\n", world->fusion_id ); fusion_skirmish_prevail( &world->shared->fusionees_lock ); if (_fusion_add_fusionee( world, world->fusion_id )) { fusion_skirmish_dismiss( &world->shared->fusionees_lock ); raise( SIGTRAP ); } D_DEBUG_AT( Fusion_Main, " -> duplicating local refs...\n" ); direct_list_foreach (fusionee_ref, fusionee->refs) { FusioneeRef *new_ref; new_ref = SHCALLOC( world->shared->main_pool, 1, sizeof(FusioneeRef) ); if (!new_ref) { D_OOSHM(); fusion_skirmish_dismiss( &world->shared->fusionees_lock ); raise( SIGTRAP ); } new_ref->ref = fusionee_ref->ref; new_ref->count = fusionee_ref->count; /* Avoid locking. */ new_ref->ref->multi.builtin.local += new_ref->count; direct_list_append( &((Fusionee*) world->fusionee)->refs, &new_ref->link ); } fusion_skirmish_dismiss( &world->shared->fusionees_lock ); D_DEBUG_AT( Fusion_Main, " -> restarting dispatcher loop...\n" ); /* Restart the dispatcher thread. */ world->dispatch_loop = direct_thread_create( DTT_MESSAGING, fusion_dispatch_loop, world, "Fusion Dispatch" ); if (!world->dispatch_loop) raise( SIGTRAP ); break; } } } } DirectResult fusion_enter( int world_index, int abi_version, FusionEnterRole role, FusionWorld **ret_world ) { DirectResult ret = DR_OK; int orig_index = world_index; int fd = -1; FusionID id = -1; FusionWorld *world = NULL; FusionWorldShared *shared = MAP_FAILED; struct sockaddr_un addr; char buf[128]; int err; int len; D_DEBUG_AT( Fusion_Main, "%s( %d, %d, %p )\n", __FUNCTION__, world_index, abi_version, ret_world ); D_ASSERT( ret_world != NULL ); if (world_index >= FUSION_MAX_WORLDS) { D_ERROR( "Fusion/Main: World index %d exceeds maximum index %d!\n", world_index, FUSION_MAX_WORLDS - 1 ); return DR_INVARG; } if (fusion_config->force_slave) role = FER_SLAVE; direct_once( &fusion_init_once, init_once ); direct_initialize(); direct_mutex_lock( &fusion_worlds_lock ); retry: world_index = orig_index; fd = -1; id = -1; world = NULL; shared = MAP_FAILED; fd = socket( PF_LOCAL, SOCK_RAW, 0 ); if (fd < 0) { D_PERROR( "Fusion/Main: Error creating local socket!\n" ); direct_mutex_unlock( &fusion_worlds_lock ); return DR_IO; } /* Set close-on-exec flag. */ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0) D_PERROR( "Fusion/Main: Setting FD_CLOEXEC flag failed!\n" ); addr.sun_family = AF_UNIX; if (world_index < 0) { if (role == FER_SLAVE) { D_ERROR( "Fusion/Main: Slave role and a new world (index -1) was requested!\n" ); direct_mutex_unlock( &fusion_worlds_lock ); close( fd ); return DR_INVARG; } for (world_index = 0; world_index < FUSION_MAX_WORLDS; world_index++) { if (fusion_worlds[world_index]) continue; len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/", world_index ); /* Make socket directory if it doesn't exits. */ ret = direct_dir_create( addr.sun_path, 0775 ); if (ret == DR_OK) { if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); } snprintf( addr.sun_path + len, sizeof(addr.sun_path) - len, "%lx", (unsigned long) FUSION_ID_MASTER ); /* Bind to address. */ err = bind( fd, (struct sockaddr*) &addr, sizeof(addr) ); if (err == 0) { direct_chmod( addr.sun_path, 0660 ); /* Change group, if requested. */ if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); id = FUSION_ID_MASTER; break; } } } else { world = fusion_worlds[world_index]; if (!world) { len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/", world_index ); /* Make socket directory if it doesn't exits. */ ret = direct_dir_create( addr.sun_path, 0775 ); if (ret == DR_OK) { if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); } /* Check wether we are master. */ snprintf( addr.sun_path + len, sizeof(addr.sun_path) - len, "%lx", (unsigned long) FUSION_ID_MASTER ); err = bind( fd, (struct sockaddr*) &addr, sizeof(addr) ); if (err < 0) { if (role == FER_MASTER) { D_ERROR( "Fusion/Main: Could not start session as master -> remove %s!\n", addr.sun_path ); ret = DR_INIT; goto error; } /* Auto generate slave id. */ for (id = FUSION_ID_MASTER + 1; id < (FusionID) -1; id++) { snprintf( addr.sun_path + len, sizeof(addr.sun_path) - len, "%lx", id ); err = bind( fd, (struct sockaddr*) &addr, sizeof(addr) ); if (err == 0) { direct_chmod( addr.sun_path, 0660 ); /* Change group, if requested. */ if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); break; } } } else if (err == 0 && role != FER_SLAVE) { direct_chmod( addr.sun_path, 0660 ); /* Change group, if requested. */ if (fusion_config->shmfile_gid != -1) direct_chown( addr.sun_path, -1, fusion_config->shmfile_gid ); id = FUSION_ID_MASTER; } } } /* Enter a world again. */ if (world) { D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( world->refs > 0 ); /* Check the role again. */ switch (role) { case FER_MASTER: if (world->fusion_id != FUSION_ID_MASTER) { D_ERROR( "Fusion/Main: Master role requested for a world (%d), but we are already slave in!\n", world_index ); ret = DR_UNSUPPORTED; goto error; } break; case FER_SLAVE: if (world->fusion_id == FUSION_ID_MASTER) { D_ERROR( "Fusion/Main: Slave role requested for a world (%d), but we are already master in!\n", world_index ); ret = DR_UNSUPPORTED; goto error; } break; case FER_ANY: break; } shared = world->shared; D_MAGIC_ASSERT( shared, FusionWorldShared ); if (shared->world_abi != abi_version) { D_ERROR( "Fusion/Main: World ABI (%d) of world '%d' doesn't match own (%d)!\n", shared->world_abi, world_index, abi_version ); ret = DR_VERSIONMISMATCH; goto error; } world->refs++; direct_mutex_unlock( &fusion_worlds_lock ); D_DEBUG_AT( Fusion_Main, " -> using existing world %p [%d]\n", world, world_index ); close( fd ); /* Return the world. */ *ret_world = world; return DR_OK; } if (id == (FusionID) -1) { D_ERROR( "Fusion/Main: Opening fusion socket (world %d) as '%s' failed!\n", world_index, role == FER_ANY ? "any" : (role == FER_MASTER ? "master" : "slave") ); ret = DR_INIT; goto error; } D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", id ); if (id == FUSION_ID_MASTER) { DirectFile shared_fd; snprintf( buf, sizeof(buf), "%s/fusion.%d.core", fusion_config->tmpfs ?: "/dev/shm", world_index ); /* Open shared memory file. */ ret = direct_file_open( &shared_fd, buf, O_RDWR | O_CREAT | O_TRUNC, 0660 ); if (ret) { D_DERROR( ret, "Fusion/Main: Could not open shared memory file '%s'!\n", buf ); ret = DR_INIT; goto error; } if (fusion_config->shmfile_gid != -1) { if (direct_file_chown( &shared_fd, -1, fusion_config->shmfile_gid )) D_INFO( "Fusion/Main: Changing owner on '%s' failed... continuing on\n", buf ); } direct_file_chmod( &shared_fd, 0660 ); direct_file_truncate( &shared_fd, sizeof(FusionWorldShared) ); unsigned long size = direct_page_align( sizeof(FusionWorldShared) ); unsigned long base = (unsigned long) 0x20000000 + (size + direct_pagesize()) * world_index; /* Map shared area. */ ret = direct_file_map( &shared_fd, (void*) base, 0, size, DFP_READ | DFP_WRITE, (void**) &shared ); if (ret) { D_DERROR( ret, "Fusion/Main: Mapping shared area failed!\n" ); direct_file_close( &shared_fd ); ret = DR_INIT; goto error; } direct_file_close( &shared_fd ); D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size "_ZU"\n", shared, sizeof(FusionWorldShared) ); /* Initialize reference counter. */ shared->refs = 1; /* Set ABI version. */ shared->world_abi = abi_version; /* Set the world index. */ shared->world_index = world_index; /* Set pool allocation base/max. */ shared->pool_base = (void*) 0x20000000 + (size + direct_pagesize())*FUSION_MAX_WORLDS + 0x8000000*world_index; shared->pool_max = shared->pool_base + 0x8000000 - 1; /* Set start time of world clock. */ shared->start_time = direct_clock_get_time( DIRECT_CLOCK_SESSION ); D_MAGIC_SET( shared, FusionWorldShared ); } else { FusionEnter enter; DirectFile shared_fd; /* Fill enter information. */ enter.type = FMT_ENTER; enter.fusion_id = id; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", world_index, (unsigned long) FUSION_ID_MASTER ); /* Send enter message (used to sync with the master). */ ret = _fusion_send_message( fd, &enter, sizeof(FusionEnter), &addr ); if (ret == DR_DESTROYED) { DirectDir dir; DirectEntry entry; D_DEBUG_AT( Fusion_Main, " -> master seems dead, cleaning up...\n" ); snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d", world_index ); ret = direct_dir_open( &dir, addr.sun_path ); if (ret) { D_DERROR( ret, "Fusion/Main: Error opening directory '%s' for cleanup!\n", addr.sun_path ); /* Unbind. */ socklen_t addrlen = sizeof(addr); if (getsockname( fd, (struct sockaddr*) &addr, &addrlen ) == 0) direct_unlink( addr.sun_path ); close( fd ); ret = DR_INIT; goto error; } while (direct_dir_read( &dir, &entry ) == DR_OK) { if (!strcmp( entry.name, "." ) || !strcmp( entry.name, ".." )) continue; /* sizeof(addr.sun_path) = 108 */ snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%.83s", world_index, entry.name ); D_DEBUG_AT( Fusion_Main, " -> removing '%s'\n", addr.sun_path ); ret = direct_unlink( addr.sun_path ); if (ret) { D_DERROR( ret, "Fusion/Main: Error deleting '%s' for cleanup!\n", addr.sun_path ); direct_dir_close( &dir ); /* Unbind. */ socklen_t addrlen = sizeof(addr); if (getsockname( fd, (struct sockaddr*) &addr, &addrlen ) == 0) direct_unlink( addr.sun_path ); close( fd ); ret = DR_ACCESSDENIED; goto error; } } direct_dir_close( &dir ); /* Unbind. */ socklen_t addrlen = sizeof(addr); if (getsockname( fd, (struct sockaddr*) &addr, &addrlen ) == 0) direct_unlink( addr.sun_path ); close( fd ); D_DEBUG_AT( Fusion_Main, " -> retrying...\n" ); goto retry; } if (ret) D_DERROR( ret, "Fusion/Main: Send message failed!\n" ); if (ret == DR_OK) { ret = _fusion_recv_message( fd, &enter, sizeof(FusionEnter), NULL ); if (ret) D_DERROR( ret, "Fusion/Main: Receive message failed!\n" ); if (ret == DR_OK && enter.type != FMT_ENTER) { D_ERROR( "Fusion/Main: Expected message ENTER, got '%u'!\n", enter.type ); ret = DR_FUSION; } } if (ret) { D_ERROR( "Fusion/Main: Could not enter world '%d'!\n", world_index ); goto error; } snprintf( buf, sizeof(buf), "%s/fusion.%d.core", fusion_config->tmpfs ?: "/dev/shm", world_index ); /* Open shared memory file. */ ret = direct_file_open( &shared_fd, buf, O_RDWR, 0 ); if (ret) { D_DERROR( ret, "Fusion/Main: Could not open shared memory file '%s'!\n", buf ); ret = DR_INIT; goto error; } unsigned long size = direct_page_align( sizeof(FusionWorldShared) ); unsigned long base = (unsigned long) 0x20000000 + (size + direct_pagesize()) * world_index; /* Map shared area. */ ret = direct_file_map( &shared_fd, (void*) base, 0, size, DFP_READ | DFP_WRITE, (void**) &shared ); if (ret) { D_DERROR( ret, "Fusion/Main: Mapping shared area failed!\n" ); direct_file_close( &shared_fd ); ret = DR_INIT; goto error; } direct_file_close( &shared_fd ); D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size "_ZU"\n", shared, sizeof(FusionWorldShared) ); D_MAGIC_ASSERT( shared, FusionWorldShared ); /* Check ABI version. */ if (shared->world_abi != abi_version) { D_ERROR( "Fusion/Main: World ABI (%d) doesn't match own (%d)!\n", shared->world_abi, abi_version ); ret = DR_VERSIONMISMATCH; goto error; } } /* Synchronize to world clock. */ direct_clock_set_time( DIRECT_CLOCK_SESSION, shared->start_time ); /* Allocate local data. */ world = D_CALLOC( 1, sizeof(FusionWorld) ); if (!world) { ret = D_OOM(); goto error; } /* Initialize local data. */ world->refs = 1; world->shared = shared; world->fusion_fd = fd; world->fusion_id = id; D_MAGIC_SET( world, FusionWorld ); fusion_worlds[world_index] = world; /* Initialize shared memory part. */ ret = fusion_shm_init( world ); if (ret) goto error2; D_DEBUG_AT( Fusion_Main, " -> initializing other parts...\n" ); direct_mutex_init( &world->refs_lock ); /* Initialize other parts. */ if (world->fusion_id == FUSION_ID_MASTER) { fusion_skirmish_init( &shared->arenas_lock, "Fusion Arenas", world ); fusion_skirmish_init( &shared->reactor_globals, "Fusion Reactor Globals", world ); fusion_skirmish_init( &shared->fusionees_lock, "Fusionees", world ); /* Create the main pool. */ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x100000, fusion_config->debugshm, &shared->main_pool ); if (ret) goto error3; fusion_hash_create( shared->main_pool, HASH_INT, HASH_PTR, 109, &shared->call_hash ); fusion_call_init( &shared->refs_call, world_refs_call, world, world ); fusion_call_set_name( &shared->refs_call, "world_refs" ); fusion_call_add_permissions( &shared->refs_call, 0, FUSION_CALL_PERMIT_EXECUTE ); direct_map_create( 37, refs_map_compare, refs_map_hash, world, &world->refs_map ); } else { direct_map_create( 37, refs_map_slave_compare, refs_map_slave_hash, world, &world->refs_map ); } /* Add ourselves to the list of fusionees. */ ret = _fusion_add_fusionee( world, id ); if (ret) goto error4; D_DEBUG_AT( Fusion_Main, " -> starting dispatcher loop...\n" ); /* Start the dispatcher thread. */ world->dispatch_loop = direct_thread_create( DTT_MESSAGING, fusion_dispatch_loop, world, "Fusion Dispatch" ); if (!world->dispatch_loop) { ret = DR_FAILURE; goto error5; } D_DEBUG_AT( Fusion_Main, " -> done (%p)\n", world ); direct_mutex_unlock( &fusion_worlds_lock ); /* Return the fusion world. */ *ret_world = world; return DR_OK; error5: if (world->dispatch_loop) direct_thread_destroy( world->dispatch_loop ); _fusion_remove_fusionee( world, id ); error4: if (world->fusion_id == FUSION_ID_MASTER) fusion_shm_pool_destroy( world, shared->main_pool ); error3: if (world->fusion_id == FUSION_ID_MASTER) { fusion_skirmish_destroy( &shared->arenas_lock ); fusion_skirmish_destroy( &shared->reactor_globals ); fusion_skirmish_destroy( &shared->fusionees_lock ); } fusion_shm_deinit( world ); error2: fusion_worlds[world_index] = world; D_MAGIC_CLEAR( world ); D_FREE( world ); error: if (shared != MAP_FAILED) { if (id == FUSION_ID_MASTER) D_MAGIC_CLEAR( shared ); direct_file_unmap( shared, sizeof(FusionWorldShared) ); } if (fd != -1) { /* Unbind. */ socklen_t addrlen = sizeof(addr); if (getsockname( fd, (struct sockaddr*) &addr, &addrlen ) == 0) direct_unlink( addr.sun_path ); close( fd ); } direct_mutex_unlock( &fusion_worlds_lock ); direct_shutdown(); return ret; } DirectResult fusion_world_activate( FusionWorld *world ) { return DR_OK; } DirectResult fusion_stop_dispatcher( FusionWorld *world, bool emergency ) { if (!world->dispatch_loop) return DR_OK; if (!emergency) { fusion_sync( world ); direct_thread_lock( world->dispatch_loop ); } world->dispatch_stop = true; if (!emergency) { direct_thread_unlock( world->dispatch_loop ); fusion_sync( world ); } return DR_OK; } DirectResult fusion_exit( FusionWorld *world, bool emergency ) { DirectResult ret; int world_index; bool clear = false; D_DEBUG_AT( Fusion_Main, "%s( %p, %semergency )\n", __FUNCTION__, world, emergency ? "" : "no " ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( world->refs > 0 ); world_index = world->shared->world_index; direct_mutex_lock( &fusion_worlds_lock ); if (--world->refs) { direct_mutex_unlock( &fusion_worlds_lock ); return DR_OK; } if (!emergency) { FusionMessageType msg = FMT_SEND; /* Wakeup dispatcher. */ if (_fusion_send_message( world->fusion_fd, &msg, sizeof(msg), NULL )) direct_thread_cancel( world->dispatch_loop ); /* Wait for its termination. */ direct_thread_join( world->dispatch_loop ); } direct_thread_destroy( world->dispatch_loop ); /* Remove ourselves from list. */ if (!emergency || fusion_master( world )) { _fusion_remove_fusionee( world, world->fusion_id ); } else { struct sockaddr_un addr; FusionLeave leave; addr.sun_family = AF_UNIX; snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/%lx", world_index, (unsigned long) FUSION_ID_MASTER ); leave.type = FMT_LEAVE; leave.fusion_id = world->fusion_id; _fusion_send_message( world->fusion_fd, &leave, sizeof(FusionLeave), &addr ); } direct_mutex_deinit( &world->refs_lock ); direct_map_destroy( world->refs_map ); /* Master has to deinitialize shared data. */ if (fusion_master( world )) { fusion_call_destroy( &world->shared->refs_call ); fusion_hash_destroy( world->shared->call_hash ); world->shared->refs--; if (world->shared->refs == 0) { fusion_skirmish_destroy( &world->shared->reactor_globals ); fusion_skirmish_destroy( &world->shared->arenas_lock ); fusion_skirmish_destroy( &world->shared->fusionees_lock ); fusion_shm_pool_destroy( world, world->shared->main_pool ); /* Deinitialize shared memory. */ fusion_shm_deinit( world ); clear = true; } } else { /* Leave shared memory. */ fusion_shm_deinit( world ); } /* Reset local dispatch nodes. */ _fusion_reactor_free_all( world ); /* Remove world from global list. */ fusion_worlds[world->shared->world_index] = NULL; /* Unmap shared area. */ if (clear) D_MAGIC_CLEAR( world->shared ); direct_file_unmap( world->shared, sizeof(FusionWorldShared) ); /* Close socket. */ close( world->fusion_fd ); if (clear) { DirectDir dir; char buf[128]; int len; /* Remove core shmfile. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.core", fusion_config->tmpfs ?: "/dev/shm", world_index ); D_DEBUG_AT( Fusion_Main, " -> removing shmfile %s\n", buf ); direct_unlink( buf ); /* Cleanup socket directory. */ len = snprintf( buf, sizeof(buf), "/tmp/.fusion-%d/", world_index ); ret = direct_dir_open( &dir, buf ); if (ret == DR_OK) { DirectEntry entry; while (direct_dir_read( &dir, &entry ) == DR_OK) { if (entry.name[0] != '.') { struct stat st; direct_snputs( buf + len, entry.name, sizeof(buf) - len ); if (stat( buf, &st ) == 0 && S_ISSOCK(st.st_mode)) { D_DEBUG_AT( Fusion_Main, " -> removing socket %s\n", buf ); direct_unlink( buf ); } } } direct_dir_close( &dir ); } else { D_DERROR( ret, "Fusion/Main: Could not open socket directory %s", buf ); } } /* Free local world data. */ D_MAGIC_CLEAR( world ); D_FREE( world ); D_DEBUG_AT( Fusion_Main, "%s( %p ) done\n", __FUNCTION__, world ); direct_mutex_unlock( &fusion_worlds_lock ); direct_shutdown(); return DR_OK; } DirectResult fusion_kill( FusionWorld *world, FusionID fusion_id, int signal, int timeout_ms ) { DirectResult ret; Fusionee *fusionee, *next; D_DEBUG_AT( Fusion_Main, "%s( %p, %lu, %d, %d )\n", __FUNCTION__, world, fusion_id, signal, timeout_ms ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); fusion_skirmish_prevail( &world->shared->fusionees_lock ); direct_list_foreach_safe (fusionee, next, world->shared->fusionees) { if (fusion_id == 0 && fusionee->id == world->fusion_id) continue; if (fusion_id != 0 && fusionee->id != fusion_id) continue; D_DEBUG_AT( Fusion_Main, " -> killing fusionee %lu (%d)...\n", fusionee->id, fusionee->pid ); ret = direct_kill( fusionee->pid, signal ); if (ret == DR_OK && timeout_ms >= 0) { pid_t pid = fusionee->pid; long long stop = timeout_ms ? (direct_clock_get_micros() + timeout_ms*1000) : 0; fusion_skirmish_dismiss( &world->shared->fusionees_lock ); while (direct_kill( pid, 0 ) == 0) { usleep( 1000 ); if (timeout_ms && direct_clock_get_micros() >= stop) break; }; fusion_skirmish_prevail( &world->shared->fusionees_lock ); } else { if (ret == DR_NOSUCHINSTANCE) { D_DEBUG_AT( Fusion_Main, " ... fusionee %lu exited without removing itself\n", fusionee->id ); _fusion_remove_fusionee( world, fusionee->id ); } else { D_DERROR( ret, "Fusion/Main: direct_kill( %d, %d ) failed!\n", fusionee->pid, signal ); } } } fusion_skirmish_dismiss( &world->shared->fusionees_lock ); return DR_OK; } const char * fusion_get_tmpfs( FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); return "/tmp"; } DirectResult fusion_dispatch_cleanup_add( FusionWorld *world, FusionDispatchCleanupFunc func, void *ctx, FusionDispatchCleanup **ret_cleanup ) { FusionDispatchCleanup *cleanup; cleanup = D_CALLOC( 1, sizeof(FusionDispatchCleanup) ); if (!cleanup) return D_OOM(); cleanup->func = func; cleanup->ctx = ctx; direct_list_append( &world->dispatch_cleanups, &cleanup->link ); *ret_cleanup = cleanup; return DR_OK; } DirectResult fusion_dispatch_cleanup_remove( FusionWorld *world, FusionDispatchCleanup *cleanup ) { direct_list_remove( &world->dispatch_cleanups, &cleanup->link ); D_FREE( cleanup ); return DR_OK; } static void handle_dispatch_cleanups( FusionWorld *world ) { FusionDispatchCleanup *cleanup, *next; D_DEBUG_AT( Fusion_Main_Dispatch, "%s( %p )\n", __FUNCTION__, world ); direct_list_foreach_safe (cleanup, next, world->dispatch_cleanups) { if (direct_log_domain_check( &Fusion_Main_Dispatch )) D_DEBUG_AT( Fusion_Main_Dispatch, " -> %s (%p)\n", direct_trace_lookup_symbol_at( cleanup->func ), cleanup->ctx ); cleanup->func( cleanup->ctx ); D_FREE( cleanup ); } D_DEBUG_AT( Fusion_Main_Dispatch, " -> cleanups done\n" ); world->dispatch_cleanups = NULL; } static DirectEnumerationResult refs_iterate( DirectMap *map, void *object, void *ctx ) { FusionRefSlaveEntry *entry = object; if (entry->key.fusion_id == *((FusionID*) ctx)) { int i; for (i = 0; i < entry->refs; i++) fusion_ref_down( entry->ref, false ); D_FREE( entry ); return DENUM_REMOVE; } return DENUM_OK; } static void * fusion_dispatch_loop( DirectThread *self, void *arg ) { FusionWorld *world = arg; struct sockaddr_un addr; socklen_t addrlen = sizeof(addr); fd_set set; char buf[FUSION_MESSAGE_SIZE]; D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ ); D_MAGIC_ASSERT( world, FusionWorld ); while (true) { int err; ssize_t msg_size; FD_ZERO( &set ); FD_SET( world->fusion_fd, &set ); err = select( world->fusion_fd + 1, &set, NULL, NULL, NULL ); if (err < 0) { switch (errno) { case EINTR: continue; default: D_PERROR( "Fusion/Main: select() failed!\n" ); return NULL; } } if (FD_ISSET( world->fusion_fd, &set ) && (msg_size = recvfrom( world->fusion_fd, buf, sizeof(buf), 0, (struct sockaddr*) &addr, &addrlen )) > 0) { FusionMessage *msg = (FusionMessage*) buf; direct_thread_setcancelstate( DIRECT_THREAD_CANCEL_DISABLE ); D_DEBUG_AT( Fusion_Main_Dispatch, " -> message from '%s'...\n", addr.sun_path ); direct_thread_lock( self ); if (world->dispatch_stop) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> ignoring (dispatch_stop)\n" ); } else { switch (msg->type) { case FMT_SEND: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND!\n" ); break; case FMT_ENTER: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_ENTER...\n" ); if (!fusion_master( world )) { D_ERROR( "Fusion/Main/Dispatch: Got ENTER request, but we are not master!\n" ); break; } if (msg->enter.fusion_id == world->fusion_id) { D_ERROR( "Fusion/Main/Dispatch: ENTER request received from ourselves!\n" ); break; } _fusion_send_message( world->fusion_fd, msg, sizeof(FusionEnter), &addr ); break; case FMT_LEAVE: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_LEAVE...\n" ); if (!fusion_master( world )) { D_ERROR( "Fusion/Main/Dispatch: Got LEAVE request, but we are not master!\n" ); break; } if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &world->refs_lock ); direct_map_iterate( world->refs_map, refs_iterate, &msg->leave.fusion_id ); direct_mutex_unlock( &world->refs_lock ); } if (msg->leave.fusion_id == world->fusion_id) { D_ERROR( "Fusion/Main/Dispatch: LEAVE request received from ourselves!\n" ); break; } _fusion_remove_fusionee( world, msg->leave.fusion_id ); break; case FMT_CALL: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" ); if (((FusionCallMessage*) msg)->caller == 0) handle_dispatch_cleanups( world ); _fusion_call_process( world, msg->call.call_id, &msg->call, (msg_size != sizeof(FusionCallMessage)) ? (((FusionCallMessage*) msg) + 1) : NULL ); break; case FMT_REACTOR: D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" ); _fusion_reactor_process_message( world, msg->reactor.id, msg->reactor.channel, &buf[sizeof(FusionReactorMessage)] ); if (msg->reactor.ref) { fusion_ref_down( msg->reactor.ref, true ); if (fusion_ref_zero_trylock( msg->reactor.ref ) == DR_OK) { fusion_ref_destroy( msg->reactor.ref ); SHFREE( world->shared->main_pool, msg->reactor.ref ); } } break; default: D_BUG( "unexpected message type %u", msg->type ); break; } } handle_dispatch_cleanups( world ); direct_thread_unlock( self ); if (!world->refs) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" ); return NULL; } D_DEBUG_AT( Fusion_Main_Dispatch, " -> done\n" ); direct_thread_setcancelstate( DIRECT_THREAD_CANCEL_ENABLE ); } } return NULL; } DirectResult fusion_dispatch( FusionWorld *world, size_t buf_size ) { return DR_OK; } DirectResult fusion_get_fusionee_path( const FusionWorld *world, FusionID fusion_id, char *buf, size_t buf_size, size_t *ret_size ) { D_ASSERT( world != NULL ); D_ASSERT( buf != NULL ); D_ASSERT( ret_size != NULL ); *buf = '\0'; *ret_size = 0; return DR_UNIMPLEMENTED; } DirectResult fusion_get_fusionee_pid( const FusionWorld *world, FusionID fusion_id, pid_t *ret_pid ) { D_ASSERT( world != NULL ); return DR_UNIMPLEMENTED; } DirectResult fusion_world_set_root( FusionWorld *world, void *root ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); if (world->fusion_id != FUSION_ID_MASTER) return DR_ACCESSDENIED; world->shared->world_root = root; return DR_OK; } void * fusion_world_get_root( FusionWorld *world ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); return world->shared->world_root; } DirectResult fusion_sync( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Main, "%s( %p )\n", __FUNCTION__, world ); D_DEBUG_AT( Fusion_Main, " -> syncing with fusion device...\n" ); D_DEBUG_AT( Fusion_Main, " -> synced\n" ); return DR_OK; } #endif /* FUSION_BUILD_KERNEL */ void fusion_world_set_fork_action( FusionWorld *world, FusionForkAction action ) { D_MAGIC_ASSERT( world, FusionWorld ); world->fork_action = action; } FusionForkAction fusion_world_get_fork_action( FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return world->fork_action; } void fusion_world_set_fork_callback( FusionWorld *world, FusionForkCallback callback ) { D_MAGIC_ASSERT( world, FusionWorld ); world->fork_callback = callback; } void fusion_world_set_leave_callback( FusionWorld *world, FusionLeaveCallback callback, void *ctx ) { D_MAGIC_ASSERT( world, FusionWorld ); world->leave_callback = callback; world->leave_ctx = ctx; } int fusion_world_index( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); return world->shared->world_index; } FusionID fusion_id( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return world->fusion_id; } bool fusion_is_multi( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return true; } pid_t fusion_dispatcher_tid( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); if (world->dispatch_loop) return direct_thread_get_tid( world->dispatch_loop ); return 0; } bool fusion_master( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return world->fusion_id == FUSION_ID_MASTER; } bool fusion_is_shared( FusionWorld *world, const void *ptr ) { int i; DirectResult ret; FusionSHM *shm; D_MAGIC_ASSERT( world, FusionWorld ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); if (ptr >= (void*) world->shared && ptr < (void*) world->shared + sizeof(FusionWorldShared)) return true; ret = fusion_skirmish_prevail( &shm->shared->lock ); if (ret) return false; for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (shm->shared->pools[i].active) { FusionSHMPoolShared *pool = &shm->shared->pools[i]; shmalloc_heap *heap; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_MAGIC_ASSERT( pool->heap, shmalloc_heap ); heap = pool->heap; if (ptr >= pool->addr_base && ptr < pool->addr_base + heap->size) { fusion_skirmish_dismiss( &shm->shared->lock ); return true; } } } fusion_skirmish_dismiss( &shm->shared->lock ); return false; } #else /* FUSION_BUILD_MULTI */ static void * event_dispatcher_loop( DirectThread *thread, void *arg ) { const int call_size = sizeof(FusionEventDispatcherCall); FusionWorld *world = arg; D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ ); D_MAGIC_ASSERT( world, FusionWorld ); while (1) { FusionEventDispatcherBuffer *buf; direct_mutex_lock( &world->event_dispatcher_mutex ); while (1) { if (!world->event_dispatcher_buffers) direct_waitqueue_wait( &world->event_dispatcher_cond, &world->event_dispatcher_mutex ); buf = (FusionEventDispatcherBuffer*) world->event_dispatcher_buffers; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (buf->can_free && buf->read_pos == buf->write_pos) { direct_list_remove( &world->event_dispatcher_buffers, &buf->link ); direct_list_append( &world->event_dispatcher_buffers_remove, &buf->link ); D_DEBUG_AT( Fusion_Main_Dispatch, "Remove buffer %p free %d read %d write %d sync %d pending %d\n", buf, buf->can_free, buf->read_pos, buf->write_pos, buf->sync_calls, buf->pending ); continue; } if (buf->read_pos >= buf->write_pos) { D_DEBUG_AT( Fusion_Main_Dispatch, "Waiting buffer %p free %d read %d write %d sync %d pending %d\n", buf, buf->can_free, buf->read_pos, buf->write_pos, buf->sync_calls, buf->pending ); direct_waitqueue_wait( &world->event_dispatcher_cond, &world->event_dispatcher_mutex ); } buf = (FusionEventDispatcherBuffer*) world->event_dispatcher_buffers; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (buf->can_free && buf->read_pos == buf->write_pos) { direct_list_remove( &world->event_dispatcher_buffers, &buf->link ); direct_list_append( &world->event_dispatcher_buffers_remove, &buf->link ); D_DEBUG_AT( Fusion_Main_Dispatch, "Remove buffer %p free %d read %d write %d sync %d pending %d\n", buf, buf->can_free, buf->read_pos, buf->write_pos, buf->sync_calls, buf->pending ); continue; } break; } FusionEventDispatcherCall *msg = (FusionEventDispatcherCall*) &buf->buffer[buf->read_pos]; D_DEBUG_AT( Fusion_Main_Dispatch, "%s() got msg %p <- arg %d, reaction %d\n", __FUNCTION__, msg, msg->call_arg, msg->reaction ); D_DEBUG_AT( Fusion_Main_Dispatch, " -> processing buffer %p free %d read %d write %d sync %d pending %d\n", buf, buf->can_free, buf->read_pos, buf->write_pos, buf->sync_calls, buf->pending ); buf->read_pos += call_size; if (msg->flags & FCEF_ONEWAY) buf->read_pos += msg->length; /* Align on 4-byte boundaries. */ buf->read_pos = (buf->read_pos + 3) & ~3; if (world->dispatch_stop) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> ignoring (dispatch_stop)\n" ); FusionEventDispatcherBuffer *next; direct_list_foreach_safe (buf, next, world->event_dispatcher_buffers) { D_MAGIC_CLEAR( buf ); D_FREE( buf ); } direct_mutex_unlock( &world->event_dispatcher_mutex ); break; } else { direct_mutex_unlock( &world->event_dispatcher_mutex ); if (msg->call_handler3) { if (FCHR_RETAIN == msg->call_handler3( 1, msg->call_arg, msg->ptr, msg->length, msg->call_ctx, 0, msg->ret_ptr, msg->ret_size, &msg->ret_length )) D_WARN( "fusion dispatch => FCHR_RETAIN\n" ); } else if (msg->call_handler) { if (FCHR_RETAIN == msg->call_handler( 1, msg->call_arg, msg->ptr, msg->call_ctx, 0, &msg->ret_val )) D_WARN( "fusion dispatch => FCHR_RETAIN\n" ); } else if (msg->reaction == 1) { FusionReactor *reactor = msg->call_ctx; Reaction *reaction, *next; D_MAGIC_ASSERT( reactor, FusionReactor ); direct_mutex_lock( &reactor->reactions_lock ); direct_list_foreach_safe (reaction, next, reactor->reactions) { if ((long) reaction->node_link == msg->call_arg) { if (RS_REMOVE == reaction->func( msg->ptr, reaction->ctx )) direct_list_remove( &reactor->reactions, &reaction->link ); } } direct_mutex_unlock( &reactor->reactions_lock ); } else if (msg->reaction == 2) { FusionReactor *reactor = msg->call_ctx; fusion_reactor_free( reactor ); } else { D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" ); return NULL; } if (!(msg->flags & FCEF_ONEWAY)) { direct_mutex_lock( &world->event_dispatcher_call_mutex ); msg->processed = 1; direct_waitqueue_broadcast( &world->event_dispatcher_call_cond ); direct_mutex_unlock( &world->event_dispatcher_call_mutex ); } direct_mutex_lock( &world->event_dispatcher_mutex ); buf->pending--; } direct_waitqueue_signal( &world->event_dispatcher_process_cond ); if (world->event_dispatcher_buffers_remove) { buf = (FusionEventDispatcherBuffer*) world->event_dispatcher_buffers_remove; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (!buf->sync_calls && !buf->pending) { D_DEBUG_AT( Fusion_Main_Dispatch, "Free buffer %p free %d read %d write %d sync %d pending %d\n\n", buf, buf->can_free, buf->read_pos, buf->write_pos, buf->sync_calls, buf->pending ); direct_list_remove( &world->event_dispatcher_buffers_remove, &buf->link ); D_MAGIC_CLEAR( buf ); D_FREE( buf ); } } direct_mutex_unlock( &world->event_dispatcher_mutex ); if (!world->refs) { D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" ); return NULL; } } D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" ); return NULL; } DirectResult _fusion_event_dispatcher_process( FusionWorld *world, const FusionEventDispatcherCall *call, FusionEventDispatcherCall **ret ) { const int call_size = sizeof(FusionEventDispatcherCall); D_MAGIC_ASSERT( world, FusionWorld ); direct_mutex_lock( &world->event_dispatcher_mutex ); if (world->dispatch_stop) { direct_mutex_unlock( &world->event_dispatcher_mutex ); return DR_DESTROYED; } while (call->call_handler3 && (call->flags & FCEF_ONEWAY) && direct_list_count_elements_EXPENSIVE( world->event_dispatcher_buffers ) > 4) { direct_waitqueue_wait( &world->event_dispatcher_process_cond, &world->event_dispatcher_mutex ); } if (!world->event_dispatcher_buffers) { FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); } FusionEventDispatcherBuffer *buf = direct_list_get_last( world->event_dispatcher_buffers ); if (!buf) return DR_FAILURE; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (buf->write_pos + call_size + call->length > EVENT_DISPATCHER_BUFFER_LENGTH) { buf->can_free = 1; FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); buf = new_buf; } *ret = (FusionEventDispatcherCall*) &buf->buffer[buf->write_pos]; /* Copy data and signal dispatcher. */ direct_memcpy( *ret, call, call_size ); buf->write_pos += call_size; buf->pending++; if (!(call->flags & FCEF_ONEWAY)) buf->sync_calls++; /* Copy extra data to buffer. */ if (call->flags & FCEF_ONEWAY && call->length) { (*ret)->ptr = &buf->buffer[buf->write_pos]; direct_memcpy( (*ret)->ptr, call->ptr, call->length ); buf->write_pos += call->length; } /* Align on 4-byte boundaries. */ buf->write_pos = (buf->write_pos + 3) & ~3; direct_waitqueue_signal( &world->event_dispatcher_cond ); direct_mutex_unlock( &world->event_dispatcher_mutex ); if (!(call->flags & FCEF_ONEWAY)) { direct_mutex_lock( &world->event_dispatcher_call_mutex ); while (!(*ret)->processed) direct_waitqueue_wait( &world->event_dispatcher_call_cond, &world->event_dispatcher_call_mutex ); direct_mutex_unlock( &world->event_dispatcher_call_mutex ); direct_mutex_lock( &world->event_dispatcher_mutex ); buf->sync_calls--; direct_mutex_unlock( &world->event_dispatcher_mutex ); } return DR_OK; } DirectResult _fusion_event_dispatcher_process_reactions( FusionWorld *world, FusionReactor *reactor, int channel, void *msg_data, int msg_size ) { const int call_size = sizeof(FusionEventDispatcherCall); FusionEventDispatcherCall msg; FusionEventDispatcherCall *res; D_MAGIC_ASSERT( world, FusionWorld ); msg.processed = 0; msg.reaction = 1; msg.call_handler = 0; msg.call_handler3 = 0; msg.call_ctx = reactor; msg.flags = FCEF_ONEWAY; msg.call_arg = channel; msg.ptr = msg_data; msg.length = msg_size; msg.ret_val = 0; msg.ret_ptr = 0; msg.ret_size = 0; msg.ret_length = 0; direct_mutex_lock( &world->event_dispatcher_mutex ); if (world->dispatch_stop) { direct_mutex_unlock( &world->event_dispatcher_mutex ); return DR_DESTROYED; } if (!world->event_dispatcher_buffers) { FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); } FusionEventDispatcherBuffer *buf = direct_list_get_last( world->event_dispatcher_buffers ); if (!buf) return DR_FAILURE; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (buf->write_pos + call_size + msg_size > EVENT_DISPATCHER_BUFFER_LENGTH) { buf->can_free = 1; FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); buf = new_buf; } res = (FusionEventDispatcherCall*) &buf->buffer[buf->write_pos]; /* Copy data and signal dispatcher. */ direct_memcpy( res, &msg, call_size ); buf->write_pos += call_size; buf->pending++; /* Copy extra data to buffer. */ if (msg.length) { res->ptr = &buf->buffer[buf->write_pos]; direct_memcpy( res->ptr, msg.ptr, msg.length ); buf->write_pos += msg.length; } /* Align on 4-byte boundaries. */ buf->write_pos = (buf->write_pos + 3) & ~3; direct_waitqueue_signal( &world->event_dispatcher_cond ); direct_mutex_unlock( &world->event_dispatcher_mutex ); return DR_OK; } DirectResult _fusion_event_dispatcher_process_reactor_free( FusionWorld *world, FusionReactor *reactor ) { const int call_size = sizeof(FusionEventDispatcherCall); FusionEventDispatcherCall msg; FusionEventDispatcherCall *res; D_MAGIC_ASSERT( world, FusionWorld ); if (reactor->free) return DR_OK; reactor->free = 1; msg.processed = 0; msg.reaction = 2; msg.call_handler = 0; msg.call_handler3 = 0; msg.call_ctx = reactor; msg.flags = FCEF_ONEWAY; msg.call_arg = 0; msg.ptr = 0; msg.length = 0; msg.ret_val = 0; msg.ret_ptr = 0; msg.ret_size = 0; msg.ret_length = 0; direct_mutex_lock( &world->event_dispatcher_mutex ); if (world->dispatch_stop) { direct_mutex_unlock( &world->event_dispatcher_mutex ); return DR_DESTROYED; } if (!world->event_dispatcher_buffers) { FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); } FusionEventDispatcherBuffer *buf = direct_list_get_last( world->event_dispatcher_buffers ); if (!buf) return DR_FAILURE; D_MAGIC_ASSERT( buf, FusionEventDispatcherBuffer ); if (buf->write_pos + call_size > EVENT_DISPATCHER_BUFFER_LENGTH) { buf->can_free = 1; FusionEventDispatcherBuffer *new_buf = D_CALLOC( 1, sizeof(FusionEventDispatcherBuffer) ); D_MAGIC_SET( new_buf, FusionEventDispatcherBuffer ); direct_list_append( &world->event_dispatcher_buffers, &new_buf->link ); buf = new_buf; } res = (FusionEventDispatcherCall*) &buf->buffer[buf->write_pos]; /* Copy data and signal dispatcher. */ direct_memcpy( res, &msg, call_size ); buf->write_pos += call_size; buf->pending++; /* Align on 4-byte boundaries. */ buf->write_pos = (buf->write_pos + 3) & ~3; direct_waitqueue_signal( &world->event_dispatcher_cond ); direct_mutex_unlock( &world->event_dispatcher_mutex ); return DR_INCOMPLETE; } DirectResult fusion_enter( int world_index, int abi_version, FusionEnterRole role, FusionWorld **ret_world ) { DirectResult ret; FusionWorld *world = NULL; FusionWorldShared *shared = NULL; D_ASSERT( ret_world != NULL ); ret = direct_initialize(); if (ret) return ret; world = D_CALLOC( 1, sizeof(FusionWorld) ); if (!world) { ret = D_OOM(); goto error; } shared = D_CALLOC( 1, sizeof(FusionWorldShared) ); if (!shared) { ret = D_OOM(); goto error; } world->shared = shared; world->fusion_id = FUSION_ID_MASTER; /* Create the main pool. */ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x100000, fusion_config->debugshm, &shared->main_pool ); if (ret) goto error; D_MAGIC_SET( world, FusionWorld ); D_MAGIC_SET( world->shared, FusionWorldShared ); fusion_skirmish_init( &shared->arenas_lock, "Fusion Arenas", world ); shared->world = world; direct_mutex_init( &world->event_dispatcher_mutex ); direct_waitqueue_init( &world->event_dispatcher_cond ); direct_waitqueue_init( &world->event_dispatcher_process_cond ); direct_mutex_init( &world->event_dispatcher_call_mutex ); direct_waitqueue_init( &world->event_dispatcher_call_cond ); world->event_dispatcher_thread = direct_thread_create( DTT_MESSAGING, event_dispatcher_loop, world, "Fusion Dispatch" ); world->refs = 1; *ret_world = world; return DR_OK; error: if (world) { if (world->shared) D_FREE( world->shared ); D_FREE( world ); } direct_shutdown(); return ret; } DirectResult fusion_world_activate( FusionWorld *world ) { return DR_OK; } DirectResult fusion_stop_dispatcher( FusionWorld *world, bool emergency ) { return DR_OK; } DirectResult fusion_exit( FusionWorld *world, bool emergency ) { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); fusion_shm_pool_destroy( world, world->shared->main_pool ); direct_mutex_lock( &world->event_dispatcher_mutex ); world->dispatch_stop = 1; direct_mutex_unlock( &world->event_dispatcher_mutex ); direct_waitqueue_signal( &world->event_dispatcher_call_cond ); direct_waitqueue_signal( &world->event_dispatcher_cond ); direct_thread_join( world->event_dispatcher_thread ); direct_thread_destroy( world->event_dispatcher_thread ); direct_mutex_deinit( &world->event_dispatcher_mutex ); direct_waitqueue_deinit( &world->event_dispatcher_cond ); direct_mutex_deinit( &world->event_dispatcher_call_mutex ); direct_waitqueue_deinit( &world->event_dispatcher_call_cond ); fusion_skirmish_destroy( &world->shared->arenas_lock ); D_MAGIC_CLEAR( world->shared ); D_FREE( world->shared ); D_MAGIC_CLEAR( world ); D_FREE( world ); direct_shutdown(); return DR_OK; } DirectResult fusion_kill( FusionWorld *world, FusionID fusion_id, int signal, int timeout_ms ) { D_MAGIC_ASSERT( world, FusionWorld ); world->dispatch_stop = 1; return DR_OK; } const char * fusion_get_tmpfs( FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); return "/tmp"; } DirectResult fusion_dispatch_cleanup_add( FusionWorld *world, FusionDispatchCleanupFunc func, void *ctx, FusionDispatchCleanup **ret_cleanup ) { func( ctx ); return DR_OK; } DirectResult fusion_dispatch_cleanup_remove( FusionWorld *world, FusionDispatchCleanup *cleanup ) { return DR_OK; } DirectResult fusion_dispatch( FusionWorld *world, size_t buf_size ) { return DR_OK; } DirectResult fusion_get_fusionee_path( const FusionWorld *world, FusionID fusion_id, char *buf, size_t buf_size, size_t *ret_size ) { D_ASSERT( world != NULL ); D_ASSERT( buf != NULL ); D_ASSERT( ret_size != NULL ); *buf = '\0'; *ret_size = 0; return DR_UNIMPLEMENTED; } DirectResult fusion_get_fusionee_pid( const FusionWorld *world, FusionID fusion_id, pid_t *ret_pid ) { D_MAGIC_ASSERT( world, FusionWorld ); return DR_UNIMPLEMENTED; } DirectResult fusion_world_set_root( FusionWorld *world, void *root ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); if (world->fusion_id != FUSION_ID_MASTER) return DR_ACCESSDENIED; world->shared->world_root = root; return DR_OK; } void * fusion_world_get_root( FusionWorld *world ) { D_ASSERT( world != NULL ); D_ASSERT( world->shared != NULL ); return world->shared->world_root; } DirectResult fusion_sync( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return DR_OK; } void fusion_world_set_fork_action( FusionWorld *world, FusionForkAction action ) { D_MAGIC_ASSERT( world, FusionWorld ); } FusionForkAction fusion_world_get_fork_action( FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return world->fork_action; } void fusion_world_set_fork_callback( FusionWorld *world, FusionForkCallback callback ) { D_MAGIC_ASSERT( world, FusionWorld ); } void fusion_world_set_leave_callback( FusionWorld *world, FusionLeaveCallback callback, void *ctx ) { D_MAGIC_ASSERT( world, FusionWorld ); } int fusion_world_index( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return 0; } FusionID fusion_id( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return world->fusion_id; } bool fusion_is_multi( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return false; } pid_t fusion_dispatcher_tid( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return direct_thread_get_tid( world->event_dispatcher_thread ); } bool fusion_master( const FusionWorld *world ) { D_MAGIC_ASSERT( world, FusionWorld ); return true; } bool fusion_is_shared( FusionWorld *world, const void *ptr ) { D_MAGIC_ASSERT( world, FusionWorld ); return true; } #endif /* FUSION_BUILD_MULTI */ ================================================ FILE: lib/fusion/fusion.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__FUSION_H__ #define __FUSION__FUSION_H__ #include #include /**********************************************************************************************************************/ typedef enum { FER_ANY = 0x00000000, FER_MASTER = 0x00000001, FER_SLAVE = 0x00000002 } FusionEnterRole; typedef enum { FFA_CLOSE = 0x00000000, FFA_FORK = 0x00000001 } FusionForkAction; typedef enum { FFS_PREPARE = 0x00000000, FFS_PARENT = 0x00000001, FFS_CHILD = 0x00000002 } FusionForkState; typedef void (*FusionForkCallback) ( FusionForkAction action, FusionForkState state ); typedef void (*FusionLeaveCallback)( FusionWorld *world, FusionID fusion_id, void *ctx ); typedef void (*FusionDispatchCleanupFunc)( void *ctx ); typedef struct { DirectLink link; FusionDispatchCleanupFunc func; void *ctx; } FusionDispatchCleanup; /**********************************************************************************************************************/ /* * Enters a fusion world by joining or creating it. * If 'world_index' is negative, the next free index is used to create a new world. * Otherwise the world with the specified index is joined or created. */ DirectResult FUSION_API fusion_enter ( int world_index, int abi_version, FusionEnterRole role, FusionWorld **ret_world ); /* * Unblock slaves from entering. */ DirectResult FUSION_API fusion_world_activate ( FusionWorld *world ); /* * Stop the dispatcher thread. */ DirectResult FUSION_API fusion_stop_dispatcher ( FusionWorld *world, bool emergency ); /* * Exits the fusion world. * If 'emergency' is true the function won't join but kill the dispatcher thread. */ DirectResult FUSION_API fusion_exit ( FusionWorld *world, bool emergency ); /* * Sends a signal to one or more fusionees and optionally waits for their processes to terminate. * A fusion_id of zero means all fusionees. * A timeout of zero means infinite waiting while a negative value means no waiting at all. */ DirectResult FUSION_API fusion_kill ( FusionWorld *world, FusionID fusion_id, int signal, int timeout_ms ); /* * Return the location of shared memory file. */ const char FUSION_API *fusion_get_tmpfs ( FusionWorld *world ); /* * Add dispatch cleanup handler. */ DirectResult FUSION_API fusion_dispatch_cleanup_add ( FusionWorld *world, FusionDispatchCleanupFunc func, void *ctx, FusionDispatchCleanup **ret_cleanup ); /* * Remove dispatch cleanup handler. */ DirectResult FUSION_API fusion_dispatch_cleanup_remove ( FusionWorld *world, FusionDispatchCleanup *cleanup ); /* * Dispatch. */ DirectResult FUSION_API fusion_dispatch ( FusionWorld *world, size_t buf_size ); /* * Get the executable path of the fusionee. */ DirectResult FUSION_API fusion_get_fusionee_path ( const FusionWorld *world, FusionID fusion_id, char *buf, size_t buf_size, size_t *ret_size ); /* * Get the PID of the fusionee. */ DirectResult FUSION_API fusion_get_fusionee_pid ( const FusionWorld *world, FusionID fusion_id, pid_t *ret_pid ); /* * Set the world root, i.e. the shared core. */ DirectResult FUSION_API fusion_world_set_root ( FusionWorld *world, void *root ); /* * Get the world root. */ void FUSION_API *fusion_world_get_root ( FusionWorld *world ); /* * Wait until all pending messages are processed. */ DirectResult FUSION_API fusion_sync ( const FusionWorld *world ); /* * Sets the fork() action of the calling fusionee within the world. */ void FUSION_API fusion_world_set_fork_action ( FusionWorld *world, FusionForkAction action ); /* * Gets the current fork() action. */ FusionForkAction FUSION_API fusion_world_get_fork_action ( FusionWorld *world ); /* * Registers a callback called upon fork(). */ void FUSION_API fusion_world_set_fork_callback ( FusionWorld *world, FusionForkCallback callback ); /* * Registers a callback called when a slave exits. */ void FUSION_API fusion_world_set_leave_callback( FusionWorld *world, FusionLeaveCallback callback, void *ctx ); /* * Returns the index of the specified world. */ int FUSION_API fusion_world_index ( const FusionWorld *world ); /* * Returns the own Fusion ID within the specified world. */ FusionID FUSION_API fusion_id ( const FusionWorld *world ); /* * Returns if the world is a multi application world. */ bool FUSION_API fusion_is_multi ( const FusionWorld *world ); /* * Returns the thread ID of the Fusion Dispatcher within the specified world. */ pid_t FUSION_API fusion_dispatcher_tid ( const FusionWorld *world ); /* * Returns true if this process is the master. */ bool FUSION_API fusion_master ( const FusionWorld *world ); /* * Check if a pointer points to the shared memory. */ bool FUSION_API fusion_is_shared ( FusionWorld *world, const void *ptr ); #endif ================================================ FILE: lib/fusion/fusion_internal.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__FUSION_INTERNAL_H__ #define __FUSION__FUSION_INTERNAL_H__ #include #include #include #include /**********************************************************************************************************************/ struct __Fusion_FusionWorldShared { int magic; int refs; /* Increased by the master on fork(). */ int world_index; int world_abi; long long start_time; DirectLink *arenas; FusionSkirmish arenas_lock; FusionSkirmish reactor_globals; FusionSHMShared shm; FusionSHMPoolShared *main_pool; DirectLink *fusionees; /* Connected fusionees. */ FusionSkirmish fusionees_lock; /* Lock for fusionees. */ unsigned int call_ids; /* Generates call ids. */ unsigned int lock_ids; /* Generates locks ids. */ unsigned int ref_ids; /* Generates refs ids. */ unsigned int reactor_ids; /* Generates reactors ids. */ unsigned int pool_ids; /* Generates pools ids. */ void *pool_base; /* SHM pool allocation base. */ void *pool_max; /* SHM pool max address. */ void *world_root; FusionWorld *world; FusionCall refs_call; FusionHash *call_hash; }; struct __Fusion_FusionWorld { int magic; int refs; FusionWorldShared *shared; int fusion_fd; FusionID fusion_id; DirectThread *dispatch_loop; bool dispatch_stop; DirectLink *reactor_nodes; DirectMutex reactor_nodes_lock; FusionSHM shm; FusionForkAction fork_action; FusionForkCallback fork_callback; void *fusionee; struct { DirectThread *thread; DirectWaitQueue queue; DirectMutex lock; DirectLink *list; } deferred; FusionLeaveCallback leave_callback; void *leave_ctx; DirectLink *dispatch_cleanups; DirectMutex refs_lock; DirectMap *refs_map; DirectThread *event_dispatcher_thread; DirectMutex event_dispatcher_mutex; DirectWaitQueue event_dispatcher_cond; DirectWaitQueue event_dispatcher_process_cond; DirectLink *event_dispatcher_buffers; DirectLink *event_dispatcher_buffers_remove; DirectMutex event_dispatcher_call_mutex; DirectWaitQueue event_dispatcher_call_cond; }; /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #define FUSION_MAX_WORLDS 32 typedef struct { FusionID fusion_id; int ref_id; } FusionRefSlaveKey; typedef struct { FusionRefSlaveKey key; int refs; FusionRef *ref; } FusionRefSlaveEntry; typedef struct { int ref_id; int refs_catch; int refs_local; } FusionRefSlaveSlaveEntry; /* * from call.c */ void _fusion_call_process ( FusionWorld *world, int call_id, FusionCallMessage *call, void *ptr ); /* * from fusion.c */ int _fusion_fd ( const FusionWorldShared *shared ); FusionID _fusion_id ( const FusionWorldShared *shared ); FusionWorld *_fusion_world ( const FusionWorldShared *shared ); /* * from reactor.c */ void _fusion_reactor_free_all ( FusionWorld *world ); void _fusion_reactor_process_message ( FusionWorld *world, int reactor_id, int channel, const void *msg_data ); #if FUSION_BUILD_KERNEL static __inline__ void fusion_entry_add_permissions( const FusionWorld *world, FusionType type, int entry_id, FusionID fusion_id, ... ) { FusionEntryPermissions permissions; va_list args; int arg; permissions.type = type; permissions.id = entry_id; permissions.fusion_id = fusion_id; permissions.permissions = 0; va_start( args, fusion_id ); while ((arg = va_arg( args, int )) != 0) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, arg ); va_end( args ); while (ioctl( world->fusion_fd, FUSION_ENTRY_ADD_PERMISSIONS, &permissions ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion: FUSION_ENTRY_ADD_PERMISSIONS( type %u, id %d )\n", type, entry_id ); break; } } } typedef struct { DirectLink link; FusionReadMessage header; } DeferredCall; #define EXECUTE3_BIN_FLUSH_MILLIS 16 /* * from call.c */ void _fusion_call_process3 ( FusionWorld *world, int call_id, FusionCallMessage3 *msg, void *ptr ); /* * from shm/pool.c */ void _fusion_shmpool_process ( FusionWorld *world, int pool_id, FusionSHMPoolMessage *msg ); #else /* FUSION_BUILD_KERNEL */ /* * from fusion.c */ void _fusion_add_local ( FusionWorld *world, FusionRef *ref, int add ); void _fusion_check_locals ( FusionWorld *world, FusionRef *ref ); void _fusion_remove_all_locals ( FusionWorld *world, const FusionRef *ref ); DirectResult _fusion_send_message ( int fd, const void *msg, size_t msg_size, struct sockaddr_un *addr ); DirectResult _fusion_recv_message ( int fd, void *msg, size_t msg_size, struct sockaddr_un *addr ); /* * from ref.c */ DirectResult _fusion_ref_change ( FusionRef *ref, int add, bool global ); #endif /* FUSION_BUILD_KERNEL */ #else /* FUSION_BUILD_MULTI */ #define EVENT_DISPATCHER_BUFFER_LENGTH (FUSION_CALL_MAX_LENGTH) typedef struct { DirectLink link; int magic; char buffer[FUSION_CALL_MAX_LENGTH]; int read_pos; int write_pos; int can_free; int sync_calls; int pending; } FusionEventDispatcherBuffer; typedef struct { int reaction; FusionCallHandler call_handler; FusionCallHandler3 call_handler3; void *call_ctx; FusionCallExecFlags flags; int call_arg; void *ptr; unsigned int length; int ret_val; void *ret_ptr; unsigned int ret_size; unsigned int ret_length; int processed; } FusionEventDispatcherCall; /* * from fusion.c */ DirectResult _fusion_event_dispatcher_process ( FusionWorld *world, const FusionEventDispatcherCall *call, FusionEventDispatcherCall **ret ); DirectResult _fusion_event_dispatcher_process_reactions ( FusionWorld *world, FusionReactor *reactor, int channel, void *msg_data, int msg_size ); DirectResult _fusion_event_dispatcher_process_reactor_free( FusionWorld *world, FusionReactor *reactor ); #endif /* FUSION_BUILD_MULTI */ #endif ================================================ FILE: lib/fusion/hash.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Fusion_Hash, "Fusion/Hash", "Fusion Hash table" ); /**********************************************************************************************************************/ #define HASH_STR(h,p) \ { \ h = *p; \ if (h) \ for (p += 1; *p != '\0'; p++) \ h = (h << 5) - h + *p; \ } static const unsigned int primes[] = { 11, 19, 37, 73, 109, 163, 251, 367, 557, 823, 1237, 1861, 2777, 4177, 6247, 9371, 14057, 21089, 31627, 47431, 71143, 106721, 160073, 240101, 360163, 540217, 810343, 1215497, 1823231, 2734867, 4102283, 6153409, 9230113, 13845163, }; static const unsigned int nprimes = D_ARRAY_SIZE(primes); static unsigned int spaced_primes_closest( unsigned int num ) { unsigned int i; for (i = 0; i < nprimes; i++) if (primes[i] > num) return primes[i]; return primes[nprimes-1]; } static __inline__ FusionHashNode ** fusion_hash_lookup_node( FusionHash *hash, const void *key ) { FusionHashNode **node; if (hash->key_type == HASH_STRING) { unsigned int h; const char *p = key; HASH_STR(h,p) node = &hash->nodes[h % hash->size]; } else node = &hash->nodes[((unsigned long) key) % hash->size]; if (hash->key_type == HASH_STRING) { while (*node && strcmp( (*node)->key, key )) node = &(*node)->next; } else while (*node && (*node)->key != key) node = &(*node)->next; return node; } /**********************************************************************************************************************/ static DirectResult fusion_hash_create_internal( bool local, FusionSHMPoolShared *pool, FusionHashType key_type, FusionHashType value_type, int size, FusionHash **ret_hash ) { FusionHash *hash; if (!ret_hash) return DR_BUG; if (!local && !pool) return DR_BUG; if (size < FUSION_HASH_MIN_SIZE) size = FUSION_HASH_MIN_SIZE; if (local) hash = D_CALLOC( 1, sizeof(FusionHash) ); else hash = SHCALLOC( pool, 1, sizeof(FusionHash) ); if (!hash) return local ? DR_NOLOCALMEMORY : DR_NOSHAREDMEMORY; hash->local = local; hash->pool = pool; hash->key_type = key_type; hash->value_type = value_type; hash->size = size; hash->nnodes = 0; if (local) hash->nodes = D_CALLOC( size, sizeof(FusionHashNode*) ); else hash->nodes = SHCALLOC( pool, size, sizeof(FusionHashNode*) ); if (!hash->nodes) { if (local) D_FREE( hash ); else SHFREE( pool, hash ); return local ? DR_NOLOCALMEMORY : DR_NOSHAREDMEMORY; } D_MAGIC_SET( hash, FusionHash ); *ret_hash = hash; return DR_OK; } DirectResult fusion_hash_create_local( FusionHashType key_type, FusionHashType value_type, int size, FusionHash **ret_hash ) { D_DEBUG_AT( Fusion_Hash, "Creating local hash table with initial capacity of %d...\n", size ); return fusion_hash_create_internal( true, NULL, key_type, value_type, size, ret_hash ); } DirectResult fusion_hash_create( FusionSHMPoolShared *pool, FusionHashType key_type, FusionHashType value_type, int size, FusionHash **ret_hash ) { D_DEBUG_AT( Fusion_Hash, "Creating shared hash table with initial capacity of %d...\n", size ); return fusion_hash_create_internal( false, pool, key_type, value_type, size, ret_hash ); } static void fusion_hash_node_destroy( FusionHash *hash, FusionHashNode *node, void **old_key, void **old_value ) { if (!node) return; if (old_key) *old_key = node->key; else if (hash->key_type != HASH_INT) { if (hash->free_keys) { if (hash->local) D_FREE( node->key ); else SHFREE( hash->pool, node->key ); } } if (old_value) *old_value = node->value; else if (hash->value_type != HASH_INT) { if (hash->free_values) { if (hash->local) D_FREE( node->value ); else SHFREE( hash->pool, node->value ); } } if (hash->local) D_FREE( node ); else SHFREE( hash->pool, node ); } void fusion_hash_destroy( FusionHash *hash ) { FusionHashNode *node; FusionHashNode *next; int i; D_MAGIC_ASSERT( hash, FusionHash ); for (i = 0; i < hash->size; i++) { for (node = hash->nodes[i]; node; node = next) { next = node->next; fusion_hash_node_destroy( hash, node, NULL, NULL ); } } if (hash->local) D_FREE( hash->nodes ); else SHFREE( hash->pool, hash->nodes ); D_MAGIC_CLEAR( hash ); if (hash->local) D_FREE( hash ); else SHFREE( hash->pool, hash ); } void fusion_hash_set_autofree( FusionHash *hash, bool free_keys, bool free_values ) { D_MAGIC_ASSERT( hash, FusionHash ); hash->free_keys = free_keys; hash->free_values = free_values; } void * fusion_hash_lookup( FusionHash *hash, const void *key ) { FusionHashNode *node; D_MAGIC_ASSERT( hash, FusionHash ); node = *fusion_hash_lookup_node( hash, key ); return node ? node->value : NULL; } DirectResult fusion_hash_insert( FusionHash *hash, void *key, void *value ) { FusionHashNode **node; D_MAGIC_ASSERT( hash, FusionHash ); node = fusion_hash_lookup_node( hash, key ); if (*node) { D_BUG( "key already exists" ); return DR_BUG; } else { if (hash->local) (*node) = D_CALLOC( 1, sizeof(FusionHashNode) ); else (*node) = SHCALLOC( hash->pool, 1, sizeof(FusionHashNode) ); if (!(*node)) return hash->local ? DR_NOLOCALMEMORY : DR_NOSHAREDMEMORY; (*node)->key = key; (*node)->value = value; hash->nnodes++; if (fusion_hash_should_resize( hash )) fusion_hash_resize( hash ); } return DR_OK; } DirectResult fusion_hash_replace( FusionHash *hash, void *key, void *value, void **old_key, void **old_value ) { FusionHashNode **node; D_MAGIC_ASSERT( hash, FusionHash ); node = fusion_hash_lookup_node( hash, key ); if (*node) { if (old_key) *old_key = (*node)->key; else if (hash->key_type != HASH_INT) { if (hash->free_keys) { if (hash->local) D_FREE( (*node)->key ); else SHFREE( hash->pool, (*node)->key ); } } if (old_value) *old_value = (*node)->value; else if (hash->value_type != HASH_INT) { if (hash->free_values) { if (hash->local) D_FREE( (*node)->value ); else SHFREE( hash->pool, (*node)->value ); } } (*node)->key = key; (*node)->value = value; } else { if (hash->local) *node = D_CALLOC( 1, sizeof(FusionHashNode) ); else *node = SHCALLOC( hash->pool, 1, sizeof(FusionHashNode) ); if (!(*node)) return hash->local ? DR_NOLOCALMEMORY : DR_NOSHAREDMEMORY; (*node)->key = key; (*node)->value = value; hash->nnodes++; if (fusion_hash_should_resize( hash )) fusion_hash_resize( hash ); } return DR_OK; } DirectResult fusion_hash_remove( FusionHash *hash, const void *key, void **old_key, void **old_value ) { FusionHashNode **node; FusionHashNode *dest; D_MAGIC_ASSERT( hash, FusionHash ); node = fusion_hash_lookup_node( hash, key ); if (*node) { dest = *node; (*node) = dest->next; fusion_hash_node_destroy( hash, dest, old_key, old_value ); hash->nnodes--; return DR_OK; } return DR_OK; } void fusion_hash_iterate( FusionHash *hash, FusionHashIteratorFunc func, void *ctx ) { FusionHashNode *node; FusionHashNode *next; int i; D_MAGIC_ASSERT( hash, FusionHash ); for (i = 0; i < hash->size; i++) { for (node = hash->nodes[i]; node; node = next) { next = node->next; if (func( hash, node->key, node->value, ctx) ) return; } } } unsigned int fusion_hash_size( FusionHash *hash ) { D_MAGIC_ASSERT( hash, FusionHash ); return hash->nnodes; } bool fusion_hash_should_resize( FusionHash *hash ) { D_MAGIC_ASSERT( hash, FusionHash ); if ((hash->size >= 3 * hash->nnodes && hash->size > FUSION_HASH_MIN_SIZE) || (3 * hash->size <= hash->nnodes && hash->size < FUSION_HASH_MAX_SIZE)) return true; return false; } DirectResult fusion_hash_resize( FusionHash *hash ) { FusionHashNode **new_nodes; FusionHashNode *node; FusionHashNode *next; unsigned int hash_val; int new_size; int i; D_MAGIC_ASSERT( hash, FusionHash ); new_size = spaced_primes_closest( hash->nnodes ); if (new_size > FUSION_HASH_MAX_SIZE ) new_size = FUSION_HASH_MAX_SIZE; if (new_size < FUSION_HASH_MIN_SIZE) new_size = FUSION_HASH_MIN_SIZE; if (hash->local) new_nodes = D_CALLOC( new_size, sizeof(FusionHashNode*) ); else new_nodes = SHCALLOC( hash->pool, new_size, sizeof(FusionHashNode*) ); if (!new_nodes) return hash->local?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY; for (i = 0; i < hash->size; i++) { for (node = hash->nodes[i]; node; node = next) { next = node->next; if (hash->key_type == HASH_STRING) { unsigned int h; const char *p = node->key; HASH_STR(h, p) hash_val = h % new_size; } else hash_val = ((unsigned long) node->key) % new_size; node->next = new_nodes[hash_val]; new_nodes[hash_val] = node; } } if (hash->local) D_FREE( hash->nodes ); else SHFREE( hash->pool, hash->nodes ); hash->nodes = new_nodes; hash->size = new_size; return true; } ================================================ FILE: lib/fusion/hash.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION_HASH_H__ #define __FUSION_HASH_H__ #include #include /**********************************************************************************************************************/ typedef enum { HASH_PTR = 0x00000000, HASH_STRING = 0x00000001, HASH_INT = 0x00000002 } FusionHashType; typedef struct _FusionHashNode { void *key; void *value; struct _FusionHashNode *next; } FusionHashNode; struct __Fusion_FusionHash { int magic; bool local; FusionHashType key_type; FusionHashType value_type; int size; int nnodes; FusionHashNode **nodes; FusionSHMPoolShared *pool; bool free_keys; bool free_values; }; /**********************************************************************************************************************/ #define FUSION_HASH_MIN_SIZE 11 #define FUSION_HASH_MAX_SIZE 13845163 typedef bool (*FusionHashIteratorFunc)( FusionHash *hash, void *key, void *value, void *ctx ); /**********************************************************************************************************************/ /* * Creates a new hash that uses local memory. */ DirectResult FUSION_API fusion_hash_create_local ( FusionHashType key_type, FusionHashType value_type, int size, FusionHash **ret_hash ); /* * Creates a new hash. */ DirectResult FUSION_API fusion_hash_create ( FusionSHMPoolShared *pool, FusionHashType key_type, FusionHashType value_type, int size, FusionHash **ret_hash ); /* * Destroys a hash. */ void FUSION_API fusion_hash_destroy ( FusionHash *hash ); /* * Frees keys or values when calling fusion_hash_replace(), fusion_hash_remove(), fusion_hash_destroy(). */ void FUSION_API fusion_hash_set_autofree ( FusionHash *hash, bool free_keys, bool free_values ); /* * Looks up a key in a hash. */ void FUSION_API *fusion_hash_lookup ( FusionHash *hash, const void *key ); /* * Inserts a new key and value into a hash. * If you think a key may exist you should call fusion_hash_replace(). */ DirectResult FUSION_API fusion_hash_insert ( FusionHash *hash, void *key, void *value ); /* * Inserts a new key and value into a hash similar to hash_insert(). * The difference is that if the key already exists in the hash, it gets replaced by the new key. */ DirectResult FUSION_API fusion_hash_replace ( FusionHash *hash, void *key, void *value, void **old_key, void **old_value ); /* * Removes a key and its associated value from a hash. */ DirectResult FUSION_API fusion_hash_remove ( FusionHash *hash, const void *key, void **old_key, void **old_value ); /* * Calls the given function for each of the key/value pairs in a hash. * The hash table can't be modified while iterating over it. */ void FUSION_API fusion_hash_iterate ( FusionHash *hash, FusionHashIteratorFunc func, void *ctx ); /* * Returns the number of key/value pairs contained in a hash. */ unsigned int FUSION_API fusion_hash_size ( FusionHash *hash ); /* * Determines if the hash has grown to large. */ bool FUSION_API fusion_hash_should_resize( FusionHash *hash ); /* * Resizes the hash to minimum. */ DirectResult FUSION_API fusion_hash_resize ( FusionHash *hash ); /**********************************************************************************************************************/ typedef struct { FusionHash *hash; int index; FusionHashNode *next; } FusionHashIterator; static __inline__ void * fusion_hash_iterator_next( FusionHashIterator *iterator ) { FusionHashNode *node = NULL; if (iterator->next) { node = iterator->next; iterator->next = node->next; } else { FusionHash *hash = iterator->hash; D_MAGIC_ASSERT( hash, FusionHash ); for (iterator->index++; iterator->index < hash->size; iterator->index++) { node = hash->nodes[iterator->index]; if (node) { iterator->next = node->next; break; } } } return node ? node->value : NULL; } static __inline__ void * fusion_hash_iterator_init( FusionHashIterator *iterator, FusionHash *hash ) { D_MAGIC_ASSERT( hash, FusionHash ); iterator->hash = hash; iterator->index = -1; iterator->next = NULL; return fusion_hash_iterator_next( iterator ); } #define fusion_hash_foreach(elem,iterator,hash) \ for ((elem) = (__typeof__(elem)) fusion_hash_iterator_init( &iterator, hash ); \ (elem) != NULL; \ (elem) = (__typeof__(elem)) fusion_hash_iterator_next( &iterator )) #endif ================================================ FILE: lib/fusion/init.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ typedef void (*Func)( void ); static Func init_funcs[] = { __Fusion_conf_init, __Fusion_call_init, }; static Func deinit_funcs[] = { __Fusion_call_deinit, __Fusion_conf_deinit, }; /**********************************************************************************************************************/ __dfb_constructor__ void __Fusion_init_all( void ) { size_t i; for (i = 0; i < D_ARRAY_SIZE(init_funcs); i++) init_funcs[i](); } __dfb_destructor__ void __Fusion_deinit_all( void ) { size_t i; for (i = 0; i < D_ARRAY_SIZE(deinit_funcs); i++) deinit_funcs[i](); } ================================================ FILE: lib/fusion/lock.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #if FUSION_BUILD_MULTI #include #include #include #if !FUSION_BUILD_KERNEL #include #include #endif /* FUSION_BUILD_KERNEL */ #endif /* FUSION_BUILD_MULTI */ D_DEBUG_DOMAIN( Fusion_Skirmish, "Fusion/Skirmish", "Fusion's Skirmish (Mutex)" ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #if FUSION_BUILD_KERNEL DirectResult fusion_skirmish_init( FusionSkirmish *skirmish, const char *name, const FusionWorld *world ) { FusionEntryInfo info; D_ASSERT( skirmish != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, name ?: "" ); while (ioctl( world->fusion_fd, FUSION_SKIRMISH_NEW, &skirmish->multi.id )) { if (errno == EINTR) continue; D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_NEW" ); return DR_FUSION; } D_DEBUG_AT( Fusion_Skirmish, " -> new skirmish %p [%d]\n", skirmish, skirmish->multi.id ); info.type = FT_SKIRMISH; info.id = skirmish->multi.id; direct_snputs( info.name, name, sizeof(info.name) ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); fusion_entry_add_permissions( world, FT_SKIRMISH, skirmish->multi.id, 0, FUSION_SKIRMISH_LOCK_COUNT, 0 ); /* Keep back pointer to shared world data. */ skirmish->multi.shared = world->shared; return DR_OK; } DirectResult fusion_skirmish_init2( FusionSkirmish *skirmish, const char *name, const FusionWorld *world, bool local ) { D_ASSERT( skirmish != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s', %s )\n", __FUNCTION__, skirmish, name ?: "", local ? "local" : "shared" ); if (!local) return fusion_skirmish_init( skirmish, name, world ); skirmish->single = D_CALLOC( 1, sizeof(FusionSkirmishSingle) + strlen( name ) + 1 ); if (skirmish->single == 0) return DR_NOLOCALMEMORY; skirmish->single->name = (char*) (skirmish->single + 1); strcpy( skirmish->single->name, name ); direct_recursive_mutex_init( &skirmish->single->lock ); direct_waitqueue_init( &skirmish->single->cond ); D_MAGIC_SET( skirmish->single, FusionSkirmishSingle ); /* Keep back pointer to shared world data. */ skirmish->multi.shared = world->shared; return DR_OK; } DirectResult fusion_skirmish_prevail( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret= direct_mutex_lock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_PREVAIL, &skirmish->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_PREVAIL" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_swoop( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_SWOOP, &skirmish->multi.id )) { switch (errno) { case EINTR: continue; case EAGAIN: return DR_BUSY; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_SWOOP" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count ) { DirectResult ret; int data[2]; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) { *lock_count = 0; return ret; } *lock_count = skirmish->single->count; direct_mutex_unlock( &skirmish->single->lock ); return DR_OK; } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); data[0] = skirmish->multi.id; data[1] = 0; while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_LOCK_COUNT, data )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_LOCK_COUNT" ); return DR_FUSION; } *lock_count = data[1]; return DR_OK; } DirectResult fusion_skirmish_dismiss( FusionSkirmish *skirmish ) { D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); skirmish->single->count--; return direct_mutex_unlock( &skirmish->single->lock ); } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_DISMISS, &skirmish->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_DISMISS" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_destroy( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); direct_waitqueue_broadcast( &skirmish->single->cond ); direct_waitqueue_deinit( &skirmish->single->cond ); ret = direct_mutex_deinit( &skirmish->single->lock ); D_MAGIC_CLEAR( skirmish->single ); D_FREE( skirmish->single ); return ret; } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_DESTROY, &skirmish->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_DESTROY" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout ) { FusionSkirmishWait wait; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); if (timeout) return direct_waitqueue_wait_timeout( &skirmish->single->cond, &skirmish->single->lock, timeout * 1000 ); return direct_waitqueue_wait( &skirmish->single->cond, &skirmish->single->lock ); } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); wait.id = skirmish->multi.id; wait.timeout = timeout; wait.lock_count = 0; while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_WAIT, &wait )) { switch (errno) { case EINTR: continue; case ETIMEDOUT: return DR_TIMEOUT; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_WAIT" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_notify( FusionSkirmish *skirmish ) { D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); direct_waitqueue_broadcast( &skirmish->single->cond ); return DR_OK; } D_DEBUG_AT( Fusion_Skirmish, "%s( %p [%d] )\n", __FUNCTION__, skirmish, skirmish->multi.id ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_NOTIFY, &skirmish->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Skirmish: Invalid skirmish!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Skirmish: FUSION_SKIRMISH_NOTIFY" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_skirmish_add_permissions( FusionSkirmish *skirmish, FusionID fusion_id, FusionSkirmishPermissions skirmish_permissions ) { FusionEntryPermissions permissions; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); return DR_OK; } permissions.type = FT_SKIRMISH; permissions.id = skirmish->multi.id; permissions.fusion_id = fusion_id; permissions.permissions = 0; if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_PREVAIL) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_PREVAIL ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_SWOOP) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_SWOOP ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_DISMISS) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_DISMISS ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_LOCK_COUNT) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_LOCK_COUNT ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_WAIT) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_WAIT ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_NOTIFY) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_NOTIFY ); if (skirmish_permissions & FUSION_SKIRMISH_PERMIT_DESTROY) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_SKIRMISH_DESTROY ); while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_ENTRY_ADD_PERMISSIONS, &permissions ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion/Skirmish: FUSION_ENTRY_ADD_PERMISSIONS( id %d )\n", skirmish->multi.id ); return DR_FAILURE; } } return DR_OK; } #else /* FUSION_BUILD_KERNEL */ typedef struct { DirectLink link; pid_t pid; bool notified; } WaitNode; DirectResult fusion_skirmish_init( FusionSkirmish *skirmish, const char *name, const FusionWorld *world ) { D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, name ?: "" ); skirmish->multi.id = ++world->shared->lock_ids; /* Set state to unlocked. */ skirmish->multi.builtin.locked = 0; skirmish->multi.builtin.owner = 0; skirmish->multi.builtin.waiting = NULL; skirmish->multi.builtin.requested = false; skirmish->multi.builtin.destroyed = false; /* Keep back pointer to shared world data. */ skirmish->multi.shared = world->shared; return DR_OK; } DirectResult fusion_skirmish_init2( FusionSkirmish *skirmish, const char *name, const FusionWorld *world, bool local ) { D_ASSERT( skirmish != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s', %s )\n", __FUNCTION__, skirmish, name ?: "", local ? "local" : "shared" ); if (!local) return fusion_skirmish_init( skirmish, name, world ); skirmish->single = D_CALLOC( 1, sizeof(FusionSkirmishSingle) + strlen( name ) + 1 ); if (skirmish->single == 0) return DR_NOLOCALMEMORY; skirmish->single->name = (char*) (skirmish->single + 1); strcpy( skirmish->single->name, name ); direct_recursive_mutex_init( &skirmish->single->lock ); direct_waitqueue_init( &skirmish->single->cond ); D_MAGIC_SET( skirmish->single, FusionSkirmishSingle ); /* Keep back pointer to shared world data. */ skirmish->multi.shared = world->shared; return DR_OK; } DirectResult fusion_skirmish_prevail( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p )\n", __FUNCTION__, skirmish ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret = direct_mutex_lock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; asm( "" ::: "memory" ); if (skirmish->multi.builtin.locked && skirmish->multi.builtin.owner != direct_gettid()) { int count = 0; while (skirmish->multi.builtin.locked) { /* Check whether owner exited without unlocking. */ ret = direct_kill( skirmish->multi.builtin.owner, 0 ); if (ret == DR_NOSUCHINSTANCE) { skirmish->multi.builtin.locked = 0; skirmish->multi.builtin.requested = false; break; } skirmish->multi.builtin.requested = true; asm( "" ::: "memory" ); if (++count > 1000) { usleep( 10000 ); count = 0; } else { direct_sched_yield(); } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; } } skirmish->multi.builtin.locked++; skirmish->multi.builtin.owner = direct_gettid(); asm( "" ::: "memory" ); return DR_OK; } DirectResult fusion_skirmish_swoop( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; asm( "" ::: "memory" ); if (skirmish->multi.builtin.locked && skirmish->multi.builtin.owner != direct_gettid()) { /* Check whether owner exited without unlocking. */ ret = direct_kill( skirmish->multi.builtin.owner, 0 ); if (ret == DR_NOSUCHINSTANCE) { skirmish->multi.builtin.locked = 0; skirmish->multi.builtin.requested = false; } else return DR_BUSY; } skirmish->multi.builtin.locked++; skirmish->multi.builtin.owner = direct_gettid(); asm( "" ::: "memory" ); return DR_OK; } DirectResult fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count ) { DirectResult ret; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) { *lock_count = 0; return ret; } *lock_count = skirmish->single->count; direct_mutex_unlock( &skirmish->single->lock ); return DR_OK; } if (skirmish->multi.builtin.destroyed) { *lock_count = 0; return DR_DESTROYED; } *lock_count = skirmish->multi.builtin.locked; return DR_OK; } DirectResult fusion_skirmish_dismiss( FusionSkirmish *skirmish ) { D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); skirmish->single->count--; return direct_mutex_unlock( &skirmish->single->lock ); } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; asm( "" ::: "memory" ); if (skirmish->multi.builtin.locked) { if (skirmish->multi.builtin.owner != direct_gettid()) { D_ERROR( "Fusion/Skirmish: Tried to dismiss a skirmish not owned by the current process!\n" ); return DR_ACCESSDENIED; } if (--skirmish->multi.builtin.locked == 0) { skirmish->multi.builtin.owner = 0; if (skirmish->multi.builtin.requested) { skirmish->multi.builtin.requested = false; direct_sched_yield(); } } } asm( "" ::: "memory" ); return DR_OK; } DirectResult fusion_skirmish_destroy( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p )\n", __FUNCTION__, skirmish ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); direct_waitqueue_broadcast( &skirmish->single->cond ); direct_waitqueue_deinit( &skirmish->single->cond ); ret = direct_mutex_deinit( &skirmish->single->lock ); D_MAGIC_CLEAR( skirmish->single ); D_FREE( skirmish->single ); return ret; } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; if (skirmish->multi.builtin.waiting) fusion_skirmish_notify( skirmish ); skirmish->multi.builtin.destroyed = true; return DR_OK; } static void restart_handler( int s ) {} DirectResult fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout ) { WaitNode *node; long long stop; struct sigaction act, oldact; sigset_t mask, set; DirectResult ret = DR_OK; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); if (timeout) return direct_waitqueue_wait_timeout( &skirmish->single->cond, &skirmish->single->lock, timeout * 1000 ); return direct_waitqueue_wait( &skirmish->single->cond, &skirmish->single->lock ); } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; /* Set timeout. */ stop = direct_clock_get_micros() + timeout * 1000ll; /* Add ourself to the list of waiting processes. */ node = SHMALLOC( skirmish->multi.shared->main_pool, sizeof(WaitNode) ); if (!node) return D_OOSHM(); node->pid = direct_gettid(); node->notified = false; direct_list_append( &skirmish->multi.builtin.waiting, &node->link ); /* Install a (fake) signal handler for SIGRTMAX. */ act.sa_handler = restart_handler; act.sa_flags = SA_RESETHAND | SA_RESTART | SA_NODEFER; sigaction( SIGRTMAX, &act, &oldact ); /* Unblock SIGRTMAX. */ sigprocmask( SIG_SETMASK, NULL, &mask ); sigdelset( &mask, SIGRTMAX ); fusion_skirmish_dismiss( skirmish ); while (!node->notified) { if (timeout) { long long now = direct_clock_get_micros(); if (now >= stop) { /* Stop notifying us. */ node->notified = true; ret = DR_TIMEOUT; break; } sigprocmask( SIG_SETMASK, &mask, &set ); usleep( stop - now ); sigprocmask( SIG_SETMASK, &set, NULL ); } else { sigsuspend( &mask ); } } /* Flush pending signals. */ if (!sigpending( &set ) && sigismember( &set, SIGRTMAX ) > 0) sigsuspend( &mask ); if (fusion_skirmish_prevail( skirmish )) ret = DR_DESTROYED; direct_list_remove( &skirmish->multi.builtin.waiting, &node->link ); SHFREE( skirmish->multi.shared->main_pool, node ); sigaction( SIGRTMAX, &oldact, NULL ); return ret; } DirectResult fusion_skirmish_notify( FusionSkirmish *skirmish ) { DirectResult ret; WaitNode *node, *next; D_ASSERT( skirmish != NULL ); if (skirmish->single) { D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); direct_waitqueue_broadcast( &skirmish->single->cond ); return DR_OK; } if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; direct_list_foreach_safe (node, next, skirmish->multi.builtin.waiting) { if (node->notified) continue; node->notified = true; ret = direct_kill( node->pid, SIGRTMAX ); if (ret) { if (ret == DR_NOSUCHINSTANCE) { /* Remove dead process. */ direct_list_remove( &skirmish->multi.builtin.waiting, &node->link ); SHFREE( skirmish->multi.shared->main_pool, node ); } else { D_DERROR( ret, "Fusion/Skirmish: Could not send notification signal!\n" ); } } } return DR_OK; } DirectResult fusion_skirmish_add_permissions( FusionSkirmish *skirmish, FusionID fusion_id, FusionSkirmishPermissions skirmish_permissions ) { return DR_OK; } #endif /* FUSION_BUILD_KERNEL */ #else /* FUSION_BUILD_MULTI */ DirectResult fusion_skirmish_init( FusionSkirmish *skirmish, const char *name, const FusionWorld *world ) { D_ASSERT( skirmish != NULL ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, name ?: "" ); skirmish->single = D_CALLOC( 1, sizeof(FusionSkirmishSingle) + strlen( name ) + 1 ); if (skirmish->single == 0) return DR_NOLOCALMEMORY; skirmish->single->name = (char*) (skirmish->single + 1); strcpy( skirmish->single->name, name ); direct_recursive_mutex_init( &skirmish->single->lock ); direct_waitqueue_init( &skirmish->single->cond ); D_MAGIC_SET( skirmish->single, FusionSkirmishSingle ); return DR_OK; } DirectResult fusion_skirmish_init2( FusionSkirmish *skirmish, const char *name, const FusionWorld *world, bool local ) { return fusion_skirmish_init( skirmish, name, world ); } DirectResult fusion_skirmish_prevail( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); ret = direct_mutex_lock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } DirectResult fusion_skirmish_swoop( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) return ret; skirmish->single->count++; return DR_OK; } DirectResult fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_ASSERT( lock_count != NULL ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); ret = direct_mutex_trylock( &skirmish->single->lock ); if (ret) { *lock_count = 0; return ret; } *lock_count = skirmish->single->count; direct_mutex_unlock( &skirmish->single->lock ); return DR_OK; } DirectResult fusion_skirmish_dismiss( FusionSkirmish *skirmish ) { D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); skirmish->single->count--; return direct_mutex_unlock( &skirmish->single->lock ); } DirectResult fusion_skirmish_destroy( FusionSkirmish *skirmish ) { DirectResult ret; D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); direct_waitqueue_broadcast( &skirmish->single->cond ); direct_waitqueue_deinit( &skirmish->single->cond ); ret = direct_mutex_deinit( &skirmish->single->lock ); D_MAGIC_CLEAR( skirmish->single ); D_FREE( skirmish->single ); return ret; } DirectResult fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout ) { D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); if (timeout) return direct_waitqueue_wait_timeout( &skirmish->single->cond, &skirmish->single->lock, timeout * 1000 ); return direct_waitqueue_wait( &skirmish->single->cond, &skirmish->single->lock ); } DirectResult fusion_skirmish_notify( FusionSkirmish *skirmish ) { D_ASSERT( skirmish != NULL ); D_MAGIC_ASSERT( skirmish->single, FusionSkirmishSingle ); D_DEBUG_AT( Fusion_Skirmish, "%s( %p, '%s' )\n", __FUNCTION__, skirmish, skirmish->single->name ); direct_waitqueue_broadcast( &skirmish->single->cond ); return DR_OK; } DirectResult fusion_skirmish_add_permissions( FusionSkirmish *skirmish, FusionID fusion_id, FusionSkirmishPermissions skirmish_permissions ) { return DR_OK; } #endif /* FUSION_BUILD_MULTI */ static int ptr_compare( const void *p1, const void *p2 ) { return *(u32*) p1 - *(u32*) p2; } DirectResult fusion_skirmish_prevail_multi( FusionSkirmish **skirmishs, unsigned int num ) { DirectResult ret = DR_OK; unsigned int i; FusionSkirmish *skirmishs_sorted[num]; D_DEBUG_AT( Fusion_Skirmish, "%s( %p, %u )\n", __FUNCTION__, skirmishs, num ); direct_memcpy( skirmishs_sorted, skirmishs, num * sizeof(FusionSkirmish*) ); qsort( skirmishs_sorted, num, sizeof(FusionSkirmish*), ptr_compare ); for (i = 0; i < num; i++) { ret = fusion_skirmish_prevail( skirmishs_sorted[i] ); if (ret) { D_DERROR( ret, "Fusion/Skirmish: Failed at index %u, skirmish_id [0x%08x]\n", i, (unsigned int) skirmishs_sorted[i]->multi.id ); break; } } if (ret) { for (--i; i >= 0; i--) fusion_skirmish_dismiss( skirmishs_sorted[i] ); } return ret; } DirectResult fusion_skirmish_dismiss_multi( FusionSkirmish **skirmishs, unsigned int num ) { DirectResult ret = DR_OK, ret2; unsigned int i; FusionSkirmish *skirmishs_sorted[num]; D_DEBUG_AT( Fusion_Skirmish, "%s( %p, %u )\n", __FUNCTION__, skirmishs, num ); direct_memcpy( skirmishs_sorted, skirmishs, num * sizeof(FusionSkirmish*) ); qsort( skirmishs_sorted, num, sizeof(FusionSkirmish*), ptr_compare ); for (i = 0; i < num; i++) { ret2 = fusion_skirmish_dismiss( skirmishs_sorted[i] ); if (ret2) { D_DERROR( ret, "Fusion/Skirmish: Failed at index %u, skirmish_id [0x%08x]\n", i, (unsigned int) skirmishs_sorted[i]->multi.id ); ret = ret2; } } return ret; } ================================================ FILE: lib/fusion/lock.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__LOCK_H__ #define __FUSION__LOCK_H__ #include #include #include /**********************************************************************************************************************/ typedef struct { int magic; DirectMutex lock; DirectWaitQueue cond; int count; char *name; } FusionSkirmishSingle; typedef struct { /* multi app */ struct { int id; const FusionWorldShared *shared; /* builtin impl */ struct { unsigned int locked; pid_t owner; DirectLink *waiting; bool requested; bool destroyed; } builtin; } multi; /* single app */ FusionSkirmishSingle *single; } FusionSkirmish; typedef enum { FUSION_SKIRMISH_PERMIT_NONE = 0x00000000, FUSION_SKIRMISH_PERMIT_PREVAIL = 0x00000001, FUSION_SKIRMISH_PERMIT_SWOOP = 0x00000002, FUSION_SKIRMISH_PERMIT_DISMISS = 0x00000004, FUSION_SKIRMISH_PERMIT_LOCK_COUNT = 0x00000008, FUSION_SKIRMISH_PERMIT_WAIT = 0x00000010, FUSION_SKIRMISH_PERMIT_NOTIFY = 0x00000020, FUSION_SKIRMISH_PERMIT_DESTROY = 0x00000040, FUSION_SKIRMISH_PERMIT_ALL = 0x0000007F } FusionSkirmishPermissions; #if D_DEBUG_ENABLED #define FUSION_SKIRMISH_ASSERT(skirmish) \ do { \ int lock_count; \ \ D_ASSERT( skirmish != NULL ); \ D_ASSERT( fusion_skirmish_lock_count( skirmish, &lock_count ) == DR_OK ); \ D_ASSERT( lock_count > 0 ); \ } while (0) #else #define FUSION_SKIRMISH_ASSERT(skirmish) \ do { \ } while (0) #endif /**********************************************************************************************************************/ /* * Initialize. */ DirectResult FUSION_API fusion_skirmish_init ( FusionSkirmish *skirmish, const char *name, const FusionWorld *world ); /* * Initialize with 'local' to create a fake skirmish (simple mutex). * This can be used by secure fusion mode when skirmishs are no longer locked by slaves at all. */ DirectResult FUSION_API fusion_skirmish_init2 ( FusionSkirmish *skirmish, const char *name, const FusionWorld *world, bool local ); /* * Lock. */ DirectResult FUSION_API fusion_skirmish_prevail ( FusionSkirmish *skirmish ); /* * Try lock. */ DirectResult FUSION_API fusion_skirmish_swoop ( FusionSkirmish *skirmish ); /* * Find out how many times current thread has acquired lock. */ DirectResult FUSION_API fusion_skirmish_lock_count ( FusionSkirmish *skirmish, int *lock_count ); /* * Unlock. */ DirectResult FUSION_API fusion_skirmish_dismiss ( FusionSkirmish *skirmish ); /* * Deinitialize. */ DirectResult FUSION_API fusion_skirmish_destroy ( FusionSkirmish *skirmish ); /* * Wait. */ DirectResult FUSION_API fusion_skirmish_wait ( FusionSkirmish *skirmish, unsigned int timeout ); /* * Notify. */ DirectResult FUSION_API fusion_skirmish_notify ( FusionSkirmish *skirmish ); /* * Give permissions to another fusionee to use the skirmish. */ DirectResult FUSION_API fusion_skirmish_add_permissions( FusionSkirmish *skimrish, FusionID fusion_id, FusionSkirmishPermissions permissions ); /* * Lock by sorting by pointer first, so locks are always taken in same order. */ DirectResult FUSION_API fusion_skirmish_prevail_multi ( FusionSkirmish **skirmishs, unsigned int num ); /* * Unlock by sorting by pointer first. */ DirectResult FUSION_API fusion_skirmish_dismiss_multi ( FusionSkirmish **skirmishs, unsigned int num ); #endif ================================================ FILE: lib/fusion/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA fusion_sources = [ 'arena.c', 'call.c', 'conf.c', 'fusion.c', 'hash.c', 'init.c', 'lock.c', 'object.c', 'reactor.c', 'ref.c', 'shmalloc.c', 'vector.c' ] fusion_headers = [ 'arena.h', 'call.h', 'conf.h', 'fusion.h', 'hash.h', 'lock.h', 'object.h', 'protocol.h', 'reactor.h', 'ref.h', 'shmalloc.h', 'types.h', 'vector.h', ] if get_option('multi') shm_sources = [ 'shm/heap.c', 'shm/pool.c', 'shm/shm.c' ] else shm_sources = 'shm/fake.c' endif shm_headers = [ 'shm/pool.h' ] build_conf = configuration_data() if get_option('multi') if get_option('os') == 'linux' if get_option('multi-kernel') and cc.has_header('linux/fusion.h') build_conf.set('FUSION_BUILD_KERNEL', 1) else build_conf.set('FUSION_BUILD_KERNEL', 0) endif endif build_conf.set('FUSION_MESSAGE_SIZE', get_option('message-size')) endif build_conf.set10('FUSION_BUILD_MULTI', get_option('multi')) configure_file(configuration: build_conf, output: 'build.h', install: true, install_dir: get_option('includedir') / 'directfb/fusion') fusion_private = [] if get_option('default_library') == 'static' fusion_private = 'direct' endif libfusion_private = [] if get_option('default_library') == 'static' and get_option('constructors') libfusion_private = '-Wl,-u,__Fusion_init_all' endif libfusion = library('fusion-@0@.@1@'.format(directfb_major_version, directfb_minor_version), fusion_sources, shm_sources, include_directories: [config_inc, lib_inc], build_rpath: get_option('prefix') / get_option('libdir'), dependencies: direct_dep, version: '0.@0@.0'.format(directfb_micro_version), install: true, install_rpath: get_option('prefix') / get_option('libdir')) install_symlink('libfusion' + libsuffix, pointing_to: 'libfusion-@0@.@1@'.format(directfb_major_version, directfb_minor_version) + libsuffix, install_dir: get_option('prefix') / get_option('libdir')) install_headers(fusion_headers, subdir: 'directfb/fusion') install_headers(shm_headers, subdir: 'directfb/fusion/shm') pkgconfig.generate(filebase: 'fusion', name: 'Fusion', description: 'DirectFB IPC library', requires_private: fusion_private, libraries: '-L${libdir} -lfusion', libraries_private: libfusion_private, subdirs: 'directfb') fusion_dep = declare_dependency(include_directories: lib_inc, link_with: libfusion) ================================================ FILE: lib/fusion/object.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Fusion_Object, "Fusion/Object", "Fusion Objects and Pools" ); D_DEBUG_DOMAIN( Fusion_Object_Owner, "Fusion/Object/Owner", "Fusion Objects and Pools Owner" ); /**********************************************************************************************************************/ static FusionCallHandlerResult object_reference_watcher( int caller, int call_arg, void *call_ptr, void *ctx, unsigned int serial, int *ret_val ) { FusionObject *object; FusionObjectPool *pool = ctx; D_DEBUG_AT( Fusion_Object, "%s( %d, %d, %p, %p, %u, %p )\n", __FUNCTION__, caller, call_arg, call_ptr, ctx, serial, ret_val ); #if FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL if (caller && !pool->secure) { D_BUG( "call not coming from fusion device (caller %d)", caller ); return FCHR_RETURN; } #endif /* FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL */ D_MAGIC_ASSERT( pool, FusionObjectPool ); /* Lock the pool. */ if (fusion_skirmish_prevail( &pool->lock )) return FCHR_RETURN; /* Lookup the object. */ object = fusion_hash_lookup( pool->objects, (void*)(long) call_arg ); D_DEBUG_AT( Fusion_Object, " -> lookup %p\n", object ); if (object) { D_MAGIC_ASSERT( object, FusionObject ); D_DEBUG_AT( Fusion_Object, " -> %p [id %u] ref [%d] | [0x%08x] (single %d) identity %lu\n", object, object->id, object->ref.multi.id, (unsigned int) object->ref.multi.id, object->ref.single.refs, object->identity ); if (object->ref.single.dead) { object->ref.single.dead--; if (object->ref.single.dead) { D_DEBUG_AT( Fusion_Object, " -> died multiple times (%d more), skipping...\n", object->ref.single.dead ); fusion_skirmish_dismiss( &pool->lock ); return FCHR_RETURN; } } switch (fusion_ref_zero_trylock( &object->ref )) { case DR_OK: break; case DR_DESTROYED: D_BUG( "%p [%u] in '%s' already destroyed", object, object->id, pool->name ); fusion_hash_remove( pool->objects, (void*)(long) object->id, NULL, NULL ); fusion_skirmish_dismiss( &pool->lock ); return FCHR_RETURN; default: D_ERROR( "Fusion/Object: Error locking ref of %p [%u] in '%s'!\n", object, object->id, pool->name ); /* fall through */ case DR_BUSY: fusion_skirmish_dismiss( &pool->lock ); return FCHR_RETURN; } D_DEBUG_AT( Fusion_Object, " -> dead object %p [%u] (ref [%d] | [0x%08x])\n", object, object->id, object->ref.multi.id, (unsigned int) object->ref.multi.id ); if (object->state == FOS_INIT) { D_WARN( "won't destroy incomplete object, leaking some memory" ); fusion_hash_remove( pool->objects, (void*)(long) object->id, NULL, NULL ); fusion_skirmish_dismiss( &pool->lock ); return FCHR_RETURN; } /* Set "deinitializing" state. */ object->state = FOS_DEINIT; /* Remove the object from the pool. */ object->pool = NULL; fusion_hash_remove( pool->objects, (void*)(long) object->id, NULL, NULL ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); D_DEBUG_AT( Fusion_Object, " -> calling destructor...\n" ); /* Call the destructor. */ pool->destructor( object, false, pool->ctx ); D_DEBUG_AT( Fusion_Object, " -> destructor done\n" ); return FCHR_RETURN; } D_BUG( "unknown object [%d] in '%s'", call_arg, pool->name ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return FCHR_RETURN; } FusionObjectPool * fusion_object_pool_create( const char *name, int object_size, int message_size, FusionObjectDestructor destructor, void *ctx, const FusionWorld *world ) { FusionObjectPool *pool; D_ASSERT( name != NULL ); D_ASSERT( object_size >= sizeof(FusionObject) ); D_ASSERT( destructor != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Object, "%s( '%s' )\n", __FUNCTION__, name ); /* Allocate shared memory for the pool. */ pool = SHCALLOC( world->shared->main_pool, 1, sizeof(FusionObjectPool) ); if (!pool) { D_OOSHM(); return NULL; } /* Initialize the pool lock. */ if (fusion_config->secure_fusion) fusion_skirmish_init2( &pool->lock, name, world, true ); else { fusion_skirmish_init2( &pool->lock, name, world, false ); fusion_skirmish_add_permissions( &pool->lock, 0, FUSION_SKIRMISH_PERMIT_PREVAIL | FUSION_SKIRMISH_PERMIT_DISMISS ); } /* Fill information. */ pool->shared = world->shared; pool->name = SHSTRDUP( world->shared->main_pool, name ); pool->object_size = object_size; pool->message_size = message_size; pool->destructor = destructor; pool->ctx = ctx; pool->secure = fusion_config->secure_fusion; fusion_hash_create( world->shared->main_pool, HASH_INT, HASH_PTR, 17, &pool->objects ); /* Destruction call from Fusion. */ fusion_call_init( &pool->call, object_reference_watcher, pool, world ); fusion_call_set_name( &pool->call, "object_reference_watcher" ); D_MAGIC_SET( pool, FusionObjectPool ); return pool; } DirectResult fusion_object_pool_destroy( FusionObjectPool *pool, FusionWorld *world, bool shutdown_info ) { DirectResult ret; FusionObject *object; FusionHashIterator it; D_MAGIC_ASSERT( pool, FusionObjectPool ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( world->shared == pool->shared ); D_DEBUG_AT( Fusion_Object, "%s( %p '%s' )\n", __FUNCTION__, pool, pool->name ); D_DEBUG_AT( Fusion_Object, " -> destroying pool...\n" ); fusion_world_flush_calls( world, 1 ); D_DEBUG_AT( Fusion_Object, " -> locking...\n" ); /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) return ret; /* Destroy the call. */ fusion_call_destroy( &pool->call ); /* Destroy zombies. */ fusion_hash_foreach (object, it, pool->objects) { int refs; fusion_ref_stat( &object->ref, &refs ); if (refs > 0) { if (shutdown_info) { D_WARN( "zombie %p [%u], refs %d (in %s) => ref [%d] | [0x%08x]", object, object->id, refs, pool->name, object->ref.multi.id, (unsigned int) object->ref.multi.id ); direct_trace_print_stack( object->create_stack ); } } D_DEBUG_AT( Fusion_Object, " -> %p [%u], refs %d\n", object, object->id, refs ); /* Set "deinitializing" state. */ object->state = FOS_DEINIT; D_DEBUG_AT( Fusion_Object, " -> calling destructor...\n" ); /* Call the destructor. */ pool->destructor( object, refs > 0, pool->ctx ); D_DEBUG_AT( Fusion_Object, " -> destructor done\n" ); } fusion_hash_destroy( pool->objects ); D_MAGIC_CLEAR( pool ); D_DEBUG_AT( Fusion_Object, " -> pool destroyed (%s)\n", pool->name ); /* Destroy the pool lock. */ fusion_skirmish_dismiss( &pool->lock ); fusion_skirmish_destroy( &pool->lock ); /* Deallocate shared memory. */ SHFREE( world->shared->main_pool, pool->name ); SHFREE( world->shared->main_pool, pool ); return DR_OK; } typedef struct { FusionObjectPool *pool; FusionObjectCallback callback; void *ctx; } ObjectIteratorContext; static bool object_iterator( FusionHash *hash, void *key, void *value, void *ctx ) { ObjectIteratorContext *context = ctx; FusionObject *object = value; D_MAGIC_ASSERT( object, FusionObject ); return !context->callback( context->pool, object, context->ctx ); } DirectResult fusion_object_pool_enum( FusionObjectPool *pool, FusionObjectCallback callback, void *ctx ) { ObjectIteratorContext iterator_context; D_MAGIC_ASSERT( pool, FusionObjectPool ); D_ASSERT( callback != NULL ); D_DEBUG_AT( Fusion_Object, "%s( %p '%s' )\n", __FUNCTION__, pool, pool->name ); /* Lock the pool. */ if (fusion_skirmish_prevail( &pool->lock )) return DR_FUSION; iterator_context.pool = pool; iterator_context.callback = callback; iterator_context.ctx = ctx; fusion_hash_iterate( pool->objects, object_iterator, &iterator_context ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return DR_OK; } DirectResult fusion_object_pool_size( FusionObjectPool *pool, size_t *ret_size ) { D_MAGIC_ASSERT( pool, FusionObjectPool ); if (!ret_size) return DR_INVARG; *ret_size = fusion_hash_size( pool->objects ); return DR_OK; } FusionObject * fusion_object_create( FusionObjectPool *pool, const FusionWorld *world, FusionID identity ) { FusionObject *object; D_MAGIC_ASSERT( pool, FusionObjectPool ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( world->shared == pool->shared ); D_DEBUG_AT( Fusion_Object, "%s( %p '%s', identity %lu )\n", __FUNCTION__, pool, pool->name, identity ); /* Lock the pool. */ if (fusion_skirmish_prevail( &pool->lock )) return NULL; /* Allocate shared memory for the object. */ object = SHCALLOC( world->shared->main_pool, 1, pool->object_size ); if (!object) { D_OOSHM(); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Set "initializing" state. */ object->state = FOS_INIT; /* Set object id. */ object->id = ++pool->id_pool; object->identity = identity; if (pool->secure || world->fusion_id == FUSION_ID_MASTER) object->create_stack = direct_trace_copy_buffer( NULL ); /* Initialize the reference counter. */ if (fusion_ref_init2( &object->ref, pool->name, pool->secure, world )) { SHFREE( world->shared->main_pool, object ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Increase the object's reference counter. */ fusion_ref_up( &object->ref, false ); /* Install handler for automatic destruction. */ if (fusion_ref_watch( &object->ref, &pool->call, object->id )) { fusion_ref_destroy( &object->ref ); SHFREE( world->shared->main_pool, object ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Create a reactor for message dispatching. */ object->reactor = fusion_reactor_new( pool->message_size, pool->name, world ); if (!object->reactor) { fusion_ref_destroy( &object->ref ); SHFREE( world->shared->main_pool, object ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } fusion_reactor_set_lock( object->reactor, &pool->lock ); fusion_vector_init( &object->access, 1, world->shared->main_pool ); fusion_vector_init( &object->owners, 1, world->shared->main_pool ); /* Set pool/world back pointer. */ object->pool = pool; object->shared = world->shared; /* Add the object to the pool. */ fusion_hash_insert( pool->objects, (void*)(long) object->id, object ); D_DEBUG_AT( Fusion_Object, " -> added object %p [%u] (ref [%d] | [0x%08x])\n", object, object->id, object->ref.multi.id, (unsigned int) object->ref.multi.id ); D_MAGIC_SET( object, FusionObject ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return object; } DirectResult fusion_object_get( FusionObjectPool *pool, FusionObjectID object_id, FusionObject **ret_object ) { DirectResult ret; FusionObject *object = NULL; D_MAGIC_ASSERT( pool, FusionObjectPool ); D_ASSERT( ret_object != NULL ); D_DEBUG_AT( Fusion_Object, "%s( %p '%s', object_id %u )\n", __FUNCTION__, pool, pool->name, object_id ); /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret == DR_OK) { object = fusion_hash_lookup( pool->objects, (void*)(long) object_id ); if (object) { int refs; ret = fusion_ref_stat( &object->ref, &refs ); if (ret == DR_OK) { D_DEBUG_AT( Fusion_Object, " -> refs %d\n", refs ); if (refs > 0) ret = fusion_object_ref( object ); else ret = DR_DEAD; } } else { D_DEBUG_AT( Fusion_Object, " -> not found\n" ); ret = DR_IDNOTFOUND; } } if (ret == DR_OK) *ret_object = object; /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return ret; } DirectResult fusion_object_lookup( FusionObjectPool *pool, FusionObjectID object_id, FusionObject **ret_object ) { DirectResult ret = DR_IDNOTFOUND; FusionObject *object = NULL; D_MAGIC_ASSERT( pool, FusionObjectPool ); D_ASSERT( ret_object != NULL ); D_DEBUG_AT( Fusion_Object, "%s( %p '%s', object_id %u )\n", __FUNCTION__, pool, pool->name, object_id ); /* Lock the pool. */ if (fusion_skirmish_prevail( &pool->lock )) return DR_FUSION; object = fusion_hash_lookup( pool->objects, (void*)(long) object_id ); if (object) { ret = DR_OK; } else D_DEBUG_AT( Fusion_Object, " -> not found\n" ); *ret_object = object; /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return ret; } DirectResult fusion_object_set_lock( FusionObject *object, FusionSkirmish *lock ) { D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( lock != NULL ); D_ASSUME( object->state == FOS_INIT ); return fusion_reactor_set_lock_only( object->reactor, lock ); } DirectResult fusion_object_activate( FusionObject *object ) { D_MAGIC_ASSERT( object, FusionObject ); /* Set active state. */ object->state = FOS_ACTIVE; return DR_OK; } DirectResult fusion_object_destroy( FusionObject *object ) { FusionObjectPool *pool; char *access; int index; D_MAGIC_ASSERT( object, FusionObject ); D_MAGIC_ASSERT( object->shared, FusionWorldShared ); D_ASSERT( object->state != FOS_ACTIVE ); pool = object->pool; /* Set "deinitializing" state. */ object->state = FOS_DEINIT; /* Remove the object from the pool. */ if (pool) { D_MAGIC_ASSERT( pool, FusionObjectPool ); /* Lock the pool. */ if (fusion_skirmish_prevail( &pool->lock )) return DR_FAILURE; /* Remove the object from the pool. */ if (object->pool) { D_ASSERT( object->pool == pool ); object->pool = NULL; fusion_hash_remove( pool->objects, (void*)(long) object->id, NULL, NULL ); } /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); } fusion_vector_foreach (access, index, object->access) { SHFREE( object->shared->main_pool, access ); } fusion_vector_destroy( &object->access ); fusion_vector_destroy( &object->owners ); fusion_ref_destroy( &object->ref ); fusion_reactor_free( object->reactor ); if (object->properties) fusion_hash_destroy( object->properties ); if (object->create_stack) direct_trace_free_buffer( object->create_stack ); D_MAGIC_CLEAR( object ); SHFREE( object->shared->main_pool, object ); return DR_OK; } DirectResult fusion_object_set_property( FusionObject *object, const char *key, void *value, void **old_value ) { DirectResult ret; char *sharedkey; D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( object->shared != NULL ); D_ASSERT( key != NULL ); D_ASSERT( value != NULL ); /* Create property hash on demand. */ if (!object->properties) { ret = fusion_hash_create( object->shared->main_pool, HASH_STRING, HASH_PTR, FUSION_HASH_MIN_SIZE, &object->properties ); if (ret) return ret; } /* Create a shared copy of the key. */ sharedkey = SHSTRDUP( object->shared->main_pool, key ); if (!sharedkey) return D_OOSHM(); /* Put it into the hash. */ ret = fusion_hash_replace( object->properties, sharedkey, value, NULL, old_value ); if (ret) SHFREE( object->shared->main_pool, sharedkey ); return ret; } void * fusion_object_get_property( FusionObject *object, const char *key ) { D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( key != NULL ); if (!object->properties) return NULL; return fusion_hash_lookup( object->properties, key ); } void fusion_object_remove_property( FusionObject *object, const char *key, void **old_value ) { D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( key != NULL ); if (!object->properties) return; fusion_hash_remove( object->properties, key, NULL, old_value ); if (fusion_hash_should_resize( object->properties )) fusion_hash_resize( object->properties ); } DirectResult fusion_object_add_access( FusionObject *object, const char *executable ) { DirectResult ret; char *copy; D_DEBUG_AT( Fusion_Object, "%s( %p, '%s' )\n", __FUNCTION__, object, executable ); D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( executable != NULL ); copy = SHSTRDUP( object->shared->main_pool, executable ); if (!copy) return D_OOM(); ret = fusion_vector_add( &object->access, copy ); if (ret) { SHFREE( object->shared->main_pool, copy ); return ret; } return DR_OK; } DirectResult fusion_object_has_access( FusionObject *object, const char *executable ) { char *access; int index; D_DEBUG_AT( Fusion_Object, "%s( %p, '%s' )\n", __FUNCTION__, object, executable ); D_MAGIC_ASSERT( object, FusionObject ); D_ASSERT( executable != NULL ); fusion_vector_foreach (access, index, object->access) { int len = strlen( access ); if (access[len-1] == '*') { if (!strncmp( access, executable, len - 1 )) return DR_OK; } else if (!strcmp( access, executable )) return DR_OK; } return DR_ACCESSDENIED; } DirectResult fusion_object_add_owner( FusionObject *object, FusionID owner ) { FusionID id; int i; D_DEBUG_AT( Fusion_Object, "%s( %p, %lu )\n", __FUNCTION__, object, owner ); D_MAGIC_ASSERT( object, FusionObject ); fusion_vector_foreach (id, i, object->owners) { if (id == owner) return DR_OK; } D_DEBUG_AT( Fusion_Object_Owner, " -> add %lu (object %p id %u)\n", owner, object, object->id ); return fusion_vector_add( &object->owners, (void*) owner ); } DirectResult fusion_object_check_owner( FusionObject *object, FusionID owner, bool succeed_if_not_owned ) { FusionID id; int i; D_DEBUG_AT( Fusion_Object, "%s( %p, %lu )\n", __FUNCTION__, object, owner ); D_MAGIC_ASSERT( object, FusionObject ); D_DEBUG_AT( Fusion_Object_Owner, " -> check %lu and %ssucceed if not owned (object %p id %u)\n", owner, succeed_if_not_owned ? "" : "don't ", object, object->id ); if (succeed_if_not_owned && object->owners.count == 0) { D_DEBUG_AT( Fusion_Object_Owner, " => SUCCESS (no owner)\n" ); return DR_OK; } fusion_vector_foreach (id, i, object->owners) { if (id == owner) { D_DEBUG_AT( Fusion_Object_Owner, " => SUCCESS (found as owner with index %d)\n", i ); return DR_OK; } } D_DEBUG_AT( Fusion_Object_Owner, " => FAIL (not found)\n" ); return DR_IDNOTFOUND; } DirectResult fusion_object_catch( FusionObject *object ) { DirectResult ret; D_MAGIC_ASSERT( object, FusionObject ); ret = fusion_ref_up( &object->ref, false ); if (ret) return ret; ret = fusion_ref_catch( &object->ref ); if (ret) { D_DERROR( ret, "Fusion/Object: Failed to catch reference [%d] | [0x%08x]!\n", object->ref.multi.id, (unsigned int) object->ref.multi.id ); fusion_ref_down( &object->ref, false ); return ret; } return DR_OK; } ================================================ FILE: lib/fusion/object.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__OBJECT_H__ #define __FUSION__OBJECT_H__ #include #include #include #include /**********************************************************************************************************************/ typedef u32 FusionObjectID; typedef enum { FOS_INIT = 0x00000000, FOS_ACTIVE = 0x00000001, FOS_DEINIT = 0x00000002 } FusionObjectState; struct __Fusion_FusionObject { DirectLink link; FusionObjectPool *pool; int magic; FusionObjectID id; FusionID identity; FusionObjectState state; FusionRef ref; FusionReactor *reactor; FusionWorldShared *shared; FusionHash *properties; FusionVector owners; FusionVector access; DirectTraceBuffer *create_stack; void *type_instance; }; typedef void (*FusionObjectDestructor)( FusionObject *object, bool zombie, void *ctx ); struct __Fusion_FusionObjectPool { int magic; FusionWorldShared *shared; FusionSkirmish lock; FusionHash *objects; FusionObjectID id_pool; char *name; int object_size; int message_size; FusionObjectDestructor destructor; void *ctx; FusionCall call; bool secure; }; /**********************************************************************************************************************/ typedef bool (*FusionObjectCallback)( FusionObjectPool *pool, FusionObject *object, void *ctx ); /**********************************************************************************************************************/ FusionObjectPool FUSION_API *fusion_object_pool_create ( const char *name, int object_size, int message_size, FusionObjectDestructor destructor, void *ctx, const FusionWorld *world ); DirectResult FUSION_API fusion_object_pool_destroy ( FusionObjectPool *pool, FusionWorld *world, bool shutdown_info ); DirectResult FUSION_API fusion_object_pool_enum ( FusionObjectPool *pool, FusionObjectCallback callback, void *ctx ); DirectResult FUSION_API fusion_object_pool_size ( FusionObjectPool *pool, size_t *ret_size ); FusionObject FUSION_API *fusion_object_create ( FusionObjectPool *pool, const FusionWorld *world, FusionID identity ); DirectResult FUSION_API fusion_object_get ( FusionObjectPool *pool, FusionObjectID object_id, FusionObject **ret_object ); DirectResult FUSION_API fusion_object_lookup ( FusionObjectPool *pool, FusionObjectID object_id, FusionObject **ret_object ); DirectResult FUSION_API fusion_object_set_lock ( FusionObject *object, FusionSkirmish *lock ); DirectResult FUSION_API fusion_object_activate ( FusionObject *object ); DirectResult FUSION_API fusion_object_destroy ( FusionObject *object ); DirectResult FUSION_API fusion_object_set_property ( FusionObject *object, const char *key, void *value, void **old_value ); void FUSION_API *fusion_object_get_property ( FusionObject *object, const char *key ); void FUSION_API fusion_object_remove_property( FusionObject *object, const char *key, void **ret_val ); DirectResult FUSION_API fusion_object_add_access ( FusionObject *object, const char *exectuable ); DirectResult FUSION_API fusion_object_has_access ( FusionObject *object, const char *executable ); DirectResult FUSION_API fusion_object_add_owner ( FusionObject *object, FusionID owner ); DirectResult FUSION_API fusion_object_check_owner ( FusionObject *object, FusionID owner, bool succeed_if_not_owned ); DirectResult FUSION_API fusion_object_catch ( FusionObject *object ); /**********************************************************************************************************************/ #define FUSION_OBJECT_METHODS(type,prefix) \ \ static __inline__ DirectResult \ prefix##_attach( type *object, \ ReactionFunc func, \ void *ctx, \ Reaction *ret_reaction ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_attach( ((FusionObject*) object)->reactor, func, ctx, ret_reaction ); \ } \ \ static __inline__ DirectResult \ prefix##_attach_channel( type *object, \ int channel, \ ReactionFunc func, \ void *ctx, \ Reaction *ret_reaction ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_attach_channel( ((FusionObject*) object)->reactor, channel, func, ctx, ret_reaction ); \ } \ \ static __inline__ DirectResult \ prefix##_detach( type *object, \ Reaction *reaction ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_detach( ((FusionObject*) object)->reactor, reaction ); \ } \ \ static __inline__ DirectResult \ prefix##_attach_global( type *object, \ int index, \ void *ctx, \ GlobalReaction *reaction ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_attach_global( ((FusionObject*) object)->reactor, index, ctx, reaction ); \ } \ \ static __inline__ DirectResult \ prefix##_detach_global( type *object, \ GlobalReaction *reaction ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_detach_global( ((FusionObject*) object)->reactor, reaction ); \ } \ \ static __inline__ DirectResult \ prefix##_dispatch( type *object, \ void *message, \ const ReactionFunc *globals ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_dispatch( ((FusionObject*) object)->reactor, message, true, globals ); \ } \ \ static __inline__ DirectResult \ prefix##_dispatch_channel( type *object, \ int channel, \ void *message, \ int size, \ const ReactionFunc *globals ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_reactor_dispatch_channel( ((FusionObject*) object)->reactor, \ channel, message, size, true, globals ); \ } \ \ static __inline__ DirectResult \ prefix##_ref( type *object ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_ref_up( &((FusionObject*) object)->ref, false ); \ } \ \ static __inline__ DirectResult \ prefix##_unref( type *object ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_ref_down( &((FusionObject*) object)->ref, false ); \ } \ \ static __inline__ DirectResult \ prefix##_ref_stat( type *object, int *refs ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ return fusion_ref_stat ( &((FusionObject*) object)->ref, refs ); \ } \ \ static __inline__ DirectResult \ prefix##_link( type **link, \ type *object ) \ { \ DirectResult ret; \ \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ \ ret = fusion_ref_up( &((FusionObject*) object)->ref, true ); \ if (ret) \ return ret; \ \ *link = object; \ \ return DR_OK; \ } \ \ static __inline__ DirectResult \ prefix##_unlink( type **link ) \ { \ type *object = *link; \ \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ \ *link = NULL; \ \ return fusion_ref_down( &((FusionObject*) object)->ref, true ); \ } \ \ static __inline__ DirectResult \ prefix##_inherit( type *object, \ void *from ) \ { \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ D_MAGIC_ASSERT( (FusionObject*) from, FusionObject ); \ \ return fusion_ref_inherit( &((FusionObject*) object)->ref, &((FusionObject*) from)->ref ); \ } \ \ static __inline__ DirectResult \ prefix##_globalize( type *object ) \ { \ DirectResult ret; \ \ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \ \ ret = fusion_ref_up( &((FusionObject*) object)->ref, true ); \ if (ret) \ return ret; \ \ ret = fusion_ref_down( &((FusionObject*) object)->ref, false ); \ if (ret) \ fusion_ref_down( &((FusionObject*) object)->ref, true ); \ \ return ret; \ } FUSION_OBJECT_METHODS( void, fusion_object ) #endif ================================================ FILE: lib/fusion/protocol.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION_PROTOCOL_H__ #define __FUSION_PROTOCOL_H__ #include /**********************************************************************************************************************/ typedef enum { FMT_SEND = 0x00000000, FMT_ENTER = 0x00000001, FMT_LEAVE = 0x00000002, FMT_CALL = 0x00000003, FMT_CALLRET = 0x00000004, FMT_REACTOR = 0x00000005 } FusionMessageType; /* * Enter world (slave). */ typedef struct { FusionMessageType type; FusionID fusion_id; } FusionEnter; /* * Leave the world (slave). */ typedef struct { FusionMessageType type; FusionID fusion_id; } FusionLeave; /* * Execute a call. */ typedef struct { FusionMessageType type; unsigned int serial; FusionID caller; int call_id; int call_arg; unsigned int call_length; /* Length of data. */ unsigned int ret_length; /* Maximum length of return data. */ void *handler; void *handler3; void *ctx; FusionCallExecFlags flags; } FusionCallMessage; /* * Send call return. */ typedef struct { FusionMessageType type; unsigned int length; } FusionCallReturn; /* * Send reactor message. */ typedef struct { FusionMessageType type; int id; int channel; FusionRef *ref; } FusionReactorMessage; typedef union { FusionMessageType type; FusionEnter enter; FusionLeave leave; FusionCallMessage call; FusionCallReturn callret; FusionReactorMessage reactor; } FusionMessage; #endif ================================================ FILE: lib/fusion/reactor.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #if FUSION_BUILD_MULTI #include #if FUSION_BUILD_KERNEL #include #if D_DEBUG_ENABLED #include #endif #else /* FUSION_BUILD_KERNEL */ #include #endif /* FUSION_BUILD_KERNEL */ #endif /* FUSION_BUILD_MULTI */ D_DEBUG_DOMAIN( Fusion_Reactor, "Fusion/Reactor", "Fusion's Reactor" ); /**********************************************************************************************************************/ static void process_globals( FusionReactor *reactor, const void *msg_data, const ReactionFunc *globals ); #if FUSION_BUILD_MULTI typedef struct { DirectLink link; int magic; DirectRWLock lock; int reactor_id; FusionReactor *reactor; DirectLink *links; /* Reactor listeners attached to node. */ } ReactorNode; typedef struct { DirectLink link; int magic; Reaction *reaction; int channel; } NodeLink; static void remove_node_link( ReactorNode *node, NodeLink *link ) { D_MAGIC_ASSERT( node, ReactorNode ); D_MAGIC_ASSERT( link, NodeLink ); D_ASSUME( link->reaction == NULL ); direct_list_remove( &node->links, &link->link ); D_MAGIC_CLEAR( link ); D_FREE( link ); } static ReactorNode *lock_node ( int reactor_id, bool add_it, bool wlock, FusionReactor *reactor, FusionWorld *world ); static void unlock_node( ReactorNode *node ); #if FUSION_BUILD_KERNEL FusionReactor * fusion_reactor_new( int msg_size, const char *name, const FusionWorld *world ) { FusionEntryInfo info; FusionReactor *reactor; D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( '%s', size %d )\n", __FUNCTION__, name, msg_size ); /* Allocate shared reactor data. */ reactor = SHCALLOC( world->shared->main_pool, 1, sizeof(FusionReactor) ); if (!reactor) { D_OOSHM(); return NULL; } /* Create a new reactor. */ while (ioctl( world->fusion_fd, FUSION_REACTOR_NEW, &reactor->id )) { if (errno == EINTR) continue; D_PERROR( "Fusion/Reactor: FUSION_REACTOR_NEW" ); SHFREE( world->shared->main_pool, reactor ); return NULL; } /* Set the static message size. */ reactor->msg_size = msg_size; /* Set default lock for global reactions. */ reactor->globals_lock = &world->shared->reactor_globals; D_DEBUG_AT( Fusion_Reactor, " -> new reactor %p [%d] with lock %p [%d]\n", reactor, reactor->id, reactor->globals_lock, reactor->globals_lock->multi.id ); reactor->shared = world->shared; reactor->direct = true; D_MAGIC_SET( reactor, FusionReactor ); info.type = FT_REACTOR; info.id = reactor->id; direct_snputs( info.name, name, sizeof(info.name) ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); return reactor; } DirectResult fusion_reactor_destroy( FusionReactor *reactor ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_MAGIC_ASSERT( reactor->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d] )\n", __FUNCTION__, reactor, reactor->id ); D_ASSUME( !reactor->destroyed ); if (reactor->destroyed) return DR_DESTROYED; while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DESTROY, &reactor->id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Reactor: FUSION_REACTOR_DESTROY" ); return DR_FUSION; } reactor->destroyed = true; return DR_OK; } DirectResult fusion_reactor_free( FusionReactor *reactor ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_MAGIC_ASSERT( reactor->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d] )\n", __FUNCTION__, reactor, reactor->id ); D_MAGIC_CLEAR( reactor ); if (!reactor->destroyed) while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DESTROY, &reactor->id ) && errno == EINTR); /* Free shared reactor data. */ SHFREE( reactor->shared->main_pool, reactor ); return DR_OK; } DirectResult fusion_reactor_attach_channel( FusionReactor *reactor, int channel, ReactionFunc func, void *ctx, Reaction *reaction ) { ReactorNode *node; NodeLink *link; FusionReactorAttach attach; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( func != NULL ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], func %p, ctx %p, reaction %p )\n", __FUNCTION__, reactor, reactor->id, func, ctx, reaction ); link = D_CALLOC( 1, sizeof(NodeLink) ); if (!link) return D_OOM(); node = lock_node( reactor->id, true, true, reactor, NULL ); if (!node) { D_FREE( link ); return DR_FUSION; } attach.reactor_id = reactor->id; attach.channel = channel; while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_ATTACH, &attach )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); unlock_node( node ); D_FREE( link ); return DR_DESTROYED; } D_PERROR( "Fusion/Reactor: FUSION_REACTOR_ATTACH" ); unlock_node( node ); D_FREE( link ); return DR_FUSION; } /* Fill out callback information. */ reaction->func = func; reaction->ctx = ctx; reaction->node_link = link; link->reaction = reaction; link->channel = channel; D_MAGIC_SET( link, NodeLink ); /* Prepend the reaction to the local reaction list. */ direct_list_prepend( &node->links, &link->link ); unlock_node( node ); return DR_OK; } DirectResult fusion_reactor_detach( FusionReactor *reactor, Reaction *reaction ) { ReactorNode *node; NodeLink *link; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], reaction %p ) <- func %p, ctx %p\n", __FUNCTION__, reactor, reactor->id, reaction, reaction->func, reaction->ctx ); node = lock_node( reactor->id, false, true, reactor, NULL ); if (!node) { return DR_BUG; } link = reaction->node_link; D_ASSUME( link != NULL ); if (link) { FusionReactorDetach detach; D_ASSERT( link->reaction == reaction ); detach.reactor_id = reactor->id; detach.channel = link->channel; reaction->node_link = NULL; link->reaction = NULL; remove_node_link( node, link ); while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DETACH, &detach )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); unlock_node( node ); return DR_DESTROYED; } D_PERROR( "Fusion/Reactor: FUSION_REACTOR_DETACH" ); unlock_node( node ); return DR_FUSION; } } unlock_node( node ); return DR_OK; } DirectResult fusion_reactor_dispatch_channel( FusionReactor *reactor, int channel, const void *msg_data, int msg_size, bool self, const ReactionFunc *globals ) { FusionWorld *world; FusionReactorDispatch dispatch; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( msg_data != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], msg_data %p, self %s, globals %p)\n", __FUNCTION__, reactor, reactor->id, msg_data, self ? "true" : "false", globals ); world = _fusion_world( reactor->shared ); fusion_world_flush_calls( world, 1 ); /* Handle global reactions first. */ if (channel == 0 && reactor->globals) { if (fusion_config->secure_fusion && !fusion_master(world)) { D_BUG( "global reactions on channel 0, cannot dispatch from secure slave" ); return DR_BUG; } if (globals) process_globals( reactor, msg_data, globals ); else D_ERROR( "Fusion/Reactor: There are global reactions but no globals have been passed to dispatch()!\n" ); } /* Handle local reactions. */ if (self && reactor->direct) { _fusion_reactor_process_message( world, reactor->id, channel, msg_data ); self = false; } /* Initialize dispatch data. */ dispatch.reactor_id = reactor->id; dispatch.channel = channel; dispatch.self = self; dispatch.msg_size = msg_size; dispatch.msg_data = msg_data; /* Dispatch the message to handle foreign reactions. */ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DISPATCH, &dispatch )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Reactor: FUSION_REACTOR_DISPATCH" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_reactor_set_dispatch_callback( FusionReactor *reactor, FusionCall *call, void *call_ptr ) { FusionReactorSetCallback callback; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( call != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], call %p [%d], ptr %p)\n", __FUNCTION__, reactor, reactor->id, call, call->call_id, call_ptr ); /* Fill callback info. */ callback.reactor_id = reactor->id; callback.call_id = call->call_id; callback.call_ptr = call_ptr; /* Set the dispatch callback. */ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_SET_DISPATCH_CALLBACK, &callback )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); return DR_DESTROYED; } D_PERROR( "Fusion/Reactor: FUSION_REACTOR_SET_DISPATCH_CALLBACK" ); return DR_FUSION; } return DR_OK; } DirectResult fusion_reactor_set_name( FusionReactor *reactor, const char *name ) { FusionEntryInfo info; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( name != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, '%s' )\n", __FUNCTION__, reactor, name ); /* Initialize reactor info. */ info.type = FT_REACTOR; info.id = reactor->id; /* Put reactor name into info. */ direct_snputs( info.name, name, sizeof(info.name) ); /* Set the reactor info. */ while (ioctl( _fusion_fd( reactor->shared ), FUSION_ENTRY_SET_INFO, &info )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); return DR_IDNOTFOUND; } D_PERROR( "Fusion/Reactor: FUSION_ENTRY_SET_INFO( reactor %d, '%s' )\n", reactor->id, name ); return DR_FUSION; } return DR_OK; } DirectResult fusion_reactor_add_permissions( FusionReactor *reactor, FusionID fusion_id, FusionReactorPermissions reactor_permissions ) { FusionEntryPermissions permissions; permissions.type = FT_REACTOR; permissions.id = reactor->id; permissions.fusion_id = fusion_id; permissions.permissions = 0; if (reactor_permissions & FUSION_REACTOR_PERMIT_ATTACH_DETACH) { FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REACTOR_ATTACH ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REACTOR_DETACH ); } if (reactor_permissions & FUSION_REACTOR_PERMIT_DISPATCH) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REACTOR_DISPATCH ); while (ioctl( _fusion_fd( reactor->shared ), FUSION_ENTRY_ADD_PERMISSIONS, &permissions ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion/Reactor: FUSION_ENTRY_ADD_PERMISSIONS( id %d )", reactor->id ); return DR_FAILURE; } } return DR_OK; } void _fusion_reactor_process_message( FusionWorld *world, int reactor_id, int channel, const void *msg_data ) { ReactorNode *node; NodeLink *link; D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( msg_data != NULL ); D_DEBUG_AT( Fusion_Reactor, " _fusion_reactor_process_message( [%d], msg_data %p )\n", reactor_id, msg_data ); /* Find the local counter part of the reactor. */ node = lock_node( reactor_id, false, false, NULL, world ); if (!node) return; D_DEBUG_AT( Fusion_Reactor, " -> node %p, reactor %p\n", node, node->reactor ); D_ASSUME( node->links != NULL ); if (!node->links) { D_DEBUG_AT( Fusion_Reactor, " -> no local reactions!\n" ); unlock_node( node ); return; } direct_list_foreach (link, node->links) { Reaction *reaction; D_MAGIC_ASSERT( link, NodeLink ); if (link->channel != channel) continue; reaction = link->reaction; if (!reaction) continue; if (direct_log_domain_check( &Fusion_Reactor )) D_DEBUG_AT( Fusion_Reactor, " -> %s (%p)\n", direct_trace_lookup_symbol_at( reaction->func ), reaction->func ); if (reaction->func( msg_data, reaction->ctx ) == RS_REMOVE) { FusionReactorDetach detach; detach.reactor_id = reactor_id; detach.channel = channel; D_DEBUG_AT( Fusion_Reactor, " -> removing %p, func %p, ctx %p\n", reaction, reaction->func, reaction->ctx ); link->reaction = NULL; /* We can't remove the link as we only have read lock, to avoid dead locks. */ while (ioctl( world->fusion_fd, FUSION_REACTOR_DETACH, &detach )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Reactor: Invalid reactor!\n" ); break; default: D_PERROR( "Fusion/Reactor: FUSION_REACTOR_DETACH" ); break; } break; } } } unlock_node( node ); } #else /* FUSION_BUILD_KERNEL */ typedef struct { DirectLink link; unsigned int refs; FusionID fusion_id; int channel; } Listener; FusionReactor * fusion_reactor_new( int msg_size, const char *name, const FusionWorld *world ) { FusionReactor *reactor; D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( '%s', size %d )\n", __FUNCTION__, name, msg_size ); /* Allocate shared reactor data. */ reactor = SHCALLOC( world->shared->main_pool, 1, sizeof(FusionReactor) ); if (!reactor) { D_OOSHM(); return NULL; } /* Generate the reactor id. */ reactor->id = ++world->shared->reactor_ids; /* Set the static message size. */ reactor->msg_size = msg_size; /* Set default lock for global reactions. */ reactor->globals_lock = &world->shared->reactor_globals; fusion_skirmish_init( &reactor->listeners_lock, "Reactor Listeners", world ); D_DEBUG_AT( Fusion_Reactor, " -> new reactor %p [%d] with lock %p [%d]\n", reactor, reactor->id, reactor->globals_lock, reactor->globals_lock->multi.id ); reactor->shared = world->shared; reactor->direct = true; D_MAGIC_SET( reactor, FusionReactor ); return reactor; } DirectResult fusion_reactor_destroy( FusionReactor *reactor ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_MAGIC_ASSERT( reactor->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d] )\n", __FUNCTION__, reactor, reactor->id ); D_ASSUME( !reactor->destroyed ); if (reactor->destroyed) return DR_DESTROYED; fusion_skirmish_destroy( &reactor->listeners_lock ); reactor->destroyed = true; return DR_OK; } DirectResult fusion_reactor_free( FusionReactor *reactor ) { Listener *listener, *next; D_MAGIC_ASSERT( reactor, FusionReactor ); D_MAGIC_ASSERT( reactor->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d] )\n", __FUNCTION__, reactor, reactor->id ); D_MAGIC_CLEAR( reactor ); direct_list_foreach_safe (listener, next, reactor->listeners) { direct_list_remove( &reactor->listeners, &listener->link ); SHFREE( reactor->shared->main_pool, listener ); } /* Free shared reactor data. */ SHFREE( reactor->shared->main_pool, reactor ); return DR_OK; } DirectResult fusion_reactor_attach_channel( FusionReactor *reactor, int channel, ReactionFunc func, void *ctx, Reaction *reaction ) { DirectResult ret; ReactorNode *node; NodeLink *link; FusionID fusion_id; Listener *listener; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( func != NULL ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], func %p, ctx %p, reaction %p )\n", __FUNCTION__, reactor, reactor->id, func, ctx, reaction ); if (reactor->destroyed) return DR_DESTROYED; link = D_CALLOC( 1, sizeof(NodeLink) ); if (!link) return D_OOM(); node = lock_node( reactor->id, true, true, reactor, NULL ); if (!node) { D_FREE( link ); return DR_FUSION; } fusion_id = _fusion_id( reactor->shared ); fusion_skirmish_prevail( &reactor->listeners_lock ); direct_list_foreach (listener, reactor->listeners) { if (listener->fusion_id == fusion_id && listener->channel == channel) { listener->refs++; break; } } if (!listener) { listener = SHCALLOC( reactor->shared->main_pool, 1, sizeof(Listener) ); if (!listener) { ret = D_OOSHM(); fusion_skirmish_dismiss( &reactor->listeners_lock ); unlock_node( node ); D_FREE( link ); return ret; } listener->refs = 1; listener->fusion_id = fusion_id; listener->channel = channel; direct_list_append( &reactor->listeners, &listener->link ); } fusion_skirmish_dismiss( &reactor->listeners_lock ); /* Fill out callback information. */ reaction->func = func; reaction->ctx = ctx; reaction->node_link = link; link->reaction = reaction; link->channel = channel; D_MAGIC_SET( link, NodeLink ); /* Prepend the reaction to the local reaction list. */ direct_list_prepend( &node->links, &link->link ); unlock_node( node ); return DR_OK; } DirectResult fusion_reactor_detach( FusionReactor *reactor, Reaction *reaction ) { ReactorNode *node; NodeLink *link; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], reaction %p ) <- func %p, ctx %p\n", __FUNCTION__, reactor, reactor->id, reaction, reaction->func, reaction->ctx ); if (reactor->destroyed) return DR_DESTROYED; node = lock_node( reactor->id, false, true, reactor, NULL ); if (!node) { return DR_BUG; } link = reaction->node_link; D_ASSUME( link != NULL ); if (link) { Listener *listener; FusionID fusion_id = _fusion_id( reactor->shared ); D_ASSERT( link->reaction == reaction ); reaction->node_link = NULL; link->reaction = NULL; remove_node_link( node, link ); fusion_skirmish_prevail( &reactor->listeners_lock ); direct_list_foreach (listener, reactor->listeners) { if (listener->fusion_id == fusion_id && listener->channel == link->channel) { if (--listener->refs == 0) { direct_list_remove( &reactor->listeners, &listener->link ); SHFREE( reactor->shared->main_pool, listener ); } break; } } fusion_skirmish_dismiss( &reactor->listeners_lock ); } unlock_node( node ); return DR_OK; } DirectResult fusion_reactor_dispatch_channel( FusionReactor *reactor, int channel, const void *msg_data, int msg_size, bool self, const ReactionFunc *globals ) { FusionWorld *world; Listener *listener, *next; FusionRef *ref = NULL; FusionReactorMessage *msg; struct sockaddr_un addr; int len; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( msg_data != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], msg_data %p, self %s, globals %p)\n", __FUNCTION__, reactor, reactor->id, msg_data, self ? "true" : "false", globals ); if (reactor->destroyed) return DR_DESTROYED; if (msg_size > FUSION_MESSAGE_SIZE-sizeof(FusionReactorMessage)) { D_ERROR( "Fusion/Reactor: Message too large (%d)!\n", msg_size ); return DR_UNSUPPORTED; } world = _fusion_world( reactor->shared ); if (reactor->call) { ref = SHMALLOC( world->shared->main_pool, sizeof(FusionRef) ); if (!ref) return D_OOSHM(); fusion_ref_init( ref, "Dispatch Ref", world ); fusion_ref_up( ref, true ); fusion_ref_watch( ref, reactor->call, 0 ); } /* Handle global reactions first. */ if (channel == 0 && reactor->globals) { if (globals) process_globals( reactor, msg_data, globals ); else D_ERROR( "Fusion/Reactor: There are global reactions but no globals have been passed to dispatch()!\n" ); } /* Handle local reactions. */ if (self && reactor->direct) { _fusion_reactor_process_message( _fusion_world(reactor->shared), reactor->id, channel, msg_data ); self = false; } msg = alloca( sizeof(FusionReactorMessage) + msg_size ); msg->type = FMT_REACTOR; msg->id = reactor->id; msg->channel = channel; msg->ref = ref; direct_memcpy( (void*) msg + sizeof(FusionReactorMessage), msg_data, msg_size ); addr.sun_family = AF_UNIX; len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/", fusion_world_index( world ) ); fusion_skirmish_prevail( &reactor->listeners_lock ); direct_list_foreach_safe (listener, next, reactor->listeners) { if (listener->channel == channel) { DirectResult ret; if (!self && listener->fusion_id == world->fusion_id) continue; if (ref) fusion_ref_up( ref, true ); snprintf( addr.sun_path + len, sizeof(addr.sun_path) - len, "%lx", listener->fusion_id ); D_DEBUG_AT( Fusion_Reactor, " -> sending to '%s'\n", addr.sun_path ); ret = _fusion_send_message( world->fusion_fd, msg, sizeof(FusionReactorMessage) + msg_size, &addr ); if (ret == DR_FUSION) { D_DEBUG_AT( Fusion_Reactor, " -> removing dead listener %lu\n", listener->fusion_id ); if (ref) fusion_ref_down( ref, true ); direct_list_remove( &reactor->listeners, &listener->link ); SHFREE( reactor->shared->main_pool, listener ); } } } fusion_skirmish_dismiss( &reactor->listeners_lock ); if (ref) { fusion_ref_down( ref, true ); if (fusion_ref_zero_trylock( ref ) == DR_OK) { fusion_ref_destroy( ref ); SHFREE( world->shared->main_pool, ref ); } } D_DEBUG_AT( Fusion_Reactor, "%s( %p ) done\n", __FUNCTION__, reactor ); return DR_OK; } DirectResult fusion_reactor_set_dispatch_callback( FusionReactor *reactor, FusionCall *call, void *call_ptr ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( call != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], call %p [%d], ptr %p)\n", __FUNCTION__, reactor, reactor->id, call, call->call_id, call_ptr ); if (reactor->destroyed) return DR_DESTROYED; if (call_ptr) return DR_UNIMPLEMENTED; reactor->call = call; return DR_OK; } DirectResult fusion_reactor_set_name( FusionReactor *reactor, const char *name ) { return DR_UNIMPLEMENTED; } DirectResult fusion_reactor_add_permissions( FusionReactor *reactor, FusionID fusion_id, FusionReactorPermissions permissions ) { return DR_UNIMPLEMENTED; } void _fusion_reactor_process_message( FusionWorld *world, int reactor_id, int channel, const void *msg_data ) { ReactorNode *node; NodeLink *link; D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( msg_data != NULL ); D_DEBUG_AT( Fusion_Reactor, " _fusion_reactor_process_message( [%d], msg_data %p )\n", reactor_id, msg_data ); /* Find the local counter part of the reactor. */ node = lock_node( reactor_id, false, false, NULL, world ); if (!node) return; D_DEBUG_AT( Fusion_Reactor, " -> node %p, reactor %p\n", node, node->reactor ); D_ASSUME( node->links != NULL ); if (!node->links) { D_DEBUG_AT( Fusion_Reactor, " -> no local reactions!\n" ); unlock_node( node ); return; } direct_list_foreach (link, node->links) { Reaction *reaction; D_MAGIC_ASSERT( link, NodeLink ); if (link->channel != channel) continue; reaction = link->reaction; if (!reaction) continue; if (reaction->func( msg_data, reaction->ctx ) == RS_REMOVE) { FusionReactor *reactor = node->reactor; Listener *listener; D_DEBUG_AT( Fusion_Reactor, " -> removing %p, func %p, ctx %p\n", reaction, reaction->func, reaction->ctx ); fusion_skirmish_prevail( &reactor->listeners_lock ); direct_list_foreach (listener, reactor->listeners) { if (listener->fusion_id == world->fusion_id && listener->channel == channel) { if (--listener->refs == 0) { direct_list_remove( &reactor->listeners, &listener->link ); SHFREE( world->shared->main_pool, listener ); } break; } } fusion_skirmish_dismiss( &reactor->listeners_lock ); } } unlock_node( node ); } #endif /* FUSION_BUILD_KERNEL */ DirectResult fusion_reactor_set_lock( FusionReactor *reactor, FusionSkirmish *lock ) { DirectResult ret; FusionSkirmish *old; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( lock != NULL ); old = reactor->globals_lock; D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], lock %p [%d] ) <- old %p [%d]\n", __FUNCTION__, reactor, reactor->id, lock, lock->multi.id, old, old->multi.id ); /* Acquire the old lock to make sure that changing the lock doesn't result in mismatching lock/unlock pairs. */ ret = fusion_skirmish_prevail( old ); if (ret) return ret; D_ASSUME( reactor->globals_lock != lock ); /* Set the lock replacement. */ reactor->globals_lock = lock; /* Release the old lock which is obsolete now. */ fusion_skirmish_dismiss( old ); return DR_OK; } DirectResult fusion_reactor_set_lock_only( FusionReactor *reactor, FusionSkirmish *lock ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( lock != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], lock %p [%d] ) <- old %p [%d]\n", __FUNCTION__, reactor, reactor->id, lock, lock->multi.id, reactor->globals_lock, reactor->globals_lock->multi.id ); D_ASSUME( reactor->globals_lock != lock ); /* Set the lock replacement. */ reactor->globals_lock = lock; return DR_OK; } DirectResult fusion_reactor_attach( FusionReactor *reactor, ReactionFunc func, void *ctx, Reaction *reaction ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( func != NULL ); D_ASSERT( reaction != NULL ); return fusion_reactor_attach_channel( reactor, 0, func, ctx, reaction ); } DirectResult fusion_reactor_attach_global( FusionReactor *reactor, int index, void *ctx, GlobalReaction *reaction ) { DirectResult ret; FusionSkirmish *lock; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( index >= 0 ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], index %d, ctx %p, reaction %p )\n", __FUNCTION__, reactor, reactor->id, index, ctx, reaction ); /* Initialize reaction data. */ reaction->index = index; reaction->ctx = ctx; reaction->attached = true; /* Remember for safety. */ lock = reactor->globals_lock; /* Lock the list of global reactions. */ ret = fusion_skirmish_prevail( lock ); if (ret) return ret; if (lock != reactor->globals_lock) D_WARN( "using old lock once more" ); /* Prepend the reaction to the list. */ direct_list_prepend( &reactor->globals, &reaction->link ); /* Unlock the list of global reactions. */ fusion_skirmish_dismiss( lock ); return DR_OK; } DirectResult fusion_reactor_detach_global( FusionReactor *reactor, GlobalReaction *reaction ) { DirectResult ret; FusionSkirmish *lock; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p [%d], reaction %p ) <- index %d, ctx %p\n", __FUNCTION__, reactor, reactor->id, reaction, reaction->index, reaction->ctx ); /* Remember for safety. */ lock = reactor->globals_lock; /* Lock the list of global reactions. */ ret = fusion_skirmish_prevail( lock ); if (ret) return ret; if (lock != reactor->globals_lock) D_WARN( "using old lock once more" ); /* Check against multiple detach. */ if (reaction->attached) { /* Mark as detached. */ reaction->attached = false; /* Remove the reaction from the list. */ direct_list_remove( &reactor->globals, &reaction->link ); } /* Unlock the list of global reactions. */ fusion_skirmish_dismiss( lock ); return DR_OK; } DirectResult fusion_reactor_dispatch( FusionReactor *reactor, const void *msg_data, bool self, const ReactionFunc *globals ) { D_MAGIC_ASSERT( reactor, FusionReactor ); return fusion_reactor_dispatch_channel( reactor, 0, msg_data, reactor->msg_size, self, globals ); } DirectResult fusion_reactor_direct( FusionReactor *reactor, bool direct ) { D_MAGIC_ASSERT( reactor, FusionReactor ); reactor->direct = direct; return DR_OK; } void _fusion_reactor_free_all( FusionWorld *world ) { ReactorNode *node, *node_next; D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Reactor, "%s() <- nodes %p\n", __FUNCTION__, world->reactor_nodes ); direct_mutex_lock( &world->reactor_nodes_lock ); direct_list_foreach_safe (node, node_next, world->reactor_nodes) { NodeLink *link, *link_next; D_MAGIC_ASSERT( node, ReactorNode ); direct_rwlock_wrlock( &node->lock ); direct_list_foreach_safe (link, link_next, node->links) { D_MAGIC_ASSERT( link, NodeLink ); D_MAGIC_CLEAR( link ); D_FREE( link ); } direct_rwlock_unlock( &node->lock ); direct_rwlock_deinit( &node->lock ); D_MAGIC_CLEAR( node ); D_FREE( node ); } world->reactor_nodes = NULL; direct_mutex_unlock( &world->reactor_nodes_lock ); } static void process_globals( FusionReactor *reactor, const void *msg_data, const ReactionFunc *globals ) { GlobalReaction *global, *next; FusionSkirmish *lock; int max_index = -1; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( msg_data != NULL ); D_ASSERT( globals != NULL ); D_DEBUG_AT( Fusion_Reactor, " process_globals( %p [%d], msg_data %p, globals %p )\n", reactor, reactor->id, msg_data, globals ); /* Find maximum reaction index. */ while (globals[max_index+1]) max_index++; if (max_index < 0) return; /* Remember for safety. */ lock = reactor->globals_lock; /* Lock the list of global reactions. */ if (fusion_skirmish_prevail( lock )) return; if (lock != reactor->globals_lock) D_WARN( "using old lock once more" ); /* Loop through all global reactions. */ direct_list_foreach_safe (global, next, reactor->globals) { int index = global->index; /* Check if the index is valid. */ if (index < 0 || index > max_index) { D_WARN( "global reaction index out of bounds (%d/%d)", global->index, max_index ); continue; } /* Remove the reaction if requested. */ if (globals[global->index]( msg_data, global->ctx ) == RS_REMOVE) { D_DEBUG_AT( Fusion_Reactor, " -> removing %p, index %d, ctx %p\n", global, global->index, global->ctx ); /* Mark as detached, since the global reaction is being removed from the global reaction list. */ global->attached = false; direct_list_remove( &reactor->globals, &global->link ); } } /* Unlock the list of global reactions. */ fusion_skirmish_dismiss( lock ); } static ReactorNode * lock_node( int reactor_id, bool add_it, bool wlock, FusionReactor *reactor, FusionWorld *world ) { ReactorNode *node, *node_next; FusionWorldShared *shared; D_DEBUG_AT( Fusion_Reactor, " lock_node( [%d], add %s, reactor %p )\n", reactor_id, add_it ? "true" : "false", reactor ); D_ASSERT( reactor != NULL || (!add_it && world != NULL) ); if (reactor) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_MAGIC_ASSERT( reactor->shared, FusionWorldShared ); shared = reactor->shared; world = _fusion_world( shared ); } else { D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); shared = world->shared; } direct_mutex_lock( &world->reactor_nodes_lock ); direct_list_foreach_safe (node, node_next, world->reactor_nodes) { D_MAGIC_ASSERT( node, ReactorNode ); if (node->reactor_id == reactor_id) { if (wlock) { NodeLink *link, *link_next; direct_rwlock_wrlock( &node->lock ); direct_list_foreach_safe (link, link_next, node->links) { D_MAGIC_ASSERT( link, NodeLink ); if (!link->reaction) { D_DEBUG_AT( Fusion_Reactor, " -> cleaning up %p\n", link ); remove_node_link( node, link ); } else D_ASSERT( link->reaction->node_link == link ); } } else direct_rwlock_rdlock( &node->lock ); if (!node->links && !add_it) { direct_list_remove( &world->reactor_nodes, &node->link ); direct_rwlock_unlock( &node->lock ); direct_rwlock_deinit( &node->lock ); D_MAGIC_CLEAR( node ); D_FREE( node ); node = NULL; } else { D_ASSERT( node->reactor == reactor || reactor == NULL ); direct_list_move_to_front( &world->reactor_nodes, &node->link ); } direct_mutex_unlock( &world->reactor_nodes_lock ); return node; } if (!direct_rwlock_trywrlock( &node->lock )) { if (!node->links) { direct_list_remove( &world->reactor_nodes, &node->link ); direct_rwlock_unlock( &node->lock ); direct_rwlock_deinit( &node->lock ); D_MAGIC_CLEAR( node ); D_FREE( node ); } else { direct_rwlock_unlock( &node->lock ); } } } if (add_it) { D_MAGIC_ASSERT( reactor, FusionReactor ); node = D_CALLOC( 1, sizeof(ReactorNode) ); if (!node) { D_OOM(); return NULL; } direct_rwlock_init( &node->lock ); if (wlock) direct_rwlock_wrlock( &node->lock ); else direct_rwlock_rdlock( &node->lock ); node->reactor_id = reactor_id; node->reactor = reactor; D_MAGIC_SET( node, ReactorNode ); direct_list_prepend( &world->reactor_nodes, &node->link ); direct_mutex_unlock( &world->reactor_nodes_lock ); return node; } direct_mutex_unlock( &world->reactor_nodes_lock ); return NULL; } static void unlock_node( ReactorNode *node ) { D_ASSERT( node != NULL ); direct_rwlock_unlock( &node->lock ); } #else /* FUSION_BUILD_MULTI */ FusionReactor * fusion_reactor_new( int msg_size, const char *name, const FusionWorld *world ) { FusionReactor *reactor; D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Reactor, "%s( '%s', size %d )\n", __FUNCTION__, name, msg_size ); reactor = D_CALLOC( 1, sizeof(FusionReactor) ); if (!reactor) return NULL; reactor->msg_size = msg_size; reactor->world = (FusionWorld*) world; direct_recursive_mutex_init( &reactor->reactions_lock ); direct_recursive_mutex_init( &reactor->globals_mutex ); D_MAGIC_SET( reactor, FusionReactor ); return reactor; } DirectResult fusion_reactor_destroy( FusionReactor *reactor ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_DEBUG_AT( Fusion_Reactor, "%s( %p )\n", __FUNCTION__, reactor ); D_ASSUME( !reactor->destroyed ); reactor->destroyed = true; return DR_OK; } DirectResult fusion_reactor_free( FusionReactor *reactor ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_DEBUG_AT( Fusion_Reactor, "%s( %p )\n", __FUNCTION__, reactor ); if (_fusion_event_dispatcher_process_reactor_free( reactor->world, reactor )) return DR_OK; reactor->reactions = NULL; direct_mutex_deinit( &reactor->reactions_lock ); reactor->globals = NULL; direct_mutex_deinit( &reactor->globals_mutex ); D_MAGIC_CLEAR( reactor ); D_FREE( reactor ); return DR_OK; } DirectResult fusion_reactor_attach_channel( FusionReactor *reactor, int channel, ReactionFunc func, void *ctx, Reaction *reaction ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( func != NULL ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, func %p, ctx %p, reaction %p )\n", __FUNCTION__, reactor, func, ctx, reaction ); reaction->func = func; reaction->ctx = ctx; reaction->node_link = (void*)(long) channel; direct_mutex_lock( &reactor->reactions_lock ); direct_list_prepend( &reactor->reactions, &reaction->link ); direct_mutex_unlock( &reactor->reactions_lock ); return DR_OK; } DirectResult fusion_reactor_detach( FusionReactor *reactor, Reaction *reaction ) { D_ASSERT( reactor != NULL ); D_ASSERT( reaction != NULL ); D_MAGIC_ASSERT( reactor, FusionReactor ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, reaction %p ) <- func %p, ctx %p\n", __FUNCTION__, reactor, reaction, reaction->func, reaction->ctx ); direct_mutex_lock( &reactor->reactions_lock ); direct_list_remove( &reactor->reactions, &reaction->link ); direct_mutex_unlock( &reactor->reactions_lock ); return DR_OK; } DirectResult fusion_reactor_dispatch_channel( FusionReactor *reactor, int channel, const void *msg_data, int msg_size, bool self, const ReactionFunc *globals ) { D_ASSERT( reactor != NULL ); D_ASSERT( msg_data != NULL ); D_MAGIC_ASSERT( reactor, FusionReactor ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, msg_data %p, self %s, globals %p)\n", __FUNCTION__, reactor, msg_data, self ? "true" : "false", globals ); if (channel == 0 && reactor->globals) { if (globals) process_globals( reactor, msg_data, globals ); else D_ERROR( "Fusion/Reactor: There are global reactions but no globals have been passed to dispatch()!\n" ); } if (!self) return DR_OK; _fusion_event_dispatcher_process_reactions( reactor->world, reactor, channel, (void*) msg_data, msg_size ); return DR_OK; } DirectResult fusion_reactor_set_dispatch_callback( FusionReactor *reactor, FusionCall *call, void *call_ptr ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } DirectResult fusion_reactor_set_name( FusionReactor *reactor, const char *name ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } DirectResult fusion_reactor_add_permissions( FusionReactor *reactor, FusionID fusion_id, FusionReactorPermissions permissions ) { D_MAGIC_ASSERT( reactor, FusionReactor ); return DR_OK; } DirectResult fusion_reactor_set_lock( FusionReactor *reactor, FusionSkirmish *lock ) { D_ASSERT( reactor != NULL ); D_ASSERT( lock != NULL ); return DR_UNIMPLEMENTED; } DirectResult fusion_reactor_set_lock_only( FusionReactor *reactor, FusionSkirmish *lock ) { D_ASSERT( reactor != NULL ); D_ASSERT( lock != NULL ); return DR_UNIMPLEMENTED; } DirectResult fusion_reactor_attach( FusionReactor *reactor, ReactionFunc func, void *ctx, Reaction *reaction ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( func != NULL ); D_ASSERT( reaction != NULL ); return fusion_reactor_attach_channel( reactor, 0, func, ctx, reaction ); } DirectResult fusion_reactor_attach_global( FusionReactor *reactor, int index, void *ctx, GlobalReaction *reaction ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( index >= 0 ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, index %d, ctx %p, reaction %p )\n", __FUNCTION__, reactor, index, ctx, reaction ); reaction->index = index; reaction->ctx = ctx; /* Mark the reaction as attached now. */ reaction->attached = true; direct_mutex_lock( &reactor->globals_mutex ); direct_list_prepend( &reactor->globals, &reaction->link ); direct_mutex_unlock( &reactor->globals_mutex ); return DR_OK; } DirectResult fusion_reactor_detach_global( FusionReactor *reactor, GlobalReaction *reaction ) { D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( reaction != NULL ); D_DEBUG_AT( Fusion_Reactor, "%s( %p, reaction %p ) <- index %d, ctx %p\n", __FUNCTION__, reactor, reaction, reaction->index, reaction->ctx ); direct_mutex_lock( &reactor->globals_mutex ); /* Check to prevent multiple detaches from being performed. */ if (reaction->attached) { /* Mark as detached, since the global reaction is being removed from the global reaction list. */ reaction->attached = false; /* Remove the reaction from the list. */ direct_list_remove( &reactor->globals, &reaction->link ); } direct_mutex_unlock( &reactor->globals_mutex ); return DR_OK; } DirectResult fusion_reactor_dispatch( FusionReactor *reactor, const void *msg_data, bool self, const ReactionFunc *globals ) { D_MAGIC_ASSERT( reactor, FusionReactor ); return fusion_reactor_dispatch_channel( reactor, 0, msg_data, reactor->msg_size, self, globals ); } DirectResult fusion_reactor_direct( FusionReactor *reactor, bool direct ) { D_MAGIC_ASSERT( reactor, FusionReactor ); return DR_OK; } static void process_globals( FusionReactor *reactor, const void *msg_data, const ReactionFunc *globals ) { GlobalReaction *global, *next; int max_index = -1; D_MAGIC_ASSERT( reactor, FusionReactor ); D_ASSERT( msg_data != NULL ); D_ASSERT( globals != NULL ); D_DEBUG_AT( Fusion_Reactor, " process_globals( %p [%d], msg_data %p, globals %p )\n", reactor, reactor->id, msg_data, globals ); /* Find maximum reaction index. */ while (globals[max_index+1]) max_index++; if (max_index < 0) return; direct_mutex_lock( &reactor->globals_mutex ); /* Loop through all global reactions. */ direct_list_foreach_safe (global, next, reactor->globals) { if (global->index < 0 || global->index > max_index) { D_WARN( "global reaction index out of bounds (%d/%d)", global->index, max_index ); } else { /* Remove the reaction if requested. */ if (globals[global->index]( msg_data, global->ctx ) == RS_REMOVE) { D_DEBUG_AT( Fusion_Reactor, " -> removing %p, index %d, ctx %p\n", global, global->index, global->ctx ); /* Mark as detached, since the global reaction is being removed from the global reaction list. */ global->attached = false; direct_list_remove( &reactor->globals, &global->link ); } } } direct_mutex_unlock( &reactor->globals_mutex ); } #endif /* FUSION_BUILD_MULTI */ ================================================ FILE: lib/fusion/reactor.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__REACTOR_H__ #define __FUSION__REACTOR_H__ #include #include /**********************************************************************************************************************/ struct __Fusion_FusionReactor { int magic; int id; int msg_size; bool direct; bool destroyed; bool free; DirectLink *globals; FusionSkirmish *globals_lock; DirectMutex globals_mutex; FusionWorldShared *shared; FusionWorld *world; DirectLink *listeners; FusionSkirmish listeners_lock; FusionCall *call; DirectLink *reactions; DirectMutex reactions_lock; }; /**********************************************************************************************************************/ typedef enum { RS_OK = 0x00000000, RS_REMOVE = 0x00000001, RS_DROP = 0x00000002 } ReactionResult; typedef enum { FUSION_REACTOR_PERMIT_NONE = 0x00000000, FUSION_REACTOR_PERMIT_ATTACH_DETACH = 0x00000001, FUSION_REACTOR_PERMIT_DISPATCH = 0x00000002, FUSION_REACTOR_PERMIT_ALL = 0x00000003 } FusionReactorPermissions; typedef ReactionResult (*ReactionFunc)( const void *msg_data, void *ctx ); typedef struct { DirectLink link; ReactionFunc func; void *ctx; void *node_link; } Reaction; typedef struct { DirectLink link; int index; void *ctx; bool attached; } GlobalReaction; /**********************************************************************************************************************/ /* * Create a new reactor configured for the specified message data size. */ FusionReactor FUSION_API *fusion_reactor_new ( int msg_size, const char *name, const FusionWorld *world ); /* * Destroy the reactor. */ DirectResult FUSION_API fusion_reactor_destroy ( FusionReactor *reactor ); /* * Free the reactor. */ DirectResult FUSION_API fusion_reactor_free ( FusionReactor *reactor ); /* * Attach a local reaction to a specific reactor channel (0-1023). */ DirectResult FUSION_API fusion_reactor_attach_channel ( FusionReactor *reactor, int channel, ReactionFunc func, void *ctx, Reaction *reaction ); /* * Detach an attached local reaction from the reactor. */ DirectResult FUSION_API fusion_reactor_detach ( FusionReactor *reactor, Reaction *reaction ); /* * Dispatch a message via a specific channel (0-1023). * Setting 'self' to false excludes the caller's local reactions. */ DirectResult FUSION_API fusion_reactor_dispatch_channel ( FusionReactor *reactor, int channel, const void *msg_data, int msg_size, bool self, const ReactionFunc *globals ); /* * Have the call executed when a dispatched message has been processed by all recipients. */ DirectResult FUSION_API fusion_reactor_set_dispatch_callback( FusionReactor *reactor, FusionCall *call, void *call_ptr ); /* * Change the name of the reactor. */ DirectResult FUSION_API fusion_reactor_set_name ( FusionReactor *reactor, const char *name ); /* * Give permissions to another fusionee to use the reactor. */ DirectResult FUSION_API fusion_reactor_add_permissions ( FusionReactor *reactor, FusionID fusion_id, FusionReactorPermissions permissions ); /* * Make the reactor use the specified lock for managing global reactions. */ DirectResult FUSION_API fusion_reactor_set_lock ( FusionReactor *reactor, FusionSkirmish *lock ); /* * Don't lock, i.e. use this function in fusion_object_set_lock() as this is called during object initialization. */ DirectResult FUSION_API fusion_reactor_set_lock_only ( FusionReactor *reactor, FusionSkirmish *lock ); /* * Attach a local reaction to the reactor (channel 0). */ DirectResult FUSION_API fusion_reactor_attach ( FusionReactor *reactor, ReactionFunc func, void *ctx, Reaction *reaction ); /* * Attach a global reaction to the reactor. * It's always called directly, no matter which fusionee calls fusion_reactor_dispatch(). */ DirectResult FUSION_API fusion_reactor_attach_global ( FusionReactor *reactor, int index, void *ctx, GlobalReaction *reaction ); /* * Detach an attached global reaction from the reactor. */ DirectResult FUSION_API fusion_reactor_detach_global ( FusionReactor *reactor, GlobalReaction *reaction ); /* * Dispatch a message to any attached reaction (channel 0). * Setting 'self' to false excludes the caller's local reactions. */ DirectResult FUSION_API fusion_reactor_dispatch ( FusionReactor *reactor, const void *msg_data, bool self, const ReactionFunc *globals ); /* * Specify whether local message handlers (reactions) should be called directly. */ DirectResult FUSION_API fusion_reactor_direct ( FusionReactor *reactor, bool direct ); #endif ================================================ FILE: lib/fusion/ref.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #if FUSION_BUILD_MULTI #include #include #include #else /* FUSION_BUILD_MULTI */ #include #endif /* FUSION_BUILD_MULTI */ D_DEBUG_DOMAIN( Fusion_Ref, "Fusion/Ref", "Fusion's Reference Counter" ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #if FUSION_BUILD_KERNEL DirectResult fusion_ref_init( FusionRef *ref, const char *name, const FusionWorld *world ) { return fusion_ref_init2( ref, name, false, world ); } DirectResult fusion_ref_init2( FusionRef *ref, const char *name, bool user, const FusionWorld *world ) { FusionEntryInfo info; D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Ref, "%s( %p, '%s' )\n", __FUNCTION__, ref, name ?: "" ); if (user) { ref->multi.id = (long) ref; ref->multi.user = true; direct_recursive_mutex_init( &ref->single.lock ); direct_waitqueue_init( &ref->single.cond ); ref->single.refs = 0; ref->single.destroyed = false; ref->single.locked = 0; } else { while (ioctl( world->fusion_fd, FUSION_REF_NEW, &ref->multi.id )) { if (errno == EINTR) continue; D_PERROR( "Fusion/Ref: FUSION_REF_NEW" ); return DR_FUSION; } D_DEBUG_AT( Fusion_Ref, " -> new ref %p [%d]\n", ref, ref->multi.id ); info.type = FT_REF; info.id = ref->multi.id; direct_snputs( info.name, name, sizeof(info.name) ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); } /* Keep back pointer to shared world data. */ ref->multi.shared = world->shared; ref->multi.creator = fusion_id( world ); return DR_OK; } DirectResult fusion_ref_set_name( FusionRef *ref, const char *name ) { FusionEntryInfo info; D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p, '%s' )\n", __FUNCTION__, ref, name ); if (ref->multi.user) return DR_OK; info.type = FT_REF; info.id = ref->multi.id; direct_snputs( info.name, name, sizeof(info.name) ); while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_ENTRY_SET_INFO, &info )) { switch (errno) { case EINTR: continue; case EAGAIN: return DR_LOCKED; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_ENTRY_SET_INFO" ); return DR_FAILURE; } return DR_OK; } DirectResult fusion_ref_up( FusionRef *ref, bool global ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d]%s )\n", __FUNCTION__, ref, ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] up (%s), single refs %d\n", ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else ref->single.refs++; direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { entry = D_CALLOC( 1, sizeof(FusionRefSlaveSlaveEntry) ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } entry->ref_id = ref->multi.id; direct_map_insert( world->refs_map, &ref->multi.id, entry ); } entry->refs_local++; direct_mutex_unlock( &world->refs_lock ); } } else { while (ioctl( _fusion_fd( ref->multi.shared ), global ? FUSION_REF_UP_GLOBAL : FUSION_REF_UP, &ref->multi.id )) { switch (errno) { case EINTR: continue; case EAGAIN: return DR_LOCKED; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } if (global) D_PERROR( "Fusion/Ref: FUSION_REF_UP_GLOBAL" ); else D_PERROR( "Fusion/Ref: FUSION_REF_UP" ); return DR_FAILURE; } D_DEBUG_AT( Fusion_Ref, " -> %d references now\n", ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_STAT, &ref->multi.id ) ); } return ret; } DirectResult fusion_ref_down( FusionRef *ref, bool global ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d]%s )\n", __FUNCTION__, ref, ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), single refs %d\n", ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (!ref->single.refs) { D_BUG( "no more references" ); direct_mutex_unlock( &ref->single.lock ); return DR_BUG; } if (ref->single.destroyed) { direct_mutex_unlock( &ref->single.lock ); return DR_DESTROYED; } if (!--ref->single.refs) { ref->single.dead++; if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), single refs got %d -> call %p\n", ref->multi.id, global ? "global" : "local", ref->single.refs, ref->single.call ); } if (ref->single.call) { FusionCall *call = ref->single.call; if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), call_id %d, handler %p/%p\n", ref->multi.id, global ? "global" : "local", call->call_id, call->handler, call->handler3 ); } if (call->handler) { FusionCall copy_call = *call; int copy_arg = ref->single.call_arg; direct_mutex_unlock( &ref->single.lock ); fusion_call_execute( ©_call, FCEF_NODIRECT | FCEF_ONEWAY, copy_arg, NULL, NULL ); return DR_OK; } else if (call->handler3) { fusion_call_execute3( call, FCEF_NODIRECT | FCEF_ONEWAY | FCEF_QUEUE, ref->single.call_arg, NULL, 0, NULL, 0, NULL ); direct_mutex_unlock( &ref->single.lock ); fusion_world_flush_calls( world, 1 ); return DR_OK; } } else direct_waitqueue_broadcast( &ref->single.cond ); } direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); D_WARN( "[%d] not found", ref->multi.id ); return DR_ITEMNOTFOUND; } if (!--entry->refs_local) { int i; for (i = 0; i < entry->refs_catch; i++) fusion_call_execute( &ref->multi.shared->refs_call, FCEF_ONEWAY, ref->multi.id, NULL, NULL ); entry->refs_catch = 0; } direct_mutex_unlock( &world->refs_lock ); } } else { fusion_world_flush_calls( _fusion_world( ref->multi.shared ), 1 ); while (ioctl( _fusion_fd( ref->multi.shared ), global ? FUSION_REF_DOWN_GLOBAL : FUSION_REF_DOWN, &ref->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } return DR_FAILURE; } } return DR_OK; } DirectResult fusion_ref_catch( FusionRef *ref ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d] )\n", __FUNCTION__, ref, ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] catch, single refs %d\n", ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { /* If catcher is master, then we are most likely running in always-indirect mode. */ direct_mutex_lock( &ref->single.lock ); if (ref->single.refs < 2) { D_BUG( "master catch with less than two refs" ); direct_mutex_unlock( &ref->single.lock ); return DR_BUG; } ref->single.refs--; direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { entry = D_CALLOC( 1, sizeof(FusionRefSlaveSlaveEntry) ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } entry->ref_id = ref->multi.id; direct_map_insert( world->refs_map, &ref->multi.id, entry ); } entry->refs_catch++; direct_mutex_unlock( &world->refs_lock ); } } else { while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_CATCH, &ref->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_CATCH" ); return DR_FAILURE; } } return DR_OK; } DirectResult fusion_ref_throw( FusionRef *ref, FusionID catcher ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d] )\n", __FUNCTION__, ref, ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] throw, single refs %d\n", ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { /* If catcher is master, then we are most likely running in always-indirect mode. */ if (catcher != FUSION_ID_MASTER) { FusionRefSlaveKey key; FusionRefSlaveEntry *slave; key.fusion_id = catcher; key.ref_id = ref->multi.id; direct_mutex_lock( &world->refs_lock ); slave = direct_map_lookup( world->refs_map, &key ); if (!slave) { slave = D_CALLOC( 1, sizeof(FusionRefSlaveEntry) ); if (!slave) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } slave->key = key; slave->ref = ref; direct_map_insert( world->refs_map, &key, slave ); } slave->refs++; direct_mutex_unlock( &world->refs_lock ); } } else { D_UNIMPLEMENTED(); } } else { FusionRefThrow throw_; throw_.id = ref->multi.id; throw_.catcher = catcher; while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_THROW, &throw_ )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_THROW" ); return DR_FAILURE; } } return DR_OK; } DirectResult fusion_ref_stat( FusionRef *ref, int *refs ) { int val; D_ASSERT( ref != NULL ); D_ASSERT( refs != NULL ); if (ref->multi.user) { if (ref->single.destroyed) return DR_DESTROYED; val = ref->single.refs; } else { while ((val = ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_STAT, &ref->multi.id )) < 0) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_STAT" ); return DR_FAILURE; } } *refs = val; return DR_OK; } DirectResult fusion_ref_zero_trylock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else if (ref->single.refs) ret = DR_BUSY; else ref->single.locked = direct_gettid(); direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_ZERO_TRYLOCK, &ref->multi.id )) { switch (errno) { case EINTR: continue; case ETOOMANYREFS: return DR_BUSY; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_ZERO_TRYLOCK" ); return DR_FAILURE; } } return ret; } DirectResult fusion_ref_unlock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.locked == direct_gettid()) { ref->single.locked = 0; direct_waitqueue_broadcast( &ref->single.cond ); } else ret = DR_ACCESSDENIED; direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_UNLOCK, &ref->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_UNLOCK" ); return DR_FAILURE; } } return ret; } DirectResult fusion_ref_watch( FusionRef *ref, FusionCall *call, int call_arg ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_ASSERT( call != NULL ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (!ref->single.refs) ret = DR_BUG; else if (ref->single.call) ret = DR_BUSY; else { ref->single.call = call; ref->single.call_arg = call_arg; } direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { FusionRefWatch watch; watch.id = ref->multi.id; watch.call_id = call->call_id; watch.call_arg = call_arg; while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_WATCH, &watch )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_WATCH" ); return DR_FAILURE; } } return ret; } DirectResult fusion_ref_inherit( FusionRef *ref, FusionRef *from ) { D_ASSERT( ref != NULL ); D_ASSERT( from != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p, %p )\n", __FUNCTION__, ref, from ); if (ref->multi.user) { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } else { FusionRefInherit inherit; inherit.id = ref->multi.id; inherit.from = from->multi.id; while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_INHERIT, &inherit )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_INHERIT" ); return DR_FAILURE; } } return DR_OK; } DirectResult fusion_ref_destroy( FusionRef *ref ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d] )\n", __FUNCTION__, ref, ref->multi.id ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { ref->single.destroyed = true; direct_waitqueue_broadcast( &ref->single.cond ); direct_mutex_deinit( &ref->single.lock ); direct_waitqueue_deinit( &ref->single.cond ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { fusion_world_flush_calls( _fusion_world( ref->multi.shared ), 1 ); while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_REF_DESTROY, &ref->multi.id )) { switch (errno) { case EINTR: continue; case EINVAL: D_ERROR( "Fusion/Ref: Invalid reference!\n" ); return DR_DESTROYED; default: break; } D_PERROR( "Fusion/Ref: FUSION_REF_DESTROY" ); return DR_FAILURE; } } return DR_OK; } DirectResult fusion_ref_add_permissions( FusionRef *ref, FusionID fusion_id, FusionRefPermissions ref_permissions ) { if (!ref->multi.user) { FusionEntryPermissions permissions; permissions.type = FT_REF; permissions.id = ref->multi.id; permissions.fusion_id = fusion_id; permissions.permissions = 0; if (ref_permissions & FUSION_REF_PERMIT_REF_UNREF_LOCAL) { FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_UP ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_DOWN ); } if (ref_permissions & FUSION_REF_PERMIT_REF_UNREF_GLOBAL) { FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_UP_GLOBAL ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_DOWN_GLOBAL ); } if (ref_permissions & FUSION_REF_PERMIT_ZERO_LOCK_UNLOCK) { FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_ZERO_LOCK ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_ZERO_TRYLOCK ); FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_UNLOCK ); } if (ref_permissions & FUSION_REF_PERMIT_WATCH) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_WATCH ); if (ref_permissions & FUSION_REF_PERMIT_INHERIT) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_INHERIT ); if (ref_permissions & FUSION_REF_PERMIT_DESTROY) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_DESTROY ); if (ref_permissions & FUSION_REF_PERMIT_CATCH) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_CATCH ); if (ref_permissions & FUSION_REF_PERMIT_THROW) FUSION_ENTRY_PERMISSIONS_ADD( permissions.permissions, FUSION_REF_THROW ); while (ioctl( _fusion_fd( ref->multi.shared ), FUSION_ENTRY_ADD_PERMISSIONS, &permissions ) < 0) { if (errno != EINTR) { D_PERROR( "Fusion/Ref: FUSION_ENTRY_ADD_PERMISSIONS( id %d )\n", ref->multi.id ); return DR_FAILURE; } } } return DR_OK; } #else /* FUSION_BUILD_KERNEL */ DirectResult fusion_ref_init( FusionRef *ref, const char *name, const FusionWorld *world ) { return fusion_ref_init2( ref, name, false, world ); } DirectResult fusion_ref_init2( FusionRef *ref, const char *name, bool user, const FusionWorld *world ) { D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_Ref, "%s( %p, '%s' )\n", __FUNCTION__, ref, name ?: "" ); ref->multi.id = ++world->shared->ref_ids; ref->multi.shared = world->shared; ref->multi.creator = fusion_id( world ); ref->multi.user = user; if (user) { direct_recursive_mutex_init( &ref->single.lock ); direct_waitqueue_init( &ref->single.cond ); ref->single.refs = 0; ref->single.destroyed = false; ref->single.locked = 0; } else { ref->multi.builtin.local = 0; ref->multi.builtin.global = 0; fusion_skirmish_init( &ref->multi.builtin.lock, name, world ); ref->multi.builtin.call = NULL; } return DR_OK; } DirectResult fusion_ref_set_name( FusionRef *ref, const char *name ) { D_DEBUG_AT( Fusion_Ref, "%s( %p, '%s' )\n", __FUNCTION__, ref, name ); return DR_OK; } DirectResult _fusion_ref_change( FusionRef *ref, int add, bool global ) { DirectResult ret; D_ASSERT( ref != NULL ); D_ASSERT( add != 0 ); ret = fusion_skirmish_prevail( &ref->multi.builtin.lock ); if (ret) return ret; if (global) { if (ref->multi.builtin.global + add < 0) { D_BUG( "ref has no global references" ); fusion_skirmish_dismiss( &ref->multi.builtin.lock ); return DR_BUG; } ref->multi.builtin.global += add; } else { if (ref->multi.builtin.local + add < 0) { D_BUG( "ref has no local references" ); fusion_skirmish_dismiss( &ref->multi.builtin.lock ); return DR_BUG; } ref->multi.builtin.local += add; _fusion_add_local( _fusion_world(ref->multi.shared), ref, add ); } if (ref->multi.builtin.local + ref->multi.builtin.global == 0) { fusion_skirmish_notify( &ref->multi.builtin.lock ); if (ref->multi.builtin.call) { fusion_skirmish_dismiss( &ref->multi.builtin.lock ); return fusion_call_execute( ref->multi.builtin.call, FCEF_ONEWAY, ref->multi.builtin.call_arg, NULL, NULL ); } } fusion_skirmish_dismiss( &ref->multi.builtin.lock ); return DR_OK; } DirectResult fusion_ref_up( FusionRef *ref, bool global ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d]%s )\n", __FUNCTION__, ref, ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] up (%s), single refs %d\n", ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else ref->single.refs++; direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { entry = D_CALLOC( 1, sizeof(FusionRefSlaveSlaveEntry) ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } entry->ref_id = ref->multi.id; direct_map_insert( world->refs_map, &ref->multi.id, entry ); } entry->refs_local++; direct_mutex_unlock( &world->refs_lock ); } } else return _fusion_ref_change( ref, +1, global ); return ret; } DirectResult fusion_ref_down( FusionRef *ref, bool global ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d]%s )\n", __FUNCTION__, ref, ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), single refs %d\n", ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (!ref->single.refs) { D_BUG( "no more references" ); direct_mutex_unlock( &ref->single.lock ); return DR_BUG; } if (ref->single.destroyed) { direct_mutex_unlock( &ref->single.lock ); return DR_DESTROYED; } if (!--ref->single.refs) { ref->single.dead++; if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), single refs got %d -> call %p\n", ref->multi.id, global ? "global" : "local", ref->single.refs, ref->single.call ); } if (ref->single.call) { FusionCall *call = ref->single.call; if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] down (%s), call_id %d, handler %p/%p\n", ref->multi.id, global ? "global" : "local", call->call_id, call->handler, call->handler3 ); } if (call->handler) { FusionCall copy_call = *call; int copy_arg = ref->single.call_arg; direct_mutex_unlock( &ref->single.lock ); fusion_call_execute( ©_call, FCEF_NODIRECT | FCEF_ONEWAY, copy_arg, NULL, NULL ); return DR_OK; } else if (call->handler3) { fusion_call_execute3( call, FCEF_NODIRECT | FCEF_ONEWAY | FCEF_QUEUE, ref->single.call_arg, NULL, 0, NULL, 0, NULL ); direct_mutex_unlock( &ref->single.lock ); fusion_world_flush_calls( world, 1 ); return DR_OK; } } else direct_waitqueue_broadcast( &ref->single.cond ); } direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); D_WARN( "[%d] not found", ref->multi.id ); return DR_ITEMNOTFOUND; } if (!--entry->refs_local) { int i; for (i = 0; i < entry->refs_catch; i++) fusion_call_execute( &ref->multi.shared->refs_call, FCEF_ONEWAY, ref->multi.id, NULL, NULL ); entry->refs_catch = 0; } direct_mutex_unlock( &world->refs_lock ); } } else return _fusion_ref_change( ref, -1, global ); return DR_OK; } DirectResult fusion_ref_catch( FusionRef *ref ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d] )\n", __FUNCTION__, ref, ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] catch, single refs %d\n", ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { /* If catcher is master, then we are most likely running in always-indirect mode. */ direct_mutex_lock( &ref->single.lock ); if (ref->single.refs < 2) { D_BUG( "master catch with less than two refs" ); direct_mutex_unlock( &ref->single.lock ); return DR_BUG; } ref->single.refs--; direct_mutex_unlock( &ref->single.lock ); } else { FusionRefSlaveSlaveEntry *entry; direct_mutex_lock( &world->refs_lock ); entry = direct_map_lookup( world->refs_map, &ref->multi.id ); if (!entry) { entry = D_CALLOC( 1, sizeof(FusionRefSlaveSlaveEntry) ); if (!entry) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } entry->ref_id = ref->multi.id; direct_map_insert( world->refs_map, &ref->multi.id, entry ); } entry->refs_catch++; direct_mutex_unlock( &world->refs_lock ); } } else return fusion_ref_down( ref, false ); return DR_OK; } DirectResult fusion_ref_throw( FusionRef *ref, FusionID catcher ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [%d] )\n", __FUNCTION__, ref, ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [%d] throw, single refs %d\n", ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { /* If catcher is master, then we are most likely running in always-indirect mode. */ if (catcher != FUSION_ID_MASTER) { FusionRefSlaveKey key; FusionRefSlaveEntry *slave; key.fusion_id = catcher; key.ref_id = ref->multi.id; direct_mutex_lock( &world->refs_lock ); slave = direct_map_lookup( world->refs_map, &key ); if (!slave) { slave = D_CALLOC( 1, sizeof(FusionRefSlaveEntry) ); if (!slave) { direct_mutex_unlock( &world->refs_lock ); return D_OOM(); } slave->key = key; slave->ref = ref; direct_map_insert( world->refs_map, &key, slave ); } slave->refs++; direct_mutex_unlock( &world->refs_lock ); } } else { D_UNIMPLEMENTED(); } } return DR_OK; } DirectResult fusion_ref_stat( FusionRef *ref, int *refs ) { int val; D_ASSERT( ref != NULL ); D_ASSERT( refs != NULL ); if (ref->multi.user) { if (ref->single.destroyed) return DR_DESTROYED; val = ref->single.refs; } else val = ref->multi.builtin.local + ref->multi.builtin.global; *refs = val; return DR_OK; } DirectResult fusion_ref_zero_trylock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else if (ref->single.refs) ret = DR_BUSY; else ref->single.locked = direct_gettid(); direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { ret = fusion_skirmish_prevail( &ref->multi.builtin.lock ); if (ret) return ret; if (ref->multi.builtin.local) _fusion_check_locals( _fusion_world(ref->multi.shared), ref ); if (ref->multi.builtin.local + ref->multi.builtin.global) ret = DR_BUSY; if (ret) fusion_skirmish_dismiss( &ref->multi.builtin.lock ); } return ret; } DirectResult fusion_ref_unlock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.locked == direct_gettid()) { ref->single.locked = 0; direct_waitqueue_broadcast( &ref->single.cond ); } else ret = DR_ACCESSDENIED; direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else fusion_skirmish_dismiss( &ref->multi.builtin.lock ); return ret; } DirectResult fusion_ref_watch( FusionRef *ref, FusionCall *call, int call_arg ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_ASSERT( call != NULL ); if (ref->multi.user) { FusionWorld *world = _fusion_world( ref->multi.shared ); if (world->fusion_id == FUSION_ID_MASTER) { direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (!ref->single.refs) ret = DR_BUG; else if (ref->single.call) ret = DR_BUSY; else { ref->single.call = call; ref->single.call_arg = call_arg; } direct_mutex_unlock( &ref->single.lock ); } else { D_UNIMPLEMENTED(); return DR_UNIMPLEMENTED; } } else { ret = fusion_skirmish_prevail( &ref->multi.builtin.lock ); if (ret) return ret; if (ref->multi.builtin.local + ref->multi.builtin.global == 0) { D_BUG( "ref has no references" ); ret = DR_BUG; } else if (ref->multi.builtin.call) { ret = DR_BUSY; } else { ref->multi.builtin.call = call; ref->multi.builtin.call_arg = call_arg; fusion_skirmish_notify( &ref->multi.builtin.lock ); } fusion_skirmish_dismiss( &ref->multi.builtin.lock ); } return ret; } DirectResult fusion_ref_inherit( FusionRef *ref, FusionRef *from ) { D_ASSERT( ref != NULL ); D_ASSERT( from != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p, %p )\n", __FUNCTION__, ref, from ); D_UNIMPLEMENTED(); return fusion_ref_up( ref, true ); } DirectResult fusion_ref_destroy( FusionRef *ref ) { FusionSkirmish *skirmish; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); skirmish = &ref->multi.builtin.lock; if (skirmish->multi.builtin.destroyed) return DR_DESTROYED; _fusion_remove_all_locals( _fusion_world(ref->multi.shared), ref ); fusion_skirmish_destroy( skirmish ); return DR_OK; } DirectResult fusion_ref_add_permissions( FusionRef *ref, FusionID fusion_id, FusionRefPermissions ref_permissions ) { return DR_UNIMPLEMENTED; } #endif /* FUSION_BUILD_KERNEL */ #else /* FUSION_BUILD_MULTI */ DirectResult fusion_ref_init( FusionRef *ref, const char *name, const FusionWorld *world ) { D_ASSERT( ref != NULL ); D_ASSERT( name != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); direct_recursive_mutex_init( &ref->single.lock ); direct_waitqueue_init( &ref->single.cond ); ref->single.refs = 0; ref->single.destroyed = false; ref->single.locked = 0; ref->multi.id = (long) ref; return DR_OK; } DirectResult fusion_ref_init2( FusionRef *ref, const char *name, bool user, const FusionWorld *world ) { return fusion_ref_init( ref, name, world ); } DirectResult fusion_ref_set_name( FusionRef *ref, const char *name ) { D_DEBUG_AT( Fusion_Ref, "%s( %p, '%s' )\n", __FUNCTION__, ref, name ); return DR_OK; } DirectResult fusion_ref_up( FusionRef *ref, bool global ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [0x%08x]%s )\n", __FUNCTION__, ref, (unsigned int) ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [0x%08x] up (%s), single refs %d\n", (unsigned int) ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else ref->single.refs++; direct_mutex_unlock( &ref->single.lock ); return ret; } DirectResult fusion_ref_down( FusionRef *ref, bool global ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p [0x%08x]%s )\n", __FUNCTION__, ref, (unsigned int) ref->multi.id, global ? " GLOBAL" : "" ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [0x%08x] down (%s), single refs %d\n", (unsigned int) ref->multi.id, global ? "global" : "local", ref->single.refs ); direct_trace_print_stack( NULL ); } direct_mutex_lock( &ref->single.lock ); if (!ref->single.refs) { D_BUG( "no more references" ); direct_mutex_unlock( &ref->single.lock ); return DR_BUG; } if (ref->single.destroyed) { direct_mutex_unlock( &ref->single.lock ); return DR_DESTROYED; } if (!--ref->single.refs) { if (ref->single.call) { FusionCall *call = ref->single.call; if (call->handler) { FusionCall copy_call = *call; int copy_arg = ref->single.call_arg; direct_mutex_unlock( &ref->single.lock ); fusion_call_execute( ©_call, FCEF_NODIRECT | FCEF_ONEWAY, copy_arg, NULL, NULL ); return DR_OK; } } else direct_waitqueue_broadcast( &ref->single.cond ); } direct_mutex_unlock( &ref->single.lock ); return DR_OK; } DirectResult fusion_ref_catch( FusionRef *ref ) { D_DEBUG_AT( Fusion_Ref, "%s( %p [0x%08x] )\n", __FUNCTION__, ref, (unsigned int) ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [0x%08x] catch, single refs %d\n", (unsigned int) ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } return fusion_ref_down( ref, false ); } DirectResult fusion_ref_throw( FusionRef *ref, FusionID catcher ) { D_DEBUG_AT( Fusion_Ref, "%s( %p [0x%08x] )\n", __FUNCTION__, ref, (unsigned int) ref->multi.id ); if (fusion_config->trace_ref == -1 || ref->multi.id == fusion_config->trace_ref) { D_INFO( "Fusion/Ref: [0x%08x] throw, single refs %d\n", (unsigned int) ref->multi.id, ref->single.refs ); direct_trace_print_stack( NULL ); } return DR_OK; } DirectResult fusion_ref_stat( FusionRef *ref, int *refs ) { D_ASSERT( ref != NULL ); D_ASSERT( refs != NULL ); if (ref->single.destroyed) return DR_DESTROYED; *refs = ref->single.refs; return DR_OK; } DirectResult fusion_ref_zero_trylock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (ref->single.locked) ret = DR_LOCKED; else if (ref->single.refs) ret = DR_BUSY; else ref->single.locked = direct_gettid(); direct_mutex_unlock( &ref->single.lock ); return ret; } DirectResult fusion_ref_unlock( FusionRef *ref ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); direct_mutex_lock( &ref->single.lock ); if (ref->single.locked == direct_gettid()) { ref->single.locked = 0; direct_waitqueue_broadcast( &ref->single.cond ); } else ret = DR_ACCESSDENIED; direct_mutex_unlock( &ref->single.lock ); return ret; } DirectResult fusion_ref_watch( FusionRef *ref, FusionCall *call, int call_arg ) { DirectResult ret = DR_OK; D_ASSERT( ref != NULL ); D_ASSERT( call != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); direct_mutex_lock( &ref->single.lock ); if (ref->single.destroyed) ret = DR_DESTROYED; else if (!ref->single.refs) ret = DR_BUG; else if (ref->single.call) ret = DR_BUSY; else { ref->single.call = call; ref->single.call_arg = call_arg; } direct_mutex_unlock( &ref->single.lock ); return ret; } DirectResult fusion_ref_inherit( FusionRef *ref, FusionRef *from ) { D_ASSERT( ref != NULL ); D_ASSERT( from != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p, %p )\n", __FUNCTION__, ref, from ); D_UNIMPLEMENTED(); return fusion_ref_up( ref, true ); } DirectResult fusion_ref_destroy( FusionRef *ref ) { D_ASSERT( ref != NULL ); D_DEBUG_AT( Fusion_Ref, "%s( %p )\n", __FUNCTION__, ref ); ref->single.destroyed = true; direct_waitqueue_broadcast( &ref->single.cond ); direct_mutex_deinit( &ref->single.lock ); direct_waitqueue_deinit( &ref->single.cond ); return DR_OK; } DirectResult fusion_ref_add_permissions( FusionRef *ref, FusionID fusion_id, FusionRefPermissions ref_permissions ) { return DR_OK; } #endif /* FUSION_BUILD_MULTI */ ================================================ FILE: lib/fusion/ref.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__REF_H__ #define __FUSION__REF_H__ #include /**********************************************************************************************************************/ struct __Fusion_FusionRef { /* multi app */ struct { int id; FusionWorldShared *shared; FusionID creator; /* builtin impl */ struct { int local; int global; FusionSkirmish lock; FusionCall *call; int call_arg; } builtin; bool user; } multi; /* single app */ struct { int refs; DirectWaitQueue cond; DirectMutex lock; int dead; bool destroyed; int locked; FusionCall *call; int call_arg; } single; }; /**********************************************************************************************************************/ typedef enum { FUSION_REF_PERMIT_NONE = 0x00000000, FUSION_REF_PERMIT_REF_UNREF_LOCAL = 0x00000001, FUSION_REF_PERMIT_REF_UNREF_GLOBAL = 0x00000002, FUSION_REF_PERMIT_ZERO_LOCK_UNLOCK = 0x00000004, FUSION_REF_PERMIT_WATCH = 0x00000008, FUSION_REF_PERMIT_INHERIT = 0x00000010, FUSION_REF_PERMIT_DESTROY = 0x00000020, FUSION_REF_PERMIT_CATCH = 0x00000040, FUSION_REF_PERMIT_THROW = 0x00000080, FUSION_REF_PERMIT_ALL = 0x000000FF } FusionRefPermissions; /**********************************************************************************************************************/ /* * Initialize. */ DirectResult FUSION_API fusion_ref_init ( FusionRef *ref, const char *name, const FusionWorld *world ); /* * Initialize with 'user' set to true for secure fusion. */ DirectResult FUSION_API fusion_ref_init2 ( FusionRef *ref, const char *name, bool user, const FusionWorld *world ); /* * Change name. */ DirectResult FUSION_API fusion_ref_set_name ( FusionRef *ref, const char *name ); /* * Lock, increase, unlock. */ DirectResult FUSION_API fusion_ref_up ( FusionRef *ref, bool global ); /* * Lock, decrease, unlock. */ DirectResult FUSION_API fusion_ref_down ( FusionRef *ref, bool global ); /* * Catch reference */ DirectResult FUSION_API fusion_ref_catch ( FusionRef *ref ); /* * Throw reference */ DirectResult FUSION_API fusion_ref_throw ( FusionRef *ref, FusionID catcher ); /* * Get the current reference count. This value is not reliable, because no locking will be performed. */ DirectResult FUSION_API fusion_ref_stat ( FusionRef *ref, int *refs ); /* * Check for zero and lock if true. */ DirectResult FUSION_API fusion_ref_zero_trylock ( FusionRef *ref ); /* * Unlock the counter. */ DirectResult FUSION_API fusion_ref_unlock ( FusionRef *ref ); /* * Have the call executed when reference counter reaches zero. */ DirectResult FUSION_API fusion_ref_watch ( FusionRef *ref, FusionCall *call, int call_arg ); /* * Inherit local reference count from another reference. */ DirectResult FUSION_API fusion_ref_inherit ( FusionRef *ref, FusionRef *from ); /* * Deinitialize. */ DirectResult FUSION_API fusion_ref_destroy ( FusionRef *ref ); /* * Give permissions to another fusionee to use the reference. */ DirectResult FUSION_API fusion_ref_add_permissions( FusionRef *ref, FusionID fusion_id, FusionRefPermissions permissions ); #endif ================================================ FILE: lib/fusion/shm/fake.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Fusion_FakeSHMPool, "Fusion/FakeSHMPool", "Fusion Fake Shared Memory Pool" ); /**********************************************************************************************************************/ DirectResult fusion_shm_pool_create( FusionWorld *world, const char *name, unsigned int max_size, bool debug, FusionSHMPoolShared **ret_pool ) { FusionSHMPoolShared *pool; D_DEBUG_AT( Fusion_FakeSHMPool, "%s( %p [%d], '%s', %u, %p, %sdebug )\n", __FUNCTION__, world, world->shared->world_index, name, max_size, ret_pool, debug ? "" : "no-" ); pool = D_CALLOC( 1, sizeof(FusionSHMPoolShared) ); if (!pool) return D_OOM(); pool->debug = debug; D_MAGIC_SET( pool, FusionSHMPoolShared ); *ret_pool = pool; D_DEBUG_AT( Fusion_FakeSHMPool, " -> %p\n", *ret_pool ); return DR_OK; } DirectResult fusion_shm_pool_destroy( FusionWorld *world, FusionSHMPoolShared *pool ) { D_DEBUG_AT( Fusion_FakeSHMPool, "%s( %p, %p )\n", __FUNCTION__, world, pool ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_MAGIC_CLEAR( pool ); D_FREE( pool ); return DR_OK; } ================================================ FILE: lib/fusion/shm/heap.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Fusion_SHMHeap, "Fusion/SHMHeap", "Fusion Shared Memory Heap" ); /**********************************************************************************************************************/ /* Number of contiguous free blocks allowed to build up at the end of memory before being returned to the system. */ #define FINAL_FREE_BLOCKS 8 /* Address to block number and vice versa. */ #define BLOCK(A) (((char*) (A) - heap->heapbase) / BLOCKSIZE + 1) #define ADDRESS(B) ((void*) (((B) - 1) * BLOCKSIZE + heap->heapbase)) /* * Aligned allocation. */ static void * align( shmalloc_heap *heap, size_t size ) { void *result; unsigned long adj; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, "_ZU" )\n", __FUNCTION__, heap, size ); D_MAGIC_ASSERT( heap, shmalloc_heap ); result = __shmalloc_brk( heap, size ); adj = (unsigned long) result % BLOCKSIZE; if (adj != 0) { adj = BLOCKSIZE - adj; __shmalloc_brk( heap, adj ); result = (char*) result + adj; } return result; } /* * Get neatly aligned memory, initializing or growing the heap info table as necessary. */ static void * morecore( shmalloc_heap *heap, size_t size ) { void *result; shmalloc_info *newinfo, *oldinfo; size_t newsize; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, "_ZU" )\n", __FUNCTION__, heap, size ); D_MAGIC_ASSERT( heap, shmalloc_heap ); result = align( heap, size ); if (result == NULL) return NULL; /* Check if we need to grow the info table. */ if ((size_t) BLOCK( (char*) result + size ) > heap->heapsize) { newsize = heap->heapsize; while ((size_t) BLOCK( (char*) result + size ) > newsize) newsize *= 2; newinfo = (shmalloc_info*) align( heap, newsize * sizeof(shmalloc_info) ); if (newinfo == NULL) { __shmalloc_brk( heap, -size ); return NULL; } direct_memcpy( newinfo, heap->heapinfo, heap->heapsize * sizeof(shmalloc_info) ); memset( newinfo + heap->heapsize, 0, (newsize - heap->heapsize) * sizeof(shmalloc_info) ); oldinfo = heap->heapinfo; newinfo[BLOCK( oldinfo )].busy.type = 0; newinfo[BLOCK( oldinfo )].busy.info.size = BLOCKIFY( heap->heapsize * sizeof(shmalloc_info) ); heap->heapinfo = newinfo; _fusion_shfree( heap, oldinfo ); heap->heapsize = newsize; } heap->heaplimit = BLOCK( (char*) result + size ); return result; } /**********************************************************************************************************************/ void * _fusion_shmalloc( shmalloc_heap *heap, size_t size ) { void *result; size_t i, block, blocks, lastblocks, start; struct list *next; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, "_ZU" )\n", __FUNCTION__, heap, size ); D_MAGIC_ASSERT( heap, shmalloc_heap ); /* Some programs will call shmalloc with size = 0. We let them pass. */ if (size == 0) return NULL; if (size < sizeof(struct list)) size = sizeof(struct list); /* Determine the allocation policy based on the request size. */ if (size <= BLOCKSIZE / 2) { /* Small allocation to receive a fragment of a block. Determine the logarithm to base two of the fragment size. */ size_t log = 1; --size; while ((size /= 2) != 0) ++log; /* Look in the fragment lists for a free fragment of the desired size. */ next = heap->fraghead[log].next; if (next != NULL) { /* There are free fragments of this size. Pop a fragment out of the fragment list and return it. */ result = next; next->prev->next = next->next; if (next->next != NULL) next->next->prev = next->prev; block = BLOCK( result ); if (--heap->heapinfo[block].busy.info.frag.nfree != 0) heap->heapinfo[block].busy.info.frag.first = ((char*) next->next - (char*) NULL) % BLOCKSIZE >> log; /* Update the statistics. */ heap->chunks_used++; heap->bytes_used += 1 << log; heap->chunks_free--; heap->bytes_free -= 1 << log; } else { /* No free fragments of the desired size. Get a new block and break it into fragments, returning the first. */ result = _fusion_shmalloc( heap, BLOCKSIZE ); if (result == NULL) return NULL; heap->fragblocks[log]++; /* Link all fragments but the first into the free list. */ for (i = 1; i < BLOCKSIZE >> log; ++i) { next = (struct list*) ((char*) result + (i << log)); next->next = heap->fraghead[log].next; next->prev = &heap->fraghead[log]; next->prev->next = next; if (next->next != NULL) next->next->prev = next; } /* Initialize the nfree and first counters for this block. */ block = BLOCK( result ); heap->heapinfo[block].busy.type = log; heap->heapinfo[block].busy.info.frag.nfree = i - 1; heap->heapinfo[block].busy.info.frag.first = i - 1; heap->chunks_free += (BLOCKSIZE >> log) - 1; heap->bytes_free += BLOCKSIZE - (1 << log); heap->bytes_used -= BLOCKSIZE - (1 << log); } } else { /* Large allocation to receive one or more blocks. Search the free list in a circle starting at the last place visited. If we loop completely around without finding a large enough space, we will have to get more memory from the system. */ blocks = BLOCKIFY( size ); start = block = heap->heapindex; while (heap->heapinfo[block].free.size < blocks) { block = heap->heapinfo[block].free.next; if (block == start) { /* Need to get more from the system. Check to see if the new core will be contiguous with the final free block. If so we don't need to get as much. */ block = heap->heapinfo[0].free.prev; lastblocks = heap->heapinfo[block].free.size; if (heap->heaplimit != 0 && block + lastblocks == heap->heaplimit && __shmalloc_brk( heap, 0 ) == ADDRESS( block + lastblocks ) && (morecore( heap, (blocks - lastblocks) * BLOCKSIZE) ) != NULL) { block = heap->heapinfo[0].free.prev; heap->heapinfo[block].free.size += blocks - lastblocks; heap->bytes_free += (blocks - lastblocks) * BLOCKSIZE; continue; } result = morecore( heap, blocks * BLOCKSIZE ); if (result == NULL) return NULL; block = BLOCK( result ); heap->heapinfo[block].busy.type = 0; heap->heapinfo[block].busy.info.size = blocks; heap->chunks_used++; heap->bytes_used += blocks * BLOCKSIZE; return result; } } /* At this point we have found a suitable free list entry. Figure out how to remove what we need from the list. */ result = ADDRESS( block ); if (heap->heapinfo[block].free.size > blocks) { /* The block we found has a bit left over, so relink the tail end back into the free list. */ heap->heapinfo[block + blocks].free.size = heap->heapinfo[block].free.size - blocks; heap->heapinfo[block + blocks].free.next = heap->heapinfo[block].free.next; heap->heapinfo[block + blocks].free.prev = heap->heapinfo[block].free.prev; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block + blocks; heap->heapinfo[heap->heapinfo[block].free.prev].free.next = block + blocks; heap->heapindex = block + blocks; } else { /* The block exactly matches our requirements, so just remove it from the list. */ heap->heapinfo[heap->heapinfo[block].free.next].free.prev = heap->heapinfo[block].free.prev; heap->heapinfo[heap->heapinfo[block].free.prev].free.next = heap->heapinfo[block].free.next; heap->heapindex = heap->heapinfo[block].free.next; heap->chunks_free--; } heap->heapinfo[block].busy.type = 0; heap->heapinfo[block].busy.info.size = blocks; heap->chunks_used++; heap->bytes_used += blocks * BLOCKSIZE; heap->bytes_free -= blocks * BLOCKSIZE; } return result; } void * _fusion_shrealloc( shmalloc_heap *heap, void *ptr, size_t size ) { void *result; int type; size_t block, blocks, oldlimit; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %p, "_ZU" )\n", __FUNCTION__, heap, ptr, size ); D_MAGIC_ASSERT( heap, shmalloc_heap ); if (ptr == NULL) return _fusion_shmalloc( heap, size ); else if (size == 0) { _fusion_shfree( heap, ptr ); return NULL; } block = BLOCK( ptr ); type = heap->heapinfo[block].busy.type; switch (type) { case 0: /* Maybe reallocate a large block to a small fragment. */ if (size <= BLOCKSIZE / 2) { result = _fusion_shmalloc( heap, size ); if (result != NULL) { direct_memcpy( result, ptr, size ); _fusion_shfree( heap, ptr ); return result; } } /* The new size is a large allocation as well; see if we can hold it in place. */ blocks = BLOCKIFY( size ); if (blocks < heap->heapinfo[block].busy.info.size) { /* The new size is smaller; return excess memory to the free list. */ heap->heapinfo[block + blocks].busy.type = 0; heap->heapinfo[block + blocks].busy.info.size = heap->heapinfo[block].busy.info.size - blocks; heap->heapinfo[block].busy.info.size = blocks; _fusion_shfree( heap, ADDRESS( block + blocks ) ); result = ptr; } else if (blocks == heap->heapinfo[block].busy.info.size) /* No size change necessary. */ result = ptr; else { /* Won't fit, so allocate a new region that will. Free the old region first in case there is sufficient adjacent space to grow without moving. */ blocks = heap->heapinfo[block].busy.info.size; oldlimit = heap->heaplimit; heap->heaplimit = 0; _fusion_shfree( heap, ptr ); heap->heaplimit = oldlimit; result = _fusion_shmalloc( heap, size ); if (result == NULL) { /* We have to unfree the thing we just freed. Unfortunately it might have been coalesced with its neighbors. */ if (heap->heapindex == block) _fusion_shmalloc( heap, blocks * BLOCKSIZE ); else { void *previous = _fusion_shmalloc( heap, (block - heap->heapindex) * BLOCKSIZE ); _fusion_shmalloc( heap, blocks * BLOCKSIZE ); _fusion_shfree( heap, previous ); } return NULL; } if (ptr != result) direct_memmove( result, ptr, blocks * BLOCKSIZE ); } break; default: /* Old size is a fragment; type is logarithm to base two of the fragment size. */ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) /* The new size is the same kind of fragment. */ result = ptr; else { /* The new size is different; allocate a new space, copy the lesser of the new size and the old. */ result = _fusion_shmalloc( heap, size ); if (result == NULL) return NULL; direct_memcpy( result, ptr, MIN( size, (size_t) 1 << type ) ); _fusion_shfree( heap, ptr ); } break; } return result; } void _fusion_shfree( shmalloc_heap *heap, void *ptr ) { int type; size_t i, block, blocks; struct list *prev, *next; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %p )\n", __FUNCTION__, heap, ptr ); D_MAGIC_ASSERT( heap, shmalloc_heap ); if (ptr == NULL) return; block = BLOCK( ptr ); type = heap->heapinfo[block].busy.type; switch (type) { case 0: /* Get as many statistics as early as we can. */ heap->chunks_used--; heap->bytes_used -= heap->heapinfo[block].busy.info.size * BLOCKSIZE; heap->bytes_free += heap->heapinfo[block].busy.info.size * BLOCKSIZE; /* Find the free cluster previous to this one in the free list. */ i = heap->heapindex; if (i > block) while (i > block) i = heap->heapinfo[i].free.prev; else { do i = heap->heapinfo[i].free.next; while (i > 0 && i < block); i = heap->heapinfo[i].free.prev; } /* Determine how to link this block into the free list. */ if (block == i + heap->heapinfo[i].free.size) { /* Coalesce this block with its predecessor. */ heap->heapinfo[i].free.size += heap->heapinfo[block].busy.info.size; block = i; } else { /* Really link this block back into the free list. */ heap->heapinfo[block].free.size = heap->heapinfo[block].busy.info.size; heap->heapinfo[block].free.next = heap->heapinfo[i].free.next; heap->heapinfo[block].free.prev = i; heap->heapinfo[i].free.next = block; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block; heap->chunks_free++; } /* Now that the block is linked in, see if we can coalesce it with its successor (by deleting its successor from the list and adding in its size). */ if (block + heap->heapinfo[block].free.size == heap->heapinfo[block].free.next) { heap->heapinfo[block].free.size += heap->heapinfo[heap->heapinfo[block].free.next].free.size; heap->heapinfo[block].free.next = heap->heapinfo[heap->heapinfo[block].free.next].free.next; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block; heap->chunks_free--; } blocks = heap->heapinfo[block].free.size; /* Punch a hole into the tmpfs file to really free RAM. */ if (fusion_config->madv_remove) madvise( ADDRESS( block ), blocks * BLOCKSIZE, MADV_REMOVE ); /* Now see if we can truncate the end. */ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == heap->heaplimit && __shmalloc_brk( heap, 0 ) == ADDRESS( block + blocks )) { size_t bytes = blocks * BLOCKSIZE; heap->heaplimit -= blocks; __shmalloc_brk( heap, -bytes ); heap->heapinfo[heap->heapinfo[block].free.prev].free.next = heap->heapinfo[block].free.next; heap->heapinfo[heap->heapinfo[block].free.next].free.prev = heap->heapinfo[block].free.prev; block = heap->heapinfo[block].free.prev; heap->chunks_free--; heap->bytes_free -= bytes; } /* Set the next search to begin at this block. */ heap->heapindex = block; break; default: /* Do some of the statistics. */ heap->chunks_used--; heap->bytes_used -= 1 << type; heap->chunks_free++; heap->bytes_free += 1 << type; /* Get the address of the first free fragment in this block. */ prev = (struct list*) ((char*) ADDRESS( block ) + (heap->heapinfo[block].busy.info.frag.first << type)); if (heap->heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 && heap->fragblocks[type] > 1) { /* If all fragments of this block are free, remove them from the fragment list, free whole block. */ heap->fragblocks[type]--; next = prev; for (i = 1; i < BLOCKSIZE >> type; ++i) next = next->next; prev->prev->next = next; if (next != NULL) next->prev = prev->prev; heap->heapinfo[block].busy.type = 0; heap->heapinfo[block].busy.info.size = 1; /* Keep the statistics accurate. */ heap->chunks_used++; heap->bytes_used += BLOCKSIZE; heap->chunks_free -= BLOCKSIZE >> type; heap->bytes_free -= BLOCKSIZE; _fusion_shfree( heap, ADDRESS( block ) ); } else if (heap->heapinfo[block].busy.info.frag.nfree != 0) { /* If some fragments of this block are free, link this fragment into the fragment list after the first free fragment of this block. */ next = (struct list*) ptr; next->next = prev->next; next->prev = prev; prev->next = next; if (next->next != NULL) next->next->prev = next; heap->heapinfo[block].busy.info.frag.nfree++; } else { /* No fragments of this block are free, so link this fragment into the fragment list and announce that it is the first free fragment of this block. */ prev = (struct list*) ptr; heap->heapinfo[block].busy.info.frag.nfree = 1; heap->heapinfo[block].busy.info.frag.first = ((char*) ptr - (char*) NULL) % BLOCKSIZE >> type; prev->next = heap->fraghead[type].next; prev->prev = &heap->fraghead[type]; prev->prev->next = prev; if (prev->next != NULL) prev->next->prev = prev; } break; } } /**********************************************************************************************************************/ DirectResult __shmalloc_init_heap( FusionSHM *shm, const char *filename, void *addr_base, int space, int *ret_size ) { DirectResult ret; int size; int heapsize = (space + BLOCKSIZE - 1) / BLOCKSIZE; DirectFile fd; shmalloc_heap *heap = NULL; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d, %p )\n", __FUNCTION__, shm, filename, addr_base, space, ret_size ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_ASSERT( shm->shared->tmpfs[0] != 0 ); D_ASSERT( filename != NULL ); D_ASSERT( addr_base != NULL ); D_ASSERT( ret_size != NULL ); size = BLOCKALIGN( sizeof(shmalloc_heap) ) + BLOCKALIGN( heapsize * sizeof(shmalloc_info) ); D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename ); /* Open the virtual file. */ ret = direct_file_open( &fd, filename, O_RDWR | O_CREAT | O_TRUNC, 0660 ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not open shared memory file '%s'!\n", filename ); return ret; } if (fusion_config->shmfile_gid != -1) { if (direct_file_chown( &fd, -1, fusion_config->shmfile_gid )) D_WARN( "changing owner on %s failed", filename ); } direct_file_chmod( &fd, fusion_config->secure_fusion ? 0640 : 0660 ); if (fusion_config->madv_remove) ret = direct_file_truncate( &fd, size + space ); else ret = direct_file_truncate( &fd, size ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not truncate shared memory file '%s'!\n", filename ); goto error; } D_DEBUG_AT( Fusion_SHMHeap, " -> mapping shared memory file... (%d bytes)\n", size ); /* Map it shared. */ ret = direct_file_map( &fd, addr_base, 0, size + space, DFP_READ | DFP_WRITE, (void**) &heap ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not mmap shared memory file '%s'!\n", filename ); goto error; } if (heap != addr_base) { D_ERROR( "Fusion/SHMHeap: The mmap returned address (%p) differs from requested (%p)!\n", heap, addr_base ); ret = DR_FUSION; goto error; } direct_file_close( &fd ); D_DEBUG_AT( Fusion_SHMHeap, " -> done\n" ); heap->size = size; heap->heapsize = heapsize; heap->heapinfo = (void*) heap + BLOCKALIGN( sizeof(shmalloc_heap) ); heap->heapbase = (char*) heap->heapinfo; direct_snputs( heap->filename, filename, sizeof(heap->filename) ); D_MAGIC_SET( heap, shmalloc_heap ); *ret_size = size; return DR_OK; error: if (heap) direct_file_unmap( heap, size + space ); direct_file_close( &fd ); direct_unlink( filename ); return ret; } DirectResult __shmalloc_join_heap( FusionSHM *shm, const char *filename, void *addr_base, int size, bool write ) { DirectResult ret; DirectFile fd; shmalloc_heap *heap = NULL; int open_flags = write ? O_RDWR : O_RDONLY; int perms = DFP_READ; int heapsize = (size + BLOCKSIZE - 1) / BLOCKSIZE; if (write) perms |= DFP_WRITE; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d )\n", __FUNCTION__, shm, filename, addr_base, size ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_ASSERT( shm->shared->tmpfs[0] != 0 ); D_ASSERT( filename != NULL ); D_ASSERT( addr_base != NULL ); D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename ); /* Open the virtual file. */ ret = direct_file_open( &fd, filename, open_flags, 0 ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not open shared memory file '%s'!\n", filename ); return ret; } size += BLOCKALIGN( sizeof(shmalloc_heap) ) + BLOCKALIGN( heapsize * sizeof(shmalloc_info) ); D_DEBUG_AT( Fusion_SHMHeap, " -> mapping shared memory file... (%d bytes)\n", size ); /* Map it shared. */ ret = direct_file_map( &fd, addr_base, 0, size, perms, (void**) &heap ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not mmap shared memory file '%s'!\n", filename ); goto error; } if (heap != addr_base) { D_ERROR( "Fusion/SHMHeap: The mmap returned address (%p) differs from requested (%p)!\n", heap, addr_base ); ret = DR_FUSION; goto error; } direct_file_close( &fd ); D_MAGIC_ASSERT( heap, shmalloc_heap ); D_DEBUG_AT( Fusion_SHMHeap, " -> done\n" ); return DR_OK; error: if (heap) direct_file_unmap( heap, size ); direct_file_close( &fd ); return ret; } void * __shmalloc_brk( shmalloc_heap *heap, int increment ) { DirectResult ret; DirectFile fd; D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %d )\n", __FUNCTION__, heap, increment ); D_MAGIC_ASSERT( heap, shmalloc_heap ); D_MAGIC_ASSERT( heap->pool, FusionSHMPoolShared ); if (increment) { int new_size = heap->size + increment; if (new_size > heap->pool->max_size) { D_WARN( "maximum shared memory size exceeded" ); fusion_print_memleaks( heap->pool ); return NULL; } if (!fusion_config->madv_remove) { ret = direct_file_open( &fd, heap->filename, O_RDWR, 0 ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not open shared memory file '%s'!\n", heap->filename ); return NULL; } ret = direct_file_truncate( &fd, new_size ); if (ret) { D_DERROR( ret, "Fusion/SHMHeap: Could not truncate shared memory file '%s'!\n", heap->filename ); return NULL; } direct_file_close( &fd ); } heap->size = new_size; } return heap->pool->addr_base + heap->size - increment; } ================================================ FILE: lib/fusion/shm/pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #if FUSION_BUILD_KERNEL #include #else /* FUSION_BUILD_KERNEL */ #include #endif /* FUSION_BUILD_KERNEL */ D_DEBUG_DOMAIN( Fusion_SHMPool, "Fusion/SHMPool", "Fusion Shared Memory Pool" ); /**********************************************************************************************************************/ static DirectResult init_pool ( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared, const char *name, unsigned int max_size, bool debug ); static DirectResult join_pool ( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ); static void leave_pool ( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ); static void shutdown_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ); /**********************************************************************************************************************/ DirectResult fusion_shm_pool_create( FusionWorld *world, const char *name, unsigned int max_size, bool debug, FusionSHMPoolShared **ret_pool ) { int i; DirectResult ret; FusionSHM *shm; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( name != NULL ); D_ASSERT( max_size > 0 ); D_ASSERT( ret_pool != NULL ); D_DEBUG_AT( Fusion_SHMPool, "%s( %p [%d], '%s', %u, %p, %sdebug )\n", __FUNCTION__, world, world->shared->world_index, name, max_size, ret_pool, debug ? "" : "no-" ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); if (max_size < 8192) { D_ERROR( "Fusion/SHMPool: Maximum size (%u) should be 8192 at least!\n", max_size ); return DR_INVARG; } ret = fusion_skirmish_prevail( &shm->shared->lock ); if (ret) goto error; if (shm->shared->num_pools == FUSION_SHM_MAX_POOLS) { D_ERROR( "Fusion/SHMPool: Maximum number of pools (%d) already reached!\n", FUSION_SHM_MAX_POOLS ); ret = DR_LIMITEXCEEDED; goto error; } for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (!shm->shared->pools[i].active) break; D_MAGIC_ASSERT( &shm->shared->pools[i], FusionSHMPoolShared ); D_MAGIC_ASSUME( &shm->pools[i], FusionSHMPool ); } D_ASSERT( i < FUSION_SHM_MAX_POOLS ); D_DEBUG_AT( Fusion_SHMPool, " -> index %d\n", i ); memset( &shm->pools[i], 0, sizeof(FusionSHMPool) ); memset( &shm->shared->pools[i], 0, sizeof(FusionSHMPoolShared) ); shm->shared->pools[i].index = i; ret = init_pool( shm, &shm->pools[i], &shm->shared->pools[i], name, max_size, debug ); if (ret) goto error; shm->shared->num_pools++; fusion_skirmish_dismiss( &shm->shared->lock ); *ret_pool = &shm->shared->pools[i]; D_DEBUG_AT( Fusion_SHMPool, " -> %p\n", *ret_pool ); return DR_OK; error: fusion_skirmish_dismiss( &shm->shared->lock ); return ret; } DirectResult fusion_shm_pool_destroy( FusionWorld *world, FusionSHMPoolShared *pool ) { DirectResult ret; FusionSHM *shm; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, world, pool ); D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_ASSERT( shm->shared == pool->shm ); ret = fusion_skirmish_prevail( &shm->shared->lock ); if (ret) return ret; ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { fusion_skirmish_dismiss( &shm->shared->lock ); return ret; } D_ASSERT( pool->active ); D_ASSERT( pool->index >= 0 ); D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS ); D_ASSERT( pool->pool_id == shm->pools[pool->index].pool_id ); D_ASSERT( pool == &shm->shared->pools[pool->index] ); D_MAGIC_ASSERT( &shm->pools[pool->index], FusionSHMPool ); shutdown_pool( shm, &shm->pools[pool->index], pool ); shm->shared->num_pools--; fusion_skirmish_dismiss( &shm->shared->lock ); return DR_OK; } DirectResult fusion_shm_pool_attach( FusionSHM *shm, FusionSHMPoolShared *pool ) { D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, shm, pool ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( shm->shared == pool->shm ); D_ASSERT( pool->active ); D_ASSERT( pool->index >= 0 ); D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS ); D_ASSERT( pool == &shm->shared->pools[pool->index] ); D_ASSERT( !shm->pools[pool->index].attached ); return join_pool( shm, &shm->pools[pool->index], pool ); } DirectResult fusion_shm_pool_detach( FusionSHM *shm, FusionSHMPoolShared *pool ) { D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, shm, pool ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( shm->shared == pool->shm ); D_ASSERT( pool->active ); D_ASSERT( pool->index >= 0 ); D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS ); D_ASSERT( pool->pool_id == shm->pools[pool->index].pool_id ); D_ASSERT( pool == &shm->shared->pools[pool->index] ); D_ASSERT( shm->pools[pool->index].attached ); D_MAGIC_ASSERT( &shm->pools[pool->index], FusionSHMPool ); leave_pool( shm, &shm->pools[pool->index], pool ); return DR_OK; } DirectResult fusion_shm_pool_allocate( FusionSHMPoolShared *pool, int size, bool clear, bool lock, void **ret_data ) { DirectResult ret; void *data; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %d, %sclear, %p )\n", __FUNCTION__, pool, size, clear ? "" : "un", ret_data ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( size > 0 ); D_ASSERT( ret_data != NULL ); if (lock) { ret = fusion_skirmish_prevail( &pool->lock ); if (ret) return ret; } __shmalloc_brk( pool->heap, 0 ); data = _fusion_shmalloc( pool->heap, size ); if (!data) { if (lock) fusion_skirmish_dismiss( &pool->lock ); return DR_NOSHAREDMEMORY; } if (clear) memset( data, 0, size ); *ret_data = data; if (lock) fusion_skirmish_dismiss( &pool->lock ); return DR_OK; } DirectResult fusion_shm_pool_reallocate( FusionSHMPoolShared *pool, void *data, int size, bool lock, void **ret_data ) { DirectResult ret; void *new_data; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %d, %p )\n", __FUNCTION__, pool, data, size, ret_data ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( data != NULL ); D_ASSERT( data >= pool->addr_base ); D_ASSERT( data < pool->addr_base + pool->max_size ); D_ASSERT( size > 0 ); D_ASSERT( ret_data != NULL ); if (lock) { ret = fusion_skirmish_prevail( &pool->lock ); if (ret) return ret; } __shmalloc_brk( pool->heap, 0 ); new_data = _fusion_shrealloc( pool->heap, data, size ); if (!new_data) { if (lock) fusion_skirmish_dismiss( &pool->lock ); return DR_NOSHAREDMEMORY; } *ret_data = new_data; if (lock) fusion_skirmish_dismiss( &pool->lock ); return DR_OK; } DirectResult fusion_shm_pool_deallocate( FusionSHMPoolShared *pool, void *data, bool lock ) { DirectResult ret; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, pool, data ); D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( data != NULL ); D_ASSERT( data >= pool->addr_base ); D_ASSERT( data < pool->addr_base + pool->max_size ); if (lock) { ret = fusion_skirmish_prevail( &pool->lock ); if (ret) return ret; } __shmalloc_brk( pool->heap, 0 ); _fusion_shfree( pool->heap, data ); if (lock) fusion_skirmish_dismiss( &pool->lock ); return DR_OK; } /**********************************************************************************************************************/ #if FUSION_BUILD_KERNEL static DirectResult init_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared, const char *name, unsigned int max_size, bool debug ) { DirectResult ret; int size; FusionWorld *world; FusionSHMPoolNew pool_new = { .pool_id = 0 }; FusionSHMPoolAttach pool_attach = { .pool_id = 0 }; FusionEntryInfo info; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %u, %sdebug )\n", __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "no-" ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_ASSERT( pool != NULL ); D_ASSERT( shared != NULL ); D_ASSERT( name != NULL ); D_ASSERT( max_size > sizeof(shmalloc_heap) ); world = shm->world; /* Fill out information for new pool. */ pool_new.max_size = max_size; pool_new.max_size += BLOCKALIGN( sizeof(shmalloc_heap) ) + BLOCKALIGN( (max_size + BLOCKSIZE - 1) / BLOCKSIZE * sizeof(shmalloc_info) ); /* Create the new pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_NEW, &pool_new )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_NEW" ); return DR_FUSION; } /* Set the pool info. */ info.type = FT_SHMPOOL; info.id = pool_new.pool_id; snprintf( info.name, sizeof(info.name), "%s", name ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); fusion_entry_add_permissions( world, FT_SHMPOOL, pool_new.pool_id, 0, FUSION_SHMPOOL_ATTACH, FUSION_SHMPOOL_DETACH, 0 ); /* Set pool to attach to. */ pool_attach.pool_id = pool_new.pool_id; /* Attach to the pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_ATTACH" ); while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_DESTROY" ); break; } } return DR_FUSION; } /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( shm->world ), pool_new.pool_id ); /* Initialize the heap. */ ret = __shmalloc_init_heap( shm, buf, pool_new.addr_base, max_size, &size ); if (ret) { while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_DESTROY" ); break; } } return ret; } /* Initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = pool_new.pool_id; pool->filename = D_STRDUP( buf ); /* Initialize shared data. */ shared->active = true; shared->debug = debug; shared->shm = shm->shared; shared->max_size = pool_new.max_size; shared->pool_id = pool_new.pool_id; shared->addr_base = pool_new.addr_base; shared->heap = pool_new.addr_base; shared->heap->pool = shared; fusion_skirmish_init2( &shared->lock, name, world, fusion_config->secure_fusion ); D_MAGIC_SET( pool, FusionSHMPool ); D_MAGIC_SET( shared, FusionSHMPoolShared ); shared->name = SHSTRDUP( shared, name ); return DR_OK; } static DirectResult join_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { DirectResult ret; FusionWorld *world; FusionSHMPoolAttach pool_attach = { .pool_id = 0 }; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; /* Set pool to attach to. */ pool_attach.pool_id = shared->pool_id; /* Attach to the pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_ATTACH" ); return DR_FUSION; } /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( shm->world ), shared->pool_id ); /* Join the heap. */ ret = __shmalloc_join_heap( shm, buf, pool_attach.addr_base, shared->max_size, !fusion_config->secure_fusion ); if (ret) { while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_DETACH" ); break; } } return ret; } /* Initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = shared->pool_id; pool->filename = D_STRDUP( buf ); D_MAGIC_SET( pool, FusionSHMPool ); return DR_OK; } static void leave_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { FusionWorld *world; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_DETACH" ); break; } } if (direct_file_unmap( shared->addr_base, shared->max_size )) D_ERROR( "Fusion/SHMPool: Could not unmap shared memory file '%s'!\n", pool->filename ); pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); } static void shutdown_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { FusionWorld *world; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; SHFREE( shared, shared->name ); fusion_print_memleaks( shared ); while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHMPool: FUSION_SHMPOOL_DESTROY" ); break; } } if (direct_file_unmap( shared->addr_base, shared->max_size )) D_ERROR( "Fusion/SHMPool: Could not unmap shared memory file '%s'!\n", pool->filename ); if (direct_unlink( pool->filename )) D_ERROR( "Fusion/SHMPool: Could not unlink shared memory file '%s'!\n", pool->filename ); shared->active = false; pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); fusion_skirmish_destroy( &shared->lock ); D_MAGIC_CLEAR( shared ); } void _fusion_shmpool_process( FusionWorld *world, int pool_id, FusionSHMPoolMessage *msg ) { int i; DirectResult ret; FusionSHM *shm; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %d, %p )\n", __FUNCTION__, world, pool_id, msg ); D_MAGIC_ASSERT( world, FusionWorld ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); ret = fusion_skirmish_prevail( &shm->shared->lock ); if (ret) return; for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (shm->pools[i].attached) { D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool ); if (shm->pools[i].pool_id == pool_id) { switch (msg->type) { case FSMT_REMAP: break; case FSMT_UNMAP: D_UNIMPLEMENTED(); break; } break; } } } fusion_skirmish_dismiss( &shm->shared->lock ); } #else /* FUSION_BUILD_KERNEL */ static DirectResult init_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared, const char *name, unsigned int max_size, bool debug ) { DirectResult ret; int size; long page_size; int pool_id; unsigned int pool_max_size; void *pool_addr_base = NULL; FusionWorld *world; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %u, %sdebug )\n", __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "non-" ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_ASSERT( pool != NULL ); D_ASSERT( shared != NULL ); D_ASSERT( name != NULL ); D_ASSERT( max_size > sizeof(shmalloc_heap) ); world = shm->world; page_size = direct_pagesize(); pool_id = ++world->shared->pool_ids; pool_max_size = max_size + BLOCKALIGN( sizeof(shmalloc_heap) ) + BLOCKALIGN( (max_size + BLOCKSIZE - 1) / BLOCKSIZE * sizeof(shmalloc_info) ); pool_addr_base = world->shared->pool_base; world->shared->pool_base += ((pool_max_size + page_size - 1) & ~(page_size - 1)) + page_size; if (world->shared->pool_base > world->shared->pool_max) return DR_NOSHAREDMEMORY; /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( world ), pool_id ); /* Initialize the heap. */ ret = __shmalloc_init_heap( shm, buf, pool_addr_base, max_size, &size ); if (ret) return ret; /* initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = pool_id; pool->filename = D_STRDUP( buf ); /* Initialize shared data. */ shared->active = true; shared->debug = debug; shared->shm = shm->shared; shared->max_size = pool_max_size; shared->pool_id = pool_id; shared->addr_base = pool_addr_base; shared->heap = pool_addr_base; shared->heap->pool = shared; fusion_skirmish_init( &shared->lock, name, world ); D_MAGIC_SET( pool, FusionSHMPool ); D_MAGIC_SET( shared, FusionSHMPoolShared ); shared->name = SHSTRDUP( shared, name ); return DR_OK; } static DirectResult join_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { DirectResult ret; FusionWorld *world; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( world ), shared->pool_id ); /* Join the heap. */ ret = __shmalloc_join_heap( shm, buf, shared->addr_base, shared->max_size, true ); if (ret) return ret; /* Initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = shared->pool_id; pool->filename = D_STRDUP( buf ); D_MAGIC_SET( pool, FusionSHMPool ); return DR_OK; } static void leave_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); if (direct_file_unmap( shared->addr_base, shared->max_size )) D_ERROR( "Fusion/SHMPool: Could not unmap shared memory file '%s'!\n", pool->filename ); pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); } static void shutdown_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->world, FusionWorld ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); SHFREE( shared, shared->name ); fusion_print_memleaks( shared ); if (direct_file_unmap( shared->addr_base, shared->max_size )) D_ERROR( "Fusion/SHMPool: Could not unmap shared memory file '%s'!\n", pool->filename ); if (direct_unlink( pool->filename )) D_ERROR( "Fusion/SHMPool: Could not unlink shared memory file '%s'!\n", pool->filename ); shared->active = false; pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); fusion_skirmish_destroy( &shared->lock ); D_MAGIC_CLEAR( shared ); } #endif /* FUSION_BUILD_KERNEL */ ================================================ FILE: lib/fusion/shm/pool.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__SHM__POOL_H__ #define __FUSION__SHM__POOL_H__ #include /**********************************************************************************************************************/ DirectResult fusion_shm_pool_create ( FusionWorld *world, const char *name, unsigned int max_size, bool debug, FusionSHMPoolShared **ret_pool ); DirectResult fusion_shm_pool_destroy ( FusionWorld *world, FusionSHMPoolShared *pool ); DirectResult fusion_shm_pool_attach ( FusionSHM *shm, FusionSHMPoolShared *pool ); DirectResult fusion_shm_pool_detach ( FusionSHM *shm, FusionSHMPoolShared *pool ); DirectResult fusion_shm_pool_allocate ( FusionSHMPoolShared *pool, int size, bool clear, bool lock, void **ret_data ); DirectResult fusion_shm_pool_reallocate( FusionSHMPoolShared *pool, void *data, int size, bool lock, void **ret_data ); DirectResult fusion_shm_pool_deallocate( FusionSHMPoolShared *pool, void *data, bool lock ); #endif ================================================ FILE: lib/fusion/shm/shm.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Fusion_SHMInit, "Fusion/SHMInit", "Fusion Shared Memory Init" ); /**********************************************************************************************************************/ int fusion_find_tmpfs( char *name, int len ) { int largest = 0; char buffer[1024]; DirectFile mounts_handle; if (direct_file_open( &mounts_handle, "/proc/mounts", O_RDONLY, 0 )) return 0; while (!direct_file_get_string( &mounts_handle, buffer, sizeof(buffer) )) { char *mount_point; char *mount_fs; char *pointer = buffer; strsep( &pointer, " " ); mount_point = strsep( &pointer, " " ); mount_fs = strsep( &pointer, " " ); if (mount_fs && mount_point && (direct_access( mount_point, W_OK ) == DR_OK) && (!strcmp( mount_fs, "tmpfs" ) || !strcmp( mount_fs, "shmfs" ) || !strcmp( mount_fs, "ramfs" ))) { size_t size; if (direct_filesystem_size( mount_point, &size )) { D_ERROR( "Fusion/SHMInit: Failed to get filesystem size on '%s'!\n", mount_point ); continue; } if (size > largest || (size == largest && !strcmp( mount_point, "/dev/shm" ))) { largest = size; direct_snputs( name, mount_point, len ); } } } direct_file_close( &mounts_handle ); D_DEBUG_AT( Fusion_SHMInit, "%s( %s )\n", __FUNCTION__, name ); return largest; } DirectResult fusion_shm_init( FusionWorld *world ) { int i; int num; DirectResult ret; FusionSHM *shm; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_DEBUG_AT( Fusion_SHMInit, "%s( %p )\n", __FUNCTION__, world ); shm = &world->shm; /* Initialize local data. */ memset( shm, 0, sizeof(FusionSHM) ); shm->world = world; shm->shared = &world->shared->shm; /* Initialize shared data. */ if (fusion_master( world )) { memset( shm->shared, 0, sizeof(FusionSHMShared) ); if (fusion_config->tmpfs) { direct_snputs( shm->shared->tmpfs, fusion_config->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN ); } else if (!fusion_find_tmpfs( shm->shared->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN )) { D_ERROR( "Fusion/SHMInit: Could not find tmpfs mount point, falling back to /dev/shm!\n" ); snprintf( shm->shared->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN, "/dev/shm" ); } shm->shared->world = world->shared; /* Initialize shared lock. */ ret = fusion_skirmish_init2( &shm->shared->lock, "Fusion SHM", world, fusion_config->secure_fusion ); if (ret) { D_DERROR( ret, "Fusion/SHMInit: Failed to create skirmish!\n" ); return ret; } /* Initialize static pool array. */ for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) shm->shared->pools[i].index = i; D_MAGIC_SET( shm, FusionSHM ); D_MAGIC_SET( shm->shared, FusionSHMShared ); } else { D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_SET( shm, FusionSHM ); for (i = 0, num = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (shm->shared->pools[i].active) { D_MAGIC_ASSERT( &shm->shared->pools[i], FusionSHMPoolShared ); ret = fusion_shm_pool_attach( shm, &shm->shared->pools[i] ); if (ret) { for (--i; i >= 0; i--) { if (shm->shared->pools[i].active) fusion_shm_pool_detach( shm, &shm->shared->pools[i] ); } D_MAGIC_CLEAR( shm ); return ret; } num++; } } D_ASSERT( num == shm->shared->num_pools ); } return DR_OK; } DirectResult fusion_shm_deinit( FusionWorld *world ) { int i; DirectResult ret; FusionSHM *shm; D_MAGIC_ASSERT( world, FusionWorld ); D_DEBUG_AT( Fusion_SHMInit, "%s( %p )\n", __FUNCTION__, world ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); /* Deinitialize shared data. */ if (fusion_master( world )) { ret = fusion_skirmish_prevail( &shm->shared->lock ); if (ret) return ret; D_ASSUME( shm->shared->num_pools == 0 ); for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (shm->shared->pools[i].active) { D_MAGIC_ASSERT( &shm->shared->pools[i], FusionSHMPoolShared ); D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool ); D_WARN( "destroying remaining '%s'", shm->shared->pools[i].name ); fusion_shm_pool_destroy( world, &shm->shared->pools[i] ); } } /* Destroy shared lock. */ fusion_skirmish_destroy( &shm->shared->lock ); D_MAGIC_CLEAR( shm->shared ); } else { for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (shm->shared->pools[i].active) { D_MAGIC_ASSERT( &shm->shared->pools[i], FusionSHMPoolShared ); D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool ); fusion_shm_pool_detach( shm, &shm->shared->pools[i] ); } } } D_MAGIC_CLEAR( shm ); return DR_OK; } DirectResult fusion_shm_enum_pools( FusionWorld *world, FusionSHMPoolCallback callback, void *ctx ) { int i; FusionSHM *shm; D_MAGIC_ASSERT( world, FusionWorld ); D_MAGIC_ASSERT( world->shared, FusionWorldShared ); D_ASSERT( callback != NULL ); shm = &world->shm; D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); for (i = 0; i < FUSION_SHM_MAX_POOLS; i++) { if (!shm->shared->pools[i].active) continue; if (!shm->pools[i].attached) { D_BUG( "not attached to pool" ); continue; } D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool ); D_MAGIC_ASSERT( &shm->shared->pools[i], FusionSHMPoolShared ); if (callback( &shm->pools[i], ctx ) == DENUM_CANCEL) break; } return DR_OK; } ================================================ FILE: lib/fusion/shm/shm.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__SHM__SHM_H__ #define __FUSION__SHM__SHM_H__ #include /**********************************************************************************************************************/ typedef DirectEnumerationResult (*FusionSHMPoolCallback)( FusionSHMPool *pool, void *ctx ); /**********************************************************************************************************************/ int fusion_find_tmpfs ( char *name, int len ); DirectResult fusion_shm_init ( FusionWorld *world ); DirectResult fusion_shm_deinit ( FusionWorld *world ); DirectResult fusion_shm_enum_pools( FusionWorld *world, FusionSHMPoolCallback callback, void *ctx ); #endif ================================================ FILE: lib/fusion/shm/shm_internal.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__SHM__SHM_INTERNAL_H__ #define __FUSION__SHM__SHM_INTERNAL_H__ #include #include /**********************************************************************************************************************/ #define FUSION_SHM_MAX_POOLS 16 /* * The allocator divides the heap into blocks of fixed size. * Large requests receive one or more whole blocks, and small requests receive a fragment of a block. * Fragment sizes are powers of two, and all fragments of a block are the same size. * When all the fragments in a block have been freed, the block itself is freed. */ #define BLOCKLOG 12 /* Data structure giving per-block information. */ typedef union { /* Heap information for a busy block. */ struct { /* Zero for a large block, or positive giving the logarithm to the base two of the fragment size. */ int type; union { struct { size_t nfree; /* Free fragments in a fragmented block. */ size_t first; /* First free fragment of the block. */ } frag; /* Size (in blocks) of a large cluster. */ size_t size; } info; } busy; /* Heap information for a free block. */ struct { size_t size; /* Size (in blocks) of a free cluster. */ size_t next; /* Index of next free cluster. */ size_t prev; /* Index of previous free cluster. */ } free; } shmalloc_info; /* Doubly linked lists of free fragments. */ struct list { struct list *next; struct list *prev; }; typedef struct { int magic; /* Pointer to first block of the heap. */ char *heapbase; /* Block information table indexed by block number giving per-block information. */ shmalloc_info *heapinfo; /* Number of info entries. */ size_t heapsize; /* Current search index for the heap table. */ size_t heapindex; /* Limit of valid info table indices. */ size_t heaplimit; /* Count of large blocks allocated for each fragment size. */ int fragblocks[BLOCKLOG]; /* Free list headers for each fragment size. */ struct list fraghead[BLOCKLOG]; /* Instrumentation. */ size_t chunks_used; size_t bytes_used; size_t chunks_free; size_t bytes_free; /* Total size of heap in bytes. */ int size; /* Back pointer to shared memory pool. */ FusionSHMPoolShared *pool; /* Name of the shared memory file. */ char filename[FUSION_SHM_TMPFS_PATH_NAME_LEN+32]; } shmalloc_heap; /* * Local pool data. */ struct __Fusion_FusionSHMPool { int magic; bool attached; /* Indicates usage of this entry in the static pool array. */ FusionSHM *shm; /* Back pointer to local SHM data. */ FusionSHMPoolShared *shared; /* Pointer to shared pool data. */ int pool_id; /* The pool's ID within the world. */ char *filename; /* Name of the shared memory file. */ }; /* * Shared pool data. */ struct __Fusion_FusionSHMPoolShared { int magic; bool debug; /* Debug allocations in this pool. */ int index; /* Index within the static pool array. */ bool active; /* Indicates usage of this entry in the static pool array. */ FusionSHMShared *shm; /* Back pointer to shared SHM data. */ int max_size; /* Maximum possible size of the shared memory. */ int pool_id; /* The pool's ID within the world. */ void *addr_base; /* Virtual starting address of shared memory. */ FusionSkirmish lock; /* Lock for this pool. */ shmalloc_heap *heap; /* The actual heap information. */ char *name; /* Name of the pool (allocated in the pool). */ DirectLink *allocs; /* Used for debugging. */ }; /* * Local SHM data. */ struct __Fusion_FusionSHM { int magic; FusionWorld *world; /* Back pointer to local world data. */ FusionSHMShared *shared; /* Pointer to shared SHM data. */ FusionSHMPool pools[FUSION_SHM_MAX_POOLS]; /* Local data of all pools. */ }; /* * Shared SHM data. */ struct __Fusion_FusionSHMShared { int magic; FusionWorldShared *world; /* Back pointer to shared world data. */ FusionSkirmish lock; /* Lock for list of pools. */ int num_pools; /* Number of active pools. */ FusionSHMPoolShared pools[FUSION_SHM_MAX_POOLS]; /* Shared data of all pools. */ char tmpfs[FUSION_SHM_TMPFS_PATH_NAME_LEN]; /* Location of shared memory file. */ }; /**********************************************************************************************************************/ #define BLOCKSIZE (1 << BLOCKLOG) #define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) #define BLOCKALIGN(SIZE) (((SIZE) + BLOCKSIZE - 1) & ~(BLOCKSIZE - 1)) #define SHMEMDESC_FUNC_NAME_LENGTH 48 #define SHMEMDESC_FILE_NAME_LENGTH 24 typedef struct { DirectLink link; const void *mem; size_t bytes; char func[SHMEMDESC_FUNC_NAME_LENGTH]; char file[SHMEMDESC_FILE_NAME_LENGTH]; unsigned int line; FusionID fid; } SHMemDesc; /**********************************************************************************************************************/ /* * Allocate memory from the heap. */ void *_fusion_shmalloc ( shmalloc_heap *heap, size_t size ); /* * Resize the given region to the new size, returning a pointer to the (possibly moved) region. */ void *_fusion_shrealloc( shmalloc_heap *heap, void *ptr, size_t size ); /* * Return memory to the heap. */ void _fusion_shfree ( shmalloc_heap *heap, void *ptr ); /**********************************************************************************************************************/ DirectResult __shmalloc_init_heap( FusionSHM *shm, const char *filename, void *addr_base, int space, int *ret_size ); DirectResult __shmalloc_join_heap( FusionSHM *shm, const char *filename, void *addr_base, int size, bool write ); void *__shmalloc_brk ( shmalloc_heap *heap, int increment ); #endif ================================================ FILE: lib/fusion/shmalloc.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #if FUSION_BUILD_MULTI #include #include #include #include #include #include #else /* FUSION_BUILD_MULTI */ #include #include #endif /* FUSION_BUILD_MULTI */ #if DIRECT_BUILD_DEBUGS D_DEBUG_DOMAIN( Fusion_SHM, "Fusion/SHM", "Fusion Shared Memory allocation" ); #endif /* DIRECT_BUILD_DEBUGS */ /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI void fusion_print_madvise() { if (fusion_config->madv_remove_force) { if (fusion_config->madv_remove) D_INFO( "Fusion/SHM: Using MADV_REMOVE (forced)\n" ); else D_INFO( "Fusion/SHM: Not using MADV_REMOVE (forced)!\n" ); } else { if (direct_madvise()) D_INFO( "Fusion/SHM: Using MADV_REMOVE\n" ); else D_INFO( "Fusion/SHM: NOT using MADV_REMOVE!\n" ); } } #endif /* FUSION_BUILD_MULTI */ #if DIRECT_BUILD_DEBUGS #if FUSION_BUILD_MULTI void fusion_print_memleaks( FusionSHMPoolShared *pool ) { DirectResult ret; SHMemDesc *desc; unsigned int total = 0; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return; } if (pool->allocs) { direct_log_printf( NULL, "\nShared memory allocations remaining (%d) in '%s': \n", direct_list_count_elements_EXPENSIVE( pool->allocs ), pool->name ); direct_list_foreach (desc, pool->allocs) { direct_log_printf( NULL, " "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line ); total += desc->bytes; } direct_log_printf( NULL, " -------\n %7uk total\n", total >> 10 ); direct_log_printf( NULL, "\nShared memory file size: %dk\n", pool->heap->size >> 10 ); } fusion_skirmish_dismiss( &pool->lock ); } static SHMemDesc * fill_shmem_desc( SHMemDesc *desc, int bytes, const char *func, const char *file, int line, FusionID fusion_id ) { D_ASSERT( desc != NULL ); desc->mem = desc + 1; desc->bytes = bytes; direct_snputs( desc->func, func, SHMEMDESC_FUNC_NAME_LENGTH ); direct_snputs( desc->file, file, SHMEMDESC_FILE_NAME_LENGTH ); desc->line = line; desc->fid = fusion_id; return desc; } void * fusion_dbg_shmalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t size ) { DirectResult ret; SHMemDesc *desc; void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( file != NULL ); D_ASSERT( line > 0 ); D_ASSERT( func != NULL ); D_ASSERT( size > 0 ); if (!pool->debug) return fusion_shmalloc( pool, size ); /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return NULL; } /* Allocate memory from the pool. */ ret = fusion_shm_pool_allocate( pool, size + sizeof(SHMemDesc), false, false, &data ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not allocate "_ZU" bytes from pool!\n", size + sizeof(SHMemDesc) ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Fill description. */ desc = fill_shmem_desc( data, size, func, file, line, _fusion_id( pool->shm->world ) ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line ); /* Add description to list. */ direct_list_append( &pool->allocs, &desc->link ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return data + sizeof(SHMemDesc); } void * fusion_dbg_shcalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t nmemb, size_t size ) { DirectResult ret; SHMemDesc *desc; void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( file != NULL ); D_ASSERT( line > 0 ); D_ASSERT( func != NULL ); D_ASSERT( nmemb > 0 ); D_ASSERT( size > 0 ); if (!pool->debug) return fusion_shcalloc( pool, nmemb, size ); /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return NULL; } /* Allocate memory from the pool. */ ret = fusion_shm_pool_allocate( pool, nmemb * size + sizeof(SHMemDesc), true, false, &data ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not allocate "_ZU" bytes from pool!\n", nmemb * size + sizeof(SHMemDesc) ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Fill description. */ desc = fill_shmem_desc( data, nmemb * size, func, file, line, _fusion_id( pool->shm->world ) ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line ); /* Add description to list. */ direct_list_append( &pool->allocs, &desc->link ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return data + sizeof(SHMemDesc); } void * fusion_dbg_shrealloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr, size_t size ) { DirectResult ret; SHMemDesc *desc; void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( file != NULL ); D_ASSERT( line > 0 ); D_ASSERT( func != NULL ); D_ASSERT( what != NULL ); if (!pool->debug) return fusion_shrealloc( pool, ptr, size ); if (!ptr) return fusion_dbg_shmalloc( pool, file, line, func, size ); if (!size) { fusion_dbg_shfree( pool, file, line, func, what, ptr ); return NULL; } /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return NULL; } /* Lookup the corresponding description. */ direct_list_foreach (desc, pool->allocs) { if (desc->mem == ptr) break; } if (!desc) { D_ERROR( "Fusion/SHM: Cannot reallocate unknown chunk at %p (%s) from [%s:%d in %s()]!\n", ptr, what, file, line, func ); return NULL; } /* Remove the description in case the block moves. */ direct_list_remove( &pool->allocs, &desc->link ); /* Reallocate the memory block. */ ret = fusion_shm_pool_reallocate( pool, ptr - sizeof(SHMemDesc), size + sizeof(SHMemDesc), false, &data ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not reallocate from "_ZU" to "_ZU" bytes!\n", desc->bytes + sizeof(SHMemDesc), size + sizeof(SHMemDesc) ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Fill description. */ desc = fill_shmem_desc( data, size, func, file, line, _fusion_id( pool->shm->world ) ); D_DEBUG_AT( Fusion_SHM, "Reallocating "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) '%s'\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line, what ); /* Add description to list. */ direct_list_append( &pool->allocs, &desc->link ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); return data + sizeof(SHMemDesc); } char * fusion_dbg_shstrdup( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *string ) { DirectResult ret; SHMemDesc *desc; void *data = NULL; int length; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( file != NULL ); D_ASSERT( line > 0 ); D_ASSERT( func != NULL ); D_ASSERT( string != NULL ); if (!pool->debug) return fusion_shstrdup( pool, string ); length = strlen( string ) + 1; /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return NULL; } /* Allocate memory from the pool. */ ret = fusion_shm_pool_allocate( pool, length + sizeof(SHMemDesc), false, false, &data ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not allocate "_ZU" bytes from pool!\n", length + sizeof(SHMemDesc) ); fusion_skirmish_dismiss( &pool->lock ); return NULL; } /* Fill description. */ desc = fill_shmem_desc( data, length, func, file, line, _fusion_id( pool->shm->world ) ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) <- \"%s\"\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line, string ); D_DEBUG_AT( Fusion_SHM, " -> allocs %p\n", pool->allocs ); /* Add description to list. */ direct_list_append( &pool->allocs, &desc->link ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); /* Copy string content. */ direct_memcpy( data + sizeof(SHMemDesc), string, length ); return data + sizeof(SHMemDesc); } void fusion_dbg_shfree( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr ) { DirectResult ret; SHMemDesc *desc; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( file != NULL ); D_ASSERT( line > 0 ); D_ASSERT( func != NULL ); D_ASSERT( what != NULL ); D_ASSERT( ptr != NULL ); if (!pool->debug) return fusion_shfree( pool, ptr ); /* Lock the pool. */ ret = fusion_skirmish_prevail( &pool->lock ); if (ret) { D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" ); return; } /* Lookup the corresponding description. */ direct_list_foreach (desc, pool->allocs) { if (desc->mem == ptr) break; } if (!desc) { D_ERROR( "Fusion/SHM: Cannot free unknown chunk at %p (%s) from [%s:%d in %s()]!\n", ptr, what, file, line, func ); return; } D_DEBUG_AT( Fusion_SHM, "Freeing "_ZUn(9)" bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) '%s'\n", desc->bytes, desc->mem, (unsigned long) desc->mem - (unsigned long) pool->heap, desc->func, desc->fid, desc->file, desc->line, what ); /* Remove the description. */ direct_list_remove( &pool->allocs, &desc->link ); /* Free the memory block. */ fusion_shm_pool_deallocate( pool, ptr - sizeof(SHMemDesc), false ); /* Unlock the pool. */ fusion_skirmish_dismiss( &pool->lock ); } #else /* FUSION_BUILD_MULTI */ void * fusion_dbg_shmalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( size > 0 ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes in %-30s (%s: %d)\n", size, func, file, line ); if (pool->debug) return direct_dbg_malloc( file, line, func, size ); return malloc( size ); } void * fusion_dbg_shcalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t nmemb, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( nmemb > 0 ); D_ASSERT( size > 0 ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes in %-30s (%s: %d)\n", size, func, file, line ); if (pool->debug) return direct_dbg_calloc( file, line, func, nmemb, size ); return calloc( nmemb, size ); } void * fusion_dbg_shrealloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_DEBUG_AT( Fusion_SHM, "Reallocating "_ZUn(9)" bytes in %-30s (%s: %d) '%s'\n", size, func, file, line, what ); if (pool->debug) return direct_dbg_realloc( file, line, func, what, ptr, size ); return realloc( ptr, size ); } char * fusion_dbg_shstrdup( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *string ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( string != NULL ); D_DEBUG_AT( Fusion_SHM, "Allocating "_ZUn(9)" bytes in %-30s (%s: %d) <- \"%s\"\n", strlen( string ), func, file, line, string ); if (pool->debug) return direct_dbg_strdup( file, line, func, string ); return strdup( string ); } void fusion_dbg_shfree( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( ptr != NULL ); D_DEBUG_AT( Fusion_SHM, "Freeing bytes in %-30s (%s: %d) '%s'\n", func, file, line, what ); if (pool->debug) direct_dbg_free( file, line, func, what, ptr ); else free( ptr ); } #endif /* FUSION_BUILD_MULTI */ #else /* DIRECT_BUILD_DEBUGS */ #if FUSION_BUILD_MULTI void fusion_print_memleaks( FusionSHMPoolShared *pool ) { } #endif /* FUSION_BUILD_MULTI */ void * fusion_dbg_shmalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t size ) { return fusion_shmalloc( pool, size ); } void * fusion_dbg_shcalloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t nmemb, size_t size ) { return fusion_shcalloc( pool, nmemb, size ); } void * fusion_dbg_shrealloc( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr, size_t size ) { return fusion_shrealloc( pool, ptr, size ); } char * fusion_dbg_shstrdup( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *string ) { return fusion_shstrdup( pool, string ); } void fusion_dbg_shfree( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr ) { return fusion_shfree( pool, ptr ); } #endif /* DIRECT_BUILD_DEBUGS */ #if FUSION_BUILD_MULTI void * fusion_shmalloc( FusionSHMPoolShared *pool, size_t size ) { void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( size > 0 ); if (fusion_shm_pool_allocate( pool, size, false, true, &data )) return NULL; D_ASSERT( data != NULL ); return data; } void * fusion_shcalloc( FusionSHMPoolShared *pool, size_t nmemb, size_t size ) { void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( nmemb > 0 ); D_ASSERT( size > 0 ); if (fusion_shm_pool_allocate( pool, nmemb * size, true, true, &data )) return NULL; D_ASSERT( data != NULL ); return data; } void * fusion_shrealloc( FusionSHMPoolShared *pool, void *ptr, size_t size ) { void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); if (!ptr) return fusion_shmalloc( pool, size ); if (!size) { fusion_shfree( pool, ptr ); return NULL; } if (fusion_shm_pool_reallocate( pool, ptr, size, true, &data )) return NULL; D_ASSERT( data != NULL || size == 0 ); return data; } char * fusion_shstrdup( FusionSHMPoolShared *pool, const char *string ) { int len; void *data = NULL; D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( string != NULL ); len = strlen( string ) + 1; if (fusion_shm_pool_allocate( pool, len, false, true, &data )) return NULL; D_ASSERT( data != NULL ); direct_memcpy( data, string, len ); return data; } void fusion_shfree( FusionSHMPoolShared *pool, void *ptr ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( ptr != NULL ); fusion_shm_pool_deallocate( pool, ptr, true ); } #else /* FUSION_BUILD_MULTI */ void * fusion_shmalloc( FusionSHMPoolShared *pool, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( size > 0 ); return malloc( size ); } void * fusion_shcalloc( FusionSHMPoolShared *pool, size_t nmemb, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( nmemb > 0 ); D_ASSERT( size > 0 ); return calloc( nmemb, size ); } void * fusion_shrealloc( FusionSHMPoolShared *pool, void *ptr, size_t size ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); return realloc( ptr, size ); } char * fusion_shstrdup( FusionSHMPoolShared *pool, const char *string ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( string != NULL ); return strdup( string ); } void fusion_shfree( FusionSHMPoolShared *pool, void *ptr ) { D_MAGIC_ASSERT( pool, FusionSHMPoolShared ); D_ASSERT( ptr != NULL ); free( ptr ); } #endif /* FUSION_BUILD_MULTI */ ================================================ FILE: lib/fusion/shmalloc.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__SHMALLOC_H__ #define __FUSION__SHMALLOC_H__ #include /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI void FUSION_API fusion_print_madvise ( void ); void FUSION_API fusion_print_memleaks ( FusionSHMPoolShared *pool ); #endif /* FUSION_BUILD_MULTI */ void FUSION_API *fusion_dbg_shmalloc ( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t size ); void FUSION_API *fusion_dbg_shcalloc ( FusionSHMPoolShared *pool, const char *file, int line, const char *func, size_t nmemb, size_t size ); void FUSION_API *fusion_dbg_shrealloc ( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr, size_t size ); char FUSION_API *fusion_dbg_shstrdup ( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *string ); void FUSION_API fusion_dbg_shfree ( FusionSHMPoolShared *pool, const char *file, int line, const char *func, const char *what, void *ptr ); void FUSION_API *fusion_shmalloc ( FusionSHMPoolShared *pool, size_t size ); void FUSION_API *fusion_shcalloc ( FusionSHMPoolShared *pool, size_t nmemb, size_t size ); void FUSION_API *fusion_shrealloc ( FusionSHMPoolShared *pool, void *ptr, size_t size ); char FUSION_API *fusion_shstrdup ( FusionSHMPoolShared *pool, const char *string ); void FUSION_API fusion_shfree ( FusionSHMPoolShared *pool, void *ptr ); /**********************************************************************************************************************/ #if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) #define SHMALLOC(pool,bytes) fusion_dbg_shmalloc ( pool, __FILE__, __LINE__, __FUNCTION__, bytes ) #define SHCALLOC(pool,count,bytes) fusion_dbg_shcalloc ( pool, __FILE__, __LINE__, __FUNCTION__, count, bytes ) #define SHREALLOC(pool,mem,bytes) fusion_dbg_shrealloc( pool, __FILE__, __LINE__, __FUNCTION__, #mem, mem, bytes ) #define SHSTRDUP(pool,string) fusion_dbg_shstrdup ( pool, __FILE__, __LINE__, __FUNCTION__, string ) #define SHFREE(pool,mem) fusion_dbg_shfree ( pool, __FILE__, __LINE__, __FUNCTION__, #mem, mem ) #else /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ #define SHMALLOC fusion_shmalloc #define SHCALLOC fusion_shcalloc #define SHREALLOC fusion_shrealloc #define SHSTRDUP fusion_shstrdup #define SHFREE fusion_shfree #endif /* DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) */ #endif ================================================ FILE: lib/fusion/types.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__TYPES_H__ #define __FUSION__TYPES_H__ #include #include /**********************************************************************************************************************/ #define FUSION_API #define FCEF_NODIRECT 0x80 #define FUSION_SHM_TMPFS_PATH_NAME_LEN 64 /**********************************************************************************************************************/ typedef struct __Fusion_FusionArena FusionArena; typedef struct __Fusion_FusionCall FusionCall; typedef struct __Fusion_FusionHash FusionHash; typedef struct __Fusion_FusionObject FusionObject; typedef struct __Fusion_FusionObjectPool FusionObjectPool; typedef struct __Fusion_FusionReactor FusionReactor; typedef struct __Fusion_FusionRef FusionRef; typedef struct __Fusion_FusionSHMPool FusionSHMPool; typedef struct __Fusion_FusionSHMPoolShared FusionSHMPoolShared; typedef struct __Fusion_FusionSHM FusionSHM; typedef struct __Fusion_FusionSHMShared FusionSHMShared; typedef struct __Fusion_FusionWorld FusionWorld; typedef struct __Fusion_FusionWorldShared FusionWorldShared; /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL #include #define FUSION_CALL_MAX_LENGTH (FUSION_MESSAGE_SIZE - sizeof(FusionReadMessage)) #else /* FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL */ typedef unsigned long FusionID; typedef enum { FCEF_NONE = 0x00000000, FCEF_ONEWAY = 0x00000001, FCEF_QUEUE = 0x00000002, FCEF_ALL = 0x00000003 } FusionCallExecFlags; #if FUSION_BUILD_MULTI #include #endif /* FUSION_BUILD_MULTI */ #define FUSION_ID_MASTER 1L #define FUSION_CALL_MAX_LENGTH (64 * 1024) #endif /* FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL */ #if FUSION_BUILD_MULTI #define D_OOSHM() direct_messages_ooshm( __FUNCTION__, __FILE__, __LINE__ ) #else /* FUSION_BUILD_MULTI */ #define D_OOSHM() D_OOM() #endif /* FUSION_BUILD_MULTI */ #endif ================================================ FILE: lib/fusion/vector.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Fusion_Vector, "Fusion/Vector", "Fusion Vector" ); /**********************************************************************************************************************/ static __inline__ bool ensure_capacity( FusionVector *vector ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( vector->capacity > 0 ); if (!vector->elements) { if (vector->pool) vector->elements = SHMALLOC( vector->pool, vector->capacity * sizeof(void*) ); else vector->elements = D_MALLOC( vector->capacity * sizeof(void*) ); if (!vector->elements) return false; } else if (vector->count == vector->capacity) { void *elements; void *oldelements = vector->elements; int capacity = vector->capacity << 1; if (vector->pool) elements = SHMALLOC( vector->pool, capacity * sizeof(void*) ); else elements = D_MALLOC( capacity * sizeof(void*) ); if (!elements) return false; direct_memcpy( elements, vector->elements, vector->count * sizeof(void*) ); vector->elements = elements; vector->capacity = capacity; if (vector->pool) SHFREE( vector->pool, oldelements ); else D_FREE( oldelements ); } return true; } void fusion_vector_init( FusionVector *vector, int capacity, FusionSHMPoolShared *pool ) { D_ASSERT( vector != NULL ); D_ASSERT( capacity > 0 ); D_DEBUG_AT( Fusion_Vector, "Creating vector with initial capacity of %d...\n", capacity ); vector->elements = NULL; vector->count = 0; vector->capacity = capacity; vector->pool = pool; D_MAGIC_SET( vector, FusionVector ); } void fusion_vector_destroy( FusionVector *vector ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( vector->count == 0 || vector->elements != NULL ); if (vector->elements) { if (vector->pool) SHFREE( vector->pool, vector->elements ); else D_FREE( vector->elements ); vector->elements = NULL; } D_MAGIC_CLEAR( vector ); } DirectResult fusion_vector_add( FusionVector *vector, void *element ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( element != NULL ); /* Make sure there's a free entry left. */ if (!ensure_capacity( vector )) return D_OOSHM(); /* Add the element to the vector. */ vector->elements[vector->count++] = element; return DR_OK; } DirectResult fusion_vector_insert( FusionVector *vector, void *element, int index ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( element != NULL ); D_ASSERT( index >= 0 ); D_ASSERT( index <= vector->count ); /* Make sure there's a free entry left. */ if (!ensure_capacity( vector )) return D_OOSHM(); /* Move elements from insertion point one up. */ memmove( &vector->elements[index+1], &vector->elements[index], (vector->count - index) * sizeof(void*) ); /* Insert the element into the vector. */ vector->elements[index] = element; /* Increase the element counter. */ vector->count++; return DR_OK; } DirectResult fusion_vector_move( FusionVector *vector, int from, int to ) { void *element; D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( from >= 0 ); D_ASSERT( from < vector->count ); D_ASSERT( to >= 0 ); D_ASSERT( to < vector->count ); if (to == from) return DR_OK; /* Save the element. */ element = vector->elements[from]; /* Move elements that lie on the way to the new position. */ if (to > from) { /* Element is moving up -> move other elements down. */ memmove( &vector->elements[from], &vector->elements[from+1], (to - from) * sizeof(void*) ); } else { /* Element is moving down -> move other elements up. */ memmove( &vector->elements[to+1], &vector->elements[to], (from - to) * sizeof(void*) ); } /* Restore the element at the new position. */ vector->elements[to] = element; return DR_OK; } DirectResult fusion_vector_remove( FusionVector *vector, int index ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( index >= 0 ); D_ASSERT( index < vector->count ); /* Move elements after this element one down. */ memmove( &vector->elements[index], &vector->elements[index+1], (vector->count - index - 1) * sizeof(void*) ); /* Decrease the element counter. */ vector->count--; return DR_OK; } ================================================ FILE: lib/fusion/vector.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __FUSION__VECTOR_H__ #define __FUSION__VECTOR_H__ #include #include /**********************************************************************************************************************/ typedef struct { int magic; void **elements; int count; int capacity; FusionSHMPoolShared *pool; } FusionVector; /**********************************************************************************************************************/ void FUSION_API fusion_vector_init ( FusionVector *vector, int capacity, FusionSHMPoolShared *pool ); void FUSION_API fusion_vector_destroy( FusionVector *vector ); DirectResult FUSION_API fusion_vector_add ( FusionVector *vector, void *element ); DirectResult FUSION_API fusion_vector_insert ( FusionVector *vector, void *element, int index ); DirectResult FUSION_API fusion_vector_move ( FusionVector *vector, int from, int to ); DirectResult FUSION_API fusion_vector_remove ( FusionVector *vector, int index ); /**********************************************************************************************************************/ static __inline__ bool fusion_vector_has_elements( const FusionVector *vector ) { D_MAGIC_ASSERT( vector, FusionVector ); return vector->count > 0; } static __inline__ bool fusion_vector_is_empty( const FusionVector *vector ) { D_MAGIC_ASSERT( vector, FusionVector ); return vector->count == 0; } static __inline__ int fusion_vector_size( const FusionVector *vector ) { D_MAGIC_ASSERT( vector, FusionVector ); return vector->count; } static __inline__ void * fusion_vector_at( const FusionVector *vector, int index ) { D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( index >= 0 ); D_ASSERT( index < vector->count ); return vector->elements[index]; } static __inline__ bool fusion_vector_contains( const FusionVector *vector, const void *element ) { int i; int count; void * const *elements; D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( element != NULL ); count = vector->count; elements = vector->elements; /* Start with more recently added elements. */ for (i = count - 1; i >= 0; i--) if (elements[i] == element) return true; return false; } static __inline__ int fusion_vector_index_of( const FusionVector *vector, const void *element ) { int i; int count; void * const *elements; D_MAGIC_ASSERT( vector, FusionVector ); D_ASSERT( element != NULL ); count = vector->count; elements = vector->elements; /* Start with more recently added elements. */ for (i = count - 1; i >= 0; i--) if (elements[i] == element) return i; return INT_MIN >> 2; } #define fusion_vector_foreach(element,index,vector) \ for ((index) = 0; \ (index) < (vector).count && \ (element = (__typeof__(element)) (vector).elements[index]); \ (index)++) #define fusion_vector_foreach_reverse(element,index,vector) \ for ((index) = (vector).count - 1; \ (index) >= 0 && (vector).count && (vector).elements && \ (element = (__typeof__(element)) (vector).elements[index]); \ (index)--) #endif ================================================ FILE: meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA project('DirectFB2', 'c', version: '2.0.0', meson_version: '>= 0.61', default_options: 'buildtype=release') directfb_version = meson.project_version() directfb_major_version = directfb_version.split('.')[0].to_int() directfb_minor_version = directfb_version.split('.')[1].to_int() directfb_micro_version = directfb_version.split('.')[2].to_int() if get_option('default_library') == 'both' error('''Choose library type between 'shared' or 'static'.''') elif get_option('default_library') == 'shared' libsuffix = '.so' else libsuffix = '.a' endif if get_option('default_library') == 'shared' and not get_option('constructors') error('''Choose 'static' library type to disable use of constructor attribute.''') endif moduledirname = get_option('moduledirname') if moduledirname == '' if get_option('debug') moduledirname = 'directfb-@0@.@1@-0-debug'.format(directfb_major_version, directfb_minor_version) else if not get_option('debug-support') moduledirname = 'directfb-@0@.@1@-0-pure'.format(directfb_major_version, directfb_minor_version) else moduledirname = 'directfb-@0@.@1@-0'.format(directfb_major_version, directfb_minor_version) endif endif endif moduledir = get_option('prefix') / get_option('libdir') / moduledirname cc = meson.get_compiler('c') config_conf = configuration_data() config_conf.set('SIZEOF_LONG', cc.sizeof('long'), description: 'The size of long, as computed by sizeof.') config_conf.set('WORDS_BIGENDIAN', host_machine.endian() == 'big', description: 'Byte ordering is bigendian.') if host_machine.cpu_family() == 'x86' or host_machine.cpu_family() == 'x86_64' if get_option('mmx') config_conf.set('USE_MMX', 1, description: 'Define to 1 if you are compiling MMX assembly support.') endif endif if host_machine.cpu_family() == 'arm' or host_machine.cpu_family() == 'aarch64' if get_option('neon') config_conf.set('USE_NEON', 1, description: 'Define to 1 if you are compiling NEON assembly support.') endif endif configure_file(configuration: config_conf, output: 'config.h') config_inc = include_directories('.') lib_inc = include_directories('lib') directfb_inc = [include_directories('include', 'src'), lib_inc] add_global_arguments('-Wstrict-prototypes', language: 'c') pkgconfig = import('pkgconfig') # core libraries subdir('include') subdir('lib/direct') subdir('lib/fusion') subdir('src') # core system modules subdir('systems/dummy') if get_option('os') == 'linux' if get_option('drmkms') subdir('systems/drmkms') endif if get_option('fbdev') subdir('systems/fbdev') endif endif # input driver modules if get_option('os') == 'linux' if get_option('linux_input') subdir('inputdrivers/linux_input') endif endif # interface modules subdir('interfaces/ICoreResourceManager') subdir('interfaces/IDirectFBFont') subdir('interfaces/IDirectFBImageProvider') subdir('interfaces/IDirectFBVideoProvider') subdir('interfaces/IDirectFBWindows') # wm modules subdir('wm/default') # generate the .pc files of the static modules if get_option('default_library') == 'static' dfb_update_pkgconfig_conf = configuration_data() dfb_update_pkgconfig_conf.set('PKGCONFIGDIR', get_option('prefix') / get_option('libdir') / 'pkgconfig') dfb_update_pkgconfig_conf.set('VERSION', directfb_version) dfb_update_pkgconfig = configure_file(configuration: dfb_update_pkgconfig_conf, input: 'dfb-update-pkgconfig.in', output: 'dfb-update-pkgconfig', install: true, install_dir: get_option('bindir')) meson.add_install_script(dfb_update_pkgconfig) endif ================================================ FILE: meson_options.txt ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA option('args-size', type: 'integer', value: '1024', description: 'Maximum static args size (bytes) for Flux') option('constructors', type: 'boolean', description: 'Use constructor attribute for library initialization and loaded modules') option('debug-support', type: 'boolean', description: 'Debug support') option('drmkms', type: 'boolean', description: 'Linux DRM/KMS support') option('fbdev', type: 'boolean', description: 'Linux FBDev support') option('fluxcomp', type : 'string', value: 'fluxcomp.py', description : 'The fluxcomp program to use') option('linux_input', type: 'boolean', description: 'Linux Input support') option('memcpy-probing', type: 'boolean', value: false, description: 'Use memcpy() probing') option('message-size', type: 'integer', value: '16384', description: 'Maximum message size (bytes) for Fusion') option('mmx', type: 'boolean', description: 'MMX assembly support') option('moduledirname', type: 'string', description: 'DirectFB module directory name') option('multi', type: 'boolean', value: false, description: 'Multi application support') option('multi-kernel', type: 'boolean', value: false, description: 'Use the Linux Fusion device for multi application') option('neon', type: 'boolean', description: 'NEON assembly support') option('network', type: 'boolean', description: 'Network support') option('os', type: 'string', value: 'linux', description: 'OS name') option('piped-stream', type: 'boolean', description: 'Piped stream support') option('sentinels', type: 'boolean', value: false, description: 'Sentinels') option('smooth-scaling', type: 'boolean', description: 'Smooth scaling') option('text', type: 'boolean', description: 'Text output') option('trace', type: 'boolean', value: false, description: 'Call tracing') option('vendor-version', type: 'string', value: '', description: 'Vendor version') ================================================ FILE: src/core/CoreDFB.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ICore version 1.0 object CoreDFB method { name Initialize } method { name Register arg { name slave_call direction input type int typename u32 } } method { name CreateSurface arg { name config direction input type struct typename CoreSurfaceConfig } arg { name type direction input type enum typename CoreSurfaceTypeFlags } arg { name resource_id direction input type int typename u64 } arg { name palette direction input type object typename CorePalette optional yes } arg { name surface direction output type object typename CoreSurface } } method { name CreatePalette arg { name size direction input type int typename u32 } arg { name colorspace direction input type enum typename DFBSurfaceColorSpace } arg { name palette direction output type object typename CorePalette } } method { name ClipboardSet arg { name mime_type direction input type int typename char count mime_type_size } arg { name mime_type_size direction input type int typename u32 } arg { name data direction input type int typename char count data_size } arg { name data_size direction input type int typename u32 } arg { name timestamp_us direction input type int typename u64 } } method { name ClipboardGet arg { name mime_type direction output type int typename char max MAX_CLIPBOARD_MIME_TYPE_SIZE count mime_type_size } arg { name mime_type_size direction output type int typename u32 } arg { name data direction output type int typename char max MAX_CLIPBOARD_DATA_SIZE count data_size } arg { name data_size direction output type int typename u32 } } method { name ClipboardGetTimestamp arg { name timestamp_us direction output type int typename u64 } } method { name WaitIdle } method { name GetSurface arg { name surface_id direction input type int typename u32 } arg { name surface direction output type object typename CoreSurface } } method { name AllowSurface arg { name surface direction input type object typename CoreSurface } arg { name executable direction input type int typename char count executable_length } arg { name executable_length direction input type int typename u32 } } method { name CreateState arg { name state direction output type object typename CoreGraphicsState } } } ================================================ FILE: src/core/CoreDFB_CallMode.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ typedef enum { COREDFB_CALL_DENY = 0x00000000, COREDFB_CALL_DIRECT = 0x00000001, COREDFB_CALL_INDIRECT = 0x00000002 } CoreDFBCallMode; static __inline__ CoreDFBCallMode CoreDFB_CallMode( CoreDFB *core ) { #if FUSION_BUILD_MULTI if (dfb_config->call_nodirect) { if (dfb_core_is_master( core )) { DirectThread *self = direct_thread_self(); if (self && fusion_dispatcher_tid( core->world ) == direct_thread_get_tid( self )) return COREDFB_CALL_DIRECT; } return COREDFB_CALL_INDIRECT; } if (core->shutdown_tid && core->shutdown_tid != direct_gettid() && direct_gettid() != fusion_dispatcher_tid(core->world) && !Core_GetCalling()) { while (core_dfb) direct_thread_sleep( 10000 ); return COREDFB_CALL_DENY; } if (dfb_core_is_master( core ) || !fusion_config->secure_fusion) return COREDFB_CALL_DIRECT; return COREDFB_CALL_INDIRECT; #else /* FUSION_BUILD_MULTI */ if (dfb_config->call_nodirect) { DirectThread *self = direct_thread_self(); if (self && fusion_dispatcher_tid( core->world ) == direct_thread_get_tid( self )) return COREDFB_CALL_DIRECT; return COREDFB_CALL_INDIRECT; } return COREDFB_CALL_DIRECT; #endif /* FUSION_BUILD_MULTI */ } ================================================ FILE: src/core/CoreDFB_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__COREDFB_INCLUDES_H__ #define __CORE__COREDFB_INCLUDES_H__ #include #include #include #include #include #include #include #include /**********************************************************************************************************************/ static __inline__ DirectResult CoreDFB_Call( CoreDFB *core, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &core->shared->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } /**********************************************************************************************************************/ static __inline__ DirectResult CoreGraphicsState_Catch( CoreDFB *core, void *object_ptr, CoreGraphicsState **ret_state ) { *ret_state = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreGraphicsState_Throw( CoreGraphicsState *state, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = state->object.id; fusion_reactor_add_permissions( state->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( &state->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &state->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); if (dfb_config->graphics_state_call_limit) fusion_call_set_quota( &state->call, catcher, dfb_config->graphics_state_call_limit ); fusion_object_add_owner( &state->object, catcher ); return fusion_ref_throw( &state->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ u32 CoreLayerContext_GetID( const CoreLayerContext *context ) { return context->object.id; } static __inline__ DirectResult CoreLayerContext_Lookup( CoreDFB *core, u32 object_id, FusionID caller, CoreLayerContext **ret_context ) { DFBResult ret; CoreLayerContext *context; ret = dfb_core_get_layer_context( core, object_id, &context ); if (ret) return ret; if (fusion_object_check_owner( &context->object, caller, true )) { dfb_layer_context_unref( context ); return DR_ACCESSDENIED; } *ret_context = context; return DR_OK; } static __inline__ DirectResult CoreLayerContext_Unref( CoreLayerContext *context ) { return dfb_layer_context_unref( context ); } static __inline__ DirectResult CoreLayerContext_Catch( CoreDFB *core, void *object_ptr, CoreLayerContext **ret_context ) { *ret_context = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreLayerContext_Throw( CoreLayerContext *context, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = context->object.id; fusion_reactor_add_permissions( context->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( &context->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &context->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); if (context->stack) fusion_call_add_permissions( &context->stack->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); return fusion_ref_throw( &context->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ DirectResult CoreLayerRegion_Catch( CoreDFB *core, void *object_ptr, CoreLayerRegion **ret_region ) { *ret_region = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreLayerRegion_Throw( CoreLayerRegion *region, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = region->object.id; fusion_reactor_add_permissions( region->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( ®ion->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( ®ion->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); return fusion_ref_throw( ®ion->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ u32 CorePalette_GetID( const CorePalette *palette ) { return palette->object.id; } static __inline__ DirectResult CorePalette_Lookup( CoreDFB *core, u32 object_id, FusionID caller, CorePalette **ret_palette ) { DFBResult ret; CorePalette *palette; ret = dfb_core_get_palette( core, object_id, &palette ); if (ret) return ret; if (fusion_object_check_owner( &palette->object, caller, false )) { dfb_palette_unref( palette ); return DR_ACCESSDENIED; } *ret_palette = palette; return DR_OK; } static __inline__ DirectResult CorePalette_Unref( CorePalette *palette ) { return dfb_palette_unref( palette ); } static __inline__ DirectResult CorePalette_Catch( CoreDFB *core, void *object_ptr, CorePalette **ret_palette ) { *ret_palette = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CorePalette_Throw( CorePalette *palette, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = palette->object.id; fusion_reactor_add_permissions( palette->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( &palette->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &palette->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); fusion_object_add_owner( &palette->object, catcher ); return fusion_ref_throw( &palette->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ u32 CoreSurface_GetID( const CoreSurface *surface ) { return surface->object.id; } static __inline__ DirectResult CoreSurface_Lookup( CoreDFB *core, u32 object_id, FusionID caller, CoreSurface **ret_surface ) { DFBResult ret; CoreSurface *surface; ret = fusion_object_lookup( core->shared->surface_pool, object_id, (FusionObject**) &surface ); if (ret) return ret; if (caller != FUSION_ID_MASTER && surface->object.identity != caller && fusion_object_check_owner( &surface->object, caller, false )) { return DR_ACCESSDENIED; } *ret_surface = surface; return DR_OK; } static __inline__ DirectResult CoreSurface_Unref( CoreSurface *surface ) { return DR_OK; } static __inline__ DirectResult CoreSurface_Catch( CoreDFB *core, void *object_ptr, CoreSurface **ret_surface ) { *ret_surface = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreSurface_Throw( CoreSurface *surface, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = surface->object.id; fusion_reactor_add_permissions( surface->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH | FUSION_REACTOR_PERMIT_DISPATCH ); fusion_ref_add_permissions( &surface->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &surface->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); fusion_object_add_owner( &surface->object, catcher ); return fusion_ref_throw( &surface->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ DirectResult CoreSurfaceAllocation_Catch( CoreDFB *core, void *object_ptr, CoreSurfaceAllocation **ret_allocation ) { *ret_allocation = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreSurfaceAllocation_Throw( CoreSurfaceAllocation *allocation, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = allocation->object.id; fusion_reactor_add_permissions( allocation->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( &allocation->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &allocation->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); fusion_object_add_owner( &allocation->object, catcher ); return fusion_ref_throw( &allocation->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ u32 CoreSurfaceBuffer_GetID( const CoreSurfaceBuffer *buffer ) { return buffer->object.id; } static __inline__ DirectResult CoreSurfaceBuffer_Lookup( CoreDFB *core, u32 object_id, FusionID caller, CoreSurfaceBuffer **ret_buffer ) { DFBResult ret; CoreSurfaceBuffer *buffer; ret = dfb_core_get_surface_buffer( core, object_id, &buffer ); if (ret) return ret; if (fusion_object_check_owner( &buffer->object, caller, false )) { dfb_surface_buffer_unref( buffer ); return DR_ACCESSDENIED; } *ret_buffer = buffer; return DR_OK; } static __inline__ DirectResult CoreSurfaceBuffer_Unref( CoreSurfaceBuffer *buffer ) { return dfb_surface_buffer_unref( buffer ); } /**********************************************************************************************************************/ static __inline__ DirectResult CoreSurfaceClient_Catch( CoreDFB *core, void *object_ptr, CoreSurfaceClient **ret_client ) { *ret_client = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreSurfaceClient_Throw( CoreSurfaceClient *client, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = client->object.id; fusion_reactor_add_permissions( client->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_ref_add_permissions( &client->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &client->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); fusion_object_add_owner( &client->object, catcher ); return fusion_ref_throw( &client->object.ref, catcher ); } /**********************************************************************************************************************/ static __inline__ u32 CoreWindow_GetID( const CoreWindow *window ) { return window->object.id; } static __inline__ DirectResult CoreWindow_Lookup( CoreDFB *core, u32 object_id, FusionID caller, CoreWindow **ret_window ) { DFBResult ret; CoreWindow *window; ret = dfb_core_get_window( core, object_id, &window ); if (ret) return ret; if (caller != FUSION_ID_MASTER && window->object.identity != caller && fusion_object_check_owner( &window->object, caller, false )) { dfb_window_unref( window ); return DR_ACCESSDENIED; } *ret_window = window; return DR_OK; } static __inline__ DirectResult CoreWindow_Unref( CoreWindow *window ) { return dfb_window_unref( window ); } static __inline__ DirectResult CoreWindow_Catch( CoreDFB *core, void *object_ptr, CoreWindow **ret_window ) { *ret_window = object_ptr; return fusion_object_catch( object_ptr ); } static __inline__ DirectResult CoreWindow_Throw( CoreWindow *window, FusionID catcher, u32 *ret_object_id ) { *ret_object_id = window->object.id; fusion_reactor_add_permissions( window->object.reactor, catcher, FUSION_REACTOR_PERMIT_ATTACH_DETACH | FUSION_REACTOR_PERMIT_DISPATCH ); fusion_ref_add_permissions( &window->object.ref, catcher, FUSION_REF_PERMIT_REF_UNREF_LOCAL | FUSION_REF_PERMIT_CATCH ); fusion_call_add_permissions( &window->call, catcher, FUSION_CALL_PERMIT_EXECUTE ); fusion_object_add_owner( &window->object, catcher ); return fusion_ref_throw( &window->object.ref, catcher ); } #endif ================================================ FILE: src/core/CoreDFB_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreDFB, "DirectFB/Core", "DirectFB Core" ); /**********************************************************************************************************************/ DFBResult ICore_Real__Initialize( CoreDFB *obj ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); if (Core_GetIdentity() != FUSION_ID_MASTER) return DFB_ACCESSDENIED; return dfb_core_initialize( core_dfb ); } DFBResult ICore_Real__Register( CoreDFB *obj, u32 slave_call ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); return Core_Resource_AddIdentity( Core_GetIdentity(), slave_call ); } DFBResult ICore_Real__CreateSurface( CoreDFB *obj, const CoreSurfaceConfig *config, CoreSurfaceTypeFlags type, u64 resource_id, CorePalette *palette, CoreSurface **ret_surface ) { DFBResult ret; CoreSurface *surface; D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); D_ASSERT( config != NULL ); D_ASSERT( ret_surface != NULL ); ret = Core_Resource_CheckSurface( config, resource_id ); if (ret) return ret; ret = dfb_surface_create( obj, config, type, resource_id, palette, &surface ); if (ret) return ret; Core_Resource_AddSurface( surface ); *ret_surface = surface; return DFB_OK; } DFBResult ICore_Real__CreatePalette( CoreDFB *obj, u32 size, DFBSurfaceColorSpace colorspace, CorePalette **ret_palette ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); D_ASSERT( ret_palette != NULL ); return dfb_palette_create( obj, size, colorspace, ret_palette ); } DFBResult ICore_Real__ClipboardSet( CoreDFB *obj, const char *mime_type, u32 mime_type_size, const char *data, u32 data_size, u64 timestamp_us ) { struct timeval tv; D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); tv.tv_sec = timestamp_us / 1000000; tv.tv_usec = timestamp_us % 1000000; return dfb_clipboard_set( dfb_core_get_part( core_dfb, DFCP_CLIPBOARD ), mime_type, data, data_size, &tv ); } DFBResult ICore_Real__ClipboardGet( CoreDFB *obj, char *ret_mime_type, u32 *ret_mime_type_size, char *ret_data, u32 *ret_data_size ) { DFBResult ret; char *mime_type; void *data; unsigned int data_size; D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); ret = dfb_clipboard_get( dfb_core_get_part( core_dfb, DFCP_CLIPBOARD ), &mime_type, &data, &data_size ); if (ret) return ret; direct_memcpy( ret_mime_type, mime_type, strlen( mime_type ) + 1 ); *ret_mime_type_size = strlen( mime_type ) + 1; direct_memcpy( ret_data, data, data_size ); *ret_data_size = data_size; D_FREE( data ); D_FREE( mime_type ); return DFB_OK; } DFBResult ICore_Real__ClipboardGetTimestamp( CoreDFB *obj, u64 *ret_timestamp_us ) { DFBResult ret; struct timeval tv; D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); ret = dfb_clipboard_get_timestamp( dfb_core_get_part( core_dfb, DFCP_CLIPBOARD ), &tv ); if (ret) return ret; *ret_timestamp_us = tv.tv_sec * 1000000 + tv.tv_usec; return DFB_OK; } DFBResult ICore_Real__WaitIdle( CoreDFB *obj ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); return dfb_gfxcard_sync(); } DFBResult ICore_Real__GetSurface( CoreDFB *obj, u32 surface_id, CoreSurface **ret_surface ) { DFBResult ret; CoreSurface *surface; char path[1000]; size_t path_length; D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p, %u )\n", __FUNCTION__, obj, surface_id ); D_MAGIC_ASSERT( obj, CoreDFB ); if (fusion_config->secure_fusion && dfb_config->ownership_check && !dfb_core_is_master( core_dfb )) { ret = fusion_get_fusionee_path( dfb_core_world( core_dfb ), Core_GetIdentity(), path, sizeof(path), &path_length ); if (ret) return ret; D_DEBUG_AT( DirectFB_CoreDFB, " -> '%s'\n", path ); } ret = dfb_core_get_surface( core_dfb, surface_id, &surface ); if (ret) { D_DEBUG_AT( DirectFB_CoreDFB, " -> dfb_core_get_surface() failed!\n" ); return ret; } if (fusion_config->secure_fusion && dfb_config->ownership_check && !dfb_core_is_master( core_dfb )) { ret = fusion_object_has_access( &surface->object, path ); if (ret) { D_DEBUG_AT( DirectFB_CoreDFB, " -> no access!\n" ); dfb_surface_unref( surface ); return ret; } fusion_object_add_owner( &surface->object, Core_GetIdentity() ); } D_DEBUG_AT( DirectFB_CoreDFB, " -> surface %p\n", surface ); *ret_surface = surface; return DFB_OK; } DFBResult ICore_Real__AllowSurface( CoreDFB *obj, CoreSurface *surface, const char *executable, u32 executable_length ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p, %p, '%s' )\n", __FUNCTION__, obj, surface, executable ); D_MAGIC_ASSERT( obj, CoreDFB ); D_ASSERT( surface != NULL ); D_ASSERT( executable != NULL ); return fusion_object_add_access( &surface->object, executable ); } DFBResult ICore_Real__CreateState( CoreDFB *obj, CoreGraphicsState **ret_state ) { D_DEBUG_AT( DirectFB_CoreDFB, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreDFB ); D_ASSERT( ret_state != NULL ); return dfb_graphics_state_create( core_dfb, ret_state ); } ================================================ FILE: src/core/CoreGraphicsState.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IGraphicsState version 1.0 object CoreGraphicsState method { name SetDrawingFlags async yes queue yes arg { name flags direction input type enum typename DFBSurfaceDrawingFlags } } method { name SetBlittingFlags async yes queue yes arg { name flags direction input type enum typename DFBSurfaceBlittingFlags } } method { name SetClip async yes queue yes arg { name region direction input type struct typename DFBRegion } } method { name SetColor async yes queue yes arg { name color direction input type struct typename DFBColor } } method { name SetColorAndIndex async yes queue yes arg { name color direction input type struct typename DFBColor } arg { name index direction input type int typename u32 } } method { name SetSrcBlend async yes queue yes arg { name function direction input type enum typename DFBSurfaceBlendFunction } } method { name SetDstBlend async yes queue yes arg { name function direction input type enum typename DFBSurfaceBlendFunction } } method { name SetSrcColorKey async yes queue yes arg { name key direction input type int typename u32 } } method { name SetDstColorKey async yes queue yes arg { name key direction input type int typename u32 } } method { name SetDestination async yes queue yes arg { name surface direction input type object typename CoreSurface } } method { name SetSource async yes queue yes arg { name surface direction input type object typename CoreSurface } } method { name SetSourceMask async yes queue yes arg { name surface direction input type object typename CoreSurface } } method { name SetSourceMaskVals async yes queue yes arg { name offset direction input type struct typename DFBPoint } arg { name flags direction input type enum typename DFBSurfaceMaskFlags } } method { name SetIndexTranslation async yes queue yes arg { name indices direction input type struct typename s32 count num } arg { name num direction input type int typename u32 } } method { name SetColorKey async yes queue yes arg { name key direction input type struct typename DFBColorKey } } method { name SetRenderOptions async yes queue yes arg { name options direction input type enum typename DFBSurfaceRenderOptions } } method { name SetMatrix async yes queue yes arg { name values direction input type struct typename s32 count 9 } } method { name SetSource2 async yes queue yes arg { name surface direction input type object typename CoreSurface } } method { name SetFrom async yes queue yes arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name eye direction input type enum typename DFBSurfaceStereoEye } } method { name SetTo async yes queue yes arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name eye direction input type enum typename DFBSurfaceStereoEye } } method { name FillRectangles async yes queue yes arg { name rects direction input type struct typename DFBRectangle count num } arg { name num direction input type int typename u32 } } method { name DrawRectangles async yes queue yes arg { name rects direction input type struct typename DFBRectangle count num } arg { name num direction input type int typename u32 } } method { name DrawLines async yes queue yes arg { name lines direction input type struct typename DFBRegion count num } arg { name num direction input type int typename u32 } } method { name FillTriangles async yes queue yes arg { name triangles direction input type struct typename DFBTriangle count num } arg { name num direction input type int typename u32 } } method { name FillTrapezoids async yes queue yes arg { name trapezoids direction input type struct typename DFBTrapezoid count num } arg { name num direction input type int typename u32 } } method { name FillQuadrangles async yes queue yes arg { name quadrangles direction input type struct typename DFBPoint count num } arg { name num direction input type int typename u32 } } method { name FillSpans async yes queue yes arg { name y direction input type int typename s32 } arg { name spans direction input type struct typename DFBSpan count num } arg { name num direction input type int typename u32 } } method { name Blit async yes queue yes arg { name rects direction input type struct typename DFBRectangle count num } arg { name points direction input type struct typename DFBPoint count num } arg { name num direction input type int typename u32 } } method { name Blit2 async yes queue yes arg { name rects direction input type struct typename DFBRectangle count num } arg { name points1 direction input type struct typename DFBPoint count num } arg { name points2 direction input type struct typename DFBPoint count num } arg { name num direction input type int typename u32 } } method { name StretchBlit async yes queue yes arg { name srects direction input type struct typename DFBRectangle count num } arg { name drects direction input type struct typename DFBRectangle count num } arg { name num direction input type int typename u32 } } method { name TileBlit async yes queue yes arg { name rects direction input type struct typename DFBRectangle count num } arg { name points1 direction input type struct typename DFBPoint count num } arg { name points2 direction input type struct typename DFBPoint count num } arg { name num direction input type int typename u32 } } method { name TextureTriangles async yes queue yes arg { name vertices direction input type struct typename DFBVertex count num } arg { name num direction input type int typename u32 } arg { name formation direction input type enum typename DFBTriangleFormation } } method { name Flush async yes } method { name ReleaseSource async yes queue yes } method { name SetSrcConvolution async yes queue yes arg { name filter direction input type struct typename DFBConvolutionFilter } } method { name GetAccelerationMask arg { name accel direction output type enum typename DFBAccelerationMask } } } ================================================ FILE: src/core/CoreGraphicsStateClient.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_GraphicsStateClient, "Core/GfxState/Client", "DirectFB Core Graphics State Client" ); D_DEBUG_DOMAIN( Core_GraphicsStateClient_Flush, "Core/GfxState/Client/Flush", "DirectFB Core Graphics State Client Flush" ); /**********************************************************************************************************************/ typedef struct clients_s { CoreGraphicsStateClient *client; struct clients_s *next; } clients_t; static clients_t *clients_begin = NULL, *clients_end; static int lock_init = 0; static DirectMutex lock; void AddClient( CoreGraphicsStateClient *client ) { if (!lock_init) { direct_mutex_init( &lock ); lock_init = 1; } direct_mutex_lock( &lock ); clients_t *clients = D_CALLOC (1, sizeof(clients_t)); clients->client = client; clients->next = NULL; if (!clients_begin) clients_begin = clients_end = clients; else { clients_end->next = clients; clients_end = clients; } direct_mutex_unlock( &lock ); } void RemoveClient( CoreGraphicsStateClient *client ) { direct_mutex_lock( &lock ); clients_t *clients = clients_begin; if (clients->client == client) { if (clients->next) { clients_begin = clients->next; D_FREE( clients ); } else { D_FREE( clients ); clients_begin = NULL; direct_mutex_unlock( &lock ); direct_mutex_deinit( &lock ); lock_init = 0; return; } } else { while (clients->next) { if (clients->next->client == client) { clients_t *tmp_clients = clients; tmp_clients = clients->next; clients->next = tmp_clients->next; if (!tmp_clients->next) clients_end = clients; D_FREE( tmp_clients ); break; } clients = clients->next; } } direct_mutex_unlock( &lock ); } /**********************************************************************************************************************/ DFBResult CoreGraphicsStateClient_Init( CoreGraphicsStateClient *client, CardState *state ) { DFBResult ret; D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p, %p )\n", __FUNCTION__, client, state ); D_ASSERT( client != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT( state->core, CoreDFB ); client->magic = 0; client->core = state->core; client->state = state; client->gfx_state = NULL; ret = CoreDFB_CreateState( state->core, &client->gfx_state ); if (ret) return ret; D_DEBUG_AT( Core_GraphicsStateClient, " -> gfxstate id 0x%x\n", (unsigned int) client->gfx_state->object.ref.multi.id ); D_MAGIC_SET( client, CoreGraphicsStateClient ); AddClient( client ); /* Make legacy functions use state client. */ state->client = client; return DFB_OK; } void CoreGraphicsStateClient_Deinit( CoreGraphicsStateClient *client ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_DEBUG_AT( Core_GraphicsStateClient, " -> gfxstate id 0x%x\n", (unsigned int) client->gfx_state->object.ref.multi.id ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); CoreGraphicsStateClient_Flush( client ); dfb_graphics_state_unref( client->gfx_state ); RemoveClient( client ); D_MAGIC_CLEAR( client ); } void CoreGraphicsStateClient_Flush( CoreGraphicsStateClient *client ) { D_DEBUG_AT( Core_GraphicsStateClient_Flush, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_flush(); } else { CoreGraphicsState_Flush( client->gfx_state ); } } DFBResult CoreGraphicsStateClient_ReleaseSource( CoreGraphicsStateClient *client ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); CoreGraphicsState_ReleaseSource( client->gfx_state ); return DFB_OK; } DFBResult CoreGraphicsStateClient_SetColorAndIndex( CoreGraphicsStateClient *client, const DFBColor *color, u32 index ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); CoreGraphicsState_SetColorAndIndex( client->gfx_state, color, index ); return DFB_OK; } static DFBResult CoreGraphicsStateClient_SetState( CoreGraphicsStateClient *client, CardState *state, StateModificationFlags flags ) { DFBResult ret; D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p, %p, flags 0x%08x )\n", __FUNCTION__, client, state, flags ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_MAGIC_ASSERT( state, CardState ); if (flags & SMF_DRAWING_FLAGS) { ret = CoreGraphicsState_SetDrawingFlags( client->gfx_state, state->drawingflags ); if (ret) return ret; } if (flags & SMF_BLITTING_FLAGS) { ret = CoreGraphicsState_SetBlittingFlags( client->gfx_state, state->blittingflags ); if (ret) return ret; } if (flags & SMF_CLIP) { ret = CoreGraphicsState_SetClip( client->gfx_state, &state->clip ); if (ret) return ret; } if (flags & SMF_COLOR) { ret = CoreGraphicsState_SetColor( client->gfx_state, &state->color ); if (ret) return ret; } if (flags & SMF_SRC_BLEND) { ret = CoreGraphicsState_SetSrcBlend( client->gfx_state, state->src_blend ); if (ret) return ret; } if (flags & SMF_DST_BLEND) { ret = CoreGraphicsState_SetDstBlend( client->gfx_state, state->dst_blend ); if (ret) return ret; } if (flags & SMF_SRC_COLORKEY) { ret = CoreGraphicsState_SetSrcColorKey( client->gfx_state, state->src_colorkey ); if (ret) return ret; } if (flags & SMF_DST_COLORKEY) { ret = CoreGraphicsState_SetDstColorKey( client->gfx_state, state->dst_colorkey ); if (ret) return ret; } if (flags & SMF_DESTINATION) { D_DEBUG_AT( Core_GraphicsStateClient, " -> destination %p [%u]\n", state->destination, state->destination->object.id ); ret = CoreGraphicsState_SetDestination( client->gfx_state, state->destination ); if (ret) return ret; } if (flags & SMF_SOURCE) { ret = CoreGraphicsState_SetSource( client->gfx_state, state->source ); if (ret) return ret; } if (flags & SMF_SOURCE_MASK) { ret = CoreGraphicsState_SetSourceMask( client->gfx_state, state->source_mask ); if (ret) return ret; } if (flags & SMF_SOURCE_MASK_VALS) { ret = CoreGraphicsState_SetSourceMaskVals( client->gfx_state, &state->src_mask_offset, state->src_mask_flags ); if (ret) return ret; } if (flags & SMF_INDEX_TRANSLATION) { ret = CoreGraphicsState_SetIndexTranslation( client->gfx_state, state->index_translation, state->num_translation ); if (ret) return ret; } if (flags & SMF_COLORKEY) { ret = CoreGraphicsState_SetColorKey( client->gfx_state, &state->colorkey ); if (ret) return ret; } if (flags & SMF_RENDER_OPTIONS) { ret = CoreGraphicsState_SetRenderOptions( client->gfx_state, state->render_options ); if (ret) return ret; } if (flags & SMF_MATRIX) { ret = CoreGraphicsState_SetMatrix( client->gfx_state, state->matrix ); if (ret) return ret; } if (flags & SMF_SOURCE2) { ret = CoreGraphicsState_SetSource2( client->gfx_state, state->source2 ); if (ret) return ret; } if (flags & SMF_FROM) { ret = CoreGraphicsState_SetFrom( client->gfx_state, state->from, state->from_eye ); if (ret) return ret; } if (flags & SMF_TO) { ret = CoreGraphicsState_SetTo( client->gfx_state, state->to, state->to_eye ); if (ret) return ret; } if (flags & SMF_SRC_CONVOLUTION) { ret = CoreGraphicsState_SetSrcConvolution( client->gfx_state, &state->src_convolution ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_Update( CoreGraphicsStateClient *client, DFBAccelerationMask accel, CardState *state ) { DFBResult ret; StateModificationFlags flags = SMF_TO | SMF_DESTINATION | SMF_CLIP | SMF_RENDER_OPTIONS; D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->mod_hw == SMF_NONE ); if (state->render_options & DSRO_MATRIX) flags |= SMF_MATRIX; if (DFB_DRAWING_FUNCTION( accel )) { flags |= SMF_DRAWING_FLAGS | SMF_COLOR; if (state->drawingflags & DSDRAW_BLEND) flags |= SMF_SRC_BLEND | SMF_DST_BLEND; if (state->drawingflags & DSDRAW_DST_COLORKEY) flags |= SMF_DST_COLORKEY; } else { flags |= SMF_BLITTING_FLAGS | SMF_FROM | SMF_SOURCE; if (accel == DFXL_BLIT2) flags |= SMF_FROM | SMF_SOURCE2; if (state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) flags |= SMF_COLOR; if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) flags |= SMF_SRC_BLEND | SMF_DST_BLEND; if (state->blittingflags & DSBLIT_SRC_COLORKEY) flags |= SMF_SRC_COLORKEY; if (state->blittingflags & DSBLIT_DST_COLORKEY) flags |= SMF_DST_COLORKEY; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) flags |= SMF_FROM | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS; if (state->blittingflags & DSBLIT_INDEX_TRANSLATION) flags |= SMF_INDEX_TRANSLATION; if (state->blittingflags & DSBLIT_COLORKEY_PROTECT) flags |= SMF_COLORKEY; if (state->blittingflags & DSBLIT_SRC_CONVOLUTION) flags |= SMF_SRC_CONVOLUTION; } ret = CoreGraphicsStateClient_SetState( client, state, state->modified & flags ); if (ret) return ret; state->modified = state->modified & ~flags; return DFB_OK; } DFBResult CoreGraphicsStateClient_GetAccelerationMask( CoreGraphicsStateClient *client, DFBAccelerationMask *ret_accel ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( ret_accel != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { return dfb_state_get_acceleration_mask( client->state, ret_accel ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, client->state->source ? (client->state->source2 ? DFXL_BLIT2 : DFXL_BLIT) : DFXL_FILLRECTANGLE, client->state ); ret = CoreGraphicsState_GetAccelerationMask( client->gfx_state, ret_accel ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_FillRectangles( CoreGraphicsStateClient *client, const DFBRectangle *rects, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( rects != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_fillrectangles( (DFBRectangle*) rects, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_FILLRECTANGLE, client->state ); ret = CoreGraphicsState_FillRectangles( client->gfx_state, rects, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_DrawRectangles( CoreGraphicsStateClient *client, const DFBRectangle *rects, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( rects != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { unsigned int i; for (i = 0; i < num; i++) dfb_gfxcard_drawrectangle( (DFBRectangle*) &rects[i], client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_DRAWRECTANGLE, client->state ); ret = CoreGraphicsState_DrawRectangles( client->gfx_state, rects, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_DrawLines( CoreGraphicsStateClient *client, const DFBRegion *lines, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( lines != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_drawlines( (DFBRegion*) lines, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_DRAWLINE, client->state ); ret = CoreGraphicsState_DrawLines( client->gfx_state, lines, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_FillTriangles( CoreGraphicsStateClient *client, const DFBTriangle *triangles, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( triangles != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_filltriangles( (DFBTriangle*) triangles, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_FILLTRIANGLE, client->state ); ret = CoreGraphicsState_FillTriangles( client->gfx_state, triangles, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_FillTrapezoids( CoreGraphicsStateClient *client, const DFBTrapezoid *trapezoids, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( trapezoids != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_filltrapezoids( (DFBTrapezoid*) trapezoids, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_FILLTRAPEZOID, client->state ); ret = CoreGraphicsState_FillTrapezoids( client->gfx_state, trapezoids, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_FillQuadrangles( CoreGraphicsStateClient *client, const DFBPoint *points, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( points != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_fillquadrangles( (DFBPoint*) points, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_FILLQUADRANGLE, client->state ); ret = CoreGraphicsState_FillQuadrangles( client->gfx_state, points, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_FillSpans( CoreGraphicsStateClient *client, int y, const DFBSpan *spans, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( spans != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_fillspans( y, (DFBSpan*) spans, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_FILLRECTANGLE, client->state ); ret = CoreGraphicsState_FillSpans( client->gfx_state, y, spans, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_Blit( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_batchblit( (DFBRectangle*) rects, (DFBPoint*) points, num, client->state ); } else { DFBResult ret; unsigned int i; CoreGraphicsStateClient_Update( client, DFXL_BLIT, client->state ); for (i = 0; i < num; i += 200) { ret = CoreGraphicsState_Blit( client->gfx_state, &rects[i], &points[i], MIN( 200, num - i ) ); if (ret) return ret; } } return DFB_OK; } DFBResult CoreGraphicsStateClient_Blit2( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( rects != NULL ); D_ASSERT( points1 != NULL ); D_ASSERT( points2 != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_batchblit2( (DFBRectangle*) rects, (DFBPoint*) points1, (DFBPoint*) points2, num, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_BLIT2, client->state ); ret = CoreGraphicsState_Blit2( client->gfx_state, rects, points1, points2, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_StretchBlit( CoreGraphicsStateClient *client, const DFBRectangle *srects, const DFBRectangle *drects, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p ) <- source buffer %p\n", __FUNCTION__, client, client->state->source_buffer ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( srects != NULL ); D_ASSERT( drects != NULL ); if (num == 0) return DFB_OK; if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { if (num == 1 && srects[0].w == drects[0].w && srects[0].h == drects[0].h) { DFBPoint point = { drects[0].x, drects[0].y }; D_DEBUG_AT( Core_GraphicsStateClient, " -> %4d,%4d => %4d,%4d-%4dx%4d\n", srects[0].x, srects[0].y, drects[0].x, drects[0].x, drects[0].w, drects[0].h ); dfb_gfxcard_batchblit( (DFBRectangle*) srects, &point, 1, client->state ); } else { dfb_gfxcard_batchstretchblit( (DFBRectangle*) srects, (DFBRectangle*) drects, num, client->state ); } } else { DFBResult ret; if (num == 1 && srects[0].w == drects[0].w && srects[0].h == drects[0].h) { CoreGraphicsStateClient_Update( client, DFXL_BLIT, client->state ); DFBPoint point = { drects[0].x, drects[0].y }; ret = CoreGraphicsState_Blit( client->gfx_state, srects, &point, 1 ); if (ret) return ret; } else { CoreGraphicsStateClient_Update( client, DFXL_STRETCHBLIT, client->state ); ret = CoreGraphicsState_StretchBlit( client->gfx_state, srects, drects, num ); if (ret) return ret; } } return DFB_OK; } DFBResult CoreGraphicsStateClient_TileBlit( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, unsigned int num ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( rects != NULL ); D_ASSERT( points1 != NULL ); D_ASSERT( points2 != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { u32 i; for (i = 0; i < num; i++) dfb_gfxcard_tileblit( (DFBRectangle*) &rects[i], points1[i].x, points1[i].y, points2[i].x, points2[i].y, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_BLIT, client->state ); ret = CoreGraphicsState_TileBlit( client->gfx_state, rects, points1, points2, num ); if (ret) return ret; } return DFB_OK; } DFBResult CoreGraphicsStateClient_TextureTriangles( CoreGraphicsStateClient *client, const DFBVertex *vertices, int num, DFBTriangleFormation formation ) { D_DEBUG_AT( Core_GraphicsStateClient, "%s( %p )\n", __FUNCTION__, client ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); D_ASSERT( vertices != NULL ); if (!dfb_config->call_nodirect && (dfb_core_is_master( client->core ) || !fusion_config->secure_fusion)) { dfb_gfxcard_texture_triangles( (DFBVertex*) vertices, num, formation, client->state ); } else { DFBResult ret; CoreGraphicsStateClient_Update( client, DFXL_TEXTRIANGLES, client->state ); ret = CoreGraphicsState_TextureTriangles( client->gfx_state, vertices, num, formation ); if (ret) return ret; } return DFB_OK; } ================================================ FILE: src/core/CoreGraphicsStateClient.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORE_GRAPHICS_STATE_CLIENT_H__ #define __CORE__CORE_GRAPHICS_STATE_CLIENT_H__ #include /**********************************************************************************************************************/ struct __DFB_CoreGraphicsStateClient { int magic; void *priv; CoreDFB *core; CardState *state; /* Local state structure. */ CoreGraphicsState *gfx_state; /* Remote object for rendering, syncing values from local state as needed. */ }; /**********************************************************************************************************************/ DFBResult CoreGraphicsStateClient_Init ( CoreGraphicsStateClient *client, CardState *state ); void CoreGraphicsStateClient_Deinit ( CoreGraphicsStateClient *client ); void CoreGraphicsStateClient_Flush ( CoreGraphicsStateClient *client ); DFBResult CoreGraphicsStateClient_ReleaseSource ( CoreGraphicsStateClient *client ); DFBResult CoreGraphicsStateClient_SetColorAndIndex ( CoreGraphicsStateClient *client, const DFBColor *color, u32 index ); DFBResult CoreGraphicsStateClient_Update ( CoreGraphicsStateClient *client, DFBAccelerationMask accel, CardState *state ); DFBResult CoreGraphicsStateClient_GetAccelerationMask( CoreGraphicsStateClient *client, DFBAccelerationMask *ret_accel ); DFBResult CoreGraphicsStateClient_FillRectangles ( CoreGraphicsStateClient *client, const DFBRectangle *rects, unsigned int num ); DFBResult CoreGraphicsStateClient_DrawRectangles ( CoreGraphicsStateClient *client, const DFBRectangle *rects, unsigned int num ); DFBResult CoreGraphicsStateClient_DrawLines ( CoreGraphicsStateClient *client, const DFBRegion *lines, unsigned int num ); DFBResult CoreGraphicsStateClient_FillTriangles ( CoreGraphicsStateClient *client, const DFBTriangle *triangles, unsigned int num ); DFBResult CoreGraphicsStateClient_FillTrapezoids ( CoreGraphicsStateClient *client, const DFBTrapezoid *trapezoids, unsigned int num ); DFBResult CoreGraphicsStateClient_FillQuadrangles ( CoreGraphicsStateClient *client, const DFBPoint *points, unsigned int num ); DFBResult CoreGraphicsStateClient_FillSpans ( CoreGraphicsStateClient *client, int y, const DFBSpan *spans, unsigned int num ); DFBResult CoreGraphicsStateClient_Blit ( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points, unsigned int num ); DFBResult CoreGraphicsStateClient_Blit2 ( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, unsigned int num ); DFBResult CoreGraphicsStateClient_StretchBlit ( CoreGraphicsStateClient *client, const DFBRectangle *srects, const DFBRectangle *drects, unsigned int num ); DFBResult CoreGraphicsStateClient_TileBlit ( CoreGraphicsStateClient *client, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, unsigned int num ); DFBResult CoreGraphicsStateClient_TextureTriangles ( CoreGraphicsStateClient *client, const DFBVertex *vertices, int num, DFBTriangleFormation formation ); #endif ================================================ FILE: src/core/CoreGraphicsState_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreGraphicsState_Call( CoreGraphicsState *state, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &state->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreGraphicsState_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( DirectFB_CoreGraphicsState, "DirectFB/CoreGraphicsState", "DirectFB CoreGraphicsState" ); /**********************************************************************************************************************/ DFBResult IGraphicsState_Real__SetDrawingFlags( CoreGraphicsState *obj, DFBSurfaceDrawingFlags flags ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_drawing_flags( &obj->state, flags ); return DFB_OK; } DFBResult IGraphicsState_Real__SetBlittingFlags( CoreGraphicsState *obj, DFBSurfaceBlittingFlags flags ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_blitting_flags( &obj->state, flags ); return DFB_OK; } DFBResult IGraphicsState_Real__SetClip( CoreGraphicsState *obj, const DFBRegion *region ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( region != NULL ); dfb_state_set_clip( &obj->state, region ); return DFB_OK; } DFBResult IGraphicsState_Real__SetColor( CoreGraphicsState *obj, const DFBColor *color ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( color != NULL ); dfb_state_set_color( &obj->state, color ); return DFB_OK; } DFBResult IGraphicsState_Real__SetColorAndIndex( CoreGraphicsState *obj, const DFBColor *color, u32 index ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( color != NULL ); dfb_state_set_color( &obj->state, color ); dfb_state_set_color_index( &obj->state, index ); obj->state.colors[0] = *color; obj->state.color_indices[0] = index; return DFB_OK; } DFBResult IGraphicsState_Real__SetSrcBlend( CoreGraphicsState *obj, DFBSurfaceBlendFunction function ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_src_blend( &obj->state, function ); return DFB_OK; } DFBResult IGraphicsState_Real__SetDstBlend( CoreGraphicsState *obj, DFBSurfaceBlendFunction function ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_dst_blend( &obj->state, function ); return DFB_OK; } DFBResult IGraphicsState_Real__SetSrcColorKey( CoreGraphicsState *obj, u32 key ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_src_colorkey( &obj->state, key ); return DFB_OK; } DFBResult IGraphicsState_Real__SetDstColorKey( CoreGraphicsState *obj, u32 key ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_dst_colorkey( &obj->state, key ); return DFB_OK; } DFBResult IGraphicsState_Real__SetDestination( CoreGraphicsState *obj, CoreSurface *surface ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( surface != NULL ); dfb_state_set_destination( &obj->state, surface ); obj->state.modified |= SMF_DESTINATION; return DFB_OK; } DFBResult IGraphicsState_Real__SetSource( CoreGraphicsState *obj, CoreSurface *surface ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( surface != NULL ); dfb_state_set_source( &obj->state, surface ); return DFB_OK; } DFBResult IGraphicsState_Real__SetSourceMask( CoreGraphicsState *obj, CoreSurface *surface ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( surface != NULL ); dfb_state_set_source_mask( &obj->state, surface ); return DFB_OK; } DFBResult IGraphicsState_Real__SetSourceMaskVals( CoreGraphicsState *obj, const DFBPoint *offset, DFBSurfaceMaskFlags flags ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( offset != NULL ); dfb_state_set_source_mask_vals( &obj->state, offset, flags ); return DFB_OK; } DFBResult IGraphicsState_Real__SetIndexTranslation( CoreGraphicsState *obj, const s32 *indices, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_index_translation( &obj->state, indices, num ); return DFB_OK; } DFBResult IGraphicsState_Real__SetColorKey( CoreGraphicsState *obj, const DFBColorKey *key ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( key != NULL ); dfb_state_set_colorkey( &obj->state, key ); return DFB_OK; } DFBResult IGraphicsState_Real__SetRenderOptions( CoreGraphicsState *obj, DFBSurfaceRenderOptions options ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_render_options( &obj->state, options ); return DFB_OK; } DFBResult IGraphicsState_Real__SetMatrix( CoreGraphicsState *obj, const s32 *values ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_matrix( &obj->state, values ); return DFB_OK; } DFBResult IGraphicsState_Real__SetSource2( CoreGraphicsState *obj, CoreSurface *surface ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( surface != NULL ); dfb_state_set_source2( &obj->state, surface ); return DFB_OK; } DFBResult IGraphicsState_Real__SetFrom( CoreGraphicsState *obj, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p, %u, %u )\n", __FUNCTION__, obj, role, eye ); dfb_state_set_from( &obj->state, role, eye ); return DFB_OK; } DFBResult IGraphicsState_Real__SetTo( CoreGraphicsState *obj, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p, %u, %u )\n", __FUNCTION__, obj, role, eye ); dfb_state_set_to( &obj->state, role, eye ); return DFB_OK; } DFBResult IGraphicsState_Real__FillRectangles( CoreGraphicsState *obj, const DFBRectangle *rects, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_fillrectangles( (DFBRectangle*) rects, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__DrawRectangles( CoreGraphicsState *obj, const DFBRectangle *rects, u32 num ) { u32 i; D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; for (i = 0; i < num; i++) dfb_gfxcard_drawrectangle( (DFBRectangle*) &rects[i], &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__DrawLines( CoreGraphicsState *obj, const DFBRegion *lines, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_drawlines( (DFBRegion*) lines, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__FillTriangles( CoreGraphicsState *obj, const DFBTriangle *triangles, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_filltriangles( (DFBTriangle*) triangles, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__FillTrapezoids( CoreGraphicsState *obj, const DFBTrapezoid *trapezoids, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_filltrapezoids( (DFBTrapezoid*) trapezoids, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__FillQuadrangles( CoreGraphicsState *obj, const DFBPoint *points, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_fillquadrangles( (DFBPoint*) points, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__FillSpans( CoreGraphicsState *obj, s32 y, const DFBSpan *spans, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination) return DFB_NOCONTEXT; dfb_gfxcard_fillspans( y, (DFBSpan*) spans, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__Blit( CoreGraphicsState *obj, const DFBRectangle *rects, const DFBPoint *points, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination || !obj->state.source) return DFB_NOCONTEXT; if ((obj->state.blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && !obj->state.source_mask) return DFB_NOCONTEXT; D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); dfb_gfxcard_batchblit( (DFBRectangle*) rects, (DFBPoint*) points, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__Blit2( CoreGraphicsState *obj, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination || !obj->state.source || !obj->state.source2) return DFB_NOCONTEXT; if ((obj->state.blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && !obj->state.source_mask) return DFB_NOCONTEXT; D_ASSERT( rects != NULL ); D_ASSERT( points1 != NULL ); D_ASSERT( points2 != NULL ); dfb_gfxcard_batchblit2( (DFBRectangle*) rects, (DFBPoint*) points1, (DFBPoint*) points2, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__StretchBlit( CoreGraphicsState *obj, const DFBRectangle *srects, const DFBRectangle *drects, u32 num ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination || !obj->state.source) return DFB_NOCONTEXT; if ((obj->state.blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && !obj->state.source_mask) return DFB_NOCONTEXT; D_ASSERT( srects != NULL ); D_ASSERT( drects != NULL ); dfb_gfxcard_batchstretchblit( (DFBRectangle*) srects, (DFBRectangle*) drects, num, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__TileBlit( CoreGraphicsState *obj, const DFBRectangle *rects, const DFBPoint *points1, const DFBPoint *points2, u32 num ) { u32 i; D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination || !obj->state.source) return DFB_NOCONTEXT; if ((obj->state.blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && !obj->state.source_mask) return DFB_NOCONTEXT; D_ASSERT( rects != NULL ); D_ASSERT( points1 != NULL ); D_ASSERT( points2 != NULL ); for (i = 0; i < num; i++) dfb_gfxcard_tileblit( (DFBRectangle*) &rects[i], points1[i].x, points1[i].y, points2[i].x, points2[i].y, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__TextureTriangles( CoreGraphicsState *obj, const DFBVertex *vertices, u32 num, DFBTriangleFormation formation ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); if (!obj->state.destination || !obj->state.source) return DFB_NOCONTEXT; if ((obj->state.blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && !obj->state.source_mask) return DFB_NOCONTEXT; D_ASSERT( vertices != NULL ); dfb_gfxcard_texture_triangles( (DFBVertex*) vertices, num, formation, &obj->state ); return DFB_OK; } DFBResult IGraphicsState_Real__Flush( CoreGraphicsState *obj ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_gfxcard_flush(); return DFB_OK; } DFBResult IGraphicsState_Real__ReleaseSource( CoreGraphicsState *obj ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); dfb_state_set_source( &obj->state, NULL ); dfb_state_set_source_mask( &obj->state, NULL ); dfb_state_set_source2( &obj->state, NULL ); return DFB_OK; } DFBResult IGraphicsState_Real__SetSrcConvolution( CoreGraphicsState *obj, const DFBConvolutionFilter *filter ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( filter != NULL ); dfb_state_set_src_convolution( &obj->state, filter ); return DFB_OK; } DFBResult IGraphicsState_Real__GetAccelerationMask( CoreGraphicsState *obj, DFBAccelerationMask *ret_accel ) { D_DEBUG_AT( DirectFB_CoreGraphicsState, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_accel != NULL ); return dfb_state_get_acceleration_mask( &obj->state, ret_accel ); } ================================================ FILE: src/core/CoreInputDevice.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IInputDevice version 1.0 object CoreInputDevice method { name SetKeymapEntry arg { name key_code direction input type int typename s32 } arg { name entry direction input type struct typename DFBInputDeviceKeymapEntry } } method { name SetConfiguration arg { name config direction input type struct typename DFBInputDeviceConfig } } } ================================================ FILE: src/core/CoreInputDevice_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include static __inline__ DirectResult CoreInputDevice_Call( CoreInputDevice *device, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return fusion_call_execute3( &device->shared->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreInputDevice_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( DirectFB_CoreInputDevice, "DirectFB/CoreInputDevice", "DirectFB CoreInputDevice" ); /**********************************************************************************************************************/ DFBResult IInputDevice_Real__SetKeymapEntry( CoreInputDevice *obj, s32 key_code, const DFBInputDeviceKeymapEntry *entry ) { D_DEBUG_AT( DirectFB_CoreInputDevice, "%s( %p )\n", __FUNCTION__, obj ); return dfb_input_device_set_keymap_entry( obj, key_code, entry ); } DFBResult IInputDevice_Real__SetConfiguration( CoreInputDevice *obj, const DFBInputDeviceConfig *config ) { D_DEBUG_AT( DirectFB_CoreInputDevice, "%s( %p )\n", __FUNCTION__, obj ); return dfb_input_device_set_configuration( obj, config ); } ================================================ FILE: src/core/CoreLayer.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ILayer version 1.0 object CoreLayer method { name CreateContext arg { name context direction output type object typename CoreLayerContext } } method { name GetPrimaryContext arg { name activate direction input type enum typename DFBBoolean } arg { name context direction output type object typename CoreLayerContext } } method { name ActivateContext arg { name context direction input type object typename CoreLayerContext } } method { name GetCurrentOutputField arg { name field direction output type int typename s32 } } method { name SetLevel arg { name level direction input type int typename s32 } } method { name WaitVSync } } ================================================ FILE: src/core/CoreLayerContext.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ILayerContext version 1.0 object CoreLayerContext method { name GetPrimaryRegion arg { name create direction input type enum typename DFBBoolean } arg { name region direction output type object typename CoreLayerRegion } } method { name TestConfiguration arg { name config direction input type struct typename DFBDisplayLayerConfig } arg { name failed direction output type enum typename DFBDisplayLayerConfigFlags optional yes } } method { name SetConfiguration arg { name config direction input type struct typename DFBDisplayLayerConfig } } method { name SetScreenLocation arg { name location direction input type struct typename DFBLocation } } method { name SetScreenPosition arg { name position direction input type struct typename DFBPoint } } method { name SetScreenRectangle arg { name rectangle direction input type struct typename DFBRectangle } } method { name SetStereoDepth arg { name follow_video direction input type enum typename DFBBoolean } arg { name z direction input type int typename s32 } } method { name SetOpacity arg { name opacity direction input type int typename u8 } } method { name SetSourceRectangle arg { name rectangle direction input type struct typename DFBRectangle } } method { name SetFieldParity arg { name field direction input type int typename u32 } } method { name SetClipRegions arg { name regions direction input type struct typename DFBRegion count num } arg { name num direction input type int typename u32 } arg { name positive direction input type enum typename DFBBoolean } } method { name SetSrcColorKey arg { name key direction input type struct typename DFBColorKey } } method { name SetDstColorKey arg { name key direction input type struct typename DFBColorKey } } method { name SetColorAdjustment arg { name adjustment direction input type struct typename DFBColorAdjustment } } method { name CreateWindow arg { name description direction input type struct typename DFBWindowDescription } arg { name window direction output type object typename CoreWindow } } method { name FindWindow arg { name window_id direction input type int typename u32 } arg { name window direction output type object typename CoreWindow } } method { name SetRotation arg { name rotation direction input type int typename s32 } } method { name FindWindowByResourceID arg { name resource_id direction input type int typename u64 } arg { name window direction output type object typename CoreWindow } } } ================================================ FILE: src/core/CoreLayerContext_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreLayerContext_Call( CoreLayerContext *context, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &context->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreLayerContext_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreLayerContext, "DirectFB/CoreLayerContext", "DirectFB CoreLayerContext" ); /**********************************************************************************************************************/ DFBResult ILayerContext_Real__GetPrimaryRegion( CoreLayerContext *obj, DFBBoolean create, CoreLayerRegion **ret_region ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_region != NULL ); return dfb_layer_context_get_primary_region( obj, create, ret_region ); } DFBResult ILayerContext_Real__TestConfiguration( CoreLayerContext *obj, const DFBDisplayLayerConfig *config, DFBDisplayLayerConfigFlags *ret_failed ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_layer_context_test_configuration( obj, config, ret_failed ); } DFBResult ILayerContext_Real__SetConfiguration( CoreLayerContext *obj, const DFBDisplayLayerConfig *config ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_layer_context_set_configuration( obj, config ); } DFBResult ILayerContext_Real__SetScreenLocation( CoreLayerContext *obj, const DFBLocation *location ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( location != NULL ); return dfb_layer_context_set_screenlocation( obj, location ); } DFBResult ILayerContext_Real__SetScreenPosition( CoreLayerContext *obj, const DFBPoint *position ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( position != NULL ); return dfb_layer_context_set_screenposition( obj, position->x, position->y ); } DFBResult ILayerContext_Real__SetScreenRectangle( CoreLayerContext *obj, const DFBRectangle *rectangle ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( rectangle != NULL ); return dfb_layer_context_set_screenrectangle( obj, rectangle ); } DFBResult ILayerContext_Real__SetStereoDepth( CoreLayerContext *obj, DFBBoolean follow_video, s32 z ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_context_set_stereo_depth( obj, follow_video, z ); } DFBResult ILayerContext_Real__SetOpacity( CoreLayerContext *obj, u8 opacity ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_context_set_opacity( obj, opacity ); } DFBResult ILayerContext_Real__SetSourceRectangle( CoreLayerContext *obj, const DFBRectangle *rectangle ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( rectangle != NULL ); return dfb_layer_context_set_sourcerectangle( obj, rectangle ); } DFBResult ILayerContext_Real__SetFieldParity( CoreLayerContext *obj, u32 field ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_context_set_field_parity( obj, field ); } DFBResult ILayerContext_Real__SetClipRegions( CoreLayerContext *obj, const DFBRegion *regions, u32 num, DFBBoolean positive ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( regions != NULL ); return dfb_layer_context_set_clip_regions( obj, regions, num, positive ? DFB_TRUE : DFB_FALSE ); } DFBResult ILayerContext_Real__SetSrcColorKey( CoreLayerContext *obj, const DFBColorKey *key ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( key != NULL ); return dfb_layer_context_set_src_colorkey( obj, key->r, key->g, key->b, key->index ); } DFBResult ILayerContext_Real__SetDstColorKey( CoreLayerContext *obj, const DFBColorKey *key ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( key != NULL ); return dfb_layer_context_set_dst_colorkey( obj, key->r, key->g, key->b, key->index ); } DFBResult ILayerContext_Real__SetColorAdjustment( CoreLayerContext *obj, const DFBColorAdjustment *adjustment ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( adjustment != NULL ); return dfb_layer_context_set_coloradjustment( obj, adjustment ); } DFBResult ILayerContext_Real__CreateWindow( CoreLayerContext *obj, const DFBWindowDescription *description, CoreWindow **ret_window ) { DFBResult ret; D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( description != NULL ); D_ASSERT( ret_window != NULL ); if (description->flags & DWDESC_PARENT) { CoreWindow *parent; ret = dfb_core_get_window( core_dfb, description->parent_id, &parent ); if (ret) return ret; if (fusion_object_check_owner( &parent->object, Core_GetIdentity(), false )) { dfb_window_unref( parent ); return DFB_ACCESSDENIED; } dfb_window_unref( parent ); } if (description->flags & DWDESC_TOPLEVEL_ID) { CoreWindow *toplevel; ret = dfb_core_get_window( core_dfb, description->toplevel_id, &toplevel ); if (ret) return ret; if (fusion_object_check_owner( &toplevel->object, Core_GetIdentity(), false )) { dfb_window_unref( toplevel ); return DFB_ACCESSDENIED; } dfb_window_unref( toplevel ); } return dfb_layer_context_create_window( core_dfb, obj, description, ret_window ); } DFBResult ILayerContext_Real__FindWindow( CoreLayerContext *obj, u32 window_id, CoreWindow **ret_window ) { CoreWindow *window; FusionID caller; D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_window != NULL ); window = dfb_layer_context_find_window( obj, window_id ); if (!window) return DFB_IDNOTFOUND; caller = Core_GetIdentity(); if (dfb_config->ownership_check && caller != FUSION_ID_MASTER && window->object.identity != caller && fusion_object_check_owner( &window->object, caller, false )) { dfb_window_unref( window ); return DFB_ACCESSDENIED; } *ret_window = window; return DFB_OK; } DFBResult ILayerContext_Real__SetRotation( CoreLayerContext *obj, s32 rotation ) { D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_context_set_rotation( obj, rotation ); } typedef struct { unsigned long resource_id; CoreWindow *window; } FindWindowByResourceID_Context; static DFBEnumerationResult FindWindowByResourceID_WindowCallback( CoreWindow *window, void *_ctx ) { FindWindowByResourceID_Context *ctx = _ctx; if (window->surface) { if (window->surface->resource_id == ctx->resource_id) { ctx->window = window; return DFENUM_CANCEL; } } return DFENUM_OK; } DFBResult ILayerContext_Real__FindWindowByResourceID( CoreLayerContext *obj, u64 resource_id, CoreWindow **ret_window ) { DFBResult ret; CoreLayerContext *context = obj; CoreWindowStack *stack; FindWindowByResourceID_Context ctx; D_DEBUG_AT( DirectFB_CoreLayerContext, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( context->stack != NULL ); D_ASSERT( ret_window != NULL ); ret = dfb_layer_context_lock( context ); if (ret) return ret; stack = context->stack; ctx.resource_id = resource_id; ctx.window = NULL; ret = dfb_wm_enum_windows( stack, FindWindowByResourceID_WindowCallback, &ctx ); if (ret == DFB_OK) { if (ctx.window) { ret = dfb_window_ref( ctx.window ); if (ret == DFB_OK) *ret_window = ctx.window; } else ret = DFB_IDNOTFOUND; } dfb_layer_context_unlock( context ); return ret; } ================================================ FILE: src/core/CoreLayerRegion.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ILayerRegion version 1.0 object CoreLayerRegion method { name GetSurface arg { name surface direction output type object typename CoreSurface } } method { name FlipUpdate2 arg { name left_update direction input type struct typename DFBRegion optional yes } arg { name right_update direction input type struct typename DFBRegion optional yes } arg { name flags direction input type enum typename DFBSurfaceFlipFlags } arg { name flip_count direction input type int typename u32 } arg { name pts direction input type int typename s64 } } method { name SetSurface arg { name surface direction input type object typename CoreSurface } } } ================================================ FILE: src/core/CoreLayerRegion_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreLayerRegion_Call( CoreLayerRegion *region, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( ®ion->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreLayerRegion_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( DirectFB_CoreLayerRegion, "DirectFB/CoreLayerRegion", "DirectFB CoreLayerRegion" ); /**********************************************************************************************************************/ DFBResult ILayerRegion_Real__GetSurface( CoreLayerRegion *obj, CoreSurface **ret_surface ) { D_DEBUG_AT( DirectFB_CoreLayerRegion, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_region_get_surface( obj, ret_surface ); } DFBResult ILayerRegion_Real__FlipUpdate2( CoreLayerRegion *obj, const DFBRegion *left_update, const DFBRegion *right_update, DFBSurfaceFlipFlags flags, u32 flip_count, s64 pts ) { D_DEBUG_AT( DirectFB_CoreLayerRegion, "%s( %p, flags 0x%08x, flip_count %u, pts %lld )\n", __FUNCTION__, obj, flags, flip_count, (long long) pts ); return dfb_layer_region_flip_update2( obj, left_update, right_update, flags, flip_count, pts ); } DFBResult ILayerRegion_Real__SetSurface( CoreLayerRegion *obj, CoreSurface *surface ) { D_DEBUG_AT( DirectFB_CoreLayerRegion, "%s( %p, surface %p )\n", __FUNCTION__, obj, surface ); D_ASSERT( surface != NULL ); dfb_layer_region_set_surface( obj, surface, true ); return DFB_OK; } ================================================ FILE: src/core/CoreLayer_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include static __inline__ DirectResult CoreLayer_Call( CoreLayer *layer, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); return fusion_call_execute3( &layer->shared->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreLayer_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( DirectFB_CoreLayer, "DirectFB/CoreLayer", "DirectFB CoreLayer" ); /**********************************************************************************************************************/ DFBResult ILayer_Real__CreateContext( CoreLayer *obj, CoreLayerContext **ret_context ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_context != NULL ); return dfb_layer_create_context( obj, false, ret_context ); } DFBResult ILayer_Real__GetPrimaryContext( CoreLayer *obj, DFBBoolean activate, CoreLayerContext **ret_context ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_context != NULL ); return dfb_layer_get_primary_context( obj, activate, ret_context ); } DFBResult ILayer_Real__ActivateContext( CoreLayer *obj, CoreLayerContext *context ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( context != NULL ); return dfb_layer_activate_context( obj, context ); } DFBResult ILayer_Real__GetCurrentOutputField( CoreLayer *obj, s32 *ret_field ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_field != NULL ); return dfb_layer_get_current_output_field( obj, ret_field ); } DFBResult ILayer_Real__SetLevel( CoreLayer *obj, s32 level ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_set_level( obj, level ); } DFBResult ILayer_Real__WaitVSync( CoreLayer *obj ) { D_DEBUG_AT( DirectFB_CoreLayer, "%s( %p )\n", __FUNCTION__, obj ); return dfb_layer_wait_vsync( obj ); } ================================================ FILE: src/core/CorePalette.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IPalette version 1.0 object CorePalette method { name SetEntries arg { name colors direction input type struct typename DFBColor count num } arg { name num direction input type int typename u32 } arg { name offset direction input type int typename u32 } } method { name SetEntriesYUV arg { name colors direction input type struct typename DFBColorYUV count num } arg { name num direction input type int typename u32 } arg { name offset direction input type int typename u32 } } } ================================================ FILE: src/core/CorePalette_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CorePalette_Call( CorePalette *palette, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &palette->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CorePalette_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( DirectFB_CorePalette, "DirectFB/CorePalette", "DirectFB CorePalette" ); /**********************************************************************************************************************/ DFBResult IPalette_Real__SetEntries( CorePalette *obj, const DFBColor *colors, u32 num, u32 offset ) { D_DEBUG_AT( DirectFB_CorePalette, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( colors != NULL ); if (offset + num > obj->num_entries) return DFB_INVARG; if (num) { u32 i; direct_memcpy( obj->entries + offset, colors, num * sizeof(DFBColor) ); for (i = offset; i < offset + num; i++) { obj->entries_yuv[i].a = obj->entries[i].a; if (obj->colorspace == DSCS_BT601) RGB_TO_YCBCR_BT601( obj->entries[i].r, obj->entries[i].g, obj->entries[i].b, obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v ); else if (obj->colorspace == DSCS_RGB || obj->colorspace == DSCS_BT709) RGB_TO_YCBCR_BT709( obj->entries[i].r, obj->entries[i].g, obj->entries[i].b, obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v ); else if (obj->colorspace == DSCS_BT2020) RGB_TO_YCBCR_BT2020( obj->entries[i].r, obj->entries[i].g, obj->entries[i].b, obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v ); else { obj->entries_yuv[i].y = 16; obj->entries_yuv[i].u = obj->entries_yuv[i].v = 128; } } dfb_palette_update( obj, offset, offset + num - 1 ); } return DFB_OK; } DFBResult IPalette_Real__SetEntriesYUV( CorePalette *obj, const DFBColorYUV *colors, u32 num, u32 offset ) { D_DEBUG_AT( DirectFB_CorePalette, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( colors != NULL ); if (offset + num > obj->num_entries) return DFB_INVARG; if (num) { u32 i; direct_memcpy( obj->entries_yuv + offset, colors, num * sizeof(DFBColorYUV) ); for (i = offset; i < offset + num; i++) { obj->entries[i].a = obj->entries_yuv[i].a; if (obj->colorspace == DSCS_BT601) YCBCR_TO_RGB_BT601( obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v, obj->entries[i].r, obj->entries[i].g, obj->entries[i].b ); else if (obj->colorspace == DSCS_RGB || obj->colorspace == DSCS_BT709) YCBCR_TO_RGB_BT709( obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v, obj->entries[i].r, obj->entries[i].g, obj->entries[i].b ); else if (obj->colorspace == DSCS_BT2020) YCBCR_TO_RGB_BT2020( obj->entries_yuv[i].y, obj->entries_yuv[i].u, obj->entries_yuv[i].v, obj->entries[i].r, obj->entries[i].g, obj->entries[i].b ); else { obj->entries[i].r = obj->entries[i].g = obj->entries[i].b = 0; } } dfb_palette_update( obj, offset, offset + num - 1 ); } return DFB_OK; } ================================================ FILE: src/core/CoreScreen.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IScreen version 1.0 object CoreScreen method { name GetScreenSize arg { name size direction output type struct typename DFBDimension } } method { name SetPowerMode arg { name mode direction input type enum typename DFBScreenPowerMode } } method { name WaitVSync } method { name TestMixerConfig arg { name mixer direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenMixerConfig } arg { name failed direction output optional yes type enum typename DFBScreenMixerConfigFlags } } method { name SetMixerConfig arg { name mixer direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenMixerConfig } } method { name TestEncoderConfig arg { name encoder direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenEncoderConfig } arg { name failed direction output optional yes type enum typename DFBScreenEncoderConfigFlags } } method { name SetEncoderConfig arg { name encoder direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenEncoderConfig } } method { name TestOutputConfig arg { name output direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenOutputConfig } arg { name failed direction output optional yes type enum typename DFBScreenOutputConfigFlags } } method { name SetOutputConfig arg { name output direction input type int typename u32 } arg { name config direction input type struct typename DFBScreenOutputConfig } } method { name GetVSyncCount arg { name count direction output type int typename u64 } } } ================================================ FILE: src/core/CoreScreen_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include static __inline__ DirectResult CoreScreen_Call( CoreScreen *screen, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); return fusion_call_execute3( &screen->shared->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreScreen_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( DirectFB_CoreScreen, "DirectFB/CoreScreen", "DirectFB CoreScreen" ); /**********************************************************************************************************************/ DFBResult IScreen_Real__GetScreenSize( CoreScreen *obj, DFBDimension *ret_size ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_size != NULL ); return dfb_screen_get_screen_size( obj, &ret_size->w, &ret_size->h ); } DFBResult IScreen_Real__SetPowerMode( CoreScreen *obj, DFBScreenPowerMode mode ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); return dfb_screen_set_powermode( obj, mode ); } DFBResult IScreen_Real__WaitVSync( CoreScreen *obj ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); return dfb_screen_wait_vsync( obj ); } DFBResult IScreen_Real__TestMixerConfig( CoreScreen *obj, u32 mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_test_mixer_config( obj, mixer, config, ret_failed ); } DFBResult IScreen_Real__SetMixerConfig( CoreScreen *obj, u32 mixer, const DFBScreenMixerConfig *config ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_set_mixer_config( obj, mixer, config ); } DFBResult IScreen_Real__TestEncoderConfig( CoreScreen *obj, u32 encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_test_encoder_config( obj, encoder, config, ret_failed ); } DFBResult IScreen_Real__SetEncoderConfig( CoreScreen *obj, u32 encoder, const DFBScreenEncoderConfig *config ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_set_encoder_config( obj, encoder, config ); } DFBResult IScreen_Real__TestOutputConfig( CoreScreen *obj, u32 output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_test_output_config( obj, output, config, ret_failed ); } DFBResult IScreen_Real__SetOutputConfig( CoreScreen *obj, u32 output, const DFBScreenOutputConfig *config ) { D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_screen_set_output_config( obj, output, config ); } DFBResult IScreen_Real__GetVSyncCount( CoreScreen *obj, u64 *ret_count ) { DFBResult ret; unsigned long count; D_DEBUG_AT( DirectFB_CoreScreen, "%s( %p )\n", __FUNCTION__, obj ); ret = dfb_screen_get_vsync_count( obj, &count ); if (ret) return ret; *ret_count = count; return DFB_OK; } ================================================ FILE: src/core/CoreSlave.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ICoreSlave version 1.0 object CoreSlave dispatch CoreDFB method { name GetData arg { name address direction input type int typename "void*" } arg { name bytes direction input type int typename u32 } arg { name data direction output type int typename u8 count bytes max bytes } } method { name PutData arg { name address direction input type int typename "void*" } arg { name bytes direction input type int typename u32 } arg { name data direction input type int typename u8 count bytes } } } ================================================ FILE: src/core/CoreSlave_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORESLAVE_INCLUDES_H__ #define __CORE__CORESLAVE_INCLUDES_H__ #include #include typedef struct { FusionCall call; } CoreSlave; static __inline__ DirectResult CoreSlave_Call( CoreSlave *slave, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &slave->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } #endif ================================================ FILE: src/core/CoreSlave_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreSlave, "DirectFB/CoreSlave", "DirectFB Core Slave" ); /**********************************************************************************************************************/ DFBResult ICoreSlave_Real__GetData( CoreDFB *obj, void *address, u32 bytes, u8 *ret_data ) { DFBResult ret; D_DEBUG_AT( DirectFB_CoreSlave, "%s( %p, address %p, bytes %u ) from %lu\n", __FUNCTION__, obj, address, bytes, Core_GetIdentity() ); ret = dfb_core_memory_permissions_check( core_dfb, CMPF_READ, address, bytes ); if (ret) return ret; direct_memcpy( ret_data, address, bytes ); return DFB_OK; } DFBResult ICoreSlave_Real__PutData( CoreDFB *obj, void *address, u32 bytes, const u8 *data ) { DFBResult ret; D_DEBUG_AT( DirectFB_CoreSlave, "%s( %p, address %p, bytes %u ) from %lu\n", __FUNCTION__, obj, address, bytes, Core_GetIdentity() ); ret = dfb_core_memory_permissions_check( core_dfb, CMPF_WRITE, address, bytes ); if (ret) return ret; direct_memcpy( address, data, bytes ); return DFB_OK; } ================================================ FILE: src/core/CoreSurface.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ISurface version 1.0 object CoreSurface method { name SetConfig arg { name config direction input type struct typename CoreSurfaceConfig } } method { name GetPalette arg { name palette direction output type object typename CorePalette } } method { name SetPalette arg { name palette direction input type object typename CorePalette } } method { name SetAlphaRamp arg { name a0 direction input type int typename u8 } arg { name a1 direction input type int typename u8 } arg { name a2 direction input type int typename u8 } arg { name a3 direction input type int typename u8 } } method { name PreLockBuffer arg { name buffer direction input type object typename CoreSurfaceBuffer } arg { name accessor direction input type enum typename CoreSurfaceAccessorID } arg { name access direction input type enum typename CoreSurfaceAccessFlags } arg { name allocation direction output type object typename CoreSurfaceAllocation } } method { name PreLockBuffer2 arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name eye direction input type enum typename DFBSurfaceStereoEye } arg { name accessor direction input type enum typename CoreSurfaceAccessorID } arg { name access direction input type enum typename CoreSurfaceAccessFlags } arg { name lock direction input type enum typename DFBBoolean } arg { name allocation direction output type object typename CoreSurfaceAllocation } } method { name PreLockBuffer3 arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name flip_count direction input type int typename u32 } arg { name eye direction input type enum typename DFBSurfaceStereoEye } arg { name accessor direction input type enum typename CoreSurfaceAccessorID } arg { name access direction input type enum typename CoreSurfaceAccessFlags } arg { name lock direction input type enum typename DFBBoolean } arg { name allocation direction output type object typename CoreSurfaceAllocation } } method { name DispatchUpdate async yes arg { name swap direction input type enum typename DFBBoolean } arg { name left direction input type struct typename DFBRegion optional yes } arg { name right direction input type struct typename DFBRegion optional yes } arg { name flags direction input type enum typename DFBSurfaceFlipFlags } arg { name timestamp direction input type int typename s64 } arg { name flip_count direction input type int typename u32 } } method { name Flip2 arg { name swap direction input type enum typename DFBBoolean } arg { name left direction input type struct typename DFBRegion optional yes } arg { name right direction input type struct typename DFBRegion optional yes } arg { name flags direction input type enum typename DFBSurfaceFlipFlags } arg { name timestamp direction input type int typename s64 } } method { name SetField arg { name field direction input type int typename s32 } } method { name CreateClient arg { name client direction output type object typename CoreSurfaceClient } } method { name Allocate arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name eye direction input type enum typename DFBSurfaceStereoEye } arg { name key direction input type int typename char count key_len } arg { name key_len direction input type int typename u32 } arg { name handle direction input type int typename u64 } arg { name allocation direction output type object typename CoreSurfaceAllocation } } method { name GetAllocation arg { name role direction input type enum typename DFBSurfaceBufferRole } arg { name eye direction input type enum typename DFBSurfaceStereoEye } arg { name key direction input type int typename char count key_len } arg { name key_len direction input type int typename u32 } arg { name allocation direction output type object typename CoreSurfaceAllocation } } } ================================================ FILE: src/core/CoreSurfaceAllocation.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ISurfaceAllocation version 1.0 object CoreSurfaceAllocation method { name Updated async yes arg { name updates direction input type struct typename DFBBox optional yes count num_updates } arg { name num_updates direction input type int typename u32 } } } ================================================ FILE: src/core/CoreSurfaceAllocation_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreSurfaceAllocation_Call( CoreSurfaceAllocation *allocation, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &allocation->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreSurfaceAllocation_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreSurfaceAllocation, "DirectFB/CoreSurfaceAllocation", "DirectFB CoreSurfaceAllocation" ); /**********************************************************************************************************************/ DFBResult ISurfaceAllocation_Real__Updated( CoreSurfaceAllocation *obj, const DFBBox *updates, u32 num_updates ) { DFBResult ret; CoreSurfaceBuffer *buffer; D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, "%s( %p, updates %p, num %u )\n", __FUNCTION__, obj, updates, num_updates ); ret = fusion_object_get( core_dfb->shared->surface_buffer_pool, obj->buffer_id, (FusionObject**) &buffer ); if (ret && ret != DFB_DEAD) return ret; if (ret == DFB_DEAD) { D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " -> dead object!\n" ); } else { CoreSurface *surface; ret = fusion_object_get( core_dfb->shared->surface_pool, buffer->surface_id, (FusionObject**) &surface ); if (ret && ret != DFB_DEAD) { dfb_surface_buffer_unref( buffer ); return ret; } if (ret == DFB_DEAD) { D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " -> dead object!\n" ); } else { dfb_surface_lock( surface ); if (obj->buffer) { D_ASSERT( obj->buffer == buffer ); D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " <- buffer %p\n", buffer ); D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " <- written %p\n", buffer->written ); D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " <- read %p\n", buffer->read ); D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " <- serial %lu (this %lu)\n", buffer->serial.value, obj->serial.value ); direct_serial_increase( &buffer->serial ); direct_serial_copy( &obj->serial, &buffer->serial ); buffer->written = obj; buffer->read = NULL; D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " -> serial %lu\n", buffer->serial.value ); } else { D_DEBUG_AT( DirectFB_CoreSurfaceAllocation, " -> already decoupled!\n" ); } dfb_surface_unlock( surface ); dfb_surface_unref( surface ); } dfb_surface_buffer_unref( buffer ); } return DFB_OK; } ================================================ FILE: src/core/CoreSurfaceClient.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name ISurfaceClient version 1.0 object CoreSurfaceClient method { name FrameAck async yes arg { name flip_count direction input type int typename u32 } } } ================================================ FILE: src/core/CoreSurfaceClient_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreSurfaceClient_Call( CoreSurfaceClient *client, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &client->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreSurfaceClient_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreSurfaceClient, "DirectFB/CoreSurfaceClient", "DirectFB CoreSurfaceClient" ); /**********************************************************************************************************************/ DFBResult ISurfaceClient_Real__FrameAck( CoreSurfaceClient *obj, u32 flip_count ) { CoreSurface *surface; D_DEBUG_AT( DirectFB_CoreSurfaceClient, "%s( %p, count %u ) <- old count %u\n", __FUNCTION__, obj, flip_count, obj->flip_count ); D_MAGIC_ASSERT( obj->surface, CoreSurface ); surface = obj->surface; D_DEBUG_AT( DirectFB_CoreSurfaceClient, " -> surface %p (id %u)\n", surface, surface->object.id ); dfb_surface_lock( surface ); obj->flip_count = flip_count; dfb_surface_check_acks( surface ); dfb_surface_unlock( surface ); return DFB_OK; } ================================================ FILE: src/core/CoreSurface_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreSurface_Call( CoreSurface *surface, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &surface->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreSurface_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreSurface, "DirectFB/CoreSurface", "DirectFB CoreSurface" ); /**********************************************************************************************************************/ DFBResult ISurface_Real__SetConfig( CoreSurface *obj, const CoreSurfaceConfig *config ) { D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( config != NULL ); return dfb_surface_reconfig( obj, config ); } DFBResult ISurface_Real__GetPalette( CoreSurface *obj, CorePalette **ret_palette ) { DFBResult ret; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_palette != NULL ); if (!obj->palette) return DFB_UNSUPPORTED; ret = dfb_palette_ref( obj->palette ); if (ret) return ret; *ret_palette = obj->palette; return DFB_OK; } DFBResult ISurface_Real__SetPalette( CoreSurface *obj, CorePalette *palette ) { D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( palette != NULL ); return dfb_surface_set_palette( obj, palette ); } DFBResult ISurface_Real__SetAlphaRamp( CoreSurface *obj, u8 a0, u8 a1, u8 a2, u8 a3 ) { D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); return dfb_surface_set_alpha_ramp( obj, a0, a1, a2, a3 ); } static void manage_interlocks( CoreSurfaceAllocation *allocation, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ) { int locks; locks = dfb_surface_allocation_locks( allocation ); /* Software read/write access. */ if (accessor != CSAID_GPU) { /* If hardware has written or is writing. */ if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { /* Wait for the operation to finish. */ dfb_gfxcard_wait_serial( &allocation->gfx_serial ); /* Software read access after hardware write requires flush of the (bus) read cache. */ dfb_gfxcard_flush_read_cache(); if (!locks) { /* Clear hardware write access. */ allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; /* Clear hardware read access (to avoid syncing twice). */ allocation->accessed[CSAID_GPU] &= ~CSAF_READ; } } /* Software write access. */ if (access & CSAF_WRITE) { /* If hardware has (to) read... */ if (allocation->accessed[CSAID_GPU] & CSAF_READ) { /* Wait for the operation to finish. */ dfb_gfxcard_wait_serial( &allocation->gfx_serial ); /* Clear hardware read access. */ if (!locks) allocation->accessed[CSAID_GPU] &= ~CSAF_READ; } } } /* Hardware read or write access. */ if (accessor == CSAID_GPU && access & (CSAF_READ | CSAF_WRITE)) { /* If software has read or written before. */ if (allocation->accessed[CSAID_CPU] & (CSAF_READ | CSAF_WRITE)) { /* Flush texture cache. */ dfb_gfxcard_flush_texture_cache(); /* Clear software read and write access. */ if (!locks) allocation->accessed[CSAID_CPU] &= ~(CSAF_READ | CSAF_WRITE); } } allocation->accessed[accessor] |= access; } DFBResult ISurface_Real__PreLockBuffer( CoreSurface *obj, CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurfaceAllocation *allocation; bool allocated = false; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); dfb_surface_lock( obj ); if (obj->state & CSSF_DESTROYED) { dfb_surface_unlock( obj ); return DFB_DESTROYED; } if (!buffer->surface) { dfb_surface_unlock( obj ); return DFB_BUFFEREMPTY; } /* Look for allocation with proper access. */ allocation = dfb_surface_buffer_find_allocation( buffer, accessor, access, true ); if (!allocation) { /* If no allocation exists, create one. */ ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation ); if (ret) { if (ret != DFB_NOVIDEOMEMORY && ret != DFB_UNSUPPORTED) D_DERROR( ret, "DirectFB/CoreSurface: Buffer allocation failed!\n" ); goto out; } allocated = true; } CORE_SURFACE_ALLOCATION_ASSERT( allocation ); /* Synchronize with other allocations. */ ret = dfb_surface_allocation_update( allocation, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } ret = dfb_surface_pool_prelock( allocation->pool, allocation, accessor, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } manage_interlocks( allocation, accessor, access ); dfb_surface_allocation_ref( allocation ); *ret_allocation = allocation; out: dfb_surface_unlock( obj ); return ret; } DFBResult ISurface_Real__PreLockBuffer2( CoreSurface *obj, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, DFBBoolean lock, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *allocation; bool allocated = false; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, role %u, eye %u, accessor 0x%02x, access 0x%02x, %slock )\n", __FUNCTION__, obj, role, eye, accessor, access, lock ? "" : "no " ); ret = dfb_surface_lock( obj ); if (ret) return ret; if (obj->state & CSSF_DESTROYED) { dfb_surface_unlock( obj ); return DFB_DESTROYED; } if (obj->num_buffers < 1) { dfb_surface_unlock( obj ); return DFB_BUFFEREMPTY; } buffer = dfb_surface_get_buffer2( obj, role, eye ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( DirectFB_CoreSurface, " -> buffer %p\n", buffer ); if (!lock && access & CSAF_READ) { if (fusion_vector_is_empty( &buffer->allocs )) { dfb_surface_unlock( obj ); return DFB_NOALLOCATION; } } /* Look for allocation with proper access. */ allocation = dfb_surface_buffer_find_allocation( buffer, accessor, access, lock ); if (!allocation) { /* If no allocation exists, create one. */ ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation ); if (ret) { if (ret != DFB_NOVIDEOMEMORY && ret != DFB_UNSUPPORTED) D_DERROR( ret, "DirectFB/CoreSurface: Buffer allocation failed!\n" ); goto out; } allocated = true; } CORE_SURFACE_ALLOCATION_ASSERT( allocation ); /* Synchronize with other allocations. */ ret = dfb_surface_allocation_update( allocation, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } if (!lock) { if (access & CSAF_WRITE) { if (!(allocation->pool->desc.caps & CSPCAPS_WRITE)) lock = DFB_TRUE; } else if (access & CSAF_READ) { if (!(allocation->pool->desc.caps & CSPCAPS_READ)) lock = DFB_TRUE; } } if (lock) { ret = dfb_surface_pool_prelock( allocation->pool, allocation, accessor, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } manage_interlocks( allocation, accessor, access ); } dfb_surface_allocation_ref( allocation ); *ret_allocation = allocation; out: dfb_surface_unlock( obj ); return ret; } DFBResult ISurface_Real__PreLockBuffer3( CoreSurface *obj, DFBSurfaceBufferRole role, u32 flip_count, DFBSurfaceStereoEye eye, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, DFBBoolean lock, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *allocation; bool allocated = false; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, role %u, count %u, eye %u, accessor 0x%02x, access 0x%02x, %slock )\n", __FUNCTION__, obj, role, flip_count, eye, accessor, access, lock ? "" : "no " ); ret = dfb_surface_lock( obj ); if (ret) return ret; if (obj->num_buffers < 1) { dfb_surface_unlock( obj ); return DFB_BUFFEREMPTY; } buffer = dfb_surface_get_buffer3( obj, role, eye, flip_count ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( DirectFB_CoreSurface, " -> buffer %p\n", buffer ); if (!lock && access & CSAF_READ) { if (fusion_vector_is_empty( &buffer->allocs )) { dfb_surface_unlock( obj ); return DFB_NOALLOCATION; } } /* Look for allocation with proper access. */ allocation = dfb_surface_buffer_find_allocation( buffer, accessor, access, lock ); if (!allocation) { /* If no allocation exists, create one. */ ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation ); if (ret) { if (ret != DFB_NOVIDEOMEMORY && ret != DFB_UNSUPPORTED) D_DERROR( ret, "DirectFB/CoreSurface: Buffer allocation failed!\n" ); goto out; } allocated = true; } CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_DEBUG_AT( DirectFB_CoreSurface, " -> allocation %p\n", allocation ); /* Synchronize with other allocations. */ ret = dfb_surface_allocation_update( allocation, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } if (!lock) { if (access & CSAF_WRITE) { if (!(allocation->pool->desc.caps & CSPCAPS_WRITE)) lock = DFB_TRUE; } else if (access & CSAF_READ) { if (!(allocation->pool->desc.caps & CSPCAPS_READ)) lock = DFB_TRUE; } } if (lock) { ret = dfb_surface_pool_prelock( allocation->pool, allocation, accessor, access ); if (ret) { /* Destroy if newly created. */ if (allocated) dfb_surface_allocation_decouple( allocation ); goto out; } manage_interlocks( allocation, accessor, access ); } dfb_surface_allocation_ref( allocation ); *ret_allocation = allocation; out: dfb_surface_unlock( obj ); return ret; } DFBResult ISurface_Real__DispatchUpdate( CoreSurface *obj, DFBBoolean swap, const DFBRegion *left, const DFBRegion *right, DFBSurfaceFlipFlags flags, s64 timestamp, u32 flip_count ) { DFBRegion l, r; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, timestamp %lld, flip_count %u )\n", __FUNCTION__, obj, (long long) timestamp, flip_count ); dfb_surface_lock( obj ); if (left) l = *left; else { l.x1 = 0; l.y1 = 0; l.x2 = obj->config.size.w - 1; l.y2 = obj->config.size.h - 1; } if (right) r = *right; else r = l; if (!(flags & DSFLIP_UPDATE)) obj->flips = flip_count; dfb_surface_dispatch_update( obj, &l, &r, timestamp, flags ); dfb_surface_unlock( obj ); return DFB_OK; } DFBResult ISurface_Real__Flip2( CoreSurface *obj, DFBBoolean swap, const DFBRegion *left, const DFBRegion *right, DFBSurfaceFlipFlags flags, s64 timestamp ) { DFBResult ret; DFBRegion l, r; D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, timestamp %lld )\n", __FUNCTION__, obj, (long long) timestamp ); dfb_surface_lock( obj ); if (left) l = *left; else { l.x1 = 0; l.y1 = 0; l.x2 = obj->config.size.w - 1; l.y2 = obj->config.size.h - 1; } if (right) r = *right; else r = l; if (obj->config.caps & DSCAPS_FLIPPING) { if (obj->config.caps & DSCAPS_STEREO) { if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && l.x1 == 0 && l.y1 == 0 && l.x2 == obj->config.size.w - 1 && l.y2 == obj->config.size.h - 1 && r.x1 == 0 && r.y1 == 0 && r.x2 == obj->config.size.w - 1 && r.y2 == obj->config.size.h - 1)) { ret = dfb_surface_flip_buffers( obj, swap ); if (ret) goto out; } else { if (left) dfb_gfx_copy_regions_client( obj, DSBR_BACK, DSSE_LEFT, obj, DSBR_FRONT, DSSE_LEFT, &l, 1, 0, 0, NULL ); if (right) dfb_gfx_copy_regions_client( obj, DSBR_BACK, DSSE_RIGHT, obj, DSBR_FRONT, DSSE_RIGHT, &r, 1, 0, 0, NULL ); } } else { if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && l.x1 == 0 && l.y1 == 0 && l.x2 == obj->config.size.w - 1 && l.y2 == obj->config.size.h - 1)) { ret = dfb_surface_flip_buffers( obj, swap ); if (ret) goto out; } else { dfb_gfx_copy_regions_client( obj, DSBR_BACK, DSSE_LEFT, obj, DSBR_FRONT, DSSE_LEFT, &l, 1, 0, 0, NULL ); } } } dfb_surface_dispatch_update( obj, &l, &r, timestamp, flags ); ret = DFB_OK; out: dfb_surface_unlock( obj ); return ret; } DFBResult ISurface_Real__SetField( CoreSurface *obj, s32 field ) { D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); return dfb_surface_set_field( obj, field ); } DFBResult ISurface_Real__CreateClient( CoreSurface *obj, CoreSurfaceClient **ret_client ) { D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p )\n", __FUNCTION__, obj ); D_ASSERT( ret_client != NULL ); return dfb_surface_client_create( core_dfb, obj, ret_client ); } DFBResult ISurface_Real__Allocate( CoreSurface *obj, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, u32 key_len, u64 handle, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *allocation; D_ASSERT( key != NULL ); D_ASSERT( key_len > 0 ); D_ASSERT( key[key_len-1] == 0 ); D_ASSERT( ret_allocation != NULL ); D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, role %u, eye %u, key '%s', handle 0x%08llx )\n", __FUNCTION__, obj, role, eye, key, (unsigned long long) handle ); ret = dfb_surface_lock( obj ); if (ret) return ret; if (obj->num_buffers == 0) { ret = DFB_NOBUFFER; goto out; } buffer = dfb_surface_get_buffer3( obj, role, eye, obj->flips ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); ret = dfb_surface_pools_allocate_key( buffer, key, handle, &allocation ); if (ret) goto out; CORE_SURFACE_ALLOCATION_ASSERT( allocation ); dfb_surface_allocation_update( allocation, CSAF_WRITE ); ret = dfb_surface_allocation_ref( allocation ); if (ret) goto out; *ret_allocation = allocation; out: dfb_surface_unlock( obj ); return ret; } DFBResult ISurface_Real__GetAllocation( CoreSurface *obj, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, u32 key_len, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *allocation; D_ASSERT( key != NULL ); D_ASSERT( key_len > 0 ); D_ASSERT( key[key_len-1] == 0 ); D_ASSERT( ret_allocation != NULL ); D_DEBUG_AT( DirectFB_CoreSurface, "%s( %p, role %u, eye %u, key '%s' )\n", __FUNCTION__, obj, role, eye, key ); if (eye != DSSE_LEFT && eye != DSSE_RIGHT) return DFB_INVARG; ret = dfb_surface_lock( obj ); if (ret) return ret; if (obj->num_buffers == 0) { ret = DFB_NOBUFFER; goto out; } if (role > obj->num_buffers - 1) { ret = DFB_LIMITEXCEEDED; goto out; } if (eye == DSSE_RIGHT && !(obj->config.caps & DSCAPS_STEREO)) { ret = DFB_INVAREA; goto out; } buffer = dfb_surface_get_buffer3( obj, role, eye, obj->flips ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); allocation = dfb_surface_buffer_find_allocation_key( buffer, key ); if (!allocation) { ret = DFB_ITEMNOTFOUND; goto out; } CORE_SURFACE_ALLOCATION_ASSERT( allocation ); dfb_surface_allocation_update( allocation, CSAF_WRITE ); ret = dfb_surface_allocation_ref( allocation ); if (ret) goto out; *ret_allocation = allocation; out: dfb_surface_unlock( obj ); return ret; } ================================================ FILE: src/core/CoreWindow.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IWindow version 1.0 object CoreWindow method { name SetConfig arg { name config direction input type struct typename CoreWindowConfig } arg { name keys direction input type enum typename DFBInputDeviceKeySymbol count num_keys optional yes } arg { name num_keys direction input type int typename u32 } arg { name flags direction input type enum typename DFBWindowConfigFlags } } method { name GetInsets arg { name insets direction output type struct typename DFBInsets } } method { name Destroy } method { name ChangeEvents arg { name disable direction input type enum typename DFBWindowEventType } arg { name enable direction input type enum typename DFBWindowEventType } } method { name ChangeOptions arg { name disable direction input type enum typename DFBWindowOptions } arg { name enable direction input type enum typename DFBWindowOptions } } method { name SetColor arg { name color direction input type struct typename DFBColor } } method { name SetColorKey arg { name key direction input type int typename u32 } } method { name SetOpacity arg { name opacity direction input type int typename u8 } } method { name SetOpaque arg { name opaque direction input type struct typename DFBRegion } } method { name SetCursorShape arg { name shape direction input type object typename CoreSurface optional yes } arg { name hotspot direction input type struct typename DFBPoint } } method { name Move arg { name dx direction input type int typename s32 } arg { name dy direction input type int typename s32 } } method { name MoveTo arg { name x direction input type int typename s32 } arg { name y direction input type int typename s32 } } method { name Resize arg { name width direction input type int typename s32 } arg { name height direction input type int typename s32 } } method { name SetBounds arg { name bounds direction input type struct typename DFBRectangle } } method { name SetStacking arg { name stacking direction input type enum typename DFBWindowStackingClass } } method { name Restack arg { name relative direction input type object typename CoreWindow optional yes } arg { name relation direction input type int typename s32 } } method { name Bind arg { name source direction input type object typename CoreWindow } arg { name x direction input type int typename s32 } arg { name y direction input type int typename s32 } } method { name Unbind arg { name source direction input type object typename CoreWindow } } method { name RequestFocus } method { name ChangeGrab arg { name target direction input type enum typename CoreWMGrabTarget } arg { name grab direction input type enum typename DFBBoolean } } method { name GrabKey arg { name symbol direction input type enum typename DFBInputDeviceKeySymbol } arg { name modifiers direction input type enum typename DFBInputDeviceModifierMask } } method { name UngrabKey arg { name symbol direction input type enum typename DFBInputDeviceKeySymbol } arg { name modifiers direction input type enum typename DFBInputDeviceModifierMask } } method { name SetKeySelection arg { name selection direction input type enum typename DFBWindowKeySelection } arg { name keys direction input type enum typename DFBInputDeviceKeySymbol count num_keys optional yes } arg { name num_keys direction input type int typename u32 } } method { name SetRotation arg { name rotation direction input type int typename s32 } } method { name BeginUpdates arg { name update direction input type struct typename DFBRegion optional yes } } method { name PostEvent arg { name event direction input type struct typename DFBWindowEvent } } method { name SetCursorPosition arg { name x direction input type int typename s32 } arg { name y direction input type int typename s32 } } method { name SetTypeHint arg { name type_hint direction input type enum typename DFBWindowTypeHint } } method { name ChangeHintFlags arg { name clear direction input type enum typename DFBWindowHintFlags } arg { name set direction input type enum typename DFBWindowHintFlags } } method { name AllowFocus } method { name GetSurface arg { name surface direction output type object typename CoreSurface } } } ================================================ FILE: src/core/CoreWindowStack.flux ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA interface { name IWindowStack version 1.0 object CoreWindowStack method { name RepaintAll } method { name BackgroundSetMode arg { name mode direction input type enum typename DFBDisplayLayerBackgroundMode } } method { name BackgroundSetImage arg { name image direction input type object typename CoreSurface } } method { name BackgroundSetColor arg { name color direction input type struct typename DFBColor } } method { name BackgroundSetColorIndex arg { name index direction input type int typename s32 } } method { name CursorEnable arg { name enable direction input type enum typename bool } } method { name CursorGetPosition arg { name position direction output type struct typename DFBPoint } } method { name CursorWarp arg { name position direction input type struct typename DFBPoint } } method { name CursorSetAcceleration arg { name numerator direction input type int typename u32 } arg { name denominator direction input type int typename u32 } arg { name threshold direction input type int typename u32 } } method { name CursorSetShape arg { name shape direction input type object typename CoreSurface } arg { name hotspot direction input type struct typename DFBPoint } } method { name CursorSetOpacity arg { name opacity direction input type int typename u8 } } } ================================================ FILE: src/core/CoreWindowStack_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreWindowStack_Call( CoreWindowStack *stack, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &stack->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreWindowStack_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( DirectFB_CoreWindowStack, "DirectFB/CoreWindowStack", "DirectFB CoreWindowStack" ); /**********************************************************************************************************************/ DFBResult IWindowStack_Real__RepaintAll( CoreWindowStack *obj ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_repaint_all( obj ); } DFBResult IWindowStack_Real__BackgroundSetMode( CoreWindowStack *obj, DFBDisplayLayerBackgroundMode mode ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_set_background_mode( obj, mode ); } DFBResult IWindowStack_Real__BackgroundSetImage( CoreWindowStack *obj, CoreSurface *image ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_set_background_image( obj, image ); } DFBResult IWindowStack_Real__BackgroundSetColor( CoreWindowStack *obj, const DFBColor *color ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_set_background_color( obj, color ); } DFBResult IWindowStack_Real__BackgroundSetColorIndex( CoreWindowStack *obj, s32 index ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_set_background_color_index( obj, index ); } DFBResult IWindowStack_Real__CursorEnable( CoreWindowStack *obj, bool enable ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_cursor_enable( obj, enable ); } DFBResult IWindowStack_Real__CursorGetPosition( CoreWindowStack *obj, DFBPoint *ret_position ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_get_cursor_position( obj, &ret_position->x, &ret_position->y ); } DFBResult IWindowStack_Real__CursorWarp( CoreWindowStack *obj, const DFBPoint *position ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_cursor_warp( obj, position->x, position->y ); } DFBResult IWindowStack_Real__CursorSetAcceleration( CoreWindowStack *obj, u32 numerator, u32 denominator, u32 threshold ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_cursor_set_acceleration( obj, numerator, denominator, threshold ); } DFBResult IWindowStack_Real__CursorSetShape( CoreWindowStack *obj, CoreSurface *shape, const DFBPoint *hotspot ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); dfb_layer_context_set_cursor_shape( obj->context, shape, hotspot->x, hotspot->y ); return dfb_windowstack_cursor_set_shape( obj, shape, hotspot->x, hotspot->y ); } DFBResult IWindowStack_Real__CursorSetOpacity( CoreWindowStack *obj, u8 opacity ) { D_DEBUG_AT( DirectFB_CoreWindowStack, "%s( %p )\n", __FUNCTION__, obj ); return dfb_windowstack_cursor_set_opacity( obj, opacity ); } ================================================ FILE: src/core/CoreWindow_includes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include static __inline__ DirectResult CoreWindow_Call( CoreWindow *window, FusionCallExecFlags flags, int call_arg, void *ptr, unsigned int length, void *ret_ptr, unsigned int ret_size, unsigned int *ret_length ) { return fusion_call_execute3( &window->call, dfb_config->call_nodirect | flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length ); } ================================================ FILE: src/core/CoreWindow_real.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Window, "DirectFB/CoreWindow", "DirectFB CoreWindow" ); /**********************************************************************************************************************/ DFBResult IWindow_Real__SetConfig( CoreWindow *obj, const CoreWindowConfig *config, const DFBInputDeviceKeySymbol *keys, u32 num_keys, DFBWindowConfigFlags flags ) { CoreWindowConfig config_copy; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); D_ASSERT( config != NULL ); if ((flags & DWCONF_ASSOCIATION) && config->association) { DFBResult ret; CoreWindow *parent; ret = dfb_core_get_window( core_dfb, config->association, &parent ); if (ret) return ret; if (fusion_object_check_owner( &parent->object, Core_GetIdentity(), false )) { dfb_window_unref( parent ); return DFB_ACCESSDENIED; } dfb_window_unref( parent ); } config_copy = *config; config_copy.keys = (DFBInputDeviceKeySymbol*) keys; config_copy.num_keys = num_keys; return dfb_window_set_config( obj, &config_copy, flags ); } DFBResult IWindow_Real__GetInsets( CoreWindow *obj, DFBInsets *ret_insets ) { DFBResult ret; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); ret = dfb_layer_context_lock( obj->stack->context ); if (ret) return ret; ret = dfb_wm_get_insets( obj->stack, obj, ret_insets ); dfb_layer_context_unlock( obj->stack->context ); return ret; } DFBResult IWindow_Real__Destroy( CoreWindow *obj ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); dfb_window_destroy( obj ); return DFB_OK; } DFBResult IWindow_Real__ChangeEvents( CoreWindow *obj, DFBWindowEventType disable, DFBWindowEventType enable ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_change_events( obj, disable, enable ); } DFBResult IWindow_Real__ChangeOptions( CoreWindow *obj, DFBWindowOptions disable, DFBWindowOptions enable ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_change_options( obj, disable, enable ); } DFBResult IWindow_Real__SetColor( CoreWindow *obj, const DFBColor *color ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_color( obj, *color ); } DFBResult IWindow_Real__SetColorKey( CoreWindow *obj, u32 key ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_colorkey( obj, key ); } DFBResult IWindow_Real__SetOpacity( CoreWindow *obj, u8 opacity ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_opacity( obj, opacity ); } DFBResult IWindow_Real__SetOpaque( CoreWindow *obj, const DFBRegion *opaque ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_opaque( obj, opaque ); } DFBResult IWindow_Real__SetCursorShape( CoreWindow *obj, CoreSurface *shape, const DFBPoint *hotspot ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_cursor_shape( obj, shape, hotspot->x, hotspot->y ); } DFBResult IWindow_Real__Move( CoreWindow *obj, s32 dx, s32 dy ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_move( obj, dx, dy, true ); } DFBResult IWindow_Real__MoveTo( CoreWindow *obj, s32 x, s32 y ) { DFBResult ret; DFBInsets insets; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); dfb_windowstack_lock( obj->stack ); dfb_wm_get_insets( obj->stack, obj, &insets ); ret = dfb_window_move( obj, x + insets.l, y + insets.t, false ); dfb_windowstack_unlock( obj->stack ); return ret; } DFBResult IWindow_Real__Resize( CoreWindow *obj, s32 width, s32 height ) { DFBResult ret; DFBInsets insets; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); dfb_windowstack_lock( obj->stack ); dfb_wm_get_insets( obj->stack, obj, &insets ); ret = dfb_window_resize( obj, width + insets.l+insets.r, height + insets.t+insets.b ); dfb_windowstack_unlock( obj->stack ); return ret; } DFBResult IWindow_Real__SetBounds( CoreWindow *obj, const DFBRectangle *bounds ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_bounds( obj, bounds->x, bounds->y, bounds->w, bounds->h ); } DFBResult IWindow_Real__SetStacking( CoreWindow *obj, DFBWindowStackingClass stacking ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_change_stacking( obj, stacking ); } DFBResult IWindow_Real__Restack( CoreWindow *obj, CoreWindow *relative, s32 relation ) { DFBResult ret; CoreWindowStack *stack; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); D_ASSERT( obj->stack != NULL ); stack = obj->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( obj )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( obj, relative, relation ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult IWindow_Real__Bind( CoreWindow *obj, CoreWindow *source, s32 x, s32 y ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); D_MAGIC_ASSERT( source, CoreWindow ); return dfb_window_bind( obj, source, x, y ); } DFBResult IWindow_Real__Unbind( CoreWindow *obj, CoreWindow *source ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); D_MAGIC_ASSERT( source, CoreWindow ); return dfb_window_unbind( obj, source ); } DFBResult IWindow_Real__RequestFocus( CoreWindow *obj ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_request_focus( obj ); } DFBResult IWindow_Real__ChangeGrab( CoreWindow *obj, CoreWMGrabTarget target, DFBBoolean grab ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_change_grab( obj, target, grab ); } DFBResult IWindow_Real__GrabKey( CoreWindow *obj, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_grab_key( obj, symbol, modifiers ); } DFBResult IWindow_Real__UngrabKey( CoreWindow *obj, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_ungrab_key( obj, symbol, modifiers ); } DFBResult IWindow_Real__SetKeySelection( CoreWindow *obj, DFBWindowKeySelection selection, const DFBInputDeviceKeySymbol *keys, u32 num_keys ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_key_selection( obj, selection, keys, num_keys ); } DFBResult IWindow_Real__SetRotation( CoreWindow *obj, s32 rotation ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_rotation( obj, rotation ); } DFBResult IWindow_Real__BeginUpdates( CoreWindow *obj, const DFBRegion *update ) { DFBResult ret; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); dfb_windowstack_lock( obj->stack ); ret = dfb_wm_begin_updates( obj, update ); dfb_windowstack_unlock( obj->stack ); return ret; } DFBResult IWindow_Real__PostEvent( CoreWindow *obj, const DFBWindowEvent *event ) { DFBWindowEvent e; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); e = *event; dfb_window_post_event( obj, &e ); return DFB_OK; } DFBResult IWindow_Real__SetCursorPosition( CoreWindow *obj, s32 x, s32 y ) { DFBResult ret; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); dfb_windowstack_lock( obj->stack ); ret = dfb_wm_set_cursor_position( obj, x, y ); dfb_windowstack_unlock( obj->stack ); return ret; } DFBResult IWindow_Real__SetTypeHint( CoreWindow *obj, DFBWindowTypeHint type_hint ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_set_type_hint( obj, type_hint ); } DFBResult IWindow_Real__ChangeHintFlags( CoreWindow *obj, DFBWindowHintFlags clear, DFBWindowHintFlags set ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); return dfb_window_change_hint_flags( obj, clear, set ); } DFBResult IWindow_Real__AllowFocus( CoreWindow *obj ) { D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); obj->caps = (DFBWindowCapabilities) ((obj->caps & ~DWCAPS_NOFOCUS) | (obj->requested_caps & DWCAPS_NOFOCUS)); return DFB_OK; } DFBResult IWindow_Real__GetSurface( CoreWindow *obj, CoreSurface **ret_surface ) { DFBResult ret; D_DEBUG_AT( Core_Window, "%s( %p )\n", __FUNCTION__, obj ); D_MAGIC_ASSERT( obj, CoreWindow ); D_ASSERT( ret_surface != NULL ); if (!obj->surface) return DFB_UNSUPPORTED; ret = dfb_surface_ref( obj->surface ); if (ret) return ret; *ret_surface = obj->surface; return DFB_OK; } ================================================ FILE: src/core/clipboard.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Clipboard, "Core/Clipboard", "DirectFB Core Clipboard" ); /**********************************************************************************************************************/ DFB_CORE_PART( clipboard_core, ClipboardCore ); /**********************************************************************************************************************/ static DFBResult dfb_clipboard_core_initialize( CoreDFB *core, DFBClipboardCore *data, DFBClipboardCoreShared *shared ) { D_DEBUG_AT( Core_Clipboard, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; shared->shmpool = dfb_core_shmpool( core ); fusion_skirmish_init2( &shared->lock, "Clipboard Core", dfb_core_world( core ), fusion_config->secure_fusion ); D_MAGIC_SET( data, DFBClipboardCore ); D_MAGIC_SET( shared, DFBClipboardCoreShared ); return DFB_OK; } static DFBResult dfb_clipboard_core_join( CoreDFB *core, DFBClipboardCore *data, DFBClipboardCoreShared *shared ) { D_DEBUG_AT( Core_Clipboard, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); data->core = core; data->shared = shared; D_MAGIC_SET( data, DFBClipboardCore ); return DFB_OK; } static DFBResult dfb_clipboard_core_shutdown( DFBClipboardCore *data, bool emergency ) { DFBClipboardCoreShared *shared; D_DEBUG_AT( Core_Clipboard, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBClipboardCore ); D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); shared = data->shared; fusion_skirmish_destroy( &shared->lock ); if (shared->data) SHFREE( shared->shmpool, shared->data ); if (shared->mime_type) SHFREE( shared->shmpool, shared->mime_type ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_clipboard_core_leave( DFBClipboardCore *data, bool emergency ) { D_DEBUG_AT( Core_Clipboard, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBClipboardCore ); D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_clipboard_core_suspend( DFBClipboardCore *data ) { D_DEBUG_AT( Core_Clipboard, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBClipboardCore ); D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); return DFB_OK; } static DFBResult dfb_clipboard_core_resume( DFBClipboardCore *data ) { D_DEBUG_AT( Core_Clipboard, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBClipboardCore ); D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_clipboard_set( DFBClipboardCore *core, const char *mime_type, const void *data, unsigned int size, struct timeval *timestamp ) { DFBClipboardCoreShared *shared; char *new_mime; void *new_data; D_MAGIC_ASSERT( core, DFBClipboardCore ); D_MAGIC_ASSERT( core->shared, DFBClipboardCoreShared ); D_ASSERT( mime_type != NULL ); D_ASSERT( data != NULL ); D_ASSERT( size > 0 ); shared = core->shared; new_mime = SHSTRDUP( shared->shmpool, mime_type ); if (!new_mime) return D_OOSHM(); new_data = SHMALLOC( shared->shmpool, size ); if (!new_data) { SHFREE( shared->shmpool, new_mime ); return D_OOSHM(); } direct_memcpy( new_data, data, size ); if (fusion_skirmish_prevail( &shared->lock )) { SHFREE( shared->shmpool, new_data ); SHFREE( shared->shmpool, new_mime ); return DFB_FUSION; } if (shared->data) SHFREE( shared->shmpool, shared->data ); if (shared->mime_type) SHFREE( shared->shmpool, shared->mime_type ); shared->mime_type = new_mime; shared->data = new_data; shared->size = size; shared->timestamp = *timestamp; fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_clipboard_get( DFBClipboardCore *core, char **mime_type, void **data, unsigned int *size ) { DFBClipboardCoreShared *shared; D_MAGIC_ASSERT( core, DFBClipboardCore ); D_MAGIC_ASSERT( core->shared, DFBClipboardCoreShared ); shared = core->shared; if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; if (!shared->mime_type || !shared->data) { fusion_skirmish_dismiss( &shared->lock ); return DFB_BUFFEREMPTY; } if (mime_type) *mime_type = D_STRDUP( shared->mime_type ); if (data) { *data = D_MALLOC( shared->size ); direct_memcpy( *data, shared->data, shared->size ); } if (size) *size = shared->size; fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_clipboard_get_timestamp( DFBClipboardCore *core, struct timeval *timestamp ) { DFBClipboardCoreShared *shared; D_MAGIC_ASSERT( core, DFBClipboardCore ); D_MAGIC_ASSERT( core->shared, DFBClipboardCoreShared ); D_ASSERT( timestamp != NULL ); shared = core->shared; if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; *timestamp = shared->timestamp; fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } ================================================ FILE: src/core/clipboard.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CLIPBOARD_H__ #define __CORE__CLIPBOARD_H__ #include #include /**********************************************************************************************************************/ typedef struct { int magic; FusionSkirmish lock; char *mime_type; void *data; unsigned int size; struct timeval timestamp; FusionSHMPoolShared *shmpool; } DFBClipboardCoreShared; typedef struct { int magic; CoreDFB *core; DFBClipboardCoreShared *shared; } DFBClipboardCore; /**********************************************************************************************************************/ DFBResult dfb_clipboard_set ( DFBClipboardCore *core, const char *mime_type, const void *data, unsigned int size, struct timeval *timestamp ); DFBResult dfb_clipboard_get ( DFBClipboardCore *core, char **mime_type, void **data, unsigned int *size ); DFBResult dfb_clipboard_get_timestamp( DFBClipboardCore *core, struct timeval *timestamp ); #endif ================================================ FILE: src/core/colorhash.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Core_ColorHash, "Core/ColorHash", "DirectFB Core ColorHash" ); /**********************************************************************************************************************/ DFB_CORE_PART( colorhash_core, ColorHashCore ); /**********************************************************************************************************************/ #define HASH_SIZE 823 static DFBColorHashCore *colorhash; static DFBResult dfb_colorhash_core_initialize( CoreDFB *core, DFBColorHashCore *data, DFBColorHashCoreShared *shared ) { D_DEBUG_AT( Core_ColorHash, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); colorhash = data; data->core = core; data->shared = shared; data->hash = D_CALLOC( HASH_SIZE, sizeof(Colorhash) ); if (!data->hash) return D_OOM(); direct_mutex_init( &data->hash_lock ); D_MAGIC_SET( data, DFBColorHashCore ); D_MAGIC_SET( shared, DFBColorHashCoreShared ); return DFB_OK; } static DFBResult dfb_colorhash_core_join( CoreDFB *core, DFBColorHashCore *data, DFBColorHashCoreShared *shared ) { D_DEBUG_AT( Core_ColorHash, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBColorHashCoreShared ); colorhash = data; data->core = core; data->shared = shared; data->hash = D_CALLOC( HASH_SIZE, sizeof(Colorhash) ); if (!data->hash) return D_OOM(); direct_mutex_init( &data->hash_lock ); D_MAGIC_SET( data, DFBColorHashCore ); return DFB_OK; } static DFBResult dfb_colorhash_core_shutdown( DFBColorHashCore *data, bool emergency ) { D_DEBUG_AT( Core_ColorHash, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); direct_mutex_deinit( &data->hash_lock ); D_FREE( data->hash ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_colorhash_core_leave( DFBColorHashCore *data, bool emergency ) { D_DEBUG_AT( Core_ColorHash, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); direct_mutex_deinit( &data->hash_lock ); D_FREE( data->hash ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_colorhash_core_suspend( DFBColorHashCore *data ) { D_DEBUG_AT( Core_ColorHash, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); return DFB_OK; } static DFBResult dfb_colorhash_core_resume( DFBColorHashCore *data ) { D_DEBUG_AT( Core_ColorHash, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBColorHashCore ); D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); return DFB_OK; } /**********************************************************************************************************************/ unsigned int dfb_colorhash_lookup( DFBColorHashCore *core, CorePalette *palette, u8 r, u8 g, u8 b, u8 a ) { unsigned int pixel = PIXEL_ARGB( a, r, g, b ); unsigned int index = (pixel ^ (unsigned long) palette) % HASH_SIZE; if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = colorhash; D_ASSERT( core->hash != NULL ); direct_mutex_lock( &core->hash_lock ); /* Try a lookup in the hash table. */ if (core->hash[index].palette_id == palette->object.id && core->hash[index].pixel == pixel) { /* Set the return value. */ index = core->hash[index].index; } /* Look for the closest match. */ else { DFBColor *entries = palette->entries; int min_diff = 0; unsigned int i, min_index = 0; for (i = 0; i < palette->num_entries; i++) { int diff; int r_diff = (int) entries[i].r - (int) r; int g_diff = (int) entries[i].g - (int) g; int b_diff = (int) entries[i].b - (int) b; int a_diff = (int) entries[i].a - (int) a; if (a) diff = (r_diff * r_diff + g_diff * g_diff + b_diff * b_diff + ((a_diff * a_diff) >> 6)); else diff = (r_diff + g_diff + b_diff + (a_diff * a_diff)); if (i == 0 || diff < min_diff) { min_diff = diff; min_index = i; } if (!diff) break; } /* Store the matching entry in the hash table. */ core->hash[index].pixel = pixel; core->hash[index].index = min_index; core->hash[index].palette_id = palette->object.id; /* Set the return value. */ index = min_index; } direct_mutex_unlock( &core->hash_lock ); return index; } void dfb_colorhash_invalidate( DFBColorHashCore *core, CorePalette *palette ) { unsigned int index = HASH_SIZE - 1; if (core) { D_MAGIC_ASSERT( core, DFBColorHashCore ); D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); } else core = colorhash; D_ASSERT( core->hash != NULL ); direct_mutex_lock( &core->hash_lock ); /* Invalidate all entries owned by this palette. */ do { if (core->hash[index].palette_id == palette->object.id) core->hash[index].palette_id = 0; } while (index--); direct_mutex_unlock( &core->hash_lock ); } ================================================ FILE: src/core/colorhash.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__COLORHASH_H__ #define __CORE__COLORHASH_H__ #include #include /**********************************************************************************************************************/ typedef struct { unsigned int pixel; unsigned int index; u32 palette_id; } Colorhash; typedef struct { int magic; } DFBColorHashCoreShared; typedef struct { int magic; CoreDFB *core; DFBColorHashCoreShared *shared; Colorhash *hash; DirectMutex hash_lock; } DFBColorHashCore; /**********************************************************************************************************************/ unsigned int dfb_colorhash_lookup ( DFBColorHashCore *core, CorePalette *palette, u8 r, u8 g, u8 b, u8 a ); void dfb_colorhash_invalidate( DFBColorHashCore *core, CorePalette *palette ); #endif ================================================ FILE: src/core/core.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Main, "Core/Main", "DirectFB Core" ); D_DEBUG_DOMAIN( Core_Resource, "Core/Resource", "DirectFB Core Resource" ); /**********************************************************************************************************************/ struct __DFB_CoreCleanup { DirectLink link; CoreCleanupFunc func; /* the cleanup function to be called */ void *data; /* context of the cleanup function */ bool emergency; /* if true, cleanup is also done during emergency shutdown (from signal handler) */ }; struct __DFB_CoreMemoryPermission { DirectLink link; CoreMemoryPermissionFlags flags; void *data; void *end; size_t length; }; CoreDFB *core_dfb = NULL; static DirectMutex core_dfb_lock = DIRECT_MUTEX_INITIALIZER(); static DirectTLS core_tls_key; extern CorePart dfb_clipboard_core; extern CorePart dfb_colorhash_core; extern CorePart dfb_graphics_core; extern CorePart dfb_input_core; extern CorePart dfb_layer_core; extern CorePart dfb_screen_core; extern CorePart dfb_surface_core; extern CorePart dfb_system_core; extern CorePart dfb_wm_core; static CorePart *core_parts[] = { &dfb_clipboard_core, &dfb_colorhash_core, &dfb_surface_core, &dfb_system_core, &dfb_input_core, &dfb_graphics_core, &dfb_screen_core, &dfb_layer_core, &dfb_wm_core }; static void dfb_core_deinit_check( void *ctx ); static void dfb_core_thread_init_handler( DirectThread *thread, void *arg ); static void dfb_core_process_cleanups( CoreDFB *core, bool emergency ); static DirectSignalHandlerResult dfb_core_signal_handler( int num, void *addr, void *ctx ); static DFBResult dfb_core_arena_initialize( void *ctx ); static DFBResult dfb_core_arena_shutdown ( void *ctx, bool emergency ); static DFBResult dfb_core_arena_join ( void *ctx ); static DFBResult dfb_core_arena_leave ( void *ctx, bool emergency ); typedef struct { ICoreResourceClient *client; CoreSlave slave; } ResourceIdentity; /**********************************************************************************************************************/ static FusionCallHandlerResult Core_AsyncCall_Handler( int caller, /* fusion id of the caller */ int call_arg, /* optional call parameter */ void *call_ptr, /* optional call parameter */ void *ctx, /* optional handler context */ unsigned int serial, int *ret_val ) { AsyncCall *call = call_ptr; call->func( call->ctx, call->ctx2 ); return FCHR_RETURN; } DFBResult dfb_core_create( CoreDFB **ret_core ) { DFBResult ret; #if FUSION_BUILD_MULTI char buf[16]; #endif /* FUSION_BUILD_MULTI */ CoreDFB *core = NULL; D_ASSERT( ret_core != NULL ); D_ASSERT( dfb_config != NULL ); D_DEBUG_AT( Core_Main, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &core_dfb_lock ); D_ASSERT( core_dfb == NULL || core_dfb->refs > 0 ); if (core_dfb) { D_MAGIC_ASSERT( core_dfb, CoreDFB ); core_dfb->refs++; *ret_core = core_dfb; direct_mutex_unlock( &core_dfb_lock ); return DFB_OK; } direct_initialize(); D_INFO( "DirectFB/Core: %s Application Core. ("BUILDTIME") %s%s\n", FUSION_BUILD_MULTI ? "Multi" : "Single", DIRECT_BUILD_DEBUG ? "[ DEBUG ]" : "", DIRECT_BUILD_TRACE ? "[ TRACE ]" : "" ); ret = dfb_system_lookup(); if (ret) goto error; if (dfb_system_caps() & CSCAPS_SECURE_FUSION) { D_INFO( "DirectFB/Core: Forcing 'secure-fusion' option (requested by system module)\n" ); fusion_config->secure_fusion = true; } if (dfb_system_caps() & CSCAPS_ALWAYS_INDIRECT) { D_INFO( "DirectFB/Core: Forcing 'always-indirect' option (requested by system module)\n" ); dfb_config->call_nodirect = FCEF_NODIRECT; } /* Allocate local core structure. */ core = D_CALLOC( 1, sizeof(CoreDFB) ); if (!core) { ret = D_OOM(); goto error; } core->refs = 1; core->init_handler = direct_thread_add_init_handler( dfb_core_thread_init_handler, core ); #if FUSION_BUILD_MULTI dfb_system_thread_init(); #endif /* FUSION_BUILD_MULTI */ direct_find_best_memcpy(); D_MAGIC_SET( core, CoreDFB ); core_dfb = core; ret = fusion_enter( dfb_config->session, DIRECTFB_CORE_ABI, FER_ANY, &core->world ); if (ret) goto error; core->fusion_id = fusion_id( core->world ); #if FUSION_BUILD_MULTI D_DEBUG_AT( Core_Main, " -> world %d, fusion id %lu\n", fusion_world_index( core->world ), core->fusion_id ); snprintf( buf, sizeof(buf), "%d", fusion_world_index( core->world ) ); setenv( "DIRECTFB_SESSION", buf, true ); #endif /* FUSION_BUILD_MULTI */ if (dfb_config->sync) { D_INFO( "DirectFB/Core: Synchronize data on disk with memory\n" ); direct_sync(); } if (dfb_config->core_sighandler) direct_signal_handler_add( DIRECT_SIGNAL_ANY, dfb_core_signal_handler, core, &core->signal_handler ); /* Initialize async call. */ fusion_call_init( &core_dfb->async_call, Core_AsyncCall_Handler, core, core_dfb->world ); fusion_call_set_name( &core_dfb->async_call, "Core_AsyncCall" ); if (dfb_core_is_master( core_dfb )) ret = dfb_core_arena_initialize( core_dfb ); else ret = dfb_core_arena_join( core_dfb ); if (ret) goto error; if (dfb_config->block_all_signals) direct_signals_block_all(); if (dfb_config->deinit_check) direct_cleanup_handler_add( dfb_core_deinit_check, NULL, &core->cleanup_handler ); dfb_font_manager_create( core, &core->font_manager ); *ret_core = core; direct_mutex_unlock( &core_dfb_lock ); D_DEBUG_AT( Core_Main, " -> core successfully created\n" ); return DFB_OK; error: if (core) { if (core->world) { fusion_call_destroy( &core_dfb->async_call ); fusion_exit( core->world, false ); } if (core->init_handler) direct_thread_remove_init_handler( core->init_handler ); if (core->signal_handler) direct_signal_handler_remove( core->signal_handler ); D_MAGIC_CLEAR( core ); D_FREE( core ); core_dfb = NULL; } direct_mutex_unlock( &core_dfb_lock ); direct_shutdown(); return ret; } DFBResult dfb_core_destroy( CoreDFB *core, bool emergency ) { DFBResult ret; D_MAGIC_ASSERT( core, CoreDFB ); D_ASSERT( core->refs > 0 ); D_ASSERT( core == core_dfb ); D_DEBUG_AT( Core_Main, "%s()\n", __FUNCTION__ ); if (!emergency) { direct_mutex_lock( &core_dfb_lock ); if (--core->refs) { direct_mutex_unlock( &core_dfb_lock ); return DFB_OK; } } if (!core->shutdown_running) core->shutdown_running = 1; else { if (!emergency) direct_mutex_unlock( &core_dfb_lock ); D_WARN( "core shutdown already running" ); return DFB_OK; } if (core->signal_handler) { DirectSignalHandler *signal_handler = core->signal_handler; core->signal_handler = NULL; direct_signal_handler_remove( signal_handler ); } if (core->cleanup_handler) { DirectCleanupHandler *cleanup_handler = core->cleanup_handler; core->cleanup_handler = NULL; direct_cleanup_handler_remove( cleanup_handler ); } direct_thread_sleep( 100000 ); if (core->font_manager) dfb_font_manager_destroy( core->font_manager ); if (dfb_core_is_master( core )) { if (emergency) { fusion_kill( core->world, 0, SIGKILL, 1000 ); } else { fusion_kill( core->world, 0, SIGTERM, 5000 ); fusion_kill( core->world, 0, SIGKILL, 2000 ); } } dfb_core_process_cleanups( core, emergency ); if (dfb_core_is_master( core_dfb )) ret = dfb_core_arena_shutdown( core_dfb, emergency ); else ret = dfb_core_arena_leave( core_dfb, emergency ); fusion_call_destroy( &core_dfb->async_call ); fusion_exit( core->world, emergency ); if (!emergency) direct_thread_remove_init_handler( core->init_handler ); D_MAGIC_CLEAR( core ); D_FREE( core ); core_dfb = NULL; if (!emergency) direct_mutex_unlock( &core_dfb_lock ); direct_shutdown(); return ret; } void * dfb_core_get_part( CoreDFB *core, CorePartID part_id ) { switch (part_id) { case DFCP_CLIPBOARD: return dfb_clipboard_core.data_local; case DFCP_COLORHASH: return dfb_colorhash_core.data_local; case DFCP_GRAPHICS: return dfb_graphics_core.data_local; case DFCP_INPUT: return dfb_input_core.data_local; case DFCP_LAYER: return dfb_layer_core.data_local; case DFCP_SCREEN: return dfb_screen_core.data_local; case DFCP_SURFACE: return dfb_surface_core.data_local; case DFCP_SYSTEM: return dfb_system_core.data_local; case DFCP_WM: return dfb_wm_core.data_local; default: D_BUG( "unknown core part" ); } return NULL; } DFBResult dfb_core_initialize( CoreDFB *core ) { int i; DFBResult ret; CoreDFBShared *shared; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); direct_hash_create( 23, &core->resource.identities ); direct_mutex_init( &core->memory_permissions_lock ); shared = core->shared; ret = fusion_shm_pool_create( core->world, "DirectFB Data Pool", 0x1000000, fusion_config->debugshm, &shared->shmpool_data ); if (ret) return ret; shared->graphics_state_pool = dfb_graphics_state_pool_create( core->world ); shared->layer_context_pool = dfb_layer_context_pool_create( core->world ); shared->layer_region_pool = dfb_layer_region_pool_create( core->world ); shared->palette_pool = dfb_palette_pool_create( core->world ); shared->surface_pool = dfb_surface_pool_create( core->world ); shared->surface_allocation_pool = dfb_surface_allocation_pool_create( core->world ); shared->surface_buffer_pool = dfb_surface_buffer_pool_create( core->world ); shared->surface_client_pool = dfb_surface_client_pool_create( core->world ); shared->window_pool = dfb_window_pool_create( core->world ); for (i = 0; i < D_ARRAY_SIZE(core_parts); i++) { if ((ret = dfb_core_part_initialize( core, core_parts[i] ))) return ret; } if (dfb_config->resource_manager) { DirectInterfaceFuncs *funcs; ret = DirectGetInterface( &funcs, "ICoreResourceManager", dfb_config->resource_manager, NULL, NULL ); if (ret == DFB_OK) { void *iface; ret = funcs->Allocate( &iface ); if (ret == DFB_OK) { ret = funcs->Construct( iface, core ); if (ret == DFB_OK) { D_INFO( "Core/Resource: Using resource manager '%s'\n", dfb_config->resource_manager ); core->resource.manager = iface; } else D_DERROR( ret, "Core/Resource: Failed to construct manager '%s'!\n", dfb_config->resource_manager ); } else D_DERROR( ret, "Core/Resource: Failed to allocate manager '%s'!\n", dfb_config->resource_manager ); } else D_DERROR( ret, "Core/Resource: Failed to load manager '%s'!\n", dfb_config->resource_manager ); } return DFB_OK; } CoreGraphicsState * dfb_core_create_graphics_state( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->graphics_state_pool != NULL ); shared = core->shared; return (CoreGraphicsState*) fusion_object_create( shared->graphics_state_pool, core->world, Core_GetIdentity() ); } CoreLayerContext * dfb_core_create_layer_context( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->layer_context_pool != NULL ); shared = core->shared; return (CoreLayerContext*) fusion_object_create( shared->layer_context_pool, core->world, Core_GetIdentity() ); } CoreLayerRegion * dfb_core_create_layer_region( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->layer_region_pool != NULL ); shared = core->shared; return (CoreLayerRegion*) fusion_object_create( shared->layer_region_pool, core->world, Core_GetIdentity() ); } CorePalette * dfb_core_create_palette( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->palette_pool != NULL ); shared = core->shared; return (CorePalette*) fusion_object_create( shared->palette_pool, core->world, Core_GetIdentity() ); } CoreSurface * dfb_core_create_surface( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_pool != NULL ); shared = core->shared; return (CoreSurface*) fusion_object_create( shared->surface_pool, core->world, Core_GetIdentity() ); } CoreSurfaceAllocation * dfb_core_create_surface_allocation( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_allocation_pool != NULL ); shared = core->shared; return (CoreSurfaceAllocation*) fusion_object_create( shared->surface_allocation_pool, core->world, Core_GetIdentity() ); } CoreSurfaceBuffer * dfb_core_create_surface_buffer( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_buffer_pool != NULL ); shared = core->shared; return (CoreSurfaceBuffer*) fusion_object_create( shared->surface_buffer_pool, core->world, Core_GetIdentity() ); } CoreSurfaceClient * dfb_core_create_surface_client( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_client_pool != NULL ); shared = core->shared; return (CoreSurfaceClient*) fusion_object_create( shared->surface_client_pool, core->world, Core_GetIdentity() ); } CoreWindow * dfb_core_create_window( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->window_pool != NULL ); shared = core->shared; return (CoreWindow*) fusion_object_create( shared->window_pool, core->world, Core_GetIdentity() ); } DFBResult dfb_core_get_graphics_state( CoreDFB *core, u32 object_id, CoreGraphicsState **ret_state ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->graphics_state_pool != NULL ); D_ASSERT( ret_state != NULL ); shared = core->shared; ret = fusion_object_get( shared->graphics_state_pool, object_id, &object ); if (ret) return ret; *ret_state = (CoreGraphicsState*) object; return DFB_OK; } DFBResult dfb_core_get_layer_context( CoreDFB *core, u32 object_id, CoreLayerContext **ret_context ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->layer_context_pool != NULL ); D_ASSERT( ret_context != NULL ); shared = core->shared; ret = fusion_object_get( shared->layer_context_pool, object_id, &object ); if (ret) return ret; *ret_context = (CoreLayerContext*) object; return DFB_OK; } DFBResult dfb_core_get_layer_region( CoreDFB *core, u32 object_id, CoreLayerRegion **ret_region ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->layer_region_pool != NULL ); D_ASSERT( ret_region != NULL ); shared = core->shared; ret = fusion_object_get( shared->layer_region_pool, object_id, &object ); if (ret) return ret; *ret_region = (CoreLayerRegion*) object; return DFB_OK; } DFBResult dfb_core_get_palette( CoreDFB *core, u32 object_id, CorePalette **ret_palette ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->palette_pool != NULL ); D_ASSERT( ret_palette != NULL ); shared = core->shared; ret = fusion_object_get( shared->palette_pool, object_id, &object ); if (ret) return ret; *ret_palette = (CorePalette*) object; return DFB_OK; } DFBResult dfb_core_get_surface( CoreDFB *core, u32 object_id, CoreSurface **ret_surface ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_pool != NULL ); D_ASSERT( ret_surface != NULL ); shared = core->shared; ret = fusion_object_get( shared->surface_pool, object_id, &object ); if (ret) return ret; *ret_surface = (CoreSurface*) object; return DFB_OK; } DFBResult dfb_core_get_surface_allocation( CoreDFB *core, u32 object_id, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_allocation_pool != NULL ); D_ASSERT( ret_allocation != NULL ); shared = core->shared; ret = fusion_object_get( shared->surface_allocation_pool, object_id, &object ); if (ret) return ret; *ret_allocation = (CoreSurfaceAllocation*) object; return DFB_OK; } DFBResult dfb_core_get_surface_buffer( CoreDFB *core, u32 object_id, CoreSurfaceBuffer **ret_buffer ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_buffer_pool != NULL ); D_ASSERT( ret_buffer != NULL ); shared = core->shared; ret = fusion_object_get( shared->surface_buffer_pool, object_id, &object ); if (ret) return ret; *ret_buffer = (CoreSurfaceBuffer*) object; return DFB_OK; } DFBResult dfb_core_get_surface_client( CoreDFB *core, u32 object_id, CoreSurfaceClient **ret_client ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->surface_client_pool != NULL ); D_ASSERT( ret_client != NULL ); shared = core->shared; ret = fusion_object_get( shared->surface_client_pool, object_id, &object ); if (ret) return ret; *ret_client = (CoreSurfaceClient*) object; return DFB_OK; } DFBResult dfb_core_get_window( CoreDFB *core, u32 object_id, CoreWindow **ret_window ) { DFBResult ret; FusionObject *object; CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); D_ASSERT( core->shared->window_pool != NULL ); D_ASSERT( ret_window != NULL ); shared = core->shared; ret = fusion_object_get( shared->window_pool, object_id, &object ); if (ret) return ret; *ret_window = (CoreWindow*) object; return DFB_OK; } DirectResult dfb_core_enum_graphics_states( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->graphics_state_pool, callback, ctx ); } DirectResult dfb_core_enum_layer_contexts( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->layer_context_pool, callback, ctx ); } DirectResult dfb_core_enum_layer_regions( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->layer_region_pool, callback, ctx ); } DirectResult dfb_core_enum_layer_palettes( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->palette_pool, callback, ctx ); } DirectResult dfb_core_enum_surfaces( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->surface_pool, callback, ctx ); } DirectResult dfb_core_enum_surface_allocations( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->surface_allocation_pool, callback, ctx ); } DirectResult dfb_core_enum_surface_buffers( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->surface_buffer_pool, callback, ctx ); } DirectResult dfb_core_enum_surface_clients( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->surface_client_pool, callback, ctx ); } DirectResult dfb_core_enum_windows( CoreDFB *core, FusionObjectCallback callback, void *ctx ) { CoreDFBShared *shared; D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return fusion_object_pool_enum( shared->window_pool, callback, ctx ); } static bool dump_objects( FusionObjectPool *pool, FusionObject *object, void *ctx ) { D_LOG( Core_Main, VERBOSE, " %p [id %u] ref 0x%x (single %d) identity %lu\n", object, object->id, (unsigned int) object->ref.multi.id, object->ref.single.refs, object->identity ); direct_trace_print_stack( object->create_stack ); return true; } static void dfb_core_dump_all( CoreDFB *core ) { int i; CoreDFBShared *shared; D_DEBUG_AT( Core_Main, "%s()\n", __FUNCTION__ ); D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; FusionObjectPool *pools[] = { shared->graphics_state_pool, shared->layer_context_pool, shared->layer_region_pool, shared->palette_pool, shared->surface_pool, shared->surface_allocation_pool, shared->surface_buffer_pool, shared->surface_client_pool, shared->window_pool }; for (i = 0; i < D_ARRAY_SIZE(pools); i++) { if (pools[i]) { D_LOG( Core_Main, VERBOSE, " - Objects in '%s' -\n", pools[i]->name ); fusion_object_pool_enum( pools[i], dump_objects, NULL ); } } } static DirectResult dfb_core_wait_all( CoreDFB *core, long long timeout ) { long long start; CoreDFBShared *shared; D_DEBUG_AT( Core_Main, "%s( timeout %lld us )\n", __FUNCTION__, timeout ); D_ASSERT( core != NULL || core_dfb != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; start = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); while (true) { int i; FusionObjectPool *pools[] = { shared->graphics_state_pool, shared->layer_context_pool, shared->layer_region_pool, shared->palette_pool, shared->surface_pool, shared->surface_allocation_pool, shared->surface_buffer_pool, shared->surface_client_pool, shared->window_pool }; long long now = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); for (i = 0; i < D_ARRAY_SIZE(pools); i++) { if (pools[i]) { size_t num = 0; DFBResult ret; D_UNUSED_P( ret ); ret = fusion_object_pool_size( pools[i], &num ); if (ret) return ret; if (num > 0) { if (now - start >= timeout) { D_DEBUG_AT( Core_Main, " -> still "_ZU" objects in pool, timeout!\n", num ); return DR_TIMEOUT; } D_DEBUG_AT( Core_Main, " -> still "_ZU" objects in '%s', waiting 10ms...\n", num, pools[i]->name ); break; } } } if (i < D_ARRAY_SIZE(pools)) { D_DEBUG_AT( Core_Main, " -> waiting another 10ms for objects to be dead...\n" ); direct_thread_sleep( 10000 ); } else break; } return DR_OK; } DirectResult core_arena_add_shared_field( CoreDFB *core, const char *name, void *data ) { DirectResult ret; char *shname; CoreDFBShared *shared; D_DEBUG_AT( Core_Main, "%s( '%s', %p )\n", __FUNCTION__, name, data ); D_ASSERT( core != NULL ); D_ASSERT( core->shared != NULL ); shared = core->shared; /* Give it the requested name. */ shname = SHSTRDUP( shared->shmpool, name ); if (shname) ret = fusion_hash_replace( shared->field_hash, shname, data, NULL, NULL ); else ret = D_OOSHM(); return ret; } DirectResult core_arena_get_shared_field( CoreDFB *core, const char *name, void **data ) { void *ptr; CoreDFBShared *shared; D_DEBUG_AT( Core_Main, "%s( '%s' )\n", __FUNCTION__, name ); D_ASSERT( core != NULL ); D_ASSERT( core->shared != NULL ); shared = core->shared; /* Lookup entry. */ ptr = fusion_hash_lookup( shared->field_hash, name ); D_DEBUG_AT( Core_Main, " -> %p\n", ptr ); if (!ptr) return DR_ITEMNOTFOUND; *data = ptr; return DR_OK; } bool dfb_core_is_master( CoreDFB *core ) { D_MAGIC_ASSERT( core, CoreDFB ); return core->fusion_id == FUSION_ID_MASTER; } void dfb_core_activate( CoreDFB *core ) { D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); /* Let others enter the world. */ fusion_world_activate( core->world ); } FusionWorld * dfb_core_world( CoreDFB *core ) { if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); return core->world; } FusionSHMPoolShared * dfb_core_shmpool( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return shared->shmpool; } FusionSHMPoolShared * dfb_core_shmpool_data( CoreDFB *core ) { CoreDFBShared *shared; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; return shared->shmpool_data; } DFBResult dfb_core_suspend( CoreDFB *core ) { DFBResult ret; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); if (!dfb_core_is_master( core )) return DFB_ACCESSDENIED; if (core->suspended) return DFB_BUSY; ret = dfb_input_core.Suspend( dfb_input_core.data_local ); if (ret) goto error_input; ret = dfb_layer_core.Suspend( dfb_layer_core.data_local ); if (ret) goto error_layers; ret = dfb_screen_core.Suspend( dfb_screen_core.data_local ); if (ret) goto error_screens; ret = dfb_graphics_core.Suspend( dfb_graphics_core.data_local ); if (ret) goto error_graphics; core->suspended = true; return DFB_OK; error_graphics: dfb_screen_core.Resume( dfb_screen_core.data_local ); error_screens: dfb_layer_core.Resume( dfb_layer_core.data_local ); error_layers: dfb_input_core.Resume( dfb_input_core.data_local ); error_input: return ret; } DFBResult dfb_core_resume( CoreDFB *core ) { DFBResult ret; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); if (!dfb_core_is_master( core )) return DFB_ACCESSDENIED; if (!core->suspended) return DFB_BUSY; ret = dfb_graphics_core.Resume( dfb_graphics_core.data_local ); if (ret) goto error_graphics; ret = dfb_screen_core.Resume( dfb_screen_core.data_local ); if (ret) goto error_screens; ret = dfb_layer_core.Resume( dfb_layer_core.data_local ); if (ret) goto error_layers; ret = dfb_input_core.Resume( dfb_input_core.data_local ); if (ret) goto error_input; core->suspended = false; return DFB_OK; error_input: dfb_layer_core.Suspend( dfb_layer_core.data_local ); error_layers: dfb_screen_core.Suspend( dfb_screen_core.data_local ); error_screens: dfb_graphics_core.Suspend( dfb_graphics_core.data_local ); error_graphics: return ret; } CoreCleanup * dfb_core_cleanup_add( CoreDFB *core, CoreCleanupFunc func, void *data, bool emergency ) { CoreCleanup *cleanup; D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); cleanup = D_CALLOC( 1, sizeof(CoreCleanup) ); cleanup->func = func; cleanup->data = data; cleanup->emergency = emergency; direct_list_prepend( &core->cleanups, &cleanup->link ); return cleanup; } void dfb_core_cleanup_remove( CoreDFB *core, CoreCleanup *cleanup ) { D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); direct_list_remove( &core->cleanups, &cleanup->link ); D_FREE( cleanup ); } CoreFontManager * dfb_core_font_manager( CoreDFB *core ) { D_ASSUME( core != NULL ); if (!core) core = core_dfb; D_MAGIC_ASSERT( core, CoreDFB ); return core->font_manager; } /**********************************************************************************************************************/ DFBResult dfb_core_memory_permissions_add( CoreDFB *core, CoreMemoryPermissionFlags flags, void *data, size_t length, CoreMemoryPermission **ret_permission ) { CoreMemoryPermission *permission; D_DEBUG_AT( Core_Main, "%s( flags 0x%02x, data %p, length "_ZU" )\n", __FUNCTION__, flags, data, length ); D_MAGIC_ASSERT( core, CoreDFB ); permission = D_CALLOC( 1, sizeof(CoreMemoryPermission) ); if (!permission) return D_OOM(); permission->flags = flags; permission->data = data; permission->end = data + length; permission->length = length; direct_mutex_lock( &core->memory_permissions_lock ); direct_list_prepend( &core->memory_permissions, &permission->link ); direct_mutex_unlock( &core->memory_permissions_lock ); *ret_permission = permission; return DFB_OK; } DFBResult dfb_core_memory_permissions_remove( CoreDFB *core, CoreMemoryPermission *permission ) { D_DEBUG_AT( Core_Main, "%s( flags 0x%02x, data %p, length "_ZU" )\n", __FUNCTION__, permission->flags, permission->data, permission->length ); D_MAGIC_ASSERT( core, CoreDFB ); direct_mutex_lock( &core->memory_permissions_lock ); direct_list_remove( &core->memory_permissions, &permission->link ); direct_mutex_unlock( &core->memory_permissions_lock ); D_FREE( permission ); return DFB_OK; } DFBResult dfb_core_memory_permissions_check( CoreDFB *core, CoreMemoryPermissionFlags flags, void *data, size_t length ) { CoreMemoryPermission *permission; D_DEBUG_LOG( Core_Main, 9, "%s( flags 0x%02x, data %p, length "_ZU" )\n", __FUNCTION__, flags, data, length ); D_MAGIC_ASSERT( core, CoreDFB ); direct_mutex_lock( &core->memory_permissions_lock ); direct_list_foreach (permission, core->memory_permissions) { if (permission->data <= data && permission->end >= data + length && D_FLAGS_ARE_SET( permission->flags, flags )) { D_DEBUG_LOG( Core_Main, 9, " -> found flags 0x%02x, data %p, length "_ZU"\n", permission->flags, permission->data, permission->length ); direct_mutex_unlock( &core->memory_permissions_lock ); return DFB_OK; } } direct_mutex_unlock( &core->memory_permissions_lock ); return DFB_ITEMNOTFOUND; } /**********************************************************************************************************************/ static void dfb_core_deinit_check( void *ctx ) { if (core_dfb && core_dfb->refs) { D_WARN( "application exited without deinitialization of DirectFB" ); direct_print_interface_leaks(); dfb_core_destroy( core_dfb, false ); } } static void dfb_core_thread_init_handler( DirectThread *thread, void *arg ) { dfb_system_thread_init(); } static void dfb_core_process_cleanups( CoreDFB *core, bool emergency ) { D_MAGIC_ASSERT( core, CoreDFB ); while (core->cleanups) { CoreCleanup *cleanup = (CoreCleanup*) core->cleanups; core->cleanups = core->cleanups->next; if (cleanup->emergency || !emergency) cleanup->func( cleanup->data, emergency ); D_FREE( cleanup ); } } static DirectSignalHandlerResult dfb_core_signal_handler( int num, void *addr, void *ctx ) { bool locked; CoreDFB *core = ctx; D_ASSERT( core == core_dfb ); locked = direct_mutex_trylock( &core_dfb_lock ) == 0; dfb_core_destroy( core, true ); if (locked) direct_mutex_unlock( &core_dfb_lock ); return DSHR_OK; } /**********************************************************************************************************************/ static bool region_callback( FusionObjectPool *pool, FusionObject *object, void *ctx ) { CoreLayerRegion *region = (CoreLayerRegion*) object; if (region->state & CLRSF_ENABLED) dfb_layer_region_disable( region ); return true; } static DFBResult dfb_core_shutdown( CoreDFB *core, bool emergency ) { DFBResult ret = DFB_OK; int loops = 200; CoreDFBShared *shared; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; /* Suspend input core to stop all input threads before shutting down. */ if (dfb_input_core.initialized) dfb_input_core.Suspend( dfb_input_core.data_local ); core->shutdown_tid = direct_gettid(); if (dfb_wm_core.initialized) dfb_wm_deactivate_all_stacks( dfb_wm_core.data_local ); dfb_core_enum_layer_regions( core, region_callback, core ); fusion_stop_dispatcher( core->world, false ); while (loops--) { fusion_dispatch( core->world, 16384 ); /* Blocks until objects are gone or timeout is reached. */ ret = dfb_core_wait_all( core, 10000 ); if (ret == DFB_OK) break; } if (ret == DFB_TIMEOUT) { if (fusion_config->shutdown_info) { D_ERROR( "Core/Main: Some objects remain alive, application or internal ref counting issue!\n" ); /* Print objects from all pools. */ dfb_core_dump_all( core ); direct_print_interface_leaks(); } } /* Destroy window objects. */ fusion_object_pool_destroy( shared->window_pool, core->world, fusion_config->shutdown_info ); shared->window_pool = NULL; /* Close window stacks. */ if (dfb_wm_core.initialized) dfb_wm_close_all_stacks( dfb_wm_core.data_local ); CoreDFB_Deinit_Dispatch( &shared->call ); /* Destroy layer context and region objects. */ fusion_object_pool_destroy( shared->layer_region_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->layer_context_pool, core->world, fusion_config->shutdown_info ); /* Shutdown WM core. */ dfb_core_part_shutdown( core, &dfb_wm_core, emergency ); /* Shutdown layer core. */ dfb_core_part_shutdown( core, &dfb_layer_core, emergency ); dfb_core_part_shutdown( core, &dfb_screen_core, emergency ); /* Destroy surface and palette objects. */ fusion_object_pool_destroy( shared->graphics_state_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->surface_client_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->surface_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->surface_buffer_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->surface_allocation_pool, core->world, fusion_config->shutdown_info ); fusion_object_pool_destroy( shared->palette_pool, core->world, fusion_config->shutdown_info ); /* Destroy remaining core parts. */ dfb_core_part_shutdown( core, &dfb_graphics_core, emergency ); dfb_core_part_shutdown( core, &dfb_surface_core, emergency ); dfb_core_part_shutdown( core, &dfb_input_core, emergency ); dfb_core_part_shutdown( core, &dfb_system_core, emergency ); dfb_core_part_shutdown( core, &dfb_colorhash_core, emergency ); dfb_core_part_shutdown( core, &dfb_clipboard_core, emergency ); /* Destroy shared memory pool for surface data. */ fusion_shm_pool_destroy( core->world, shared->shmpool_data ); direct_hash_destroy( core->resource.identities ); direct_mutex_deinit( &core->memory_permissions_lock ); return DFB_OK; } static DFBResult dfb_core_leave( CoreDFB *core, bool emergency ) { int i; D_MAGIC_ASSERT( core, CoreDFB ); for (i = D_ARRAY_SIZE(core_parts) - 1; i >= 0; i--) dfb_core_part_leave( core, core_parts[i], emergency ); CoreSlave_Deinit_Dispatch( &core->slave_call ); direct_hash_destroy( core->resource.identities ); direct_mutex_deinit( &core->memory_permissions_lock ); return DFB_OK; } static DFBResult dfb_core_join( CoreDFB *core ) { int i; D_MAGIC_ASSERT( core, CoreDFB ); direct_hash_create( 23, &core->resource.identities ); direct_mutex_init( &core->memory_permissions_lock ); CoreSlave_Init_Dispatch( core, core, &core->slave_call ); if (fusion_config->secure_fusion) CoreDFB_Register( core, core->slave_call.call_id ); for (i = 0; i < D_ARRAY_SIZE(core_parts); i++) { DFBResult ret; if ((ret = dfb_core_part_join( core, core_parts[i] ))) { dfb_core_leave( core, true ); return ret; } } return DFB_OK; } /**********************************************************************************************************************/ static void dfb_core_leave_callback( FusionWorld *world, FusionID fusion_id, void *ctx ) { Core_Resource_DisposeIdentity( fusion_id ); } static DFBResult dfb_core_arena_initialize( void *ctx ) { DFBResult ret; CoreDFB *core = ctx; CoreDFBShared *shared; FusionSHMPoolShared *pool; D_MAGIC_ASSERT( core, CoreDFB ); D_DEBUG_AT( Core_Main, "%s() initializing...\n", __FUNCTION__ ); /* Create the shared memory pool first. */ ret = fusion_shm_pool_create( core->world, "DirectFB Main Pool", 0x400000, fusion_config->debugshm, &pool ); if (ret) return ret; /* Allocate shared structure in the new pool. */ shared = SHCALLOC( pool, 1, sizeof(CoreDFBShared) ); if (!shared) { fusion_shm_pool_destroy( core->world, pool ); return D_OOSHM(); } core->shared = shared; shared->shmpool = pool; shared->secure = fusion_config->secure_fusion; ret = fusion_hash_create( pool, HASH_STRING, HASH_PTR, 7, &shared->field_hash ); if (ret) { SHFREE( pool, shared ); fusion_shm_pool_destroy( core->world, pool ); return ret; } fusion_hash_set_autofree( shared->field_hash, true, false ); D_MAGIC_SET( shared, CoreDFBShared ); CoreDFB_Init_Dispatch( core, core, &shared->call ); fusion_call_add_permissions( &shared->call, 0, FUSION_CALL_PERMIT_EXECUTE ); fusion_world_set_leave_callback( core->world, dfb_core_leave_callback, NULL ); /* Register shared data. */ fusion_world_set_root( core->world, shared ); /* Initialize. */ ret = CoreDFB_Initialize( core ); if (ret) { dfb_core_arena_shutdown( core, true ); return ret; } return DFB_OK; } static DFBResult dfb_core_arena_shutdown( void *ctx, bool emergency ) { DFBResult ret; CoreDFB *core = ctx; CoreDFBShared *shared; FusionSHMPoolShared *pool; D_MAGIC_ASSERT( core, CoreDFB ); D_MAGIC_ASSERT( core->shared, CoreDFBShared ); shared = core->shared; pool = shared->shmpool; D_DEBUG_AT( Core_Main, "%s() shutting down...\n", __FUNCTION__ ); if (!dfb_core_is_master( core )) { D_WARN( "refusing shutdown in slave" ); return dfb_core_leave( core, emergency ); } if (core_dfb->resource.manager) { core_dfb->resource.manager->Release(core_dfb->resource.manager); } /* Shutdown. */ ret = dfb_core_shutdown( core, emergency ); fusion_hash_destroy( shared->field_hash ); D_MAGIC_CLEAR( shared ); SHFREE( pool, shared ); fusion_shm_pool_destroy( core->world, pool ); return ret; } static DFBResult dfb_core_arena_join( void *ctx ) { DFBResult ret; CoreDFB *core = ctx; CoreDFBShared *shared; D_MAGIC_ASSERT( core, CoreDFB ); D_DEBUG_AT( Core_Main, "%s() joining...\n", __FUNCTION__ ); /* Get shared data. */ shared = fusion_world_get_root( core->world ); core->shared = shared; if (fusion_config->secure_fusion != shared->secure) { D_ERROR( "Core/Main: Local secure-fusion config (%d) does not match with running session (%d)!\n", fusion_config->secure_fusion, shared->secure ); return DFB_UNSUPPORTED; } /* Join. */ ret = dfb_core_join( core ); if (ret) return ret; return DFB_OK; } static DFBResult dfb_core_arena_leave( void *ctx, bool emergency ) { DFBResult ret; CoreDFB *core = ctx; D_MAGIC_ASSERT( core, CoreDFB ); D_DEBUG_AT( Core_Main, "%s() leaving...\n", __FUNCTION__ ); /* Leave. */ ret = dfb_core_leave( core, emergency ); if (ret) return ret; return DFB_OK; } /**********************************************************************************************************************/ static void core_tls_destroy( void *arg ) { CoreTLS *core_tls = arg; D_MAGIC_ASSERT( core_tls, CoreTLS ); D_MAGIC_CLEAR( core_tls ); D_FREE( core_tls ); } void Core_TLS__init() { direct_tls_register( &core_tls_key, core_tls_destroy ); } void Core_TLS__deinit() { direct_tls_unregister( &core_tls_key ); } CoreTLS * Core_GetTLS() { CoreTLS *core_tls; core_tls = direct_tls_get( &core_tls_key ); if (!core_tls) { core_tls = D_CALLOC( 1, sizeof(CoreTLS) ); if (!core_tls) { D_OOM(); return NULL; } D_MAGIC_SET( core_tls, CoreTLS ); direct_tls_set( &core_tls_key, core_tls ); } D_MAGIC_ASSERT( core_tls, CoreTLS ); return core_tls; } /**********************************************************************************************************************/ void Core_PushIdentity( FusionID caller ) { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) { core_tls->identity_count++; if (core_tls->identity_count <= CORE_TLS_IDENTITY_STACK_MAX) core_tls->identity[core_tls->identity_count-1] = caller ?: core_dfb->fusion_id; else D_WARN( "identity stack overflow" ); } else D_WARN( "TLS error" ); } void Core_PopIdentity() { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) { D_ASSERT( core_tls->identity_count > 0 ); if (core_tls->identity_count > 0) core_tls->identity_count--; else D_BUG( "no identity" ); } else D_WARN( "TLS error" ); } FusionID Core_GetIdentity() { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) { if (core_tls->identity_count == 0) { D_ASSERT( core_dfb != NULL ); D_ASSUME( core_dfb->fusion_id != 0 ); return core_dfb->fusion_id; } if (core_tls->identity_count <= CORE_TLS_IDENTITY_STACK_MAX) return core_tls->identity[core_tls->identity_count-1]; D_WARN( "wrong identity due to overflow" ); return core_tls->identity[CORE_TLS_IDENTITY_STACK_MAX-1]; } D_WARN( "TLS error" ); return 0; } #if FUSION_BUILD_MULTI void Core_PushCalling() { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) core_tls->calling++; else D_WARN( "TLS error" ); } void Core_PopCalling() { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) { if (core_tls->calling == 0) { D_BUG( "no more call" ); return; } core_tls->calling--; } else D_WARN( "TLS error" ); } int Core_GetCalling() { CoreTLS *core_tls = Core_GetTLS(); if (core_tls) return core_tls->calling; D_WARN( "TLS error" ); return 0; } #endif /* FUSION_BUILD_MULTI */ /**********************************************************************************************************************/ DFBResult Core_Resource_CheckSurface( const CoreSurfaceConfig *config, u64 resource_id ) { ICoreResourceClient *client; D_DEBUG_AT( Core_Resource, "%s( %dx%d, %s, resource id %llu ) <- identity %lu\n", __FUNCTION__, config->size.w, config->size.h, dfb_pixelformat_name( config->format ), (unsigned long long) resource_id, Core_GetIdentity() ); if (Core_GetIdentity() == core_dfb->fusion_id) return DFB_OK; if (core_dfb->resource.manager) { client = Core_Resource_GetClient( Core_GetIdentity() ); if (!client) return DFB_DEAD; return client->CheckSurface( client, config, resource_id ); } return DFB_OK; } DFBResult Core_Resource_CheckSurfaceUpdate( CoreSurface *surface, const CoreSurfaceConfig *config ) { ICoreResourceClient *client; D_DEBUG_AT( Core_Resource, "%s( %dx%d, %s, type %u, resource id %lu ) <- identity %lu\n", __FUNCTION__, config->size.w, config->size.h, dfb_pixelformat_name( config->format ), surface->type, surface->resource_id, surface->object.identity ); if (!surface->object.identity || surface->object.identity == core_dfb->fusion_id) return DFB_OK; if (core_dfb->resource.manager) { client = Core_Resource_GetClient( surface->object.identity ); if (!client) return DFB_DEAD; return client->CheckSurfaceUpdate( client, surface, config ); } return DFB_OK; } DFBResult Core_Resource_AddSurface( CoreSurface *surface ) { ICoreResourceClient *client; D_DEBUG_AT( Core_Resource, "%s( %dx%d, %s, type %u, resource id %lu ) <- identity %lu\n", __FUNCTION__, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), surface->type, surface->resource_id, Core_GetIdentity() ); if (!surface->object.identity || surface->object.identity == core_dfb->fusion_id) return DFB_OK; if (core_dfb->resource.manager) { client = Core_Resource_GetClient( surface->object.identity ); if (!client) return DFB_DEAD; return client->AddSurface( client, surface ); } return DFB_OK; } DFBResult Core_Resource_RemoveSurface( CoreSurface *surface ) { ICoreResourceClient *client; D_DEBUG_AT( Core_Resource, "%s( %dx%d, %s, type %u, resource id %lu ) <- identity %lu\n", __FUNCTION__, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), surface->type, surface->resource_id, surface->object.identity ); if (!surface->object.identity || surface->object.identity == core_dfb->fusion_id) return DFB_OK; if (core_dfb->resource.manager) { client = Core_Resource_GetClient( surface->object.identity ); if (!client) return DFB_DEAD; return client->RemoveSurface( client, surface ); } return DFB_OK; } DFBResult Core_Resource_UpdateSurface( CoreSurface *surface, const CoreSurfaceConfig *config ) { ICoreResourceClient *client; D_DEBUG_AT( Core_Resource, "%s( %dx%d, %s, type %u, resource id %lu ) <- identity %lu\n", __FUNCTION__, config->size.w, config->size.h, dfb_pixelformat_name( config->format ), surface->type, surface->resource_id, surface->object.identity ); if (!surface->object.identity || surface->object.identity == core_dfb->fusion_id) return DFB_OK; if (core_dfb->resource.manager) { client = Core_Resource_GetClient( surface->object.identity ); if (!client) return DFB_DEAD; return client->UpdateSurface( client, surface, config ); } return DFB_OK; } DFBResult Core_Resource_AddIdentity( FusionID fusion_id, u32 slave_call ) { DFBResult ret; ResourceIdentity *identity; FusionID call_owner; D_DEBUG_AT( Core_Resource, "%s( %lu )\n", __FUNCTION__, fusion_id ); identity = direct_hash_lookup( core_dfb->resource.identities, fusion_id ); if (identity) { D_BUG( "alredy registered" ); return DFB_BUSY; } identity = D_CALLOC( 1, sizeof(ResourceIdentity) ); if (!identity) return D_OOM(); fusion_call_init_from( &identity->slave.call, slave_call, dfb_core_world( core_dfb ) ); ret = fusion_call_get_owner( &identity->slave.call, &call_owner ); if (ret) { D_FREE( identity ); return ret; } if (call_owner != fusion_id) { D_ERROR( "Core/Resource: Slave call owner (%lu) does not match new identity (%lu)!\n", call_owner, fusion_id ); D_FREE( identity ); return DFB_FAILURE; } if (core_dfb->resource.manager) { ret = core_dfb->resource.manager->CreateClient( core_dfb->resource.manager, fusion_id, &identity->client ); if (ret) { D_DERROR( ret, "Core/Resource: CreateClient() failed!\n" ); D_FREE( identity ); return ret; } } ret = direct_hash_insert( core_dfb->resource.identities, fusion_id, identity ); if (ret) { D_DERROR( ret, "Core/Resource: Could not insert identity into hash table!\n" ); if (identity->client) identity->client->Release( identity->client ); D_FREE( identity ); return ret; } return DFB_OK; } void Core_Resource_DisposeIdentity( FusionID fusion_id ) { ResourceIdentity *identity; D_DEBUG_AT( Core_Resource, "%s( %lu )\n", __FUNCTION__, fusion_id ); identity = direct_hash_lookup( core_dfb->resource.identities, fusion_id ); if (identity) { if (identity->client) identity->client->Release( identity->client ); direct_hash_remove( core_dfb->resource.identities, fusion_id ); D_FREE( identity ); } } ICoreResourceClient * Core_Resource_GetClient( FusionID fusion_id ) { ResourceIdentity *identity; D_DEBUG_AT( Core_Resource, "%s( %lu )\n", __FUNCTION__, fusion_id ); identity = direct_hash_lookup( core_dfb->resource.identities, fusion_id ); if (identity) return identity->client; return NULL; } CoreSlave * Core_Resource_GetSlave( FusionID fusion_id ) { ResourceIdentity *identity; D_DEBUG_AT( Core_Resource, "%s( %lu )\n", __FUNCTION__, fusion_id ); identity = direct_hash_lookup( core_dfb->resource.identities, fusion_id ); if (identity) return &identity->slave; return NULL; } ================================================ FILE: src/core/core.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORE_H__ #define __CORE__CORE_H__ #include #include #include /**********************************************************************************************************************/ #define DIRECTFB_CORE_ABI 46 typedef struct { int magic; bool secure; FusionObjectPool *graphics_state_pool; FusionObjectPool *layer_context_pool; FusionObjectPool *layer_region_pool; FusionObjectPool *palette_pool; FusionObjectPool *surface_pool; FusionObjectPool *surface_allocation_pool; FusionObjectPool *surface_buffer_pool; FusionObjectPool *surface_client_pool; FusionObjectPool *window_pool; FusionSHMPoolShared *shmpool; FusionSHMPoolShared *shmpool_data; FusionCall call; FusionHash *field_hash; } CoreDFBShared; struct __DFB_CoreDFB { int magic; int refs; FusionID fusion_id; FusionWorld *world; CoreDFBShared *shared; bool suspended; DirectLink *cleanups; DirectThreadInitHandler *init_handler; DirectSignalHandler *signal_handler; DirectCleanupHandler *cleanup_handler; CoreFontManager *font_manager; struct { ICoreResourceManager *manager; DirectHash *identities; } resource; FusionCall async_call; FusionCall slave_call; DirectLink *memory_permissions; DirectMutex memory_permissions_lock; int shutdown_tid; int shutdown_running; }; /**********************************************************************************************************************/ typedef enum { DFCP_CLIPBOARD = 0x00000000, DFCP_COLORHASH = 0x00000001, DFCP_GRAPHICS = 0x00000002, DFCP_INPUT = 0x00000003, DFCP_LAYER = 0x00000004, DFCP_SCREEN = 0x00000005, DFCP_SURFACE = 0x00000006, DFCP_SYSTEM = 0x00000007, DFCP_WM = 0x00000008, } CorePartID; typedef enum { CMPF_READ = 0x00000001, CMPF_WRITE = 0x00000002, } CoreMemoryPermissionFlags; typedef void (*CoreCleanupFunc)( void *data, int emergency ); typedef void (*AsyncCallFunc)( void *ctx, void *ctx2 ); typedef struct { AsyncCallFunc func; void *ctx; void *ctx2; } AsyncCall; #define CORE_TLS_IDENTITY_STACK_MAX 8 typedef struct { int magic; FusionID identity[CORE_TLS_IDENTITY_STACK_MAX]; unsigned int identity_count; int calling; } CoreTLS; /**********************************************************************************************************************/ extern CoreDFB *core_dfb; /* * Core initialization and deinitialization. */ DFBResult dfb_core_create ( CoreDFB **ret_core ); DFBResult dfb_core_destroy ( CoreDFB *core, bool emergency ); void *dfb_core_get_part ( CoreDFB *core, CorePartID part_id ); DFBResult dfb_core_initialize ( CoreDFB *core ); /* * Object creation. */ CoreGraphicsState *dfb_core_create_graphics_state ( CoreDFB *core ); CoreLayerContext *dfb_core_create_layer_context ( CoreDFB *core ); CoreLayerRegion *dfb_core_create_layer_region ( CoreDFB *core ); CorePalette *dfb_core_create_palette ( CoreDFB *core ); CoreSurface *dfb_core_create_surface ( CoreDFB *core ); CoreSurfaceAllocation *dfb_core_create_surface_allocation( CoreDFB *core ); CoreSurfaceBuffer *dfb_core_create_surface_buffer ( CoreDFB *core ); CoreSurfaceClient *dfb_core_create_surface_client ( CoreDFB *core ); CoreWindow *dfb_core_create_window ( CoreDFB *core ); /* * Object accessor. */ DFBResult dfb_core_get_graphics_state ( CoreDFB *core, u32 object_id, CoreGraphicsState **ret_state ); DFBResult dfb_core_get_layer_context ( CoreDFB *core, u32 object_id, CoreLayerContext **ret_context ); DFBResult dfb_core_get_layer_region ( CoreDFB *core, u32 object_id, CoreLayerRegion **ret_region ); DFBResult dfb_core_get_palette ( CoreDFB *core, u32 object_id, CorePalette **ret_palette ); DFBResult dfb_core_get_surface ( CoreDFB *core, u32 object_id, CoreSurface **ret_surface ); DFBResult dfb_core_get_surface_allocation ( CoreDFB *core, u32 object_id, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_core_get_surface_buffer ( CoreDFB *core, u32 object_id, CoreSurfaceBuffer **ret_surface ); DFBResult dfb_core_get_surface_client ( CoreDFB *core, u32 object_id, CoreSurfaceClient **ret_client ); DFBResult dfb_core_get_window ( CoreDFB *core, u32 object_id, CoreWindow **ret_window ); /* * Object enumeration. */ DirectResult dfb_core_enum_graphics_states ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_layer_contexts ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_layer_regions ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_palettes ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_surfaces ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_surface_allocations ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_surface_buffers ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_surface_clients ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); DirectResult dfb_core_enum_windows ( CoreDFB *core, FusionObjectCallback callback, void *ctx ); /* * Arena shared fields. */ DirectResult core_arena_add_shared_field ( CoreDFB *core, const char *name, void *data ); DirectResult core_arena_get_shared_field ( CoreDFB *core, const char *name, void **data ); /* * Returns true if the calling process is the master fusionee. */ bool dfb_core_is_master ( CoreDFB *core ); /* * Allows other (blocking) fusionees to enter the DirectFB session. */ void dfb_core_activate ( CoreDFB *core ); /* * Returns the core's fusion world. */ FusionWorld *dfb_core_world ( CoreDFB *core ); /* * Returns the shared memory pool of the core. */ FusionSHMPoolShared *dfb_core_shmpool ( CoreDFB *core ); /* * Returns the shared memory pool for raw data, e.g. surface buffers. */ FusionSHMPoolShared *dfb_core_shmpool_data ( CoreDFB *core ); /* * Suspends all core parts, stopping input threads, closing devices... */ DFBResult dfb_core_suspend ( CoreDFB *core ); /* * Resumes all core parts, reopening devices, starting input threads... */ DFBResult dfb_core_resume ( CoreDFB *core ); /* * Adds a function to the cleanup stack that is called during deinitialization. */ CoreCleanup *dfb_core_cleanup_add ( CoreDFB *core, CoreCleanupFunc func, void *data, bool emergency ); /* * Removes a function from the cleanup stack. */ void dfb_core_cleanup_remove ( CoreDFB *core, CoreCleanup *cleanup ); /* * Returns the font manager of the core. */ CoreFontManager *dfb_core_font_manager ( CoreDFB *core ); /* * Memory permissions management. */ DFBResult dfb_core_memory_permissions_add ( CoreDFB *core, CoreMemoryPermissionFlags flags, void *data, size_t length, CoreMemoryPermission **ret_permission ); DFBResult dfb_core_memory_permissions_remove( CoreDFB *core, CoreMemoryPermission *permission ); DFBResult dfb_core_memory_permissions_check ( CoreDFB *core, CoreMemoryPermissionFlags flags, void *data, size_t length ); /* * Thread Local Storage management. */ void Core_TLS__init ( void ); void Core_TLS__deinit ( void ); CoreTLS *Core_GetTLS ( void ); /* * Identity management, incoming dispatch pushes ID of caller. */ void Core_PushIdentity ( FusionID caller ); void Core_PopIdentity ( void ); FusionID Core_GetIdentity ( void ); #if FUSION_BUILD_MULTI void Core_PushCalling ( void ); void Core_PopCalling ( void ); int Core_GetCalling ( void ); #else /* FUSION_BUILD_MULTI */ #define Core_PushCalling(x) #define Core_PopCalling(x) #endif /* FUSION_BUILD_MULTI */ /* * Resource management. */ DFBResult Core_Resource_CheckSurface ( const CoreSurfaceConfig *config, u64 resource_id ); DFBResult Core_Resource_CheckSurfaceUpdate ( CoreSurface *surface, const CoreSurfaceConfig *config ); DFBResult Core_Resource_AddSurface ( CoreSurface *surface ); DFBResult Core_Resource_RemoveSurface ( CoreSurface *surface ); DFBResult Core_Resource_UpdateSurface ( CoreSurface *surface, const CoreSurfaceConfig *config ); /* * Client instance management. */ DFBResult Core_Resource_AddIdentity ( FusionID identity, u32 slave_call ); void Core_Resource_DisposeIdentity ( FusionID identity ); ICoreResourceClient *Core_Resource_GetClient ( FusionID identity ); CoreSlave *Core_Resource_GetSlave ( FusionID identity ); /* * Runs a call on the Fusion dispatch thread. * Used for asynchronous destruct, i.e. when a call needs to destroy itself. */ static __inline__ DFBResult Core_AsyncCall( AsyncCallFunc func, void *ctx, void *ctx2 ) { AsyncCall call; call.func = func; call.ctx = ctx; call.ctx2 = ctx2; return fusion_call_execute2( &core_dfb->async_call, FCEF_ONEWAY | FCEF_NODIRECT, 0, &call, sizeof(call), NULL ); } #endif ================================================ FILE: src/core/core_parts.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Core_Parts, "Core/Parts", "DirectFB Core Parts" ); /**********************************************************************************************************************/ DFBResult dfb_core_part_initialize( CoreDFB *core, CorePart *core_part ) { DFBResult ret; void *local = NULL; void *shared = NULL; FusionSHMPoolShared *pool; pool = dfb_core_shmpool( core ); if (core_part->initialized) { D_BUG( "%s already initialized", core_part->name ); return DFB_BUG; } D_DEBUG_AT( Core_Parts, "Going to initialize '%s' core...\n", core_part->name ); if (core_part->size_local) local = D_CALLOC( 1, core_part->size_local ); if (core_part->size_shared) shared = SHCALLOC( pool, 1, core_part->size_shared ); core_part->data_local = local; core_part->data_shared = shared; ret = core_part->Initialize( core, local, shared ); if (ret) { D_DERROR( ret, "Core/Parts: Could not initialize '%s' core!\n", core_part->name ); if (shared) SHFREE( pool, shared ); if (local) D_FREE( local ); core_part->data_local = NULL; core_part->data_shared = NULL; return ret; } if (shared) core_arena_add_shared_field( core, core_part->name, shared ); core_part->initialized = true; return DFB_OK; } DFBResult dfb_core_part_join( CoreDFB *core, CorePart *core_part ) { DFBResult ret; void *local = NULL; void *shared = NULL; if (core_part->initialized) { D_BUG( "%s already joined", core_part->name ); return DFB_BUG; } D_DEBUG_AT( Core_Parts, "Going to join '%s' core...\n", core_part->name ); if (core_part->size_shared && core_arena_get_shared_field( core, core_part->name, &shared )) return DFB_FUSION; if (core_part->size_local) local = D_CALLOC( 1, core_part->size_local ); ret = core_part->Join( core, local, shared ); if (ret) { D_DERROR( ret, "Core/Parts: Could not join '%s' core!\n", core_part->name ); if (local) D_FREE( local ); return ret; } core_part->data_local = local; core_part->data_shared = shared; core_part->initialized = true; return DFB_OK; } DFBResult dfb_core_part_shutdown( CoreDFB *core, CorePart *core_part, bool emergency ) { DFBResult ret; FusionSHMPoolShared *pool; pool = dfb_core_shmpool( core ); if (!core_part->initialized) return DFB_OK; D_DEBUG_AT( Core_Parts, "Going to shutdown '%s' core...\n", core_part->name ); ret = core_part->Shutdown( core_part->data_local, emergency ); if (ret) direct_messages_derror( ret, "Core/Parts: Could not shutdown '%s' core!\n", core_part->name ); if (core_part->data_shared) SHFREE( pool, core_part->data_shared ); if (core_part->data_local) D_FREE( core_part->data_local ); core_part->data_local = NULL; core_part->data_shared = NULL; core_part->initialized = false; return DFB_OK; } DFBResult dfb_core_part_leave( CoreDFB *core, CorePart *core_part, bool emergency ) { DFBResult ret; if (!core_part->initialized) return DFB_OK; D_DEBUG_AT( Core_Parts, "Going to leave '%s' core...\n", core_part->name ); ret = core_part->Leave( core_part->data_local, emergency ); if (ret) D_DERROR( ret, "Core/Parts: Could not leave '%s' core!\n", core_part->name ); if (core_part->data_local) D_FREE( core_part->data_local ); core_part->data_local = NULL; core_part->data_shared = NULL; core_part->initialized = false; return DFB_OK; } ================================================ FILE: src/core/core_parts.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORE_PARTS_H__ #define __CORE__CORE_PARTS_H__ #include /**********************************************************************************************************************/ typedef DFBResult (*CoreInitialize)( CoreDFB *core, void *data_local, void *data_shared ); typedef DFBResult (*CoreJoin) ( CoreDFB *core, void *data_local, void *data_shared ); typedef DFBResult (*CoreShutdown) ( void *data_local, bool emergency ); typedef DFBResult (*CoreLeave) ( void *data_local, bool emergency ); typedef DFBResult (*CoreSuspend) ( void *data_local ); typedef DFBResult (*CoreResume) ( void *data_local ); typedef struct { const char *name; int size_local; int size_shared; CoreInitialize Initialize; CoreJoin Join; CoreShutdown Shutdown; CoreLeave Leave; CoreSuspend Suspend; CoreResume Resume; void *data_local; void *data_shared; bool initialized; } CorePart; /**********************************************************************************************************************/ DFBResult dfb_core_part_initialize( CoreDFB *core, CorePart *core_part ); DFBResult dfb_core_part_join ( CoreDFB *core, CorePart *core_part ); DFBResult dfb_core_part_shutdown ( CoreDFB *core, CorePart *core_part, bool emergency ); DFBResult dfb_core_part_leave ( CoreDFB *core, CorePart *core_part, bool emergency ); #define DFB_CORE_PART(part,Type) \ \ static DFBResult dfb_##part##_initialize( CoreDFB *core, \ DFB##Type *local, \ DFB##Type##Shared *shared ); \ \ static DFBResult dfb_##part##_join ( CoreDFB *core, \ DFB##Type *local, \ DFB##Type##Shared *shared ); \ \ static DFBResult dfb_##part##_shutdown ( DFB##Type *local, \ bool emergency ); \ \ static DFBResult dfb_##part##_leave ( DFB##Type *local, \ bool emergency ); \ \ static DFBResult dfb_##part##_suspend ( DFB##Type *local ); \ \ static DFBResult dfb_##part##_resume ( DFB##Type *local ); \ \ CorePart dfb_##part = { \ .name = #part, \ \ .size_local = sizeof(DFB##Type), \ .size_shared = sizeof(DFB##Type##Shared), \ \ .Initialize = (void*) dfb_##part##_initialize, \ .Join = (void*) dfb_##part##_join, \ .Shutdown = (void*) dfb_##part##_shutdown, \ .Leave = (void*) dfb_##part##_leave, \ .Suspend = (void*) dfb_##part##_suspend, \ .Resume = (void*) dfb_##part##_resume, \ } #endif ================================================ FILE: src/core/core_resourcemanager.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORE_RESOURCEMANAGER_H__ #define __CORE__CORE_RESOURCEMANAGER_H__ #include #include /* * Resource manager interface. */ D_DECLARE_INTERFACE( ICoreResourceManager ) D_DECLARE_INTERFACE( ICoreResourceClient ) /************************ * ICoreResourceManager * ************************/ /* * ICoreResourceManager is the resource manager interface. */ D_DEFINE_INTERFACE( ICoreResourceManager, /** Creating client **/ /* * Create a new client instance (called within master, * per slave). */ DFBResult (*CreateClient) ( ICoreResourceManager *thiz, FusionID identity, ICoreResourceClient **ret_client ); ) /* * ICoreResourceClient per slave resource accounting. */ D_DEFINE_INTERFACE( ICoreResourceClient, /** Tracking of the resource client instance **/ /* * Check surface creation. */ DFBResult (*CheckSurface) ( ICoreResourceClient *thiz, const CoreSurfaceConfig *config, u64 resource_id ); /* * Check surface reconfig. */ DFBResult (*CheckSurfaceUpdate) ( ICoreResourceClient *thiz, CoreSurface *surface, const CoreSurfaceConfig *config ); /* * Add surface. */ DFBResult (*AddSurface) ( ICoreResourceClient *thiz, CoreSurface *surface ); /* * Remove surface. */ DFBResult (*RemoveSurface) ( ICoreResourceClient *thiz, CoreSurface *surface ); /* * Update surface. */ DFBResult (*UpdateSurface) ( ICoreResourceClient *thiz, CoreSurface *surface, const CoreSurfaceConfig *config ); ) #endif ================================================ FILE: src/core/core_system.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORE_SYSTEM_H__ #define __CORE__CORE_SYSTEM_H__ #include /**********************************************************************************************************************/ static void system_get_info ( CoreSystemInfo *info ); static DFBResult system_initialize ( CoreDFB *core, void **ret_data ); static DFBResult system_join ( CoreDFB *core, void **ret_data ); static DFBResult system_shutdown ( bool emergency ); static DFBResult system_leave ( bool emergency ); static DFBResult system_suspend ( void ); static DFBResult system_resume ( void ); static VideoMode *system_get_modes ( void ); static VideoMode *system_get_current_mode ( void ); static DFBResult system_thread_init ( void ); static bool system_input_filter ( CoreInputDevice *device, DFBInputEvent *event ); static volatile void *system_map_mmio ( unsigned int offset, int length ); static void system_unmap_mmio ( volatile void *addr, int length ); static unsigned int system_get_accelerator ( void ); static unsigned long system_video_memory_physical( unsigned int offset ); static void *system_video_memory_virtual ( unsigned int offset ); static unsigned int system_videoram_length ( void ); static void system_get_busid ( int *ret_bus, int *ret_dev, int *ret_func ); static void system_get_deviceid ( unsigned int *ret_vendor_id, unsigned int *ret_device_id ); static CoreSystemFuncs system_funcs = { .GetSystemInfo = system_get_info, .Initialize = system_initialize, .Join = system_join, .Shutdown = system_shutdown, .Leave = system_leave, .Suspend = system_suspend, .Resume = system_resume, .GetModes = system_get_modes, .GetCurrentMode = system_get_current_mode, .ThreadInit = system_thread_init, .InputFilter = system_input_filter, .MapMMIO = system_map_mmio, .UnmapMMIO = system_unmap_mmio, .GetAccelerator = system_get_accelerator, .VideoMemoryPhysical = system_video_memory_physical, .VideoMemoryVirtual = system_video_memory_virtual, .VideoRamLength = system_videoram_length, .GetBusID = system_get_busid, .GetDeviceID = system_get_deviceid }; #define DFB_CORE_SYSTEM(shortname) \ \ __dfb_constructor__ \ void \ directfb_##shortname##_ctor( void ) \ { \ direct_modules_register( &dfb_core_systems, \ DFB_CORE_SYSTEM_ABI_VERSION, \ #shortname, \ &system_funcs ); \ } #endif ================================================ FILE: src/core/coredefs.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__COREDEFS_H__ #define __CORE__COREDEFS_H__ #define MAX_INPUT_GLOBALS 8 #define MAX_INPUTDEVICES 16 #define MAX_LAYERS 24 #define MAX_SCREENS 4 #define MAX_SURFACE_BUFFERS 6 #define MAX_SURFACE_POOLS 8 #define MAX_SURFACE_POOL_BRIDGES 4 #define MAX_CLIPBOARD_MIME_TYPE_SIZE (128) #define MAX_CLIPBOARD_DATA_SIZE (48*1024) #endif ================================================ FILE: src/core/coretypes.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__CORETYPES_H__ #define __CORE__CORETYPES_H__ #include #include /**********************************************************************************************************************/ typedef struct __DFB_CardState CardState; typedef struct __DFB_CoreCleanup CoreCleanup; typedef struct __DFB_CoreDFB CoreDFB; typedef struct __DFB_CoreGraphicsState CoreGraphicsState; typedef struct __DFB_CoreGraphicsStateClient CoreGraphicsStateClient; typedef struct __DFB_CoreFont CoreFont; typedef struct __DFB_CoreFontCache CoreFontCache; typedef struct __DFB_CoreFontCacheRow CoreFontCacheRow; typedef struct __DFB_CoreFontManager CoreFontManager; typedef struct __DFB_CoreGlyphData CoreGlyphData; typedef struct __DFB_CoreInputDevice CoreInputDevice; typedef struct __DFB_CoreLayer CoreLayer; typedef struct __DFB_CoreLayerContext CoreLayerContext; typedef struct __DFB_CoreLayerRegion CoreLayerRegion; typedef struct __DFB_CoreMemoryPermission CoreMemoryPermission; typedef struct __DFB_CorePalette CorePalette; typedef struct __DFB_CoreScreen CoreScreen; typedef struct __DFB_CoreSurface CoreSurface; typedef struct __DFB_CoreSurfaceAllocation CoreSurfaceAllocation; typedef struct __DFB_CoreSurfaceBuffer CoreSurfaceBuffer; typedef struct __DFB_CoreSurfaceBufferLock CoreSurfaceBufferLock; typedef struct __DFB_CoreSurfaceClient CoreSurfaceClient; typedef struct __DFB_CoreSurfaceConfig CoreSurfaceConfig; typedef struct __DFB_CoreSurfacePool CoreSurfacePool; typedef struct __DFB_CoreSurfacePoolBridge CoreSurfacePoolBridge; typedef struct __DFB_CoreWindow CoreWindow; typedef struct __DFB_CoreWindowConfig CoreWindowConfig; typedef struct __DFB_CoreWindowStack CoreWindowStack; typedef struct __DFB_GenefxState GenefxState; typedef struct __DFB_GraphicsDeviceInfo GraphicsDeviceInfo; typedef struct __DFB_GraphicsDriverInfo GraphicsDriverInfo; /**********************************************************************************************************************/ typedef struct { unsigned int serial; unsigned int generation; } CoreGraphicsSerial; /**********************************************************************************************************************/ typedef enum { CWMGT_KEYBOARD = 0x00000000, CWMGT_POINTER = 0x00000001, CWMGT_KEY = 0x00000002, CWMGT_UNSELECTED_KEYS = 0x00000003, } CoreWMGrabTarget; /**********************************************************************************************************************/ typedef enum { CSAID_NONE = 0x00000000, /* none or unknown accessor */ CSAID_CPU = 0x00000001, /* local processor */ CSAID_GPU = 0x00000002, /* primary accelerator, as in traditional 'gfxcard' core (ACCEL0) */ CSAID_ACCEL0 = 0x00000002, /* accelerators, decoders (CSAID_ACCEL0 + accel_id<0-5>) */ CSAID_ACCEL1 = 0x00000003, CSAID_ACCEL2 = 0x00000004, CSAID_ACCEL3 = 0x00000005, CSAID_ACCEL4 = 0x00000006, CSAID_ACCEL5 = 0x00000007, CSAID_LAYER0 = 0x00000008, /* display layers (CSAID_LAYER0 + layer_id<0-MAX_LAYERS>) */ CSAID_LAYER1 = 0x00000009, CSAID_LAYER2 = 0x0000000a, CSAID_LAYER3 = 0x0000000b, CSAID_LAYER4 = 0x0000000c, CSAID_LAYER5 = 0x0000000d, CSAID_LAYER6 = 0x0000000e, CSAID_LAYER7 = 0x0000000f, CSAID_LAYER8 = 0x00000010, CSAID_LAYER9 = 0x00000011, CSAID_LAYER10 = 0x00000012, CSAID_LAYER11 = 0x00000013, CSAID_LAYER12 = 0x00000014, CSAID_LAYER13 = 0x00000015, CSAID_LAYER14 = 0x00000016, CSAID_LAYER15 = 0x00000017, CSAID_NUM = 0x00000018, /* number of statically assigned IDs for usage in static arrays */ CSAID_ANY = 0x00000100 /* any other accessor needs to be registered using IDs starting from here */ } CoreSurfaceAccessorID; typedef unsigned int CoreSurfacePoolID; typedef unsigned int CoreSurfacePoolBridgeID; #endif ================================================ FILE: src/core/cursor.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ static const unsigned int cursor_data[] = { 0xe8fdfdfd, 0x83e8e8e8, 0x40d3d3d3, 0x1ed0d0d0, 0x15dddddd, 0x10ebebeb, 0x0af3f3f3, 0x05f8f8f8, 0x02fbfbfb, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xd9fcfcfc, 0xefffffff, 0xd0f9f9f9, 0x96e2e2e2, 0x51cccccc, 0x23cbcbcb, 0x15dadada, 0x0fe9e9e9, 0x0af2f2f2, 0x05f8f8f8, 0x02fbfbfb, 0x02fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xa1e0e0e0, 0xdaffffff, 0xedffffff, 0xd6ffffff, 0xd0fafafa, 0x9be3e3e3, 0x56cccccc, 0x25c9c9c9, 0x15d8d8d8, 0x10e7e7e7, 0x0af1f1f1, 0x06f7f7f7, 0x03fbfbfb, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x67b7b7b7, 0xd5fbfbfb, 0xd6ffffff, 0xebffffff, 0xd2ffffff, 0xcfffffff, 0xccfdfdfd, 0x9fe7e7e7, 0x5bcfcfcf, 0x28c9c9c9, 0x15d6d6d6, 0x10e7e7e7, 0x0af1f1f1, 0x06f7f7f7, 0x03fbfbfb, 0x01fdfdfd, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x44a5a5a5, 0xb1d9d9d9, 0xd4ffffff, 0xd2ffffff, 0xe9ffffff, 0xceffffff, 0xccffffff, 0xc9ffffff, 0xc7fefefe, 0xa1ebebeb, 0x62d3d3d3, 0x2dcacaca, 0x15d4d4d4, 0x0fe5e5e5, 0x0af1f1f1, 0x06f7f7f7, 0x03fafafa, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x36b3b3b3, 0x78ababab, 0xd1fdfdfd, 0xcfffffff, 0xceffffff, 0xccffffff, 0xcaffffff, 0xc7ffffff, 0xc5ffffff, 0xc2ffffff, 0xc0ffffff, 0xa7f0f0f0, 0x69d6d6d6, 0x30c9c9c9, 0x15d3d3d3, 0x0fe4e4e4, 0x0af0f0f0, 0x05f6f6f6, 0x03fbfbfb, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x2ac9c9c9, 0x4e999999, 0xb4dcdcdc, 0xcdffffff, 0xccffffff, 0xcaffffff, 0xc7ffffff, 0xc6ffffff, 0xc3ffffff, 0xc1ffffff, 0xbfffffff, 0xbcffffff, 0xb9ffffff, 0xa4f2f2f2, 0x68d8d8d8, 0x2fcacaca, 0x14d3d3d3, 0x0ee5e5e5, 0x09f1f1f1, 0x05f7f7f7, 0x03fbfbfb, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x1ed9d9d9, 0x39aaaaaa, 0x80acacac, 0xcafefefe, 0xc9ffffff, 0xc7ffffff, 0xc6ffffff, 0xc4ffffff, 0xc1ffffff, 0xbfffffff, 0xbdffffff, 0xbaffffff, 0xb8ffffff, 0xb6ffffff, 0xb3ffffff, 0x9ff3f3f3, 0x67d9d9d9, 0x2ccbcbcb, 0x13d4d4d4, 0x0ee6e6e6, 0x09f1f1f1, 0x05f7f7f7, 0x02fbfbfb, 0x01fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x14e5e5e5, 0x2dc3c3c3, 0x53959595, 0xb4e2e2e2, 0xc7ffffff, 0xc5ffffff, 0xc3ffffff, 0xc1ffffff, 0xbfffffff, 0xbeffffff, 0xbbffffff, 0xb9ffffff, 0xb7ffffff, 0xb4ffffff, 0xb1ffffff, 0xafffffff, 0xacffffff, 0x98f2f2f2, 0x5fd9d9d9, 0x29cbcbcb, 0x10d6d6d6, 0x0ce7e7e7, 0x08f2f2f2, 0x04f8f8f8, 0x02fcfcfc, 0x01fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x0deeeeee, 0x21d5d5d5, 0x3ca3a3a3, 0x85afafaf, 0xc4ffffff, 0xc2ffffff, 0xc1ffffff, 0xbfffffff, 0xbeffffff, 0xbbffffff, 0xb9ffffff, 0xb7ffffff, 0xb5ffffff, 0xb2ffffff, 0xb0ffffff, 0xaeffffff, 0xabffffff, 0xa9ffffff, 0xa6ffffff, 0x90f2f2f2, 0x58d8d8d8, 0x23cccccc, 0x0fd8d8d8, 0x0be9e9e9, 0x07f3f3f3, 0x03f9f9f9, 0x02fcfcfc, 0x01fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x08f5f5f5, 0x16e2e2e2, 0x2fbebebe, 0x57939393, 0xb3e7e7e7, 0xc0ffffff, 0xbfffffff, 0xbdffffff, 0xbbffffff, 0xb9ffffff, 0xb8ffffff, 0xb5ffffff, 0xb3ffffff, 0xb0ffffff, 0xafffffff, 0xacffffff, 0xa9ffffff, 0xa7ffffff, 0xa4ffffff, 0xa1ffffff, 0xa0ffffff, 0x87f0f0f0, 0x4ed6d6d6, 0x1dcdcdcd, 0x0ddcdcdc, 0x0aececec, 0x06f5f5f5, 0x03fafafa, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x05f9f9f9, 0x0eececec, 0x22d1d1d1, 0x3d9e9e9e, 0x88b4b4b4, 0xbeffffff, 0xbcffffff, 0xbaffffff, 0xb9ffffff, 0xb7ffffff, 0xb5ffffff, 0xb3ffffff, 0xb1ffffff, 0xafffffff, 0xadffffff, 0xaaffffff, 0xa8ffffff, 0xa6ffffff, 0xa3ffffff, 0xa1ffffff, 0x9effffff, 0x9bffffff, 0x99ffffff, 0x7bececec, 0x3fd3d3d3, 0x16d0d0d0, 0x0be1e1e1, 0x08f0f0f0, 0x04f8f8f8, 0x02fcfcfc, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x02fcfcfc, 0x08f4f4f4, 0x18dfdfdf, 0x30b9b9b9, 0x5c949494, 0xb3efefef, 0xb9ffffff, 0xb8ffffff, 0xb7ffffff, 0xb5ffffff, 0xb3ffffff, 0xb1ffffff, 0xafffffff, 0xadffffff, 0xaaffffff, 0xa9ffffff, 0xa6ffffff, 0xa4ffffff, 0xa1ffffff, 0x9fffffff, 0x9cffffff, 0x9affffff, 0x98ffffff, 0x95ffffff, 0x92fdfdfd, 0x6ae6e6e6, 0x2ed0d0d0, 0x0fd6d6d6, 0x0ae9e9e9, 0x06f4f4f4, 0x02fafafa, 0x01fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fefefe, 0x04f8f8f8, 0x0feaeaea, 0x24cdcdcd, 0x41989898, 0x8dbcbcbc, 0xb7ffffff, 0xb6ffffff, 0xb4ffffff, 0xb2ffffff, 0xb0ffffff, 0xafffffff, 0xadffffff, 0xabffffff, 0xa9ffffff, 0xa7ffffff, 0xa4ffffff, 0xa2ffffff, 0xa0ffffff, 0x9dffffff, 0x9bffffff, 0x99ffffff, 0x96ffffff, 0x93ffffff, 0x91ffffff, 0x8effffff, 0x84f9f9f9, 0x51dedede, 0x1ad0d0d0, 0x0ae1e1e1, 0x07f2f2f2, 0x02f9f9f9, 0x00fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x02fcfcfc, 0x09f2f2f2, 0x18dddddd, 0x31b3b3b3, 0x5f929292, 0xaff1f1f1, 0xb3ffffff, 0xb1ffffff, 0xb0ffffff, 0xafffffff, 0xadffffff, 0xaaffffff, 0xa9ffffff, 0xa7ffffff, 0xa5ffffff, 0xa2ffffff, 0xa1ffffff, 0x9effffff, 0x9bffffff, 0x9affffff, 0x97ffffff, 0x94ffffff, 0x92ffffff, 0x90ffffff, 0x8dffffff, 0x8bffffff, 0x88ffffff, 0x6ceeeeee, 0x2cd3d3d3, 0x0bdcdcdc, 0x07f0f0f0, 0x02f9f9f9, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x05f7f7f7, 0x10e8e8e8, 0x25c9c9c9, 0x42929292, 0x8bbebebe, 0xb0ffffff, 0xafffffff, 0xaeffffff, 0xacffffff, 0xaaffffff, 0xa9ffffff, 0xa7ffffff, 0xa5ffffff, 0xa2ffffff, 0xa1ffffff, 0x9effffff, 0x9cffffff, 0x9affffff, 0x98ffffff, 0x95ffffff, 0x92ffffff, 0x91ffffff, 0x8effffff, 0x8bffffff, 0x89ffffff, 0x86ffffff, 0x83ffffff, 0x78f8f8f8, 0x30d6d6d6, 0x0adddddd, 0x07f2f2f2, 0x02fafafa, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x02fbfbfb, 0x0af1f1f1, 0x1adadada, 0x33adadad, 0x60909090, 0xaaf2f2f2, 0xacffffff, 0xabffffff, 0xa9ffffff, 0xa8ffffff, 0xa6ffffff, 0xa4ffffff, 0xa2ffffff, 0xa1ffffff, 0x9fffffff, 0x9cffffff, 0x9affffff, 0x98ffffff, 0x96ffffff, 0x93ffffff, 0x92ffffff, 0x8fffffff, 0x8cffffff, 0x8affffff, 0x88ffffff, 0x85ffffff, 0x83ffffff, 0x80ffffff, 0x72f6f6f6, 0x24d1d1d1, 0x09e2e2e2, 0x05f5f5f5, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x05f7f7f7, 0x11e6e6e6, 0x26c6c6c6, 0x428f8f8f, 0x87bcbcbc, 0xa9ffffff, 0xa9ffffff, 0xa7ffffff, 0xa6ffffff, 0xa4ffffff, 0xa2ffffff, 0xa1ffffff, 0x9effffff, 0x9cffffff, 0x9affffff, 0x99ffffff, 0x96ffffff, 0x94ffffff, 0x92ffffff, 0x90ffffff, 0x8dffffff, 0x8bffffff, 0x88ffffff, 0x86ffffff, 0x83ffffff, 0x81ffffff, 0x7effffff, 0x7cffffff, 0x60ebebeb, 0x14d0d0d0, 0x08ebebeb, 0x03f9f9f9, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x03fbfbfb, 0x0af0f0f0, 0x1bd7d7d7, 0x33ababab, 0x5d8d8d8d, 0xa2f1f1f1, 0xa6ffffff, 0xa4ffffff, 0xa3ffffff, 0xa1ffffff, 0xa0ffffff, 0x9effffff, 0x9cffffff, 0x9affffff, 0x99ffffff, 0x96ffffff, 0x94ffffff, 0x92ffffff, 0x90ffffff, 0x8dffffff, 0x8bffffff, 0x89ffffff, 0x87ffffff, 0x84ffffff, 0x82ffffff, 0x7fffffff, 0x7dffffff, 0x7bffffff, 0x78fefefe, 0x36d6d6d6, 0x0adcdcdc, 0x05f4f4f4, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x06f6f6f6, 0x12e3e3e3, 0x27c3c3c3, 0x428c8c8c, 0x82bababa, 0xa3ffffff, 0xa1ffffff, 0xa1ffffff, 0x9fffffff, 0x9dffffff, 0x9bffffff, 0x9affffff, 0x98ffffff, 0x96ffffff, 0x94ffffff, 0x92ffffff, 0x90ffffff, 0x8effffff, 0x8bffffff, 0x8affffff, 0x87ffffff, 0x85ffffff, 0x83ffffff, 0x80ffffff, 0x7effffff, 0x7cffffff, 0x79ffffff, 0x76ffffff, 0x59e8e8e8, 0x12d0d0d0, 0x07ededed, 0x02fafafa, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x03fafafa, 0x0bededed, 0x1bd5d5d5, 0x33a8a8a8, 0x5a898989, 0x9df0f0f0, 0xa0ffffff, 0x9effffff, 0x9cffffff, 0x9bffffff, 0x9affffff, 0x98ffffff, 0x96ffffff, 0x94ffffff, 0x92ffffff, 0x90ffffff, 0x8effffff, 0x8cffffff, 0x8affffff, 0x88ffffff, 0x85ffffff, 0x83ffffff, 0x81ffffff, 0x7effffff, 0x7cffffff, 0x7affffff, 0x77ffffff, 0x74ffffff, 0x6df7f7f7, 0x1fcacaca, 0x09e5e5e5, 0x03f8f8f8, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x06f5f5f5, 0x12e2e2e2, 0x26c2c2c2, 0x40898989, 0x7db5b5b5, 0x9dffffff, 0x9bffffff, 0x9affffff, 0x99ffffff, 0x97ffffff, 0x95ffffff, 0x93ffffff, 0x92ffffff, 0x90ffffff, 0x8effffff, 0x8cffffff, 0x8affffff, 0x88ffffff, 0x85ffffff, 0x83ffffff, 0x81ffffff, 0x7fffffff, 0x7cffffff, 0x7bffffff, 0x78ffffff, 0x75ffffff, 0x74ffffff, 0x71fdfdfd, 0x2dcdcdcd, 0x0adedede, 0x04f5f5f5, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x03fafafa, 0x0bededed, 0x1bd3d3d3, 0x32a7a7a7, 0x56848484, 0x95ededed, 0x99ffffff, 0x98ffffff, 0x96ffffff, 0x94ffffff, 0x92ffffff, 0x92ffffff, 0x90ffffff, 0x8dffffff, 0x8bffffff, 0x8affffff, 0x88ffffff, 0x86ffffff, 0x83ffffff, 0x82ffffff, 0x7fffffff, 0x7dffffff, 0x7bffffff, 0x79ffffff, 0x76ffffff, 0x74ffffff, 0x72ffffff, 0x6ffefefe, 0x35cfcfcf, 0x0bd8d8d8, 0x05f3f3f3, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fcfcfc, 0x06f5f5f5, 0x12e2e2e2, 0x25c1c1c1, 0x3e888888, 0x75acacac, 0x96ffffff, 0x95ffffff, 0x93ffffff, 0x92ffffff, 0x91ffffff, 0x8fffffff, 0x8dffffff, 0x8bffffff, 0x8affffff, 0x88ffffff, 0x85ffffff, 0x83ffffff, 0x82ffffff, 0x80ffffff, 0x7dffffff, 0x7cffffff, 0x79ffffff, 0x77ffffff, 0x74ffffff, 0x72ffffff, 0x70ffffff, 0x6dfefefe, 0x35cccccc, 0x0cd6d6d6, 0x05f2f2f2, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fefefe, 0x04f9f9f9, 0x0bececec, 0x1ad3d3d3, 0x30a8a8a8, 0x517e7e7e, 0x8ce5e5e5, 0x92ffffff, 0x91ffffff, 0x90ffffff, 0x8effffff, 0x8cffffff, 0x8bffffff, 0x89ffffff, 0x87ffffff, 0x85ffffff, 0x83ffffff, 0x82ffffff, 0x80ffffff, 0x7dffffff, 0x7cffffff, 0x79ffffff, 0x77ffffff, 0x74ffffff, 0x73ffffff, 0x70ffffff, 0x6effffff, 0x6cfdfdfd, 0x2fc4c4c4, 0x0dd7d7d7, 0x05f2f2f2, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fcfcfc, 0x06f5f5f5, 0x11e2e2e2, 0x24c1c1c1, 0x3b898989, 0x6b9f9f9f, 0x90ffffff, 0x8effffff, 0x8dffffff, 0x8bffffff, 0x8affffff, 0x88ffffff, 0x87ffffff, 0x85ffffff, 0x83ffffff, 0x81ffffff, 0x7fffffff, 0x7dffffff, 0x7cffffff, 0x7affffff, 0x77ffffff, 0x75ffffff, 0x73ffffff, 0x71ffffff, 0x6effffff, 0x6dffffff, 0x65f5f5f5, 0x23bbbbbb, 0x0cdbdbdb, 0x05f4f4f4, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fefefe, 0x03f9f9f9, 0x0aededed, 0x18d4d4d4, 0x2eaaaaaa, 0x4a797979, 0x81d6d6d6, 0x8bffffff, 0x8bffffff, 0x89ffffff, 0x88ffffff, 0x86ffffff, 0x84ffffff, 0x83ffffff, 0x81ffffff, 0x7fffffff, 0x7dffffff, 0x7cffffff, 0x79ffffff, 0x77ffffff, 0x75ffffff, 0x73ffffff, 0x71ffffff, 0x6fffffff, 0x6dffffff, 0x6bffffff, 0x53dfdfdf, 0x19bababa, 0x0be2e2e2, 0x03f5f5f5, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fcfcfc, 0x06f5f5f5, 0x0fe3e3e3, 0x21c2c2c2, 0x378e8e8e, 0x5e8b8b8b, 0x88fafafa, 0x88ffffff, 0x86ffffff, 0x85ffffff, 0x83ffffff, 0x82ffffff, 0x80ffffff, 0x7effffff, 0x7cffffff, 0x7bffffff, 0x79ffffff, 0x77ffffff, 0x75ffffff, 0x73ffffff, 0x71ffffff, 0x6fffffff, 0x6dffffff, 0x6bffffff, 0x68ffffff, 0x39bebebe, 0x12c3c3c3, 0x08e8e8e8, 0x02f8f8f8, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fefefe, 0x03fafafa, 0x09eeeeee, 0x16d6d6d6, 0x2aafafaf, 0x42777777, 0x71b8b8b8, 0x85ffffff, 0x83ffffff, 0x83ffffff, 0x81ffffff, 0x7fffffff, 0x7effffff, 0x7cffffff, 0x7bffffff, 0x79ffffff, 0x77ffffff, 0x74ffffff, 0x73ffffff, 0x71ffffff, 0x6fffffff, 0x6dffffff, 0x6bffffff, 0x69ffffff, 0x57e0e0e0, 0x20ababab, 0x0fd5d5d5, 0x06efefef, 0x02fbfbfb, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x05f6f6f6, 0x0ee5e5e5, 0x1dc7c7c7, 0x32999999, 0x4e757575, 0x7ce0e0e0, 0x81ffffff, 0x80ffffff, 0x7effffff, 0x7dffffff, 0x7cffffff, 0x7affffff, 0x78ffffff, 0x76ffffff, 0x74ffffff, 0x73ffffff, 0x71ffffff, 0x6fffffff, 0x6dffffff, 0x6bffffff, 0x69ffffff, 0x62f4f4f4, 0x32a9a9a9, 0x16bdbdbd, 0x0be3e3e3, 0x04f5f5f5, 0x01fcfcfc, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x02fafafa, 0x07f1f1f1, 0x12dcdcdc, 0x23bababa, 0x37878787, 0x56808080, 0x7be9e9e9, 0x7dffffff, 0x7cffffff, 0x7bffffff, 0x79ffffff, 0x77ffffff, 0x75ffffff, 0x74ffffff, 0x72ffffff, 0x70ffffff, 0x6effffff, 0x6dffffff, 0x6bffffff, 0x69ffffff, 0x64f6f6f6, 0x3dacacac, 0x1cababab, 0x0fd6d6d6, 0x06eeeeee, 0x02f9f9f9, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fdfdfd, 0x04f8f8f8, 0x0aebebeb, 0x16d3d3d3, 0x27b1b1b1, 0x397e7e7e, 0x54777777, 0x72d2d2d2, 0x7affffff, 0x78ffffff, 0x76ffffff, 0x74ffffff, 0x74ffffff, 0x72ffffff, 0x70ffffff, 0x6effffff, 0x6dffffff, 0x6bffffff, 0x68ffffff, 0x5ee3e3e3, 0x3d9e9e9e, 0x1fa1a1a1, 0x13cdcdcd, 0x09e7e7e7, 0x03f6f6f6, 0x01fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x01fcfcfc, 0x05f5f5f5, 0x0ce6e6e6, 0x18cdcdcd, 0x28adadad, 0x37808080, 0x49666666, 0x629b9b9b, 0x70dfdfdf, 0x74fefefe, 0x73ffffff, 0x71ffffff, 0x6fffffff, 0x6dffffff, 0x6cffffff, 0x6affffff, 0x63e6e6e6, 0x4fb1b1b1, 0x34898989, 0x219f9f9f, 0x14c8c8c8, 0x0ae3e3e3, 0x04f3f3f3, 0x01fbfbfb, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x02fafafa, 0x06f3f3f3, 0x0de4e4e4, 0x17cecece, 0x24b3b3b3, 0x31919191, 0x3d6d6d6d, 0x49666666, 0x56838383, 0x5ea4a4a4, 0x61bababa, 0x61c2c2c2, 0x5ebdbdbd, 0x57acacac, 0x4a929292, 0x397d7d7d, 0x2a888888, 0x1eababab, 0x14cbcbcb, 0x0be1e1e1, 0x05f1f1f1, 0x02fafafa, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x02fafafa, 0x06f3f3f3, 0x0be6e6e6, 0x13d5d5d5, 0x1dc0c0c0, 0x26a9a9a9, 0x2f929292, 0x347b7b7b, 0x386c6c6c, 0x3a6b6b6b, 0x3a6e6e6e, 0x36717171, 0x30787878, 0x298c8c8c, 0x21a5a5a5, 0x19bebebe, 0x11d3d3d3, 0x0ae5e5e5, 0x05f2f2f2, 0x02fafafa, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x02fbfbfb, 0x04f5f5f5, 0x08ededed, 0x0de0e0e0, 0x14d2d2d2, 0x19c4c4c4, 0x1eb8b8b8, 0x22afafaf, 0x23a9a9a9, 0x22a9a9a9, 0x20aeaeae, 0x1cb8b8b8, 0x17c4c4c4, 0x11d2d2d2, 0x0ce0e0e0, 0x07ececec, 0x04f5f5f5, 0x01fbfbfb, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x01fcfcfc, 0x03f9f9f9, 0x05f4f4f4, 0x08ededed, 0x0be5e5e5, 0x0ededede, 0x0fd9d9d9, 0x11d6d6d6, 0x10d6d6d6, 0x0fd9d9d9, 0x0ddedede, 0x09e5e5e5, 0x07ededed, 0x04f4f4f4, 0x02f9f9f9, 0x01fcfcfc, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x01fcfcfc, 0x02fafafa, 0x03f7f7f7, 0x04f4f4f4, 0x05f2f2f2, 0x06f1f1f1, 0x06f1f1f1, 0x05f2f2f2, 0x04f4f4f4, 0x03f7f7f7, 0x02fafafa, 0x01fcfcfc, 0x00fdfdfd, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00fefefe, 0x01fdfdfd, 0x01fcfcfc, 0x01fcfcfc, 0x01fcfcfc, 0x01fcfcfc, 0x01fcfcfc, 0x01fcfcfc, 0x01fdfdfd, 0x00fefefe, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, }; ================================================ FILE: src/core/fluxcomp.py ================================================ #!/bin/env python3 license = """ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ """ import argparse parser = argparse.ArgumentParser(description="Flux Compiler Tool") parser.add_argument("filename") parser.add_argument("-c", "--generate-c", action="store_true", required=True, help="Generate C code") parser.add_argument("-i", "--identity", action="store_true", help="Generate caller identity tracking code") parser.add_argument("--object-ptrs", action="store_true", required=True, help="Return object pointers rather than IDs") parser.add_argument("--call-mode", action="store_true", required=True, help="Use call mode function to determine call mode") parser.add_argument("-p", "--include-prefix", required=True, help="Override standard include prefix for includes") parser.add_argument("--static-args-bytes", default=1000, help="Override standard limit (1000) for stack based arguments") parser.add_argument("--dispatch-error-abort", action="store_true", help="Abort execution when object lookups fail") parser.add_argument("-o", dest="output_dir", default="", help="Write to output directory") # -------------------------------------------------------------------------------------------------------------------------- class Entity: def __init__(self): self.position = 0 self.entities = [] class Interface(Entity): def SetProperty(self, name, value): if name == "name": self.name = value elif name == "object": self.object = value self.dispatch = value elif name == "dispatch": self.dispatch = value class Method(Entity): sync = True queue = False def SetProperty(self, name, value): if name == "name": self.name = value elif name == "async": self.sync = not value == "yes" elif name == "queue": self.queue = value == "yes" def ArgumentsAsParamDecl(self): result = "" first = True for arg in self.entities: result += "" if first else ",\n" if arg.type == "struct": if arg.direction == "input": result += f" {'const ' + arg.type_name:<40} *{arg.name}" else: result += f" {arg.type_name:<40} *ret_{arg.name}" elif arg.type == "enum" or arg.type == "int": if arg.direction == "input": if arg.array: result += f" {'const ' + arg.type_name:<40} *{arg.name}" else: result += f" {arg.type_name:<40} {arg.name}" else: result += f" {arg.type_name:<40} *ret_{arg.name}" else: if arg.direction == "input": result += f" {arg.type_name:<40} *{arg.name}" else: result += f" {arg.type_name:<40} **ret_{arg.name}" if first: first = False return result def ArgumentsAsMemberDecl(self): result = "" for arg in self.entities: if arg.array: continue if arg.direction == "input": if arg.optional: result += f" bool {arg.name}_set;\n" if arg.type == "struct" or arg.type == "enum" or arg.type == "int": result += f" {arg.type_name:<40} {arg.name};\n" else: result += f" u32 {arg.name}_id;\n" for arg in self.entities: if not arg.array: continue if arg.direction == "input": if arg.optional: result += f" bool {arg.name}_set;\n" result += f" /* '{arg.count}' {arg.type_name} follow ({arg.name}) */\n" return result def ArgumentsOutputAsMemberDecl(self): result = " DFBResult result;\n" for arg in self.entities: if arg.array: continue if arg.direction == "output": if arg.type == "struct" or arg.type == "enum" or arg.type == "int": result += f" {arg.type_name:<40} {arg.name};\n" else: result += f" u32 {arg.name}_id;\n" \ f" void* {arg.name}_ptr;\n" for arg in self.entities: if not arg.array: continue if arg.direction == "output": result += f" /* '{arg.count}' {arg.type_name} follow ({arg.name}) */\n" return result def ArgumentsAsMemberParams(self): result = "" first = True second_output_array = False for arg in self.entities: if first: first = False else: result += ", " if arg.direction == "input": if arg.optional: result += f"args->{arg.name}_set ? " if arg.array: result += f"({arg.type_name}*) ((char*)(args + 1){arg.offset(self, True, False)})" else: if arg.type == "struct": result += f"&args->{arg.name}" elif arg.type == "enum" or arg.type == "int": result += f"args->{arg.name}" else: result += f"{arg.name}" if arg.optional: result += " : NULL" if arg.direction == "output": if arg.array: if second_output_array: result += f"tmp_{arg.name}" else: result += f"({arg.type_name}*) ((char*)(return_args + 1){arg.offset(self, True, True)})" second_output_array = True else: if arg.type == "struct" or arg.type == "enum" or arg.type == "int": result += f"&return_args->{arg.name}" else: result += f"&{arg.name}" return result def ArgumentsInputAssignments(self): result = "" for arg in self.entities: if arg.array: continue if arg.direction == "input": if arg.optional: result += f" if ({arg.name}) {{\n" if arg.type == "struct": result += f" args->{arg.name} = *{arg.name};\n" elif arg.type == "enum" or arg.type == "int": result += f" args->{arg.name} = {arg.name};\n" else: result += f" args->{arg.name}_id = {arg.type_name}_GetID( {arg.name} );\n" result += f" args->{arg.name}_set = true;\n" \ " }\n" \ " else\n" \ f" args->{arg.name}_set = false;\n" else: if arg.type == "struct": result += f" args->{arg.name} = *{arg.name};\n" elif arg.type == "enum" or arg.type == "int": result += f" args->{arg.name} = {arg.name};\n" else: result += f" args->{arg.name}_id = {arg.type_name}_GetID( {arg.name} );\n" for arg in self.entities: if not arg.array: continue if arg.direction == "input": if arg.optional: result += f" if ({arg.name}) {{\n" result += " direct_memcpy( (char*) (args + 1)" \ f"{arg.offset(self, False, False)}, {arg.name}, {arg.size(False)} );\n" if arg.optional: result += f" args->{arg.name}_set = true;\n" \ " }\n" \ " else {\n" \ f" args->{arg.name}_set = false;\n" \ f" {arg.name} = 0;\n" \ " }\n" return result def ArgumentsOutputAssignments(self): result = "" for arg in self.entities: if arg.array: continue if arg.direction == "output": if arg.type == "struct" or arg.type == "enum" or arg.type == "int": if arg.optional: result += f" if (ret_{arg.name})\n" \ f" *ret_{arg.name} = return_args->{arg.name};\n" else: result += f" *ret_{arg.name} = return_args->{arg.name};\n" for arg in self.entities: if not arg.array: continue if arg.direction == "output": result += f" direct_memcpy( ret_{arg.name}, (char*) (return_args + 1)" \ f"{arg.offset(self, False, True)}, {arg.sizeReturn(self)} );\n" return result def ArgumentsAssertions(self): result = "" for arg in self.entities: if (arg.type == "struct" or arg.type == "object") and not arg.optional : result += " D_ASSERT( " + (arg.name if arg.direction == "input" else f"ret_{arg.name}") + " != NULL );\n" return result def ArgumentsOutputObjectDecl(self): result = "" for arg in self.entities: if arg.direction == "output" and arg.type == "object": result += f" {arg.type_name} *{arg.name} = NULL;\n" return result def ArgumentsOutputTmpDecl(self): result = "" second = False for arg in self.entities: if arg.direction == "output" and arg.array: if second: result += f" {arg.type_name} tmp_{arg.name}[{arg.max}];\n" else: second = True return result def ArgumentsInputObjectDecl(self): result = "" for arg in self.entities: if arg.direction == "input" and arg.type == "object": result += f" {arg.type_name} *{arg.name} = NULL;\n" return result def ArgumentsOutputObjectCatch(self): result = "" for arg in self.entities: if arg.direction == "output" and arg.type == "object": result += f" ret = (DFBResult) {arg.type_name}_Catch" \ f"( core_dfb, return_args->{arg.name}_ptr, &{arg.name} );\n" \ " if (ret) {\n" \ " D_DERROR( ret, \"%s: " \ f"Catching {arg.name} by ID %u failed!\\n\", __FUNCTION__, return_args->{arg.name}_id );\n" \ " goto out;\n" \ " }\n" \ "\n" \ " *" + (arg.name if arg.direction == "input" else f"ret_{arg.name}") + f" = {arg.name};\n" \ "\n" return result def ArgumentsOutputObjectThrow(self): result = "" for arg in self.entities: if arg.type == "object" and arg.direction == "output": result += f" {arg.type_name}_Throw" \ f"( {arg.name}, caller, &return_args->{arg.name}_id );\n" \ f" return_args->{arg.name}_ptr = (void*) {arg.name};\n" return result def ArgumentsOutputTmpReturn(self): result = "" second_output_array = False for arg in self.entities: if arg.direction == "output" and arg.array: if second_output_array: result += f" direct_memcpy( (char*) ((char*)(return_args + 1)" \ f"{arg.offset(self, True, True)}), tmp_{arg.name}, return_args->{arg.name}_size );\n" else: second_output_array = True return result def ArgumentsInputObjectLookup(self): result = "" for arg in self.entities: if arg.direction == "input" and arg.type == "object": if arg.optional: result += f" if (args->{arg.name}_set) {{\n" \ f" ret = (DFBResult) {arg.type_name}_Lookup" \ f"( core_dfb, args->{arg.name}_id, caller, &{arg.name} );\n" \ " if (ret) {\n" \ f" D_DERROR( ret, \"%s({self.name}): " \ f"Looking up {arg.name} by ID %u failed!\\n\", __FUNCTION__, args->{arg.name}_id );\n" + \ (" return_args->result = ret;\n" if self.sync else "") + \ (" D_BREAK( \"could not lookup object\" );\n" \ if config.dispatch_error_abort else "") + \ " return ret;\n" \ " }\n" else: result += f" ret = (DFBResult) {arg.type_name}_Lookup" \ f"( core_dfb, args->{arg.name}_id, caller, &{arg.name} );\n" \ " if (ret) {\n" \ f" D_DERROR( ret, \"%s({self.name}): " \ f"Looking up {arg.name} by ID %u failed!\\n\", __FUNCTION__, args->{arg.name}_id );\n" + \ (" return_args->result = ret;\n" if self.sync else "") + \ (" D_BREAK( \"could not lookup object\" );\n" \ if config.dispatch_error_abort else "") + \ " return ret;\n" \ result += " }\n" \ "\n" return result def ArgumentsInputDebug(self): result = "" for arg in self.entities: if arg.array: continue if arg.optional: result += f" if (args->{arg.name}_set)\n" if arg.type == "struct": result += f" ; // TODO: {arg.type_name}_debug args->{arg.name};\n" else: result += f" D_DEBUG_AT( DirectFB_{face.object}, \" -> {arg.name} = " if arg.type == "object": result += f"%u\\n\", args->{arg.name}_id );\n" else: result += f"%{arg.formatCharacter()}\\n\", {arg.typeCast()}args->{arg.name} );\n" return result def ArgumentsInputObjectUnref(self): result = "" for arg in self.entities: if arg.direction == "input" and arg.type == "object": result += f" if ({arg.name})\n" \ f" {arg.type_name}_Unref( {arg.name} );\n" \ "\n" return result def ArgumentsNames(self): result = "" for index, arg in enumerate(self.entities): last = index == len(self.entities) - 1 result += arg.name if arg.direction == "input" else "ret_" + arg.name if not last: result += ", " return result def ArgumentsSize(self, output): result = "sizeof(" if output: result += f"{face.object}{self.name}Return)" else: result += f"{face.object}{self.name})" for arg in self.entities: if not arg.array: continue if output: if arg.direction == "output": result += f" + {arg.sizeMax()}" else: if arg.direction == "input": result += f" + {arg.size(False)}" return result def ArgumentsSizeReturn(self): result = f"sizeof({face.object}{self.name}Return)" for arg in self.entities: if not arg.array: continue if arg.direction == "output": result += f" + {arg.sizeReturn(self)}" return result class Arg(Entity): array = False optional = False def SetProperty(self, name, value): if name == "name": self.name = value elif name == "direction": self.direction = value elif name == "type": self.type = value elif name == "typename": self.type_name = value elif name == "optional": self.optional = value == "yes" elif name == "count": self.array = True self.count = value elif name == "max": self.max = value def formatCharacter(self): if self.type == "int": if self.type_name == "u32": return "u" elif self.type_name == "s32": return "d" elif self.type_name == "u64": return "llu" elif self.type_name == "s64": return "lld" else: return "p" else: return "x" def typeCast(self): if self.type == "int": if self.type_name == "u64": return "(unsigned long long) " elif self.type_name == "s64": return "(long long) " return "" def size(self, use_args): if use_args: return f"args->{self.count} * sizeof({self.type_name})" else: return f"{self.count} * sizeof({self.type_name})" def sizeMax(self): return f"{self.max} * sizeof({self.type_name})" def sizeReturn(self, method): if self.array: for arg in method.entities: if arg.direction == "input": return f"args->{self.count} * sizeof({self.type_name})" else: return f"return_args->{self.count} * sizeof({self.type_name})" def offset(self, method, use_args, output): result = "" for arg in method.entities: if not arg.array: continue if arg == self: break if output: result += f" + return_args->{arg.size(False)}" else: result += f" + {arg.size(use_args)}" return result # -------------------------------------------------------------------------------------------------------------------------- face = Interface() def GetEntities(position, out_vector): with open(config.filename, 'r') as file: file.seek(position) content = file.read() index = 0 level = 0 comment = False quote = False name = "" names = {} for char in content: index += 1 if comment: if char == '\n': comment = False elif quote: if char == '"': quote = False else: name += char else: if char == '"': quote = True elif char == '#': comment = True elif char in ('.', '-', '_', *'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): name += char else: if name: if level in names and names[level]: if level == 1: entity.SetProperty(names[level], name) name = "" names[level] = name name = "" if char == '{': if level == 0: if names[level] == "interface": entity = face entity.position = position + index elif names[level] == "method": entity = Method() entity.position = position + index else: entity = Arg() entity.position = position + index names[level] = "" level += 1 elif char == '}': level -= 1 if level == 0: GetEntities(entity.position, entity.entities) out_vector.append(entity) if level < 0: break def GenerateHeader(): with open((config.output_dir + "/" if config.output_dir else "") + face.object + ".h", "w") as file: file.write( "/*\n" " * This file was automatically generated by fluxcomp; DO NOT EDIT!\n" " */\n" f"{license}" "\n") # Start of header guard and includes file.write(f"#ifndef ___{face.object}__H___\n" f"#define ___{face.object}__H___\n" "\n" f"#include <{config.include_prefix}/{face.object}_includes.h>\n" "\n" "/***************************************************************************************************\n" f" * {face.object}\n" " */\n" "\n" "#ifdef __cplusplus\n" "#include \n" "\n" "extern \"C\" {\n" "#endif\n" "\n" "\n") # C Wrappers for method in face.entities: if isinstance(method, Method): file.write(f"DFBResult {face.object}_{method.name}(\n" f" {face.object:<40} *obj" + (",\n" if method.entities else "\n") + f"{method.ArgumentsAsParamDecl()});\n" "\n") file.write( "\n" f"void {face.object}_Init_Dispatch(\n" " CoreDFB *core,\n" f" {face.dispatch:<20} *obj,\n" " FusionCall *call\n" ");\n" "\n" f"void {face.object}_Deinit_Dispatch(\n" " FusionCall *call\n" ");\n" "\n" "\n" "#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "\n" "\n" "\n") # Method IDs file.write( "/*\n" f" * {face.object} Calls\n" " */\n" "typedef enum {\n") index = 1 for method in face.entities: if isinstance(method, Method): file.write(f" _{face.object}_{method.name} = {index},\n") index += 1 file.write(f"}} {face.object}Call;\n" "\n") # Method Argument Structures for method in face.entities: if isinstance(method, Method): file.write( "/*\n" f" * {face.object}_{method.name}\n" " */\n" "typedef struct {\n" f"{method.ArgumentsAsMemberDecl()}" f"}} {face.object}{method.name};\n" "\n" "typedef struct {\n" f"{method.ArgumentsOutputAsMemberDecl()}" f"}} {face.object}{method.name}Return;\n" "\n" "\n") # Real Interface for method in face.entities: if isinstance(method, Method): file.write(f"DFBResult {face.name}_Real__{method.name}( {face.dispatch} *obj" + (",\n" if method.ArgumentsAsParamDecl() else "\n") + f"{method.ArgumentsAsParamDecl()} );\n" "\n") # Requestor Interface for method in face.entities: if isinstance(method, Method): file.write(f"DFBResult {face.name}_Requestor__{method.name}( {face.object} *obj" + (",\n" if method.ArgumentsAsParamDecl() else "\n") + f"{method.ArgumentsAsParamDecl()} );\n" "\n") # Dispatch Function file.write( "\n" f"DFBResult {face.object}Dispatch__Dispatch( {face.dispatch} *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length );\n" "\n") # End of header guard file.write( "\n" "#endif\n") def GenerateSource(): direct = True if face.object != face.dispatch: direct = False with open((config.output_dir + "/" if config.output_dir else "") + face.object + ".c", "w") as file: file.write( "/*\n" " * This file was automatically generated by fluxcomp; DO NOT EDIT!\n" " */\n" f"{license}" "\n") # includes file.write( "#include \n" "\n" f"#include \"{face.object}.h\"\n" "\n" "#include \n" "\n" "#include \n" "#include \n" "#include \n" "#include \n" "\n" "#include \n" "\n" "#include \n" "\n" "#include \n" "\n" f"D_DEBUG_DOMAIN( DirectFB_{face.object}, \"DirectFB/{face.object}\", \"DirectFB {face.object}\" );\n" "\n" "/**************************************************************************************************/\n" "\n") # C Wrappers for method in face.entities: if isinstance(method, Method): file.write( "DFBResult\n" f"{face.object}_{method.name}(\n" f" {face.object:<40} *obj" + (",\n" if method.entities else "\n") + f"{method.ArgumentsAsParamDecl()}\n" ")\n" "{\n" " DFBResult ret;\n" "\n" " switch (CoreDFB_CallMode( core_dfb )) {\n" " case COREDFB_CALL_DIRECT:") if direct: file.write( "{\n" " Core_PushCalling();\n" f" ret = {face.name}_Real__{method.name}( obj" + (", " if method.ArgumentsAsParamDecl() else "") + f"{method.ArgumentsNames()} );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }\n") file.write( "\n case COREDFB_CALL_INDIRECT: {\n" " Core_PushCalling();\n" f" ret = {face.name}_Requestor__{method.name}( obj" + (", " if method.ArgumentsAsParamDecl() else "") + f"{method.ArgumentsNames()} );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }\n" " case COREDFB_CALL_DENY:\n" " return DFB_DEAD;\n" " }\n" "\n" " return DFB_UNIMPLEMENTED;\n" "}\n" "\n") file.write( "/**************************************************************************************************/\n" "\n" "static FusionCallHandlerResult\n" f"{face.object}_Dispatch( int caller, /* fusion id of the caller */\n" " int call_arg, /* optional call parameter */\n" " void *ptr, /* optional call parameter */\n" " unsigned int length,\n" " void *ctx, /* optional handler context */\n" " unsigned int serial,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n" f" {face.dispatch} *obj = ({face.dispatch}*) ctx;\n" f" {face.object}Dispatch__Dispatch" "( obj, caller, call_arg, ptr, length, ret_ptr, ret_size, ret_length );\n" "\n" " return FCHR_RETURN;\n" "}\n" "\n" f"void {face.object}_Init_Dispatch(\n" " CoreDFB *core,\n" f" {face.dispatch:<20} *obj,\n" " FusionCall *call\n" ")\n" "{\n" f" fusion_call_init3( call, {face.object}_Dispatch, obj, core->world );\n" "}\n" "\n" f"void {face.object}_Deinit_Dispatch(\n" " FusionCall *call\n" ")\n" "{\n" " fusion_call_destroy( call );\n" "}\n" "\n" "/**************************************************************************************************/\n" "\n") # Requestor Methods file.write( "static __inline__ void *args_alloc( void *static_buffer, size_t size )\n" "{\n" " void *buffer = static_buffer;\n" "\n" f" if (size > {config.static_args_bytes}) {{\n" " buffer = D_MALLOC( size );\n" " if (!buffer)\n" " return NULL;\n" " }\n" "\n" " return buffer;\n" "}\n" "\n" "static __inline__ void args_free( void *static_buffer, void *buffer )\n" "{\n" " if (buffer != static_buffer)\n" " D_FREE( buffer );\n" "}\n" "\n") for method in face.entities: if isinstance(method, Method): file.write( "\n" "DFBResult\n" f"{face.name}_Requestor__{method.name}( {face.object} *obj" + (",\n" if method.ArgumentsAsParamDecl() else "\n") + f"{method.ArgumentsAsParamDecl()}\n" ")\n" "{\n" " DFBResult ret = DFB_OK;\n" f"{method.ArgumentsOutputObjectDecl()}" f" char args_static[{config.static_args_bytes}];\n") if method.sync: file.write(f" char return_args_static[{config.static_args_bytes}];\n") file.write(f" {face.object}{method.name} *args = ({face.object}{method.name}*) args_alloc" f"( args_static, {method.ArgumentsSize(False)} );\n") if method.sync: file.write(f" {face.object}{method.name}Return *return_args;\n") file.write( "\n" " if (!args)\n" " return (DFBResult) D_OOM();\n" "\n") if method.sync: file.write(f" return_args = ({face.object}{method.name}Return*) args_alloc" f"( return_args_static, {method.ArgumentsSize(True)} );\n" "\n") if method.sync: file.write( " if (!return_args) {\n" " args_free( args_static, args );\n" " return (DFBResult) D_OOM();\n" " }\n" "\n") file.write(f" D_DEBUG_AT( DirectFB_{face.object}, \"{face.name}_Requestor::%s()\\n\", __FUNCTION__ );\n" "\n" f"{method.ArgumentsAssertions()}" "\n" f"{method.ArgumentsInputAssignments()}" "\n" f" ret = (DFBResult) {face.object}_Call") if method.sync: file.write( "( obj, FCEF_NONE" f", _{face.object}_{method.name}, args, {method.ArgumentsSize(False)}" f", return_args, {method.ArgumentsSize(True)}, NULL );\n") else: file.write("( obj, (FusionCallExecFlags)(FCEF_ONEWAY" + (" | FCEF_QUEUE" if method.queue else "") + ")" f", _{face.object}_{method.name}, args, {method.ArgumentsSize(False)}" ", NULL, 0, NULL );\n") file.write( " if (ret) {\n" " D_DERROR( ret, \"%s: " f"{face.object}_Call( {face.object}_{method.name} ) failed!\\n\", __FUNCTION__ );\n" " goto out;\n" " }\n" "\n") if method.sync: file.write( " if (return_args->result) {\n" " /*D_DERROR( return_args->result, \"%s: " f"{face.object}_{method.name} failed!\\n\", __FUNCTION__ );*/\n" " ret = return_args->result;\n" " goto out;\n" " }\n" "\n") file.write(f"{method.ArgumentsOutputAssignments()}" "\n" f"{method.ArgumentsOutputObjectCatch()}" "\n" "out:\n") if method.sync: file.write( " args_free( return_args_static, return_args );\n") file.write( " args_free( args_static, args );\n" " return ret;\n" "}\n" "\n") # Dispatch Object file.write( "/**************************************************************************************************/\n" "\n" "static DFBResult\n" f"__{face.object}Dispatch__Dispatch( {face.dispatch} *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n" " D_UNUSED\n" " DFBResult ret;\n" "\n" "\n" " switch (method) {\n") # Dispatch Methods for method in face.entities: if isinstance(method, Method): file.write(f" case _{face.object}_{method.name}: {{\n" f"{method.ArgumentsInputObjectDecl()}" f"{method.ArgumentsOutputObjectDecl()}") if method.sync: file.write(f"{method.ArgumentsOutputTmpDecl()}") file.write( " D_UNUSED\n" f" {face.object}{method.name} *args = " f"({face.object}{method.name} *) ptr;\n") if method.sync: file.write(f" {face.object}{method.name}Return *return_args = " f"({face.object}{method.name}Return *) ret_ptr;\n") file.write( "\n" f" D_DEBUG_AT( DirectFB_{face.object}, \"=-> {face.object}_{method.name}\\n\" );\n" "\n") if not method.sync: file.write(f"{method.ArgumentsInputDebug()}" "\n") file.write(f"{method.ArgumentsInputObjectLookup()}") if not method.sync: file.write(f" {face.name}_Real__{method.name}( obj" + (", " if method.ArgumentsAsParamDecl() else "") + f"{method.ArgumentsAsMemberParams()} );\n") else: file.write(f" return_args->result = {face.name}_Real__{method.name}( obj" + (", " if method.ArgumentsAsParamDecl() else "") + f"{method.ArgumentsAsMemberParams()} );\n" " if (return_args->result == DFB_OK) {\n" f"{method.ArgumentsOutputObjectThrow()}" f"{method.ArgumentsOutputTmpReturn()}" " }\n" "\n" f" *ret_length = {method.ArgumentsSizeReturn()};\n") file.write( "\n" f"{method.ArgumentsInputObjectUnref()}" " return DFB_OK;\n" " }\n" "\n") file.write( " }\n" "\n" " return DFB_NOSUCHMETHOD;\n" "}\n") file.write( "/**************************************************************************************************/\n" "\n" "DFBResult\n" f"{face.object}Dispatch__Dispatch( {face.dispatch} *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n" " DFBResult ret = DFB_OK;\n" "\n" f" D_DEBUG_AT( DirectFB_{face.object}, \"{face.object}Dispatch::%s( %p )\\n\", " "__FUNCTION__, obj );\n") if config.identity: file.write( "\n" " Core_PushIdentity( caller );\n") file.write( "\n" f" ret = __{face.object}Dispatch__Dispatch" "( obj, caller, method, ptr, length, ret_ptr, ret_size, ret_length );\n") if config.identity: file.write( "\n" " Core_PopIdentity();\n") file.write( "\n" " return ret;\n" "}\n") # -------------------------------------------------------------------------------------------------------------------------- config = parser.parse_args() GetEntities(0, face.entities) GenerateHeader() GenerateSource() ================================================ FILE: src/core/fonts.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Font, "Core/Font", "DirectFB Core Font" ); D_DEBUG_DOMAIN( Font_Cache, "Core/Font/Cache", "DirectFB Core Font Cache" ); D_DEBUG_DOMAIN( Font_CacheRow, "Core/Font/CacheRow", "DirectFB Core Font Cache Row" ); D_DEBUG_DOMAIN( Core_FontSurfaces, "Core/Font/Surf", "DirectFB Core Font Surfaces" ); D_DEBUG_DOMAIN( Font_Manager, "Core/Font/Manager", "DirectFB Core Font Manager" ); /**********************************************************************************************************************/ struct __DFB_CoreFontCache { int magic; CoreFontManager *manager; CoreFontCacheType type; unsigned int row_width; DirectLink *rows; }; struct __DFB_CoreFontCacheRow { DirectLink link; int magic; CoreFontCache *cache; unsigned long long stamp; CoreSurface *surface; unsigned int next_x; DirectLink *glyphs; }; struct __DFB_CoreFontManager { int magic; CoreDFB *core; DirectMutex lock; DirectMap *caches; unsigned int max_rows; unsigned int num_rows; unsigned long long row_stamp; }; /**********************************************************************************************************************/ DFBResult dfb_font_manager_create( CoreDFB *core, CoreFontManager **ret_manager ) { DFBResult ret; CoreFontManager *manager; D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_ASSERT( core != NULL ); D_ASSERT( ret_manager != NULL ); manager = D_CALLOC( 1, sizeof(CoreFontManager) ); if (!manager) return D_OOM(); ret = dfb_font_manager_init( manager, core ); if (ret) { D_FREE( manager ); return ret; } *ret_manager = manager; return DFB_OK; } DFBResult dfb_font_manager_destroy( CoreFontManager *manager ) { D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); dfb_font_manager_deinit( manager ); D_FREE( manager ); return DFB_OK; } static bool font_cache_map_compare( DirectMap *map, const void *key, void *object, void *ctx ) { const CoreFontCacheType *type = key; CoreFontCache *cache = object; return memcmp( type, &cache->type, sizeof(*type) ) == 0; } static unsigned int font_cache_map_hash( DirectMap *map, const void *key, void *ctx ) { const CoreFontCacheType *type = key; return (type->height * 131 + type->pixel_format) * 131 + type->surface_caps; } DFBResult dfb_font_manager_init( CoreFontManager *manager, CoreDFB *core ) { DFBResult ret; D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_ASSERT( core != NULL ); D_ASSERT( manager != NULL ); manager->core = core; manager->max_rows = dfb_config->max_font_rows; ret = direct_map_create( 11, font_cache_map_compare, font_cache_map_hash, NULL, &manager->caches ); if (ret) return ret; direct_recursive_mutex_init( &manager->lock ); D_MAGIC_SET( manager, CoreFontManager ); return DFB_OK; } static DirectEnumerationResult destroy_caches( DirectMap *map, void *object, void *ctx ) { CoreFontCache *cache = object; D_DEBUG_AT( Font_Manager, "%s( %p )\n", __FUNCTION__, cache ); D_MAGIC_ASSERT( cache, CoreFontCache ); dfb_font_cache_destroy( cache ); return DENUM_OK; } DFBResult dfb_font_manager_deinit( CoreFontManager *manager ) { D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); direct_map_iterate( manager->caches, destroy_caches, NULL ); direct_map_destroy( manager->caches ); direct_mutex_deinit( &manager->lock ); D_MAGIC_CLEAR( manager ); return DFB_OK; } DFBResult dfb_font_manager_lock( CoreFontManager *manager ) { D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); direct_mutex_lock( &manager->lock ); return DFB_OK; } DFBResult dfb_font_manager_unlock( CoreFontManager *manager ) { D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); direct_mutex_unlock( &manager->lock ); return DFB_OK; } DFBResult dfb_font_manager_get_cache( CoreFontManager *manager, const CoreFontCacheType *type, CoreFontCache **ret_cache ) { D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); D_ASSERT( type != NULL ); D_ASSERT( ret_cache != NULL ); D_DEBUG_AT( Font_Manager, " -> height %u, format 0x%x, caps 0x%x\n", type->height, (unsigned int) type->pixel_format, (unsigned int) type->surface_caps ); DFBResult ret; CoreFontCache *cache; CoreFontCacheType _type = *type; if (_type.height < 8) _type.height = 8; cache = direct_map_lookup( manager->caches, &_type ); if (!cache) { ret = dfb_font_cache_create( manager, &_type, &cache ); if (ret) return ret; ret = direct_map_insert( manager->caches, &_type, cache ); if (ret) { dfb_font_cache_destroy( cache ); return ret; } } *ret_cache = cache; return DFB_OK; } typedef struct { unsigned int lru_stamp; CoreFontCacheRow *lru_row; } FindLruRowContext; static DirectEnumerationResult find_lru_row( DirectMap *map, void *object, void *ctx ) { FindLruRowContext *context = ctx; CoreFontCache *cache = object; CoreFontCacheRow *row; D_DEBUG_AT( Font_Manager, "%s( %p )\n", __FUNCTION__, cache ); D_MAGIC_ASSERT( cache, CoreFontCache ); direct_list_foreach (row, cache->rows) { D_DEBUG_AT( Font_Manager, " -> stamp %llu\n", row->stamp ); if (!context->lru_row || context->lru_stamp > row->stamp) { context->lru_row = row; context->lru_stamp = row->stamp; } } return DENUM_OK; } DFBResult dfb_font_manager_remove_lru_row( CoreFontManager *manager ) { FindLruRowContext context; CoreFontCache *cache; D_DEBUG_AT( Font_Manager, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); context.lru_stamp = 0; context.lru_row = NULL; direct_map_iterate( manager->caches, find_lru_row, &context ); if (!context.lru_row) { D_ERROR( "Core/Font: Could not find any LRU row!\n" ); return DFB_ITEMNOTFOUND; } D_DEBUG_AT( Font_Manager, " -> row %p (stamp %llu)\n", context.lru_row, context.lru_row->stamp ); cache = context.lru_row->cache; D_MAGIC_ASSERT( cache, CoreFontCache ); direct_list_remove( &cache->rows, &context.lru_row->link ); dfb_font_cache_row_destroy( context.lru_row ); /* Decrease row counter. */ manager->num_rows--; return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_font_cache_create( CoreFontManager *manager, const CoreFontCacheType *type, CoreFontCache **ret_cache ) { DFBResult ret; CoreFontCache *cache; D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); D_ASSERT( type != NULL ); D_ASSERT( ret_cache != NULL ); cache = D_CALLOC( 1, sizeof(CoreFontCache) ); if (!cache) return D_OOM(); ret = dfb_font_cache_init( cache, manager, type ); if (ret) { D_FREE( cache ); return ret; } *ret_cache = cache; return DFB_OK; } DFBResult dfb_font_cache_destroy( CoreFontCache *cache ) { D_MAGIC_ASSERT( cache, CoreFontCache ); dfb_font_cache_deinit( cache ); D_FREE( cache ); return DFB_OK; } DFBResult dfb_font_cache_init( CoreFontCache *cache, CoreFontManager *manager, const CoreFontCacheType *type ) { D_ASSERT( cache != NULL ); D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); D_ASSERT( type != NULL ); cache->manager = manager; cache->type = *type; cache->row_width = 2048 * type->height / 64; if (cache->row_width > dfb_config->max_font_row_width) cache->row_width = dfb_config->max_font_row_width; if (cache->row_width < type->height) cache->row_width = type->height; cache->row_width = (cache->row_width + 7) & ~7; D_MAGIC_SET( cache, CoreFontCache ); return DFB_OK; } DFBResult dfb_font_cache_deinit( CoreFontCache *cache ) { CoreFontCacheRow *row, *next; D_MAGIC_ASSERT( cache, CoreFontCache ); direct_list_foreach_safe (row, next, cache->rows) { dfb_font_cache_row_destroy( row ); } #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" #endif cache->rows = NULL; D_MAGIC_CLEAR( cache ); #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic pop #endif return DFB_OK; } DFBResult dfb_font_cache_get_row( CoreFontCache *cache, unsigned int width, CoreFontCacheRow **ret_row ) { DFBResult ret; CoreFontManager *manager; CoreFontCacheRow *row; CoreFontCacheRow *best_row = NULL; unsigned int best_val = 0; D_MAGIC_ASSERT( cache, CoreFontCache ); D_ASSERT( ret_row != NULL ); manager = cache->manager; D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); /* Try freshest row first. */ row = (CoreFontCacheRow*) cache->rows; if (row && row->next_x + width <= cache->row_width) { *ret_row = row; return DFB_OK; } /* Check for trailing space in each row. */ direct_list_foreach (row, cache->rows) { D_MAGIC_ASSERT( row, CoreFontCacheRow ); /* If glyph fits... */ if (row->next_x + width <= cache->row_width) { /* ...and no row yet or this row fits better... */ if (!best_row || best_val < row->next_x) { /* ...remember row. */ best_row = row; best_val = row->next_x; } } } if (best_row) { *ret_row = best_row; return DFB_OK; } /* Maximum number of rows reached. */ if (manager->num_rows == manager->max_rows) { /* Remove the least recently used row. */ ret = dfb_font_manager_remove_lru_row( manager ); if (ret) return ret; } /* Create another row. */ ret = dfb_font_cache_row_create( cache, &row ); if (ret) return ret; /* Prepend to list (freshest is first). */ direct_list_prepend( &cache->rows, &row->link ); /* Increase row counter in manager. */ manager->num_rows++; *ret_row = row; return DFB_OK; } DFBResult dfb_font_cache_row_create( CoreFontCache *cache, CoreFontCacheRow **ret_row ) { DFBResult ret; CoreFontCacheRow *row; row = D_CALLOC( 1, sizeof(CoreFontCacheRow) ); if (!row) return D_OOM(); ret = dfb_font_cache_row_init( row, cache ); if (ret) { D_FREE( row ); return ret; } *ret_row = row; return DFB_OK; } DFBResult dfb_font_cache_row_destroy( CoreFontCacheRow *row ) { D_MAGIC_ASSERT( row, CoreFontCacheRow ); dfb_font_cache_row_deinit( row ); D_FREE( row ); return DFB_OK; } DFBResult dfb_font_cache_row_init( CoreFontCacheRow *row, CoreFontCache *cache ) { DFBResult ret; CoreFontManager *manager; D_MAGIC_ASSERT( cache, CoreFontCache ); manager = cache->manager; D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); row->cache = cache; /* Create a new font surface. */ ret = dfb_surface_create_simple( manager->core, cache->row_width, cache->type.height, cache->type.pixel_format, DFB_COLORSPACE_DEFAULT( cache->type.pixel_format ), cache->type.surface_caps, CSTF_FONT, dfb_config->font_resource_id, NULL, &row->surface ); if (ret) { D_DERROR( ret, "Core/Font: Could not create font surface!\n" ); return ret; } D_DEBUG_AT( Core_FontSurfaces, " -> new row %u - %dx%d %s\n", manager->num_rows, row->surface->config.size.w, row->surface->config.size.h, dfb_pixelformat_name( row->surface->config.format ) ); D_MAGIC_SET( row, CoreFontCacheRow ); return DFB_OK; } DFBResult dfb_font_cache_row_deinit( CoreFontCacheRow *row ) { CoreGlyphData *glyph, *next; D_MAGIC_ASSERT( row, CoreFontCacheRow ); /* Kick out all glyphs. */ direct_list_foreach_safe (glyph, next, row->glyphs) { CoreFont *font = glyph->font; D_MAGIC_ASSERT( glyph, CoreGlyphData ); D_ASSERT( glyph->layer < D_ARRAY_SIZE(font->layers) ); direct_hash_remove( font->layers[glyph->layer].glyph_hash, glyph->index ); if (glyph->index < 128) font->layers[glyph->layer].glyph_data[glyph->index] = NULL; D_MAGIC_CLEAR( glyph ); D_FREE( glyph ); } dfb_surface_unref( row->surface ); D_MAGIC_CLEAR( row ); return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_font_create( CoreDFB *core, const DFBFontDescription *description, CoreFont **ret_font ) { DFBResult ret; int i; CoreFont *font; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_ASSERT( core != NULL ); D_ASSERT( ret_font != NULL ); font = D_CALLOC( 1, sizeof(CoreFont) ); if (!font) return D_OOM(); for (i = 0; i < DFB_FONT_MAX_LAYERS; i++) { ret = direct_hash_create( 163, &font->layers[i].glyph_hash ); if (ret) { while (i--) direct_hash_destroy( font->layers[i].glyph_hash ); D_FREE( font ); return ret; } } font->core = core; font->manager = dfb_core_font_manager( core ); font->description = *description; font->blittingflags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE; font->pixel_format = dfb_config->font_format; if ((font->pixel_format == DSPF_ARGB || font->pixel_format == DSPF_ABGR || font->pixel_format == DSPF_ARGB8565 || font->pixel_format == DSPF_ARGB4444 || font->pixel_format == DSPF_RGBA4444 || font->pixel_format == DSPF_ARGB1555 || font->pixel_format == DSPF_RGBA5551) && dfb_config->font_premult) { font->surface_caps = DSCAPS_PREMULTIPLIED; } D_MAGIC_SET( font, CoreFont ); *ret_font = font; return DFB_OK; } void dfb_font_destroy( CoreFont *font ) { int i; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( font, CoreFont ); D_ASSERT( font->encodings != NULL || !font->last_encoding ); dfb_font_dispose( font ); for (i = 0; i < DFB_FONT_MAX_LAYERS; i++) direct_hash_destroy( font->layers[i].glyph_hash ); for (i = DTEID_OTHER; i <= font->last_encoding; i++) { CoreFontEncoding *encoding = font->encodings[i]; D_ASSERT( encoding != NULL ); D_ASSERT( encoding->name != NULL ); D_MAGIC_CLEAR( encoding ); D_FREE( encoding->name ); D_FREE( encoding ); } if (font->encodings) D_FREE( font->encodings ); D_MAGIC_CLEAR( font ); D_FREE( font ); } static bool free_glyphs( DirectHash *hash, unsigned long key, void *value, void *ctx ) { CoreGlyphData *data = value; CoreFontCacheRow *row; D_DEBUG_AT( Core_Font, "%s( %lu )\n", __FUNCTION__, key ); D_MAGIC_ASSERT( data, CoreGlyphData ); CORE_GLYPH_DATA_DEBUG_AT( Core_Font, data ); /* Remove glyph from font. */ direct_hash_remove( hash, key ); row = data->row; if (row) { D_MAGIC_ASSERT( row, CoreFontCacheRow ); /* Remove glyph from cache row. */ direct_list_remove( &row->glyphs, &data->link ); /* If cache row got empty, destroy it. */ if (!row->glyphs) { CoreFontManager *manager; CoreFontCache *cache = row->cache; D_MAGIC_ASSERT( cache, CoreFontCache ); manager = cache->manager; D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( manager->max_rows > 0 ); D_ASSERT( manager->num_rows <= manager->max_rows ); /* Remove row from cache. */ direct_list_remove( &cache->rows, &row->link ); /* Destroy row. */ dfb_font_cache_row_destroy( row ); /* Decrease row counter in manager. */ manager->num_rows--; } } D_MAGIC_CLEAR( data ); D_FREE( data ); return true; } DFBResult dfb_font_dispose( CoreFont *font ) { int i; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( font, CoreFont ); dfb_font_manager_lock( font->manager ); for (i = 0; i < DFB_FONT_MAX_LAYERS; i++) { direct_hash_iterate( font->layers[i].glyph_hash, free_glyphs, NULL ); memset( font->layers[i].glyph_data, 0, sizeof(font->layers[i].glyph_data) ); } dfb_font_manager_unlock( font->manager ); return DFB_OK; } DFBResult dfb_font_get_glyph_data( CoreFont *font, unsigned int index, unsigned int layer, CoreGlyphData **ret_data ) { DFBResult ret; CoreGlyphData *data; int align; CoreFontManager *manager; CoreFontCache *cache; CoreFontCacheRow *row = NULL; D_DEBUG_AT( Core_Font, "%s( index %u, layer %u )\n", __FUNCTION__, index, layer ); D_MAGIC_ASSERT( font, CoreFont ); D_ASSERT( layer < D_ARRAY_SIZE(font->layers) ); D_ASSERT( ret_data != NULL ); manager = font->manager; D_MAGIC_ASSERT( manager, CoreFontManager ); D_ASSERT( (manager)->max_rows > 0 ); D_ASSERT( (manager)->num_rows <= (manager)->max_rows ); /* Quick Lookup in array. */ if (index < 128 && font->layers[layer].glyph_data[index]) { data = font->layers[layer].glyph_data[index]; if (data->retry) goto retry; *ret_data = font->layers[layer].glyph_data[index]; return DFB_OK; } /* Standard lookup in hash. */ data = direct_hash_lookup( font->layers[layer].glyph_hash, index ); if (data) { D_MAGIC_ASSERT( data, CoreGlyphData ); D_DEBUG_AT( Core_Font, " -> already in cache (%p)\n", data ); row = data->row; if (row) { D_MAGIC_ASSERT( row, CoreFontCacheRow ); row->stamp = manager->row_stamp++; } if (data->retry) goto retry; *ret_data = data; return DFB_OK; } /* No glyph data available in cache, load new glyph. */ if (!font->GetGlyphData) return DFB_UNSUPPORTED; /* Allocate glyph data. */ data = D_CALLOC( 1, sizeof(CoreGlyphData) ); if (!data) return D_OOM(); D_MAGIC_SET( data, CoreGlyphData ); data->font = font; data->index = index; data->layer = layer; retry: data->retry = false; /* Get glyph data from font implementation. */ ret = font->GetGlyphData( font, index, data ); if (ret) { D_DERROR( ret, "Core/Font: Could not get glyph info for index %u!\n", index ); data->start = data->width = data->height = 0; /* If the font module returned BUFFEREMPTY, we will retry loading next time. */ if (ret == DFB_BUFFEREMPTY) data->retry = true; goto out; } if (!(font->flags & CFF_SUBPIXEL_ADVANCE)) { data->xadvance <<= 8; data->yadvance <<= 8; } if (data->width < 1 || data->height < 1) { D_DEBUG_AT( Core_Font, " -> zero size glyph bitmap!\n" ); data->start = data->width = data->height = 0; goto out; } /* Get the proper cache based on size. */ CoreFontCacheType type; type.height = MAX( data->height, data->width ); type.pixel_format = font->pixel_format; type.surface_caps = font->surface_caps; /* Avoid too many surface switches during one string rendering. */ type.height = MAX( font->height, type.height ); ret = dfb_font_manager_get_cache( font->manager, &type, &cache ); if (ret) { D_DEBUG_AT( Core_Font, " -> could not get cache from manager!\n" ); goto error; } /* Check for a cache row (surface) to use. */ ret = dfb_font_cache_get_row( cache, data->width, &row ); if (ret) { D_DEBUG_AT( Core_Font, " -> could not get row from cache!\n" ); goto error; } /* Add the glyph to the cache row. */ D_DEBUG_AT( Core_FontSurfaces, " -> render %u - %2dx%2d at %03u\n", index, data->width, data->height, row->next_x ); data->row = row; data->start = row->next_x; data->surface = row->surface; align = (8 / (DFB_BYTES_PER_PIXEL( font->pixel_format ) ?: 1)) * (DFB_PIXELFORMAT_ALIGNMENT( font->pixel_format ) + 1) - 1; row->next_x += (data->width + align) & ~align; row->stamp = manager->row_stamp++; /* Render the glyph data into the surface. */ ret = font->RenderGlyph( font, index, data ); if (ret) { D_DEBUG_AT( Core_Font, " -> rendering glyph failed!\n" ); data->start = data->width = data->height = 0; /* If the font module returned BUFFEREMPTY we will retry loading next time. */ if (ret == DFB_BUFFEREMPTY) data->retry = true; goto out; } dfb_gfxcard_flush_texture_cache(); CORE_GLYPH_DATA_DEBUG_AT( Core_Font, data ); out: if (!data->inserted) { if (row) direct_list_append( &row->glyphs, &data->link ); direct_hash_insert( font->layers[layer].glyph_hash, index, data ); if (index < 128) font->layers[layer].glyph_data[index] = data; data->inserted = true; } *ret_data = data; return DFB_OK; error: D_MAGIC_CLEAR( data ); D_FREE( data ); return ret; } /**********************************************************************************************************************/ DFBResult dfb_font_register_encoding( CoreFont *font, const char *name, const CoreFontEncodingFuncs *funcs, DFBTextEncodingID encoding_id ) { CoreFontEncoding *encoding; CoreFontEncoding **encodings; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( font, CoreFont ); D_ASSERT( encoding_id == DTEID_UTF8 || name != NULL ); D_ASSERT( funcs != NULL ); if (!funcs->GetCharacterIndex) return DFB_INVARG; /* Special case for default, native format. */ if (encoding_id == DTEID_UTF8) { font->utf8 = funcs; return DFB_OK; } if (!funcs->DecodeText) return DFB_INVARG; /* Setup new encoding information. */ encoding = D_CALLOC( 1, sizeof(CoreFontEncoding) ); if (!encoding) return D_OOM(); encoding->encoding = font->last_encoding + 1; encoding->funcs = funcs; encoding->name = D_STRDUP( name ); if (!encoding->name) { D_FREE( encoding ); return D_OOM(); } /* Add to array. */ encodings = D_REALLOC( font->encodings, (encoding->encoding + 1) * sizeof(CoreFontEncoding*) ); if (!encodings) { D_FREE( encoding->name ); D_FREE( encoding ); return D_OOM(); } font->encodings = encodings; font->last_encoding++; D_ASSERT( font->last_encoding == encoding->encoding ); encodings[encoding->encoding] = encoding; D_MAGIC_SET( encoding, CoreFontEncoding ); return DFB_OK; } DFBResult dfb_font_decode_text( CoreFont *font, DFBTextEncodingID encoding, const void *text, int length, unsigned int *ret_indices, int *ret_num ) { int pos = 0, num = 0; const u8 *bytes = text; const CoreFontEncodingFuncs *funcs; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( font, CoreFont ); D_ASSERT( text != NULL ); D_ASSERT( length >= 0 ); D_ASSERT( ret_indices != NULL ); D_ASSERT( ret_num != NULL ); if (encoding != DTEID_UTF8) { if (encoding > font->last_encoding) return DFB_IDNOTFOUND; D_ASSERT( font->encodings[encoding] != NULL ); funcs = font->encodings[encoding]->funcs; D_ASSERT( funcs != NULL ); D_ASSERT( funcs->DecodeText != NULL ); return funcs->DecodeText( font, text, length, ret_indices, ret_num ); } else if (font->utf8) { funcs = font->utf8; if (funcs->DecodeText) return funcs->DecodeText( font, text, length, ret_indices, ret_num ); D_ASSERT( funcs->GetCharacterIndex != NULL ); while (pos < length) { unsigned int c; if (bytes[pos] < 128) c = bytes[pos++]; else { c = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); pos += DIRECT_UTF8_SKIP( bytes[pos] ); } if (funcs->GetCharacterIndex( font, c, &ret_indices[num] ) == DFB_OK) num++; } } else { while (pos < length) { if (bytes[pos] < 128) ret_indices[num++] = bytes[pos++]; else { ret_indices[num++] = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); pos += DIRECT_UTF8_SKIP( bytes[pos] ); } } } *ret_num = num; return DFB_OK; } DFBResult dfb_font_decode_character( CoreFont *font, DFBTextEncodingID encoding, u32 character, unsigned int *ret_index ) { const CoreFontEncodingFuncs *funcs; D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( font, CoreFont ); D_ASSERT( ret_index != NULL ); if (encoding > font->last_encoding) return DFB_IDNOTFOUND; if (encoding != DTEID_UTF8) { D_ASSERT( font->encodings[encoding] != NULL ); funcs = font->encodings[encoding]->funcs; D_ASSERT( funcs != NULL ); D_ASSERT( funcs->GetCharacterIndex != NULL ); return funcs->GetCharacterIndex( font, character, ret_index ); } else if (font->utf8) { funcs = font->utf8; D_ASSERT( funcs->GetCharacterIndex != NULL ); return funcs->GetCharacterIndex( font, character, ret_index ); } else *ret_index = character; return DFB_OK; } ================================================ FILE: src/core/fonts.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__FONTS_H__ #define __CORE__FONTS_H__ #include #include /**********************************************************************************************************************/ #define DFB_FONT_MAX_LAYERS 2 typedef struct { DFBResult (*GetCharacterIndex)( CoreFont *thiz, unsigned int character, unsigned int *ret_index ); DFBResult (*DecodeText) ( CoreFont *thiz, const void *text, int length, unsigned int *ret_indices, int *ret_num ); } CoreFontEncodingFuncs; typedef struct { DirectLink link; DFBTextEncodingID encoding; char *name; const CoreFontEncodingFuncs *funcs; int magic; } CoreFontEncoding; typedef enum { CFF_NONE = 0x00000000, CFF_SUBPIXEL_ADVANCE = 0x00000001, CFF_ALL = 0x00000001, } CoreFontFlags; struct __DFB_CoreFont { CoreDFB *core; CoreFontManager *manager; DFBFontDescription description; /* original description used to create the font */ DFBSurfaceBlittingFlags blittingflags; DFBSurfacePixelFormat pixel_format; DFBSurfaceCapabilities surface_caps; DFBFontAttributes attributes; struct { DirectHash *glyph_hash; CoreGlyphData *glyph_data[128]; } layers[DFB_FONT_MAX_LAYERS]; int height; /* font height */ int ascender; /* a positive value, the distance from the baseline to the top */ int descender; /* a negative value, the distance from the baseline to the bottom */ int maxadvance; /* width of largest character */ float up_unit_x; /* x coordinate of the unit vector pointing up */ float up_unit_y; /* y coordinate of the unit vector pointing up */ const CoreFontEncodingFuncs *utf8; /* for default encoding, DTEID_UTF8 */ CoreFontEncoding **encodings; /* for other encodings */ DFBTextEncodingID last_encoding; /* dynamic allocation implementation helper */ void *impl_data; /* a pointer used by the implementation */ DFBResult (*GetGlyphData)( CoreFont *thiz, unsigned int index, CoreGlyphData *data ); DFBResult (*RenderGlyph) ( CoreFont *thiz, unsigned int index, CoreGlyphData *data ); DFBResult (*GetKerning) ( CoreFont *thiz, unsigned int prev, unsigned int current, int *ret_x, int *ret_y ); int magic; int underline_position; int underline_thickness; CoreFontFlags flags; }; #define CORE_FONT_DEBUG_AT(Domain,font) \ do { \ D_DEBUG_AT( Domain, " -> ascender %d\n", (font)->ascender ); \ D_DEBUG_AT( Domain, " -> descender %d\n", (font)->descender ); \ D_DEBUG_AT( Domain, " -> height %d\n", (font)->height ); \ } while (0) struct __DFB_CoreGlyphData { DirectLink link; CoreFont *font; unsigned int index; unsigned int layer; CoreSurface *surface; /* contains bitmap of glyph */ int start; /* x offset of glyph in surface */ int width; /* width of the glyphs bitmap */ int height; /* height of the glyphs bitmap */ int left; /* x offset of the glyph */ int top; /* y offset of the glyph */ int xadvance; /* x placement of next glyph */ int yadvance; /* y placement of next glyph */ int magic; CoreFontCacheRow *row; bool inserted; bool retry; }; #define CORE_GLYPH_DATA_DEBUG_AT(Domain,data) \ do { \ D_DEBUG_AT( Domain, " -> index %u\n", (data)->index ); \ D_DEBUG_AT( Domain, " -> layer %u\n", (data)->layer ); \ D_DEBUG_AT( Domain, " -> row %p\n", (data)->row ); \ D_DEBUG_AT( Domain, " -> surface %p\n", (data)->surface ); \ D_DEBUG_AT( Domain, " -> start %d\n", (data)->start ); \ D_DEBUG_AT( Domain, " -> width %d\n", (data)->width ); \ D_DEBUG_AT( Domain, " -> height %d\n", (data)->height ); \ D_DEBUG_AT( Domain, " -> left %d\n", (data)->left ); \ D_DEBUG_AT( Domain, " -> top %d\n", (data)->top ); \ D_DEBUG_AT( Domain, " -> xadvance %d\n", (data)->xadvance ); \ D_DEBUG_AT( Domain, " -> yadvance %d\n", (data)->yadvance ); \ } while (0) /**********************************************************************************************************************/ typedef struct { unsigned int height; DFBSurfacePixelFormat pixel_format; DFBSurfaceCapabilities surface_caps; } CoreFontCacheType; /**********************************************************************************************************************/ DFBResult dfb_font_manager_create ( CoreDFB *core, CoreFontManager **ret_manager ); DFBResult dfb_font_manager_destroy ( CoreFontManager *manager ); DFBResult dfb_font_manager_init ( CoreFontManager *manager, CoreDFB *core ); DFBResult dfb_font_manager_deinit ( CoreFontManager *manager ); DFBResult dfb_font_manager_lock ( CoreFontManager *manager ); DFBResult dfb_font_manager_unlock ( CoreFontManager *manager ); DFBResult dfb_font_manager_get_cache ( CoreFontManager *manager, const CoreFontCacheType *type, CoreFontCache **ret_cache ); DFBResult dfb_font_manager_remove_lru_row( CoreFontManager *manager ); /**********************************************************************************************************************/ DFBResult dfb_font_cache_create ( CoreFontManager *manager, const CoreFontCacheType *type, CoreFontCache **ret_cache ); DFBResult dfb_font_cache_destroy ( CoreFontCache *cache ); DFBResult dfb_font_cache_init ( CoreFontCache *cache, CoreFontManager *manager, const CoreFontCacheType *type ); DFBResult dfb_font_cache_deinit ( CoreFontCache *cache ); DFBResult dfb_font_cache_get_row ( CoreFontCache *cache, unsigned int width, CoreFontCacheRow **ret_row ); DFBResult dfb_font_cache_row_create ( CoreFontCache *cache, CoreFontCacheRow **ret_row ); DFBResult dfb_font_cache_row_destroy ( CoreFontCacheRow *row ); DFBResult dfb_font_cache_row_init ( CoreFontCacheRow *row, CoreFontCache *cache ); DFBResult dfb_font_cache_row_deinit ( CoreFontCacheRow *row ); /**********************************************************************************************************************/ /* * Allocate and initialize a new font structure. */ DFBResult dfb_font_create ( CoreDFB *core, const DFBFontDescription *description, CoreFont **ret_font ); /* * Destroy all data in the font structure. */ void dfb_font_destroy ( CoreFont *font ); /* * Dispose resources that can be recreated, mainly glyph cache surfaces. */ DFBResult dfb_font_dispose ( CoreFont *font ); /* * Load glyph data from font. */ DFBResult dfb_font_get_glyph_data ( CoreFont *font, unsigned int index, unsigned int layer, CoreGlyphData **glyph_data ); /* * Register encoding implementations. * * The encoding can be DTEID_UTF8 or DTEID_OTHER, where in the latter case the actual id will be allocated dynamically. * * In the case of DTEID_UTF8, it's allowed to only provide GetCharacterIndex() and let the core do the DecodeText(), but * that would cause a GetCharacterIndex() call per decoded unicode character. So implementing both is advisable. * * If nothing is registered for DTEID_UTF8 at all, the core will pass the raw unicode characters to GetGlyphData(), * RenderGlyph() etc. It's a good choice if you want to avoid the character translation, having an efficient font module * which is based natively on unicode characters. * * For registering an encoding as DTEID_OTHER, both GetCharacterIndex() and DecodeText() must be provided. */ DFBResult dfb_font_register_encoding ( CoreFont *font, const char *name, const CoreFontEncodingFuncs *funcs, DFBTextEncodingID encoding ); /* * Decode a sequence of characters. */ DFBResult dfb_font_decode_text ( CoreFont *font, DFBTextEncodingID encoding, const void *text, int length, unsigned int *ret_indices, int *ret_num ); /* * Get the raw index of a single character. */ DFBResult dfb_font_decode_character ( CoreFont *font, DFBTextEncodingID encoding, u32 character, unsigned int *ret_index ); /**********************************************************************************************************************/ /* * Lock the font before accessing it. */ static __inline__ void dfb_font_lock( CoreFont *font ) { D_MAGIC_ASSERT( font, CoreFont ); dfb_font_manager_lock( font->manager ); } /* * Unlock the font after access. */ static __inline__ void dfb_font_unlock( CoreFont *font ) { D_MAGIC_ASSERT( font, CoreFont ); dfb_font_manager_unlock( font->manager ); } #endif ================================================ FILE: src/core/gfxcard.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Graphics, "Core/Graphics", "DirectFB Core Graphics" ); D_DEBUG_DOMAIN( Core_GraphicsOps, "Core/GraphicsOps", "DirectFB Core Graphics Operations" ); D_DEBUG_DOMAIN( Core_GfxState, "Core/GfxState", "DirectFB Core Gfx State" ); DEFINE_MODULE_DIRECTORY( dfb_graphics_drivers, "gfxdrivers", DFB_GRAPHICS_DRIVER_ABI_VERSION ); /**********************************************************************************************************************/ typedef struct { int magic; unsigned int videoram_length; /* Amount of usable memory */ char *module_name; GraphicsDriverInfo driver_info; GraphicsDeviceInfo device_info; void *device_data; FusionSkirmish lock; GraphicsDeviceLockFlags lock_flags; CardState *state; /* Current state of the graphics card. */ FusionID holder; /* Fusion ID of state owner. */ FusionObjectID last_allocation_id; bool pending_ops; long long ts_start; long long ts_busy; long long ts_busy_sum; } DFBGraphicsCoreShared; typedef struct { int magic; CoreDFB *core; DFBGraphicsCoreShared *shared; DirectModuleEntry *module; const GraphicsDriverFuncs *driver_funcs; void *driver_data; void *device_data; /* copy of shared->device_data */ CardCapabilities caps; /* local caps */ CardLimitations limits; /* local limits */ GraphicsDeviceFuncs funcs; } DFBGraphicsCore; DFB_CORE_PART( graphics_core, GraphicsCore ); /**********************************************************************************************************************/ static DFBGraphicsCore *card = NULL; /* * Load/probe/unload a driver module one at a time until a suitable driver is found and return its symlinked functions. */ static void dfb_gfxcard_find_driver( CoreDFB *core ) { DFBGraphicsCoreShared *shared; DirectLink *link; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); D_DEBUG_AT( Core_Graphics, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; link = dfb_graphics_drivers.entries; while (direct_list_check_link( link )) { DirectModuleEntry *module = (DirectModuleEntry*) link; const GraphicsDriverFuncs *funcs; D_DEBUG_AT( Core_Graphics, " -> module %p\n", module ); link = link->next; funcs = direct_module_ref( module ); if (!funcs) { D_DEBUG_AT( Core_Graphics, " -> ref failed!\n" ); continue; } if (!card->module) { D_DEBUG_AT( Core_Graphics, " -> probing '%s'...\n", module->name ); if (funcs->Probe()) { D_DEBUG_AT( Core_Graphics, " => SUCCESS\n" ); funcs->GetDriverInfo( &shared->driver_info ); card->module = module; card->driver_funcs = funcs; shared->module_name = SHSTRDUP( pool, module->name ); continue; } else D_DEBUG_AT( Core_Graphics, " => FAIL\n" ); } else D_DEBUG_AT( Core_Graphics, " -> having driver\n" ); direct_module_unref( module ); } } static void InitDevice_Async( void *ctx, void *ctx2 ) { DFBResult ret; DFBGraphicsCore *data = ctx; DFBGraphicsCoreShared *shared; const GraphicsDriverFuncs *funcs; D_ASSERT( data != NULL ); D_ASSERT( data->shared != NULL ); D_ASSERT( data->driver_funcs != NULL ); shared = data->shared; funcs = data->driver_funcs; ret = funcs->InitDevice( &shared->device_info, data->driver_data, data->device_data ); if (ret) { D_DERROR( ret, "Core/Graphics: Could not init device!\n" ); return; } if (data->funcs.EngineReset) data->funcs.EngineReset( data->driver_data, data->device_data ); data->caps = shared->device_info.caps; data->limits = shared->device_info.limits; D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", shared->device_info.vendor, shared->device_info.name, shared->driver_info.version.major, shared->driver_info.version.minor, shared->driver_info.vendor ); } static DFBResult dfb_graphics_core_initialize( CoreDFB *core, DFBGraphicsCore *data, DFBGraphicsCoreShared *shared ) { DFBResult ret; int videoram_length; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); D_DEBUG_AT( Core_Graphics, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); card = data; data->core = core; data->shared = shared; /* Fill generic driver info. */ gGetDriverInfo( &shared->driver_info ); /* Fill generic device info. */ gGetDeviceInfo( &shared->device_info ); if (!shared->device_info.limits.dst_max.w) shared->device_info.limits.dst_max.w = INT_MAX; if (!shared->device_info.limits.dst_max.h) shared->device_info.limits.dst_max.h = INT_MAX; /* Limit video ram length. */ videoram_length = dfb_system_videoram_length(); if (videoram_length) { if (dfb_config->videoram_limit > 0 && dfb_config->videoram_limit < videoram_length) shared->videoram_length = dfb_config->videoram_limit; else shared->videoram_length = videoram_length; } /* Build a list of available drivers. */ direct_modules_explore_directory( &dfb_graphics_drivers ); /* Load driver. */ if (dfb_system_caps() & CSCAPS_ACCELERATION) dfb_gfxcard_find_driver( core ); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); data->device_data = shared->device_data = SHCALLOC( pool, 1, shared->driver_info.device_data_size ); ret = funcs->InitDriver( &data->funcs, data->driver_data, data->device_data, core ); if (ret) { SHFREE( pool, shared->device_data ); SHFREE( pool, shared->module_name ); D_FREE( data->driver_data ); card = NULL; return ret; } if (dfb_config->call_nodirect) Core_AsyncCall( InitDevice_Async, data, NULL ); else InitDevice_Async( data, NULL ); } else D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", shared->device_info.vendor, shared->device_info.name, shared->driver_info.version.major, shared->driver_info.version.minor, shared->driver_info.vendor ); if (dfb_config->software_only) { if (data->funcs.CheckState) { data->funcs.CheckState = NULL; D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); } } else { data->caps = shared->device_info.caps; data->limits = shared->device_info.limits; } fusion_skirmish_init2( &shared->lock, "GfxCard", dfb_core_world( core ), fusion_config->secure_fusion ); D_MAGIC_SET( data, DFBGraphicsCore ); D_MAGIC_SET( shared, DFBGraphicsCoreShared ); return DFB_OK; } /* * Load the driver module used by the session. */ static void dfb_gfxcard_load_driver( void ) { DFBGraphicsCoreShared *shared; DirectLink *link; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; if (!shared->module_name) return; link = dfb_graphics_drivers.entries; while (direct_list_check_link( link )) { DirectModuleEntry *module = (DirectModuleEntry*) link; const GraphicsDriverFuncs *funcs; link = link->next; funcs = direct_module_ref( module ); if (!funcs) continue; if (!card->module && !strcmp( module->name, shared->module_name )) { card->module = module; card->driver_funcs = funcs; } else direct_module_unref( module ); } } static DFBResult dfb_graphics_core_join( CoreDFB *core, DFBGraphicsCore *data, DFBGraphicsCoreShared *shared ) { DFBResult ret; GraphicsDriverInfo driver_info; D_DEBUG_AT( Core_Graphics, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBGraphicsCoreShared ); card = data; data->core = core; data->shared = shared; /* Initialize software rasterizer. */ gGetDriverInfo( &driver_info ); /* Build a list of available drivers. */ direct_modules_explore_directory( &dfb_graphics_drivers ); /* Load driver. */ if (dfb_system_caps() & CSCAPS_ACCELERATION) dfb_gfxcard_load_driver(); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); data->device_data = shared->device_data; ret = funcs->InitDriver( &data->funcs, data->driver_data, data->device_data, core ); if (ret) { D_FREE( data->driver_data ); return ret; } } else if (shared->module_name) { D_ERROR( "Core/Graphics: Could not load driver used by the running session!\n" ); return DFB_UNSUPPORTED; } D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", shared->device_info.vendor, shared->device_info.name, shared->driver_info.version.major, shared->driver_info.version.minor, shared->driver_info.vendor ); if (dfb_config->software_only) { if (data->funcs.CheckState) { data->funcs.CheckState = NULL; D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); } } else { data->caps = shared->device_info.caps; data->limits = shared->device_info.limits; } D_MAGIC_SET( data, DFBGraphicsCore ); return DFB_OK; } static DFBResult dfb_graphics_core_shutdown( DFBGraphicsCore *data, bool emergency ) { DFBGraphicsCoreShared *shared; FusionSHMPoolShared *pool; D_DEBUG_AT( Core_Graphics, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); shared = data->shared; pool = dfb_core_shmpool( data->core ); dfb_gfxcard_lock( GDLF_SYNC ); if (data->driver_funcs) { const GraphicsDriverFuncs *funcs = data->driver_funcs; funcs->CloseDevice( data->driver_data, data->device_data ); funcs->CloseDriver( data->driver_data ); direct_module_unref( data->module ); SHFREE( pool, data->device_data ); D_FREE( data->driver_data ); } fusion_skirmish_destroy( &shared->lock ); if (shared->module_name) SHFREE( pool, shared->module_name ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); card = NULL; return DFB_OK; } static DFBResult dfb_graphics_core_leave( DFBGraphicsCore *data, bool emergency ) { D_DEBUG_AT( Core_Graphics, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); if (data->driver_funcs) { data->driver_funcs->CloseDriver( data->driver_data ); direct_module_unref( data->module ); D_FREE( data->driver_data ); } D_MAGIC_CLEAR( data ); card = NULL; return DFB_OK; } static DFBResult dfb_graphics_core_suspend( DFBGraphicsCore *data ) { D_DEBUG_AT( Core_Graphics, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); return DFB_OK; } static DFBResult dfb_graphics_core_resume( DFBGraphicsCore *data ) { D_DEBUG_AT( Core_Graphics, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBGraphicsCore ); D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); dfb_gfxcard_unlock(); return DFB_OK; } /**********************************************************************************************************************/ static void dfb_gfxcard_update_stats( long long now ); static void dfb_gfxcard_switch_busy ( void ); static void dfb_gfxcard_switch_idle ( void ); DFBResult dfb_gfxcard_lock( GraphicsDeviceLockFlags flags ) { DFBResult ret; DFBGraphicsCoreShared *shared; GraphicsDeviceFuncs *funcs; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; funcs = &card->funcs; D_DEBUG_AT( Core_Graphics, "%s()\n", __FUNCTION__ ); ret = fusion_skirmish_prevail( &shared->lock ); if (ret) return ret; if ((flags & GDLF_SYNC) && funcs->EngineSync) { /* Start command processing if not already running. */ if (!dfb_config->gfx_emit_early && shared->pending_ops && card->funcs.EmitCommands) { dfb_gfxcard_switch_busy(); card->funcs.EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } ret = funcs->EngineSync( card->driver_data, card->device_data ); if (ret) { if (funcs->EngineReset) funcs->EngineReset( card->driver_data, card->device_data ); shared->state = NULL; fusion_skirmish_dismiss( &shared->lock ); return ret; } dfb_gfxcard_switch_idle(); } if ((shared->lock_flags & GDLF_RESET) && funcs->EngineReset) funcs->EngineReset( card->driver_data, card->device_data ); if (shared->lock_flags & GDLF_INVALIDATE) { if (funcs->InvalidateState) funcs->InvalidateState( card->driver_data, card->device_data ); shared->state = NULL; } shared->lock_flags = flags; return DFB_OK; } void dfb_gfxcard_unlock() { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_DEBUG_AT( Core_Graphics, "%s()\n", __FUNCTION__ ); shared = card->shared; fusion_skirmish_dismiss( &shared->lock ); } DFBResult dfb_gfxcard_flush() { DFBResult ret; DFBGraphicsCoreShared *shared; GraphicsDeviceFuncs *funcs; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_DEBUG_AT( Core_Graphics, "%s()\n", __FUNCTION__ ); if (dfb_config->gfx_emit_early) { D_DEBUG_AT( Core_Graphics, " -> gfx-emit-early\n" ); return DFB_OK; } shared = card->shared; funcs = &card->funcs; ret = fusion_skirmish_prevail( &shared->lock ); if (ret) return ret; /* Start command processing if not already running. */ if (shared->pending_ops && funcs->EmitCommands) { D_DEBUG_AT( Core_Graphics, " -> pending ops, emitting...\n" ); dfb_gfxcard_switch_busy(); funcs->EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } else D_DEBUG_AT( Core_Graphics, " -> nothing to emit!\n" ); fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } void dfb_gfxcard_start_drawing( CardState *state ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); if (card->funcs.StartDrawing) card->funcs.StartDrawing( card->driver_data, card->device_data, state ); } void dfb_gfxcard_stop_drawing( CardState *state ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); if (card->funcs.StopDrawing) card->funcs.StopDrawing( card->driver_data, card->device_data, state ); } bool dfb_gfxcard_state_check( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; int cx2, cy2; CoreSurfaceBuffer *dst_buffer; CoreSurfaceBuffer *src_buffer; D_ASSERT( card != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); D_MAGIC_ASSERT_IF( state->source, CoreSurface ); D_ASSERT( state->clip.x2 >= state->clip.x1 ); D_ASSERT( state->clip.y2 >= state->clip.y1 ); D_ASSERT( state->clip.x1 >= 0 ); D_ASSERT( state->clip.y1 >= 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x, %4d,%4d-%4d,%4d )\n", __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) ); if (DFB_BLITTING_FUNCTION(accel)) { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, state, accel, state->source, state->destination ); } else { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, state, accel, state->destination ); } if (state->clip.x1 < 0) { state->clip.x1 = 0; state->modified |= SMF_CLIP; } if (state->clip.y1 < 0) { state->clip.y1 = 0; state->modified |= SMF_CLIP; } D_DEBUG_AT( Core_GfxState, " <- checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Destination may have been destroyed. */ if (!state->destination) { D_BUG( "no destination" ); return false; } /* Destination buffer may have been destroyed (suspended). i.e by a vt-switching. */ if (state->destination->num_buffers == 0) { D_DEBUG_AT( Core_GfxState, " -> no buffers in destination surface\n" ); return false; } if (DFB_BLITTING_FUNCTION( accel )) { /* Source may have been destroyed. */ if (!state->source) { D_BUG( "no source" ); return false; } /* Mask may have been destroyed. */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR) && !state->source_mask) { D_BUG( "no mask" ); return false; } /* Source2 may have been destroyed. */ if (accel == DFXL_BLIT2 && !state->source2) { D_BUG( "no source2" ); return false; } } ret = dfb_surface_lock( state->destination ); if (ret) return false; dst_buffer = dfb_surface_get_buffer( state->destination, state->to ); D_MAGIC_ASSERT( dst_buffer, CoreSurfaceBuffer ); dfb_surface_unlock( state->destination ); D_ASSUME( state->clip.x2 < state->destination->config.size.w ); D_ASSUME( state->clip.y2 < state->destination->config.size.h ); cx2 = state->destination->config.size.w - 1; cy2 = state->destination->config.size.h - 1; if (state->clip.x2 > cx2) { state->clip.x2 = cx2; if (state->clip.x1 > cx2) state->clip.x1 = cx2; state->modified |= SMF_CLIP; } if (state->clip.y2 > cy2) { state->clip.y2 = cy2; if (state->clip.y1 > cy2) state->clip.y1 = cy2; state->modified |= SMF_CLIP; } /* If there's no CheckState() function, there's no acceleration at all. */ if (!card->funcs.CheckState) { D_DEBUG_AT( Core_GfxState, " -> no acceleration available\n" ); return false; } /* * Check if this function has been disabled temporarily. */ if (state->disabled & accel) { D_DEBUG_AT( Core_GfxState, " -> acceleration disabled\n" ); return false; } /* If destination or blend functions have been changed... */ if (state->modified & (SMF_DESTINATION | SMF_SRC_BLEND | SMF_DST_BLEND | SMF_RENDER_OPTIONS)) { /* ...force rechecking for all functions. */ state->checked = DFXL_NONE; } else { /* If source/mask or blitting flags have been changed... */ if (state->modified & (SMF_SOURCE | SMF_BLITTING_FLAGS | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS)) { /* ...force rechecking for all blitting functions. */ state->checked &= ~DFXL_ALL_BLIT; } else if (state->modified & SMF_SOURCE2) { /* Otherwise force rechecking for Blit2() function if source2 has been changed. */ state->checked &= ~DFXL_BLIT2; } /* If drawing flags have been changed... */ if (state->modified & SMF_DRAWING_FLAGS) { /* ...force rechecking for all drawing functions. */ state->checked &= ~DFXL_ALL_DRAW; } } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* If the function needs to be checked. */ if (!(state->checked & accel)) { /* Unset unchecked functions. */ state->accel &= state->checked; /* Call driver to (re)set the bit if the function is supported. */ card->funcs.CheckState( card->driver_data, card->device_data, state, accel ); /* Add the function to 'checked' functions. */ state->checked |= accel; /* Add additional functions the driver might have checked, too. */ state->checked |= state->accel; } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Move modification flags to the set for drivers. */ state->mod_hw |= state->modified; state->modified = SMF_NONE; /* If back_buffer policy is 'system only' and the GPU does not fully support system memory surfaces, there's no acceleration available. */ if ((dst_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM && card->caps.flags & CCF_WRITESYSMEM)) || (!(card->caps.flags & CCF_RENDEROPTS) && (state->render_options & DSRO_MATRIX))) { /* Clear 'accelerated' functions. */ state->accel = DFXL_NONE; state->checked = DFXL_ALL; } else if (DFB_BLITTING_FUNCTION( accel )) { /* If the front buffer policy of the source is 'system only', no accelerated blitting is available. */ ret = dfb_surface_lock( state->source ); if (ret) return false; src_buffer = dfb_surface_get_buffer( state->source, state->from ); D_MAGIC_ASSERT( src_buffer, CoreSurfaceBuffer ); dfb_surface_unlock( state->source ); if (src_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM)) { /* Clear 'accelerated blitting' functions. */ state->accel &= ~DFXL_ALL_BLIT; state->checked |= DFXL_ALL_BLIT; } } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Return whether the function bit is set. */ return state->accel & accel; } /* * This function returns non zero after successful locking the surface(s) for access by hardware. * Propagate state changes to driver. */ static bool dfb_gfxcard_state_acquire( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; DFBGraphicsCoreShared *shared; CoreSurfaceAccessFlags access = CSAF_WRITE; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); D_MAGIC_ASSERT_IF( state->source, CoreSurface ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x, %4d,%4d-%4d,%4d )\n", __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) ); shared = card->shared; /* Find locking flags. */ if (DFB_BLITTING_FUNCTION( accel )) { if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | DSBLIT_DST_COLORKEY)) access |= CSAF_READ; } else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY)) access |= CSAF_READ; if (DFB_BLITTING_FUNCTION(accel)) { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, state, accel, state->source, state->destination ); } else { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, state, accel, state->destination ); } /* Push our own identity for buffer locking calls (locality of accessor). */ Core_PushIdentity( 0 ); /* Lock destination. */ ret = dfb_surface_lock_buffer2( state->destination, state->to, state->destination_flip_count_used ? state->destination_flip_count : state->destination->flips, state->to_eye, CSAID_GPU, access, &state->dst ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock destination for GPU access!\n" ); Core_PopIdentity(); return false; } /* If blitting... */ if (DFB_BLITTING_FUNCTION( accel )) { /* ...lock source for reading. */ if (state->source_buffer) { dfb_surface_lock( state->source ); CoreSurfaceBuffer *src_buffer = state->source_buffer; ret = dfb_surface_buffer_lock( src_buffer, CSAID_GPU, CSAF_READ, &state->src ); dfb_surface_unlock( state->source ); } else if (state->source_flip_count_used) ret = dfb_surface_lock_buffer2( state->source, state->from, state->source_flip_count, state->from_eye, CSAID_GPU, CSAF_READ, &state->src ); else ret = dfb_surface_lock_buffer2( state->source, state->from, state->source->flips, state->from_eye, CSAID_GPU, CSAF_READ, &state->src ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source for GPU access!\n" ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); return false; } /* If using a mask... */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { /* ...lock source mask for reading. */ ret = dfb_surface_lock_buffer2( state->source_mask, state->from, state->source_mask->flips, state->from_eye, CSAID_GPU, CSAF_READ, &state->src_mask ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source mask for GPU access!\n" ); dfb_surface_unlock_buffer( state->source, &state->src ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); return false; } state->flags |= CSF_SOURCE_MASK_LOCKED; } /* If using source2... */ if (accel == DFXL_BLIT2) { /* ...lock source2 for reading. */ ret = dfb_surface_lock_buffer2( state->source2, state->from, state->source2->flips, state->from_eye, CSAID_GPU, CSAF_READ, &state->src2 ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source2 for GPU access!\n" ); if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } dfb_surface_unlock_buffer( state->source, &state->src ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); return false; } state->flags |= CSF_SOURCE2_LOCKED; } state->flags |= CSF_SOURCE_LOCKED; } /* Make sure that state setting with subsequent command execution isn't done by two processes simultaneously. */ ret = dfb_gfxcard_lock( GDLF_NONE ); if (ret) { D_DERROR( ret, "Core/GfxState: Could not lock GPU!\n" ); dfb_surface_unlock_buffer( state->destination, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } if (state->flags & CSF_SOURCE2_LOCKED) { dfb_surface_unlock_buffer( state->source2, &state->src2 ); state->flags &= ~CSF_SOURCE2_LOCKED; } Core_PopIdentity(); return false; } /* If we are switching to another state... */ if (state != shared->state || state->fusion_id != shared->holder) { D_DEBUG_AT( Core_GfxState, " -> switch from %p [%lu] to %p [%lu]\n", shared->state, shared->holder, state, state->fusion_id ); /* ...set all modification bits and clear 'set' functions. */ state->mod_hw |= SMF_ALL; state->set = DFXL_NONE; shared->state = state; shared->holder = state->fusion_id; } dfb_state_update( state, state->flags & (CSF_SOURCE_LOCKED | CSF_SOURCE2_LOCKED | CSF_SOURCE_MASK_LOCKED) ); D_DEBUG_AT( Core_GfxState, " -> modified 0x%08x, mod_hw 0x%08x\n", state->modified, state->mod_hw ); /* Move modification flags for drivers. */ state->mod_hw |= state->modified; state->modified = SMF_ALL; if (shared->last_allocation_id != state->dst.allocation->object.id) { shared->last_allocation_id = state->dst.allocation->object.id; /* Start command processing if not already running. */ if (!dfb_config->gfx_emit_early && shared->pending_ops && card->funcs.EmitCommands) { dfb_gfxcard_switch_busy(); card->funcs.EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } } /* If function hasn't been set or state is modified, call the driver function to propagate the state changes. */ D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); if (state->mod_hw || !(state->set & accel)) { card->funcs.SetState( card->driver_data, card->device_data, &card->funcs, state, accel ); D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); } state->modified = SMF_NONE; return true; } /* * This function checks if acceleration is available for the specific function using the given state and returns * non zero after successful locking the surface(s) for access by hardware. Propagate state changes to driver. */ static bool dfb_gfxcard_state_check_acquire( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; int cx2, cy2; CoreSurfaceBuffer *dst_buffer; CoreSurfaceBuffer *src_buffer; DFBGraphicsCoreShared *shared; FusionSkirmish *locks[4]; unsigned int num_locks = 0; CoreSurfaceAccessFlags access = CSAF_WRITE; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); D_MAGIC_ASSERT_IF( state->source, CoreSurface ); D_ASSERT( state->clip.x2 >= state->clip.x1 ); D_ASSERT( state->clip.y2 >= state->clip.y1 ); D_ASSERT( state->clip.x1 >= 0 ); D_ASSERT( state->clip.y1 >= 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x, %4d,%4d-%4d,%4d )\n", __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) ); shared = card->shared; locks[num_locks++] = &state->destination->lock; /* Find locking flags. */ if (DFB_BLITTING_FUNCTION( accel )) { if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | DSBLIT_DST_COLORKEY)) access |= CSAF_READ; } else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY)) access |= CSAF_READ; if (DFB_BLITTING_FUNCTION(accel)) { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, state, accel, state->source, state->destination ); locks[num_locks++] = &state->source->lock; /* If using a mask. */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) locks[num_locks++] = &state->source_mask->lock; /* If using source2. */ if (accel == DFXL_BLIT2) locks[num_locks++] = &state->source2->lock; } else { D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, state, accel, state->destination ); } if (state->clip.x1 < 0) { state->clip.x1 = 0; state->modified |= SMF_CLIP; } if (state->clip.y1 < 0) { state->clip.y1 = 0; state->modified |= SMF_CLIP; } D_DEBUG_AT( Core_GfxState, " <- checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Destination may have been destroyed. */ if (!state->destination) { D_BUG( "no destination" ); return false; } /* Destination buffer may have been destroyed (suspended). i.e by a vt-switching */ if (state->destination->num_buffers == 0 ) return false; if (DFB_BLITTING_FUNCTION( accel )) { /* Source may have been destroyed. */ if (!state->source) { D_BUG( "no source" ); return false; } /* Mask may have been destroyed. */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR) && !state->source_mask) { D_BUG( "no mask" ); return false; } /* Source2 may have been destroyed. */ if (accel == DFXL_BLIT2 && !state->source2) { D_BUG( "no source2" ); return false; } } D_ASSUME( state->clip.x2 < state->destination->config.size.w ); D_ASSUME( state->clip.y2 < state->destination->config.size.h ); cx2 = state->destination->config.size.w - 1; cy2 = state->destination->config.size.h - 1; if (state->clip.x2 > cx2) { state->clip.x2 = cx2; if (state->clip.x1 > cx2) state->clip.x1 = cx2; state->modified |= SMF_CLIP; } if (state->clip.y2 > cy2) { state->clip.y2 = cy2; if (state->clip.y1 > cy2) state->clip.y1 = cy2; state->modified |= SMF_CLIP; } /* If there's no CheckState() function, there's no acceleration at all. */ if (!card->funcs.CheckState) return false; /* Check if this function has been disabled temporarily. */ if (state->disabled & accel) return false; if (core_dfb->shutdown_running) return false; if (fusion_skirmish_prevail_multi( locks, num_locks )) return false; dfb_state_update_destination( state ); /* If destination or blend functions have been changed... */ if (state->modified & (SMF_DESTINATION | SMF_SRC_BLEND | SMF_DST_BLEND | SMF_RENDER_OPTIONS)) { /* ...force rechecking for all functions. */ state->checked = DFXL_NONE; if (state->destination->config.size.w < card->limits.dst_min.w || state->destination->config.size.h < card->limits.dst_min.h || state->destination->config.size.w > card->limits.dst_max.w || state->destination->config.size.h > card->limits.dst_max.h) { fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } } else { /* If source/mask or blitting flags have been changed... */ if (state->modified & (SMF_SOURCE | SMF_BLITTING_FLAGS | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS)) { /* ...force rechecking for all blitting functions. */ state->checked &= ~DFXL_ALL_BLIT; } else if (state->modified & SMF_SOURCE2) { /* Otherwise force rechecking for Blit2() function if source2 has been changed. */ state->checked &= ~DFXL_BLIT2; } /* If drawing flags have been changed... */ if (state->modified & SMF_DRAWING_FLAGS) { /* ...force rechecking for all drawing functions. */ state->checked &= ~DFXL_ALL_DRAW; } if (state->source) { if (state->source->config.size.w < card->limits.dst_min.w || state->source->config.size.h < card->limits.dst_min.h || state->source->config.size.w > card->limits.dst_max.w || state->source->config.size.h > card->limits.dst_max.h) { fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } } } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); if (DFB_BLITTING_FUNCTION(accel)) { dfb_state_update_sources( state, CSF_SOURCE ); /* If using a mask. */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) dfb_state_update_sources( state, CSF_SOURCE_MASK ); /* If using source2. */ if (accel == DFXL_BLIT2) dfb_state_update_sources( state, CSF_SOURCE2 ); } /* If the function needs to be checked. */ if (!(state->checked & accel)) { /* Unset unchecked functions. */ state->accel &= state->checked; /* Call driver to (re)set the bit if the function is supported. */ card->funcs.CheckState( card->driver_data, card->device_data, state, accel ); /* Add the function to 'checked' functions. */ state->checked |= accel; /* Add additional functions the driver might have checked, too. */ state->checked |= state->accel; } D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Push our own identity for buffer locking calls (locality of accessor) */ Core_PushIdentity( 0 ); /* Move modification flags for drivers. */ state->mod_hw |= state->modified; state->modified = SMF_NONE; if (state->destination_flip_count_used) dst_buffer = dfb_surface_get_buffer3( state->destination, state->to, state->to_eye, state->destination_flip_count ); else dst_buffer = dfb_surface_get_buffer3( state->destination, state->to, state->to_eye, state->destination->flips ); D_MAGIC_ASSERT( dst_buffer, CoreSurfaceBuffer ); /* If back_buffer policy is 'system only' and the GPU does not fully support system memory surfaces, there's no acceleration available. */ if ((dst_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM && card->caps.flags & CCF_WRITESYSMEM)) || (!(card->caps.flags & CCF_RENDEROPTS) && (state->render_options & DSRO_MATRIX))) { /* Clear 'accelerated' functions. */ state->accel = DFXL_NONE; state->checked = DFXL_ALL; Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } if (!(state->accel & accel)) { D_DEBUG_AT( Core_GfxState, " -> not accelerated\n" ); Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } ret = dfb_surface_buffer_lock( dst_buffer, CSAID_GPU, access, &state->dst ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock destination for GPU access!\n" ); Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } if (DFB_BLITTING_FUNCTION( accel )) { /* If the front buffer policy of the source is 'system only', no accelerated blitting is available. */ if (state->source_buffer) src_buffer = state->source_buffer; else if (state->source_flip_count_used) src_buffer = dfb_surface_get_buffer3( state->source, state->from, state->from_eye, state->source_flip_count ); else src_buffer = dfb_surface_get_buffer3( state->source, state->from, state->from_eye, state->source->flips ); D_MAGIC_ASSERT( src_buffer, CoreSurfaceBuffer ); if (src_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM)) { D_DEBUG_AT( Core_GfxState, " -> cannot read source sysmem\n" ); /* Clear 'accelerated blitting' functions. */ state->accel &= ~DFXL_ALL_BLIT; state->checked |= DFXL_ALL_BLIT; } ret = dfb_surface_buffer_lock( src_buffer, CSAID_GPU, CSAF_READ, &state->src ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source for GPU access!\n" ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } /* If using a mask... */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { /* ...lock source mask for reading */ ret = dfb_surface_lock_buffer2( state->source_mask, state->from, state->source_mask->flips, state->from_eye, CSAID_GPU, CSAF_READ, &state->src_mask ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source mask for GPU access!\n" ); dfb_surface_unlock_buffer( state->source, &state->src ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } state->flags |= CSF_SOURCE_MASK_LOCKED; } /* If using source2... */ if (accel == DFXL_BLIT2) { /* ...lock source2 for reading */ ret = dfb_surface_lock_buffer2( state->source2, state->from, state->source2->flips, state->from_eye, CSAID_GPU, CSAF_READ, &state->src2 ); if (ret) { D_DEBUG_AT( Core_GfxState, " -> could not lock source2 for GPU access!\n" ); if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } dfb_surface_unlock_buffer( state->source, &state->src ); dfb_surface_unlock_buffer( state->destination, &state->dst ); Core_PopIdentity(); fusion_skirmish_dismiss_multi( locks, num_locks ); return false; } state->flags |= CSF_SOURCE2_LOCKED; } state->flags |= CSF_SOURCE_LOCKED; } fusion_skirmish_dismiss_multi( locks, num_locks ); D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", state->checked, state->accel, state->modified, state->mod_hw ); /* Make sure that state setting with subsequent command execution isn't done by two processes simultaneously. */ if (dfb_gfxcard_lock( GDLF_NONE )) { D_DERROR( ret, "Core/GfxState: Could not lock GPU!\n" ); dfb_surface_unlock_buffer( state->destination, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } if (state->flags & CSF_SOURCE2_LOCKED) { dfb_surface_unlock_buffer( state->source2, &state->src2 ); state->flags &= ~CSF_SOURCE2_LOCKED; } Core_PopIdentity(); return false; } /* If we are switching to another state... */ if (state != shared->state || state->fusion_id != shared->holder) { D_DEBUG_AT( Core_GfxState, " -> switch from %p [%lu] to %p [%lu]\n", shared->state, shared->holder, state, state->fusion_id ); /* ...set all modification bits and clear 'set' functions. */ state->mod_hw |= SMF_ALL; state->set = DFXL_NONE; shared->state = state; shared->holder = state->fusion_id; } D_DEBUG_AT( Core_GfxState, " -> modified 0x%08x, mod_hw 0x%08x\n", state->modified, state->mod_hw ); /* Move modification flags for drivers. */ state->mod_hw |= state->modified; state->modified = SMF_ALL; if (shared->last_allocation_id != state->dst.allocation->object.id) { shared->last_allocation_id = state->dst.allocation->object.id; /* Start command processing if not already running. */ if (!dfb_config->gfx_emit_early && shared->pending_ops && card->funcs.EmitCommands) { dfb_gfxcard_switch_busy(); card->funcs.EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } } /* If function hasn't been set or state is modified, call the driver function to propagate the state changes. */ D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); if (state->mod_hw || !(state->set & accel)) { card->funcs.SetState( card->driver_data, card->device_data, &card->funcs, state, accel ); D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); } state->modified = SMF_NONE; return true; } /* * Unlock destination and possibly the source. */ static void dfb_gfxcard_state_release( CardState *state ) { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->destination != NULL ); shared = card->shared; if (!dfb_config->software_only) { /* Store the serial of the operation. */ if (card->funcs.GetSerial) card->funcs.GetSerial( card->driver_data, card->device_data, &state->dst.allocation->gfx_serial ); if (dfb_config->gfx_emit_early && card->funcs.EmitCommands) { dfb_gfxcard_switch_busy(); card->funcs.EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } else shared->pending_ops = true; } /* Allow others to use the hardware. */ dfb_gfxcard_unlock(); /* Destination always gets locked during acquisition. */ dfb_surface_unlock_buffer( state->destination, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } if (state->flags & CSF_SOURCE2_LOCKED) { dfb_surface_unlock_buffer( state->source2, &state->src2 ); state->flags &= ~CSF_SOURCE2_LOCKED; } Core_PopIdentity(); } void dfb_gfxcard_state_init ( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); if (dfb_config->software_only) return; if (card) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); if (card->funcs.StateInit) card->funcs.StateInit( card->driver_data, card->device_data, state ); } } void dfb_gfxcard_state_destroy ( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); if (state->gfxs) { GenefxState *gfxs = state->gfxs; if (gfxs->ABstart) D_FREE( gfxs->ABstart ); D_FREE( gfxs ); } if (dfb_config->software_only) return; if (card) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); if (card->funcs.StateDestroy) card->funcs.StateDestroy( card->driver_data, card->device_data, state ); } } /**********************************************************************************************************************/ #define DFB_TRANSFORM(x,y,m,affine) \ do { \ s32 _x, _y, _w; \ if (affine) { \ _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2] + 0x8000) >> 16; \ _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5] + 0x8000) >> 16; \ } \ else { \ _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2]); \ _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5]); \ _w = ((x) * (m)[6] + (y) * (m)[7] + (m)[8]); \ if (!_w) { \ _x = (_x < 0) ? -0x7fffffff : 0x7fffffff; \ _y = (_y < 0) ? -0x7fffffff : 0x7fffffff; \ } \ else { \ _x /= _w; \ _y /= _w; \ } \ } \ (x) = _x; \ (y) = _y; \ } while (0) typedef struct { int xi; int xf; int mi; int mf; int _2dy; } DDA; #define SETUP_DDA(xs,ys,xe,ye,dda) \ do { \ int dx = (xe) - (xs); \ int dy = (ye) - (ys); \ dda.xi = (xs); \ if (dy != 0) { \ dda.mi = dx / dy; \ dda.mf = 2 * (dx % dy); \ dda.xf = -dy; \ dda._2dy = 2 * dy; \ if (dda.mf < 0) { \ dda.mf += 2 * ABS( dy ); \ dda.mi--; \ } \ } \ else { \ dda.mi = 0; \ dda.mf = 0; \ dda.xf = 0; \ dda._2dy = 0; \ } \ } while (0) #define INC_DDA(dda) \ do { \ dda.xi += dda.mi; \ dda.xf += dda.mf; \ if (dda.xf > 0) { \ dda.xi++; \ dda.xf -= dda._2dy; \ } \ } while (0) static void fill_tri( DFBTriangle *tri, CardState *state, bool accelerated ) { int y, yend; DDA dda1 = { .xi = 0 }; DDA dda2 = { .xi = 0 }; int clip_x1 = state->clip.x1; int clip_x2 = state->clip.x2; D_MAGIC_ASSERT( state, CardState ); y = tri->y1; yend = tri->y3; if (yend > state->clip.y2) yend = state->clip.y2; SETUP_DDA( tri->x1, tri->y1, tri->x3, tri->y3, dda1 ); SETUP_DDA( tri->x1, tri->y1, tri->x2, tri->y2, dda2 ); while (y <= yend) { DFBRectangle rect; if (y == tri->y2) { if (tri->y2 == tri->y3) return; SETUP_DDA( tri->x2, tri->y2, tri->x3, tri->y3, dda2 ); } rect.w = ABS( dda1.xi - dda2.xi ); rect.x = MIN( dda1.xi, dda2.xi ); if (clip_x2 < rect.x + rect.w) rect.w = clip_x2 - rect.x + 1; if (rect.w > 0) { if (clip_x1 > rect.x) { rect.w -= (clip_x1 - rect.x); rect.x = clip_x1; } rect.y = y; rect.h = 1; if (rect.w > 0 && rect.y >= state->clip.y1) { if (accelerated) card->funcs.FillRectangle( card->driver_data, card->device_data, &rect ); else gFillRectangle( state, &rect ); } } INC_DDA( dda1 ); INC_DDA( dda2 ); y++; } } void dfb_gfxcard_fillrectangles( DFBRectangle *rects, int num, CardState *state ) { D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rects != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, rects, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (!(state->render_options & DSRO_MATRIX)) { while (num > 0) { if (dfb_rectangle_region_intersects( rects, &state->clip )) break; rects++; num--; } } if (num > 0) { DFBRectangle rect; int i = 0; /* Check for acceleration and setup execution. */ if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLRECTANGLE )) { /* Now everything is prepared for execution of the FillRectangle() driver function. */ for (; i < num; i++) { if (!(state->render_options & DSRO_MATRIX) && !dfb_rectangle_region_intersects( &rects[i], &state->clip )) continue; rect = rects[i]; if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { dfb_clip_rectangle( &state->clip, &rect ); if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { D_DEBUG_AT( Core_GraphicsOps, " -> driver limits prevent hw operation\n" ); break; } } else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE )) dfb_clip_rectangle( &state->clip, &rect ); if (!card->funcs.FillRectangle( card->driver_data, card->device_data, &rect )) { D_DEBUG_AT( Core_GraphicsOps, " -> driver returned false\n" ); break; } } /* Release after state acquisition. */ dfb_gfxcard_state_release( state ); } if (i < num) { D_DEBUG_AT( Core_GraphicsOps, " -> using software fallback\n" ); /* Use software fallback. */ if (!(state->render_options & DSRO_MATRIX)) { if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { rect = rects[i]; if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } gRelease( state ); } } else if (state->matrix[1] == 0 && state->matrix[3] == 0) { /* Scaled/Translated rectangles. */ DFBRectangle tr[num]; int n = 0; for (; i < num; i++) { int x1, y1, x2, y2; x1 = rects[i].x; y1 = rects[i].y; x2 = x1 + rects[i].w; y2 = y1 + rects[i].h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); if (x1 < x2) { tr[n].x = x1; tr[n].w = x2 - x1; } else { tr[n].x = x2; tr[n].w = x1 - x2; } if (y1 < y2) { tr[n].y = y1; tr[n].h = y2 - y1; } else { tr[n].y = y2; tr[n].h = y1 - y2; } if (dfb_clip_rectangle( &state->clip, &tr[n] )) n++; } if (n > 0) { state->render_options &= ~DSRO_MATRIX; state->modified |= SMF_RENDER_OPTIONS; dfb_gfxcard_fillrectangles( tr, n, state ); state->render_options |= DSRO_MATRIX; state->modified |= SMF_RENDER_OPTIONS; } } else { /* Rotated rectangle: split into triangles. */ if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBTriangle tri; tri.x1 = rects[i].x; tri.y1 = rects[i].y; tri.x2 = rects[i].x + rects[i].w; tri.y2 = rects[i].y; tri.x3 = rects[i].x + rects[i].w; tri.y3 = rects[i].y + rects[i].h; DFB_TRANSFORM( tri.x1, tri.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x2, tri.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x3, tri.y3, state->matrix, state->affine_matrix ); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); tri.x1 = rects[i].x; tri.y1 = rects[i].y; tri.x2 = rects[i].x + rects[i].w; tri.y2 = rects[i].y + rects[i].h; tri.x3 = rects[i].x; tri.y3 = rects[i].y + rects[i].h; DFB_TRANSFORM( tri.x1, tri.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x2, tri.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x3, tri.y3, state->matrix, state->affine_matrix ); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } gRelease( state ); } } } } /* Unlock after execution. */ dfb_state_unlock( state ); } void dfb_gfxcard_drawrectangle( DFBRectangle *rect, CardState *state ) { DFBRectangle rects[4]; bool hw = false; int i = 0; int num = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); DFB_RECTANGLE_ASSERT( rect ); D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ), state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (!(state->render_options & DSRO_MATRIX) && !dfb_rectangle_region_intersects( rect, &state->clip )) { dfb_state_unlock( state ); return; } if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWRECTANGLE ) || !dfb_clip_needed( &state->clip, rect )) { if (rect->w <= card->limits.dst_max.w && rect->h <= card->limits.dst_max.h && dfb_gfxcard_state_check_acquire( state, DFXL_DRAWRECTANGLE )) { hw = card->funcs.DrawRectangle( card->driver_data, card->device_data, rect ); dfb_gfxcard_state_release( state ); } } if (!hw && !(state->render_options & DSRO_MATRIX)) { dfb_build_clipped_rectangle_outlines( rect, &state->clip, rects, &num ); if (!num) { dfb_state_unlock( state ); return; } if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { hw = rects[i].w <= card->limits.dst_max.w && rects[i].h <= card->limits.dst_max.h && card->funcs.FillRectangle( card->driver_data, card->device_data, &rects[i] ); if (!hw) break; } dfb_gfxcard_state_release( state ); } } if (!hw) { if (!(state->render_options & DSRO_MATRIX)) { if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) gFillRectangle( state, &rects[i] ); gRelease( state ); } } else { if (gAcquire( state, DFXL_DRAWLINE )) { int x1, x2, x3, x4; int y1, y2, y3, y4; DFBRegion line; x1 = rect->x; y1 = rect->y; x2 = rect->x + rect->w; y2 = rect->y; x3 = rect->x + rect->w; y3 = rect->y + rect->h; x4 = rect->x; y4 = rect->y + rect->h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x3, y3, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x4, y4, state->matrix, state->affine_matrix ); line = (DFBRegion) { x1, y1, x2, y2 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x2, y2, x3, y3 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x3, y3, x4, y4 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); line = (DFBRegion) { x4, y4, x1, y1 }; if (dfb_clip_line( &state->clip, &line )) gDrawLine( state, &line ); gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_drawlines( DFBRegion *lines, int num, CardState *state ) { int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( lines != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, lines, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_DRAWLINE )) { for (; i < num; i++) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWLINE ) && !dfb_clip_line( &state->clip, &lines[i] )) continue; if (!card->funcs.DrawLine( card->driver_data, card->device_data, &lines[i] )) break; } dfb_gfxcard_state_release( state ); } if (i < num) { if (gAcquire( state, DFXL_DRAWLINE )) { for (; i < num; i++) { if (state->render_options & DSRO_MATRIX) { DFB_TRANSFORM( lines[i].x1, lines[i].y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( lines[i].x2, lines[i].y2, state->matrix, state->affine_matrix ); } if (dfb_clip_line( &state->clip, &lines[i] )) gDrawLine( state, &lines[i] ); } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_filltriangles( DFBTriangle *tris, int num, CardState *state ) { bool hw = false; int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( tris != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, tris, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLTRIANGLE )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRIANGLE )) { DFBPoint p[6]; int n; for (; i < num; i++) { if (dfb_clip_triangle( &state->clip, &tris[i], p, &n )) { DFBTriangle tri; int j; tri.x1 = p[0].x; tri.y1 = p[0].y; tri.x2 = p[1].x; tri.y2 = p[1].y; tri.x3 = p[2].x; tri.y3 = p[2].y; hw = card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); if (!hw) { D_DEBUG_AT( Core_GraphicsOps, " -> driver returned false\n" ); break; } for (j = 3; j < n; j++) { tri.x1 = p[0].x; tri.y1 = p[0].y; tri.x2 = p[j-1].x; tri.y2 = p[j-1].y; tri.x3 = p[j].x; tri.y3 = p[j].y; hw = card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); if (!hw) { D_DEBUG_AT( Core_GraphicsOps, " -> driver returned false\n" ); break; } } } } } else { for (; i < num; i++) { DFBTriangle tri = tris[i]; hw = card->funcs.FillTriangle( card->driver_data, card->device_data, &tri ); if (!hw) { D_DEBUG_AT( Core_GraphicsOps, " -> driver returned false\n" ); break; } } } dfb_gfxcard_state_release( state ); } if (!hw && i < num) { D_DEBUG_AT( Core_GraphicsOps, " -> using software fallback\n" ); /* Try hardware accelerated rectangle filling. */ if (!(card->caps.flags & CCF_NOTRIEMU) && dfb_gfxcard_state_check_acquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBTriangle tri = tris[i]; dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, true ); } dfb_gfxcard_state_release( state ); } else if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBTriangle tri = tris[i]; if (state->render_options & DSRO_MATRIX) { DFB_TRANSFORM( tri.x1, tri.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x2, tri.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x3, tri.y3, state->matrix, state->affine_matrix ); } dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } gRelease( state ); } } dfb_state_unlock( state ); } static void fill_trap( DFBTrapezoid *trap, CardState *state, bool accelerated ) { int y, yend; DDA dda1 = { .xi = 0 }; DDA dda2 = { .xi = 0 }; int clip_x1 = state->clip.x1; int clip_x2 = state->clip.x2; D_MAGIC_ASSERT( state, CardState ); y = trap->y1; yend = trap->y2; if (yend > state->clip.y2) yend = state->clip.y2; /* Top left to bottom left. */ SETUP_DDA( trap->x1, trap->y1, trap->x2, trap->y2, dda1 ); /* Top right to bottom right. */ SETUP_DDA( trap->x1 + trap->w1 - 1, trap->y1, trap->x2 + trap->w2 - 1, trap->y2, dda2 ); while (y <= yend) { DFBRectangle rect; rect.w = ABS( dda1.xi - dda2.xi ); rect.x = MIN( dda1.xi, dda2.xi ); if (clip_x2 < rect.x + rect.w) rect.w = clip_x2 - rect.x + 1; if (rect.w > 0) { if (clip_x1 > rect.x) { rect.w -= (clip_x1 - rect.x); rect.x = clip_x1; } rect.y = y; rect.h = 1; if (rect.w > 0 && rect.y >= state->clip.y1) { if (accelerated) card->funcs.FillRectangle( card->driver_data, card->device_data, &rect ); else gFillRectangle( state, &rect ); } } INC_DDA( dda1 ); INC_DDA( dda2 ); y++; } } void dfb_gfxcard_filltrapezoids( DFBTrapezoid *traps, int num, CardState *state ) { bool hw = false; int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( traps != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, traps, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLTRAPEZOID )) { if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRAPEZOID ) || (state->render_options & DSRO_MATRIX)) { for (; i < num; i++) { DFBTrapezoid trap = traps[i]; hw = card->funcs.FillTrapezoid( card->driver_data, card->device_data, &trap ); if (!hw) break; } } dfb_gfxcard_state_release( state ); } /* Otherwise use two triangles. */ if (!hw && i < num) { if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLTRIANGLE )) { for (; i < num; i++) { bool tri1_failed = true; bool tri2_failed = true; DFBTriangle tri1 = { traps[i].x1, traps[i].y1, traps[i].x1 + traps[i].w1 - 1, traps[i].y1, traps[i].x2, traps[i].y2 }; DFBTriangle tri2 = { traps[i].x1 + traps[i].w1 - 1, traps[i].y1, traps[i].x2, traps[i].y2, traps[i].x2 + traps[i].w2 - 1, traps[i].y2 }; if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRIANGLE ) || (state->render_options & DSRO_MATRIX)) { tri1_failed = !card->funcs.FillTriangle( card->driver_data, card->device_data, &tri1 ); tri2_failed = !card->funcs.FillTriangle( card->driver_data, card->device_data, &tri2 ); } if (tri1_failed || tri2_failed) { dfb_gfxcard_state_release( state ); if (gAcquire( state, DFXL_FILLTRIANGLE )) { if (state->render_options & DSRO_MATRIX) { /* Transform first triangle completely. */ if (tri1_failed || tri2_failed) { DFB_TRANSFORM( tri1.x1, tri1.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri1.x2, tri1.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri1.x3, tri1.y3, state->matrix, state->affine_matrix ); } /* Transform last coordinate of first triangle, and assign first ones from first. */ if (tri2_failed) { DFB_TRANSFORM( tri2.x3, tri2.y3, state->matrix, state->affine_matrix ); tri2.x1 = tri1.x2; tri2.y1 = tri1.y2; tri2.x2 = tri1.x3; tri2.x2 = tri1.y3; } /* Sort triangles (matrix could have rotated them). */ dfb_sort_triangle( &tri1 ); dfb_sort_triangle( &tri2 ); } if (tri1_failed && (tri1.y3 - tri1.y1 > 0)) fill_tri( &tri1, state, false ); if (tri2_failed && (tri2.y3 - tri2.y1 > 0)) fill_tri( &tri2, state, false ); gRelease( state ); } dfb_gfxcard_state_acquire( state, DFXL_FILLTRIANGLE ); } } dfb_gfxcard_state_release( state ); } else if (gAcquire( state, DFXL_FILLTRIANGLE )) { for (; i < num; i++) { DFBTrapezoid trap = traps[i]; dfb_sort_trapezoid( &trap ); if (state->render_options & DSRO_MATRIX) { /* Split into triangles, for easier rotation. */ DFBTriangle tri1 = { trap.x1, traps[i].y1, trap.x1 + traps[i].w1 - 1, traps[i].y1, trap.x2, traps[i].y2 }; DFBTriangle tri2 = { trap.x1 + traps[i].w1 - 1, traps[i].y1, trap.x2, traps[i].y2, trap.x2 + traps[i].w2 - 1, traps[i].y2 }; /* Transform first triangle completely. */ DFB_TRANSFORM( tri1.x1, tri1.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri1.x2, tri1.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri1.x3, tri1.y3, state->matrix, state->affine_matrix ); /* Transform last coordinate of second triangle, and assign first ones from first. */ tri2.x1 = tri1.x2; tri2.y1 = tri1.y2; tri2.x2 = tri1.x3; tri2.y2 = tri1.y3; DFB_TRANSFORM( tri2.x3, tri2.y3, state->matrix, state->affine_matrix ); /* Sort triangles (matrix could have rotated them). */ dfb_sort_triangle( &tri1 ); dfb_sort_triangle( &tri2 ); if (tri1.y3 - tri1.y1 > 0) fill_tri( &tri1, state, false ); if (tri2.y3 - tri2.y1 > 0) fill_tri( &tri2, state, false ); } else fill_trap( &trap, state, false ); } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_fillquadrangles( DFBPoint *points, int num, CardState *state ) { bool hw = false; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, DFBGraphicsState ); D_ASSERT( points != NULL ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, points, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLQUADRANGLE )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLQUADRANGLE )) return; hw = card->funcs.FillQuadrangles( card->driver_data, card->device_data, points, num ); dfb_gfxcard_state_release( state ); } if (!hw) { if (gAcquire( state, DFXL_FILLTRIANGLE )) { int i; for (i = 0; i < num * 4; i += 4) { if (state->render_options & DSRO_MATRIX) { DFB_TRANSFORM( points[i+0].x, points[i+0].y, state->matrix, state->affine_matrix ); DFB_TRANSFORM( points[i+1].x, points[i+1].y, state->matrix, state->affine_matrix ); DFB_TRANSFORM( points[i+2].x, points[i+2].y, state->matrix, state->affine_matrix ); DFB_TRANSFORM( points[i+3].x, points[i+3].y, state->matrix, state->affine_matrix ); } DFBTriangle tri1 = { points[i+0].x, points[i+0].y, points[i+1].x, points[i+1].y, points[i+2].x, points[i+2].y }; DFBTriangle tri2 = { points[i+0].x, points[i+0].y, points[i+2].x, points[i+2].y, points[i+3].x, points[i+3].y }; /* Sort triangles (matrix could have rotated them). */ dfb_sort_triangle( &tri1 ); dfb_sort_triangle( &tri2 ); fill_tri( &tri1, state, false ); fill_tri( &tri2, state, false ); } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_fillspans( int y, DFBSpan *spans, int num, CardState *state ) { int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( spans != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %d, %p [%d], %p )\n", __FUNCTION__, y, spans, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_FILLRECTANGLE )) { if (card->funcs.BatchFill) { unsigned int done = 0; do { int real_num; DFBRectangle *rects; if (num > 256) { rects = D_MALLOC( sizeof(DFBRectangle) * num ); if (!rects) { D_OOM(); break; } } else rects = alloca( sizeof(DFBRectangle) * num ); for (real_num = 0; i < num; i++) { rects[real_num].x = spans[i].x; rects[real_num].y = y + i; rects[real_num].w = spans[i].w; rects[real_num].h = 1; if (rects[real_num].w > card->limits.dst_max.w || rects[real_num].h > card->limits.dst_max.h) { if (!dfb_clip_rectangle( &state->clip, &rects[real_num] )) continue; if (rects[real_num].w > card->limits.dst_max.w || rects[real_num].h > card->limits.dst_max.h) continue; } else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ) && !dfb_clip_rectangle( &state->clip, &rects[real_num] )) continue; real_num++; } if (card->funcs.BatchFill( card->driver_data, card->device_data, &rects[0], real_num, &done )) i = num; else i = done; if (num > 256) D_FREE( rects ); } while (0); } for (; i < num; i++) { DFBRectangle rect = { spans[i].x, y + i, spans[i].w, 1 }; if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { if (!dfb_clip_rectangle( &state->clip, &rect )) continue; if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) break; } else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ) && !dfb_clip_rectangle( &state->clip, &rect )) continue; if (!card->funcs.FillRectangle( card->driver_data, card->device_data, &rect )) break; } dfb_gfxcard_state_release( state ); } if (i < num) { if (gAcquire( state, DFXL_FILLRECTANGLE )) { for (; i < num; i++) { DFBRectangle rect = { spans[i].x, y + i, spans[i].w, 1 }; if (state->render_options & DSRO_MATRIX) { if (state->matrix[1] == 0 && state->matrix[3] == 0) { int x1, y1, x2, y2; x1 = rect.x; y1 = rect.y; x2 = x1 + rect.w; y2 = y1 + rect.h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); if (x1 < x2) { rect.x = x1; rect.w = x2 - x1; } else { rect.x = x2; rect.w = x1 - x2; } if (y1 < y2) { rect.y = y1; rect.h = y2 - y1; } else { rect.y = y2; rect.h = y1 - y2; } if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } else { DFBTriangle tri; tri.x1 = rect.x; tri.y1 = rect.y; tri.x2 = rect.x + rect.w; tri.y2 = rect.y; tri.x3 = rect.x + rect.w; tri.y3 = rect.y + rect.h; DFB_TRANSFORM( tri.x1, tri.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x2, tri.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x3, tri.y3, state->matrix, state->affine_matrix ); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); tri.x1 = rect.x; tri.y1 = rect.y; tri.x2 = rect.x + rect.w; tri.y2 = rect.y + rect.h; tri.x3 = rect.x; tri.y3 = rect.y + rect.h; DFB_TRANSFORM( tri.x1, tri.y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x2, tri.y2, state->matrix, state->affine_matrix ); DFB_TRANSFORM( tri.x3, tri.y3, state->matrix, state->affine_matrix ); dfb_sort_triangle( &tri ); if (tri.y3 - tri.y1 > 0) fill_tri( &tri, state, false ); } } else { if (dfb_clip_rectangle( &state->clip, &rect )) gFillRectangle( state, &rect ); } } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_draw_mono_glyphs( const void *glyph[], const DFBMonoGlyphAttributes *attributes, const DFBPoint *points, unsigned int num, CardState *state ) { int i; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( (glyph != NULL) && (attributes != NULL) && (points != NULL) ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p, %p, %p )\n", __FUNCTION__, glyph, attributes, points, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_DRAWMONOGLYPH )) { for (i = 0; i < num; i++) { const DFBMonoGlyphAttributes *attri = &attributes[i]; card->funcs.DrawMonoGlyph( card->driver_data, card->device_data, glyph[i], attri->width, attri->height, attri->rowbyte, attri->bitoffset, points[i].x, points[i].y, attri->fgcolor, attri->bgcolor, attri->hzoom, attri->vzoom ); } dfb_gfxcard_state_release( state ); } dfb_state_unlock( state ); } static void GenefxVertexAffine_Transform( GenefxVertexAffine *v, unsigned int num, s32 matrix[9], bool affine ) { unsigned int i; if (affine) { for (i = 0; i < num; i++) { int _x, _y; _x = ((v[i].x) * matrix[0] + (v[i].y) * matrix[1] + matrix[2]) / 0x10000; _y = ((v[i].x) * matrix[3] + (v[i].y) * matrix[4] + matrix[5]) / 0x10000; v[i].x = _x; v[i].y = _y; } } else { for (i = 0; i < num; i++) { int _x, _y, _w; _x = ((v[i].x) * matrix[0] + (v[i].y) * matrix[1] + matrix[2]); _y = ((v[i].x) * matrix[3] + (v[i].y) * matrix[4] + matrix[5]); _w = ((v[i].x) * matrix[6] + (v[i].y) * matrix[7] + matrix[8]); if (!_w) { _x = (_x < 0) ? -0x7fffffff : 0x7fffffff; _y = (_y < 0) ? -0x7fffffff : 0x7fffffff; } else { _x /= _w; _y /= _w; } v[i].x = _x; v[i].y = _y; } } } static void dfb_gfxcard_blit_locked( DFBRectangle *rect, int dx, int dy, CardState *state ) { bool hw = false; DFBRectangle drect = { dx, dy, rect->w, rect->h }; DFBSurfaceBlittingFlags blittingflags; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->source != NULL ); D_ASSERT( rect != NULL ); D_ASSERT( rect->x >= 0 ); D_ASSERT( rect->y >= 0 ); D_ASSERT( rect->x < state->source->config.size.w ); D_ASSERT( rect->y < state->source->config.size.h ); D_ASSERT( rect->x + rect->w - 1 < state->source->config.size.w ); D_ASSERT( rect->y + rect->h - 1 < state->source->config.size.h ); blittingflags = state->blittingflags; dfb_simplify_blittingflags( &blittingflags ); if (blittingflags & DSBLIT_ROTATE90) D_UTIL_SWAP( drect.w, drect.h ); D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS( rect ), DFB_RECTANGLE_VALS( &drect ), state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) return; if (dfb_gfxcard_state_check_acquire( state, DFXL_BLIT )) { if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) dfb_clip_blit_flipped_rotated( &state->clip, rect, &drect, blittingflags ); hw = card->funcs.Blit( card->driver_data, card->device_data, rect, drect.x, drect.y ); dfb_gfxcard_state_release( state ); } if (!hw) { /* Use software fallback. */ if (!(state->render_options & DSRO_MATRIX)) { if (gAcquire( state, DFXL_BLIT )) { dfb_clip_blit_flipped_rotated( &state->clip, rect, &drect, blittingflags ); gBlit( state, rect, drect.x, drect.y ); gRelease( state ); } } else if (state->matrix[0] == 0x10000 && state->matrix[1] == 0 && state->matrix[3] == 0 && state->matrix[4] == 0x10000) { state->render_options &= ~DSRO_MATRIX; state->modified |= SMF_RENDER_OPTIONS; dfb_gfxcard_blit( rect, dx + ((state->matrix[2] + 0x8000) >> 16), dy + ((state->matrix[5] + 0x8000) >> 16), state ); state->render_options |= DSRO_MATRIX; state->modified |= SMF_RENDER_OPTIONS; } else { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { GenefxVertexAffine v[4]; v[0].x = dx; v[0].y = dy; v[0].s = rect->x * 0x10000; v[0].t = rect->y * 0x10000; v[1].x = dx + rect->w - 1; v[1].y = dy; v[1].s = (rect->x + rect->w - 1) * 0x10000; v[1].t = v[0].t; v[2].x = dx + rect->w - 1; v[2].y = dy + rect->h - 1; v[2].s = v[1].s; v[2].t = (rect->y + rect->h - 1) * 0x10000; v[3].x = dx; v[3].y = dy + rect->h - 1; v[3].s = v[0].s; v[3].t = v[2].t; GenefxVertexAffine_Transform( v, 4, state->matrix, state->affine_matrix ); Genefx_TextureTrianglesAffine( state, v, 4, DTTF_FAN, &state->clip ); gRelease( state ); } } else if (gAcquire( state, DFXL_STRETCHBLIT )) { int x1, y1, x2, y2; x1 = dx; y1 = dy; x2 = dx + rect->w; y2 = dy + rect->h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); drect = (DFBRectangle) { x1, y1, x2 - x1, y2 - y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, rect, &drect ); gRelease( state ); } } } } void dfb_gfxcard_blit( DFBRectangle *rect, int dx, int dy, CardState *state ) { /* The state is locked during graphics operations. */ dfb_state_lock( state ); dfb_gfxcard_blit_locked( rect, dx, dy, state ); dfb_state_unlock( state ); } static void clip_blits( const DFBRegion *clip, const DFBRectangle *rects, const DFBPoint *points, unsigned int num, DFBSurfaceBlittingFlags flags, DFBRectangle *ret_rects, DFBPoint *ret_points, unsigned int *ret_num ) { unsigned int i; unsigned int clipped_num = 0; DFB_REGION_ASSERT( clip ); D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); D_ASSERT( ret_rects != NULL ); D_ASSERT( ret_points != NULL ); D_ASSERT( ret_num != NULL ); D_ASSERT( !(flags & (DSBLIT_ROTATE270 | DSBLIT_ROTATE180)) ); for (i = 0; i < num; i++) { DFBRectangle drect = { points[i].x, points[i].y, rects[i].w, rects[i].h }; if (flags & (DSBLIT_ROTATE90)) D_UTIL_SWAP( drect.w, drect.h ); if (dfb_clip_blit_precheck( clip, drect.w, drect.h, drect.x, drect.y )) { ret_rects[clipped_num] = rects[i]; dfb_clip_blit_flipped_rotated( clip, &ret_rects[clipped_num], &drect, flags ); ret_points[clipped_num].x = drect.x; ret_points[clipped_num].y = drect.y; clipped_num++; } } *ret_num = clipped_num; } void dfb_gfxcard_batchblit( DFBRectangle *rects, DFBPoint *points, int num, CardState *state ) { unsigned int i = 0; DFBSurfaceBlittingFlags blittingflags; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p [%d], %p )\n", __FUNCTION__, rects, points, num, state ); blittingflags = state->blittingflags; dfb_simplify_blittingflags( &blittingflags ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_BLIT )) { if (card->funcs.BatchBlit) { unsigned int done = 0; if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) { unsigned int clipped_num; DFBRectangle *clipped_rects; DFBPoint *clipped_points; if (num > 256) { clipped_rects = D_MALLOC( sizeof(DFBRectangle) * num ); if (!clipped_rects) { D_OOM(); } else { clipped_points = D_MALLOC( sizeof(DFBPoint) * num ); if (!clipped_points) { D_OOM(); D_FREE( clipped_rects ); } else { clip_blits( &state->clip, rects, points, num, blittingflags, clipped_rects, clipped_points, &clipped_num ); /* The driver has to reject all or none. */ if (card->funcs.BatchBlit( card->driver_data, card->device_data, clipped_rects, clipped_points, clipped_num, &done )) i = num; else i = done; D_FREE( clipped_points ); D_FREE( clipped_rects ); } } } else { clipped_rects = alloca( sizeof(DFBRectangle) * num ); clipped_points = alloca( sizeof(DFBPoint) * num ); clip_blits( &state->clip, rects, points, num, blittingflags, clipped_rects, clipped_points, &clipped_num ); /* The driver has to reject all or none. */ if (card->funcs.BatchBlit( card->driver_data, card->device_data, clipped_rects, clipped_points, clipped_num, &done )) i = num; else i = done; } } else { /* The driver has to reject all or none. */ if (card->funcs.BatchBlit( card->driver_data, card->device_data, rects, points, num, &done )) i = num; else i = done; } } else { for (; i < num; i++) { DFBRectangle drect = { points[i].x, points[i].y, rects[i].w, rects[i].h }; if (blittingflags & DSBLIT_ROTATE90) D_UTIL_SWAP( drect.w, drect.h ); if ((state->render_options & DSRO_MATRIX) || dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) { DFBRectangle srect = rects[i]; if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) dfb_clip_blit_flipped_rotated( &state->clip, &srect, &drect, blittingflags ); if (!card->funcs.Blit( card->driver_data, card->device_data, &srect, drect.x, drect.y )) break; } } } dfb_gfxcard_state_release( state ); } if (i < num) { if (state->render_options & DSRO_MATRIX) { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { for (; i < num; i++) { GenefxVertexAffine v[4]; v[0].x = points[i].x; v[0].y = points[i].y; v[0].s = rects[i].x * 0x10000; v[0].t = rects[i].y * 0x10000; v[1].x = points[i].x + rects[i].w - 1; v[1].y = points[i].y; v[1].s = (rects[i].x + rects[i].w - 1) * 0x10000; v[1].t = v[0].t; v[2].x = points[i].x + rects[i].w - 1; v[2].y = points[i].y + rects[i].h - 1; v[2].s = v[1].s; v[2].t = (rects[i].y + rects[i].h - 1) * 0x10000; v[3].x = points[i].x; v[3].y = points[i].y + rects[i].h - 1; v[3].s = v[0].s; v[3].t = v[2].t; GenefxVertexAffine_Transform( v, 4, state->matrix, state->affine_matrix ); Genefx_TextureTrianglesAffine( state, v, 4, DTTF_FAN, &state->clip ); } gRelease( state ); } } else if (gAcquire( state, DFXL_STRETCHBLIT )) { for (; i < num; i++) { int x1, y1, x2, y2; DFBRectangle drect; x1 = points[i].x; y1 = points[i].y; x2 = x1 + rects[i].w; y2 = y1 + rects[i].h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); drect = (DFBRectangle) { x1, y1, x2 - x1, y2 - y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, &rects[i], &drect ); } gRelease( state ); } } else { if (gAcquire( state, DFXL_BLIT )) { for (; i < num; i++) { DFBRectangle drect = { points[i].x, points[i].y, rects[i].w, rects[i].h }; if (blittingflags & DSBLIT_ROTATE90) D_UTIL_SWAP( drect.w, drect.h ); if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) { DFBRectangle srect = rects[i]; dfb_clip_blit_flipped_rotated( &state->clip, &srect, &drect, blittingflags ); gBlit( state, &srect, drect.x, drect.y ); } } gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_batchblit2( DFBRectangle *rects, DFBPoint *points, DFBPoint *points2, int num, CardState *state ) { int i = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rects != NULL ); D_ASSERT( points != NULL ); D_ASSERT( points2 != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p, %p [%d], %p )\n", __FUNCTION__, rects, points, points2, num, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if (dfb_gfxcard_state_check_acquire( state, DFXL_BLIT2 )) { for (; i < num; i++) { if ((state->render_options & DSRO_MATRIX) || dfb_clip_blit_precheck( &state->clip, rects[i].w, rects[i].h, points[i].x, points[i].y )) { int dx = points[i].x; int dy = points[i].y; if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT2 )) { dfb_clip_blit( &state->clip, &rects[i], &dx, &dy ); points2[i].x += dx - points[i].x; points2[i].y += dy - points[i].y; } if (!card->funcs.Blit2( card->driver_data, card->device_data, &rects[i], dx, dy, points2[i].x, points2[i].y )) break; } } dfb_gfxcard_state_release( state ); } if (i < num) { D_UNIMPLEMENTED(); for (; i < num; i++) { D_DEBUG_AT( Core_GraphicsOps, " -> rects[%d] %4d,%4d-%4dx%4d\n", i, DFB_RECTANGLE_VALS( &rects[i] ) ); D_DEBUG_AT( Core_GraphicsOps, " -> points[%d] %4d,%4d\n", i, points[i].x, points[i].y ); D_DEBUG_AT( Core_GraphicsOps, " -> points2[%d] %4d,%4d\n", i, points2[i].x, points2[i].y ); if ((state->render_options & DSRO_MATRIX) || dfb_clip_blit_precheck( &state->clip, rects[i].w, rects[i].h, points[i].x, points[i].y )) { int dx = points[i].x; int dy = points[i].y; dfb_clip_blit( &state->clip, &rects[i], &dx, &dy ); points2[i].x += dx - points[i].x; points2[i].y += dy - points[i].y; D_DEBUG_AT( Core_GraphicsOps, " -> rects[%d] %4d,%4d-%4dx%4d\n", i, DFB_RECTANGLE_VALS( &rects[i] ) ); D_DEBUG_AT( Core_GraphicsOps, " -> points[%d] %4d,%4d\n", i, dx, dy ); D_DEBUG_AT( Core_GraphicsOps, " -> points2[%d] %4d,%4d\n", i, points2[i].x, points2[i].y ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_batchstretchblit( DFBRectangle *srects, DFBRectangle *drects, unsigned int num, CardState *state ) { int i; bool need_clip; bool acquired = false; DFBSurfaceBlittingFlags blittingflags; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( srects != NULL ); D_ASSERT( drects != NULL ); D_ASSERT( num > 0 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p )\n", __FUNCTION__, state ); for (i = 0; i < num; ++i) D_DEBUG_AT( Core_GraphicsOps, " -> %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &srects[i] ), DFB_RECTANGLE_VALS( &drects[i] ) ); blittingflags = state->blittingflags; dfb_simplify_blittingflags( &blittingflags ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); need_clip = (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_STRETCHBLIT )); for (i = 0; i < num; ++i) { DFBRectangle *srect = &srects[i]; DFBRectangle *drect = &drects[i]; if (!acquired) { if (!dfb_gfxcard_state_check_acquire( state, DFXL_STRETCHBLIT )) break; acquired = true; } if ((srect->w == drect->w && srect->h == drect->h) || ((state->blittingflags & DSBLIT_ROTATE90) && (srect->w == drect->h && srect->h == drect->w))) { dfb_gfxcard_state_release( state ); acquired = false; dfb_gfxcard_blit_locked( srect, drect->x, drect->y, state ); continue; } if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( &state->clip, drect->w, drect->h, drect->x, drect->y )) continue; if (need_clip) dfb_clip_stretchblit( &state->clip, srect, drect ); if (!card->funcs.StretchBlit( card->driver_data, card->device_data, srect, drect )) break; } if (acquired) dfb_gfxcard_state_release( state ); if (i < num) { if ((state->render_options & DSRO_MATRIX) && (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0)) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { for (; i < num; ++i) { DFBRectangle *srect = &srects[i]; DFBRectangle *drect = &drects[i]; GenefxVertexAffine v[4]; v[0].x = drect->x; v[0].y = drect->y; v[0].s = srect->x * 0x10000; v[0].t = srect->y * 0x10000; v[1].x = drect->x + drect->w - 1; v[1].y = drect->y; v[1].s = (srect->x + srect->w - 1) * 0x10000; v[1].t = v[0].t; v[2].x = drect->x + drect->w - 1; v[2].y = drect->y + drect->h - 1; v[2].s = v[1].s; v[2].t = (srect->y + srect->h - 1) * 0x10000; v[3].x = drect->x; v[3].y = drect->y + drect->h - 1; v[3].s = v[0].s; v[3].t = v[2].t; GenefxVertexAffine_Transform( v, 4, state->matrix, state->affine_matrix ); Genefx_TextureTrianglesAffine( state, v, 4, DTTF_FAN, &state->clip ); } gRelease( state ); } } else if (gAcquire( state, DFXL_STRETCHBLIT )) { for (; i < num; ++i) { DFBRectangle *srect = &srects[i]; DFBRectangle *drect = &drects[i]; if (state->render_options & DSRO_MATRIX) { int x1, y1, x2, y2; x1 = drect->x; y1 = drect->y; x2 = x1 + drect->w; y2 = y1 + drect->h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); drect->x = x1; drect->y = y1; drect->w = x2 - x1; drect->h = y2 - y1; } if (!dfb_clip_blit_precheck( &state->clip, drect->w, drect->h, drect->x, drect->y )) continue; gStretchBlit( state, srect, drect ); } gRelease( state ); } } dfb_state_unlock( state ); } void dfb_gfxcard_stretchblit( DFBRectangle *srect, DFBRectangle *drect, CardState *state ) { dfb_gfxcard_batchstretchblit( srect, drect, 1, state ); } void dfb_gfxcard_tileblit( DFBRectangle *rect, int dx1, int dy1, int dx2, int dy2, CardState *state ) { int x, y; int odx; DFBRectangle srect; DFBRegion *clip; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( rect != NULL ); D_ASSERT( rect->w >= 1 ); D_ASSERT( rect->h >= 1 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4d,%4d, %p )\n", __FUNCTION__, dx1, dy1, dx2, dy2, state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); clip = &state->clip; /* Check if anything is drawn at all. */ if (!(state->render_options & DSRO_MATRIX) && !dfb_clip_blit_precheck( clip, dx2 - dx1 + 1, dy2 - dy1 + 1, dx1, dy1 )) { dfb_state_unlock( state ); return; } /* Remove clipped tiles. */ if (dx1 < clip->x1) { int outer = clip->x1 - dx1; dx1 += outer - (outer % rect->w); } if (dy1 < clip->y1) { int outer = clip->y1 - dy1; dy1 += outer - (outer % rect->h); } if (dx2 > clip->x2) { int outer = clip->x2 - dx2; dx2 -= outer - (outer % rect->w); } if (dy2 > clip->y2) { int outer = clip->y2 - dy2; dy2 -= outer - (outer % rect->h); } odx = dx1; if (dfb_gfxcard_state_check_acquire( state, DFXL_BLIT )) { bool hw = true; for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) continue; x = dx1; y = dy1; srect = *rect; if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) dfb_clip_blit( clip, &srect, &x, &y ); hw = card->funcs.Blit( card->driver_data, card->device_data, &srect, x, y ); if (!hw) break; } if (!hw) break; dx1 = odx; } dfb_gfxcard_state_release( state ); } if (dy1 < dy2) { if (state->render_options & DSRO_MATRIX) { if (state->matrix[0] < 0 || state->matrix[1] != 0 || state->matrix[3] != 0 || state->matrix[4] < 0 || state->matrix[6] != 0 || state->matrix[7] != 0) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { /* Build mesh. */ for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { GenefxVertexAffine v[4]; v[0].x = dx1; v[0].y = dy1; v[0].s = rect->x * 0x10000; v[0].t = rect->y * 0x10000; v[1].x = dx1 + rect->w - 1; v[1].y = dy1; v[1].s = (rect->x + rect->w - 1) * 0x10000; v[1].t = v[0].t; v[2].x = dx1 + rect->w - 1; v[2].y = dy1 + rect->h - 1; v[2].s = v[1].s; v[2].t = (rect->y + rect->h - 1) * 0x10000; v[3].x = dx1; v[3].y = dy1 + rect->h - 1; v[3].s = v[0].s; v[3].t = v[2].t; GenefxVertexAffine_Transform( v, 4, state->matrix, state->affine_matrix ); Genefx_TextureTrianglesAffine( state, v, 4, DTTF_FAN, &state->clip ); } dx1 = odx; } gRelease( state ); } } else if (gAcquire( state, DFXL_STRETCHBLIT )) { for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { int x1, y1, x2, y2; DFBRectangle drect; x1 = dx1; y1 = dy1; x2 = dx1 + rect->w; y2 = dy1 + rect->h; DFB_TRANSFORM( x1, y1, state->matrix, state->affine_matrix ); DFB_TRANSFORM( x2, y2, state->matrix, state->affine_matrix ); drect = (DFBRectangle) { x1, y1, x2 - x1, y2 - y1 }; if (dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) gStretchBlit( state, rect, &drect ); } dx1 = odx; } gRelease( state ); } } else { if (gAcquire( state, DFXL_BLIT )) { for (; dy1 < dy2; dy1 += rect->h) { for (; dx1 < dx2; dx1 += rect->w) { if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) continue; x = dx1; y = dy1; srect = *rect; dfb_clip_blit( clip, &srect, &x, &y ); gBlit( state, &srect, x, y ); } dx1 = odx; } gRelease( state ); } } } dfb_state_unlock( state ); } void dfb_gfxcard_texture_triangles( DFBVertex *vertices, int num, DFBTriangleFormation formation, CardState *state ) { bool hw = false; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_ASSERT( vertices != NULL ); D_ASSERT( num >= 3 ); D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %s, %p )\n", __FUNCTION__, vertices, num, (formation == DTTF_LIST) ? "LIST" : (formation == DTTF_STRIP) ? "STRIP" : (formation == DTTF_FAN) ? "FAN" : "unknown formation", state ); /* The state is locked during graphics operations. */ dfb_state_lock( state ); /* Signal beginning of sequence of operations if not already done. */ dfb_state_start_drawing( state ); if ((D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_TEXTRIANGLES )) && dfb_gfxcard_state_check_acquire( state, DFXL_TEXTRIANGLES )) { hw = card->funcs.TextureTriangles( card->driver_data, card->device_data, vertices, num, formation ); dfb_gfxcard_state_release( state ); } if (!hw) { if (gAcquire( state, DFXL_TEXTRIANGLES )) { int i; GenefxVertexAffine v[num]; /* Convert vertices. */ for (i = 0; i < num; i++) { v[i].x = vertices[i].x; v[i].y = vertices[i].y; v[i].s = vertices[i].s * state->source->config.size.w * 0x10000; v[i].t = vertices[i].t * state->source->config.size.h * 0x10000; } Genefx_TextureTrianglesAffine( state, v, num, formation, &state->clip ); gRelease( state ); } } dfb_state_unlock( state ); } static void font_state_prepare( CardState *state, CardState *backup, CoreFont *font, CoreSurface *surface, bool set_blend ) { if (state->blittingflags != DSBLIT_INDEX_TRANSLATION) { DFBSurfaceBlittingFlags flags = font->blittingflags; backup->blittingflags = state->blittingflags; backup->src_blend = state->src_blend; backup->dst_blend = state->dst_blend; /* Additional blending. */ if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) flags |= DSBLIT_BLEND_COLORALPHA; if (state->drawingflags & DSDRAW_DST_COLORKEY) flags |= DSBLIT_DST_COLORKEY; if (state->drawingflags & DSDRAW_XOR) flags |= DSBLIT_XOR; if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { /* Porter/Duff SRC_OVER composition. */ if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) || (font->surface_caps & DSCAPS_PREMULTIPLIED)) { if (font->surface_caps & DSCAPS_PREMULTIPLIED) { if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; } else flags |= DSBLIT_SRC_PREMULTIPLY; if (set_blend) dfb_state_set_src_blend( state, DSBF_ONE ); } else if (set_blend) dfb_state_set_src_blend( state, DSBF_SRCALPHA ); if (set_blend) dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); } dfb_state_set_blitting_flags( state, flags ); } else { backup->blittingflags = 0; backup->src_blend = 0; backup->dst_blend = 0; } } static void font_state_restore( CardState *state, CardState *backup ) { if (state->blittingflags != DSBLIT_INDEX_TRANSLATION) { dfb_state_set_blitting_flags( state, backup->blittingflags ); dfb_state_set_src_blend( state, backup->src_blend ); dfb_state_set_dst_blend( state, backup->dst_blend ); } } void dfb_gfxcard_drawstring( const u8 *text, int bytes, DFBTextEncodingID encoding, int x, int y, CoreFont *font, unsigned int layers, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ) { DFBResult ret; unsigned int indices[bytes]; int i, l, num; int kern_x; int kern_y; DFBRectangle rects[50]; DFBPoint points[50]; CardState state_backup; CardState *state; CoreSurface *surface; int num_blits = 0; int ox = x; int oy = y; unsigned int prev = 0; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); state = client->state; D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT( state->destination, CoreSurface ); D_ASSERT( text != NULL ); D_ASSERT( bytes > 0 ); D_ASSERT( font != NULL ); if (encoding == DTEID_UTF8) D_DEBUG_AT( Core_GraphicsOps, "%s( '%s' [%d], %d,%d, %p, %p )\n", __FUNCTION__, text, bytes, x, y, font, client ); else D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %u, %d,%d, %p, %p )\n", __FUNCTION__, text, bytes, encoding, x, y, font, client ); surface = state->destination; /* Simple prechecks. */ if (!(font->description.flags & DFDESC_ROTATION) || !font->description.rotation) { if (!(state->render_options & DSRO_MATRIX) && (x > state->clip.x2 || y > state->clip.y2 || y + font->height <= state->clip.y1)) { return; } } /* Decode string to character indices. */ ret = dfb_font_decode_text( font, encoding, text, bytes, indices, &num ); if (ret) return; font_state_prepare( state, &state_backup, font, surface, !(flags & DSTF_BLEND_FUNCS) ); dfb_font_lock( font ); for (l = layers - 1; l >= 0; l--) { x = ox << 8; y = oy << 8; if (layers > 1) dfb_state_set_color( state, &state->colors[l] ); /* Blit glyphs. */ for (i = 0; i < num; i++) { CoreGlyphData *glyph; unsigned int current = indices[i]; ret = dfb_font_get_glyph_data( font, current, l, &glyph ); if (ret) { D_DEBUG_AT( Core_GraphicsOps, " -> glyph data loading from font failed!\n" ); prev = current; continue; } if (prev && font->GetKerning && font->GetKerning( font, prev, current, &kern_x, &kern_y) == DFB_OK) { x += kern_x << 8; y += kern_y << 8; } if (glyph->width) { if (glyph->surface != state->source || num_blits == D_ARRAY_SIZE(rects)) { if (num_blits) { CoreGraphicsStateClient_Blit( client, rects, points, num_blits ); num_blits = 0; } if (glyph->surface != state->source) dfb_state_set_source( state, glyph->surface ); } points[num_blits] = (DFBPoint) { (x >> 8) + glyph->left, (y >> 8) + glyph->top }; rects[num_blits] = (DFBRectangle) { glyph->start, 0, glyph->width, glyph->height }; num_blits++; } x += glyph->xadvance; y += glyph->yadvance; prev = current; } if (num_blits) { CoreGraphicsStateClient_Blit( client, rects, points, num_blits ); num_blits = 0; } } dfb_font_unlock( font ); font_state_restore( state, &state_backup ); } void dfb_gfxcard_drawglyph( CoreGlyphData **glyph, int x, int y, CoreFont *font, unsigned int layers, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ) { int l; CardState state_backup; CardState *state; CoreSurface *surface; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( client, CoreGraphicsStateClient ); state = client->state; D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT( state->destination, CoreSurface ); D_ASSERT( font != NULL ); D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d, %u, %p, %p )\n", __FUNCTION__, x, y, layers, font, client ); surface = state->destination; font_state_prepare( state, &state_backup, font, surface, !(flags & DSTF_BLEND_FUNCS) ); for (l = layers - 1; l >= 0; l--) { if (layers > 1) dfb_state_set_color( state, &state->colors[l] ); /* Blit glyph. */ if (glyph[l]->width) { DFBRectangle rect = { glyph[l]->start, 0, glyph[l]->width, glyph[l]->height }; DFBPoint point = { x + glyph[l]->left, y + glyph[l]->top }; dfb_state_set_source( state, glyph[l]->surface ); CoreGraphicsStateClient_Blit( client, &rect, &point, 1 ); } } font_state_restore( state, &state_backup ); } bool dfb_gfxcard_drawstring_check_state( CoreFont *font, CardState *state, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ) { int i; bool result = false; CoreSurface *surface; CardState state_backup; CoreGlyphData *data; DFBAccelerationMask mask; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_MAGIC_ASSERT( state, CardState ); D_MAGIC_ASSERT( state->destination, CoreSurface ); D_ASSERT( font != NULL ); D_ASSERT( client != NULL ); D_DEBUG_AT( Core_GfxState, "%s( %p, %p, %p )\n", __FUNCTION__, font, state, client ); surface = state->destination; dfb_font_lock( font ); for (i = 0; i < 128; i++) { if (dfb_font_get_glyph_data( font, i, 0, &data ) == DFB_OK) break; } if (!data) { D_DEBUG_AT( Core_GfxState, " -> no font data!\n" ); dfb_font_unlock( font ); return false; } font_state_prepare( state, &state_backup, font, surface, !(flags & DSTF_BLEND_FUNCS) ); /* Set the source. */ dfb_state_set_source( state, data->surface ); if (CoreGraphicsStateClient_GetAccelerationMask( client, &mask ) == DFB_OK) result = mask & DFXL_BLIT; dfb_font_unlock( font ); font_state_restore( state, &state_backup ); return result; } DFBResult dfb_gfxcard_sync() { DFBResult ret; if (!card) return DFB_OK; ret = dfb_gfxcard_lock( GDLF_SYNC ); if (ret) return ret; dfb_gfxcard_unlock(); return DFB_OK; } DFBResult dfb_gfxcard_wait_serial( const CoreGraphicsSerial *serial ) { DFBResult ret; DFBGraphicsCoreShared *shared; D_ASSERT( serial != NULL ); if (!card || dfb_config->software_only) return DFB_OK; D_ASSERT( card->shared != NULL ); shared = card->shared; ret = dfb_gfxcard_lock( GDLF_NONE ); if (ret) return ret; /* Start command processing if not already running. */ if (shared->pending_ops && card->funcs.EmitCommands) { dfb_gfxcard_switch_busy(); card->funcs.EmitCommands( card->driver_data, card->device_data ); shared->pending_ops = false; } if (card->funcs.WaitSerial) ret = card->funcs.WaitSerial( card->driver_data, card->device_data, serial ); else if (card->funcs.EngineSync) ret = card->funcs.EngineSync( card->driver_data, card->device_data ); dfb_gfxcard_switch_idle(); if (ret) { if (card->funcs.EngineReset) card->funcs.EngineReset( card->driver_data, card->device_data ); shared->state = NULL; } dfb_gfxcard_unlock(); return ret; } void dfb_gfxcard_flush_texture_cache() { if (dfb_config->software_only) return; if (card && card->funcs.FlushTextureCache) card->funcs.FlushTextureCache( card->driver_data, card->device_data ); } void dfb_gfxcard_flush_read_cache() { if (dfb_config->software_only) return; if (card && card->funcs.FlushReadCache) card->funcs.FlushReadCache( card->driver_data, card->device_data ); } void dfb_gfxcard_after_set_var() { if (dfb_config->software_only) return; if (card && card->funcs.AfterSetVar) card->funcs.AfterSetVar( card->driver_data, card->device_data ); } void dfb_gfxcard_get_capabilities( CardCapabilities *ret_caps ) { D_ASSERT( card != NULL ); D_ASSERT( ret_caps != NULL ); *ret_caps = card->caps; } void dfb_gfxcard_get_device_info( GraphicsDeviceInfo *ret_device_info ) { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_ASSERT( ret_device_info != NULL ); shared = card->shared; *ret_device_info = shared->device_info; } void dfb_gfxcard_get_driver_info( GraphicsDriverInfo *ret_driver_info ) { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); D_ASSERT( ret_driver_info != NULL ); shared = card->shared; *ret_driver_info = shared->driver_info; } int dfb_gfxcard_reserve_memory( unsigned int size ) { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; if (shared->device_info.limits.surface_byteoffset_alignment) { size += shared->device_info.limits.surface_byteoffset_alignment - 1; size -= (size % shared->device_info.limits.surface_byteoffset_alignment); } else D_WARN( "no alignment specified yet" ); if (shared->videoram_length < size) { D_WARN( "not enough video memory (%u < %u)", shared->videoram_length, size ); return -1; } shared->videoram_length -= size; return shared->videoram_length; } unsigned int dfb_gfxcard_memory_length() { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; return shared->videoram_length; } volatile void * dfb_gfxcard_map_mmio( unsigned int offset, int length ) { return dfb_system_map_mmio( offset, length ); } void dfb_gfxcard_unmap_mmio( volatile void *addr, int length ) { dfb_system_unmap_mmio( addr, length ); } unsigned int dfb_gfxcard_get_accelerator() { return dfb_system_get_accelerator(); } void dfb_gfxcard_calc_buffer_size( CoreSurfaceBuffer *buffer, int *ret_pitch, int *ret_length ) { DFBResult ret = DFB_FAILURE; int pitch; int length; CoreSurface *surface; D_ASSERT( card != NULL ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); surface = buffer->surface; /* Use the Graphics card's own method to calculate the buffer size. */ if (card->funcs.CalcBufferSize) { ret = card->funcs.CalcBufferSize( card->driver_data, card->device_data, buffer, &pitch, &length ); } if (ret) { /* Calculate the required length depending on limitations. */ pitch = MAX( surface->config.size.w, surface->config.min_size.w ); if (pitch < card->limits.surface_max_power_of_two_pixelpitch && surface->config.size.h < card->limits.surface_max_power_of_two_height) pitch = 1 << direct_log2( pitch ); if (card->limits.surface_pixelpitch_alignment > 1) { pitch += card->limits.surface_pixelpitch_alignment - 1; pitch -= pitch % card->limits.surface_pixelpitch_alignment; } pitch = DFB_BYTES_PER_LINE( surface->config.format, pitch ); if (pitch < card->limits.surface_max_power_of_two_bytepitch && surface->config.size.h < card->limits.surface_max_power_of_two_height) pitch = 1 << direct_log2( pitch ); if (card->limits.surface_bytepitch_alignment > 1) { pitch += card->limits.surface_bytepitch_alignment - 1; pitch -= pitch % card->limits.surface_bytepitch_alignment; } length = DFB_PLANE_MULTIPLY( surface->config.format, MAX( surface->config.size.h, surface->config.min_size.h ) * pitch ); if (card->limits.surface_byteoffset_alignment > 1) { length += card->limits.surface_byteoffset_alignment - 1; length -= length % card->limits.surface_byteoffset_alignment; } } if (ret_pitch) *ret_pitch = pitch; if (ret_length) *ret_length = length; } unsigned long dfb_gfxcard_memory_physical( unsigned int offset ) { return dfb_system_video_memory_physical( offset ); } void * dfb_gfxcard_memory_virtual( unsigned int offset ) { return dfb_system_video_memory_virtual( offset ); } void * dfb_gfxcard_get_device_data() { DFBGraphicsCoreShared *shared; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; return shared->device_data; } void * dfb_gfxcard_get_driver_data() { D_ASSERT( card != NULL ); return card->driver_data; } /**********************************************************************************************************************/ static void dfb_gfxcard_update_stats( long long now ) { if (dfb_config->gfxcard_stats) { DFBGraphicsCoreShared *shared; long long total; D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; total = now - shared->ts_start; if (total > dfb_config->gfxcard_stats * 1000LL) { D_INFO( "DirectFB/Graphics: Stats: busy %lld / %lld -> %3lld.%lld%%\n", shared->ts_busy_sum, total, (1000 * shared->ts_busy_sum / total) / 10LL, (1000 * shared->ts_busy_sum / total) % 10LL ); shared->ts_start = now; shared->ts_busy_sum = 0; } } } static void dfb_gfxcard_switch_busy() { if (dfb_config->gfxcard_stats) { DFBGraphicsCoreShared *shared; long long now = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; if (shared->ts_busy) shared->ts_busy_sum += now - shared->ts_busy; shared->ts_busy = now; if (!shared->ts_start) shared->ts_start = shared->ts_busy; dfb_gfxcard_update_stats( now ); } } static void dfb_gfxcard_switch_idle() { if (dfb_config->gfxcard_stats) { DFBGraphicsCoreShared *shared; long long now = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); D_ASSERT( card != NULL ); D_ASSERT( card->shared != NULL ); shared = card->shared; if (shared->ts_busy) { shared->ts_busy_sum += now - shared->ts_busy; shared->ts_busy = 0; } dfb_gfxcard_update_stats( now ); } } ================================================ FILE: src/core/gfxcard.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__GFXCARD_H__ #define __CORE__GFXCARD_H__ #include #include DECLARE_MODULE_DIRECTORY( dfb_graphics_drivers ); /**********************************************************************************************************************/ #define DFB_GRAPHICS_DRIVER_ABI_VERSION 35 #define DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH 100 #define DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH 40 typedef struct { int major; /* major version */ int minor; /* minor version */ } GraphicsDriverVersion; struct __DFB_GraphicsDriverInfo { GraphicsDriverVersion version; char name[DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH]; /* Name of graphics driver */ char vendor[DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH]; /* Vendor (or author) of the driver */ char url[DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH]; /* URL for driver updates */ char license[DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH]; /* License, e.g. 'LGPL' or 'proprietary' */ unsigned int driver_data_size; /* Driver private data size to allocate */ unsigned int device_data_size; /* Device private data size to allocate */ }; #define DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH 48 #define DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH 64 typedef enum { CCF_CLIPPING = 0x00000001, CCF_NOTRIEMU = 0x00000002, CCF_READSYSMEM = 0x00000004, CCF_WRITESYSMEM = 0x00000008, CCF_RENDEROPTS = 0x00000020 } CardCapabilitiesFlags; typedef struct { CardCapabilitiesFlags flags; DFBAccelerationMask accel; DFBSurfaceBlittingFlags blitting; DFBSurfaceDrawingFlags drawing; DFBAccelerationMask clip; } CardCapabilities; typedef struct { unsigned int surface_byteoffset_alignment; unsigned int surface_pixelpitch_alignment; unsigned int surface_bytepitch_alignment; unsigned int surface_max_power_of_two_pixelpitch; unsigned int surface_max_power_of_two_bytepitch; unsigned int surface_max_power_of_two_height; DFBDimension dst_min; DFBDimension dst_max; } CardLimitations; struct __DFB_GraphicsDeviceInfo { char name[DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH]; /* Device name. */ char vendor[DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH]; /* Vendor of the device. */ CardCapabilities caps; /* Hardware acceleration capabilities. */ CardLimitations limits; /* Hardware limitations. */ }; typedef struct _GraphicsDeviceFuncs { /* * Called after screen information is changed. */ void (*AfterSetVar) ( void *driver_data, void *device_data ); /* * The driver should do the one time initialization of the engine, e.g. writing some registers that are supposed to * have a fixed value. */ void (*EngineReset) ( void *driver_data, void *device_data ); /* * Make sure that graphics hardware has finished all operations. */ DFBResult (*EngineSync) ( void *driver_data, void *device_data ); /* * Called during dfb_gfxcard_lock() to notify the driver that the current rendering state is no longer valid. */ void (*InvalidateState) ( void *driver_data, void *device_data ); /* * After the video memory has been written to by the CPU (e.g. modification of a texture) make sure the accelerator * won't use cached texture data. */ void (*FlushTextureCache)( void *driver_data, void *device_data ); /* * After the video memory has been written to by the accelerator make sure the CPU won't read back cached data. */ void (*FlushReadCache) ( void *driver_data, void *device_data ); /* * Return the serial of the last (queued) operation. * The serial is used to wait for finishing a specific graphics operation instead of the whole engine being idle. */ void (*GetSerial) ( void *driver_data, void *device_data, CoreGraphicsSerial *serial ); /* * Make sure that graphics hardware has finished the specified operation. */ DFBResult (*WaitSerial) ( void *driver_data, void *device_data, const CoreGraphicsSerial *serial ); /* * Emit any buffered commands, i.e. trigger processing. */ void (*EmitCommands) ( void *driver_data, void *device_data ); /* * Check if the function 'accel' can be accelerated with the 'state'. * If that's true, the function sets the 'accel' bit in 'state->accel'. */ void (*CheckState) ( void *driver_data, void *device_data, CardState *state, DFBAccelerationMask accel ); /* * Program card for execution of the function 'accel' with the 'state'. * 'state->modified' contains information about changed entries, at least 'accel' is set in 'state->set'. * The driver may modify 'funcs' depending on 'state' settings. */ void (*SetState) ( void *driver_data, void *device_data, struct _GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ); /* * Drawing functions. */ bool (*FillRectangle) ( void *driver_data, void *device_data, DFBRectangle *rect ); bool (*DrawRectangle) ( void *driver_data, void *device_data, DFBRectangle *rect ); bool (*DrawLine) ( void *driver_data, void *device_data, DFBRegion *line ); bool (*FillTriangle) ( void *driver_data, void *device_data, DFBTriangle *tri ); bool (*FillTrapezoid) ( void *driver_data, void *device_data, DFBTrapezoid *trap ); bool (*FillQuadrangles) ( void *driver_data, void *device_data, DFBPoint *points, int num ); bool (*DrawMonoGlyph) ( void *driver_data, void *device_data, const void *glyph, int glyph_width, int glyph_height, int glyph_rowbyte, int glyph_offset, int dx, int dy, int fg_color, int bg_color, int hzoom, int vzoom ); /* * Blitting functions. */ bool (*Blit) ( void *driver_data, void *device_data, DFBRectangle *rect, int dx, int dy ); bool (*Blit2) ( void *driver_data, void *device_data, DFBRectangle *rect, int dx, int dy, int sx2, int sy2 ); bool (*StretchBlit) ( void *driver_data, void *device_data, DFBRectangle *srect, DFBRectangle *drect ); bool (*TextureTriangles) ( void *driver_data, void *device_data, DFBVertex *vertices, int num, DFBTriangleFormation formation ); /* * Signal beginning of a sequence of operations using this 'state'. */ void (*StartDrawing) ( void *driver_data, void *device_data, CardState *state ); /* * Signal end of sequence. */ void (*StopDrawing) ( void *driver_data, void *device_data, CardState *state ); /* * BatchBlit: when driver returns false (late fallback), it may set 'ret_num' to the number of successful blits in * case of partial execution. */ bool (*BatchBlit) ( void *driver_data, void *device_data, const DFBRectangle *rects, const DFBPoint *points, unsigned int num, unsigned int *ret_num ); /* * BatchFill: when driver returns false (late fallback), it may set 'ret_num' to the number of successful fills in * case of partial execution. */ bool (*BatchFill) ( void *driver_data, void *device_data, const DFBRectangle *rects, unsigned int num, unsigned int *ret_num ); /* * Callbacks when a state is created or destroyed. This allows a graphics driver to hold additional state. */ void (*StateInit) ( void *driver_data, void *device_data, CardState *state ); void (*StateDestroy) ( void *driver_data, void *device_data, CardState *state ); /* * Calculate the amount of memory and pitch for the specified surface buffer. */ DFBResult (*CalcBufferSize) ( void *driver_data, void *device_data, CoreSurfaceBuffer *buffer, int *ret_pitch, int *ret_length ); } GraphicsDeviceFuncs; typedef struct { int (*Probe) ( void ); void (*GetDriverInfo)( GraphicsDriverInfo *driver_info ); DFBResult (*InitDriver) ( GraphicsDeviceFuncs *funcs, void *driver_data, void *device_data, CoreDFB *core ); DFBResult (*InitDevice) ( GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ); void (*CloseDevice) ( void *driver_data, void *device_data ); void (*CloseDriver) ( void *driver_data ); } GraphicsDriverFuncs; typedef enum { GDLF_NONE = 0x00000000, GDLF_WAIT = 0x00000001, GDLF_SYNC = 0x00000002, GDLF_INVALIDATE = 0x00000004, GDLF_RESET = 0x00000008 } GraphicsDeviceLockFlags; /**********************************************************************************************************************/ DFBResult dfb_gfxcard_lock ( GraphicsDeviceLockFlags flags ); void dfb_gfxcard_unlock ( void ); DFBResult dfb_gfxcard_flush ( void ); /* * Signal beginning of a sequence of operations using this state. Any number of states can be 'drawing'. */ void dfb_gfxcard_start_drawing ( CardState *state ); /* * Signal end of sequence, i.e. destination surface is consistent again. */ void dfb_gfxcard_stop_drawing ( CardState *state ); /* * This function returns non zero if acceleration is available for the specific function using the given state. */ bool dfb_gfxcard_state_check ( CardState *state, DFBAccelerationMask accel ); void dfb_gfxcard_state_init ( CardState *state ); void dfb_gfxcard_state_destroy ( CardState *state ); /* * Drawing functions, lock source and destination surfaces, handle clipping and drawing method (hardware/software). */ void dfb_gfxcard_fillrectangles ( DFBRectangle *rects, int num, CardState *state ); void dfb_gfxcard_drawrectangle ( DFBRectangle *rect, CardState *state ); void dfb_gfxcard_drawlines ( DFBRegion *lines, int num_lines, CardState *state ); void dfb_gfxcard_filltriangles ( DFBTriangle *tris, int num, CardState *state ); void dfb_gfxcard_filltrapezoids ( DFBTrapezoid *traps, int num, CardState *state ); void dfb_gfxcard_fillquadrangles ( DFBPoint *points, int num, CardState *state ); void dfb_gfxcard_fillspans ( int y, DFBSpan *spans, int num_spans, CardState *state ); void dfb_gfxcard_draw_mono_glyphs ( const void *glyph[], const DFBMonoGlyphAttributes *attributes, const DFBPoint *points, unsigned int num, CardState *state ); void dfb_gfxcard_blit ( DFBRectangle *rect, int dx, int dy, CardState *state ); void dfb_gfxcard_batchblit ( DFBRectangle *rects, DFBPoint *points, int num, CardState *state ); void dfb_gfxcard_batchblit2 ( DFBRectangle *rects, DFBPoint *points, DFBPoint *points2, int num, CardState *state ); void dfb_gfxcard_stretchblit ( DFBRectangle *srect, DFBRectangle *drect, CardState *state ); void dfb_gfxcard_batchstretchblit ( DFBRectangle *srects, DFBRectangle *drects, unsigned int num, CardState *state ); void dfb_gfxcard_tileblit ( DFBRectangle *rect, int dx1, int dy1, int dx2, int dy2, CardState *state ); void dfb_gfxcard_texture_triangles ( DFBVertex *vertices, int num, DFBTriangleFormation formation, CardState *state ); void dfb_gfxcard_drawstring ( const u8 *text, int bytes, DFBTextEncodingID encoding, int x, int y, CoreFont *font, unsigned int layers, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ); void dfb_gfxcard_drawglyph ( CoreGlyphData **glyph, int x, int y, CoreFont *font, unsigned int layers, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ); /* * Check text rendering function. */ bool dfb_gfxcard_drawstring_check_state( CoreFont *font, CardState *state, CoreGraphicsStateClient *client, DFBSurfaceTextFlags flags ); DFBResult dfb_gfxcard_sync ( void ); DFBResult dfb_gfxcard_wait_serial ( const CoreGraphicsSerial *serial ); void dfb_gfxcard_flush_texture_cache ( void ); void dfb_gfxcard_flush_read_cache ( void ); void dfb_gfxcard_after_set_var ( void ); void dfb_gfxcard_get_capabilities ( CardCapabilities *ret_caps ); void dfb_gfxcard_get_device_info ( GraphicsDeviceInfo *ret_device_info ); void dfb_gfxcard_get_driver_info ( GraphicsDriverInfo *ret_driver_info ); int dfb_gfxcard_reserve_memory ( unsigned int size ); unsigned int dfb_gfxcard_memory_length ( void ); volatile void *dfb_gfxcard_map_mmio ( unsigned int offset, int length ); void dfb_gfxcard_unmap_mmio ( volatile void *addr, int length ); unsigned int dfb_gfxcard_get_accelerator ( void ); void dfb_gfxcard_calc_buffer_size ( CoreSurfaceBuffer *buffer, int *ret_pitch, int *ret_length ); unsigned long dfb_gfxcard_memory_physical ( unsigned int offset ); void *dfb_gfxcard_memory_virtual ( unsigned int offset ); void *dfb_gfxcard_get_device_data ( void ); void *dfb_gfxcard_get_driver_data ( void ); #endif ================================================ FILE: src/core/graphics_driver.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__GRAPHICS_DRIVER_H__ #define __CORE__GRAPHICS_DRIVER_H__ #include /**********************************************************************************************************************/ static int driver_probe ( void ); static void driver_get_info ( GraphicsDriverInfo *driver_info ); static DFBResult driver_init_driver ( GraphicsDeviceFuncs *funcs, void *driver_data, void *device_data, CoreDFB *core ); static DFBResult driver_init_device ( GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ); static void driver_close_device( void *driver_data, void *device_data ); static void driver_close_driver( void *driver_data ); static GraphicsDriverFuncs gfxdriver_funcs = { .Probe = driver_probe, .GetDriverInfo = driver_get_info, .InitDriver = driver_init_driver, .InitDevice = driver_init_device, .CloseDevice = driver_close_device, .CloseDriver = driver_close_driver }; #define DFB_GRAPHICS_DRIVER(shortname) \ \ __dfb_constructor__ \ void \ directfb_##shortname##_ctor( void ) \ { \ direct_modules_register( &dfb_graphics_drivers, \ DFB_GRAPHICS_DRIVER_ABI_VERSION, \ #shortname, \ &gfxdriver_funcs ); \ } \ \ __dfb_destructor__ \ void \ directfb_##shortname##_dtor( void ) \ { \ direct_modules_unregister( &dfb_graphics_drivers, \ #shortname ); \ } #endif ================================================ FILE: src/core/graphics_state.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Core_GraphicsState, "Core/GraphicsState", "DirectFB Core Graphics State" ); /**********************************************************************************************************************/ static void state_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreGraphicsState *state = (CoreGraphicsState*) object; D_MAGIC_ASSERT( state, CoreGraphicsState ); D_DEBUG_AT( Core_GraphicsState, "Destroying state %p (%p%s)\n", state, &state->state, zombie ? " ZOMBIE" : "" ); dfb_state_set_destination( &state->state, NULL ); dfb_state_set_source( &state->state, NULL ); dfb_state_set_source2( &state->state, NULL ); dfb_state_set_source_mask( &state->state, NULL ); dfb_state_destroy( &state->state ); CoreGraphicsState_Deinit_Dispatch( &state->call ); D_MAGIC_CLEAR( state ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_graphics_state_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "GraphicsState Pool", sizeof(CoreGraphicsState), sizeof(CoreGraphicsStateNotification), state_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_graphics_state_create( CoreDFB *core, CoreGraphicsState **ret_state ) { CoreGraphicsState *state; D_ASSERT( ret_state ); D_DEBUG_AT( Core_GraphicsState, "%s()\n", __FUNCTION__ ); /* Create the state object. */ state = dfb_core_create_graphics_state( core ); if (!state) return DFB_FUSION; dfb_state_init( &state->state, core ); CoreGraphicsState_Init_Dispatch( core, state, &state->call ); if (dfb_config->graphics_state_call_limit) fusion_call_set_quota( &state->call, state->object.identity, dfb_config->graphics_state_call_limit ); D_MAGIC_SET( state, CoreGraphicsState ); /* Activate the object. */ fusion_object_activate( &state->object ); /* Return the new state. */ *ret_state = state; D_DEBUG_AT( Core_GraphicsState, " -> %p\n", state ); return DFB_OK; } ================================================ FILE: src/core/graphics_state.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__GRAPHICS_STATE_H__ #define __CORE__GRAPHICS_STATE_H__ #include /**********************************************************************************************************************/ struct __DFB_CoreGraphicsState { FusionObject object; int magic; FusionCall call; CardState state; }; /**********************************************************************************************************************/ typedef enum { CGSNF_NONE = 0x00000000, } CoreGraphicsStateNotificationFlags; typedef struct { CoreGraphicsStateNotificationFlags flags; } CoreGraphicsStateNotification; /**********************************************************************************************************************/ /* * Creates a pool of graphics state objects. */ FusionObjectPool *dfb_graphics_state_pool_create( const FusionWorld *world ); /* * Generates dfb_graphics_state_ref(), dfb_graphics_state_attach() etc. */ FUSION_OBJECT_METHODS( CoreGraphicsState, dfb_graphics_state ) /**********************************************************************************************************************/ DFBResult dfb_graphics_state_create ( CoreDFB *core, CoreGraphicsState **ret_state ); #endif ================================================ FILE: src/core/input.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #if !FUSION_BUILD_MULTI #include #endif /* FUSION_BUILD_MULTI */ #include #include #include #include D_DEBUG_DOMAIN( Core_Input, "Core/Input", "DirectFB Core Input" ); D_DEBUG_DOMAIN( Core_InputEvt, "Core/Input/Evt", "DirectFB Core Input Events & Dispatch" ); DEFINE_MODULE_DIRECTORY( dfb_input_drivers, "inputdrivers", DFB_INPUT_DRIVER_ABI_VERSION ); /**********************************************************************************************************************/ typedef struct { int magic; int num; CoreInputDeviceShared *devices[MAX_INPUTDEVICES]; FusionReactor *reactor; /* For input hot-plug event. */ } DFBInputCoreShared; typedef struct { int magic; CoreDFB *core; DFBInputCoreShared *shared; DirectLink *drivers; DirectLink *devices; } DFBInputCore; DFB_CORE_PART( input_core, InputCore ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI #define CHECK_INTERVAL 20000 #define CHECK_NUMBER 200 #endif /* FUSION_BUILD_MULTI */ typedef struct { bool is_plugin; /* Hotplug in or not */ int dev_id; /* Input device ID */ struct timeval stamp; /* Time stamp of event */ } InputDeviceHotplugEvent; typedef struct { DFBInputDeviceKeySymbol target; DFBInputDeviceKeySymbol result; } DeadKeyCombo; typedef struct { DFBInputDeviceKeySymbol deadkey; const DeadKeyCombo *combos; } DeadKeyMap; static const DeadKeyCombo combos_grave[] = { { DIKS_SPACE, (unsigned char) '`' }, { DIKS_SMALL_A, (unsigned char) '' }, { DIKS_SMALL_E, (unsigned char) '' }, { DIKS_SMALL_I, (unsigned char) '' }, { DIKS_SMALL_O, (unsigned char) '' }, { DIKS_SMALL_U, (unsigned char) '' }, { DIKS_CAPITAL_A, (unsigned char) '' }, { DIKS_CAPITAL_E, (unsigned char) '' }, { DIKS_CAPITAL_I, (unsigned char) '' }, { DIKS_CAPITAL_O, (unsigned char) '' }, { DIKS_CAPITAL_U, (unsigned char) '' }, { 0, 0 } }; static const DeadKeyCombo combos_acute[] = { { DIKS_SPACE, (unsigned char) '\'' }, { DIKS_SMALL_A, (unsigned char) '' }, { DIKS_SMALL_E, (unsigned char) '' }, { DIKS_SMALL_I, (unsigned char) '' }, { DIKS_SMALL_O, (unsigned char) '' }, { DIKS_SMALL_U, (unsigned char) '' }, { DIKS_SMALL_Y, (unsigned char) '' }, { DIKS_CAPITAL_A, (unsigned char) '' }, { DIKS_CAPITAL_E, (unsigned char) '' }, { DIKS_CAPITAL_I, (unsigned char) '' }, { DIKS_CAPITAL_O, (unsigned char) '' }, { DIKS_CAPITAL_U, (unsigned char) '' }, { DIKS_CAPITAL_Y, (unsigned char) '' }, { 0, 0 } }; static const DeadKeyCombo combos_circumflex[] = { { DIKS_SPACE, (unsigned char) '^' }, { DIKS_SMALL_A, (unsigned char) '' }, { DIKS_SMALL_E, (unsigned char) '' }, { DIKS_SMALL_I, (unsigned char) '' }, { DIKS_SMALL_O, (unsigned char) '' }, { DIKS_SMALL_U, (unsigned char) '' }, { DIKS_CAPITAL_A, (unsigned char) '' }, { DIKS_CAPITAL_E, (unsigned char) '' }, { DIKS_CAPITAL_I, (unsigned char) '' }, { DIKS_CAPITAL_O, (unsigned char) '' }, { DIKS_CAPITAL_U, (unsigned char) '' }, { 0, 0 } }; static const DeadKeyCombo combos_diaeresis[] = { { DIKS_SPACE, (unsigned char) '' }, { DIKS_SMALL_A, (unsigned char) '' }, { DIKS_SMALL_E, (unsigned char) '' }, { DIKS_SMALL_I, (unsigned char) '' }, { DIKS_SMALL_O, (unsigned char) '' }, { DIKS_SMALL_U, (unsigned char) '' }, { DIKS_CAPITAL_A, (unsigned char) '' }, { DIKS_CAPITAL_E, (unsigned char) '' }, { DIKS_CAPITAL_I, (unsigned char) '' }, { DIKS_CAPITAL_O, (unsigned char) '' }, { DIKS_CAPITAL_U, (unsigned char) '' }, { 0, 0 } }; static const DeadKeyCombo combos_tilde[] = { { DIKS_SPACE, (unsigned char) '~' }, { DIKS_SMALL_A, (unsigned char) '' }, { DIKS_SMALL_N, (unsigned char) '' }, { DIKS_SMALL_O, (unsigned char) '' }, { DIKS_CAPITAL_A, (unsigned char) '' }, { DIKS_CAPITAL_N, (unsigned char) '' }, { DIKS_CAPITAL_O, (unsigned char) '' }, { 0, 0 } }; static const DeadKeyMap deadkey_maps[] = { { DIKS_DEAD_GRAVE, combos_grave }, { DIKS_DEAD_ACUTE, combos_acute }, { DIKS_DEAD_CIRCUMFLEX, combos_circumflex }, { DIKS_DEAD_DIAERESIS, combos_diaeresis }, { DIKS_DEAD_TILDE, combos_tilde } }; static ReactionFunc dfb_input_globals[MAX_INPUT_GLOBALS+1] = { _dfb_windowstack_inputdevice_listener, NULL }; /* Define a lookup table to go from key IDs to names, used to look up the names provided in a loaded key table. */ DirectFBKeySymbolNames(KeySymbolNames); DirectFBKeyIdentifierNames(KeyIdentifierNames); /**********************************************************************************************************************/ DFBResult dfb_input_add_global( ReactionFunc func, int *ret_index ) { int i; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, func, ret_index ); D_ASSERT( func != NULL ); D_ASSERT( ret_index != NULL ); for (i = 0; i < MAX_INPUT_GLOBALS; i++) { if (!dfb_input_globals[i]) { dfb_input_globals[i] = func; D_DEBUG_AT( Core_Input, " -> index %d\n", i ); *ret_index = i; return DFB_OK; } } return DFB_LIMITEXCEEDED; } DFBResult dfb_input_set_global( ReactionFunc func, int index ) { D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, func, index ); D_ASSERT( func != NULL ); D_ASSERT( index >= 0 ); D_ASSERT( index < MAX_INPUT_GLOBALS ); D_ASSUME( dfb_input_globals[index] == NULL ); dfb_input_globals[index] = func; return DFB_OK; } /**********************************************************************************************************************/ static DFBInputCore *core_local; static DFBInputCoreShared *core_input; static void init_devices( CoreDFB *core ); static void flush_keys ( CoreInputDevice *device ); static ReactionResult local_processing_hotplug( const void *msg_data, void *ctx ); #if FUSION_BUILD_MULTI static Reaction local_processing_react; /* Local reaction to hot-plug event */ #endif /* FUSION_BUILD_MULTI */ static DFBResult dfb_input_core_initialize( CoreDFB *core, DFBInputCore *data, DFBInputCoreShared *shared ) { #if FUSION_BUILD_MULTI DFBResult ret; #endif /* FUSION_BUILD_MULTI */ D_DEBUG_AT( Core_Input, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); core_local = data; core_input = shared; data->core = core; data->shared = shared; direct_modules_explore_directory( &dfb_input_drivers ); #if FUSION_BUILD_MULTI /* Create the reactor that responds input device hot-plug events. */ shared->reactor = fusion_reactor_new( sizeof(InputDeviceHotplugEvent), "Input Hotplug", dfb_core_world( core ) ); if (!shared->reactor) { D_ERROR( "Core/Input: fusion_reactor_new() failed!\n" ); return DFB_FAILURE; } fusion_reactor_add_permissions( shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); /* Attach the local processing function to the input hot-plug reactor. */ ret = fusion_reactor_attach( shared->reactor, local_processing_hotplug, core, &local_processing_react ); if (ret) { fusion_reactor_destroy( shared->reactor ); D_ERROR( "Core/Input: fusion_reactor_attach() failed!\n" ); return ret; } #endif /* FUSION_BUILD_MULTI */ init_devices( core ); D_MAGIC_SET( data, DFBInputCore ); D_MAGIC_SET( shared, DFBInputCoreShared ); return DFB_OK; } static DFBResult dfb_input_core_join( CoreDFB *core, DFBInputCore *data, DFBInputCoreShared *shared ) { #if FUSION_BUILD_MULTI DFBResult ret; #endif /* FUSION_BUILD_MULTI */ int i; D_DEBUG_AT( Core_Input, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBInputCoreShared ); D_ASSERT( shared->reactor != NULL ); core_local = data; core_input = shared; data->core = core; data->shared = shared; #if FUSION_BUILD_MULTI /* Attach the local processing function to the input hot-plug reactor. */ ret = fusion_reactor_attach( shared->reactor, local_processing_hotplug, core, &local_processing_react ); if (ret) { D_ERROR( "Core/Input: fusion_reactor_attach() failed!\n" ); return ret; } #endif /* FUSION_BUILD_MULTI */ for (i = 0; i < shared->num; i++) { CoreInputDevice *device; CoreInputDeviceShared *ishared = shared->devices[i]; device = D_CALLOC( 1, sizeof(CoreInputDevice) ); if (!device) { D_OOM(); continue; } device->shared = ishared; #if FUSION_BUILD_MULTI /* Increase the reference counter. */ fusion_ref_up( &ishared->ref, false ); #endif /* FUSION_BUILD_MULTI */ /* Add it to the list. */ direct_list_append( &data->devices, &device->link ); D_MAGIC_SET( device, CoreInputDevice ); } D_MAGIC_SET( data, DFBInputCore ); return DFB_OK; } static DFBResult dfb_input_core_shutdown( DFBInputCore *data, bool emergency ) { DFBInputCoreShared *shared; CoreInputDevice *device; CoreInputDriver *driver; DirectLink *next; const InputDriverFuncs *funcs; FusionSHMPoolShared *pool; D_UNUSED_P( shared ); D_DEBUG_AT( Core_Input, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); shared = data->shared; pool = dfb_core_shmpool( data->core ); /* Stop each input provider's hot-plug thread that supports device hot-plugging. */ direct_list_foreach_safe (driver, next, data->drivers) { D_ASSERT( driver->funcs != NULL ); funcs = driver->funcs; if (funcs->GetCapability && funcs->StopHotplug) { if (IDC_HOTPLUG & funcs->GetCapability()) { D_DEBUG_AT( Core_Input, " -> stopping hot-plug detection in %s\n", driver->module->name ); if (funcs->StopHotplug()) { D_ERROR( "Core/Input: Failed to stop hot-plug detection in %s!\n", driver->module->name ); } } } } #if FUSION_BUILD_MULTI fusion_reactor_detach( shared->reactor, &local_processing_react ); fusion_reactor_destroy( shared->reactor ); #endif /* FUSION_BUILD_MULTI */ direct_list_foreach_safe (device, next, data->devices) { CoreInputDeviceShared *ishared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); ishared = device->shared; driver = device->driver; CoreInputDevice_Deinit_Dispatch( &ishared->call ); fusion_skirmish_destroy( &ishared->lock ); if (device->driver_data != NULL) { void *driver_data; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->CloseDevice != NULL ); funcs = driver->funcs; D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", ishared->device_info.desc.name, ishared->num + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); driver_data = device->driver_data; device->driver_data = NULL; funcs->CloseDevice( driver_data ); } if (!--driver->nr_devices) { funcs = driver->funcs; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->GetAvailable != NULL ); funcs->GetAvailable(); direct_module_unref( driver->module ); D_FREE( driver ); } #if FUSION_BUILD_MULTI fusion_ref_destroy( &ishared->ref ); #else /* FUSION_BUILD_MULTI */ fusion_reactor_free( ishared->reactor ); #endif /* FUSION_BUILD_MULTI */ fusion_reactor_free( ishared->reactor ); if (ishared->keymap.entries) SHFREE( pool, ishared->keymap.entries ); if (ishared->axis_info) SHFREE( pool, ishared->axis_info ); SHFREE( pool, ishared ); D_MAGIC_CLEAR( device ); D_FREE( device ); } D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); core_local = NULL; core_input = NULL; return DFB_OK; } static DFBResult dfb_input_core_leave( DFBInputCore *data, bool emergency ) { CoreInputDevice *device, *next; D_DEBUG_AT( Core_Input, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); #if FUSION_BUILD_MULTI DFBInputCoreShared *shared = data->shared; fusion_reactor_detach( shared->reactor, &local_processing_react ); #endif /* FUSION_BUILD_MULTI */ direct_list_foreach_safe (device, next, data->devices) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); #if FUSION_BUILD_MULTI /* Decrease the ref between shared device and local device. */ CoreInputDeviceShared *ishared = device->shared; fusion_ref_down( &ishared->ref, false ); #endif /* FUSION_BUILD_MULTI */ D_FREE( device ); } D_MAGIC_CLEAR( data ); core_local = NULL; core_input = NULL; return DFB_OK; } static DFBResult dfb_input_core_suspend( DFBInputCore *data ) { CoreInputDevice *device; CoreInputDriver *driver; const InputDriverFuncs *funcs; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); D_DEBUG_AT( Core_Input, " -> suspending...\n" ); /* Go through the drivers list and attempt to suspend all of the drivers that support the Suspend() function. */ direct_list_foreach (driver, data->drivers) { DFBResult ret; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->Suspend != NULL ); funcs = driver->funcs; ret = funcs->Suspend(); if (ret != DFB_OK && ret != DFB_UNSUPPORTED) { D_DERROR( ret, "Core/Input: Could not suspend '%s'!\n", driver->info.name ); } } direct_list_foreach (device, data->devices) { CoreInputDeviceShared *ishared; D_UNUSED_P( ishared ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); ishared = device->shared; driver = device->driver; if (device->driver_data != NULL) { void *driver_data; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->CloseDevice != NULL ); funcs = driver->funcs; D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", ishared->device_info.desc.name, ishared->num + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); driver_data = device->driver_data; device->driver_data = NULL; funcs->CloseDevice( driver_data ); } flush_keys( device ); } D_DEBUG_AT( Core_Input, " -> suspended\n" ); return DFB_OK; } static DFBResult dfb_input_core_resume( DFBInputCore *data ) { DFBResult ret; CoreInputDevice *device; CoreInputDriver *driver; const InputDriverFuncs *funcs; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); D_DEBUG_AT( Core_Input, " -> resuming...\n" ); direct_list_foreach (device, data->devices) { CoreInputDeviceShared *ishared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); D_ASSERT( device->driver->funcs != NULL ); D_ASSERT( device->driver->funcs->OpenDevice != NULL ); ishared = device->shared; driver = device->driver; funcs = driver->funcs; D_DEBUG_AT( Core_Input, " -> reopening '%s' (%d) %d.%d (%s)\n", ishared->device_info.desc.name, ishared->num + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); D_ASSERT( device->driver_data == NULL ); ret = funcs->OpenDevice( device, ishared->num, &ishared->device_info, &device->driver_data ); if (ret) { D_DERROR( ret, "Core/Input: Failed reopening device '%s' during resume!\n", ishared->device_info.desc.name ); device->driver_data = NULL; } } /* Go through the drivers list and attempt to resume all of the drivers that support the Resume() function. */ direct_list_foreach (driver, data->drivers) { D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->Resume != NULL ); funcs = driver->funcs; ret = funcs->Resume(); if (ret != DFB_OK && ret != DFB_UNSUPPORTED) { D_DERROR( ret, "Core/Input: Could not resume '%s'!\n", driver->info.name ); } } D_DEBUG_AT( Core_Input, " -> resumed\n" ); return DFB_OK; } /**********************************************************************************************************************/ static DFBInputDeviceKeymapEntry *get_keymap_entry( CoreInputDevice *device, int code ); static DFBResult set_keymap_entry( CoreInputDevice *device, int code, const DFBInputDeviceKeymapEntry *entry ); static DFBResult load_keymap ( CoreInputDevice *device, char *filename ); static DFBResult reload_keymap ( CoreInputDevice *device ); static bool lookup_from_table( CoreInputDevice *device, DFBInputEvent *event, DFBInputEventFlags lookup ); static void fixup_key_event ( CoreInputDevice *device, DFBInputEvent *event ); static void fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event ); static bool core_input_filter( CoreInputDevice *device, DFBInputEvent *event ); void dfb_input_enumerate_devices( InputDeviceCallback callback, void *ctx, DFBInputDeviceCapabilities caps ) { CoreInputDevice *device; CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %p, 0x08%x )\n", __FUNCTION__, callback, ctx, caps ); D_ASSERT( core_input != NULL ); direct_list_foreach (device, core_local->devices) { DFBInputDeviceCapabilities dev_caps; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); shared = device->shared; dev_caps = shared->device_info.desc.caps; /* Always match if unclassified. */ if (!dev_caps) dev_caps = DICAPS_ALL; if ((dev_caps & caps) && callback( device, ctx ) == DFENUM_CANCEL) break; } } DirectResult dfb_input_attach( CoreInputDevice *device, ReactionFunc func, void *ctx, Reaction *reaction ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %p, %p, %p )\n", __FUNCTION__, device, func, ctx, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return fusion_reactor_attach( shared->reactor, func, ctx, reaction ); } DirectResult dfb_input_detach( CoreInputDevice *device, Reaction *reaction ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return fusion_reactor_detach( shared->reactor, reaction ); } DirectResult dfb_input_attach_global( CoreInputDevice *device, int index, void *ctx, GlobalReaction *reaction ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %d, %p, %p )\n", __FUNCTION__, device, index, ctx, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return fusion_reactor_attach_global( shared->reactor, index, ctx, reaction ); } DirectResult dfb_input_detach_global( CoreInputDevice *device, GlobalReaction *reaction ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return fusion_reactor_detach_global( shared->reactor, reaction ); } void dfb_input_dispatch( CoreInputDevice *device, DFBInputEvent *event ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, event ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( event != NULL ); /* When a USB device is hot-removed, it is possible that there are pending events still being dispatched. */ shared = device->shared; if (!shared) { D_DEBUG_AT( Core_Input, " -> no shared data!\n" ); return; } D_ASSUME( shared->reactor != NULL ); if (!shared->reactor) { D_DEBUG_AT( Core_Input, " -> no reactor!\n" ); return; } D_DEBUG_AT( Core_InputEvt, " -> (%02x) %s%s%s\n", event->type, dfb_input_event_type_name( event->type ), (event->flags & DIEF_FOLLOW) ? " [FOLLOW]" : "", (event->flags & DIEF_REPEAT) ? " [REPEAT]" : "" ); if (direct_log_domain_check( &Core_InputEvt )) { if (event->flags & DIEF_TIMESTAMP) D_DEBUG_AT( Core_InputEvt, " -> TIMESTAMP %lu.%06lu\n", (unsigned long) event->timestamp.tv_sec, (unsigned long) event->timestamp.tv_usec ); if (event->flags & DIEF_AXISABS) D_DEBUG_AT( Core_InputEvt, " -> AXISABS %u at %d\n", event->axis, event->axisabs ); if (event->flags & DIEF_AXISREL) D_DEBUG_AT( Core_InputEvt, " -> AXISREL %u by %d\n", event->axis, event->axisrel ); if (event->flags & DIEF_KEYCODE) D_DEBUG_AT( Core_InputEvt, " -> KEYCODE %d\n", event->key_code ); if (event->flags & DIEF_KEYID) D_DEBUG_AT( Core_InputEvt, " -> KEYID 0x%04x\n", event->key_id ); if (event->flags & DIEF_KEYSYMBOL) D_DEBUG_AT( Core_InputEvt, " -> KEYSYMBOL 0x%04x\n", event->key_symbol ); if (event->flags & DIEF_MODIFIERS) D_DEBUG_AT( Core_InputEvt, " -> MODIFIERS 0x%04x\n", event->modifiers ); if (event->flags & DIEF_LOCKS) D_DEBUG_AT( Core_InputEvt, " -> LOCKS 0x%04x\n", event->locks ); if (event->flags & DIEF_BUTTONS) D_DEBUG_AT( Core_InputEvt, " -> BUTTONS 0x%04x\n", event->buttons ); if (event->flags & DIEF_GLOBAL) D_DEBUG_AT( Core_InputEvt, " -> GLOBAL\n" ); } /* Fixup event. */ event->clazz = DFEC_INPUT; event->device_id = shared->id; if (!(event->flags & DIEF_TIMESTAMP)) { long long timestamp_us = direct_clock_get_abs_micros(); event->timestamp.tv_sec = timestamp_us / 1000000; event->timestamp.tv_usec = timestamp_us % 1000000; event->flags |= DIEF_TIMESTAMP; } switch (event->type) { case DIET_BUTTONPRESS: case DIET_BUTTONRELEASE: D_DEBUG_AT( Core_InputEvt, " -> BUTTON 0x%04x\n", event->button ); if (dfb_config->lefty) { if (event->button == DIBI_LEFT) event->button = DIBI_RIGHT; else if (event->button == DIBI_RIGHT) event->button = DIBI_LEFT; D_DEBUG_AT( Core_InputEvt, " -> LEFTY 0x%04x\n", event->button ); } case DIET_AXISMOTION: fixup_mouse_event( device, event ); break; case DIET_KEYPRESS: case DIET_KEYRELEASE: if (dfb_config->capslock_meta) { if (shared->keymap.num_entries && (event->flags & DIEF_KEYCODE)) lookup_from_table( device, event, (DIEF_KEYID | DIEF_KEYSYMBOL) & ~event->flags ); if (event->key_id == DIKI_CAPS_LOCK || event->key_symbol == DIKS_CAPS_LOCK) { event->flags |= DIEF_KEYID | DIEF_KEYSYMBOL; event->key_code = -1; event->key_id = DIKI_META_L; event->key_symbol = DIKS_META; } } fixup_key_event( device, event ); break; default: ; } if (direct_log_domain_check( &Core_InputEvt )) { if (event->flags & DIEF_TIMESTAMP) D_DEBUG_AT( Core_InputEvt, " => TIMESTAMP %lu.%06lu\n", (unsigned long) event->timestamp.tv_sec, (unsigned long) event->timestamp.tv_usec ); if (event->flags & DIEF_AXISABS) D_DEBUG_AT( Core_InputEvt, " => AXISABS %u at %d\n", event->axis, event->axisabs ); if (event->flags & DIEF_AXISREL) D_DEBUG_AT( Core_InputEvt, " => AXISREL %u by %d\n", event->axis, event->axisrel ); if (event->flags & DIEF_KEYCODE) D_DEBUG_AT( Core_InputEvt, " => KEYCODE %d\n", event->key_code ); if (event->flags & DIEF_KEYID) D_DEBUG_AT( Core_InputEvt, " => KEYID 0x%04x\n", event->key_id ); if (event->flags & DIEF_KEYSYMBOL) D_DEBUG_AT( Core_InputEvt, " => KEYSYMBOL 0x%04x\n", event->key_symbol ); if (event->flags & DIEF_MODIFIERS) D_DEBUG_AT( Core_InputEvt, " => MODIFIERS 0x%04x\n", event->modifiers ); if (event->flags & DIEF_LOCKS) D_DEBUG_AT( Core_InputEvt, " => LOCKS 0x%04x\n", event->locks ); if (event->flags & DIEF_BUTTONS) D_DEBUG_AT( Core_InputEvt, " => BUTTONS 0x%04x\n", event->buttons ); if (event->flags & DIEF_GLOBAL) D_DEBUG_AT( Core_InputEvt, " => GLOBAL\n" ); } if (core_input_filter( device, event )) D_DEBUG_AT( Core_InputEvt, " ****>> FILTERED\n" ); else fusion_reactor_dispatch( shared->reactor, event, true, dfb_input_globals ); } DFBInputDeviceID dfb_input_device_id( const CoreInputDevice *device ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return shared->id; } CoreInputDevice * dfb_input_device_at( DFBInputDeviceID id ) { CoreInputDevice *device; CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( 0x%02x )\n", __FUNCTION__, id ); D_ASSERT( core_input != NULL ); direct_list_foreach (device, core_local->devices) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (shared->id == id) return device; } return NULL; } DFBInputDeviceCapabilities dfb_input_device_caps( const CoreInputDevice *device ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; return shared->device_info.desc.caps; } void dfb_input_device_description( const CoreInputDevice *device, DFBInputDeviceDescription *desc ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; *desc = shared->device_info.desc; } DFBResult dfb_input_device_get_keymap_entry( CoreInputDevice *device, int keycode, DFBInputDeviceKeymapEntry *entry ) { DFBInputDeviceKeymapEntry *keymap_entry; D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, device, keycode ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( entry != NULL ); keymap_entry = get_keymap_entry( device, keycode ); if (!keymap_entry) return DFB_FAILURE; *entry = *keymap_entry; return DFB_OK; } DFBResult dfb_input_device_set_keymap_entry( CoreInputDevice *device, int keycode, const DFBInputDeviceKeymapEntry *entry ) { D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, device, keycode ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( entry != NULL ); return set_keymap_entry( device, keycode, entry ); } DFBResult dfb_input_device_load_keymap( CoreInputDevice *device, char *filename ) { D_DEBUG_AT( Core_Input, "%s( %p, '%s' )\n", __FUNCTION__, device, filename ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( filename != NULL ); return load_keymap( device, filename ); } DFBResult dfb_input_device_reload_keymap( CoreInputDevice *device ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; D_INFO( "DirectFB/Input: Reloading keymap for '%s' [0x%02x]...\n", shared->device_info.desc.name, shared->id ); return reload_keymap( device ); } DFBResult dfb_input_device_get_state( CoreInputDevice *device, InputDeviceState *ret_state ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; *ret_state = shared->state; return DFB_OK; } DFBResult dfb_input_device_set_configuration( CoreInputDevice *device, const DFBInputDeviceConfig *config ) { CoreInputDriver *driver; const InputDriverFuncs *funcs; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, config ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->driver != NULL ); D_ASSERT( device->driver->funcs != NULL ); driver = device->driver; funcs = driver->funcs; if (!funcs->SetConfiguration) return DFB_UNSUPPORTED; return funcs->SetConfiguration( device, device->driver_data, config ); } /**********************************************************************************************************************/ static void input_add_device( CoreInputDevice *device ) { CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (core_input->num == MAX_INPUTDEVICES) { D_ERROR( "Core/Input: Maximum number of devices reached!\n" ); return; } direct_list_append( &core_local->devices, &device->link ); core_input->devices[core_input->num++] = shared; } static void allocate_device_keymap( CoreDFB *core, CoreInputDevice *device ) { int i; DFBInputDeviceKeymapEntry *entries; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); CoreInputDeviceShared *shared; DFBInputDeviceDescription *desc; int num_entries; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, core, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; desc = &shared->device_info.desc; num_entries = desc->max_keycode - desc->min_keycode + 1; entries = SHCALLOC( pool, num_entries, sizeof(DFBInputDeviceKeymapEntry) ); if (!entries) { D_OOSHM(); return; } /* Write -1 indicating entry is not fetched yet from driver. */ for (i = 0; i < num_entries; i++) entries[i].code = -1; shared->keymap.min_keycode = desc->min_keycode; shared->keymap.max_keycode = desc->max_keycode; shared->keymap.num_entries = num_entries; shared->keymap.entries = entries; #if FUSION_BUILD_MULTI /* We need to fetch the whole map, otherwise a slave would try to. */ for (i = desc->min_keycode; i <= desc->max_keycode; i++) get_keymap_entry( device, i ); #endif /* FUSION_BUILD_MULTI */ } static int make_id( DFBInputDeviceID prefered ) { CoreInputDevice *device; CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( 0x%02x )\n", __FUNCTION__, prefered ); D_ASSERT( core_input != NULL ); direct_list_foreach (device, core_local->devices) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (shared->id == prefered) return make_id( (prefered < DIDID_ANY) ? DIDID_ANY : (prefered + 1) ); } return prefered; } static DFBResult init_axes( CoreInputDevice *device ) { DFBResult ret; int i, num; CoreInputDeviceShared *shared; CoreInputDriver *driver; const InputDriverFuncs *funcs; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); D_ASSERT( device->driver->funcs != NULL ); shared = device->shared; driver = device->driver; funcs = driver->funcs; if (shared->device_info.desc.max_axis < 0) return DFB_OK; num = shared->device_info.desc.max_axis + 1; shared->axis_info = SHCALLOC( dfb_core_shmpool(device->core), num, sizeof(InputDeviceAxisInfo) ); if (!shared->axis_info) return D_OOSHM(); shared->axis_num = num; if (funcs->GetAxisInfo) { for (i = 0; i < num; i++) { ret = funcs->GetAxisInfo( device, device->driver_data, i, &shared->axis_info[i] ); if (ret) D_DERROR( ret, "Core/Input: Could not get axis info for '%s' [%u] on axis %d!\n", shared->device_info.desc.name, shared->id, i ); } } return DFB_OK; } static void init_devices( CoreDFB *core ) { DirectModuleEntry *module, *next; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); direct_list_foreach_safe (module, next, dfb_input_drivers.entries) { DFBResult ret; CoreInputDriver *driver; const InputDriverFuncs *funcs; InputDriverCapability driver_cap; int n; driver_cap = IDC_NONE; funcs = direct_module_ref( module ); if (!funcs) continue; driver = D_CALLOC( 1, sizeof(CoreInputDriver) ); if (!driver) { D_OOM(); direct_module_unref( module ); continue; } D_ASSERT( funcs->GetDriverInfo != NULL ); funcs->GetDriverInfo( &driver->info ); D_DEBUG_AT( Core_Input, " -> probing '%s'...\n", driver->info.name ); driver->nr_devices = funcs->GetAvailable(); /* If the input provider supports hot-plug, always load the module. */ if (!funcs->GetCapability) { D_DEBUG_AT( Core_Input, " -> GetCapability() is NULL\n" ); } else { driver_cap = funcs->GetCapability(); } if (!driver->nr_devices && !(driver_cap & IDC_HOTPLUG)) { direct_module_unref( module ); D_FREE( driver ); continue; } D_DEBUG_AT( Core_Input, " -> %d available device(s) provided by '%s'\n", driver->nr_devices, driver->info.name ); driver->module = module; driver->funcs = funcs; direct_list_prepend( &core_local->drivers, &driver->link ); for (n = 0; n < driver->nr_devices; n++) { char buf[128]; CoreInputDevice *device; InputDeviceInfo device_info; CoreInputDeviceShared *shared; void *driver_data; device = D_CALLOC( 1, sizeof(CoreInputDevice) ); if (!device) { D_OOM(); continue; } shared = SHCALLOC( pool, 1, sizeof(CoreInputDeviceShared) ); if (!shared) { D_OOSHM(); D_FREE( device ); continue; } device->core = core; memset( &device_info, 0, sizeof(InputDeviceInfo) ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; D_MAGIC_SET( device, CoreInputDevice ); if (funcs->OpenDevice( device, n, &device_info, &driver_data )) { SHFREE( pool, shared ); D_MAGIC_CLEAR( device ); D_FREE( device ); continue; } D_DEBUG_AT( Core_Input, " -> opened '%s' (%d) %d.%d (%s)\n", device_info.desc.name, n + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); if (driver->nr_devices > 1) snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, n + 1 ); else snprintf( buf, sizeof(buf), "%s", device_info.desc.name ); /* Init skirmish. */ fusion_skirmish_init2( &shared->lock, buf, dfb_core_world( core ), fusion_config->secure_fusion ); /* Create reactor. */ shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world( core ) ); fusion_reactor_direct( shared->reactor, false ); fusion_reactor_add_permissions( shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_reactor_set_lock( shared->reactor, &shared->lock ); /* Init call. */ CoreInputDevice_Init_Dispatch( core, device, &shared->call ); /* Initialize shared data. */ shared->id = make_id( device_info.prefered_id ); shared->num = n; shared->device_info = device_info; shared->last_key = DIKI_UNKNOWN; shared->first_press = true; /* Initialize local data. */ device->shared = shared; device->driver = driver; device->driver_data = driver_data; D_INFO( "DirectFB/Input: %s %d.%d (%s)\n", buf, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); #if FUSION_BUILD_MULTI /* Initialize the ref between shared device and local device. */ snprintf( buf, sizeof(buf), "Ref of input device(%u)", shared->id ); fusion_ref_init( &shared->ref, buf, dfb_core_world( core ) ); fusion_ref_add_permissions( &shared->ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL ); /* Increase reference counter. */ fusion_ref_up( &shared->ref, false ); #endif /* FUSION_BUILD_MULTI */ if (device_info.desc.min_keycode > device_info.desc.max_keycode) { D_BUG( "min_keycode > max_keycode" ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; } else if (device_info.desc.min_keycode >= 0 && device_info.desc.max_keycode >= 0) allocate_device_keymap( core, device ); init_axes( device ); /* Add it to the list. */ input_add_device( device ); } /* If the driver supports hot-plug, launch its hot-plug thread to respond to hot-plug events. */ if (driver_cap == IDC_HOTPLUG) { ret = funcs->LaunchHotplug( core, driver ); /* On failure, the input provider can still be used without hot-plug. */ if (ret) { D_INFO( "DirectFB/Input: Failed to enable hot-plug detection with %s\n", driver->info.name ); } else { D_INFO( "DirectFB/Input: Hot-plug detection enabled with %s\n", driver->info.name ); } } } } static void release_key( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id ) { DFBInputEvent evt; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); evt.type = DIET_KEYRELEASE; if (DFB_KEY_TYPE( id ) == DIKT_IDENTIFIER) { evt.flags = DIEF_KEYID; evt.key_id = id; } else { evt.flags = DIEF_KEYSYMBOL; evt.key_symbol = id; } dfb_input_dispatch( device, &evt ); } static void flush_keys( CoreInputDevice *device ) { CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (shared->state.modifiers_l) { if (shared->state.modifiers_l & DIMM_ALT) release_key( device, DIKI_ALT_L ); if (shared->state.modifiers_l & DIMM_CONTROL) release_key( device, DIKI_CONTROL_L ); if (shared->state.modifiers_l & DIMM_HYPER) release_key( device, DIKI_HYPER_L ); if (shared->state.modifiers_l & DIMM_META) release_key( device, DIKI_META_L ); if (shared->state.modifiers_l & DIMM_SHIFT) release_key( device, DIKI_SHIFT_L ); if (shared->state.modifiers_l & DIMM_SUPER) release_key( device, DIKI_SUPER_L ); } if (shared->state.modifiers_r) { if (shared->state.modifiers_r & DIMM_ALTGR) release_key( device, DIKS_ALTGR ); if (shared->state.modifiers_r & DIMM_ALT) release_key( device, DIKI_ALT_R ); if (shared->state.modifiers_r & DIMM_CONTROL) release_key( device, DIKI_CONTROL_R ); if (shared->state.modifiers_r & DIMM_HYPER) release_key( device, DIKI_HYPER_R ); if (shared->state.modifiers_r & DIMM_META) release_key( device, DIKI_META_R ); if (shared->state.modifiers_r & DIMM_SHIFT) release_key( device, DIKI_SHIFT_R ); if (shared->state.modifiers_r & DIMM_SUPER) release_key( device, DIKI_SUPER_R ); } } /**********************************************************************************************************************/ DFBResult dfb_input_create_device( int device_index, CoreDFB *core_in, void *driver_in ) { DFBResult ret; char buf[128]; CoreInputDevice *device; InputDeviceInfo device_info; CoreInputDeviceShared *shared; CoreInputDriver *driver = driver_in; void *driver_data; const InputDriverFuncs *funcs; FusionSHMPoolShared *pool; D_DEBUG_AT( Core_Input, "%s()\n", __FUNCTION__ ); funcs = driver->funcs; pool = dfb_core_shmpool( core_in ); if (!funcs) { return DFB_FAILURE; } device = D_CALLOC( 1, sizeof(CoreInputDevice) ); if (!device) { return D_OOM(); } shared = SHCALLOC( pool, 1, sizeof(CoreInputDeviceShared) ); if (!shared) { D_FREE( device ); return D_OOSHM(); } device->core = core_in; memset( &device_info, 0, sizeof(InputDeviceInfo) ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; D_MAGIC_SET( device, CoreInputDevice ); if (funcs->OpenDevice( device, device_index, &device_info, &driver_data )) { SHFREE( pool, shared ); D_MAGIC_CLEAR( device ); D_FREE( device ); D_ERROR( "Core/Input: Could not open device!\n" ); return DFB_FAILURE; } snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, device_index ); /* Init skirmish. */ ret = fusion_skirmish_init2( &shared->lock, buf, dfb_core_world( device->core ), fusion_config->secure_fusion ); if (ret) { funcs->CloseDevice( driver_data ); SHFREE( pool, shared ); D_MAGIC_CLEAR( device ); D_FREE( device ); D_ERROR( "Core/Input: fusion_skirmish_init2() failed!\n" ); return DFB_FAILURE; } /* Create reactor. */ shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world( device->core ) ); if (!shared->reactor) { funcs->CloseDevice( driver_data ); SHFREE( pool, shared ); D_MAGIC_CLEAR( device ); D_FREE( device ); fusion_skirmish_destroy( &shared->lock ); D_ERROR( "Core/Input: fusion_reactor_new() failed!\n" ); return DFB_FAILURE; } fusion_reactor_direct( shared->reactor, false ); fusion_reactor_add_permissions( shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); fusion_reactor_set_lock( shared->reactor, &shared->lock ); /* Init call. */ CoreInputDevice_Init_Dispatch( device->core, device, &shared->call ); /* Initialize shared data. */ shared->id = make_id( device_info.prefered_id ); shared->num = device_index; shared->device_info = device_info; shared->last_key = DIKI_UNKNOWN; shared->first_press = true; /* Initialize local data. */ device->shared = shared; device->driver = driver; device->driver_data = driver_data; D_INFO( "DirectFB/Input: %s %d.%d (%s)\n", buf, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); #if FUSION_BUILD_MULTI snprintf( buf, sizeof(buf), "Ref of input device(%u)", shared->id ); fusion_ref_init( &shared->ref, buf, dfb_core_world( core_in ) ); fusion_ref_add_permissions( &shared->ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL ); fusion_ref_up( &shared->ref, false ); #endif /* FUSION_BUILD_MULTI */ if (device_info.desc.min_keycode > device_info.desc.max_keycode) { D_BUG( "min_keycode > max_keycode" ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; } else if (device_info.desc.min_keycode >= 0 && device_info.desc.max_keycode >= 0) allocate_device_keymap( device->core, device ); /* Add it into local device list and shared dev array. */ input_add_device( device ); driver->nr_devices++; D_DEBUG_AT( Core_Input, " -> add new input device with dev_id = %u\n", shared->id ); /* Setup the hot-plug in message. */ InputDeviceHotplugEvent message; long long timestamp_us = direct_clock_get_abs_micros(); message.is_plugin = true; message.dev_id = shared->id; message.stamp.tv_sec = timestamp_us / 1000000; message.stamp.tv_usec = timestamp_us % 1000000; /* Send the hot-plug in message. */ #if FUSION_BUILD_MULTI fusion_reactor_dispatch( core_input->reactor, &message, true, NULL ); #else /* FUSION_BUILD_MULTI */ local_processing_hotplug( &message, core_in ); #endif /* FUSION_BUILD_MULTI */ return DFB_OK; } /* * Tell whether the DFB input device handling of the system input device indicated by 'device_index' is already created. */ static CoreInputDevice * search_device_created( int device_index, void *driver_in ) { CoreInputDevice *device, *next; CoreInputDeviceShared *shared; CoreInputDriver *driver; const InputDriverFuncs *funcs; D_UNUSED_P( shared ); D_ASSERT( driver_in != NULL ); direct_list_foreach_safe (device, next, core_local->devices) { D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); shared = device->shared; driver = device->driver; if (driver != driver_in) continue; if (device->driver_data == NULL) { D_DEBUG_AT( Core_Input, " -> the device %u has been closed!\n", shared->id ); return NULL; } D_ASSERT( device->driver->funcs != NULL ); funcs = driver->funcs; if (funcs->IsCreated && !funcs->IsCreated(device_index, device->driver_data)) { return device; } } return NULL; } DFBResult dfb_input_remove_device( int device_index, void *driver_in ) { CoreInputDevice *device; CoreInputDeviceShared *shared; CoreInputDriver *driver; const InputDriverFuncs *funcs; FusionSHMPoolShared *pool; int i; int found = 0; int device_id; D_DEBUG_AT( Core_Input, "%s()\n", __FUNCTION__ ); D_ASSERT( driver_in != NULL ); device = search_device_created( device_index, driver_in ); if (device == NULL) { D_DEBUG_AT( Core_Input, " -> failed to find the device[%d] or the device is closed\n", device_index ); return DFB_FAILURE; } D_ASSERT( device->shared != NULL ); D_ASSERT( device->driver != NULL ); D_ASSERT( device->driver->funcs != NULL ); shared = device->shared; driver = device->driver; funcs = driver->funcs; pool = dfb_core_shmpool( device->core ); device_id = shared->id; D_DEBUG_AT( Core_Input, " -> find the device with dev_id = %d\n", device_id ); funcs->CloseDevice( device->driver_data ); driver->nr_devices--; /* Setup the hot-plug out message. */ InputDeviceHotplugEvent message; long long timestamp_us = direct_clock_get_abs_micros(); message.is_plugin = false; message.dev_id = device_id; message.stamp.tv_sec = timestamp_us / 1000000; message.stamp.tv_usec = timestamp_us % 1000000; /* Send the hot-plug out message. */ #if FUSION_BUILD_MULTI fusion_reactor_dispatch( core_input->reactor, &message, true, NULL ); int loop = CHECK_NUMBER; while (--loop) { if (fusion_ref_zero_trylock( &shared->ref ) == DR_OK) { fusion_ref_unlock( &shared->ref ); break; } usleep( CHECK_INTERVAL ); } if (!loop) D_DEBUG_AT( Core_Input, " -> the device can be connected by others\n" ); fusion_ref_destroy( &shared->ref ); #else /* FUSION_BUILD_MULTI */ local_processing_hotplug( &message, device->core ); #endif /* FUSION_BUILD_MULTI */ /* Remove the device from shared array. */ for (i = 0; i < core_input->num; i++) { if (!found && (core_input->devices[i]->id == shared->id)) found = 1; if (found) core_input->devices[i] = core_input->devices[(i + 1) % MAX_INPUTDEVICES]; } if (found) core_input->devices[core_input->num -1] = NULL; core_input->num--; CoreInputDevice_Deinit_Dispatch( &shared->call ); fusion_skirmish_destroy( &shared->lock ); fusion_reactor_free( shared->reactor ); if (shared->keymap.entries) SHFREE( pool, shared->keymap.entries ); SHFREE( pool, shared ); D_DEBUG_AT( Core_Input, " -> successfully remove the device with dev_id = %d\n", device_id ); return DFB_OK; } /**********************************************************************************************************************/ /* * Create local input device and add it into the local input devices list. */ static CoreInputDevice * add_device_into_local_list( int dev_id ) { int i; for (i = 0; i < core_input->num; i++) { if (core_input->devices[i]->id == dev_id) { CoreInputDevice *device; CoreInputDeviceShared *shared; D_DEBUG_AT( Core_Input, " -> find the device with dev_id = %d, and allocate local device\n", dev_id ); shared = core_input->devices[i]; device = D_CALLOC( 1, sizeof(CoreInputDevice) ); if (!device) return NULL; device->shared = shared; #if FUSION_BUILD_MULTI /* Increase the reference counter. */ fusion_ref_up( &shared->ref, false ); #endif /* FUSION_BUILD_MULTI */ /* Add it to the list. */ direct_list_append( &core_local->devices, &device->link ); D_MAGIC_SET( device, CoreInputDevice ); return device; } } return NULL; } /* * Local input device function that handles hot-plug in/out messages. */ static ReactionResult local_processing_hotplug( const void *msg_data, void *ctx ) { const InputDeviceHotplugEvent *message = msg_data; CoreInputDevice *device; D_DEBUG_AT( Core_Input, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( Core_Input, " -> hotplug-in:%d device_id=%d message\n", getpid(), message->is_plugin, message->dev_id ); if (message->is_plugin) { device = dfb_input_device_at( message->dev_id ); if (!device) { /* Update local device list according to shared devices array. */ if (!(device = add_device_into_local_list( message->dev_id ))) { D_ERROR( "Core/Input: Failed to update local device list!\n" ); return RS_DROP; } } /* Attach the device to event buffer containers. */ eventbuffer_containers_attach_device( device ); /* Attach the device to stack containers. */ stack_containers_attach_device( device ); } else { device = dfb_input_device_at( message->dev_id ); if (device) { direct_list_remove( &core_local->devices, &device->link ); eventbuffer_containers_detach_device( device ); stack_containers_detach_device( device ); #if FUSION_BUILD_MULTI /* Decrease reference counter. */ CoreInputDeviceShared *shared = shared = device->shared; fusion_ref_down( &shared->ref, false ); #endif /* FUSION_BUILD_MULTI */ D_MAGIC_CLEAR( device ); D_FREE( device ); } else D_ERROR( "Core/Input: Can't find the device to be removed!\n" ); } return RS_OK; } /**********************************************************************************************************************/ static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol symbol ); static DFBInputDeviceKeySymbol id_to_symbol( DFBInputDeviceKeyIdentifier id, DFBInputDeviceModifierMask modifiers, DFBInputDeviceLockState locks ); /* * Get a single keymap entry with the code-entry pair. */ static DFBInputDeviceKeymapEntry * get_keymap_entry( CoreInputDevice *device, int code ) { InputDeviceKeymap *map; DFBInputDeviceKeymapEntry *entry; CoreInputDeviceShared *shared; CoreInputDriver *driver; const InputDriverFuncs *funcs; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); D_ASSERT( device->driver != NULL ); D_ASSERT( device->driver->funcs != NULL ); shared = device->shared; driver = device->driver; funcs = driver->funcs; map = &shared->keymap; /* Safety check. */ if (!device->driver_data) return NULL; if (code < map->min_keycode || code > map->max_keycode) return NULL; /* Point to right array index. */ entry = &map->entries[code - map->min_keycode]; /* Need to initialize. */ if (entry->code != code) { DFBResult ret; /* Write keycode to entry. */ entry->code = code; /* Fetch entry from driver. */ ret = funcs->GetKeymapEntry( device, device->driver_data, entry ); if (ret) return NULL; /* Drivers may leave this blank. */ if (entry->identifier == DIKI_UNKNOWN) entry->identifier = symbol_to_id( entry->symbols[DIKSI_BASE] ); if (entry->symbols[DIKSI_BASE_SHIFT] == DIKS_NULL) entry->symbols[DIKSI_BASE_SHIFT] = entry->symbols[DIKSI_BASE]; if (entry->symbols[DIKSI_ALT] == DIKS_NULL) entry->symbols[DIKSI_ALT] = entry->symbols[DIKSI_BASE]; if (entry->symbols[DIKSI_ALT_SHIFT] == DIKS_NULL) entry->symbols[DIKSI_ALT_SHIFT] = entry->symbols[DIKSI_ALT]; } return entry; } /* * Replace a single keymap entry with the code-entry pair. */ static DFBResult set_keymap_entry( CoreInputDevice *device, int code, const DFBInputDeviceKeymapEntry *entry ) { InputDeviceKeymap *map; CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); shared = device->shared; map = &shared->keymap; /* Sanity check. */ if (code < map->min_keycode || code > map->max_keycode) return DFB_FAILURE; /* Copy the entry to the map. */ map->entries[code - map->min_keycode] = *entry; return DFB_OK; } static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername ) { int i; /* We want uppercase. */ for (i = 0; i < strlen( identifiername ); i++) if (identifiername[i] >= 'a' && identifiername[i] <= 'z') identifiername[i] = identifiername[i] - 'a' + 'A'; for (i = 0; i < D_ARRAY_SIZE(KeyIdentifierNames); i++) { if (strcmp( identifiername, KeyIdentifierNames[i].name ) == 0) return KeyIdentifierNames[i].identifier; } return DIKI_UNKNOWN; } static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname ) { int i; /* We want uppercase. */ for (i = 0; i < strlen( symbolname ); i++) if (symbolname[i] >= 'a' && symbolname[i] <= 'z') symbolname[i] = symbolname[i] - 'a' + 'A'; for (i = 0; i < D_ARRAY_SIZE(KeySymbolNames); i++) { if (strcmp( symbolname, KeySymbolNames[i].name ) == 0) return KeySymbolNames[i].symbol; } /* Not found, maybe starting with 0x for raw conversion. We are already at uppercase. */ if (symbolname[0] == '0' && symbolname[1] == 'X') { int code = 0; symbolname += 2; while (*symbolname) { if (*symbolname >= '0' && *symbolname <= '9') { code = code * 16 + *symbolname - '0'; } else if (*symbolname >= 'A' && *symbolname <= 'F') { code = code * 16 + *symbolname - 'A' + 10; } else { /* Invalid character. */ return DIKS_NULL; } symbolname++; } return code; } return DIKS_NULL; } /* * Replace the complete current keymap with a keymap from a file. */ static DFBResult load_keymap( CoreInputDevice *device, char *filename ) { DFBResult ret; DirectFile fd; InputDeviceKeymap *map; CoreInputDeviceShared *shared; DFBInputDeviceLockState lockstate = 0; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); shared = device->shared; map = &shared->keymap; /* Open the file. */ ret = direct_file_open( &fd, filename, O_RDONLY, 0 ); if (ret) return ret; /* Read the file, line by line, and consume the mentioned scancodes. */ while (1) { int i; int dummy; char buffer[201]; int keycode; char diki[201]; char diks[4][201]; DFBInputDeviceKeymapEntry entry = { .code = 0 }; ret = direct_file_get_string( &fd, buffer, 200 ); if (ret) { if (ret == DFB_EOF) { direct_file_close( &fd ); return DFB_OK; } direct_file_close( &fd ); return ret; } /* Comment or empty line. */ if (buffer[0] == '#' || strcmp( buffer, "\n" ) == 0) continue; /* Check for lock state change. */ if (!strncmp( buffer, "capslock:", 9)) { lockstate |= DILS_CAPS; continue; } if (!strncmp( buffer, ":capslock", 9)) { lockstate &= ~DILS_CAPS; continue; } if (!strncmp( buffer, "numlock:", 8)) { lockstate |= DILS_NUM; continue; } if (!strncmp( buffer, ":numlock", 8)) { lockstate &= ~DILS_NUM; continue; } i = sscanf( buffer, " keycode %i = %s = %s %s %s %s %i\n", &keycode, diki, diks[0], diks[1], diks[2], diks[3], &dummy ); if (i < 3 || i > 6) { /* We want 1 to 4 key symbols. */ D_INFO( "DirectFB/Input: skipped erroneous input line %s\n", buffer ); continue; } if (keycode > map->max_keycode || keycode < map->min_keycode) { D_INFO( "DirectFB/Input: skipped keycode %d out of range\n", keycode ); continue; } entry.code = keycode; entry.locks = lockstate; entry.identifier = lookup_keyidentifier( diki ); switch (i) { case 6: entry.symbols[3] = lookup_keysymbol( diks[3] ); case 5: entry.symbols[2] = lookup_keysymbol( diks[2] ); case 4: entry.symbols[1] = lookup_keysymbol( diks[1] ); case 3: entry.symbols[0] = lookup_keysymbol( diks[0] ); /* fall through */ } switch (i) { case 3: entry.symbols[1] = entry.symbols[0]; case 4: entry.symbols[2] = entry.symbols[0]; case 5: entry.symbols[3] = entry.symbols[1]; /* fall through */ } ret = CoreInputDevice_SetKeymapEntry( device, keycode, &entry ); if (ret) return ret; } } /* * Reload the keymap. */ static DFBResult reload_keymap( CoreInputDevice *device ) { int i; InputDeviceKeymap *map; CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); shared = device->shared; map = &shared->keymap; if (shared->device_info.desc.min_keycode < 0 || shared->device_info.desc.max_keycode < 0) return DFB_UNSUPPORTED; /* Write -1 indicating entry is not fetched yet from driver. */ for (i = 0; i < shared->keymap.num_entries; i++) map->entries[i].code = -1; /* Fetch the whole map. */ for (i = shared->keymap.min_keycode; i <= shared->keymap.max_keycode; i++) get_keymap_entry( device, i ); D_INFO( "DirectFB/Input: Reloaded keymap for '%s' [0x%02x]\n", shared->device_info.desc.name, shared->id ); return DFB_OK; } static bool lookup_from_table( CoreInputDevice *device, DFBInputEvent *event, DFBInputEventFlags lookup ) { DFBInputDeviceKeymapEntry *entry; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( event != NULL ); /* Fetch the entry from the keymap, possibly calling the driver. */ entry = get_keymap_entry( device, event->key_code ); if (!entry) return false; /* Lookup identifier. */ if (lookup & DIEF_KEYID) event->key_id = entry->identifier; /* Lookup symbol. */ if (lookup & DIEF_KEYSYMBOL) { DFBInputDeviceKeymapSymbolIndex index = (event->modifiers & DIMM_ALTGR) ? DIKSI_ALT : DIKSI_BASE; if (!(event->modifiers & DIMM_SHIFT) ^ !(entry->locks & event->locks)) index++; /* Don't modify modifiers. */ if (DFB_KEY_TYPE( entry->symbols[DIKSI_BASE] ) == DIKT_MODIFIER) event->key_symbol = entry->symbols[DIKSI_BASE]; else event->key_symbol = entry->symbols[index]; } return true; } static int find_key_code_by_id( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id ) { int i; InputDeviceKeymap *map; CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); shared = device->shared; map = &shared->keymap; for (i = 0; i < map->num_entries; i++) { DFBInputDeviceKeymapEntry *entry = &map->entries[i]; if (entry->identifier == id) return entry->code; } return -1; } static int find_key_code_by_symbol( CoreInputDevice *device, DFBInputDeviceKeySymbol symbol ) { int i; InputDeviceKeymap *map; CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); shared = device->shared; map = &shared->keymap; for (i = 0; i < map->num_entries; i++) { int n; DFBInputDeviceKeymapEntry *entry = &map->entries[i]; for (n = 0; n <= DIKSI_LAST; n++) if (entry->symbols[n] == symbol) return entry->code; } return -1; } #define FIXUP_KEY_FIELDS (DIEF_MODIFIERS | DIEF_LOCKS | DIEF_KEYCODE | DIEF_KEYID | DIEF_KEYSYMBOL) /* * Fill partially missing values for key_code, key_id and key_symbol by translating those that are set. * Fix modifiers/locks before if not set. * * There are five valid constellations that give reasonable values. * (not counting the constellation where everything is set) * * Device has no translation table * 1. key_id is set, key_symbol not * -> key_code defaults to -1, key_symbol from key_id (up-translation) * 2. key_symbol is set, key_id not * -> key_code defaults to -1, key_id from key_symbol (down-translation) * * Device has a translation table * 3. key_code is set * -> look up key_id and/or key_symbol (key_code being the index) * 4. key_id is set * -> look up key_code and possibly key_symbol (key_id being searched for) * 5. key_symbol is set * -> look up key_code and key_id (key_symbol being searched for) * * Fields remaining will be set to the default, e.g. key_code to -1. */ static void fixup_key_event( CoreInputDevice *device, DFBInputEvent *event ) { int i; DFBInputEventFlags valid = event->flags & FIXUP_KEY_FIELDS; DFBInputEventFlags missing = valid ^ FIXUP_KEY_FIELDS; CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); shared = device->shared; /* Add missing flags. */ event->flags |= missing; /* Use cached values for modifiers/locks if they are missing. */ if (missing & DIEF_MODIFIERS) event->modifiers = shared->state.modifiers_l | shared->state.modifiers_r; if (missing & DIEF_LOCKS) event->locks = shared->state.locks; /* With translation table. */ if (shared->keymap.num_entries) { if (valid & DIEF_KEYCODE) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYID | DIEF_KEYSYMBOL); } else if (valid & DIEF_KEYID) { event->key_code = find_key_code_by_id( device, event->key_id ); if (event->key_code != -1) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYCODE | DIEF_KEYSYMBOL); } else if (missing & DIEF_KEYSYMBOL) { event->key_symbol = id_to_symbol( event->key_id, event->modifiers, event->locks ); missing &= ~DIEF_KEYSYMBOL; } } else if (valid & DIEF_KEYSYMBOL) { event->key_code = find_key_code_by_symbol( device, event->key_symbol ); if (event->key_code != -1) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYCODE | DIEF_KEYID); } else { event->key_id = symbol_to_id( event->key_symbol ); missing &= ~DIEF_KEYSYMBOL; } } } /* Without translation table. */ else { if (valid & DIEF_KEYID) { if (missing & DIEF_KEYSYMBOL) { event->key_symbol = id_to_symbol( event->key_id, event->modifiers, event->locks ); missing &= ~DIEF_KEYSYMBOL; } } else if (valid & DIEF_KEYSYMBOL) { event->key_id = symbol_to_id( event->key_symbol ); missing &= ~DIEF_KEYID; } } /* Clear remaining fields. */ if (missing & DIEF_KEYCODE) event->key_code = -1; if (missing & DIEF_KEYID) event->key_id = DIKI_UNKNOWN; if (missing & DIEF_KEYSYMBOL) event->key_symbol = DIKS_NULL; /* Update cached values for modifiers. */ if (DFB_KEY_TYPE( event->key_symbol ) == DIKT_MODIFIER) { if (event->type == DIET_KEYPRESS) { switch (event->key_id) { case DIKI_SHIFT_L: shared->state.modifiers_l |= DIMM_SHIFT; break; case DIKI_SHIFT_R: shared->state.modifiers_r |= DIMM_SHIFT; break; case DIKI_CONTROL_L: shared->state.modifiers_l |= DIMM_CONTROL; break; case DIKI_CONTROL_R: shared->state.modifiers_r |= DIMM_CONTROL; break; case DIKI_ALT_L: shared->state.modifiers_l |= DIMM_ALT; break; case DIKI_ALT_R: shared->state.modifiers_r |= (event->key_symbol == DIKS_ALTGR) ? DIMM_ALTGR : DIMM_ALT; break; case DIKI_META_L: shared->state.modifiers_l |= DIMM_META; break; case DIKI_META_R: shared->state.modifiers_r |= DIMM_META; break; case DIKI_SUPER_L: shared->state.modifiers_l |= DIMM_SUPER; break; case DIKI_SUPER_R: shared->state.modifiers_r |= DIMM_SUPER; break; case DIKI_HYPER_L: shared->state.modifiers_l |= DIMM_HYPER; break; case DIKI_HYPER_R: shared->state.modifiers_r |= DIMM_HYPER; break; default: ; } } else { switch (event->key_id) { case DIKI_SHIFT_L: shared->state.modifiers_l &= ~DIMM_SHIFT; break; case DIKI_SHIFT_R: shared->state.modifiers_r &= ~DIMM_SHIFT; break; case DIKI_CONTROL_L: shared->state.modifiers_l &= ~DIMM_CONTROL; break; case DIKI_CONTROL_R: shared->state.modifiers_r &= ~DIMM_CONTROL; break; case DIKI_ALT_L: shared->state.modifiers_l &= ~DIMM_ALT; break; case DIKI_ALT_R: shared->state.modifiers_r &= (event->key_symbol == DIKS_ALTGR) ? ~DIMM_ALTGR : ~DIMM_ALT; break; case DIKI_META_L: shared->state.modifiers_l &= ~DIMM_META; break; case DIKI_META_R: shared->state.modifiers_r &= ~DIMM_META; break; case DIKI_SUPER_L: shared->state.modifiers_l &= ~DIMM_SUPER; break; case DIKI_SUPER_R: shared->state.modifiers_r &= ~DIMM_SUPER; break; case DIKI_HYPER_L: shared->state.modifiers_l &= ~DIMM_HYPER; break; case DIKI_HYPER_R: shared->state.modifiers_r &= ~DIMM_HYPER; break; default: ; } } /* Write back to event. */ if (missing & DIEF_MODIFIERS) event->modifiers = shared->state.modifiers_l | shared->state.modifiers_r; } /* * Update cached values for locks. */ if (event->type == DIET_KEYPRESS) { /* When we receive a new key press, toggle lock flags. */ if (shared->first_press || shared->last_key != event->key_id) { switch (event->key_id) { case DIKI_CAPS_LOCK: shared->state.locks ^= DILS_CAPS; break; case DIKI_NUM_LOCK: shared->state.locks ^= DILS_NUM; break; case DIKI_SCROLL_LOCK: shared->state.locks ^= DILS_SCROLL; break; default: ; } } /* Write back to event. */ if (missing & DIEF_LOCKS) event->locks = shared->state.locks; /* Store last pressed key. */ shared->last_key = event->key_id; shared->first_press = false; } else if (event->type == DIET_KEYRELEASE) { shared->first_press = true; } /* Handle dead keys. */ if (DFB_KEY_TYPE( shared->last_symbol ) == DIKT_DEAD) { for (i = 0; i < D_ARRAY_SIZE(deadkey_maps); i++) { const DeadKeyMap *map = &deadkey_maps[i]; if (map->deadkey == shared->last_symbol) { for (i = 0; map->combos[i].target; i++) { if (map->combos[i].target == event->key_symbol) { event->key_symbol = map->combos[i].result; break; } } break; } } if (event->type == DIET_KEYRELEASE && DFB_KEY_TYPE( event->key_symbol ) != DIKT_MODIFIER) shared->last_symbol = event->key_symbol; } else shared->last_symbol = event->key_symbol; } static void fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event ) { CoreInputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); shared = device->shared; if (event->flags & DIEF_BUTTONS) { shared->state.buttons = event->buttons; } else { switch (event->type) { case DIET_BUTTONPRESS: shared->state.buttons |= (1 << event->button); break; case DIET_BUTTONRELEASE: shared->state.buttons &= ~(1 << event->button); break; default: ; } /* Add missing flag. */ event->flags |= DIEF_BUTTONS; event->buttons = shared->state.buttons; } switch (event->type) { case DIET_AXISMOTION: if ((event->flags & DIEF_AXISABS) && event->axis >= 0 && event->axis < shared->axis_num) { if (!(event->flags & DIEF_MIN) && (shared->axis_info[event->axis].flags & IDAIF_ABS_MIN)) { event->min = shared->axis_info[event->axis].abs_min; event->flags |= DIEF_MIN; } if (!(event->flags & DIEF_MAX) && (shared->axis_info[event->axis].flags & IDAIF_ABS_MAX)) { event->max = shared->axis_info[event->axis].abs_max; event->flags |= DIEF_MAX; } } break; default: break; } } /**********************************************************************************************************************/ static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol symbol ) { if (symbol >= 'a' && symbol <= 'z') return DIKI_A + symbol - 'a'; if (symbol >= 'A' && symbol <= 'Z') return DIKI_A + symbol - 'A'; if (symbol >= '0' && symbol <= '9') return DIKI_0 + symbol - '0'; if (symbol >= DIKS_F1 && symbol <= DIKS_F12) return DIKI_F1 + symbol - DIKS_F1; switch (symbol) { case DIKS_ESCAPE: return DIKI_ESCAPE; case DIKS_CURSOR_LEFT: return DIKI_LEFT; case DIKS_CURSOR_RIGHT: return DIKI_RIGHT; case DIKS_CURSOR_UP: return DIKI_UP; case DIKS_CURSOR_DOWN: return DIKI_DOWN; case DIKS_ALTGR: return DIKI_ALT_R; case DIKS_CONTROL: return DIKI_CONTROL_L; case DIKS_SHIFT: return DIKI_SHIFT_L; case DIKS_ALT: return DIKI_ALT_L; case DIKS_META: return DIKI_META_L; case DIKS_SUPER: return DIKI_SUPER_L; case DIKS_HYPER: return DIKI_HYPER_L; case DIKS_TAB: return DIKI_TAB; case DIKS_ENTER: return DIKI_ENTER; case DIKS_SPACE: return DIKI_SPACE; case DIKS_BACKSPACE: return DIKI_BACKSPACE; case DIKS_INSERT: return DIKI_INSERT; case DIKS_DELETE: return DIKI_DELETE; case DIKS_HOME: return DIKI_HOME; case DIKS_END: return DIKI_END; case DIKS_PAGE_UP: return DIKI_PAGE_UP; case DIKS_PAGE_DOWN: return DIKI_PAGE_DOWN; case DIKS_CAPS_LOCK: return DIKI_CAPS_LOCK; case DIKS_NUM_LOCK: return DIKI_NUM_LOCK; case DIKS_SCROLL_LOCK: return DIKI_SCROLL_LOCK; case DIKS_PRINT: return DIKI_PRINT; case DIKS_PAUSE: return DIKI_PAUSE; case DIKS_BACKSLASH: return DIKI_BACKSLASH; case DIKS_PERIOD: return DIKI_PERIOD; case DIKS_COMMA: return DIKI_COMMA; default: ; } return DIKI_UNKNOWN; } static DFBInputDeviceKeySymbol id_to_symbol( DFBInputDeviceKeyIdentifier id, DFBInputDeviceModifierMask modifiers, DFBInputDeviceLockState locks ) { bool shift = !(modifiers & DIMM_SHIFT) ^ !(locks & DILS_CAPS); if (id >= DIKI_A && id <= DIKI_Z) return (shift ? DIKS_CAPITAL_A : DIKS_SMALL_A) + id - DIKI_A; if (id >= DIKI_0 && id <= DIKI_9) return DIKS_0 + id - DIKI_0; if (id >= DIKI_KP_0 && id <= DIKI_KP_9) return DIKS_0 + id - DIKI_KP_0; if (id >= DIKI_F1 && id <= DIKI_F12) return DIKS_F1 + id - DIKI_F1; switch (id) { case DIKI_ESCAPE: return DIKS_ESCAPE; case DIKI_LEFT: return DIKS_CURSOR_LEFT; case DIKI_RIGHT: return DIKS_CURSOR_RIGHT; case DIKI_UP: return DIKS_CURSOR_UP; case DIKI_DOWN: return DIKS_CURSOR_DOWN; case DIKI_CONTROL_L: case DIKI_CONTROL_R: return DIKS_CONTROL; case DIKI_SHIFT_L: case DIKI_SHIFT_R: return DIKS_SHIFT; case DIKI_ALT_L: case DIKI_ALT_R: return DIKS_ALT; case DIKI_META_L: case DIKI_META_R: return DIKS_META; case DIKI_SUPER_L: case DIKI_SUPER_R: return DIKS_SUPER; case DIKI_HYPER_L: case DIKI_HYPER_R: return DIKS_HYPER; case DIKI_TAB: return DIKS_TAB; case DIKI_ENTER: return DIKS_ENTER; case DIKI_SPACE: return DIKS_SPACE; case DIKI_BACKSPACE: return DIKS_BACKSPACE; case DIKI_INSERT: return DIKS_INSERT; case DIKI_DELETE: return DIKS_DELETE; case DIKI_HOME: return DIKS_HOME; case DIKI_END: return DIKS_END; case DIKI_PAGE_UP: return DIKS_PAGE_UP; case DIKI_PAGE_DOWN: return DIKS_PAGE_DOWN; case DIKI_CAPS_LOCK: return DIKS_CAPS_LOCK; case DIKI_NUM_LOCK: return DIKS_NUM_LOCK; case DIKI_SCROLL_LOCK: return DIKS_SCROLL_LOCK; case DIKI_PRINT: return DIKS_PRINT; case DIKI_PAUSE: return DIKS_PAUSE; case DIKI_KP_DIV: return DIKS_SLASH; case DIKI_KP_MULT: return DIKS_ASTERISK; case DIKI_KP_MINUS: return DIKS_MINUS_SIGN; case DIKI_KP_PLUS: return DIKS_PLUS_SIGN; case DIKI_KP_ENTER: return DIKS_ENTER; case DIKI_KP_SPACE: return DIKS_SPACE; case DIKI_KP_TAB: return DIKS_TAB; case DIKI_KP_EQUAL: return DIKS_EQUALS_SIGN; case DIKI_KP_DECIMAL: return DIKS_PERIOD; case DIKI_KP_SEPARATOR: return DIKS_COMMA; case DIKI_BACKSLASH: return DIKS_BACKSLASH; case DIKI_EQUALS_SIGN: return DIKS_EQUALS_SIGN; case DIKI_LESS_SIGN: return DIKS_LESS_THAN_SIGN; case DIKI_MINUS_SIGN: return DIKS_MINUS_SIGN; case DIKI_PERIOD: return DIKS_PERIOD; case DIKI_QUOTE_LEFT: case DIKI_QUOTE_RIGHT: return DIKS_QUOTATION; case DIKI_SEMICOLON: return DIKS_SEMICOLON; case DIKI_SLASH: return DIKS_SLASH; default: ; } return DIKS_NULL; } /**********************************************************************************************************************/ static void dump_primary_layer_surface( CoreDFB *core ) { CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); CoreLayerContext *context; /* Get the currently active context. */ if (dfb_layer_get_active_context( layer, &context ) == DFB_OK) { CoreLayerRegion *region; /* Get the first region. */ if (dfb_layer_context_get_primary_region( context, false, ®ion ) == DFB_OK) { CoreSurface *surface; /* Lock the region to avoid tearing due to concurrent updates. */ dfb_layer_region_lock( region ); /* Get the surface of the region. */ if (dfb_layer_region_get_surface( region, &surface ) == DFB_OK) { /* Dump the surface contents. */ dfb_surface_dump_buffer( surface, DSBR_FRONT, dfb_config->screenshot_dir, "dfb" ); /* Release the surface. */ dfb_surface_unref( surface ); } /* Unlock the region. */ dfb_layer_region_unlock( region ); /* Release the region. */ dfb_layer_region_unref( region ); } /* Release the context. */ dfb_layer_context_unref( context ); } } static bool core_input_filter( CoreInputDevice *device, DFBInputEvent *event ) { D_MAGIC_ASSERT( device, CoreInputDevice ); if (dfb_system_input_filter( device, event )) return true; if (event->type == DIET_KEYPRESS) { switch (event->key_symbol) { case DIKS_PRINT: if (!event->modifiers && dfb_config->screenshot_dir) { dump_primary_layer_surface( device->core ); return true; } break; case DIKS_BACKSPACE: if (event->modifiers == DIMM_META) direct_trace_print_stacks(); break; case DIKS_ESCAPE: if (event->modifiers == DIMM_META) { #if FUSION_BUILD_MULTI DFBResult ret; CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); CoreLayerContext *context; /* Get primary (shared) context. */ ret = dfb_layer_get_primary_context( layer, false, &context ); if (ret) return false; /* Activate the context. */ dfb_layer_activate_context( layer, context ); /* Release the context. */ dfb_layer_context_unref( context ); #else /* FUSION_BUILD_MULTI */ direct_kill( 0, SIGINT ); #endif /* FUSION_BUILD_MULTI */ return true; } break; default: break; } } return false; } ================================================ FILE: src/core/input.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__INPUT_H__ #define __CORE__INPUT_H__ #include #include #include #include #include DECLARE_MODULE_DIRECTORY( dfb_input_drivers ); /**********************************************************************************************************************/ #define DFB_INPUT_DRIVER_ABI_VERSION 7 #define DFB_INPUT_DRIVER_INFO_NAME_LENGTH 60 #define DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH 80 #define DFB_INPUT_DRIVER_INFO_URL_LENGTH 120 #define DFB_INPUT_DRIVER_INFO_LICENSE_LENGTH 40 typedef struct { int major; /* major version */ int minor; /* minor version */ } InputDriverVersion; typedef struct { InputDriverVersion version; char name[DFB_INPUT_DRIVER_INFO_NAME_LENGTH]; /* Name of input driver */ char vendor[DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH]; /* Vendor (or author) of the driver */ char url[DFB_INPUT_DRIVER_INFO_URL_LENGTH]; /* URL for driver updates */ char license[DFB_INPUT_DRIVER_INFO_LICENSE_LENGTH]; /* License, e.g. 'LGPL' or 'proprietary' */ } InputDriverInfo; typedef enum { IDC_NONE = 0x00000000, /* None. */ IDC_HOTPLUG = 0x00000001, /* Input devices support hot-plug. */ IDC_ALL = 0x00000001 /* All flags supported. */ } InputDriverCapability; typedef struct { unsigned int prefered_id; /* Prefered predefined input device id. */ DFBInputDeviceDescription desc; /* Capabilities, type, etc. */ } InputDeviceInfo; typedef enum { IDAIF_NONE = 0x00000000, /* None of these. */ IDAIF_ABS_MIN = 0x00000001, /* Minimum possible value. */ IDAIF_ABS_MAX = 0x00000002, /* Maximum possible value. */ IDAIF_ALL = 0x00000003 /* All of these. */ } InputDeviceAxisInfoFlags; typedef struct { InputDeviceAxisInfoFlags flags; int abs_min; int abs_max; } InputDeviceAxisInfo; typedef struct { int (*GetAvailable) ( void ); void (*GetDriverInfo) ( InputDriverInfo *driver_info ); DFBResult (*OpenDevice) ( CoreInputDevice *device, unsigned int number, InputDeviceInfo *device_info, void **driver_data ); DFBResult (*GetKeymapEntry) ( CoreInputDevice *device, void *driver_data, DFBInputDeviceKeymapEntry *entry ); void (*CloseDevice) ( void *driver_data ); DFBResult (*Suspend) ( void ); DFBResult (*Resume) ( void ); DFBResult (*IsCreated) ( int index, void *data ); InputDriverCapability (*GetCapability) ( void ); DFBResult (*LaunchHotplug) ( CoreDFB *core, void *input_driver ); DFBResult (*StopHotplug) ( void ); DFBResult (*GetAxisInfo) ( CoreInputDevice *device, void *driver_data, DFBInputDeviceAxisIdentifier axis, InputDeviceAxisInfo *ret_info ); DFBResult (*SetConfiguration)( CoreInputDevice *device, void *driver_data, const DFBInputDeviceConfig *config ); } InputDriverFuncs; typedef struct { int min_keycode; int max_keycode; int num_entries; DFBInputDeviceKeymapEntry *entries; } InputDeviceKeymap; typedef struct { DFBInputDeviceModifierMask modifiers_l; DFBInputDeviceModifierMask modifiers_r; DFBInputDeviceLockState locks; DFBInputDeviceButtonMask buttons; } InputDeviceState; typedef struct { int magic; DFBInputDeviceID id; /* unique device id */ int num; InputDeviceInfo device_info; InputDeviceKeymap keymap; InputDeviceState state; DFBInputDeviceKeyIdentifier last_key; /* last key pressed */ DFBInputDeviceKeySymbol last_symbol; /* last symbol pressed */ bool first_press; /* first press of key */ FusionReactor *reactor; /* event dispatcher */ FusionSkirmish lock; unsigned int axis_num; InputDeviceAxisInfo *axis_info; FusionRef ref; /* ref between shared device & local device */ FusionCall call; } CoreInputDeviceShared; typedef struct { DirectLink link; int magic; DirectModuleEntry *module; const InputDriverFuncs *funcs; InputDriverInfo info; int nr_devices; } CoreInputDriver; struct __DFB_CoreInputDevice { DirectLink link; int magic; CoreInputDeviceShared *shared; CoreInputDriver *driver; void *driver_data; CoreDFB *core; }; /**********************************************************************************************************************/ typedef DFBEnumerationResult (*InputDeviceCallback)( CoreInputDevice *device, void *ctx ); /**********************************************************************************************************************/ DFBResult dfb_input_add_global ( ReactionFunc func, int *ret_index ); DFBResult dfb_input_set_global ( ReactionFunc func, int index ); void dfb_input_enumerate_devices ( InputDeviceCallback callback, void *ctx, DFBInputDeviceCapabilities caps ); DirectResult dfb_input_attach ( CoreInputDevice *device, ReactionFunc func, void *ctx, Reaction *reaction ); DirectResult dfb_input_detach ( CoreInputDevice *device, Reaction *reaction ); DirectResult dfb_input_attach_global ( CoreInputDevice *device, int index, void *ctx, GlobalReaction *reaction ); DirectResult dfb_input_detach_global ( CoreInputDevice *device, GlobalReaction *reaction ); void dfb_input_dispatch ( CoreInputDevice *device, DFBInputEvent *event ); DFBInputDeviceID dfb_input_device_id ( const CoreInputDevice *device ); CoreInputDevice *dfb_input_device_at ( DFBInputDeviceID id ); DFBInputDeviceCapabilities dfb_input_device_caps ( const CoreInputDevice *device ); void dfb_input_device_description ( const CoreInputDevice *device, DFBInputDeviceDescription *desc ); DFBResult dfb_input_device_get_keymap_entry ( CoreInputDevice *device, int keycode, DFBInputDeviceKeymapEntry *entry ); DFBResult dfb_input_device_set_keymap_entry ( CoreInputDevice *device, int keycode, const DFBInputDeviceKeymapEntry *entry ); DFBResult dfb_input_device_load_keymap ( CoreInputDevice *device, char *filename ); DFBResult dfb_input_device_reload_keymap ( CoreInputDevice *device ); DFBResult dfb_input_device_get_state ( CoreInputDevice *device, InputDeviceState *ret_state ); DFBResult dfb_input_device_set_configuration ( CoreInputDevice *device, const DFBInputDeviceConfig *config ); void eventbuffer_containers_attach_device( CoreInputDevice *device ); void eventbuffer_containers_detach_device( CoreInputDevice *device ); void stack_containers_attach_device ( CoreInputDevice *device ); void stack_containers_detach_device ( CoreInputDevice *device ); /* * Create the DFB shared core input device, add the input device into the local device list and shared dev array, and * broadcast the hot-plug in message to all slaves. */ DFBResult dfb_input_create_device ( int device_index, CoreDFB *core_in, void *driver_in ); /* * Remove the DFB shared core input device handling of the system input device indicated by 'device_index' and broadcast * the hot-plug out message to all slaves. */ DFBResult dfb_input_remove_device ( int device_index, void *driver_in ); #endif ================================================ FILE: src/core/input_driver.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__INPUT_DRIVER_H__ #define __CORE__INPUT_DRIVER_H__ #include /**********************************************************************************************************************/ static int driver_get_available ( void ); static void driver_get_info ( InputDriverInfo *driver_info ); static DFBResult driver_open_device ( CoreInputDevice *device, unsigned int number, InputDeviceInfo *device_info, void **driver_data ); static DFBResult driver_get_keymap_entry ( CoreInputDevice *device, void *driver_data, DFBInputDeviceKeymapEntry *entry ); static void driver_close_device ( void *driver_data ); static DFBResult driver_suspend ( void ); static DFBResult driver_resume ( void ); static DFBResult is_created ( int index, void *driver_data ); static InputDriverCapability get_capability ( void ); static DFBResult launch_hotplug ( CoreDFB *core, void *input_driver ); static DFBResult stop_hotplug ( void ); #ifdef DFB_INPUTDRIVER_HAS_AXIS_INFO static DFBResult driver_get_axis_info ( CoreInputDevice *device, void *driver_data, DFBInputDeviceAxisIdentifier axis, InputDeviceAxisInfo *ret_info ); #endif #ifdef DFB_INPUTDRIVER_HAS_SET_CONFIGURATION static DFBResult driver_set_configuration( CoreInputDevice *device, void *driver_data, const DFBInputDeviceConfig *config ); #endif /* * Add hot-plug stub function implementations for all input drivers by default. */ #if !defined(DISABLE_INPUT_HOTPLUG_FUNCTION_STUB) static DFBResult driver_suspend() { return DFB_UNSUPPORTED; } static DFBResult driver_resume() { return DFB_UNSUPPORTED; } static DFBResult is_created( int index, void *driver_data ) { return DFB_UNSUPPORTED; } static InputDriverCapability get_capability() { return IDC_NONE; } static DFBResult launch_hotplug( CoreDFB *core, void *input_driver ) { return DFB_UNSUPPORTED; } static DFBResult stop_hotplug() { return DFB_UNSUPPORTED; } #endif static const InputDriverFuncs inputdriver_funcs = { .GetAvailable = driver_get_available, .GetDriverInfo = driver_get_info, .OpenDevice = driver_open_device, .GetKeymapEntry = driver_get_keymap_entry, .CloseDevice = driver_close_device, .Suspend = driver_suspend, .Resume = driver_resume, .IsCreated = is_created, .GetCapability = get_capability, .LaunchHotplug = launch_hotplug, .StopHotplug = stop_hotplug, #ifdef DFB_INPUTDRIVER_HAS_AXIS_INFO .GetAxisInfo = driver_get_axis_info, #endif #ifdef DFB_INPUTDRIVER_HAS_SET_CONFIGURATION .SetConfiguration = driver_set_configuration #endif }; #define DFB_INPUT_DRIVER(shortname) \ \ __dfb_constructor__ \ void \ directfb_##shortname##_ctor( void ) \ { \ direct_modules_register( &dfb_input_drivers, \ DFB_INPUT_DRIVER_ABI_VERSION, \ #shortname, \ &inputdriver_funcs ); \ } \ \ __dfb_destructor__ \ void \ directfb_##shortname##_dtor( void ) \ { \ direct_modules_unregister( &dfb_input_drivers, \ #shortname ); \ } #endif ================================================ FILE: src/core/layer_context.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_LayerContext, "Core/LayerContext", "DirectFB Core Display Layer Context" ); /**********************************************************************************************************************/ static void context_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreLayerContext *context = (CoreLayerContext*) object; CoreLayer *layer; CoreLayerShared *shared; D_UNUSED_P( shared ); D_MAGIC_ASSERT( context, CoreLayerContext ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; D_DEBUG_AT( Core_LayerContext, "Destroying context %p (%s, %sactive%s)\n", context, shared->description.name, context->active ? "" : "in", zombie ? " ZOMBIE" : "" ); CoreLayerContext_Deinit_Dispatch( &context->call ); /* Remove the context from the layer's context stack. */ dfb_layer_remove_context( layer, context ); /* Detach input devices before taking the context lock to prevent a deadlock between windowstack destruction and input event processing. */ if (context->stack) dfb_windowstack_detach_devices( context->stack ); dfb_layer_context_lock( context ); if (context->cursor.surface) dfb_surface_unlink( &context->cursor.surface ); /* Destroy the window stack. */ if (context->stack) { dfb_windowstack_destroy( context->stack ); context->stack = NULL; } /* Destroy the region vector. */ fusion_vector_destroy( &context->regions ); /* Deinitialize the lock. */ fusion_skirmish_destroy( &context->lock ); /* Free clip regions. */ if (context->primary.config.clips) SHFREE( context->shmpool, context->primary.config.clips ); D_MAGIC_CLEAR( context ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_layer_context_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Layer Context Pool", sizeof(CoreLayerContext), sizeof(CoreLayerContextNotification), context_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ static void screen_rectangle( CoreLayerContext *context, const DFBLocation *location, DFBRectangle *rect ) { DFBResult ret; int width; int height; CoreLayer *layer; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, location, rect ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( location != NULL ); D_ASSERT( rect != NULL ); D_DEBUG_AT( Core_LayerContext, " <- %4.2f,%4.2f-%4.2f,%4.2f\n", location->x, location->y, location->w, location->h ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->screen != NULL ); ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height ); if (ret) { D_WARN( "could not determine mixer/screen dimension of layer %u", context->layer_id ); rect->x = location->x * 720; rect->y = location->y * 576; rect->w = location->w * 720; rect->h = location->h * 576; } else { rect->x = location->x * width; rect->y = location->y * height; rect->w = location->w * width; rect->h = location->h * height; } D_DEBUG_AT( Core_LayerContext, " -> %4d,%4d-%4d,%4d\n", DFB_RECTANGLE_VALS( rect ) ); } static void init_region_config( CoreLayerContext *context, CoreLayerRegionConfig *config ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( config != NULL ); memset( config, 0, sizeof(CoreLayerRegionConfig) ); /* Initialize values from layer config. */ config->width = context->config.width; config->height = context->config.height; config->format = context->config.pixelformat; config->colorspace = context->config.colorspace; config->buffermode = context->config.buffermode; config->options = context->config.options; config->source_id = context->config.source; config->surface_caps = context->config.surface_caps; /* Initialize source rectangle. */ config->source.x = 0; config->source.y = 0; config->source.w = config->width; config->source.h = config->height; /* Initialize screen rectangle. */ screen_rectangle( context, &context->screen.location, &config->dest ); /* Set default opacity. */ config->opacity = 0xff; /* Set default alpha ramp. */ config->alpha_ramp[0] = 0x00; config->alpha_ramp[1] = 0x55; config->alpha_ramp[2] = 0xaa; config->alpha_ramp[3] = 0xff; } static void update_stack_geometry( CoreLayerContext *context ) { DFBDimension size; int rotation; CoreLayerRegion *region; CoreSurface *surface; D_MAGIC_ASSERT( context, CoreLayerContext ); rotation = context->rotation; switch (rotation) { default: D_BUG( "invalid rotation %d", rotation ); case 0: case 180: size.w = context->config.width; size.h = context->config.height; break; case 90: case 270: size.w = context->config.height; size.h = context->config.width; break; } region = context->primary.region; if (region) { surface = region->surface; if (surface) { D_MAGIC_ASSERT( surface, CoreSurface ); rotation -= surface->rotation; if (rotation < 0) rotation += 360; } } if (context->stack) dfb_windowstack_resize( context->stack, size.w, size.h, rotation ); } DFBResult dfb_layer_context_init( CoreLayerContext *context, CoreLayer *layer, bool stack ) { CoreLayerShared *shared; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, layer ); D_ASSERT( context != NULL ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; D_DEBUG_AT( Core_LayerContext, " -> %s", shared->description.name ); context->shmpool = shared->shmpool; /* Initialize the lock. */ if (fusion_skirmish_init2( &context->lock, "Layer Context", dfb_core_world( layer->core ), fusion_config->secure_fusion )) { fusion_object_destroy( &context->object ); return DFB_FUSION; } /* Initialize the region vector. */ fusion_vector_init( &context->regions, 4, context->shmpool ); /* Store layer ID, default configuration and default color adjustment. */ context->layer_id = shared->layer_id; context->config = shared->default_config; context->adjustment = shared->default_adjustment; /* Get the layer rotation. */ if (dfb_config->layers[dfb_layer_id_translated( layer )].rotate_set) context->rotation = dfb_config->layers[dfb_layer_id_translated( layer )].rotate; else dfb_screen_get_rotation( layer->screen, &context->rotation ); /* Initialize screen location. */ context->screen.location.x = 0.0f; context->screen.location.y = 0.0f; context->screen.location.w = 1.0f; context->screen.location.h = 1.0f; if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_LOCATION )) context->screen.mode = CLLM_LOCATION; else if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_POSITION )) context->screen.mode = CLLM_CENTER; /* Change global reaction lock. */ fusion_object_set_lock( &context->object, &context->lock ); D_MAGIC_SET( context, CoreLayerContext ); /* Initialize the primary region's configuration. */ init_region_config( context, &context->primary.config ); /* Activate the object. */ fusion_object_activate( &context->object ); dfb_layer_context_lock( context ); /* Create the window stack. */ if (stack && shared->description.caps & DLCAPS_SURFACE) { context->stack = dfb_windowstack_create( context ); if (!context->stack) { dfb_layer_context_unlock( context ); dfb_layer_context_unref( context ); return D_OOSHM(); } } /* Tell the window stack about its size. */ update_stack_geometry( context ); CoreLayerContext_Init_Dispatch( layer->core, context, &context->call ); dfb_layer_context_unlock( context ); return DFB_OK; } DirectResult dfb_layer_context_lock( CoreLayerContext *context ) { DFBResult ret; D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); ret = fusion_skirmish_prevail( &context->lock ); if (ret == DFB_OK) { int locked; ret = fusion_skirmish_lock_count( &context->lock, &locked ); if (ret == DFB_OK) D_DEBUG_AT( Core_LayerContext, " -> locked %dx now\n", locked ); } return ret; } DirectResult dfb_layer_context_unlock( CoreLayerContext *context ) { D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); return fusion_skirmish_dismiss( &context->lock ); } bool dfb_layer_context_active( const CoreLayerContext *context ) { D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); return context->active; } DFBResult dfb_layer_context_activate( CoreLayerContext *context ) { DFBResult ret; int index; CoreLayer *layer; CoreLayerShared *shared; CoreLayerRegion *region; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); shared = layer->shared; funcs = layer->funcs; /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; D_ASSUME( !context->active ); if (context->active) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Iterate through all regions. */ fusion_vector_foreach (region, index, context->regions) { /* First reallocate. */ if (region->surface && region->surface->num_buffers == 0) { ret = dfb_layer_context_reallocate_surface( layer, context, region, ®ion->config ); if (ret) D_DERROR( ret, "Core/LayerContext: Reallocation of layer surface failed!\n" ); } /* Then activate each region. */ if (dfb_layer_region_activate( region )) D_WARN( "could not activate region" ); } context->active = true; /* Remember new primary pixel format. */ shared->pixelformat = context->primary.config.format; /* Set new adjustment. */ if (funcs->SetColorAdjustment) funcs->SetColorAdjustment( layer, layer->driver_data, layer->layer_data, &context->adjustment ); /* Resume window stack. */ if (context->stack) { CoreWindowStack *stack = context->stack; D_MAGIC_ASSERT( stack, CoreWindowStack ); if (stack->flags & CWSF_INITIALIZED) dfb_wm_set_active( stack, true ); } /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_deactivate( CoreLayerContext *context ) { int index; CoreLayerRegion *region; D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; D_ASSUME( context->active ); if (!context->active) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Iterate through all regions. */ fusion_vector_foreach (region, index, context->regions) { /* Deactivate each region. */ dfb_layer_region_deactivate( region ); } context->active = false; /* Suspend window stack. */ if (context->stack) { CoreWindowStack *stack = context->stack; D_MAGIC_ASSERT( stack, CoreWindowStack ); if (stack->flags & CWSF_ACTIVATED) dfb_wm_set_active( stack, false ); } /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_add_region( CoreLayerContext *context, CoreLayerRegion *region ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, region ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( region != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; D_ASSUME( !fusion_vector_contains( &context->regions, region ) ); if (fusion_vector_contains( &context->regions, region )) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Add region to vector. */ if (fusion_vector_add( &context->regions, region )) { dfb_layer_context_unlock( context ); return DFB_FUSION; } /* Inherit state from context. */ if (context->active) region->state |= CLRSF_ACTIVE; /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_remove_region( CoreLayerContext *context, CoreLayerRegion *region ) { int index; D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( region != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; D_ASSUME( fusion_vector_contains( &context->regions, region ) ); /* Lookup region. */ index = fusion_vector_index_of( &context->regions, region ); if (index < 0) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Remove region from vector. */ fusion_vector_remove( &context->regions, index ); /* Check if the primary region is removed. */ if (region == context->primary.region) context->primary.region = NULL; /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_get_primary_region( CoreLayerContext *context, bool create, CoreLayerRegion **ret_region ) { DFBResult ret; D_DEBUG_AT( Core_LayerContext, "%s( %p, %screate )\n", __FUNCTION__, context, create ? "" : "don't " ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( ret_region != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; restart: while (context->primary.region) { /* Make sure the primary region's reference count is non-zero. If it is, a failure is returned to indicate that it is unavailable. In this scenario, this prevents the object_reference_watcher() from being called more than once triggered by the reference count changing from 1 to 0 again. */ int num = 0; if (dfb_layer_region_ref_stat( context->primary.region, &num ) || num == 0) { dfb_layer_context_unlock( context ); return DFB_TEMPUNAVAIL; } /* Increase the primary region's reference counter. */ ret = dfb_layer_region_ref( context->primary.region ); if (ret == DFB_OK) break; dfb_layer_context_unlock( context ); if (ret == DFB_LOCKED) { /* If the primary region is Fusion zero-locked (being destroyed) and creating a new primary region is not requested, return an error immediately. */ if (!create) return DFB_TEMPUNAVAIL; direct_thread_sleep( 10000 ); if (dfb_layer_context_lock( context )) return DFB_FUSION; } else return DFB_FUSION; } if (!context->primary.region) { if (create) { CoreLayerRegion *region; /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Create the primary region. */ ret = dfb_layer_region_create( context, ®ion ); if (ret) { D_ERROR( "Core/LayerContext: Could not create primary region!\n" ); return ret; } /* Lock the context again. */ if (dfb_layer_context_lock( context )) { dfb_layer_region_unref( region ); return DFB_FUSION; } /* Check for race. */ if (context->primary.region) { dfb_layer_region_unref( region ); goto restart; } /* Set the region configuration. */ ret = dfb_layer_region_set_configuration( region, &context->primary.config, CLRCF_ALL ); if (ret) { D_DERROR( ret, "Core/LayerContext: Could not set primary region config!\n" ); dfb_layer_region_unref( region ); dfb_layer_context_unlock( context ); return ret; } /* Remember the primary region. */ context->primary.region = region; /* Allocate surface, enable region etc. */ ret = dfb_layer_context_set_configuration( context, &context->config ); if (ret) { D_DERROR( ret, "Core/LayerContext: Could not set layer context config!\n" ); context->primary.region = NULL; dfb_layer_region_unref( region ); dfb_layer_context_unlock( context ); return ret; } } else { dfb_layer_context_unlock( context ); return DFB_TEMPUNAVAIL; } } /* Return region. */ *ret_region = context->primary.region; /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } /**********************************************************************************************************************/ static void build_updated_config( CoreLayer *layer, CoreLayerContext *context, const DFBDisplayLayerConfig *update, CoreLayerRegionConfig *ret_config, CoreLayerRegionConfigFlags *ret_flags ) { CoreLayerRegionConfigFlags flags = CLRCF_NONE; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p, %p )\n", __FUNCTION__, layer, context, update, ret_config, ret_flags ); D_ASSERT( layer != NULL ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( update != NULL ); D_ASSERT( ret_config != NULL ); /* Get the current region configuration. */ *ret_config = context->primary.config; /* Change width. */ if (update->flags & DLCONF_WIDTH) { flags |= CLRCF_WIDTH; ret_config->width = update->width; } /* Change height. */ if (update->flags & DLCONF_HEIGHT) { flags |= CLRCF_HEIGHT; ret_config->height = update->height; } /* Update source and destination rectangle. */ if (update->flags & (DLCONF_WIDTH | DLCONF_HEIGHT)) { int width, height; DFBResult ret; flags |= CLRCF_SOURCE | CLRCF_DEST; ret_config->source.x = 0; ret_config->source.y = 0; ret_config->source.w = ret_config->width; ret_config->source.h = ret_config->height; switch (context->screen.mode) { case CLLM_CENTER: ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height ); if (ret == DFB_OK) { ret_config->dest.x = (width - ret_config->width) / 2; ret_config->dest.y = (height - ret_config->height) / 2; } /* fall through */ case CLLM_POSITION: ret_config->dest.w = ret_config->width; ret_config->dest.h = ret_config->height; break; case CLLM_LOCATION: case CLLM_RECTANGLE: { CoreLayerShared *shared; D_ASSERT( layer->shared != NULL ); shared = layer->shared; /* If the display layer does not support scaling and the destination rectangle size is not the same as the source rectangle, change it to match. The origin is left alone to allow the driver to handle it. */ if (!D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_SIZE ) && (ret_config->dest.w != ret_config->source.w || ret_config->dest.h != ret_config->source.h)) { ret_config->dest.w = ret_config->width; ret_config->dest.h = ret_config->height; } break; } default: D_ERROR( "Core/LayerContext: Invalid layout mode!\n" ); } } /* Change pixel format. */ if (update->flags & DLCONF_PIXELFORMAT) { flags |= CLRCF_FORMAT; ret_config->format = update->pixelformat; flags |= CLRCF_COLORSPACE; ret_config->colorspace = DFB_COLORSPACE_DEFAULT( ret_config->format ); } /* Change color space. */ if (update->flags & DLCONF_COLORSPACE) { flags |= CLRCF_COLORSPACE; ret_config->colorspace = DFB_COLORSPACE_IS_COMPATIBLE( update->colorspace, ret_config->format ) ? update->colorspace : DFB_COLORSPACE_DEFAULT( ret_config->format ); } /* Change buffer mode. */ if (update->flags & DLCONF_BUFFERMODE) { flags |= CLRCF_BUFFERMODE; ret_config->buffermode = update->buffermode; } /* Change options. */ if (update->flags & DLCONF_OPTIONS) { flags |= CLRCF_OPTIONS; ret_config->options = update->options; } /* Change source id. */ if (update->flags & DLCONF_SOURCE) { flags |= CLRCF_SOURCE_ID; ret_config->source_id = update->source; } /* Change surface caps. */ if (update->flags & DLCONF_SURFACE_CAPS) { flags |= CLRCF_SURFACE_CAPS; ret_config->surface_caps = update->surface_caps; } /* Return translated flags. */ if (ret_flags) *ret_flags = flags; } DFBResult dfb_layer_context_test_configuration( CoreLayerContext *context, const DFBDisplayLayerConfig *config, DFBDisplayLayerConfigFlags *ret_failed ) { DFBResult ret = DFB_OK; CoreLayer *layer; CoreLayerShared *shared; CoreLayerRegionConfig region_config; CoreLayerRegionConfigFlags failed; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, config, ret_failed ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( config != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->TestRegion != NULL ); shared = layer->shared; funcs = layer->funcs; /* Build a new region configuration with the changes. */ build_updated_config( layer, context, config, ®ion_config, NULL ); /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Test the region configuration. */ if (region_config.buffermode == DLBM_WINDOWS) { if (!D_FLAGS_IS_SET( shared->description.caps, DLCAPS_WINDOWS )) { failed = CLRCF_BUFFERMODE; ret = DFB_UNSUPPORTED; } } else { /* Let the driver examine the modified configuration. */ ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, ®ion_config, &failed ); } /* Return flags for failing entries. */ if (ret_failed) { DFBDisplayLayerConfigFlags flags = DLCONF_NONE; /* Translate flags. */ if (ret) { if (failed & CLRCF_WIDTH) flags |= DLCONF_WIDTH; if (failed & CLRCF_HEIGHT) flags |= DLCONF_HEIGHT; if (failed & CLRCF_FORMAT) flags |= DLCONF_PIXELFORMAT; if (failed & CLRCF_BUFFERMODE) flags |= DLCONF_BUFFERMODE; if (failed & CLRCF_OPTIONS) flags |= DLCONF_OPTIONS; if (failed & CLRCF_SOURCE_ID) flags |= DLCONF_SOURCE; if (failed & CLRCF_SURFACE_CAPS) flags |= DLCONF_SURFACE_CAPS; } *ret_failed = flags; } return ret; } DFBResult dfb_layer_context_set_configuration( CoreLayerContext *context, const DFBDisplayLayerConfig *config ) { int i; DFBResult ret; CoreLayer *layer; CoreLayerShared *shared; CoreLayerRegionConfig region_config; CoreLayerRegionConfigFlags flags; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( config != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->TestRegion != NULL ); shared = layer->shared; funcs = layer->funcs; /* Build a new region configuration with the changes. */ build_updated_config( layer, context, config, ®ion_config, &flags ); /* Test the region configuration first. */ if (region_config.buffermode == DLBM_WINDOWS) { if (!D_FLAGS_IS_SET( shared->description.caps, DLCAPS_WINDOWS )) { dfb_layer_context_unlock( context ); return DFB_UNSUPPORTED; } } else { ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, ®ion_config, NULL ); if (ret) { dfb_layer_context_unlock( context ); return ret; } } /* Set the region configuration. */ if (context->primary.region) { CoreLayerRegion *region = context->primary.region; /* Add local reference. */ if (dfb_layer_region_ref( region )) { dfb_layer_context_unlock( context ); return DFB_FUSION; } /* Lock the region. */ if (dfb_layer_region_lock( region )) { dfb_layer_region_unref( region ); dfb_layer_context_unlock( context ); return DFB_FUSION; } /* Normal buffer mode. */ if (region_config.buffermode != DLBM_WINDOWS) { bool surface = shared->description.caps & DLCAPS_SURFACE; CoreLayerRegionStateFlags configured = region->state & CLRSF_CONFIGURED; if (shared->description.caps & DLCAPS_SOURCES) { for (i = 0; i < shared->description.sources; i++) { if (shared->sources[i].description.source_id == region_config.source_id) break; } D_ASSERT( i < shared->description.sources ); surface = shared->sources[i].description.caps & DDLSCAPS_SURFACE; } D_FLAGS_CLEAR( region->state, CLRSF_CONFIGURED ); /* (Re)allocate the region's surface. */ if (surface) { flags |= CLRCF_SURFACE | CLRCF_PALETTE; if (region->surface) { ret = dfb_layer_context_reallocate_surface( layer, context, region, ®ion_config ); if (ret) D_DERROR( ret, "Core/LayerContext: Reallocation of layer surface failed!\n" ); } else { ret = dfb_layer_context_allocate_surface( layer, context, region, ®ion_config ); if (ret) D_DERROR( ret, "Core/LayerContext: Allocation of layer surface failed!\n" ); } if (ret) { dfb_layer_region_unlock( region ); dfb_layer_region_unref( region ); dfb_layer_context_unlock( context ); return ret; } } else if (region->surface) dfb_layer_context_deallocate_surface( layer, context, region ); region->state |= configured; /* Set the new region configuration. */ dfb_layer_region_set_configuration( region, ®ion_config, flags | CLRCF_FREEZE ); /* Enable the primary region. */ if (!D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) dfb_layer_region_enable( region ); } else { /* Disable and deallocate the primary region. */ if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { dfb_layer_region_disable( region ); if (region->surface) dfb_layer_context_deallocate_surface( layer, context, region ); } } /* Unlock the region and give up the local reference. */ dfb_layer_region_unlock( region ); dfb_layer_region_unref( region ); } /* Remember new region config. */ context->primary.config = region_config; /* Remember new primary pixel format. */ shared->pixelformat = region_config.format; /* Write back modified entries. */ if (config->flags & DLCONF_WIDTH) context->config.width = config->width; if (config->flags & DLCONF_HEIGHT) context->config.height = config->height; if (config->flags & DLCONF_PIXELFORMAT) context->config.pixelformat = config->pixelformat; if (config->flags & DLCONF_COLORSPACE) context->config.colorspace = config->colorspace; if (config->flags & DLCONF_BUFFERMODE) context->config.buffermode = config->buffermode; if (config->flags & DLCONF_OPTIONS) context->config.options = config->options; if (config->flags & DLCONF_SOURCE) context->config.source = config->source; if (config->flags & DLCONF_SURFACE_CAPS) context->config.surface_caps = config->surface_caps; /* Update the window stack. */ if (context->stack) { CoreWindowStack *stack = context->stack; /* Update hardware flag. */ stack->hw_mode = (region_config.buffermode == DLBM_WINDOWS); /* Tell the windowing core about the new size. */ if (config->flags & (DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_SURFACE_CAPS)) { update_stack_geometry( context ); /* Fixed window stack repainting to not be performed when the region is frozen, because a frozen display layer should not be allocated and made visible until absolutely necessary. This prevents a display layer surface flip from being done and showing an uninitialized buffer. */ if (context->primary.region && !D_FLAGS_IS_SET( context->primary.region->state, CLRSF_FROZEN )) { dfb_windowstack_repaint_all( stack ); } } } /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_get_configuration( CoreLayerContext *context, DFBDisplayLayerConfig *ret_config ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, ret_config ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( ret_config != NULL ); *ret_config = context->config; return DFB_OK; } /**********************************************************************************************************************/ static DFBResult update_primary_region_config( CoreLayerContext *context, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags flags ) { DFBResult ret; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, context, config, flags ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( config != NULL ); if (context->primary.region) { if (flags != CLRCF_DEST) flags |= CLRCF_FREEZE; /* Set the new configuration. */ ret = dfb_layer_region_set_configuration( context->primary.region, config, flags ); } else { CoreLayer *layer = dfb_layer_at( context->layer_id ); const DisplayLayerFuncs *funcs; D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->TestRegion != NULL ); funcs = layer->funcs; /* Just test the new configuration. */ ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, config, NULL ); } if (ret) return ret; /* Remember the configuration. */ context->primary.config = *config; return DFB_OK; } DFBResult dfb_layer_context_set_src_colorkey( CoreLayerContext *context, u8 r, u8 g, u8 b, int index ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Take the current configuration. */ config = context->primary.config; /* Change the color key. */ config.src_key.r = r; config.src_key.g = g; config.src_key.b = b; if (index >= 0) config.src_key.index = index & 0xff; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_SRCKEY ); /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_dst_colorkey( CoreLayerContext *context, u8 r, u8 g, u8 b, int index ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Take the current configuration. */ config = context->primary.config; /* Change the color key. */ config.dst_key.r = r; config.dst_key.g = g; config.dst_key.b = b; if (index >= 0) config.dst_key.index = index & 0xff; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_DSTKEY ); /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_sourcerectangle( CoreLayerContext *context, const DFBRectangle *source ) { DFBResult ret; CoreLayer *layer; CoreLayerShared *shared; CoreLayerRegionConfig config; CoreLayerRegionConfigFlags flags; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, source ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( source != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Take the current configuration. */ config = context->primary.config; /* Do nothing if the source rectangle didn't change. */ if (DFB_RECTANGLE_EQUAL( config.source, *source )) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Check if the new source rectangle is valid. */ if (source->x < 0 || source->y < 0 || source->x + source->w > config.width || source->y + source->h > config.height) { dfb_layer_context_unlock( context ); return DFB_INVAREA; } /* Change the source rectangle. */ config.source = *source; flags = CLRCF_SOURCE; layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; /* If the display layer does not support scaling and the destination rectangle size is not the same as the source, change it to match. The origin is left alone to allow the driver to handle it. */ if (!D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_SIZE ) && (config.dest.w != config.source.w || config.dest.h != config.source.h)) { config.dest.w = config.source.w; config.dest.h = config.source.h; flags |= CLRCF_DEST; } /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, flags ); /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_screenlocation( CoreLayerContext *context, const DFBLocation *location ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, location ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( location != NULL ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Take the current configuration. */ config = context->primary.config; /* Calculate new absolute screen coordinates. */ screen_rectangle( context, location, &config.dest ); /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_DEST ); if (ret == DFB_OK) { context->screen.location = *location; context->screen.rectangle = config.dest; context->screen.mode = CLLM_LOCATION; } /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_screenrectangle( CoreLayerContext *context, const DFBRectangle *rect ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, rect ); D_MAGIC_ASSERT( context, CoreLayerContext ); DFB_RECTANGLE_ASSERT( rect ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Take the current configuration. */ config = context->primary.config; /* Use supplied absolute screen coordinates. */ config.dest = *rect; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_DEST ); if (ret == DFB_OK) { context->screen.rectangle = config.dest; context->screen.mode = CLLM_RECTANGLE; } /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_screenposition( CoreLayerContext *context, int x, int y ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %4d,%4d )\n", __FUNCTION__, context, x, y ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Do nothing if the location didn't change. */ if (context->primary.config.dest.x == x && context->primary.config.dest.y == y) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Take the current configuration. */ config = context->primary.config; /* Set new absolute screen coordinates. */ config.dest.x = x; config.dest.y = y; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_DEST ); if (ret == DFB_OK) { context->screen.rectangle = config.dest; context->screen.mode = CLLM_POSITION; } /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_opacity( CoreLayerContext *context, u8 opacity ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, opacity ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Do nothing if the opacity didn't change. */ if (context->primary.config.opacity == opacity) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Take the current configuration. */ config = context->primary.config; /* Change the opacity. */ config.opacity = opacity; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_OPACITY ); if (ret == DFB_OK) context->primary.config.opacity = opacity; /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_rotation( CoreLayerContext *context, int rotation ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, rotation ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Do nothing if the rotation didn't change. */ if (context->rotation != rotation) { context->rotation = rotation; update_stack_geometry( context ); if (context->stack) dfb_windowstack_repaint_all( context->stack ); } /* Unlock the context. */ dfb_layer_context_unlock( context ); return DFB_OK; } DFBResult dfb_layer_context_set_coloradjustment( CoreLayerContext *context, const DFBColorAdjustment *adjustment ) { DFBResult ret; DFBColorAdjustment adj; CoreLayer *layer; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, adjustment ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( adjustment != NULL ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; adj = context->adjustment; if (!funcs->SetColorAdjustment) return DFB_UNSUPPORTED; /* If flags are set that are not in the default adjustment. */ if (adjustment->flags & ~context->adjustment.flags) return DFB_UNSUPPORTED; /* Take over changed values. */ if (adjustment->flags & DCAF_BRIGHTNESS) adj.brightness = adjustment->brightness; if (adjustment->flags & DCAF_CONTRAST) adj.contrast = adjustment->contrast; if (adjustment->flags & DCAF_HUE) adj.hue = adjustment->hue; if (adjustment->flags & DCAF_SATURATION) adj.saturation = adjustment->saturation; /* Set new adjustment. */ ret = funcs->SetColorAdjustment( layer, layer->driver_data, layer->layer_data, &adj ); if (ret) return ret; /* Keep new adjustment. */ context->adjustment = adj; return DFB_OK; } DFBResult dfb_layer_context_get_coloradjustment( CoreLayerContext *context, DFBColorAdjustment *ret_adjustment ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, ret_adjustment ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( ret_adjustment != NULL ); *ret_adjustment = context->adjustment; return DFB_OK; } DFBResult dfb_layer_context_set_stereo_depth( CoreLayerContext *context, bool follow_video, int z ) { DFBResult ret; CoreLayer *layer; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %d, %d )\n", __FUNCTION__, context, follow_video, z ); D_MAGIC_ASSERT( context, CoreLayerContext ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; if (!funcs->SetStereoDepth) return DFB_UNSUPPORTED; /* Set new depth. */ ret = funcs->SetStereoDepth( layer, layer->driver_data, layer->layer_data, follow_video, z ); if (ret) return ret; /* Keep new depth. */ context->follow_video = follow_video; context->z = z; return DFB_OK; } DFBResult dfb_layer_context_get_stereo_depth( CoreLayerContext *context, bool *ret_follow_video, int *ret_z ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, ret_follow_video, ret_z ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( ret_follow_video != NULL ); D_ASSERT( ret_z != NULL ); *ret_follow_video = context->follow_video; *ret_z = context->z; return DFB_OK; } DFBResult dfb_layer_context_set_field_parity( CoreLayerContext *context, int field ) { DFBResult ret; CoreLayerRegionConfig config; D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, field ); D_MAGIC_ASSERT( context, CoreLayerContext ); /* Lock the context. */ if (dfb_layer_context_lock( context )) return DFB_FUSION; /* Do nothing if the parity didn't change. */ if (context->primary.config.parity == field) { dfb_layer_context_unlock( context ); return DFB_OK; } /* Take the current configuration. */ config = context->primary.config; /* Change the parity. */ config.parity = field; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_PARITY ); /* Unlock the context. */ dfb_layer_context_unlock( context ); return ret; } DFBResult dfb_layer_context_set_clip_regions( CoreLayerContext *context, const DFBRegion *regions, int num_regions, DFBBoolean positive ) { DFBResult ret; CoreLayerRegionConfig config; DFBRegion *clips; DFBRegion *old_clips; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p [%d], %s )\n", __FUNCTION__, context, regions, num_regions, positive ? "positive" : "negative" ); D_MAGIC_ASSERT( context, CoreLayerContext ); clips = SHMALLOC( context->shmpool, sizeof(DFBRegion) * num_regions ); if (!clips) return D_OOSHM(); direct_memcpy( clips, regions, sizeof(DFBRegion) * num_regions ); /* Lock the context. */ if (dfb_layer_context_lock( context )) { SHFREE( context->shmpool, clips ); return DFB_FUSION; } /* Take the current configuration. */ config = context->primary.config; /* Remember for freeing later on. */ old_clips = config.clips; /* Change the clip regions. */ config.clips = clips; config.num_clips = num_regions; config.positive = positive; /* Try to set the new configuration. */ ret = update_primary_region_config( context, &config, CLRCF_CLIPS ); /* Unlock the context. */ dfb_layer_context_unlock( context ); if (ret) SHFREE( context->shmpool, clips ); else if (old_clips) SHFREE( context->shmpool, old_clips ); return ret; } DFBResult dfb_layer_context_set_cursor_shape( CoreLayerContext *context, CoreSurface *shape, int hot_x, int hot_y ) { DFBResult ret; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %d, %d )\n", __FUNCTION__, context, shape, hot_x, hot_y ); D_MAGIC_ASSERT( context, CoreLayerContext ); context->cursor.hot_x = hot_x; context->cursor.hot_y = hot_y; if (context->cursor.surface) dfb_surface_unlink( &context->cursor.surface ); if (shape) { ret = dfb_surface_link( &context->cursor.surface, shape ); if (ret) return ret; } return DFB_OK; } DFBResult dfb_layer_context_get_cursor_shape( CoreLayerContext *context, CoreSurface **ret_shape, int *ret_hot_x, int *ret_hot_y ) { D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p )\n", __FUNCTION__, context, ret_shape, ret_hot_x, ret_hot_y ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( ret_shape != NULL ); D_ASSERT( ret_hot_x != NULL ); D_ASSERT( ret_hot_y != NULL ); *ret_shape = context->cursor.surface; *ret_hot_x = context->cursor.hot_x; *ret_hot_y = context->cursor.hot_y; return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_layer_context_create_window( CoreDFB *core, CoreLayerContext *context, const DFBWindowDescription *desc, CoreWindow **ret_window ) { DFBResult ret; CoreWindow *window; CoreWindowStack *stack; CoreLayer *layer; CoreLayerShared *shared; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p )\n", __FUNCTION__, core, context, desc, ret_window ); D_MAGIC_ASSERT( context, CoreLayerContext ); D_ASSERT( desc != NULL ); D_ASSERT( ret_window != NULL ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; if ((shared->description.caps & DLCAPS_SURFACE) == 0) { D_DEBUG_AT( Core_LayerContext, " -> no DLCAPS_SURFACE!\n" ); return DFB_UNSUPPORTED; } if (!context->stack) { D_DEBUG_AT( Core_LayerContext, " -> no stack!\n" ); return DFB_UNSUPPORTED; } if (dfb_layer_context_lock( context )) { D_DEBUG_AT( Core_LayerContext, " -> dfb_layer_context_lock() failed!\n" ); return DFB_FUSION; } stack = context->stack; if (!stack->cursor.set) { ret = dfb_windowstack_cursor_enable( stack, true ); if (ret) { D_DEBUG_AT( Core_LayerContext, " -> dfb_windowstack_cursor_enable() failed!\n" ); dfb_layer_context_unlock( context ); return ret; } } /* Create the window object. */ ret = dfb_window_create( stack, desc, &window ); if (ret) { D_DEBUG_AT( Core_LayerContext, " -> dfb_window_create() failed!\n" ); dfb_layer_context_unlock( context ); return ret; } /* Return the new window. */ *ret_window = window; dfb_layer_context_unlock( context ); return DFB_OK; } CoreWindow * dfb_layer_context_find_window( CoreLayerContext *context, DFBWindowID id ) { CoreWindowStack *stack; CoreWindow *window; CoreLayer *layer; CoreLayerShared *shared; D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, id ); D_MAGIC_ASSERT( context, CoreLayerContext ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; if ((shared->description.caps & DLCAPS_SURFACE) == 0) return NULL; D_ASSERT( context->stack != NULL ); stack = context->stack; if (dfb_layer_context_lock( context )) return NULL; if (dfb_wm_window_lookup( stack, id, &window ) || dfb_window_ref( window )) window = NULL; dfb_layer_context_unlock( context ); return window; } CoreWindowStack * dfb_layer_context_windowstack( const CoreLayerContext *context ) { D_MAGIC_ASSERT( context, CoreLayerContext ); return context->stack; } /**********************************************************************************************************************/ DFBResult dfb_layer_context_allocate_surface( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region, CoreLayerRegionConfig *config ) { DFBResult ret; CoreSurface *surface; CoreSurfaceTypeFlags type = CSTF_LAYER; CoreSurfaceConfig scon; CoreLayerShared *shared; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( region != NULL ); D_ASSERT( region->surface == NULL ); D_ASSERT( config != NULL ); D_ASSERT( config->buffermode != DLBM_WINDOWS ); D_MAGIC_ASSERT( context, CoreLayerContext ); shared = layer->shared; funcs = layer->funcs; /* Create a new surface for the region. */ if (funcs->AllocateSurface) { /* Let the driver create the surface. */ ret = funcs->AllocateSurface( layer, layer->driver_data, layer->layer_data, region->region_data, config, &surface ); if (ret) { D_ERROR( "Core/LayerContext: Failed to allocate surface!\n" ); return ret; } } else { DFBSurfaceCapabilities caps = shared->description.surface_caps ?: DSCAPS_VIDEOONLY; /* Choose surface capabilities depending on the buffer mode. */ switch (config->buffermode) { case DLBM_FRONTONLY: break; case DLBM_BACKVIDEO: case DLBM_BACKSYSTEM: caps |= DSCAPS_DOUBLE; break; case DLBM_TRIPLE: caps |= DSCAPS_TRIPLE; break; default: D_BUG( "unknown buffermode" ); break; } if (context->rotation == 90 || context->rotation == 270) caps |= DSCAPS_ROTATED; if (config->options & DLOP_DEINTERLACING) caps |= DSCAPS_INTERLACED; if (config->options & DLOP_STEREO) caps |= DSCAPS_STEREO; /* Add available surface capabilities. */ caps |= config->surface_caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_GL); scon.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS; scon.size.w = config->width; scon.size.h = config->height; scon.format = config->format; scon.colorspace = config->colorspace; scon.caps = caps; if (shared->contexts.primary == context) type |= CSTF_SHARED; /* Use the default surface creation. */ ret = dfb_surface_create( layer->core, &scon, type, shared->layer_id, NULL, &surface ); if (ret) { D_DERROR( ret, "Core/LayerContext: Surface creation failed!\n" ); return ret; } if (config->buffermode == DLBM_BACKSYSTEM) { surface->left_buffers[1]->policy = CSP_SYSTEMONLY; if (config->options & DLOP_STEREO) surface->right_buffers[1]->policy = CSP_SYSTEMONLY; } } if (surface->config.caps & DSCAPS_ROTATED) surface->rotation = context->rotation; else surface->rotation = (context->rotation == 180) ? 180 : 0; /* Tell the region about its new surface (adds a global reference). */ ret = dfb_layer_region_set_surface( region, surface, false ); /* Remove local reference of dfb_surface_create(). */ dfb_surface_unref( surface ); return ret; } DFBResult dfb_layer_context_reallocate_surface( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region, CoreLayerRegionConfig *config ) { DFBResult ret; CoreSurface *surface; CoreSurfaceConfig sconfig; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( region != NULL ); D_ASSERT( region->surface != NULL ); D_ASSERT( config != NULL ); D_ASSERT( config->buffermode != DLBM_WINDOWS ); D_MAGIC_ASSERT( context, CoreLayerContext ); funcs = layer->funcs; surface = region->surface; if (funcs->ReallocateSurface) return funcs->ReallocateSurface( layer, layer->driver_data, layer->layer_data, region->region_data, config, surface ); sconfig.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS; sconfig.caps = surface->config.caps & ~(DSCAPS_FLIPPING | DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_ROTATED | DSCAPS_STEREO); switch (config->buffermode) { case DLBM_TRIPLE: sconfig.caps |= DSCAPS_TRIPLE; break; case DLBM_BACKVIDEO: case DLBM_BACKSYSTEM: sconfig.caps |= DSCAPS_DOUBLE; break; case DLBM_FRONTONLY: break; default: D_BUG( "unknown buffermode" ); return DFB_BUG; } if (context->rotation == 90 || context->rotation == 270) sconfig.caps |= DSCAPS_ROTATED; /* Add available surface capabilities. */ sconfig.caps |= config->surface_caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_GL); if (config->options & DLOP_DEINTERLACING) sconfig.caps |= DSCAPS_INTERLACED; if (config->options & DLOP_STEREO) sconfig.caps |= DSCAPS_STEREO; sconfig.size.w = config->width; sconfig.size.h = config->height; sconfig.format = config->format; sconfig.colorspace = config->colorspace; ret = dfb_surface_lock( surface ); if (ret) return ret; if (config->buffermode == DLBM_BACKSYSTEM) surface->flips = 0; else if (!(surface->config.caps & DSCAPS_FLIPPING)) surface->flips++; ret = dfb_surface_reconfig( surface, &sconfig ); if (ret) { dfb_surface_unlock( surface ); return ret; } if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format ) && !surface->palette) { ret = dfb_surface_init_palette( layer->core, surface ); if (ret) D_DERROR( ret, "Core/LayerContext: Could not initialize palette while switching to indexed mode!\n" ); } switch (config->buffermode) { case DLBM_BACKSYSTEM: surface->left_buffers[1]->policy = CSP_SYSTEMONLY; if (config->options & DLOP_STEREO) surface->right_buffers[1]->policy = CSP_SYSTEMONLY; break; case DLBM_TRIPLE: case DLBM_BACKVIDEO: case DLBM_FRONTONLY: break; default: D_BUG( "unknown buffermode" ); return DFB_BUG; } if (surface->config.caps & DSCAPS_ROTATED) surface->rotation = context->rotation; else surface->rotation = (context->rotation == 180) ? 180 : 0; dfb_surface_unlock( surface ); return DFB_OK; } DFBResult dfb_layer_context_deallocate_surface( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region ) { DFBResult ret; CoreSurface *surface; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, layer, region ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( region != NULL ); D_ASSUME( region->surface != NULL ); funcs = layer->funcs; surface = region->surface; if (surface) { /* Special deallocation by the driver. */ if (funcs->DeallocateSurface) { ret = funcs->DeallocateSurface( layer, layer->driver_data, layer->layer_data, region->region_data, surface ); if (ret) return ret; } /* Detach the global listener. */ dfb_surface_detach_global( surface, ®ion->surface_reaction ); dfb_surface_deallocate_buffers( region->surface ); /* Unlink from structure. */ dfb_surface_unlink( ®ion->surface ); } return DFB_OK; } ================================================ FILE: src/core/layer_context.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__LAYER_CONTEXT_H__ #define __CORE__LAYER_CONTEXT_H__ #include /**********************************************************************************************************************/ typedef enum { CLLM_LOCATION = 0x00000000, /* Keep normalized area. */ CLLM_CENTER = 0x00000001, /* Center layer after resizing destination area. */ CLLM_POSITION = 0x00000002, /* Keep pixel position, but resize area. */ CLLM_RECTANGLE = 0x00000003 /* Keep pixel based area. */ } CoreLayerLayoutMode; struct __DFB_CoreLayerContext { FusionObject object; int magic; DFBDisplayLayerID layer_id; /* layer id */ FusionSkirmish lock; /* Lock for layer context handling. */ bool active; /* Active context. */ DFBDisplayLayerConfig config; /* Current layer configuration. */ int rotation; /* Rotation. */ FusionVector regions; /* All regions created within this context. */ struct { CoreLayerRegion *region; /* Region of layer config if buffer mode is not DLBM_WINDOWS. */ CoreLayerRegionConfig config; /* Region config used to implement layer config and settings. */ } primary; struct { DFBLocation location; /* Normalized screen location. */ DFBRectangle rectangle; /* Pixel based position and size. */ CoreLayerLayoutMode mode; /* Resizing influences them. */ } screen; DFBColorAdjustment adjustment; /* Color adjustment of the layer.*/ bool follow_video; /* Stereo ofset is determined by video metadata. */ int z; /* Stereo offset to use when the layer is mixed. */ CoreWindowStack *stack; /* Every layer has its own window stack as every layer has its own pixel buffer. */ FusionSHMPoolShared *shmpool; /* Shared memory pool. */ FusionCall call; /* dispatch */ struct { int hot_x; /* x position of cursor hot spot */ int hot_y; /* y position of cursor hot spot */ CoreSurface *surface; /* cursor shape surface */ } cursor; }; /**********************************************************************************************************************/ typedef enum { CLCNF_ACTIVATED = 0x00000001, CLCNF_DEACTIVATED = 0x00000002 } CoreLayerContextNotificationFlags; typedef struct { CoreLayerContextNotificationFlags flags; CoreLayerContext *context; } CoreLayerContextNotification; /**********************************************************************************************************************/ /* * Creates a pool of layer context objects. */ FusionObjectPool *dfb_layer_context_pool_create ( const FusionWorld *world ); /* * Generates dfb_layer_context_ref(), dfb_layer_context_attach() etc. */ FUSION_OBJECT_METHODS( CoreLayerContext, dfb_layer_context ) /**********************************************************************************************************************/ DFBResult dfb_layer_context_init ( CoreLayerContext *context, CoreLayer *layer, bool stack ); DirectResult dfb_layer_context_lock ( CoreLayerContext *context ); DirectResult dfb_layer_context_unlock ( CoreLayerContext *context ); bool dfb_layer_context_active ( const CoreLayerContext *context ); DFBResult dfb_layer_context_activate ( CoreLayerContext *context ); DFBResult dfb_layer_context_deactivate ( CoreLayerContext *context ); DFBResult dfb_layer_context_add_region ( CoreLayerContext *context, CoreLayerRegion *region ); DFBResult dfb_layer_context_remove_region ( CoreLayerContext *context, CoreLayerRegion *region ); DFBResult dfb_layer_context_get_primary_region ( CoreLayerContext *context, bool create, CoreLayerRegion **ret_region ); /* * Configuration testing/setting/getting. */ DFBResult dfb_layer_context_test_configuration ( CoreLayerContext *context, const DFBDisplayLayerConfig *config, DFBDisplayLayerConfigFlags *ret_failed ); DFBResult dfb_layer_context_set_configuration ( CoreLayerContext *context, const DFBDisplayLayerConfig *config ); DFBResult dfb_layer_context_get_configuration ( CoreLayerContext *context, DFBDisplayLayerConfig *ret_config ); /* * Configuration details. */ DFBResult dfb_layer_context_set_src_colorkey ( CoreLayerContext *context, u8 r, u8 g, u8 b, int index ); DFBResult dfb_layer_context_set_dst_colorkey ( CoreLayerContext *context, u8 r, u8 g, u8 b, int index ); DFBResult dfb_layer_context_set_sourcerectangle( CoreLayerContext *context, const DFBRectangle *source ); DFBResult dfb_layer_context_set_screenlocation ( CoreLayerContext *context, const DFBLocation *location ); DFBResult dfb_layer_context_set_screenrectangle( CoreLayerContext *context, const DFBRectangle *rect ); DFBResult dfb_layer_context_set_screenposition ( CoreLayerContext *context, int x, int y ); DFBResult dfb_layer_context_set_opacity ( CoreLayerContext *context, u8 opacity ); DFBResult dfb_layer_context_set_rotation ( CoreLayerContext *context, int rotation ); DFBResult dfb_layer_context_set_coloradjustment( CoreLayerContext *context, const DFBColorAdjustment *adjustment ); DFBResult dfb_layer_context_get_coloradjustment( CoreLayerContext *context, DFBColorAdjustment *ret_adjustment ); DFBResult dfb_layer_context_set_stereo_depth ( CoreLayerContext *context, bool follow_video, int z ); DFBResult dfb_layer_context_get_stereo_depth ( CoreLayerContext *context, bool *ret_follow_video, int *ret_z ); DFBResult dfb_layer_context_set_field_parity ( CoreLayerContext *context, int field ); DFBResult dfb_layer_context_set_clip_regions ( CoreLayerContext *context, const DFBRegion *regions, int num_regions, DFBBoolean positive ); DFBResult dfb_layer_context_set_cursor_shape ( CoreLayerContext *context, CoreSurface *shape, int hot_x, int hot_y ); DFBResult dfb_layer_context_get_cursor_shape ( CoreLayerContext *context, CoreSurface **ret_shape, int *ret_hot_x, int *ret_hot_y ); /* * Window control. */ DFBResult dfb_layer_context_create_window ( CoreDFB *core, CoreLayerContext *context, const DFBWindowDescription *desc, CoreWindow **ret_window ); CoreWindow *dfb_layer_context_find_window ( CoreLayerContext *context, DFBWindowID id ); CoreWindowStack *dfb_layer_context_windowstack ( const CoreLayerContext *context ); /* * Region surface (re/de)allocation. */ DFBResult dfb_layer_context_allocate_surface ( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region, CoreLayerRegionConfig *config ); DFBResult dfb_layer_context_reallocate_surface ( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region, CoreLayerRegionConfig *config ); DFBResult dfb_layer_context_deallocate_surface ( CoreLayer *layer, CoreLayerContext *context, CoreLayerRegion *region ); #endif ================================================ FILE: src/core/layer_control.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Core_LayerControl, "Core/LayerControl", "DirectFB Core Display Layer Control" ); /**********************************************************************************************************************/ DFBResult dfb_layer_suspend( CoreLayer *layer ) { CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_ASSUME( !shared->suspended ); if (shared->suspended) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* Deactivate current context. */ if (contexts->active >= 0) { DFBResult ret; CoreLayerContext *current = fusion_vector_at( &contexts->stack, contexts->active ); ret = dfb_layer_context_deactivate( current ); if (ret) { D_DERROR( ret, "Core/LayerControl: Could not deactivate current context of '%s'!\n", shared->description.name ); } } shared->suspended = true; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_resume( CoreLayer *layer ) { CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_ASSUME( shared->suspended ); if (!shared->suspended) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* (Re)Activate current context. */ if (contexts->active >= 0) { DFBResult ret; CoreLayerContext *current = fusion_vector_at( &contexts->stack, contexts->active ); ret = dfb_layer_context_activate( current ); if (ret) { D_DERROR( ret, "Core/LayerControl: Could not activate current context of '%s'!\n", shared->description.name ); } } shared->suspended = false; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_create_context( CoreLayer *layer, bool stack, CoreLayerContext **ret_context ) { DFBResult ret; CoreLayerShared *shared; CoreLayerContexts *contexts; CoreLayerContext *context; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; D_DEBUG_AT( Core_LayerControl, "%s( %s )\n", __FUNCTION__, shared->description.name ); /* Create the object. */ context = dfb_core_create_layer_context( layer->core ); if (!context) return DFB_FUSION; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) { fusion_object_destroy( &context->object ); return DFB_FUSION; } /* Initialize the new context. */ ret = dfb_layer_context_init( context, layer, stack ); if (ret) { fusion_skirmish_dismiss( &shared->lock ); return ret; } /* Add it to the context stack. */ if (fusion_vector_add( &contexts->stack, context )) { dfb_layer_context_unref( context ); fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); /* Return the context. */ *ret_context = context; D_DEBUG_AT( Core_LayerControl, " -> %p\n", context ); return DFB_OK; } DFBResult dfb_layer_get_active_context( CoreLayer *layer, CoreLayerContext **ret_context ) { CoreLayerShared *shared; CoreLayerContexts *contexts; CoreLayerContext *context; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; D_DEBUG_AT( Core_LayerControl, "%s( %s )\n", __FUNCTION__, shared->description.name ); /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; /* Check for active context. */ if (contexts->active < 0) { fusion_skirmish_dismiss( &shared->lock ); return DFB_NOCONTEXT; } /* Fetch active context. */ context = fusion_vector_at( &contexts->stack, contexts->active ); /* Increase the context's reference counter. */ if (dfb_layer_context_ref( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } D_DEBUG_AT( Core_LayerControl, " -> %p, %4dx%4d %s\n", context, context->config.width, context->config.height, dfb_pixelformat_name( context->config.pixelformat ) ); /* Return the context. */ *ret_context = context; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_get_primary_context( CoreLayer *layer, bool activate, CoreLayerContext **ret_context ) { DFBResult ret; CoreLayerShared *shared; CoreLayerContexts *contexts; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_context != NULL ); shared = layer->shared; contexts = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_LayerControl, "%s( %s, %sactivate ) <- active: %d\n", __FUNCTION__, shared->description.name, activate ? "" : "don't ", contexts->active ); /* Check for primary context. */ if (contexts->primary) { /* Increase the context's reference counter. */ if (dfb_layer_context_ref( contexts->primary )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } } else { CoreLayerContext *primary; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); /* Create the primary (shared) context. */ ret = dfb_layer_create_context( layer, true, &primary ); if (ret) return ret; /* Lock the layer again. */ if (fusion_skirmish_prevail( &shared->lock )) { dfb_layer_context_unref( primary ); return DFB_FUSION; } /* Check if there was a race. */ if (contexts->primary) { /* Throw away ours, the other was faster. */ dfb_layer_context_unref( primary ); /* Increase the context's reference counter. */ if (dfb_layer_context_ref( contexts->primary )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } } else contexts->primary = primary; } /* Activate if no context is active. */ if (contexts->active < 0 && activate) { ret = dfb_layer_activate_context( layer, contexts->primary ); if (ret) { dfb_layer_context_unref( contexts->primary ); fusion_skirmish_dismiss( &shared->lock ); return ret; } } /* Return the context. */ *ret_context = contexts->primary; /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_activate_context( CoreLayer *layer, CoreLayerContext *context ) { DFBResult ret; int index; CoreLayerShared *shared; CoreLayerContexts *ctxs; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( context != NULL ); shared = layer->shared; ctxs = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_LayerControl, "%s( %s, %p )\n", __FUNCTION__, shared->description.name, context ); D_ASSERT( fusion_vector_contains( &ctxs->stack, context ) ); /* Lookup the context in the context stack. */ index = fusion_vector_index_of( &ctxs->stack, context ); /* Lock the context. */ if (dfb_layer_context_lock( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Need to activate. */ if (ctxs->active != index) { /* Another context currently active. */ if (ctxs->active >= 0) { CoreLayerContext *current = fusion_vector_at( &ctxs->stack, ctxs->active ); /* Deactivate current context. */ if (!shared->suspended) { ret = dfb_layer_context_deactivate( current ); if (ret) goto error; } /* No active context. */ ctxs->active = -1; } /* Activate context now. */ if (!shared->suspended) { ret = dfb_layer_context_activate( context ); if (ret) goto error; } ctxs->active = index; } /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; error: dfb_layer_context_unlock( context ); fusion_skirmish_dismiss( &shared->lock ); return ret; } DFBResult dfb_layer_remove_context( CoreLayer *layer, CoreLayerContext *context ) { int index; CoreLayerShared *shared; CoreLayerContexts *ctxs; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( context != NULL ); shared = layer->shared; ctxs = &shared->contexts; /* Lock the layer. */ if (fusion_skirmish_prevail( &shared->lock )) return DFB_FUSION; D_DEBUG_AT( Core_LayerControl, "%s( %s, %p )\n", __FUNCTION__, shared->description.name, context ); D_ASSUME( fusion_vector_contains( &ctxs->stack, context ) ); /* Lookup the context in the context stack. */ index = fusion_vector_index_of( &ctxs->stack, context ); if (index < 0) { fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } /* Lock the context. */ if (dfb_layer_context_lock( context )) { fusion_skirmish_dismiss( &shared->lock ); return DFB_FUSION; } /* Remove context from context stack. */ fusion_vector_remove( &ctxs->stack, index ); /* Check if the primary context is removed. */ if (context == ctxs->primary) ctxs->primary = NULL; /* Need to deactivate. */ if (ctxs->active == index) { /* Deactivate the context. */ if (!shared->suspended) dfb_layer_context_deactivate( context ); /* There's no active context anymore. */ ctxs->active = -1; if (ctxs->primary) D_ASSERT( fusion_vector_contains( &ctxs->stack, ctxs->primary ) ); if (fusion_vector_has_elements( &ctxs->stack )) { CoreLayerContext *ctx; /* Activate most recent context. */ index = fusion_vector_size( &ctxs->stack ) - 1; ctx = fusion_vector_at( &ctxs->stack, index ); if (shared->suspended || dfb_layer_context_activate( ctx ) == DFB_OK) ctxs->active = index; } } else if (ctxs->active > index) { /* Adjust index of active context due to the removed context. */ ctxs->active--; } /* Unlock the context. */ dfb_layer_context_unlock( context ); /* Unlock the layer. */ fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; } DFBResult dfb_layer_get_current_output_field( CoreLayer *layer, int *ret_field ) { DFBResult ret; const DisplayLayerFuncs *funcs; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( ret_field != NULL ); funcs = layer->funcs; if (!funcs->GetCurrentOutputField) return DFB_UNSUPPORTED; ret = funcs->GetCurrentOutputField( layer, layer->driver_data, layer->layer_data, ret_field ); if (ret) return ret; return DFB_OK; } DFBResult dfb_layer_get_level( CoreLayer *layer, int *ret_level ) { const DisplayLayerFuncs *funcs; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( ret_level != NULL ); funcs = layer->funcs; if (!funcs->GetLevel) return DFB_UNSUPPORTED; return funcs->GetLevel( layer, layer->driver_data, layer->layer_data, ret_level ); } DFBResult dfb_layer_set_level( CoreLayer *layer, int level ) { const DisplayLayerFuncs *funcs; D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; if (!funcs->SetLevel) return DFB_UNSUPPORTED; return funcs->SetLevel( layer, layer->driver_data, layer->layer_data, level ); } DFBResult dfb_layer_wait_vsync( CoreLayer *layer ) { D_ASSERT( layer != NULL ); D_ASSERT( layer->screen != NULL ); return dfb_screen_wait_vsync( layer->screen ); } DFBResult dfb_layer_get_source_info( CoreLayer *layer, int source, DFBDisplayLayerSourceDescription *ret_desc ) { CoreLayerShared *shared; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( source >= 0 ); D_ASSERT( source < layer->shared->description.sources ); D_ASSERT( ret_desc != NULL ); shared = layer->shared; *ret_desc = shared->sources[source].description; return DFB_OK; } ================================================ FILE: src/core/layer_control.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__LAYER_CONTROL_H__ #define __CORE__LAYER_CONTROL_H__ #include /**********************************************************************************************************************/ DFBResult dfb_layer_suspend ( CoreLayer *layer ); DFBResult dfb_layer_resume ( CoreLayer *layer ); DFBResult dfb_layer_create_context ( CoreLayer *layer, bool stack, CoreLayerContext **ret_context ); DFBResult dfb_layer_get_active_context ( CoreLayer *layer, CoreLayerContext **ret_context ); DFBResult dfb_layer_get_primary_context ( CoreLayer *layer, bool activate, CoreLayerContext **ret_context ); DFBResult dfb_layer_activate_context ( CoreLayer *layer, CoreLayerContext *context ); DFBResult dfb_layer_remove_context ( CoreLayer *layer, CoreLayerContext *context ); DFBResult dfb_layer_get_current_output_field( CoreLayer *layer, int *ret_field ); DFBResult dfb_layer_get_level ( CoreLayer *layer, int *ret_level ); DFBResult dfb_layer_set_level ( CoreLayer *layer, int level ); DFBResult dfb_layer_wait_vsync ( CoreLayer *layer ); DFBResult dfb_layer_get_source_info ( CoreLayer *layer, int source, DFBDisplayLayerSourceDescription *ret_desc ); #endif ================================================ FILE: src/core/layer_region.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_LayerRegion, "Core/LayerRegion", "DirectFB Core Display Layer Region" ); D_DEBUG_DOMAIN( Core_LayerRegionLock, "Core/LayerRegion/Lock", "DirectFB Core Display Layer Region Lock" ); D_DEBUG_DOMAIN( Core_LayerRegionUpdate, "Core/LayerRegion/Update", "DirectFB Core Display Layer Region Update" ); /**********************************************************************************************************************/ static DFBResult region_buffer_unlock ( CoreLayerRegion *region, CoreSurfaceBufferLock *left_buffer_lock, CoreSurfaceBufferLock *right_buffer_lock ); static DFBResult region_buffer_lock ( CoreLayerRegion *region, CoreSurface *surface, DFBSurfaceBufferRole role, CoreSurfaceBufferLock *left_buffer_lock, CoreSurfaceBufferLock *right_buffer_lock ); static DFBResult dfb_layer_region_set ( CoreLayerRegion *region, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags flags, CoreSurface *surface ); static DFBResult dfb_layer_region_realize ( CoreLayerRegion *region, bool set ); static DFBResult dfb_layer_region_unrealize( CoreLayerRegion *region ); /**********************************************************************************************************************/ static void region_destructor( FusionObject *object, bool zombie, void *ctx ) { DFBResult ret; CoreLayerRegion *region = (CoreLayerRegion*) object; CoreLayer *layer; CoreLayerShared *shared; CoreLayerContext *context; layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; D_DEBUG_AT( Core_LayerRegion, "Destroying region %p (%s, %dx%d, %s, %s, %s, %s%s)\n", region, shared->description.name, region->config.width, region->config.height, D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ? "configured" : "unconfigured", D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ? "enabled" : "disabled", D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ? "active" : "inactive", D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ? "realized" : "not realized", zombie ? " ZOMBIE" : "" ); /* Hide region etc. */ if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) dfb_layer_region_disable( region ); /* Remove the region from the context. */ ret = fusion_object_lookup( core_dfb->shared->layer_context_pool, region->context_id, (FusionObject**) &context ); if (ret == DFB_OK) dfb_layer_context_remove_region( context, region ); /* Throw away its surface. */ if (region->surface) { /* Detach the global listener. */ dfb_surface_detach_global( region->surface, ®ion->surface_reaction ); /* Detach the surface event listener. */ dfb_surface_detach( region->surface, ®ion->surface_event_reaction ); dfb_surface_client_unref( region->surface_client ); /* Unlink from structure. */ dfb_surface_unlink( ®ion->surface ); } /* Free driver's region data. */ if (region->region_data) SHFREE( shared->shmpool, region->region_data ); CoreLayerRegion_Deinit_Dispatch( ®ion->call ); /* Deinitialize the lock. */ fusion_skirmish_destroy( ®ion->lock ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_layer_region_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Layer Region Pool", sizeof(CoreLayerRegion), sizeof(CoreLayerRegionNotification), region_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_layer_region_create( CoreLayerContext *context, CoreLayerRegion **ret_region ) { CoreLayer *layer; CoreLayerShared *shared; CoreLayerRegion *region; D_ASSERT( context != NULL ); D_ASSERT( ret_region != NULL ); D_DEBUG_AT( Core_LayerRegion, "%s()\n", __FUNCTION__ ); layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; /* Create the region object. */ region = dfb_core_create_layer_region( layer->core ); if (!region) return DFB_FUSION; region->layer_id = context->layer_id; region->context_id = context->object.id; /* Initialize the lock. */ if (fusion_skirmish_init2( ®ion->lock, "Layer Region", dfb_core_world( layer->core ), fusion_config->secure_fusion )) { fusion_object_destroy( ®ion->object ); return DFB_FUSION; } /* Change global reaction lock. */ fusion_object_set_lock( ®ion->object, ®ion->lock ); region->state = CLRSF_FROZEN; if (shared->description.surface_accessor) region->surface_accessor = shared->description.surface_accessor; else region->surface_accessor = CSAID_LAYER0 + region->layer_id; CoreLayerRegion_Init_Dispatch( layer->core, region, ®ion->call ); /* Activate the object. */ fusion_object_activate( ®ion->object ); /* Add the region to the context. */ dfb_layer_context_add_region( context, region ); /* Return the new region. */ *ret_region = region; D_DEBUG_AT( Core_LayerRegion, " -> %p\n", region ); return DFB_OK; } DirectResult dfb_layer_region_lock( CoreLayerRegion *region ) { D_ASSERT( region != NULL ); return fusion_skirmish_prevail( ®ion->lock ); } DirectResult dfb_layer_region_unlock( CoreLayerRegion *region ) { D_ASSERT( region != NULL ); return fusion_skirmish_dismiss( ®ion->lock ); } DFBResult dfb_layer_region_activate( CoreLayerRegion *region ) { DFBResult ret; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; D_ASSUME( !D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { dfb_layer_region_unlock( region ); return DFB_OK; } /* Realize the region if it's enabled. */ if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { ret = dfb_layer_region_realize( region, true ); if (ret) { dfb_layer_region_unlock( region ); return ret; } } /* Update the region's state. */ D_FLAGS_SET( region->state, CLRSF_ACTIVE ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } DFBResult dfb_layer_region_deactivate( CoreLayerRegion *region ) { DFBResult ret; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); if (!D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { dfb_layer_region_unlock( region ); return DFB_OK; } /* Unrealize the region. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { ret = dfb_layer_region_unrealize( region ); if (ret) { dfb_layer_region_unlock( region ); return ret; } } /* Update the region's state. */ D_FLAGS_CLEAR( region->state, CLRSF_ACTIVE ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } DFBResult dfb_layer_region_enable( CoreLayerRegion *region ) { DFBResult ret; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; D_ASSUME( !D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { dfb_layer_region_unlock( region ); return DFB_OK; } /* Realize the region if it's active. */ if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { ret = dfb_layer_region_realize( region, true ); if (ret) { dfb_layer_region_unlock( region ); return ret; } } /* Update the region's state. */ D_FLAGS_SET( region->state, CLRSF_ENABLED ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } DFBResult dfb_layer_region_disable( CoreLayerRegion *region ) { DFBResult ret; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); if (!D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { dfb_layer_region_unlock( region ); return DFB_OK; } /* Unrealize the region. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { ret = dfb_layer_region_unrealize( region ); if (ret) return ret; } /* Update the region's state. */ D_FLAGS_CLEAR( region->state, CLRSF_ENABLED ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } static ReactionResult region_surface_react( const void *msg_data, void *ctx ) { const DFBSurfaceEvent *evt = msg_data; CoreLayerRegion *region = ctx; D_DEBUG_AT( Core_LayerRegionUpdate, "%s( %p ) <- type %06x\n", __FUNCTION__, evt, evt->type ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> surface id %u\n", evt->surface_id ); if (evt->type == DSEVT_UPDATE) { D_DEBUG_AT( Core_LayerRegionUpdate, " -> updated %4d,%4d-%4dx%4d (left)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update ) ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> updated %4d,%4d-%4dx%4d (right)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update_right ) ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> flip count %u\n", evt->flip_count ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> time stamp %lld\n", evt->time_stamp ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> layer region %p\n", region ); if (direct_log_domain_check( &Core_LayerRegionUpdate )) { dfb_surface_lock( region->surface ); CoreSurfaceBuffer *buffer; D_UNUSED_P( buffer ); buffer = dfb_surface_get_buffer3( region->surface, DSBR_FRONT, DSSE_LEFT, evt->flip_count ); D_DEBUG_AT( Core_LayerRegionUpdate, " -> buffer %p\n", buffer ); dfb_surface_unlock( region->surface ); } region->surface_flip_count = evt->flip_count; if (!CoreLayerRegion_FlipUpdate2( region, &evt->update, &evt->update_right, DSFLIP_ONSYNC | DSFLIP_UPDATE, evt->flip_count, evt->time_stamp )) CoreSurfaceClient_FrameAck( region->surface_client, evt->flip_count ); } else if (evt->type == DSEVT_DESTROYED) return RS_REMOVE; return RS_OK; } DFBResult dfb_layer_region_set_surface( CoreLayerRegion *region, CoreSurface *surface, bool update ) { DFBResult ret; D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, %d )\n", __FUNCTION__, region, surface, update ); D_ASSERT( region != NULL ); D_ASSERT( surface != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; if (region->surface != surface) { /* Setup hardware for the new surface if the region is realized. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { ret = dfb_layer_region_set( region, ®ion->config, CLRCF_SURFACE | CLRCF_PALETTE, surface ); if (ret) { dfb_layer_region_unlock( region ); return ret; } } /* Throw away the old surface. */ if (region->surface) { /* Detach the global listener. */ dfb_surface_detach_global( region->surface, ®ion->surface_reaction ); /* Detach the surface event listener. */ dfb_surface_detach( region->surface, ®ion->surface_event_reaction ); dfb_surface_client_unref( region->surface_client ); /* Unlink surface from structure. */ dfb_surface_unlink( ®ion->surface ); } /* Take the new surface. */ if (surface) { /* Link surface into structure. */ if (dfb_surface_link( ®ion->surface, surface )) { D_WARN( "region has lost its surface" ); dfb_layer_region_unlock( region ); return DFB_FUSION; } /* Create the surface client. */ ret = CoreSurface_CreateClient( region->surface, ®ion->surface_client ); if (ret) { D_WARN( "failed to create surface client" ); dfb_layer_region_unlock( region ); return ret; } /* Attach the global listener. */ dfb_surface_attach_global( region->surface, DFB_LAYER_REGION_SURFACE_LISTENER, region, ®ion->surface_reaction ); /* Attach the surface event listener. */ dfb_surface_attach_channel( region->surface, CSCH_EVENT, region_surface_react, region, ®ion->surface_event_reaction ); } if (update && D_FLAGS_ARE_SET( region->state, CLRSF_ENABLED | CLRSF_ACTIVE )) { region->surface_flip_count = surface->flips; dfb_layer_region_flip_update( region, NULL, DSFLIP_UPDATE ); } } /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } DFBResult dfb_layer_region_get_surface( CoreLayerRegion *region, CoreSurface **ret_surface ) { D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); D_ASSERT( ret_surface != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; D_ASSUME( region->surface != NULL ); /* Check for NULL surface. */ if (!region->surface) { dfb_layer_region_unlock( region ); return DFB_UNSUPPORTED; } /* Increase the surface's reference counter. */ if (dfb_surface_ref( region->surface )) { dfb_layer_region_unlock( region ); return DFB_FUSION; } /* Return the surface. */ *ret_surface = region->surface; /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } DFBResult dfb_layer_region_flip_update( CoreLayerRegion *region, const DFBRegion *update, DFBSurfaceFlipFlags flags ) { DFBResult ret = DFB_OK; DFBRegion unrotated; DFBRegion rotated; CoreLayer *layer; CoreSurface *surface; const DisplayLayerFuncs *funcs; if (update) D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, 0x%08x ) <- [%4d,%4d-%4dx%4d]\n", __FUNCTION__, region, update, flags, DFB_RECTANGLE_VALS_FROM_REGION( update ) ); else D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, region, update, flags ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; /* Check for stereo region */ if (region->config.options & DLOP_STEREO) { ret = dfb_layer_region_flip_update_stereo( region, update, update, flags ); dfb_layer_region_unlock( region ); return ret; } D_ASSUME( region->surface != NULL ); /* Check for NULL surface. */ if (!region->surface) { D_DEBUG_AT( Core_LayerRegion, " -> no surface => no update!\n" ); dfb_layer_region_unlock( region ); return DFB_UNSUPPORTED; } surface = region->surface; layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; /* Unfreeze region. */ if (D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { D_FLAGS_CLEAR( region->state, CLRSF_FROZEN ); if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { ret = dfb_layer_region_set( region, ®ion->config, CLRCF_ALL, surface ); if (ret) D_DERROR( ret, "Core/LayerRegion: " "dfb_layer_region_set() in dfb_layer_region_flip_update() failed!\n" ); } else if (D_FLAGS_ARE_SET( region->state, CLRSF_ENABLED | CLRSF_ACTIVE )) { ret = dfb_layer_region_realize( region, true ); if (ret) D_DERROR( ret, "Core/LayerRegion: " "dfb_layer_region_realize() in dfb_layer_region_flip_update() failed!\n" ); } if (ret) { dfb_layer_region_unlock( region ); return ret; } } dfb_gfxcard_flush(); dfb_surface_lock( surface ); if (!(surface->frametime_config.flags & DFTCF_INTERVAL)) dfb_screen_get_frame_interval( layer->screen, &surface->frametime_config.interval ); if (flags & DSFLIP_UPDATE) goto update_only; /* Depending on the buffer mode. */ switch (region->config.buffermode) { case DLBM_TRIPLE: case DLBM_BACKVIDEO: /* Check if simply swapping the buffers is possible. */ if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && !surface->rotation && (!update || (update->x1 == 0 && update->y1 == 0 && update->x2 == surface->config.size.w - 1 && update->y2 == surface->config.size.h - 1)))) { D_DEBUG_AT( Core_LayerRegion, " -> going to swap buffers...\n" ); /* Use the driver's routine if the region is realized. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { CoreSurfaceBufferLock left; D_ASSUME( funcs->FlipRegion != NULL ); ret = region_buffer_lock( region, surface, DSBR_BACK, &left, NULL ); if (ret) goto out; D_DEBUG_AT( Core_LayerRegion, " -> flipping region using driver...\n" ); if (funcs->FlipRegion) ret = funcs->FlipRegion( layer, layer->driver_data, layer->layer_data, region->region_data, surface, flags, update, &left, NULL, NULL ); if (!(dfb_system_caps() & CSCAPS_NOTIFY_DISPLAY)) { D_DEBUG_AT( Core_LayerRegion, " -> system without notify_display support, calling it now\n" ); dfb_surface_notify_display2( surface, left.allocation->index ); } /* Unlock region buffer since the lock is no longer needed. */ region_buffer_unlock(region, &left, NULL); } else { D_DEBUG_AT( Core_LayerRegion, " -> flipping region not using driver...\n" ); /* Just do the hardware independent work. */ dfb_surface_flip_buffers( surface, false ); } break; } /* fall through */ case DLBM_BACKSYSTEM: D_DEBUG_AT( Core_LayerRegion, " -> going to copy portion...\n" ); if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) { D_DEBUG_AT( Core_LayerRegion, " -> waiting for VSync...\n" ); dfb_layer_wait_vsync( layer ); } D_DEBUG_AT( Core_LayerRegion, " -> copying content from back to front buffer...\n" ); /* Copy updated contents from back to front buffer. */ dfb_back_to_front_copy_stereo( surface, DSSE_LEFT, update, NULL, surface->rotation ); if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAIT) { D_DEBUG_AT( Core_LayerRegion, " -> waiting for VSync...\n" ); dfb_layer_wait_vsync( layer ); } /* fall through */ case DLBM_FRONTONLY: update_only: /* Tell the driver about the update if the region is realized. */ if (funcs->UpdateRegion && D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { CoreSurfaceBufferLock left; if (surface) { /* Lock region buffer before it is used. */ region_buffer_lock( region, surface, DSBR_FRONT, &left, NULL ); D_ASSERT( left.allocation != NULL ); } D_DEBUG_AT( Core_LayerRegion, " -> notifying driver about updated content...\n" ); if (!update) { unrotated = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, region->config.width, region->config.height ); update = &unrotated; } dfb_region_from_rotated( &rotated, update, &surface->config.size, surface->rotation ); ret = funcs->UpdateRegion( layer, layer->driver_data, layer->layer_data, region->region_data, surface, &rotated, &left, NULL, NULL ); if (!(dfb_system_caps() & CSCAPS_NOTIFY_DISPLAY)) { D_DEBUG_AT( Core_LayerRegion, " -> system without notify_display support, calling it now\n" ); dfb_surface_notify_display2( surface, left.allocation->index ); } /* Unlock region buffer since the lock is no longer needed. */ if (surface) region_buffer_unlock(region, &left, NULL); } break; default: D_BUG( "unknown buffer mode" ); ret = DFB_BUG; } D_DEBUG_AT( Core_LayerRegion, " -> done\n" ); out: dfb_surface_unlock( surface ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return ret; } DFBResult dfb_layer_region_flip_update_stereo( CoreLayerRegion *region, const DFBRegion *left_update, const DFBRegion *right_update, DFBSurfaceFlipFlags flags ) { DFBResult ret = DFB_OK; DFBRegion unrotated; DFBRegion left_rotated, right_rotated; CoreLayer *layer; CoreSurface *surface; const DisplayLayerFuncs *funcs; DFBSurfaceStereoEye eyes = 0; D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, %p, 0x%08x )\n", __FUNCTION__, region, left_update, right_update, flags ); if (left_update) D_DEBUG_AT( Core_LayerRegion, "Left: [%4d,%4d-%4dx%4d]\n", DFB_RECTANGLE_VALS_FROM_REGION( left_update ) ); if (right_update) D_DEBUG_AT( Core_LayerRegion, "Right: [%4d,%4d-%4dx%4d]\n", DFB_RECTANGLE_VALS_FROM_REGION( right_update ) ); D_ASSERT( region != NULL ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; /* Check for stereo region */ if (!(region->config.options & DLOP_STEREO)) { D_DEBUG_AT( Core_LayerRegion, " -> not a stereo region!\n" ); dfb_layer_region_unlock( region ); return DFB_UNSUPPORTED; } D_ASSUME( region->surface != NULL ); /* Check for NULL surface. */ if (!region->surface) { D_DEBUG_AT( Core_LayerRegion, " -> no surface => no update!\n" ); dfb_layer_region_unlock( region ); return DFB_UNSUPPORTED; } surface = region->surface; layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); funcs = layer->funcs; /* Unfreeze region. */ if (D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { D_FLAGS_CLEAR( region->state, CLRSF_FROZEN ); if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { ret = dfb_layer_region_set( region, ®ion->config, CLRCF_ALL, surface ); if (ret) D_DERROR( ret, "Core/LayerRegion: " "dfb_layer_region_set() in dfb_layer_region_flip_update() failed!\n" ); } else if (D_FLAGS_ARE_SET( region->state, CLRSF_ENABLED | CLRSF_ACTIVE )) { ret = dfb_layer_region_realize( region, true ); if (ret) D_DERROR( ret, "Core/LayerRegion: " "dfb_layer_region_realize() in dfb_layer_region_flip_update() failed!\n" ); } if (ret) { dfb_layer_region_unlock( region ); return ret; } } dfb_gfxcard_flush(); dfb_surface_lock( surface ); if (!(surface->frametime_config.flags & DFTCF_INTERVAL)) dfb_screen_get_frame_interval( layer->screen, &surface->frametime_config.interval ); if (flags & DSFLIP_UPDATE) goto update_only; /* Depending on the buffer mode. */ switch (region->config.buffermode) { case DLBM_TRIPLE: case DLBM_BACKVIDEO: /* Check if simply swapping the buffers is possible. */ if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && !surface->rotation && ((!left_update && !right_update) || ((left_update->x1 == 0 && left_update->y1 == 0 && left_update->x2 == surface->config.size.w - 1 && left_update->y2 == surface->config.size.h - 1) && (right_update->x1 == 0 && right_update->y1 == 0 && right_update->x2 == surface->config.size.w - 1 && right_update->y2 == surface->config.size.h - 1))))) { D_DEBUG_AT( Core_LayerRegion, " -> going to swap buffers...\n" ); /* Use the driver's routine if the region is realized. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { CoreSurfaceBufferLock left, right; D_ASSUME( funcs->FlipRegion != NULL ); ret = region_buffer_lock( region, surface, DSBR_BACK, &left, &right ); if (ret) goto out; D_DEBUG_AT( Core_LayerRegion, " -> flipping region using driver...\n" ); if (funcs->FlipRegion) ret = funcs->FlipRegion( layer, layer->driver_data, layer->layer_data, region->region_data, surface, flags, left_update, &left, right_update, &right ); /* Unlock region buffer since the lock is no longer needed. */ region_buffer_unlock( region, &left, &right ); } else { D_DEBUG_AT( Core_LayerRegion, " -> flipping region not using driver...\n" ); /* Just do the hardware independent work. */ dfb_surface_flip_buffers( surface, false ); } break; } /* fall through */ case DLBM_BACKSYSTEM: D_DEBUG_AT( Core_LayerRegion, " -> going to copy portion...\n" ); if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) { D_DEBUG_AT( Core_LayerRegion, " -> waiting for VSync...\n" ); dfb_layer_wait_vsync( layer ); } D_DEBUG_AT( Core_LayerRegion, " -> copying content from back to front buffer...\n" ); if (left_update) eyes |= DSSE_LEFT; if (right_update) eyes |= DSSE_RIGHT; /* Copy updated contents from back to front buffer. */ dfb_back_to_front_copy_stereo( surface, eyes, left_update, right_update, surface->rotation ); if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAIT) { D_DEBUG_AT( Core_LayerRegion, " -> waiting for VSync...\n" ); dfb_layer_wait_vsync( layer ); } /* fall through */ case DLBM_FRONTONLY: update_only: /* Tell the driver about the update if the region is realized. */ if (funcs->UpdateRegion && D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { CoreSurfaceBufferLock left, right; if (surface) { /* Lock region buffer before it is used. */ region_buffer_lock( region, surface, DSBR_FRONT, &left, &right ); D_ASSERT( left.allocation != NULL ); D_ASSERT( right.allocation != NULL ); } D_DEBUG_AT( Core_LayerRegion, " -> notifying driver about updated content...\n" ); if (!left_update && !right_update) { unrotated = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, region->config.width, region->config.height ); left_update = &unrotated; unrotated = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, region->config.width, region->config.height ); right_update = &unrotated; } else if (!left_update) { left_update = right_update; } else if (!right_update) { right_update = left_update; } dfb_region_from_rotated( &left_rotated, left_update, &surface->config.size, surface->rotation ); if (left_update != right_update) dfb_region_from_rotated( &right_rotated, right_update, &surface->config.size, surface->rotation ); else right_rotated = left_rotated; ret = funcs->UpdateRegion( layer, layer->driver_data, layer->layer_data, region->region_data, surface, &left_rotated, &left, &right_rotated, &right ); /* Unlock region buffer since the lock is no longer needed. */ if (surface) region_buffer_unlock( region, &left, &right ); } break; default: D_BUG( "unknown buffer mode" ); ret = DFB_BUG; } D_DEBUG_AT( Core_LayerRegion, " -> done\n" ); out: dfb_surface_unlock( surface ); /* Unlock the region. */ dfb_layer_region_unlock( region ); return ret; } DFBResult dfb_layer_region_flip_update2( CoreLayerRegion *region, const DFBRegion *left_update, const DFBRegion *right_update, DFBSurfaceFlipFlags flags, unsigned int flip_count, long long pts ) { if (region->config.options & DLOP_STEREO) return dfb_layer_region_flip_update_stereo( region, left_update, right_update, flags ); return dfb_layer_region_flip_update( region, left_update, flags ); } DFBResult dfb_layer_region_set_configuration( CoreLayerRegion *region, const CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags flags ) { DFBResult ret; CoreLayer *layer; const DisplayLayerFuncs *funcs; CoreLayerRegionConfig new_config; CoreLayerRegionConfigFlags failed; D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, region, config, flags ); D_ASSERT( region != NULL ); D_ASSERT( config != NULL ); D_ASSERT( config->buffermode != DLBM_WINDOWS ); D_ASSERT( (flags == CLRCF_ALL) || (region->state & CLRSF_CONFIGURED) ); D_ASSUME( flags != CLRCF_NONE ); D_ASSUME( !(flags & ~CLRCF_ALL) ); layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->TestRegion != NULL ); funcs = layer->funcs; /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; /* Full configuration supplied. */ if (flags == CLRCF_ALL) { new_config = *config; } else { /* Use the current configuration. */ new_config = region->config; /* Update each modified entry. */ if (flags & CLRCF_WIDTH) new_config.width = config->width; if (flags & CLRCF_HEIGHT) new_config.height = config->height; if (flags & CLRCF_FORMAT) new_config.format = config->format; if (flags & CLRCF_COLORSPACE) new_config.colorspace = config->colorspace; if (flags & CLRCF_SURFACE_CAPS) new_config.surface_caps = config->surface_caps; if (flags & CLRCF_BUFFERMODE) new_config.buffermode = config->buffermode; if (flags & CLRCF_OPTIONS) new_config.options = config->options; if (flags & CLRCF_SOURCE_ID) new_config.source_id = config->source_id; if (flags & CLRCF_SOURCE) new_config.source = config->source; if (flags & CLRCF_DEST) new_config.dest = config->dest; if (flags & CLRCF_OPACITY) new_config.opacity = config->opacity; if (flags & CLRCF_ALPHA_RAMP) { new_config.alpha_ramp[0] = config->alpha_ramp[0]; new_config.alpha_ramp[1] = config->alpha_ramp[1]; new_config.alpha_ramp[2] = config->alpha_ramp[2]; new_config.alpha_ramp[3] = config->alpha_ramp[3]; } if (flags & CLRCF_SRCKEY) new_config.src_key = config->src_key; if (flags & CLRCF_DSTKEY) new_config.dst_key = config->dst_key; if (flags & CLRCF_PARITY) new_config.parity = config->parity; if (flags & CLRCF_CLIPS) { new_config.clips = config->clips; new_config.num_clips = config->num_clips; new_config.positive = config->positive; } } DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_LayerRegion, &new_config ); /* Check if the new configuration is supported. */ ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, &new_config, &failed ); if (ret) { D_DEBUG_AT( Core_LayerRegion, " -> FAILED 0x%08x\n", failed ); dfb_layer_region_unlock( region ); return ret; } /* Check if the region should be frozen, thus requiring to apply changes explicitly. */ if (flags & CLRCF_FREEZE) { D_DEBUG_AT( Core_LayerRegion, " -> FREEZE...\n" ); region->state |= CLRSF_FROZEN; } /* Propagate new configuration to the driver if the region is realized. */ if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) && !D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { ret = dfb_layer_region_set( region, &new_config, flags, region->surface ); if (ret) { dfb_layer_region_unlock( region ); return ret; } } /* Update the region's current configuration. */ region->config = new_config; /* Update the region's state. */ D_FLAGS_SET( region->state, CLRSF_CONFIGURED ); /* Unlock the region. */ dfb_layer_region_unlock( region ); D_DEBUG_AT( Core_LayerRegion, " -> done\n" ); return DFB_OK; } DFBResult dfb_layer_region_get_configuration( CoreLayerRegion *region, CoreLayerRegionConfig *ret_config ) { D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); D_ASSERT( ret_config != NULL ); D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); /* Lock the region. */ if (dfb_layer_region_lock( region )) return DFB_FUSION; /* Return the current configuration. */ *ret_config = region->config; /* Unlock the region. */ dfb_layer_region_unlock( region ); return DFB_OK; } ReactionResult _dfb_layer_region_surface_listener( const void *msg_data, void *ctx ) { CoreSurfaceNotificationFlags flags; CoreSurface *surface; CoreLayer *layer; CoreLayerShared *shared; const DisplayLayerFuncs *funcs; const CoreSurfaceNotification *notification = msg_data; CoreLayerRegion *region = ctx; D_ASSERT( notification != NULL ); D_ASSERT( notification->surface != NULL ); D_ASSERT( region != NULL ); D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p ) <- 0x%08x\n", __FUNCTION__, notification, region, notification->flags ); D_ASSUME( notification->surface == region->surface ); if (notification->surface != region->surface) return RS_OK; layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->SetRegion != NULL ); funcs = layer->funcs; shared = layer->shared; flags = notification->flags; surface = notification->surface; if (flags & CSNF_BUFFER_ALLOCATION_DESTROY) return RS_OK; if (flags & CSNF_DESTROY) { D_WARN( "layer region surface destroyed" ); region->surface = NULL; return RS_REMOVE; } if (flags & CSNF_DISPLAY) return RS_OK; if (dfb_layer_region_lock( region )) return RS_OK; if (D_FLAGS_ARE_SET( region->state, CLRSF_REALIZED | CLRSF_CONFIGURED ) && !D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { if (D_FLAGS_IS_SET( flags, CSNF_PALETTE_CHANGE | CSNF_PALETTE_UPDATE )) { if (surface->palette) { CoreSurfaceBufferLock left, right; dfb_surface_lock( surface ); /* Lock region buffer before it is used. */ region_buffer_lock( region, surface, DSBR_BACK, &left, &right ); D_ASSERT( left.buffer != NULL ); funcs->SetRegion( layer, layer->driver_data, layer->layer_data, region->region_data, ®ion->config, CLRCF_PALETTE, surface, surface->palette, &left, &right ); /* Unlock region buffer since the lock is no longer needed. */ region_buffer_unlock( region, &left, &right ); dfb_surface_unlock( surface ); } } if ((flags & CSNF_FIELD) && funcs->SetInputField) funcs->SetInputField( layer, layer->driver_data, layer->layer_data, region->region_data, surface->field ); if ((flags & CSNF_ALPHA_RAMP) && (shared->description.caps & DLCAPS_ALPHA_RAMP)) { CoreSurfaceBufferLock left, right; region->config.alpha_ramp[0] = surface->alpha_ramp[0]; region->config.alpha_ramp[1] = surface->alpha_ramp[1]; region->config.alpha_ramp[2] = surface->alpha_ramp[2]; region->config.alpha_ramp[3] = surface->alpha_ramp[3]; dfb_surface_lock( surface ); /* Lock region buffer before it is used. */ region_buffer_lock( region, surface, DSBR_BACK, &left, &right ); D_ASSERT( left.buffer != NULL ); funcs->SetRegion( layer, layer->driver_data, layer->layer_data, region->region_data, ®ion->config, CLRCF_ALPHA_RAMP, surface, surface->palette, &left, &right ); /* Unlock region buffer since the lock is no longer needed. */ region_buffer_unlock( region, &left, &right ); dfb_surface_unlock( surface ); } } dfb_layer_region_unlock( region ); return RS_OK; } /**********************************************************************************************************************/ static DFBResult region_buffer_unlock( CoreLayerRegion *region, CoreSurfaceBufferLock *left_buffer_lock, CoreSurfaceBufferLock *right_buffer_lock ) { DFBResult ret = DFB_OK; D_ASSERT( region != NULL ); D_ASSERT( left_buffer_lock != NULL ); D_DEBUG_AT( Core_LayerRegionLock, "%s( %p )\n", __FUNCTION__, region ); if (left_buffer_lock->buffer) D_DEBUG_AT( Core_LayerRegionLock, " -> lock buffer left %p\n", left_buffer_lock->buffer ); if (right_buffer_lock && right_buffer_lock->buffer) D_DEBUG_AT( Core_LayerRegionLock, " -> lock buffer right %p\n", right_buffer_lock->buffer ); /* Unlock any previously locked buffer. */ if (left_buffer_lock->buffer) { D_MAGIC_ASSERT( left_buffer_lock->buffer, CoreSurfaceBuffer ); ret = dfb_surface_unlock_buffer( left_buffer_lock->buffer->surface, left_buffer_lock ); } if (right_buffer_lock && right_buffer_lock->buffer) { D_MAGIC_ASSERT( right_buffer_lock->buffer, CoreSurfaceBuffer ); ret = dfb_surface_unlock_buffer( right_buffer_lock->buffer->surface, right_buffer_lock ); } return ret; } static DFBResult region_buffer_lock( CoreLayerRegion *region, CoreSurface *surface, DFBSurfaceBufferRole role, CoreSurfaceBufferLock *left_buffer_lock, CoreSurfaceBufferLock *right_buffer_lock ) { DFBResult ret; CoreSurfaceBuffer *buffer; bool stereo; D_ASSERT( region != NULL ); D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( left_buffer_lock != NULL ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_LayerRegionLock, "%s( %p, %p, role %u )\n", __FUNCTION__, region, surface, role ); Core_PushIdentity( FUSION_ID_MASTER ); /* Save current buffer focus. */ buffer = dfb_surface_get_buffer3( surface, role, DSSE_LEFT, region->surface_flip_count ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( Core_LayerRegionLock, " -> buffer %p\n", buffer ); /* Lock the surface buffer. */ ret = dfb_surface_buffer_lock( buffer, region->surface_accessor, CSAF_READ, left_buffer_lock ); if (ret) { D_DERROR( ret, "Core/LayerRegion: Could not lock region surface!\n" ); Core_PopIdentity(); return ret; } D_ASSERT( left_buffer_lock->allocation != NULL ); stereo = surface->config.caps & DSCAPS_STEREO; if (stereo) { D_ASSERT( right_buffer_lock != NULL ); buffer = dfb_surface_get_buffer3( surface, role, DSSE_RIGHT, region->surface_flip_count ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( Core_LayerRegionLock, " -> buffer %p\n", buffer ); /* Lock the surface buffer. */ ret = dfb_surface_buffer_lock( buffer, region->surface_accessor, CSAF_READ, right_buffer_lock ); if (ret) { D_DERROR( ret, "Core/LayerRegion: Could not lock region surface!\n" ); Core_PopIdentity(); return ret; } D_ASSERT( right_buffer_lock->allocation != NULL ); } else if (right_buffer_lock) { /* Clear for region_buffer_unlock(). */ right_buffer_lock->buffer = NULL; } Core_PopIdentity(); return DFB_OK; } DFBResult dfb_layer_region_set( CoreLayerRegion *region, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags flags, CoreSurface *surface ) { DFBResult ret; CoreLayer *layer; CoreLayerShared *shared; const DisplayLayerFuncs *funcs; CoreSurfaceBufferLock left, right; bool locked = false; D_UNUSED_P( shared ); D_DEBUG_AT( Core_LayerRegion, "%s( %p, %p, 0x%08x, %p )\n", __FUNCTION__, region, config, flags, surface ); D_ASSERT( region != NULL ); D_ASSERT( config != NULL ); D_ASSERT( config->buffermode != DLBM_WINDOWS ); D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_LayerRegion, config ); D_DEBUG_AT( Core_LayerRegion, " -> state 0x%08x\n", region->state ); layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); D_ASSERT( layer->funcs->SetRegion != NULL ); if (region->state & CLRSF_FROZEN) { D_DEBUG_AT( Core_LayerRegion, " -> FROZEN!\n" ); return DFB_OK; } shared = layer->shared; funcs = layer->funcs; if (surface) { if (flags & (CLRCF_SURFACE | CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT | CLRCF_SRCKEY | CLRCF_DSTKEY | CLRCF_OPACITY | CLRCF_SOURCE | CLRCF_DEST)) { dfb_surface_lock( surface ); ret = region_buffer_lock( region, surface, DSBR_FRONT, &left, &right ); dfb_surface_unlock( surface ); if (ret) return ret; locked = true; } } D_DEBUG_AT( Core_LayerRegion, " -> setting region of '%s'\n", shared->description.name ); /* Setup hardware. */ ret = funcs->SetRegion( layer, layer->driver_data, layer->layer_data, region->region_data, config, flags, surface, surface ? surface->palette : NULL, &left, &right ); if (ret) D_DERROR( ret, "Core/LayerRegion: Could not set region!\n" ); /* Unlock the region buffer since the lock is no longer necessary. */ if (locked) region_buffer_unlock( region, &left, &right ); return ret; } DFBResult dfb_layer_region_realize( CoreLayerRegion *region, bool set ) { DFBResult ret; CoreLayer *layer; CoreLayerShared *shared; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_LayerRegion, ®ion->config ); D_DEBUG_AT( Core_LayerRegion, " -> state 0x%08x\n", region->state ); if (region->state & CLRSF_FROZEN) { D_DEBUG_AT( Core_LayerRegion, " -> FROZEN!\n" ); return DFB_OK; } D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); D_ASSERT( !D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); shared = layer->shared; funcs = layer->funcs; D_ASSERT( !fusion_vector_contains( &shared->added_regions, region ) ); /* Allocate the driver's region data. */ if (funcs->RegionDataSize) { int size = funcs->RegionDataSize(); if (size > 0) { region->region_data = SHCALLOC( shared->shmpool, 1, size ); if (!region->region_data) return D_OOSHM(); } } D_DEBUG_AT( Core_LayerRegion, " -> adding region to '%s'\n", shared->description.name ); /* Add the region to the driver. */ if (funcs->AddRegion) { ret = funcs->AddRegion( layer, layer->driver_data, layer->layer_data, region->region_data, ®ion->config ); if (ret) { D_DERROR( ret, "Core/LayerRegion: Could not add region!\n" ); if (region->region_data) { SHFREE( shared->shmpool, region->region_data ); region->region_data = NULL; } return ret; } } /* Add the region to the 'added' list. */ fusion_vector_add( &shared->added_regions, region ); /* Update the region's state. */ D_FLAGS_SET( region->state, CLRSF_REALIZED ); /* Initially setup hardware. */ if (set) { ret = dfb_layer_region_set( region, ®ion->config, CLRCF_ALL, region->surface ); if (ret) { dfb_layer_region_unrealize( region ); return ret; } } return DFB_OK; } DFBResult dfb_layer_region_unrealize( CoreLayerRegion *region ) { DFBResult ret; int index; CoreLayer *layer; CoreLayerShared *shared; const DisplayLayerFuncs *funcs; D_DEBUG_AT( Core_LayerRegion, "%s( %p )\n", __FUNCTION__, region ); D_ASSERT( region != NULL ); D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_LayerRegion, ®ion->config ); D_DEBUG_AT( Core_LayerRegion, " -> state 0x%08x\n", region->state ); layer = dfb_layer_at( region->layer_id ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( layer->funcs != NULL ); shared = layer->shared; funcs = layer->funcs; D_ASSERT( fusion_vector_contains( &shared->added_regions, region ) ); index = fusion_vector_index_of( &shared->added_regions, region ); D_DEBUG_AT( Core_LayerRegion, " -> removing region from '%s'\n", shared->description.name ); /* Remove the region from hardware and driver. */ if (funcs->RemoveRegion) { ret = funcs->RemoveRegion( layer, layer->driver_data, layer->layer_data, region->region_data ); if (ret) { D_DERROR( ret, "Core/LayerRegion: Could not remove region!\n" ); return ret; } } /* Remove the region from the 'added' list. */ fusion_vector_remove( &shared->added_regions, index ); /* Deallocate the driver's region data. */ if (region->region_data) { SHFREE( shared->shmpool, region->region_data ); region->region_data = NULL; } /* Update the region's state. */ D_FLAGS_CLEAR( region->state, CLRSF_REALIZED ); D_FLAGS_SET( region->state, CLRSF_FROZEN ); /* Unlock the region buffer if it is locked. */ if (region->surface && !region->config.keep_buffers) dfb_surface_deallocate_buffers( region->surface ); return DFB_OK; } ================================================ FILE: src/core/layer_region.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__LAYER_REGION_H__ #define __CORE__LAYER_REGION_H__ #include #include /**********************************************************************************************************************/ typedef enum { CLRSF_NONE = 0x00000000, CLRSF_CONFIGURED = 0x00000001, CLRSF_ENABLED = 0x00000002, CLRSF_ACTIVE = 0x00000004, CLRSF_REALIZED = 0x00000008, CLRSF_FROZEN = 0x00000010, CLRSF_ALL = 0x0000001F } CoreLayerRegionStateFlags; typedef struct { int width; /* width of the source in pixels */ int height; /* height of the source in pixels */ DFBSurfacePixelFormat format; /* pixel format of the source surface */ DFBSurfaceColorSpace colorspace; /* color space of the source surface */ DFBSurfaceCapabilities surface_caps; /* capabilities of the source surface */ DFBDisplayLayerBufferMode buffermode; /* surface buffer configuration */ DFBDisplayLayerOptions options; /* various configuration options */ DFBDisplayLayerSourceID source_id; /* selected source */ DFBRectangle source; /* viewport within source (input) */ DFBRectangle dest; /* viewport on screen (output) */ u8 opacity; /* global region alpha */ DFBColorKey src_key; /* source color key */ DFBColorKey dst_key; /* destination color key */ int parity; /* field parity (for interlaced) */ u8 alpha_ramp[4]; /* alpha values for 1 or 2 bit lookup */ DFBRegion *clips; /* clip regions */ int num_clips; /* number of clip regions */ DFBBoolean positive; /* show or cut out regions */ bool keep_buffers; /* keep buffers */ } CoreLayerRegionConfig; #if D_DEBUG_ENABLED #define DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT(domain,config) \ do { \ D_DEBUG_AT( domain, " -> size %dx%d\n", (config)->width, (config)->height ); \ D_DEBUG_AT( domain, " -> format %s\n", dfb_pixelformat_name( (config)->format ) ); \ D_DEBUG_AT( domain, " -> color spc %u\n", (config)->colorspace ); \ D_DEBUG_AT( domain, " -> surf caps 0x%08x\n", (config)->surface_caps ); \ D_DEBUG_AT( domain, " -> buffermode %u\n", (config)->buffermode ); \ D_DEBUG_AT( domain, " -> options 0x%08x\n", (config)->options ); \ D_DEBUG_AT( domain, " -> source %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &(config)->source ) ); \ D_DEBUG_AT( domain, " -> dest %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &(config)->dest ) ); \ D_DEBUG_AT( domain, " -> opacity %d\n", (config)->opacity ); \ D_DEBUG_AT( domain, " -> src_key %02x%02x%02x (index %d)\n", DFB_COLORKEY_VALS( &(config)->src_key ) ); \ D_DEBUG_AT( domain, " -> dst_key %02x%02x%02x (index %d)\n", DFB_COLORKEY_VALS( &(config)->dst_key ) ); \ } while (0) #else #define DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT(domain,config) \ do { \ } while (0) #endif struct __DFB_CoreLayerRegion { FusionObject object; FusionObjectID context_id; FusionSkirmish lock; CoreLayerRegionStateFlags state; CoreLayerRegionConfig config; CoreSurface *surface; GlobalReaction surface_reaction; CoreSurfaceClient *surface_client; Reaction surface_event_reaction; void *region_data; CoreSurfaceAccessorID surface_accessor; FusionCall call; DFBDisplayLayerID layer_id; u32 surface_flip_count; }; /**********************************************************************************************************************/ typedef enum { CLRCF_NONE = 0x00000000, CLRCF_WIDTH = 0x00000001, CLRCF_HEIGHT = 0x00000002, CLRCF_FORMAT = 0x00000004, CLRCF_SURFACE_CAPS = 0x00000008, CLRCF_BUFFERMODE = 0x00000010, CLRCF_OPTIONS = 0x00000020, CLRCF_SOURCE_ID = 0x00000040, CLRCF_COLORSPACE = 0x00000080, CLRCF_SOURCE = 0x00000100, CLRCF_DEST = 0x00000200, CLRCF_CLIPS = 0x00000400, CLRCF_OPACITY = 0x00001000, CLRCF_ALPHA_RAMP = 0x00002000, CLRCF_SRCKEY = 0x00010000, CLRCF_DSTKEY = 0x00020000, CLRCF_PARITY = 0x00100000, CLRCF_SURFACE = 0x10000000, CLRCF_PALETTE = 0x20000000, CLRCF_FREEZE = 0x40000000, CLRCF_ALL = 0x701337FF } CoreLayerRegionConfigFlags; typedef enum { CLRNF_NONE = 0x00000000 } CoreLayerRegionNotificationFlags; typedef struct { CoreLayerRegionNotificationFlags flags; CoreLayerRegion *region; } CoreLayerRegionNotification; /**********************************************************************************************************************/ /* * Creates a pool of layer region objects. */ FusionObjectPool *dfb_layer_region_pool_create ( const FusionWorld *world ); /* * Generates dfb_layer_region_ref(), dfb_layer_region_attach() etc. */ FUSION_OBJECT_METHODS( CoreLayerRegion, dfb_layer_region ) /**********************************************************************************************************************/ DFBResult dfb_layer_region_create ( CoreLayerContext *context, CoreLayerRegion **ret_region ); DirectResult dfb_layer_region_lock ( CoreLayerRegion *region ); DirectResult dfb_layer_region_unlock ( CoreLayerRegion *region ); DFBResult dfb_layer_region_activate ( CoreLayerRegion *region ); DFBResult dfb_layer_region_deactivate ( CoreLayerRegion *region ); DFBResult dfb_layer_region_enable ( CoreLayerRegion *region ); DFBResult dfb_layer_region_disable ( CoreLayerRegion *region ); DFBResult dfb_layer_region_set_surface ( CoreLayerRegion *region, CoreSurface *surface, bool update ); DFBResult dfb_layer_region_get_surface ( CoreLayerRegion *region, CoreSurface **ret_surface ); DFBResult dfb_layer_region_flip_update ( CoreLayerRegion *region, const DFBRegion *update, DFBSurfaceFlipFlags flags ); DFBResult dfb_layer_region_flip_update_stereo( CoreLayerRegion *region, const DFBRegion *left_update, const DFBRegion *right_update, DFBSurfaceFlipFlags flags ); DFBResult dfb_layer_region_flip_update2 ( CoreLayerRegion *region, const DFBRegion *left_update, const DFBRegion *right_update, DFBSurfaceFlipFlags flags, unsigned int flip_count, long long pts ); /* * Configuration setting/getting. */ DFBResult dfb_layer_region_set_configuration ( CoreLayerRegion *region, const CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags flags ); DFBResult dfb_layer_region_get_configuration ( CoreLayerRegion *region, CoreLayerRegionConfig *ret_config ); /* * Global reaction, listen to the layer's surface. */ ReactionResult _dfb_layer_region_surface_listener ( const void *msg_data, void *ctx ); #endif ================================================ FILE: src/core/layers.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Layers, "Core/Layers", "DirectFB Core Display Layers" ); /**********************************************************************************************************************/ typedef struct { int magic; int num; CoreLayerShared *layers[MAX_LAYERS]; } DFBLayerCoreShared; typedef struct { int magic; CoreDFB *core; DFBLayerCoreShared *shared; } DFBLayerCore; DFB_CORE_PART( layer_core, LayerCore ); /**********************************************************************************************************************/ static int num_layers = 0; static CoreLayer *layers[MAX_LAYERS]; static DFBResult dfb_layer_core_initialize( CoreDFB *core, DFBLayerCore *data, DFBLayerCoreShared *shared ) { DFBResult ret; FusionSHMPoolShared *pool; int i; D_DEBUG_AT( Core_Layers, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; pool = dfb_core_shmpool( core ); /* Initialize all registered layers. */ for (i = 0; i < num_layers; i++) { CoreLayer *layer = layers[i]; CoreLayerShared *lshared; const DisplayLayerFuncs *funcs = layer->funcs; char buf[24]; /* Allocate shared data. */ lshared = SHCALLOC( pool, 1, sizeof(CoreLayerShared) ); /* Assign ID (zero based index). */ lshared->layer_id = i; lshared->shmpool = pool; snprintf( buf, sizeof(buf), "Display Layer %d", i ); /* Initialize the lock. */ ret = fusion_skirmish_init2( &lshared->lock, buf, dfb_core_world( core ), fusion_config->secure_fusion ); if (ret) { SHFREE( pool, lshared ); return DFB_FUSION; } /* Allocate driver's layer data. */ if (funcs->LayerDataSize) { int size = funcs->LayerDataSize(); if (size > 0) { lshared->layer_data = SHCALLOC( pool, 1, size ); if (!lshared->layer_data) { fusion_skirmish_destroy( &lshared->lock ); SHFREE( pool, lshared ); return D_OOSHM(); } } } /* Initialize the layer, get the layer description, the default configuration and default color adjustment. */ ret = funcs->InitLayer( layer, layer->driver_data, lshared->layer_data, &lshared->description, &lshared->default_config, &lshared->default_adjustment ); if (ret) { D_DERROR( ret, "Core/Layers: Failed to initialize layer %u!\n", lshared->layer_id ); fusion_skirmish_destroy( &lshared->lock ); if (lshared->layer_data) SHFREE( pool, lshared->layer_data ); SHFREE( pool, lshared ); return ret; } if (lshared->description.caps & DLCAPS_SOURCES) { int n; lshared->sources = SHCALLOC( pool, lshared->description.sources, sizeof(CoreLayerSource) ); for (n = 0; n < lshared->description.sources; n++) { CoreLayerSource *source = &lshared->sources[n]; source->index = n; funcs->InitSource( layer, layer->driver_data, lshared->layer_data, n, &source->description ); } } if (D_FLAGS_IS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION )) D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE ); if (D_FLAGS_ARE_SET( lshared->description.caps, DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE )) D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION ); /* Initialize the vector for the contexts. */ fusion_vector_init( &lshared->contexts.stack, 4, pool ); /* Initialize the vector for realized (added) regions. */ fusion_vector_init( &lshared->added_regions, 4, pool ); /* No active context by default. */ lshared->contexts.active = -1; /* Store layer data. */ layer->layer_data = lshared->layer_data; /* Store pointer to shared data and core. */ layer->shared = lshared; layer->core = core; CoreLayer_Init_Dispatch( core, layer, &lshared->call ); fusion_call_add_permissions( &lshared->call, 0, FUSION_CALL_PERMIT_EXECUTE ); /* Add the layer to the shared list. */ shared->layers[shared->num++] = lshared; } D_MAGIC_SET( data, DFBLayerCore ); D_MAGIC_SET( shared, DFBLayerCoreShared ); return DFB_OK; } static DFBResult dfb_layer_core_join( CoreDFB *core, DFBLayerCore *data, DFBLayerCoreShared *shared ) { int i; D_DEBUG_AT( Core_Layers, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBLayerCoreShared ); data->core = core; data->shared = shared; if (num_layers != shared->num) { D_ERROR( "Core/Layers: Number of layers does not match!\n" ); return DFB_BUG; } for (i = 0; i < num_layers; i++) { CoreLayer *layer = layers[i]; CoreLayerShared *lshared = shared->layers[i]; /* Make a copy for faster access. */ layer->layer_data = lshared->layer_data; /* Store pointer to shared data and core. */ layer->shared = lshared; layer->core = core; } D_MAGIC_SET( data, DFBLayerCore ); return DFB_OK; } static DFBResult dfb_layer_core_shutdown( DFBLayerCore *data, bool emergency ) { DFBResult ret; DFBLayerCoreShared *shared; int i; D_UNUSED_P( shared ); D_DEBUG_AT( Core_Layers, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBLayerCore ); D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); shared = data->shared; /* Begin with the most recently added layer. */ for (i = num_layers - 1; i >= 0; i--) { CoreLayer *layer = layers[i]; CoreLayerShared *lshared = layer->shared; const DisplayLayerFuncs *funcs = layer->funcs; D_ASSUME( emergency || fusion_vector_is_empty( &lshared->added_regions ) ); /* Remove all regions during emergency shutdown. */ if (emergency && funcs->RemoveRegion) { int n; CoreLayerRegion *region; fusion_vector_foreach (region, n, lshared->added_regions) { D_DEBUG_AT( Core_Layers, " -> removing region (%4d,%4d-%4dx%4d) from '%s'\n", DFB_RECTANGLE_VALS( ®ion->config.dest ), lshared->description.name ); ret = funcs->RemoveRegion( layer, layer->driver_data, layer->layer_data, region->region_data ); if (ret) D_DERROR( ret, "Core/Layers: Could not remove region!\n" ); } } /* Shut the layer down. */ if (funcs->ShutdownLayer) { ret = funcs->ShutdownLayer( layer, layer->driver_data, lshared->layer_data ); if (ret) D_DERROR( ret, "Core/Layers: Failed to shutdown layer %u!\n", lshared->layer_id ); } CoreLayer_Deinit_Dispatch( &lshared->call ); /* Deinitialize the lock. */ fusion_skirmish_destroy( &lshared->lock ); /* Deinitialize the state for window stack repaints. */ dfb_state_destroy( &layer->state ); /* Deinitialize the vector for the contexts. */ fusion_vector_destroy( &lshared->contexts.stack ); /* Deinitialize the vector for the realized (added) regions. */ fusion_vector_destroy( &lshared->added_regions ); /* Free the driver's layer data. */ if (lshared->layer_data) SHFREE( lshared->shmpool, lshared->layer_data ); /* Free the shared layer data. */ SHFREE( lshared->shmpool, lshared ); /* Free the local layer data. */ D_FREE( layer ); } num_layers = 0; D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_layer_core_leave( DFBLayerCore *data, bool emergency ) { int i; D_DEBUG_AT( Core_Layers, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBLayerCore ); D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); /* Deinitialize all local stuff. */ for (i = 0; i < num_layers; i++) { CoreLayer *layer = layers[i]; /* Deinitialize the state for window stack repaints. */ dfb_state_destroy( &layer->state ); /* Free local layer data. */ D_FREE( layer ); } num_layers = 0; D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_layer_core_suspend( DFBLayerCore *data ) { int i; D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBLayerCore ); D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); for (i = num_layers - 1; i >= 0; i--) dfb_layer_suspend( layers[i] ); return DFB_OK; } static DFBResult dfb_layer_core_resume( DFBLayerCore *data ) { int i; D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBLayerCore ); D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); for (i = 0; i < num_layers; i++) dfb_layer_resume( layers[i] ); return DFB_OK; } /**********************************************************************************************************************/ CoreLayer * dfb_layers_register( CoreScreen *screen, void *driver_data, const DisplayLayerFuncs *funcs ) { CoreLayer *layer; D_ASSERT( screen != NULL ); D_ASSERT( funcs != NULL ); if (num_layers == MAX_LAYERS) { D_ERROR( "Core/Layers: Maximum number of layers reached!\n" ); return NULL; } /* Allocate local data. */ layer = D_CALLOC( 1, sizeof(CoreLayer) ); /* Assign local pointers. */ layer->screen = screen; layer->driver_data = driver_data; layer->funcs = funcs; /* Initialize the state for window stack repaints. */ dfb_state_init( &layer->state, NULL ); /* Add it to the local list. */ layers[num_layers++] = layer; return layer; } typedef void (*AnyFunc)( void ); CoreLayer * dfb_layers_hook_primary( void *driver_data, DisplayLayerFuncs *funcs, DisplayLayerFuncs *primary_funcs, void **primary_driver_data ) { int i; int entries; CoreLayer *primary = layers[0]; D_ASSERT( primary != NULL ); D_ASSERT( funcs != NULL ); /* Copy content of original function table. */ if (primary_funcs) direct_memcpy( primary_funcs, primary->funcs, sizeof(DisplayLayerFuncs) ); /* Copy pointer to original driver data. */ if (primary_driver_data) *primary_driver_data = primary->driver_data; /* Replace all entries in the old table that aren't NULL in the new one. */ entries = sizeof(DisplayLayerFuncs) / sizeof(void (*)( void )); for (i = 0; i < entries; i++) { AnyFunc *newfuncs = (AnyFunc*) funcs; AnyFunc *oldfuncs = (AnyFunc*) primary->funcs; if (newfuncs[i]) oldfuncs[i] = newfuncs[i]; } /* Replace driver data pointer. */ primary->driver_data = driver_data; return primary; } void dfb_layer_get_description( const CoreLayer *layer, DFBDisplayLayerDescription *ret_desc ) { CoreLayerShared *shared; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( ret_desc != NULL ); shared = layer->shared; *ret_desc = shared->description; } DFBSurfacePixelFormat dfb_primary_layer_pixelformat() { CoreLayerShared *shared; CoreLayer *layer = dfb_layer_at_translated( DLID_PRIMARY ); D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; return shared->pixelformat; } void dfb_layers_enumerate( DisplayLayerCallback callback, void *ctx ) { int i; D_ASSERT( callback != NULL ); for (i = 0; i < num_layers; i++) { if (callback( layers[i], ctx ) == DFENUM_CANCEL) break; } } int dfb_layers_num() { return num_layers; } CoreLayer * dfb_layer_at( DFBDisplayLayerID id ) { D_ASSERT( id >= 0 ); D_ASSERT( id < num_layers ); return layers[id]; } CoreLayer * dfb_layer_at_translated( DFBDisplayLayerID id ) { D_ASSERT( id >= 0 ); D_ASSERT( id < num_layers ); D_ASSERT( dfb_config != NULL ); if (dfb_config->primary_layer > 0 && dfb_config->primary_layer < num_layers) { if (id == DLID_PRIMARY) return dfb_layer_at( dfb_config->primary_layer ); if (id == dfb_config->primary_layer) return dfb_layer_at( DLID_PRIMARY ); } return dfb_layer_at( id ); } DFBDisplayLayerID dfb_layer_id( const CoreLayer *layer ) { CoreLayerShared *shared; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); shared = layer->shared; return shared->layer_id; } DFBDisplayLayerID dfb_layer_id_translated( const CoreLayer *layer ) { CoreLayerShared *shared; D_ASSERT( layer != NULL ); D_ASSERT( layer->shared != NULL ); D_ASSERT( dfb_config != NULL ); shared = layer->shared; if (dfb_config->primary_layer > 0 && dfb_config->primary_layer < num_layers) { if (shared->layer_id == DLID_PRIMARY) return dfb_config->primary_layer; if (shared->layer_id == dfb_config->primary_layer) return DLID_PRIMARY; } return shared->layer_id; } ================================================ FILE: src/core/layers.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__LAYERS_H__ #define __CORE__LAYERS_H__ #include #include /**********************************************************************************************************************/ typedef struct { /* * Return size of layer data (shared memory). */ int (*LayerDataSize) ( void ); /* * Return size of region data (shared memory). */ int (*RegionDataSize) ( void ); /* * Called once by the master to initialize layer data and reset hardware. * Return layer description, default configuration and color adjustment. */ DFBResult (*InitLayer) ( CoreLayer *layer, void *driver_data, void *layer_data, DFBDisplayLayerDescription *description, DFBDisplayLayerConfig *config, DFBColorAdjustment *adjustment ); /* * Called once by the master to shutdown the layer. * Use this function to free any resources that were taken during init. */ DFBResult (*ShutdownLayer) ( CoreLayer *layer, void *driver_data, void *layer_data ); /* * Called once by the master for each source. * Driver fills description. */ DFBResult (*InitSource) ( CoreLayer *layer, void *driver_data, void *layer_data, int source, DFBDisplayLayerSourceDescription *description ); /* * Return the currently displayed field (interlaced only). */ DFBResult (*GetCurrentOutputField)( CoreLayer *layer, void *driver_data, void *layer_data, int *field ); /* * Return the z position of the layer. */ DFBResult (*GetLevel) ( CoreLayer *layer, void *driver_data, void *layer_data, int *level ); /* * Move the layer below or on top of others (z position). */ DFBResult (*SetLevel) ( CoreLayer *layer, void *driver_data, void *layer_data, int level ); /* * Adjust brightness, contrast, saturation etc. */ DFBResult (*SetColorAdjustment) ( CoreLayer *layer, void *driver_data, void *layer_data, DFBColorAdjustment *adjustment ); /* * Set the stereo depth for L/R mono and stereo layers. */ DFBResult (*SetStereoDepth) ( CoreLayer *layer, void *driver_data, void *layer_data, bool follow_video, int z ); /* * Check all parameters and return if this region is supported. */ DFBResult (*TestRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags *ret_failed ); /* * Add a new region to the layer, but don't program hardware, yet. */ DFBResult (*AddRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config ); /* * Setup hardware, called once after AddRegion() or when parameters have changed. * Surface and palette are only set if updated or new. */ DFBResult (*SetRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags updated, CoreSurface *surface, CorePalette *palette, CoreSurfaceBufferLock *left_lock, CoreSurfaceBufferLock *right_lock ); /* * Remove a region from the layer. */ DFBResult (*RemoveRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data ); /* * Flip the surface of the region. */ DFBResult (*FlipRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, DFBSurfaceFlipFlags flags, const DFBRegion *left_update, CoreSurfaceBufferLock *left_lock, const DFBRegion *right_update, CoreSurfaceBufferLock *right_lock ); /* * Indicate updates to the front buffer content. */ DFBResult (*UpdateRegion) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, const DFBRegion *left_update, CoreSurfaceBufferLock *left_lock, const DFBRegion *right_update, CoreSurfaceBufferLock *right_lock ); /* * Control hardware deinterlacing. */ DFBResult (*SetInputField) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, int field ); /* * Allocate the surface of the region. */ DFBResult (*AllocateSurface) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreSurface **ret_surface ); /* * Reallocate the surface of the region. */ DFBResult (*ReallocateSurface) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreSurface *surface ); /* * Deallocate the surface of the region. */ DFBResult (*DeallocateSurface) ( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface ); } DisplayLayerFuncs; typedef struct { int index; DFBDisplayLayerSourceDescription description; } CoreLayerSource; typedef struct { FusionVector stack; int active; CoreLayerContext *primary; } CoreLayerContexts; typedef struct { DFBDisplayLayerID layer_id; DFBDisplayLayerDescription description; DFBDisplayLayerConfig default_config; DFBColorAdjustment default_adjustment; CoreLayerSource *sources; FusionSHMPoolShared *shmpool; void *layer_data; /* local data (impl) */ FusionSkirmish lock; CoreLayerContexts contexts; bool suspended; FusionVector added_regions; FusionCall call; /* dispatch */ DFBSurfacePixelFormat pixelformat; } CoreLayerShared; struct __DFB_CoreLayer { CoreLayerShared *shared; CoreDFB *core; CoreScreen *screen; void *driver_data; void *layer_data; /* copy of shared->layer_data */ CardState state; const DisplayLayerFuncs *funcs; }; /**********************************************************************************************************************/ typedef DFBEnumerationResult (*DisplayLayerCallback)( CoreLayer *layer, void *ctx ); /**********************************************************************************************************************/ /* * Add a layer to a graphics device by pointing to a table containing driver functions. * The supplied 'driver_data' will be passed to these functions. */ CoreLayer *dfb_layers_register ( CoreScreen *screen, void *driver_data, const DisplayLayerFuncs *funcs ); /* * Replace functions of the primary layer implementation by passing an alternative driver function table. * All non-NULL functions in the new table replace the functions in the original function table. * The original function table is written to 'primary_funcs' before to allow drivers to use existing functionality * from the original implementation. */ CoreLayer *dfb_layers_hook_primary ( void *driver_data, DisplayLayerFuncs *funcs, DisplayLayerFuncs *primary_funcs, void **primary_driver_data ); /* * Get the description of the specified layer. */ void dfb_layer_get_description ( const CoreLayer *layer, DFBDisplayLayerDescription *ret_desc ); /* * Return the pixel format of the primary layer. */ DFBSurfacePixelFormat dfb_primary_layer_pixelformat( void ); /* * Enumerate all registered layers by invoking the callback for each layer. */ void dfb_layers_enumerate ( DisplayLayerCallback callback, void *ctx ); /* * Return the number of layers. */ int dfb_layers_num ( void ); /* * Return the layer with the specified ID. */ CoreLayer *dfb_layer_at ( DFBDisplayLayerID id ); /* * Return the (translated) layer with the specified ID. */ CoreLayer *dfb_layer_at_translated ( DFBDisplayLayerID id ); /* * Return the ID of the specified layer. */ DFBDisplayLayerID dfb_layer_id ( const CoreLayer *layer ); /* * Return the (translated) ID of the specified layer. */ DFBDisplayLayerID dfb_layer_id_translated ( const CoreLayer *layer ); #endif ================================================ FILE: src/core/local_surface_pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Core_Local, "Core/Local", "DirectFB Core Local Surface Pool" ); /**********************************************************************************************************************/ typedef struct { int magic; void *addr; int pitch; int size; } LocalAllocationData; /**********************************************************************************************************************/ static int localAllocationDataSize( void ) { return sizeof(LocalAllocationData); } static DFBResult localInitPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ) { D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( ret_desc != NULL ); ret_desc->caps = CSPCAPS_VIRTUAL; ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_INTERNAL; ret_desc->priority = CSPP_DEFAULT; if (dfb_system_caps() & CSCAPS_SYSMEM_EXTERNAL) ret_desc->types |= CSTF_EXTERNAL; snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "System Memory" ); return DFB_OK; } static DFBResult localJoinPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data ) { D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return DFB_OK; } static DFBResult localDestroyPool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return DFB_OK; } static DFBResult localLeavePool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); return DFB_OK; } static DFBResult localAllocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { CoreSurface *surface; LocalAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( alloc != NULL ); surface = buffer->surface; /* Create aligned local system surface buffer if both base address and pitch are non-zero. */ if (dfb_config->system_surface_align_base && dfb_config->system_surface_align_pitch) { /* Make sure base address and pitch are a positive power of two. */ D_ASSERT( dfb_config->system_surface_align_base >= 4 ); D_ASSERT( !(dfb_config->system_surface_align_base & (dfb_config->system_surface_align_base - 1)) ); D_ASSERT( dfb_config->system_surface_align_pitch >= 2 ); D_ASSERT( !(dfb_config->system_surface_align_pitch & (dfb_config->system_surface_align_pitch - 1)) ); dfb_surface_calc_buffer_size( surface, dfb_config->system_surface_align_pitch, 0, &alloc->pitch, &alloc->size ); /* posix_memalign() function requires base alignment to actually be at least four. */ int err = posix_memalign( &alloc->addr, dfb_config->system_surface_align_base, alloc->size ); if (err) { D_ERROR( "Core/Local: Error from posix_memalign with base alignment %u\n", dfb_config->system_surface_align_base ); return DFB_FAILURE; } } /* Create un-aligned local system surface buffer. */ else { dfb_surface_calc_buffer_size( surface, 8, 0, &alloc->pitch, &alloc->size ); alloc->addr = D_MALLOC( alloc->size ); if (!alloc->addr) return D_OOM(); } D_MAGIC_SET( alloc, LocalAllocationData ); allocation->flags = CSALF_VOLATILE; allocation->size = alloc->size; return DFB_OK; } static DFBResult localDeallocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { LocalAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( alloc, LocalAllocationData ); if (dfb_config->system_surface_align_base && dfb_config->system_surface_align_pitch) /* This was allocated by posix_memalign() function and requires free(). */ free( alloc->addr ); else D_FREE( alloc->addr ); D_MAGIC_CLEAR( alloc ); return DFB_OK; } static DFBResult localLock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { LocalAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Local, "%s() <- size %d\n", __FUNCTION__, alloc->size ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); D_MAGIC_ASSERT( alloc, LocalAllocationData ); lock->addr = alloc->addr; lock->pitch = alloc->pitch; return DFB_OK; } static DFBResult localUnlock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { LocalAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Local, "%s()\n", __FUNCTION__ ); D_UNUSED_P( alloc ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); D_MAGIC_ASSERT( alloc, LocalAllocationData ); return DFB_OK; } const SurfacePoolFuncs localSurfacePoolFuncs = { .AllocationDataSize = localAllocationDataSize, .InitPool = localInitPool, .JoinPool = localJoinPool, .DestroyPool = localDestroyPool, .LeavePool = localLeavePool, .AllocateBuffer = localAllocateBuffer, .DeallocateBuffer = localDeallocateBuffer, .Lock = localLock, .Unlock = localUnlock }; ================================================ FILE: src/core/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA flux_files = [ 'CoreDFB', 'CoreGraphicsState', 'CoreInputDevice', 'CoreLayer', 'CoreLayerContext', 'CoreLayerRegion', 'CorePalette', 'CoreSlave', 'CoreScreen', 'CoreSurface', 'CoreSurfaceAllocation', 'CoreSurfaceClient', 'CoreWindow', 'CoreWindowStack' ] fluxcomp = find_program(get_option('fluxcomp')) flux_sources = [] foreach flux_file : flux_files flux_sources += custom_target(flux_file, input: flux_file + '.flux', output: [flux_file + '.c', flux_file + '.h'], command: [fluxcomp, '--call-mode', '--dispatch-error-abort', '--identity', '--include-prefix=core', '--object-ptrs', '--static-args-bytes=FLUXED_ARGS_BYTES', '-c', '@INPUT@', '-o=src/core']) endforeach ================================================ FILE: src/core/palette.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Palette, "Core/Palette", "DirectFB Core Palette" ); /**********************************************************************************************************************/ static const ReactionFunc dfb_palette_globals[] = { _dfb_surface_palette_listener, NULL }; static void palette_destructor( FusionObject *object, bool zombie, void *ctx ) { CorePaletteNotification notification; CorePalette *palette = (CorePalette*) object; D_MAGIC_ASSERT( palette, CorePalette ); D_ASSERT( palette->entries != NULL ); D_ASSERT( palette->entries_yuv != NULL ); D_DEBUG_AT( Core_Palette, "Destroying palette %p (%u%s)\n", palette, palette->num_entries, zombie ? " ZOMBIE" : "" ); notification.flags = CPNF_DESTROY; notification.palette = palette; dfb_palette_dispatch( palette, ¬ification, dfb_palette_globals ); dfb_colorhash_invalidate( NULL, palette ); SHFREE( palette->shmpool, palette->entries_yuv ); SHFREE( palette->shmpool, palette->entries ); CorePalette_Deinit_Dispatch( &palette->call ); D_MAGIC_CLEAR( palette ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_palette_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Palette Pool", sizeof(CorePalette), sizeof(CorePaletteNotification), palette_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_palette_create( CoreDFB *core, unsigned int size, DFBSurfaceColorSpace colorspace, CorePalette **ret_palette ) { CorePalette *palette; D_ASSERT( ret_palette ); D_DEBUG_AT( Core_Palette, "%s( %u )\n", __FUNCTION__, size ); /* Create the palette object. */ palette = dfb_core_create_palette( core ); if (!palette) return DFB_FUSION; palette->shmpool = dfb_core_shmpool( core ); if (size) { palette->entries = SHCALLOC( palette->shmpool, size, sizeof(DFBColor) ); if (!palette->entries) { fusion_object_destroy( &palette->object ); return D_OOSHM(); } palette->entries_yuv = SHCALLOC( palette->shmpool, size, sizeof(DFBColorYUV) ); if (!palette->entries_yuv) { SHFREE( palette->shmpool, palette->entries ); fusion_object_destroy( &palette->object ); return D_OOSHM(); } } palette->num_entries = size; palette->colorspace = colorspace; CorePalette_Init_Dispatch( core, palette, &palette->call ); D_MAGIC_SET( palette, CorePalette ); /* Activate the object. */ fusion_object_activate( &palette->object ); /* Return the new palette. */ *ret_palette = palette; D_DEBUG_AT( Core_Palette, " -> %p\n", palette ); return DFB_OK; } static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; void dfb_palette_generate_rgb332_map( CorePalette *palette ) { unsigned int i; DFBColor entries[256]; D_DEBUG_AT( Core_Palette, "%s( %p )\n", __FUNCTION__, palette ); D_MAGIC_ASSERT( palette, CorePalette ); if (!palette->num_entries) return; for (i = 0; i < palette->num_entries; i++) { entries[i].a = i ? 0xff : 0x00; entries[i].r = lookup3to8[(i & 0xE0) >> 5]; entries[i].g = lookup3to8[(i & 0x1C) >> 2]; entries[i].b = lookup2to8[(i & 0x03)]; } CorePalette_SetEntries( palette, entries, palette->num_entries, 0 ); } void dfb_palette_generate_rgb121_map( CorePalette *palette ) { unsigned int i; DFBColor entries[256]; D_DEBUG_AT( Core_Palette, "%s( %p )\n", __FUNCTION__, palette ); D_MAGIC_ASSERT( palette, CorePalette ); if (!palette->num_entries) return; for (i = 0; i < palette->num_entries; i++) { entries[i].a = i ? 0xff : 0x00; entries[i].r = (i & 0x8) ? 0xff : 0x00; entries[i].g = lookup2to8[(i & 0x6) >> 1]; entries[i].b = (i & 0x1) ? 0xff : 0x00; } CorePalette_SetEntries( palette, entries, palette->num_entries, 0 ); } unsigned int dfb_palette_search( CorePalette *palette, u8 r, u8 g, u8 b, u8 a ) { unsigned int index; D_DEBUG_AT( Core_Palette, "%s( %p )\n", __FUNCTION__, palette ); D_MAGIC_ASSERT( palette, CorePalette ); index = dfb_colorhash_lookup( NULL, palette, r, g, b, a ); return index; } void dfb_palette_update( CorePalette *palette, int first, int last ) { CorePaletteNotification notification; D_DEBUG_AT( Core_Palette, "%s( %p, %d, %d )\n", __FUNCTION__, palette, first, last ); D_MAGIC_ASSERT( palette, CorePalette ); D_ASSERT( first >= 0 ); D_ASSERT( first < palette->num_entries ); D_ASSERT( last >= 0 ); D_ASSERT( last < palette->num_entries ); D_ASSERT( first <= last ); notification.flags = CPNF_ENTRIES; notification.palette = palette; notification.first = first; notification.last = last; dfb_colorhash_invalidate( NULL, palette ); dfb_palette_dispatch( palette, ¬ification, dfb_palette_globals ); } bool dfb_palette_equal( CorePalette *palette1, CorePalette *palette2 ) { u32 *entries1; u32 *entries2; int i; D_DEBUG_AT( Core_Palette, "%s( %p, %p )\n", __FUNCTION__, palette1, palette2 ); D_ASSERT( palette1 != NULL ); D_ASSERT( palette2 != NULL ); if (palette1 == palette2) { D_DEBUG_AT( Core_Palette, " -> SAME\n" ); return true; } if (palette1->num_entries != palette2->num_entries) { D_DEBUG_AT( Core_Palette, " -> NOT EQUAL (%u/%u)\n", palette1->num_entries, palette2->num_entries ); return false; } entries1 = (u32*) palette1->entries; entries2 = (u32*) palette2->entries; for (i = 0; i < palette1->num_entries; i++) { if (entries1[i] != entries2[i]) { D_DEBUG_AT( Core_Palette, " -> NOT EQUAL (%d)\n", i ); return false; } } D_DEBUG_AT( Core_Palette, " -> EQUAL\n" ); return true; } ================================================ FILE: src/core/palette.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__PALETTE_H__ #define __CORE__PALETTE_H__ #include #include /**********************************************************************************************************************/ struct __DFB_CorePalette { FusionObject object; int magic; unsigned int num_entries; DFBColor *entries; DFBColorYUV *entries_yuv; DFBSurfaceColorSpace colorspace; FusionSHMPoolShared *shmpool; FusionCall call; }; /**********************************************************************************************************************/ typedef enum { CPNF_ENTRIES = 0x00000001, CPNF_DESTROY = 0x00000002 } CorePaletteNotificationFlags; typedef struct { CorePaletteNotificationFlags flags; CorePalette *palette; int first; int last; } CorePaletteNotification; /**********************************************************************************************************************/ /* * Creates a pool of palette objects. */ FusionObjectPool *dfb_palette_pool_create ( const FusionWorld *world ); /* * Generates dfb_palette_ref(), dfb_palette_attach() etc. */ FUSION_OBJECT_METHODS( CorePalette, dfb_palette ) typedef enum { DFB_SURFACE_PALETTE_LISTENER = 0x00000000 } DFB_PALETTE_GLOBALS; /**********************************************************************************************************************/ DFBResult dfb_palette_create ( CoreDFB *core, unsigned int size, DFBSurfaceColorSpace colorspace, CorePalette **ret_palette ); void dfb_palette_generate_rgb332_map( CorePalette *palette ); void dfb_palette_generate_rgb121_map( CorePalette *palette ); unsigned int dfb_palette_search ( CorePalette *palette, u8 r, u8 g, u8 b, u8 a ); void dfb_palette_update ( CorePalette *palette, int first, int last ); bool dfb_palette_equal ( CorePalette *palette1, CorePalette *palette2 ); #endif ================================================ FILE: src/core/prealloc_surface_pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Core_PreAlloc, "Core/PreAlloc", "DirectFB Core PreAlloc Surface Pool" ); /**********************************************************************************************************************/ typedef struct { void *addr; int pitch; } PreallocAllocationData; /**********************************************************************************************************************/ static int preallocAllocationDataSize( void ) { return sizeof(PreallocAllocationData); } static DFBResult preallocInitPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ) { D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( ret_desc != NULL ); ret_desc->caps = CSPCAPS_NONE; ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE; ret_desc->types = CSTF_PREALLOCATED | CSTF_INTERNAL; ret_desc->priority = CSPP_DEFAULT; snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Preallocated Memory" ); return DFB_OK; } static DFBResult preallocTestConfig( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, const CoreSurfaceConfig *config ) { D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( config != NULL ); if (!(config->flags & CSCONF_PREALLOCATED)) return DFB_UNSUPPORTED; if (Core_GetIdentity() != buffer->surface->object.identity) return DFB_UNSUPPORTED; return DFB_OK; } static DFBResult preallocAllocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { int index; CoreSurface *surface; PreallocAllocationData *alloc = alloc_data; FusionID identity = Core_GetIdentity(); D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); surface = buffer->surface; D_DEBUG_AT( Core_PreAlloc, " -> surface identity %lu\n", surface->object.identity ); D_DEBUG_AT( Core_PreAlloc, " -> core identity %lu\n", identity ); if (!(surface->config.flags & CSCONF_PREALLOCATED)) return DFB_BUG; if (identity != surface->object.identity) { D_ERROR( "Core/PreAlloc: Cannot allocate buffer for other (%lu) than creator (%lu)!\n", identity, surface->object.identity ); return DFB_ACCESSDENIED; } index = dfb_surface_buffer_index( buffer ); if (!surface->config.preallocated[index].addr || surface->config.preallocated[index].pitch < DFB_BYTES_PER_LINE(surface->config.format, surface->config.size.w)) { return DFB_BUG; } alloc->addr = surface->config.preallocated[index].addr; alloc->pitch = surface->config.preallocated[index].pitch; allocation->flags = CSALF_PREALLOCATED; allocation->size = surface->config.preallocated[index].pitch * DFB_PLANE_MULTIPLY( surface->config.format, surface->config.size.h ); return DFB_OK; } static DFBResult preallocDeallocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); return DFB_OK; } static DFBResult preallocLock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { CoreSurface *surface; PreallocAllocationData *alloc = alloc_data; FusionID identity = Core_GetIdentity(); D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->surface, CoreSurface ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); surface = allocation->surface; if (identity != surface->object.identity) { D_ERROR( "Core/PreAlloc: Cannot lock buffer by other (%lu) than creator (%lu)!\n", identity, surface->object.identity ); return DFB_ACCESSDENIED; } lock->addr = alloc->addr; lock->pitch = alloc->pitch; return DFB_OK; } static DFBResult preallocUnlock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); return DFB_OK; } static DFBResult preallocPrealloc( CoreSurfacePool *pool, void *pool_data, void *pool_local, const DFBSurfaceDescription *description, CoreSurfaceConfig *config ) { unsigned int i, num = 1; D_DEBUG_AT( Core_PreAlloc, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); if (config->caps & DSCAPS_VIDEOONLY) return DFB_UNSUPPORTED; if (config->caps & DSCAPS_DOUBLE) num = 2; else if (config->caps & DSCAPS_TRIPLE) num = 3; for (i = 0; i < num; i++) { config->preallocated[i].addr = description->preallocated[i].data; config->preallocated[i].pitch = description->preallocated[i].pitch; } return DFB_OK; } const SurfacePoolFuncs preallocSurfacePoolFuncs = { .AllocationDataSize = preallocAllocationDataSize, .InitPool = preallocInitPool, .TestConfig = preallocTestConfig, .AllocateBuffer = preallocAllocateBuffer, .DeallocateBuffer = preallocDeallocateBuffer, .Lock = preallocLock, .Unlock = preallocUnlock, .PreAlloc = preallocPrealloc }; ================================================ FILE: src/core/prealloc_surface_pool_bridge.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( PreAlloc_Bridge, "Core/PreAlloc/Bridge", "DirectFB Core PreAlloc Surface Pool Bridge" ); /**********************************************************************************************************************/ typedef struct { CoreSurfacePool *shared_pool; CoreSurfacePool *prealloc_pool; } preallocPoolBridgeData; /**********************************************************************************************************************/ static int preallocPoolBridgeDataSize( void ) { return sizeof(preallocPoolBridgeData); } static DFBResult preallocInitPoolBridge( CoreDFB *core, CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, void *ctx, CoreSurfacePoolBridgeDescription *ret_desc ) { preallocPoolBridgeData *data = bridge_data; DFBSurfaceCore *sc = ctx; DFBSurfaceCoreShared *shared; D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge_data != NULL ); D_ASSERT( sc != NULL ); D_ASSERT( sc->shared != NULL ); D_ASSERT( ret_desc != NULL ); shared = sc->shared; ret_desc->caps = CSPBCAPS_NONE; snprintf( ret_desc->name, DFB_SURFACE_POOL_BRIDGE_DESC_NAME_LENGTH, "PreAlloc Pool Bridge" ); data->shared_pool = shared->surface_pool; data->prealloc_pool = shared->prealloc_pool; return DFB_OK; } static DFBResult preallocJoinPoolBridge( CoreDFB *core, CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, void *ctx ) { D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge_data != NULL ); D_ASSERT( ctx != NULL ); return DFB_OK; } static DFBResult preallocDestroyPoolBridge( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local ) { D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); return DFB_OK; } static DFBResult preallocLeavePoolBridge( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local ) { D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); return DFB_OK; } static DFBResult preallocCheckTransfer( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *from, CoreSurfaceAllocation *to ) { preallocPoolBridgeData *data = bridge_data; D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_ASSERT( bridge_data != NULL ); if (!Core_Resource_GetSlave( buffer->surface->object.identity )) { D_DEBUG_AT( PreAlloc_Bridge, " -> no slave\n" ); return DFB_NOIMPL; } if (from->pool == data->prealloc_pool) { D_DEBUG_AT( PreAlloc_Bridge, " -> from preallocated\n" ); return DFB_OK; } if (to->pool == data->prealloc_pool) { D_DEBUG_AT( PreAlloc_Bridge, " -> to preallocated\n" ); return DFB_OK; } return DFB_UNSUPPORTED; } static DFBResult prealloc_transfer_locked( CoreSurface *surface, CoreSurfacePoolTransfer *transfer, CoreSurfaceAllocation *locked, CoreSurfaceAccessFlags flags, CoreSlave *slave ) { DFBResult ret; CoreSurfaceBufferLock lock; int index; int i, y; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( transfer != NULL ); CORE_SURFACE_ALLOCATION_ASSERT( locked ); index = dfb_surface_buffer_index( locked->buffer ); D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( PreAlloc_Bridge, " -> transfer locked %s Fusion ID %lu (index %d)\n", (flags & CSAF_WRITE) ? "from" : "to", surface->object.identity, index ); dfb_surface_buffer_lock_init( &lock, CSAID_CPU, flags ); ret = dfb_surface_pool_lock( locked->pool, locked, &lock ); if (ret) { dfb_surface_buffer_lock_deinit( &lock ); return ret; } for (i = 0; i < transfer->num_rects; i++) { const DFBRectangle *rect = &transfer->rects[i]; int offset = DFB_BYTES_PER_LINE( surface->config.format, rect->x ); int length = DFB_BYTES_PER_LINE( surface->config.format, rect->w ); for (y = 0; y < rect->h; y++) { if (flags & CSAF_WRITE) ret = CoreSlave_GetData( slave, surface->config.preallocated[index].addr + (rect->y + y) * surface->config.preallocated[index].pitch + offset, length, lock.addr + (rect->y + y) * lock.pitch + offset ); else ret = CoreSlave_PutData( slave, surface->config.preallocated[index].addr + (rect->y + y) * surface->config.preallocated[index].pitch + offset, length, lock.addr + (rect->y + y) * lock.pitch + offset ); if (ret) break; } if (ret) break; } dfb_surface_pool_unlock( locked->pool, locked, &lock ); dfb_surface_buffer_lock_deinit( &lock ); return ret; } static DFBResult prealloc_transfer_readwrite( CoreSurface *surface, CoreSurfacePoolTransfer *transfer, CoreSurfaceAllocation *allocation, CoreSurfaceAccessFlags flags, CoreSlave *slave ) { DFBResult ret = DFB_OK; int index; int i, y; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( transfer != NULL ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); index = dfb_surface_buffer_index( allocation->buffer ); D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( PreAlloc_Bridge, " -> transfer read/write %s Fusion ID %lu (index %d)\n", (flags & CSAF_WRITE) ? "from" : "to", surface->object.identity, index ); for (i = 0; i < transfer->num_rects; i++) { const DFBRectangle *rect = &transfer->rects[i]; int offset = DFB_BYTES_PER_LINE( surface->config.format, rect->x ); int length = DFB_BYTES_PER_LINE( surface->config.format, rect->w ); u8 *temp = alloca( length ); for (y = 0; y < rect->h; y++) { DFBRectangle lrect = { rect->x, rect->y + y, rect->w, 1 }; if (flags & CSAF_WRITE) { ret = CoreSlave_GetData( slave, surface->config.preallocated[index].addr + (rect->y + y) * surface->config.preallocated[index].pitch + offset, length, temp ); if (ret) break; ret = dfb_surface_pool_write( allocation->pool, allocation, temp, length, &lrect ); } else { ret = dfb_surface_pool_read( allocation->pool, allocation, temp, length, &lrect ); if (ret) break; ret = CoreSlave_PutData( slave, surface->config.preallocated[index].addr + (rect->y + y) * surface->config.preallocated[index].pitch + offset, length, temp ); } if (ret) break; } if (ret) break; } return ret; } static DFBResult preallocStartTransfer( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfacePoolTransfer *transfer, void *transfer_data ) { DFBResult ret = DFB_BUG; preallocPoolBridgeData *data = bridge_data; CoreSurfaceAllocation *from = transfer->from; CoreSurfaceAllocation *to = transfer->to; CoreSurface *surface; CoreSlave *slave; D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_ASSERT( bridge_data != NULL ); D_ASSERT( transfer != NULL ); D_MAGIC_ASSERT( transfer->buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( transfer->buffer->surface, CoreSurface ); surface = transfer->buffer->surface; slave = Core_Resource_GetSlave( surface->object.identity ); if (!slave) { D_WARN( "no slave object for id %lu", surface->object.identity ); return DFB_NOIMPL; } if (from->pool == data->prealloc_pool) { if (to->pool->desc.access[CSAID_CPU] & CSAF_WRITE) ret = prealloc_transfer_locked( surface, transfer, to, CSAF_WRITE, slave ); else ret = prealloc_transfer_readwrite( surface, transfer, to, CSAF_WRITE, slave ); } else if (to->pool == data->prealloc_pool) { if (from->pool->desc.access[CSAID_CPU] & CSAF_READ) ret = prealloc_transfer_locked( surface, transfer, from, CSAF_READ, slave ); else ret = prealloc_transfer_readwrite( surface, transfer, from, CSAF_READ, slave ); } return ret; } static DFBResult preallocFinishTransfer( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfacePoolTransfer *transfer, void *transfer_data ) { D_DEBUG_AT( PreAlloc_Bridge, "%s()\n", __FUNCTION__ ); D_ASSERT( bridge_data != NULL ); return DFB_OK; } const SurfacePoolBridgeFuncs preallocSurfacePoolBridgeFuncs = { .PoolBridgeDataSize = preallocPoolBridgeDataSize, .InitPoolBridge = preallocInitPoolBridge, .JoinPoolBridge = preallocJoinPoolBridge, .DestroyPoolBridge = preallocDestroyPoolBridge, .LeavePoolBridge = preallocLeavePoolBridge, .CheckTransfer = preallocCheckTransfer, .StartTransfer = preallocStartTransfer, .FinishTransfer = preallocFinishTransfer }; ================================================ FILE: src/core/screen.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( Core_Screen, "Core/Screen", "DirectFB Core Screen" ); /**********************************************************************************************************************/ DFBResult dfb_screen_get_info( CoreScreen *screen, DFBScreenID *ret_id, DFBScreenDescription *ret_desc ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_DEBUG_AT( Core_Screen, "%s() -> %u\n", __FUNCTION__, shared->screen_id ); if (ret_id) *ret_id = shared->screen_id; if (ret_desc) *ret_desc = shared->description; return DFB_OK; } DFBResult dfb_screen_suspend( CoreScreen *screen ) { D_ASSERT( screen != NULL ); return DFB_OK; } DFBResult dfb_screen_resume( CoreScreen *screen ) { D_ASSERT( screen != NULL ); return DFB_OK; } DFBResult dfb_screen_set_powermode( CoreScreen *screen, DFBScreenPowerMode mode ) { const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->funcs != NULL ); funcs = screen->funcs; if (funcs->SetPowerMode) return funcs->SetPowerMode( screen, screen->driver_data, screen->screen_data, mode ); return DFB_UNSUPPORTED; } DFBResult dfb_screen_wait_vsync( CoreScreen *screen ) { const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->funcs != NULL ); funcs = screen->funcs; if (funcs->WaitVSync) return funcs->WaitVSync( screen, screen->driver_data, screen->screen_data ); return DFB_UNSUPPORTED; } DFBResult dfb_screen_get_vsync_count( CoreScreen *screen, unsigned long *ret_count ) { const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( ret_count != NULL ); funcs = screen->funcs; if (funcs->GetVSyncCount) return funcs->GetVSyncCount( screen, screen->driver_data, screen->screen_data, ret_count ); return DFB_UNSUPPORTED; } /**********************************************************************************************************************/ DFBResult dfb_screen_get_mixer_info( CoreScreen *screen, int mixer, DFBScreenMixerDescription *ret_desc ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( mixer >= 0 ); D_ASSERT( mixer < shared->description.mixers ); D_ASSERT( ret_desc != NULL ); /* Return mixer description. */ *ret_desc = shared->mixers[mixer].description; return DFB_OK; } DFBResult dfb_screen_get_mixer_config( CoreScreen *screen, int mixer, DFBScreenMixerConfig *ret_config ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( mixer >= 0 ); D_ASSERT( mixer < shared->description.mixers ); D_ASSERT( ret_config != NULL ); /* Return current mixer configuration. */ *ret_config = shared->mixers[mixer].configuration; return DFB_OK; } DFBResult dfb_screen_test_mixer_config( CoreScreen *screen, int mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenMixerConfigFlags failed = DSMCONF_NONE; D_UNUSED_P( shared ); D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestMixerConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( mixer >= 0 ); D_ASSERT( mixer < shared->description.mixers ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->mixers[mixer].configuration.flags ); /* Test the mixer configuration. */ ret = funcs->TestMixerConfig( screen, screen->driver_data, screen->screen_data, mixer, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK) ); if (ret_failed) *ret_failed = failed; return ret; } DFBResult dfb_screen_set_mixer_config( CoreScreen *screen, int mixer, const DFBScreenMixerConfig *config ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenMixerConfigFlags failed = DSOCONF_NONE; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestMixerConfig != NULL ); D_ASSERT( screen->funcs->SetMixerConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( mixer >= 0 ); D_ASSERT( mixer < shared->description.mixers ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->mixers[mixer].configuration.flags ); /* Test configuration first. */ ret = funcs->TestMixerConfig( screen, screen->driver_data, screen->screen_data, mixer, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); if (ret) return ret; /* Set configuration afterwards. */ ret = funcs->SetMixerConfig( screen, screen->driver_data, screen->screen_data, mixer, config ); if (ret) return ret; /* Store current configuration. */ shared->mixers[mixer].configuration = *config; return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_screen_get_encoder_info( CoreScreen *screen, int encoder, DFBScreenEncoderDescription *ret_desc ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( encoder >= 0 ); D_ASSERT( encoder < shared->description.encoders ); D_ASSERT( ret_desc != NULL ); /* Return encoder description. */ *ret_desc = shared->encoders[encoder].description; return DFB_OK; } DFBResult dfb_screen_get_encoder_config( CoreScreen *screen, int encoder, DFBScreenEncoderConfig *ret_config ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( encoder >= 0 ); D_ASSERT( encoder < shared->description.encoders ); D_ASSERT( ret_config != NULL ); /* Return current encoder configuration. */ *ret_config = shared->encoders[encoder].configuration; return DFB_OK; } DFBResult dfb_screen_test_encoder_config( CoreScreen *screen, int encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenEncoderConfigFlags failed = DSECONF_NONE; D_UNUSED_P( shared ); D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestEncoderConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( encoder >= 0 ); D_ASSERT( encoder < shared->description.encoders ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->encoders[encoder].configuration.flags ); /* Test the encoder configuration. */ ret = funcs->TestEncoderConfig( screen, screen->driver_data, screen->screen_data, encoder, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); if (ret_failed) *ret_failed = failed; return ret; } DFBResult dfb_screen_set_encoder_config( CoreScreen *screen, int encoder, const DFBScreenEncoderConfig *config ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenEncoderConfigFlags failed = DSECONF_NONE; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestEncoderConfig != NULL ); D_ASSERT( screen->funcs->SetEncoderConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( encoder >= 0 ); D_ASSERT( encoder < shared->description.encoders ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->encoders[encoder].configuration.flags ); /* Test configuration first. */ ret = funcs->TestEncoderConfig( screen, screen->driver_data, screen->screen_data, encoder, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); if (ret) return ret; /* Set configuration afterwards. */ ret = funcs->SetEncoderConfig( screen, screen->driver_data, screen->screen_data, encoder, config ); if (ret) return ret; /* Store current configuration. */ shared->encoders[encoder].configuration = *config; return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_screen_get_output_info( CoreScreen *screen, int output, DFBScreenOutputDescription *ret_desc ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( output >= 0 ); D_ASSERT( output < shared->description.outputs ); D_ASSERT( ret_desc != NULL ); /* Return output description. */ *ret_desc = shared->outputs[output].description; return DFB_OK; } DFBResult dfb_screen_get_output_config( CoreScreen *screen, int output, DFBScreenOutputConfig *ret_config ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; D_ASSERT( output >= 0 ); D_ASSERT( output < shared->description.outputs ); D_ASSERT( ret_config != NULL ); /* Return current output configuration. */ *ret_config = shared->outputs[output].configuration; return DFB_OK; } DFBResult dfb_screen_test_output_config( CoreScreen *screen, int output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenOutputConfigFlags failed = DSOCONF_NONE; D_UNUSED_P( shared ); D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestOutputConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( output >= 0 ); D_ASSERT( output < shared->description.outputs ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->outputs[output].configuration.flags ); /* Test the output configuration. */ ret = funcs->TestOutputConfig( screen, screen->driver_data, screen->screen_data, output, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); if (ret_failed) *ret_failed = failed; return ret; } DFBResult dfb_screen_set_output_config( CoreScreen *screen, int output, const DFBScreenOutputConfig *config ) { DFBResult ret; CoreScreenShared *shared; const ScreenFuncs *funcs; DFBScreenOutputConfigFlags failed = DSOCONF_NONE; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->TestOutputConfig != NULL ); D_ASSERT( screen->funcs->SetOutputConfig != NULL ); shared = screen->shared; funcs = screen->funcs; D_ASSERT( output >= 0 ); D_ASSERT( output < shared->description.outputs ); D_ASSERT( config != NULL ); D_ASSERT( config->flags == shared->outputs[output].configuration.flags ); /* Test configuration first. */ ret = funcs->TestOutputConfig( screen, screen->driver_data, screen->screen_data, output, config, &failed ); D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); if (ret) return ret; /* Set configuration afterwards. */ ret = funcs->SetOutputConfig( screen, screen->driver_data, screen->screen_data, output, config ); if (ret) return ret; /* Store current configuration. */ shared->outputs[output].configuration = *config; return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_screen_get_screen_size( CoreScreen *screen, int *ret_width, int *ret_height ) { const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( screen->funcs->GetScreenSize != NULL ); D_ASSERT( ret_width != NULL ); D_ASSERT( ret_height != NULL ); funcs = screen->funcs; return funcs->GetScreenSize( screen, screen->driver_data, screen->screen_data, ret_width, ret_height ); } DFBResult dfb_screen_get_layer_dimension( CoreScreen *screen, CoreLayer *layer, int *ret_width, int *ret_height ) { int i; DFBResult ret = DFB_UNSUPPORTED; CoreScreenShared *shared; const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( layer != NULL ); D_ASSERT( ret_width != NULL ); D_ASSERT( ret_height != NULL ); shared = screen->shared; funcs = screen->funcs; if (funcs->GetMixerState) { for (i = 0; i < shared->description.mixers; i++) { const DFBScreenMixerConfig *config = &shared->mixers[i].configuration; if ((config->flags & DSMCONF_LAYERS) && DFB_DISPLAYLAYER_IDS_HAVE( config->layers, dfb_layer_id( layer ) )) { CoreMixerState state; ret = funcs->GetMixerState( screen, screen->driver_data, screen->screen_data, i, &state ); if (ret == DFB_OK) { if (state.flags & CMSF_DIMENSION) { *ret_width = state.dimension.w; *ret_height = state.dimension.h; return DFB_OK; } ret = DFB_UNSUPPORTED; } } } for (i = 0; i < shared->description.mixers; i++) { const DFBScreenMixerDescription *desc = &shared->mixers[i].description; if ((desc->caps & DSMCAPS_SUB_LAYERS) && DFB_DISPLAYLAYER_IDS_HAVE( desc->sub_layers, dfb_layer_id( layer ) )) { CoreMixerState state; ret = funcs->GetMixerState( screen, screen->driver_data, screen->screen_data, i, &state ); if (ret == DFB_OK) { if (state.flags & CMSF_DIMENSION) { *ret_width = state.dimension.w; *ret_height = state.dimension.h; return DFB_OK; } ret = DFB_UNSUPPORTED; } } } } if (funcs->GetScreenSize) ret = funcs->GetScreenSize( screen, screen->driver_data, screen->screen_data, ret_width, ret_height ); return ret; } DFBResult dfb_screen_get_frame_interval( CoreScreen *screen, long long *ret_micros ) { CoreScreenShared *shared; long long interval = dfb_config->screen_frame_interval; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); D_ASSERT( screen->funcs != NULL ); shared = screen->shared; if (shared->description.encoders) { const DFBScreenEncoderConfig *config = &shared->encoders[0].configuration; if (config->flags & DSECONF_FREQUENCY) { switch (config->frequency) { case DSEF_25HZ: interval = 1000000000LL / 25000LL; break; case DSEF_29_97HZ: interval = 1000000000LL / 29970LL; break; case DSEF_50HZ: interval = 1000000000LL / 50000LL; break; case DSEF_59_94HZ: interval = 1000000000LL / 59940LL; break; case DSEF_60HZ: interval = 1000000000LL / 60000LL; break; case DSEF_75HZ: interval = 1000000000LL / 75000LL; break; case DSEF_30HZ: interval = 1000000000LL / 30000LL; break; case DSEF_24HZ: interval = 1000000000LL / 24000LL; break; case DSEF_23_976HZ: interval = 1000000000LL / 23976LL; break; default: break; } } } *ret_micros = interval; return DFB_OK; } DFBResult dfb_screen_get_rotation( CoreScreen *screen, int *ret_rotation ) { const ScreenFuncs *funcs; D_ASSERT( screen != NULL ); D_ASSERT( screen->funcs != NULL ); D_ASSERT( ret_rotation != NULL ); funcs = screen->funcs; if (!funcs->GetScreenRotation) { *ret_rotation = 0; return DFB_OK; } return funcs->GetScreenRotation( screen, screen->driver_data, screen->screen_data, ret_rotation ); } ================================================ FILE: src/core/screen.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SCREEN_H__ #define __CORE__SCREEN_H__ #include /**********************************************************************************************************************/ /* * Misc. */ DFBResult dfb_screen_get_info ( CoreScreen *screen, DFBScreenID *ret_id, DFBScreenDescription *ret_desc ); DFBResult dfb_screen_suspend ( CoreScreen *screen ); DFBResult dfb_screen_resume ( CoreScreen *screen ); DFBResult dfb_screen_set_powermode ( CoreScreen *screen, DFBScreenPowerMode mode ); DFBResult dfb_screen_wait_vsync ( CoreScreen *screen ); DFBResult dfb_screen_get_vsync_count ( CoreScreen *screen, unsigned long *ret_count ); /* * Mixers. */ DFBResult dfb_screen_get_mixer_info ( CoreScreen *screen, int mixer, DFBScreenMixerDescription *ret_desc ); DFBResult dfb_screen_get_mixer_config ( CoreScreen *screen, int mixer, DFBScreenMixerConfig *ret_config ); DFBResult dfb_screen_test_mixer_config ( CoreScreen *screen, int mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ); DFBResult dfb_screen_set_mixer_config ( CoreScreen *screen, int mixer, const DFBScreenMixerConfig *config ); /* * Encoders. */ DFBResult dfb_screen_get_encoder_info ( CoreScreen *screen, int encoder, DFBScreenEncoderDescription *ret_desc ); DFBResult dfb_screen_get_encoder_config ( CoreScreen *screen, int encoder, DFBScreenEncoderConfig *ret_config ); DFBResult dfb_screen_test_encoder_config( CoreScreen *screen, int encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ); DFBResult dfb_screen_set_encoder_config ( CoreScreen *screen, int encoder, const DFBScreenEncoderConfig *config ); /* * Outputs. */ DFBResult dfb_screen_get_output_info ( CoreScreen *screen, int output, DFBScreenOutputDescription *ret_desc ); DFBResult dfb_screen_get_output_config ( CoreScreen *screen, int output, DFBScreenOutputConfig *ret_config ); DFBResult dfb_screen_test_output_config ( CoreScreen *screen, int output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ); DFBResult dfb_screen_set_output_config ( CoreScreen *screen, int output, const DFBScreenOutputConfig *config ); /* * Screen configuration. */ DFBResult dfb_screen_get_screen_size ( CoreScreen *screen, int *ret_width, int *ret_height ); DFBResult dfb_screen_get_layer_dimension( CoreScreen *screen, CoreLayer *layer, int *ret_width, int *ret_height ); DFBResult dfb_screen_get_frame_interval ( CoreScreen *screen, long long *ret_micros ); DFBResult dfb_screen_get_rotation ( CoreScreen *screen, int *ret_rotation ); #endif ================================================ FILE: src/core/screens.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Screens, "Core/Screens", "DirectFB Core Screens" ); /**********************************************************************************************************************/ typedef struct { int magic; int num; CoreScreenShared *screens[MAX_SCREENS]; } DFBScreenCoreShared; typedef struct { int magic; CoreDFB *core; DFBScreenCoreShared *shared; } DFBScreenCore; DFB_CORE_PART( screen_core, ScreenCore ); /**********************************************************************************************************************/ static int num_screens = 0; static CoreScreen *screens[MAX_SCREENS]; static DFBResult dfb_screen_core_initialize( CoreDFB *core, DFBScreenCore *data, DFBScreenCoreShared *shared ) { DFBResult ret; FusionSHMPoolShared *pool; int i; D_DEBUG_AT( Core_Screens, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; pool = dfb_core_shmpool( core ); /* Initialize all registered screens. */ for (i = 0; i < num_screens; i++) { CoreScreen *screen = screens[i]; CoreScreenShared *sshared; const ScreenFuncs *funcs = screen->funcs; DFBScreenDescription desc = { .caps = DSCCAPS_NONE }; char buf[24]; /* Allocate shared data. */ sshared = SHCALLOC( pool, 1, sizeof(CoreScreenShared) ); /* Assign ID (zero based index). */ sshared->screen_id = i; snprintf( buf, sizeof(buf), "Screen %d", i ); /* Initialize the lock. */ if (fusion_skirmish_init2( &sshared->lock, buf, dfb_core_world( core ), fusion_config->secure_fusion )) { SHFREE( pool, sshared ); return DFB_FUSION; } /* Allocate driver's screen data. */ if (funcs->ScreenDataSize) { int size = funcs->ScreenDataSize(); if (size > 0) { sshared->screen_data = SHCALLOC( pool, 1, size ); if (!sshared->screen_data) { fusion_skirmish_destroy( &sshared->lock ); SHFREE( pool, sshared ); return D_OOSHM(); } } } /* Initialize the screen and get the screen description. */ ret = funcs->InitScreen( screen, screen->driver_data, sshared->screen_data, &desc ); if (ret) { D_ERROR( "Core/Screens: Failed to initialize screen %u!\n", sshared->screen_id ); fusion_skirmish_destroy( &sshared->lock ); if (sshared->screen_data) SHFREE( pool, sshared->screen_data ); SHFREE( pool, sshared ); return ret; } D_ASSUME( desc.mixers > 0 || !(desc.caps & DSCCAPS_MIXERS) ); D_ASSUME( desc.mixers == 0 || (desc.caps & DSCCAPS_MIXERS) ); D_ASSUME( desc.encoders > 0 || !(desc.caps & DSCCAPS_ENCODERS) ); D_ASSUME( desc.encoders == 0 || (desc.caps & DSCCAPS_ENCODERS) ); D_ASSUME( desc.outputs > 0 || !(desc.caps & DSCCAPS_OUTPUTS) ); D_ASSUME( desc.outputs == 0 || (desc.caps & DSCCAPS_OUTPUTS) ); D_ASSERT( desc.mixers >= 0 ); D_ASSERT( desc.mixers <= 32 ); D_ASSERT( desc.encoders >= 0 ); D_ASSERT( desc.encoders <= 32 ); D_ASSERT( desc.outputs >= 0 ); D_ASSERT( desc.outputs <= 32 ); /* Store description in sshared memory. */ sshared->description = desc; /* Initialize mixers. */ if (sshared->description.mixers) { int mixer; D_ASSERT( funcs->InitMixer != NULL ); D_ASSERT( funcs->SetMixerConfig != NULL ); sshared->mixers = SHCALLOC( pool, sshared->description.mixers, sizeof(CoreScreenMixer) ); for (mixer = 0; mixer < sshared->description.mixers; mixer++) { funcs->InitMixer( screen, screen->driver_data, sshared->screen_data, mixer, &sshared->mixers[mixer].description, &sshared->mixers[mixer].configuration ); funcs->SetMixerConfig( screen, screen->driver_data, sshared->screen_data, mixer, &sshared->mixers[mixer].configuration ); } } /* Initialize encoders. */ if (sshared->description.encoders) { int encoder; D_ASSERT( funcs->InitEncoder != NULL ); D_ASSERT( funcs->SetEncoderConfig != NULL ); sshared->encoders = SHCALLOC( pool, sshared->description.encoders, sizeof(CoreScreenEncoder) ); for (encoder = 0; encoder < sshared->description.encoders; encoder++) { funcs->InitEncoder( screen, screen->driver_data, sshared->screen_data, encoder, &sshared->encoders[encoder].description, &sshared->encoders[encoder].configuration ); funcs->SetEncoderConfig( screen, screen->driver_data, sshared->screen_data, encoder, &sshared->encoders[encoder].configuration ); } } /* Initialize outputs. */ if (sshared->description.outputs) { int output; D_ASSERT( funcs->InitOutput != NULL ); D_ASSERT( funcs->SetOutputConfig != NULL ); sshared->outputs = SHCALLOC( pool, sshared->description.outputs, sizeof(CoreScreenOutput) ); for (output = 0; output < sshared->description.outputs; output++) { funcs->InitOutput( screen, screen->driver_data, sshared->screen_data, output, &sshared->outputs[output].description, &sshared->outputs[output].configuration ); funcs->SetOutputConfig( screen, screen->driver_data, sshared->screen_data, output, &sshared->outputs[output].configuration ); } } /* Make a copy for faster access. */ screen->screen_data = sshared->screen_data; /* Store pointer to shared data and core. */ screen->shared = sshared; screen->core = core; CoreScreen_Init_Dispatch( core, screen, &sshared->call ); fusion_call_add_permissions( &sshared->call, 0, FUSION_CALL_PERMIT_EXECUTE ); /* Add the screen to the shared list. */ shared->screens[shared->num++] = sshared; } D_MAGIC_SET( data, DFBScreenCore ); D_MAGIC_SET( shared, DFBScreenCoreShared ); return DFB_OK; } static DFBResult dfb_screen_core_join( CoreDFB *core, DFBScreenCore *data, DFBScreenCoreShared *shared ) { int i; D_DEBUG_AT( Core_Screens, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBScreenCoreShared ); data->core = core; data->shared = shared; if (num_screens != shared->num) { D_ERROR( "Core/Screens: Number of screens does not match!\n" ); return DFB_BUG; } for (i = 0; i < num_screens; i++) { CoreScreen *screen = screens[i]; CoreScreenShared *sshared = shared->screens[i]; /* Make a copy for faster access. */ screen->screen_data = sshared->screen_data; /* Store pointer to shared data and core. */ screen->shared = sshared; screen->core = core; } D_MAGIC_SET( data, DFBScreenCore ); return DFB_OK; } static DFBResult dfb_screen_core_shutdown( DFBScreenCore *data, bool emergency ) { DFBScreenCoreShared *shared; FusionSHMPoolShared *pool; int i; D_UNUSED_P( shared ); D_DEBUG_AT( Core_Screens, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBScreenCore ); D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); shared = data->shared; pool = dfb_core_shmpool( data->core ); /* Begin with the most recently added screen. */ for (i = num_screens - 1; i >= 0; i--) { CoreScreen *screen = screens[i]; CoreScreenShared *sshared = screen->shared; const ScreenFuncs *funcs = screen->funcs; /* Shut the screen down. */ if (funcs->ShutdownScreen) if (funcs->ShutdownScreen( screen, screen->driver_data, sshared->screen_data )) D_ERROR( "Core/Screens: Failed to shutdown screen %u!\n", sshared->screen_id ); CoreScreen_Deinit_Dispatch( &sshared->call ); /* Deinitialize the lock. */ fusion_skirmish_destroy( &sshared->lock ); /* Free the driver's screen data. */ if (sshared->screen_data) SHFREE( pool, sshared->screen_data ); /* Free mixer data. */ if (sshared->mixers) SHFREE( pool, sshared->mixers ); /* Free encoder data. */ if (sshared->encoders) SHFREE( pool, sshared->encoders ); /* Free output data. */ if (sshared->outputs) SHFREE( pool, sshared->outputs ); /* Free the shared screen data. */ SHFREE( pool, sshared ); /* Free the local screen data. */ D_FREE( screen ); } num_screens = 0; D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_screen_core_leave( DFBScreenCore *data, bool emergency ) { int i; D_DEBUG_AT( Core_Screens, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBScreenCore ); D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); /* Deinitialize all local stuff only. */ for (i = 0; i < num_screens; i++) { CoreScreen *screen = screens[i]; /* Free local screen data. */ D_FREE( screen ); } num_screens = 0; D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_screen_core_suspend( DFBScreenCore *data ) { int i; D_DEBUG_AT( Core_Screens, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBScreenCore ); D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); for (i = num_screens - 1; i >= 0; i--) dfb_screen_suspend( screens[i] ); return DFB_OK; } static DFBResult dfb_screen_core_resume( DFBScreenCore *data ) { int i; D_DEBUG_AT( Core_Screens, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBScreenCore ); D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); for (i = 0; i < num_screens; i++) dfb_screen_resume( screens[i] ); return DFB_OK; } /**********************************************************************************************************************/ CoreScreen * dfb_screens_register( void *driver_data, const ScreenFuncs *funcs ) { CoreScreen *screen; D_ASSERT( funcs != NULL ); if (num_screens == MAX_SCREENS) { D_ERROR( "Core/Screens: Maximum number of screens reached!\n" ); return NULL; } /* Allocate local data. */ screen = D_CALLOC( 1, sizeof(CoreScreen) ); /* Assign local pointers. */ screen->driver_data = driver_data; screen->funcs = funcs; /* Add it to the local list. */ screens[num_screens++] = screen; return screen; } typedef void (*AnyFunc)( void ); CoreScreen * dfb_screens_hook_primary( void *driver_data, ScreenFuncs *funcs, ScreenFuncs *primary_funcs, void **primary_driver_data ) { int i; int entries; CoreScreen *primary = screens[0]; D_ASSERT( primary != NULL ); D_ASSERT( funcs != NULL ); /* Copy content of original function table. */ if (primary_funcs) direct_memcpy( primary_funcs, primary->funcs, sizeof(ScreenFuncs) ); /* Copy pointer to original driver data. */ if (primary_driver_data) *primary_driver_data = primary->driver_data; /* Replace all entries in the old table that aren't NULL in the new one. */ entries = sizeof(ScreenFuncs) / sizeof(void (*)( void )); for (i = 0; i < entries; i++) { AnyFunc *newfuncs = (AnyFunc*) funcs; AnyFunc *oldfuncs = (AnyFunc*) primary->funcs; if (newfuncs[i]) oldfuncs[i] = newfuncs[i]; } /* Replace device and driver data pointer. */ primary->driver_data = driver_data; return primary; } void dfb_screens_enumerate( CoreScreenCallback callback, void *ctx ) { int i; D_ASSERT( callback != NULL ); for (i = 0; i < num_screens; i++) { if (callback( screens[i], ctx ) == DFENUM_CANCEL) break; } } unsigned int dfb_screens_num() { return num_screens; } CoreScreen * dfb_screen_at( DFBScreenID screen_id ) { D_ASSERT( screen_id >= 0 ); D_ASSERT( screen_id < num_screens ); return screens[screen_id]; } CoreScreen * dfb_screen_at_translated( DFBScreenID screen_id ) { CoreScreen *primary; D_ASSERT( screen_id >= 0 ); D_ASSERT( screen_id < num_screens ); if (dfb_config->primary_layer > 0) { primary = dfb_layer_at_translated( DLID_PRIMARY )->screen ; if (screen_id == DSCID_PRIMARY) return primary; if (screen_id == primary->shared->screen_id) return dfb_screen_at( DSCID_PRIMARY ); } return dfb_screen_at( screen_id ); } DFBScreenID dfb_screen_id( const CoreScreen *screen ) { CoreScreenShared *shared; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; return shared->screen_id; } DFBScreenID dfb_screen_id_translated( const CoreScreen *screen ) { CoreScreenShared *shared; CoreScreen *primary; D_ASSERT( screen != NULL ); D_ASSERT( screen->shared != NULL ); shared = screen->shared; if (dfb_config->primary_layer > 0) { primary = dfb_layer_at_translated( DLID_PRIMARY )->screen; if (shared->screen_id == DSCID_PRIMARY) return primary->shared->screen_id; if (shared->screen_id == primary->shared->screen_id) return DSCID_PRIMARY; } return shared->screen_id; } ================================================ FILE: src/core/screens.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SCREENS_H__ #define __CORE__SCREENS_H__ #include #include #include /**********************************************************************************************************************/ typedef enum { CMSF_NONE = 0x00000000, /* none of these */ CMSF_DIMENSION = 0x00000001, /* dimension is set */ CMSF_ALL = 0x00000001, /* all of these */ } CoreMixerStateFlags; typedef struct { CoreMixerStateFlags flags; DFBDimension dimension; } CoreMixerState; typedef struct { /* * Return size of screen data (shared memory). */ int (*ScreenDataSize) ( void ); /* * Called once by the master to initialize screen data and reset hardware. * Return screen description. */ DFBResult (*InitScreen) ( CoreScreen *screen, void *driver_data, void *screen_data, DFBScreenDescription *description ); /* * Called once by the master to shutdown the screen. * Use this function to free any resources that were taken during init. */ DFBResult (*ShutdownScreen) ( CoreScreen *screen, void *driver_data, void *screen_data ); /* * Called once by the master for each mixer. * Driver fills description and default config. */ DFBResult (*InitMixer) ( CoreScreen *screen, void *driver_data, void *screen_data, int mixer, DFBScreenMixerDescription *description, DFBScreenMixerConfig *config ); /* * Called once by the master for each encoder. * Driver fills description and default config. */ DFBResult (*InitEncoder) ( CoreScreen *screen, void *driver_data, void *screen_data, int encoder, DFBScreenEncoderDescription *description, DFBScreenEncoderConfig *config ); /* * Called once by the master for each output. * Driver fills description and default config. */ DFBResult (*InitOutput) ( CoreScreen *screen, void *driver_data, void *screen_data, int output, DFBScreenOutputDescription *description, DFBScreenOutputConfig *config ); /* * Switch between "on", "standby", "suspend" and "off". */ DFBResult (*SetPowerMode) ( CoreScreen *screen, void *driver_data, void *screen_data, DFBScreenPowerMode mode ); /* * Wait for the vertical retrace. */ DFBResult (*WaitVSync) ( CoreScreen *screen, void *driver_data, void *screen_data ); /* * Test if mixer configuration is supported. */ DFBResult (*TestMixerConfig) ( CoreScreen *screen, void *driver_data, void *screen_data, int mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ); /* * Set new mixer configuration. */ DFBResult (*SetMixerConfig) ( CoreScreen *screen, void *driver_data, void *screen_data, int mixer, const DFBScreenMixerConfig *config ); /* * Test if encoder configuration is supported. */ DFBResult (*TestEncoderConfig)( CoreScreen *screen, void *driver_data, void *screen_data, int encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ); /* * Set new encoder configuration. */ DFBResult (*SetEncoderConfig) ( CoreScreen *screen, void *driver_data, void *screen_data, int encoder, const DFBScreenEncoderConfig *config ); /* * Test if output configuration is supported. */ DFBResult (*TestOutputConfig) ( CoreScreen *screen, void *driver_data, void *screen_data, int output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ); /* * Set new output configuration. */ DFBResult (*SetOutputConfig) ( CoreScreen *screen, void *driver_data, void *screen_data, int output, const DFBScreenOutputConfig *config ); /* * Return the screen size, e.g. as a basis for positioning a layer. */ DFBResult (*GetScreenSize) ( CoreScreen *screen, void *driver_data, void *screen_data, int *ret_width, int *ret_height ); /* * Return the mixer state. */ DFBResult (*GetMixerState) ( CoreScreen *screen, void *driver_data, void *screen_data, int mixer, CoreMixerState *ret_state ); /* * Return vertical retrace count. */ DFBResult (*GetVSyncCount) ( CoreScreen *screen, void *driver_data, void *screen_data, unsigned long *ret_count ); /* * Return the physical screen rotation. */ DFBResult (*GetScreenRotation)( CoreScreen *screen, void *driver_data, void *screen_data, int *ret_rotation ); } ScreenFuncs; typedef struct { DFBScreenMixerDescription description; DFBScreenMixerConfig configuration; } CoreScreenMixer; typedef struct { DFBScreenEncoderDescription description; DFBScreenEncoderConfig configuration; } CoreScreenEncoder; typedef struct { DFBScreenOutputDescription description; DFBScreenOutputConfig configuration; } CoreScreenOutput; typedef struct { DFBScreenID screen_id; DFBScreenDescription description; CoreScreenMixer *mixers; CoreScreenEncoder *encoders; CoreScreenOutput *outputs; void *screen_data; /* local data (impl) */ FusionSkirmish lock; FusionCall call; /* dispatch */ } CoreScreenShared; struct __DFB_CoreScreen { CoreScreenShared *shared; CoreDFB *core; const ScreenFuncs *funcs; void *driver_data; void *screen_data; /* copy of shared->screen_data */ }; /**********************************************************************************************************************/ typedef DFBEnumerationResult (*CoreScreenCallback)( CoreScreen *screen, void *ctx ); /**********************************************************************************************************************/ /* * Add a screen to a graphics device by pointing to a table containing driver functions. * The supplied 'driver_data' will be passed to these functions. */ CoreScreen *dfb_screens_register ( void *driver_data, const ScreenFuncs *funcs ); /* * Replace functions of the primary screen implementation by passing an alternative driver function table. * All non-NULL functions in the new table replace the functions in the original function table. * The original function table is written to 'primary_funcs' before to allow drivers to use existing functionality * from the original implementation. */ CoreScreen *dfb_screens_hook_primary( void *driver_data, ScreenFuncs *funcs, ScreenFuncs *primary_funcs, void **primary_driver_data ); /* * Enumerate all registered screens by invoking the callback for each screen. */ void dfb_screens_enumerate ( CoreScreenCallback callback, void *ctx ); /* * Return the number of screens. */ unsigned int dfb_screens_num ( void ); /* * Return the screen with the specified ID. */ CoreScreen *dfb_screen_at ( DFBScreenID screen_id ); /* * Return the (translated) screen with the specified ID. */ CoreScreen *dfb_screen_at_translated( DFBScreenID screen_id ); /* * Return the ID of the specified screen. */ DFBScreenID dfb_screen_id ( const CoreScreen *screen ); /* * Return the (translated) ID of the specified screen. */ DFBScreenID dfb_screen_id_translated( const CoreScreen *screen ); #endif ================================================ FILE: src/core/shared_secure_surface_pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_SharedSecure, "Core/SharedSecure", "DirectFB Core Shared Secure Surface Pool" ); /**********************************************************************************************************************/ typedef struct { char tmpfs_dir[FUSION_SHM_TMPFS_PATH_NAME_LEN + 20]; } SharedPoolData; typedef struct { CoreDFB *core; FusionWorld *world; } SharedPoolLocalData; typedef struct { int pitch; int size; DFBSurfaceID surface_id; void *master_map; } SharedAllocationData; /**********************************************************************************************************************/ static int sharedSecurePoolDataSize( void ) { return sizeof(SharedPoolData); } static int sharedSecurePoolLocalDataSize( void ) { return sizeof(SharedPoolLocalData); } static int sharedSecureAllocationDataSize( void ) { return sizeof(SharedAllocationData); } static DFBResult sharedSecureInitPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ) { DirectResult ret; DirectDir dir; DirectEntry entry; SharedPoolData *data = pool_data; SharedPoolLocalData *local = pool_local; D_DEBUG_AT( Core_SharedSecure, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( ret_desc != NULL ); ret_desc->caps = CSPCAPS_VIRTUAL; ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_INTERNAL; ret_desc->priority = (dfb_system_caps() & CSCAPS_PREFER_SHM) ? CSPP_PREFERED : CSPP_DEFAULT; if (dfb_system_caps() & CSCAPS_SYSMEM_EXTERNAL) ret_desc->types |= CSTF_EXTERNAL; snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Shared Secure Memory" ); local->core = core; local->world = dfb_core_world( core ); snprintf( data->tmpfs_dir, sizeof(data->tmpfs_dir), "%s/dfb.%d", fusion_get_tmpfs( local->world ), fusion_world_index( local->world ) ); ret = direct_dir_create( data->tmpfs_dir, 0750 ); if (ret) { if (ret != DR_BUSY) { D_DERROR( ret, "Core/SharedSecure: Could not create '%s'!\n", data->tmpfs_dir ); return DFB_IO; } D_DEBUG_AT( Core_SharedSecure, " -> %s exists, cleaning up\n", data->tmpfs_dir ); ret = direct_dir_open ( &dir, data->tmpfs_dir ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not open '%s'!\n", data->tmpfs_dir ); return DFB_IO; } while (direct_dir_read( &dir, &entry ) == DR_OK) { char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 20 + 256]; if (!strcmp( entry.name, "." ) || !strcmp( entry.name, ".." )) continue; snprintf( buf, sizeof(buf), "%s/%s", data->tmpfs_dir, entry.name ); ret = direct_unlink( buf ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not remove '%s'!\n", buf ); direct_dir_close( &dir ); return DFB_IO; } } direct_dir_close( &dir ); } return DFB_OK; } static DFBResult sharedSecureDestroyPool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { DirectResult ret; SharedPoolData *data = pool_data; D_DEBUG_AT( Core_SharedSecure, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); ret = direct_dir_remove( data->tmpfs_dir ); if (ret) D_DERROR( ret, "Core/SharedSecure: Could not remove '%s'!\n", data->tmpfs_dir ); return DFB_OK; } static DFBResult sharedSecureAllocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { DirectResult ret; CoreSurface *surface; SharedPoolData *data = pool_data; SharedAllocationData *alloc = alloc_data; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 99]; DirectFile fd; D_DEBUG_AT( Core_SharedSecure, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); surface = buffer->surface; alloc->surface_id = surface->object.id; dfb_surface_calc_buffer_size( surface, 8, 0, &alloc->pitch, &alloc->size ); snprintf( buf, sizeof(buf), "%s/surface_0x%08x_shared_allocation_%p", data->tmpfs_dir, alloc->surface_id, alloc ); ret = direct_file_open( &fd, buf, O_RDWR | O_CREAT | O_EXCL, 0660 ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not create '%s'!\n", buf ); return DFB_IO; } if (fusion_config->shmfile_gid != -1) { if (direct_file_chown( &fd, -1, fusion_config->shmfile_gid )) D_WARN( "changing owner on %s failed... continuing on.", buf ); } direct_file_chmod( &fd, 0660 ); if (direct_file_truncate( &fd, alloc->size )) { D_DERROR( ret, "Core/SharedSecure: Setting file size for '%s' to %d failed!\n", buf, alloc->size ); ret = direct_unlink( buf ); if (ret) D_DERROR( ret, "Core/SharedSecure: Could not remove '%s'!\n", buf ); return DFB_IO; } ret = direct_file_map( &fd, NULL, 0, alloc->size, DFP_READ | DFP_WRITE, &alloc->master_map ); direct_file_close( &fd ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not mmap '%s'!\n", buf ); ret = direct_unlink( buf ); if (ret) D_DERROR( ret, "Core/SharedSecure: Could not remove '%s'!\n", buf ); return DFB_IO; } allocation->flags = CSALF_VOLATILE; allocation->size = alloc->size; return DFB_OK; } static DFBResult sharedSecureDeallocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { DirectResult ret; SharedPoolData *data = pool_data; SharedAllocationData *alloc = alloc_data; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 99]; D_DEBUG_AT( Core_SharedSecure, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); snprintf( buf, sizeof(buf), "%s/surface_0x%08x_shared_allocation_%p", data->tmpfs_dir, alloc->surface_id, alloc ); direct_file_unmap( alloc->master_map, alloc->size ); ret = direct_unlink( buf ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not remove '%s'!\n", buf ); return DFB_IO; } return DFB_OK; } static DFBResult sharedSecureLock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { DirectResult ret; SharedPoolData *data = pool_data; SharedAllocationData *alloc = alloc_data; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 99]; DirectFile fd; D_DEBUG_AT( Core_SharedSecure, "%s() <- size %d\n", __FUNCTION__, alloc->size ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); if (dfb_core_is_master( core_dfb )) { lock->addr = alloc->master_map; } else { snprintf( buf, sizeof(buf), "%s/surface_0x%08x_shared_allocation_%p", data->tmpfs_dir, alloc->surface_id, alloc ); ret = direct_file_open( &fd, buf, O_RDWR, 0 ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not open '%s'!\n", buf ); return DFB_IO; } ret = direct_file_map( &fd, NULL, 0, alloc->size, DFP_READ | DFP_WRITE, &lock->handle ); lock->addr = lock->handle; D_DEBUG_AT( Core_SharedSecure, " -> mapped to %p\n", lock->addr ); direct_file_close( &fd ); if (ret) { D_DERROR( ret, "Core/SharedSecure: Could not mmap '%s'!\n", buf ); return DFB_IO; } } lock->pitch = alloc->pitch; return DFB_OK; } static DFBResult sharedSecureUnlock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { SharedAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_SharedSecure, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); if (!dfb_core_is_master( core_dfb )) direct_file_unmap( lock->handle, alloc->size ); return DFB_OK; } const SurfacePoolFuncs sharedSecureSurfacePoolFuncs = { .PoolDataSize = sharedSecurePoolDataSize, .PoolLocalDataSize = sharedSecurePoolLocalDataSize, .AllocationDataSize = sharedSecureAllocationDataSize, .InitPool = sharedSecureInitPool, .DestroyPool = sharedSecureDestroyPool, .AllocateBuffer = sharedSecureAllocateBuffer, .DeallocateBuffer = sharedSecureDeallocateBuffer, .Lock = sharedSecureLock, .Unlock = sharedSecureUnlock }; ================================================ FILE: src/core/shared_surface_pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Shared, "Core/Shared", "DirectFB Core Shared Surface Pool" ); /**********************************************************************************************************************/ typedef struct { FusionSHMPoolShared *shmpool; } SharedPoolData; typedef struct { CoreDFB *core; FusionWorld *world; } SharedPoolLocalData; typedef struct { void *addr; void *aligned_addr; int pitch; int size; } SharedAllocationData; /**********************************************************************************************************************/ static int sharedPoolDataSize( void ) { return sizeof(SharedPoolData); } static int sharedPoolLocalDataSize( void ) { return sizeof(SharedPoolLocalData); } static int sharedAllocationDataSize( void ) { return sizeof(SharedAllocationData); } static DFBResult sharedInitPool( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ) { DFBResult ret; SharedPoolData *data = pool_data; SharedPoolLocalData *local = pool_local; D_DEBUG_AT( Core_Shared, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( ret_desc != NULL ); local->core = core; local->world = dfb_core_world( core ); ret = fusion_shm_pool_create( local->world, "Surface Memory Pool", dfb_config->surface_shmpool_size, fusion_config->debugshm, &data->shmpool ); if (ret) return ret; ret_desc->caps = CSPCAPS_VIRTUAL; ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_INTERNAL; ret_desc->priority = (dfb_system_caps() & CSCAPS_PREFER_SHM) ? CSPP_PREFERED : CSPP_DEFAULT; if (dfb_system_caps() & CSCAPS_SYSMEM_EXTERNAL) ret_desc->types |= CSTF_EXTERNAL; snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Shared Memory" ); return DFB_OK; } static DFBResult sharedDestroyPool( CoreSurfacePool *pool, void *pool_data, void *pool_local ) { SharedPoolData *data = pool_data; SharedPoolLocalData *local = pool_local; D_DEBUG_AT( Core_Shared, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); fusion_shm_pool_destroy( local->world, data->shmpool ); return DFB_OK; } static DFBResult sharedAllocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { CoreSurface *surface; SharedPoolData *data = pool_data; SharedAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Shared, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); surface = buffer->surface; /* Create aligned shared system surface buffer if both base address and pitch are non-zero. */ if (dfb_config->system_surface_align_base && dfb_config->system_surface_align_pitch) { /* Make sure base address and pitch are a positive power of two. */ D_ASSERT( dfb_config->system_surface_align_base >= 2 ); D_ASSERT( !(dfb_config->system_surface_align_base & (dfb_config->system_surface_align_base - 1)) ); D_ASSERT( dfb_config->system_surface_align_pitch >= 2 ); D_ASSERT( !(dfb_config->system_surface_align_pitch & (dfb_config->system_surface_align_pitch - 1)) ); dfb_surface_calc_buffer_size( surface, dfb_config->system_surface_align_pitch, 0, &alloc->pitch, &alloc->size ); alloc->addr = SHMALLOC( data->shmpool, alloc->size + dfb_config->system_surface_align_base ); if (!alloc->addr) return D_OOSHM(); /* Calculate the aligned address. */ unsigned long addr = (unsigned long) alloc->addr; unsigned long aligned_offset = dfb_config->system_surface_align_base - (addr % dfb_config->system_surface_align_base ); alloc->aligned_addr = (void*) (addr + aligned_offset); } /* Create un-aligned shared system surface buffer. */ else { dfb_surface_calc_buffer_size( surface, 8, 0, &alloc->pitch, &alloc->size ); alloc->addr = SHMALLOC( data->shmpool, alloc->size ); if (!alloc->addr) return D_OOSHM(); alloc->aligned_addr = NULL; } allocation->flags = CSALF_VOLATILE; allocation->size = alloc->size; return DFB_OK; } static DFBResult sharedDeallocateBuffer( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ) { SharedPoolData *data = pool_data; SharedAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Shared, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); SHFREE( data->shmpool, alloc->addr ); return DFB_OK; } static DFBResult sharedLock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { SharedAllocationData *alloc = alloc_data; D_DEBUG_AT( Core_Shared, "%s() <- size %d\n", __FUNCTION__, alloc->size ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); /* Provide aligned address if one's available, otherwise the un-aligned one. */ if (alloc->aligned_addr) lock->addr = alloc->aligned_addr; else lock->addr = alloc->addr; lock->pitch = alloc->pitch; return DFB_OK; } static DFBResult sharedUnlock( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ) { D_DEBUG_AT( Core_Shared, "%s()\n", __FUNCTION__ ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); return DFB_OK; } const SurfacePoolFuncs sharedSurfacePoolFuncs = { .PoolDataSize = sharedPoolDataSize, .PoolLocalDataSize = sharedPoolLocalDataSize, .AllocationDataSize = sharedAllocationDataSize, .InitPool = sharedInitPool, .DestroyPool = sharedDestroyPool, .AllocateBuffer = sharedAllocateBuffer, .DeallocateBuffer = sharedDeallocateBuffer, .Lock = sharedLock, .Unlock = sharedUnlock }; ================================================ FILE: src/core/state.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Core_GfxState, "Core/GfxState", "DirectFB Core Gfx State" ); /**********************************************************************************************************************/ static __inline__ void validate_clip( CardState *state, int xmax, int ymax, bool warn ) { D_DEBUG_AT( Core_GfxState, "%s( %p, %d, %d, %d )\n", __FUNCTION__, state, xmax, ymax, warn ); D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); D_ASSERT( xmax >= 0 ); D_ASSERT( ymax >= 0 ); D_ASSERT( state->clip.x1 <= state->clip.x2 ); D_ASSERT( state->clip.y1 <= state->clip.y2 ); if (state->clip.x1 <= xmax && state->clip.y1 <= ymax && state->clip.x2 <= xmax && state->clip.y2 <= ymax) return; if (warn) D_WARN( "clip %4d,%4d-%4dx%4d invalid, adjusting to fit %dx%d", DFB_RECTANGLE_VALS_FROM_REGION( &state->clip ), xmax + 1, ymax + 1 ); if (state->clip.x1 > xmax) state->clip.x1 = xmax; if (state->clip.y1 > ymax) state->clip.y1 = ymax; if (state->clip.x2 > xmax) state->clip.x2 = xmax; if (state->clip.y2 > ymax) state->clip.y2 = ymax; state->modified |= SMF_CLIP; } /**********************************************************************************************************************/ int dfb_state_init( CardState *state, CoreDFB *core ) { D_ASSERT( state != NULL ); memset( state, 0, sizeof(CardState) ); state->core = core; state->fusion_id = fusion_id( dfb_core_world( core ) ); state->modified = SMF_ALL; state->src_blend = DSBF_SRCALPHA; state->dst_blend = DSBF_INVSRCALPHA; state->render_options = dfb_config->render_options; state->matrix[0] = 0x10000; state->matrix[1] = 0x00000; state->matrix[2] = 0x00000; state->matrix[3] = 0x00000; state->matrix[4] = 0x10000; state->matrix[5] = 0x00000; state->matrix[6] = 0x00000; state->matrix[7] = 0x00000; state->matrix[8] = 0x10000; state->affine_matrix = DFB_TRUE; state->from = DSBR_FRONT; state->from_eye = DSSE_LEFT; state->to = DSBR_BACK; state->to_eye = DSSE_LEFT; state->src_colormatrix[0] = 0x10000; state->src_colormatrix[1] = 0x00000; state->src_colormatrix[2] = 0x00000; state->src_colormatrix[3] = 0x00000; state->src_colormatrix[4] = 0x00000; state->src_colormatrix[5] = 0x10000; state->src_colormatrix[6] = 0x00000; state->src_colormatrix[7] = 0x00000; state->src_colormatrix[8] = 0x00000; state->src_colormatrix[9] = 0x00000; state->src_colormatrix[10] = 0x10000; state->src_colormatrix[11] = 0x00000; state->src_convolution.kernel[4] = 0x10000; state->src_convolution.scale = 0x10000; direct_recursive_mutex_init( &state->lock ); direct_serial_init( &state->dst_serial ); direct_serial_init( &state->src_serial ); direct_serial_init( &state->src_mask_serial ); direct_serial_init( &state->src2_serial ); D_MAGIC_SET( state, CardState ); state->gfxcard_data = NULL; dfb_gfxcard_state_init( state ); return 0; } void dfb_state_destroy( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->destination == NULL ); D_ASSERT( state->source == NULL ); D_ASSERT( state->source2 == NULL ); D_ASSERT( state->source_mask == NULL ); if (!dfb_config->startstop) D_ASSUME( !(state->flags & CSF_DRAWING) ); dfb_gfxcard_state_destroy( state ); state->gfxcard_data = NULL; D_MAGIC_CLEAR( state ); direct_serial_deinit( &state->dst_serial ); direct_serial_deinit( &state->src_serial ); direct_serial_deinit( &state->src_mask_serial ); direct_serial_deinit( &state->src2_serial ); if (state->num_translation) { D_ASSERT( state->index_translation != NULL ); D_FREE( state->index_translation ); } else D_ASSERT( state->index_translation == NULL ); direct_mutex_deinit( &state->lock ); } DFBResult dfb_state_set_destination( CardState *state, CoreSurface *destination ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (!dfb_config->startstop) D_ASSUME( !(state->flags & CSF_DRAWING) ); if (state->destination != destination) { if (destination) { if (dfb_surface_ref( destination )) { D_WARN( "could not ref() destination" ); dfb_state_unlock( state ); return DFB_DEAD; } validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, false ); } if (state->destination) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_DESTINATION ) ); dfb_surface_unref( state->destination ); } state->destination = destination; state->modified |= SMF_DESTINATION; if (destination) { direct_serial_copy( &state->dst_serial, &destination->serial ); D_FLAGS_SET( state->flags, CSF_DESTINATION ); } else D_FLAGS_CLEAR( state->flags, CSF_DESTINATION ); } dfb_state_unlock( state ); return DFB_OK; } DFBResult dfb_state_set_destination_2( CardState *state, CoreSurface *destination, u32 flip_count ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (!dfb_config->startstop) D_ASSUME( !(state->flags & CSF_DRAWING) ); if (state->destination != destination) { if (destination) { if (dfb_surface_ref( destination )) { D_WARN( "could not ref() destination" ); dfb_state_unlock( state ); return DFB_DEAD; } validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, false ); } if (state->destination) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_DESTINATION ) ); dfb_surface_unref( state->destination ); } if (destination) { direct_serial_copy( &state->dst_serial, &destination->serial ); D_FLAGS_SET( state->flags, CSF_DESTINATION ); } else D_FLAGS_CLEAR( state->flags, CSF_DESTINATION ); state->destination = destination; state->modified |= SMF_DESTINATION; } if (state->destination_flip_count != flip_count || !state->destination_flip_count_used) { state->destination_flip_count = flip_count; state->destination_flip_count_used = true; state->destination = destination; state->modified |= SMF_DESTINATION; } dfb_state_unlock( state ); return DFB_OK; } DFBResult dfb_state_set_source( CardState *state, CoreSurface *source ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (state->source != source) { if (source && dfb_surface_ref( source )) { D_WARN( "could not ref() source" ); dfb_state_unlock( state ); return DFB_DEAD; } if (state->source) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE ) ); dfb_surface_unref( state->source ); } state->source = source; state->modified |= SMF_SOURCE; if (source) { direct_serial_copy( &state->src_serial, &source->serial ); D_FLAGS_SET( state->flags, CSF_SOURCE ); } else D_FLAGS_CLEAR( state->flags, CSF_SOURCE ); } dfb_state_unlock( state ); return DFB_OK; } DFBResult dfb_state_set_source_2( CardState *state, CoreSurface *source, u32 flip_count ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (state->source != source) { if (source && dfb_surface_ref( source )) { D_WARN( "could not ref() source" ); dfb_state_unlock( state ); return DFB_DEAD; } if (state->source) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE ) ); dfb_surface_unref( state->source ); } state->source = source; state->modified |= SMF_SOURCE; if (source) { direct_serial_copy( &state->src_serial, &source->serial ); D_FLAGS_SET( state->flags, CSF_SOURCE ); } else D_FLAGS_CLEAR( state->flags, CSF_SOURCE ); } if (state->source_flip_count != flip_count || !state->source_flip_count_used) { state->source_flip_count = flip_count; state->source_flip_count_used = true; state->source = source; state->modified |= SMF_SOURCE; } dfb_state_unlock( state ); return DFB_OK; } DFBResult dfb_state_set_source2( CardState *state, CoreSurface *source2 ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (state->source2 != source2) { if (source2 && dfb_surface_ref( source2 )) { D_WARN( "could not ref() source2" ); dfb_state_unlock( state ); return DFB_DEAD; } if (state->source2) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE2 ) ); dfb_surface_unref( state->source2 ); } state->source2 = source2; state->modified |= SMF_SOURCE2; if (source2) { direct_serial_copy( &state->src2_serial, &source2->serial ); D_FLAGS_SET( state->flags, CSF_SOURCE2 ); } else D_FLAGS_CLEAR( state->flags, CSF_SOURCE2 ); } dfb_state_unlock( state ); return DFB_OK; } DFBResult dfb_state_set_source_mask( CardState *state, CoreSurface *source_mask ) { D_MAGIC_ASSERT( state, CardState ); dfb_state_lock( state ); if (state->source_mask != source_mask) { if (source_mask && dfb_surface_ref( source_mask )) { D_WARN( "could not ref() source mask" ); dfb_state_unlock( state ); return DFB_DEAD; } if (state->source_mask) { D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK ) ); dfb_surface_unref( state->source_mask ); } state->source_mask = source_mask; state->modified |= SMF_SOURCE_MASK; if (source_mask) { direct_serial_copy( &state->src_mask_serial, &source_mask->serial ); D_FLAGS_SET( state->flags, CSF_SOURCE_MASK ); } else D_FLAGS_CLEAR( state->flags, CSF_SOURCE_MASK ); } dfb_state_unlock( state ); return DFB_OK; } void dfb_state_update( CardState *state, bool update_sources ) { CoreSurface *destination; D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); destination = state->destination; if (D_FLAGS_IS_SET( state->flags, CSF_DESTINATION )) { D_ASSERT( destination != NULL ); if (direct_serial_update( &state->dst_serial, &destination->serial )) { validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); state->modified |= SMF_DESTINATION; } } else if (destination) validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE )) { CoreSurface *source = state->source; D_ASSERT( source != NULL ); if (direct_serial_update( &state->src_serial, &source->serial )) state->modified |= SMF_SOURCE; } if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK )) { CoreSurface *source_mask = state->source_mask; D_ASSERT( source_mask != NULL ); if (direct_serial_update( &state->src_mask_serial, &source_mask->serial )) state->modified |= SMF_SOURCE_MASK; } if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE2 )) { CoreSurface *source2 = state->source2; D_ASSERT( source2 != NULL ); if (direct_serial_update( &state->src2_serial, &source2->serial )) state->modified |= SMF_SOURCE2; } } void dfb_state_update_destination( CardState *state ) { CoreSurface *destination; D_DEBUG_AT( Core_GfxState, "%s( %p )\n", __FUNCTION__, state ); D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); destination = state->destination; if (D_FLAGS_IS_SET( state->flags, CSF_DESTINATION )) { D_DEBUG_AT( Core_GfxState, " -> CSF_DESTINATION is set\n" ); D_ASSERT( destination != NULL ); if (direct_serial_update( &state->dst_serial, &destination->serial )) { D_DEBUG_AT( Core_GfxState, " -> serial is updated\n" ); validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); state->modified |= SMF_DESTINATION; } } else if (destination) validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); } void dfb_state_update_sources( CardState *state, CardStateFlags flags ) { D_DEBUG_AT( Core_GfxState, "%s( %p )\n", __FUNCTION__, state ); D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); if (D_FLAGS_IS_SET( state->flags & flags, CSF_SOURCE )) { CoreSurface *source = state->source; D_ASSERT( source != NULL ); if (direct_serial_update( &state->src_serial, &source->serial )) state->modified |= SMF_SOURCE; } if (D_FLAGS_IS_SET( state->flags & flags, CSF_SOURCE_MASK )) { CoreSurface *source_mask = state->source_mask; D_ASSERT( source_mask != NULL ); if (direct_serial_update( &state->src_mask_serial, &source_mask->serial )) state->modified |= SMF_SOURCE_MASK; } if (D_FLAGS_IS_SET( state->flags & flags, CSF_SOURCE2 )) { CoreSurface *source2 = state->source2; D_ASSERT( source2 != NULL ); if (direct_serial_update( &state->src2_serial, &source2->serial )) state->modified |= SMF_SOURCE2; } } DFBResult dfb_state_set_index_translation( CardState *state, const int *indices, int num_indices ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( indices != NULL || num_indices == 0 ); dfb_state_lock( state ); if (state->num_translation != num_indices) { int *new_trans = D_REALLOC( state->index_translation, num_indices * sizeof(int) ); D_ASSERT( num_indices || new_trans == NULL ); if (num_indices && !new_trans) { dfb_state_unlock( state ); return D_OOM(); } state->index_translation = new_trans; state->num_translation = num_indices; } if (num_indices) direct_memcpy( state->index_translation, indices, num_indices * sizeof(int) ); state->modified |= SMF_INDEX_TRANSLATION; dfb_state_unlock( state ); return DFB_OK; } void dfb_state_set_matrix( CardState *state, const s32 *matrix ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( matrix != NULL ); if (memcmp( state->matrix, matrix, sizeof(state->matrix) )) { direct_memcpy( state->matrix, matrix, sizeof(state->matrix) ); state->affine_matrix = (matrix[6] == 0x00000 && matrix[7] == 0x00000 && matrix[8] == 0x10000); state->modified |= SMF_MATRIX; } } void dfb_state_set_src_colormatrix( CardState *state, const s32 *matrix ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( matrix != NULL ); if (memcmp( state->src_colormatrix, matrix, sizeof(state->src_colormatrix) )) { direct_memcpy( state->src_colormatrix, matrix, sizeof(state->src_colormatrix) ); state->modified |= SMF_SRC_COLORMATRIX; } } void dfb_state_set_src_convolution( CardState *state, const DFBConvolutionFilter *filter ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( filter != NULL ); if (memcmp( &state->src_convolution, filter, sizeof(state->src_convolution) )) { direct_memcpy( &state->src_convolution, filter, sizeof(state->src_convolution) ); state->modified |= SMF_SRC_CONVOLUTION; } } void dfb_state_set_color_or_index( CardState *state, const DFBColor *color, int index ) { CoreSurface *destination; CorePalette *palette = NULL; D_MAGIC_ASSERT( state, CardState ); D_ASSERT( color != NULL ); destination = state->destination; if (destination) palette = destination->palette; if (index < 0) { D_ASSERT( color != NULL ); if (palette) dfb_state_set_color_index( state, dfb_palette_search( palette, color->r, color->g, color->b, color->a ) ); dfb_state_set_color( state, color ); } else { dfb_state_set_color_index( state, index ); if (palette) { D_ASSERT( palette->num_entries > 0 ); D_ASSUME( palette->num_entries > index ); dfb_state_set_color( state, &palette->entries[index % palette->num_entries] ); } } } DFBResult dfb_state_get_acceleration_mask( CardState *state, DFBAccelerationMask *ret_accel ) { DFBAccelerationMask mask = DFXL_NONE; D_MAGIC_ASSERT( state, CardState ); D_ASSERT( ret_accel != NULL ); dfb_state_lock( state ); /* Check drawing functions. */ if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE )) D_FLAGS_SET( mask, DFXL_FILLRECTANGLE ); if (dfb_gfxcard_state_check( state, DFXL_DRAWRECTANGLE )) D_FLAGS_SET( mask, DFXL_DRAWRECTANGLE ); if (dfb_gfxcard_state_check( state, DFXL_DRAWLINE )) D_FLAGS_SET( mask, DFXL_DRAWLINE ); if (dfb_gfxcard_state_check( state, DFXL_FILLTRIANGLE )) D_FLAGS_SET( mask, DFXL_FILLTRIANGLE ); if (dfb_gfxcard_state_check( state, DFXL_FILLTRAPEZOID )) D_FLAGS_SET( mask, DFXL_FILLTRAPEZOID ); /* Check blitting functions. */ if (state->source) { if (dfb_gfxcard_state_check( state, DFXL_BLIT )) D_FLAGS_SET( mask, DFXL_BLIT ); if (dfb_gfxcard_state_check( state, DFXL_STRETCHBLIT )) D_FLAGS_SET( mask, DFXL_STRETCHBLIT ); if (dfb_gfxcard_state_check( state, DFXL_TEXTRIANGLES )) D_FLAGS_SET( mask, DFXL_TEXTRIANGLES ); } if (state->source2) { if (dfb_gfxcard_state_check( state, DFXL_BLIT2 )) D_FLAGS_SET( mask, DFXL_BLIT2 ); } dfb_state_unlock( state ); *ret_accel = mask; return DFB_OK; } ================================================ FILE: src/core/state.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__STATE_H__ #define __CORE__STATE_H__ #include #include #include #include /**********************************************************************************************************************/ /* * Maximum number of color ids. */ #define DFB_COLOR_IDS_MAX 8 typedef enum { CSF_NONE = 0x00000000, /* none of these */ CSF_DESTINATION = 0x00000001, /* destination is set using dfb_state_set_destination() */ CSF_SOURCE = 0x00000002, /* source is set using dfb_state_set_source() */ CSF_SOURCE_MASK = 0x00000008, /* source mask is set using dfb_state_set_source_mask() */ CSF_SOURCE_LOCKED = 0x00000010, /* source surface is locked */ CSF_SOURCE_MASK_LOCKED = 0x00000020, /* source mask surface is locked */ CSF_SOURCE2 = 0x00000100, /* source2 is set using dfb_state_set_source2() */ CSF_SOURCE2_LOCKED = 0x00000200, /* source2 surface is locked */ CSF_DRAWING = 0x00010000, /* something has been rendered with this state, this is cleared by flushing the state, e.g. upon flip */ CSF_ALL = 0x0001033B /* all of these */ } CardStateFlags; typedef enum { SMF_NONE = 0x00000000, SMF_DRAWING_FLAGS = 0x00000001, SMF_BLITTING_FLAGS = 0x00000002, SMF_CLIP = 0x00000004, SMF_COLOR = 0x00000008, SMF_SRC_BLEND = 0x00000010, SMF_DST_BLEND = 0x00000020, SMF_SRC_COLORKEY = 0x00000040, SMF_DST_COLORKEY = 0x00000080, SMF_DESTINATION = 0x00000100, SMF_SOURCE = 0x00000200, SMF_SOURCE_MASK = 0x00000400, SMF_SOURCE_MASK_VALS = 0x00000800, SMF_INDEX_TRANSLATION = 0x00001000, SMF_COLORKEY = 0x00002000, SMF_SRC_COLORMATRIX = 0x00008000, SMF_RENDER_OPTIONS = 0x00010000, SMF_MATRIX = 0x00020000, SMF_SRC_COLORKEY_EXTENDED = 0x00040000, SMF_DST_COLORKEY_EXTENDED = 0x00080000, SMF_SOURCE2 = 0x00100000, SMF_SRC_CONVOLUTION = 0x00200000, SMF_FROM = 0x10000000, SMF_TO = 0x20000000, SMF_ALL = 0x303FBFFF } StateModificationFlags; struct __DFB_CardState { /* graphics card state */ int magic; CoreDFB *core; /* core instance */ FusionID fusion_id; /* fusion id */ DirectMutex lock; /* lock for state handling */ CardStateFlags flags; /* flags defining the state */ StateModificationFlags modified; /* indicate which fields have been modified, these flags will be cleared by the gfx drivers */ StateModificationFlags mod_hw; /* modification flags for drivers. */ /* values forming the state for graphics operations */ DFBSurfaceDrawingFlags drawingflags; /* drawing flags */ DFBSurfaceBlittingFlags blittingflags; /* blitting flags */ DFBRegion clip; /* clipping rectangle */ DFBColor color; /* color for drawing or modulation */ unsigned int color_index; /* index to color in palette */ DFBSurfaceBlendFunction src_blend; /* blend function for source */ DFBSurfaceBlendFunction dst_blend; /* blend function for destination */ u32 src_colorkey; /* colorkey for source */ u32 dst_colorkey; /* colorkey for destination */ CoreSurface *destination; /* destination surface */ CoreSurface *source; /* source surface */ CoreSurfaceBuffer *source_buffer; /* source surface */ DirectSerial dst_serial; /* last destination surface serial */ DirectSerial src_serial; /* last source surface serial */ int *index_translation; /* translation table used for fast indexed to indexed pixel format conversion */ int num_translation; /* translation table size */ /* hardware abstraction and state handling helpers */ DFBAccelerationMask accel; /* remember checked commands if they are accelerated */ DFBAccelerationMask checked; /* commands for which a state has been checked */ DFBAccelerationMask set; /* commands for which a state is valid */ DFBAccelerationMask disabled; /* commands which are disabled temporarily */ CoreGraphicsSerial serial; /* hardware serial of the last operation */ /* from/to buffers */ DFBSurfaceBufferRole from; /* usually DSBR_FRONT */ DFBSurfaceStereoEye from_eye; /* usually DSSE_LEFT */ DFBSurfaceBufferRole to; /* usually DSBR_BACK */ DFBSurfaceStereoEye to_eye; /* usually DSSE_LEFT */ /* read/write locks during operation */ CoreSurfaceBufferLock dst; /* destination read/write lock */ CoreSurfaceBufferLock src; /* source read/write lock */ /* software driver */ GenefxState *gfxs; /* state of the virtual graphics processing unit */ /* extended state */ DFBSurfaceRenderOptions render_options; /* options for drawing and blitting operations */ DFBColorKey colorkey; /* key for color key protection */ s32 matrix[9]; /* transformation matrix for DSRO_MATRIX */ DFBBoolean affine_matrix; /* true if affine transformation */ CoreSurface *source_mask; /* source mask surface */ CoreSurfaceBufferLock src_mask; /* source mask surface lock */ DirectSerial src_mask_serial; /* last source mask surface serial */ DFBPoint src_mask_offset; /* relative or absolute coordinates */ DFBSurfaceMaskFlags src_mask_flags; /* controls coordinate mode and more */ CoreSurface *source2; /* source2 surface */ DirectSerial src2_serial; /* last source2 surface serial */ CoreSurfaceBufferLock src2; /* source2 surface lock */ DFBColor colors[DFB_COLOR_IDS_MAX]; /* colors for drawing or modulation */ unsigned int color_indices[DFB_COLOR_IDS_MAX]; /* indices to colors in palette */ DFBColorKeyExtended src_colorkey_extended; /* extended colorkey for source */ DFBColorKeyExtended dst_colorkey_extended; /* extended colorkey for destination */ s32 src_colormatrix[12]; /* transformation matrix for DSBLIT_SRC_COLORMATRIX */ DFBConvolutionFilter src_convolution; /* 3x3 kernel, scale and bias */ void *gfxcard_data; /* gfx driver specific state data */ u32 source_flip_count; /* source flip count */ bool source_flip_count_used; /* source flip count used */ void *client; /* state client */ u32 destination_flip_count; /* destination flip count */ bool destination_flip_count_used; /* destination flip count used */ }; /**********************************************************************************************************************/ int dfb_state_init ( CardState *state, CoreDFB *core ); void dfb_state_destroy ( CardState *state ); DFBResult dfb_state_set_destination ( CardState *state, CoreSurface *destination ); DFBResult dfb_state_set_destination_2 ( CardState *state, CoreSurface *destination, u32 flip_count ); DFBResult dfb_state_set_source ( CardState *state, CoreSurface *source ); DFBResult dfb_state_set_source_2 ( CardState *state, CoreSurface *source, u32 flip_count ); DFBResult dfb_state_set_source2 ( CardState *state, CoreSurface *source2 ); DFBResult dfb_state_set_source_mask ( CardState *state, CoreSurface *source_mask ); void dfb_state_update ( CardState *state, bool update_source ); void dfb_state_update_destination ( CardState *state ); void dfb_state_update_sources ( CardState *state, CardStateFlags flags ); DFBResult dfb_state_set_index_translation( CardState *state, const int *indices, int num_indices ); void dfb_state_set_matrix ( CardState *state, const s32 *matrix ); void dfb_state_set_src_colormatrix ( CardState *state, const s32 *matrix ); void dfb_state_set_src_convolution ( CardState *state, const DFBConvolutionFilter *filter ); /* * Multifunctional color configuration function. Always tries to set both color and index. * * If color index is -1, color is used and searched in palette of destination surface if present. * If color index is valid the color is looked up in palette if present. */ void dfb_state_set_color_or_index ( CardState *state, const DFBColor *color, int index ); /* * Return the mask of accelerated functions. */ DFBResult dfb_state_get_acceleration_mask( CardState *state, DFBAccelerationMask *ret_accel ); /**********************************************************************************************************************/ static __inline__ void dfb_state_lock( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); direct_mutex_lock( &state->lock ); } static __inline__ void dfb_state_start_drawing( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->destination != NULL ); if (dfb_config->startstop) { if (!(state->flags & CSF_DRAWING)) { dfb_gfxcard_start_drawing( state ); state->flags = state->flags | CSF_DRAWING; } } } static __inline__ void dfb_state_stop_drawing( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( state->destination != NULL ); if (dfb_config->startstop) { if (state->flags & CSF_DRAWING) { dfb_gfxcard_stop_drawing( state ); state->flags = state->flags & ~CSF_DRAWING; } } } static __inline__ void dfb_state_unlock( CardState *state ) { D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( &state->clip ); direct_mutex_unlock( &state->lock ); } static __inline__ void dfb_state_set_from( CardState *state, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( role == DSBR_FRONT || role == DSBR_BACK || role == DSBR_IDLE ); D_ASSERT( eye == DSSE_LEFT || eye == DSSE_RIGHT ); if (state->from != role || state->from_eye != eye) { state->from = role; state->from_eye = eye; state->modified = state->modified | SMF_SOURCE | SMF_SOURCE2 | SMF_SOURCE_MASK | SMF_FROM; } } static __inline__ void dfb_state_set_to( CardState *state, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( role == DSBR_FRONT || role == DSBR_BACK || role == DSBR_IDLE ); D_ASSERT( eye == DSSE_LEFT || eye == DSSE_RIGHT ); if (state->to != role || state->to_eye != eye) { state->to = role; state->to_eye = eye; state->modified = state->modified | SMF_DESTINATION | SMF_TO; } } static __inline__ void dfb_state_set_clip( CardState *state, const DFBRegion *clip ) { D_MAGIC_ASSERT( state, CardState ); DFB_REGION_ASSERT( clip ); if (!DFB_REGION_EQUAL( state->clip, *clip )) { state->clip = *clip; state->modified = state->modified | SMF_CLIP; } } static __inline__ void dfb_state_set_color( CardState *state, const DFBColor *color ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( color != NULL ); if (!DFB_COLOR_EQUAL( state->color, *color )) { state->color = *color; state->modified = state->modified | SMF_COLOR; } } static __inline__ void dfb_state_set_colorkey( CardState *state, const DFBColorKey *key ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( key != NULL ); if (!DFB_COLORKEY_EQUAL( state->colorkey, *key )) { state->colorkey = *key; state->modified = state->modified | SMF_COLORKEY; } } static __inline__ void dfb_state_set_source_mask_vals( CardState *state, const DFBPoint *offset, DFBSurfaceMaskFlags flags ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( offset != NULL ); D_FLAGS_ASSERT( flags, DSMF_ALL ); if (!DFB_POINT_EQUAL( state->src_mask_offset, *offset ) || state->src_mask_flags != flags) { state->src_mask_offset = *offset; state->src_mask_flags = flags; state->modified = state->modified | SMF_SOURCE_MASK_VALS; } } static __inline__ void dfb_state_set_src_colorkey_extended( CardState *state, const DFBColorKeyExtended *key ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( key != NULL ); if (state->src_colorkey_extended.polarity != key->polarity || !DFB_COLOR_EQUAL( state->src_colorkey_extended.lower, key->lower ) || !DFB_COLOR_EQUAL( state->src_colorkey_extended.upper, key->upper )) { state->src_colorkey_extended = *key; state->modified = state->modified | SMF_SRC_COLORKEY_EXTENDED; } } static __inline__ void dfb_state_set_dst_colorkey_extended( CardState *state, const DFBColorKeyExtended *key ) { D_MAGIC_ASSERT( state, CardState ); D_ASSERT( key != NULL ); if (state->dst_colorkey_extended.polarity != key->polarity || !DFB_COLOR_EQUAL( state->dst_colorkey_extended.lower, key->lower ) || !DFB_COLOR_EQUAL( state->dst_colorkey_extended.upper, key->upper )) { state->dst_colorkey_extended = *key; state->modified = state->modified | SMF_DST_COLORKEY_EXTENDED; } } #define _dfb_state_set_checked(member,flag,state,value) \ do { \ D_MAGIC_ASSERT( state, CardState ); \ \ if ((value) != (state)->member) { \ (state)->member = (value); \ (state)->modified = (state)->modified | SMF_##flag; \ } \ } while (0) #define dfb_state_set_drawing_flags(state,flags) _dfb_state_set_checked( drawingflags, DRAWING_FLAGS, state, flags ) #define dfb_state_set_blitting_flags(state,flags) _dfb_state_set_checked( blittingflags, BLITTING_FLAGS, state, flags ) #define dfb_state_set_color_index(state,index) _dfb_state_set_checked( color_index, COLOR, state, index ) #define dfb_state_set_src_blend(state,blend) _dfb_state_set_checked( src_blend, SRC_BLEND, state, blend ) #define dfb_state_set_dst_blend(state,blend) _dfb_state_set_checked( dst_blend, DST_BLEND, state, blend ) #define dfb_state_set_src_colorkey(state,key) _dfb_state_set_checked( src_colorkey, SRC_COLORKEY, state, key ) #define dfb_state_set_dst_colorkey(state,key) _dfb_state_set_checked( dst_colorkey, DST_COLORKEY, state, key ) #define dfb_state_set_render_options(state,opts) _dfb_state_set_checked( render_options, RENDER_OPTIONS, state, opts ) #endif ================================================ FILE: src/core/surface.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Surface, "Core/Surface", "DirectFB Core Surface" ); D_DEBUG_DOMAIN( Core_Surface_Updates, "Core/Surface/Updates", "DirectFB Core Surface Updates" ); /**********************************************************************************************************************/ static __inline__ void dfb_surface_set_stereo_eye( CoreSurface *surface, DFBSurfaceStereoEye eye ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( eye & (DSSE_LEFT | DSSE_RIGHT) ); if (eye & DSSE_LEFT) surface->buffers = surface->left_buffers; else surface->buffers = surface->right_buffers; } static __inline__ DFBSurfaceStereoEye dfb_surface_get_stereo_eye( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); if (surface->buffers == surface->left_buffers) return DSSE_LEFT; else return DSSE_RIGHT; } static void keep_frame( CoreSurface *surface ) { CoreSurfaceBuffer *buffer = surface->left_buffers[surface->buffer_indices[surface->flips % surface->num_buffers]]; D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); D_DEBUG_AT( Core_Surface, " -> buffer %p\n", buffer ); if (!buffer->busy++) { CoreSurfaceBuffer *old = NULL; fusion_hash_replace( surface->frames, (void*)(long) (surface->flips * 2), buffer, NULL, (void**) &old ); D_ASSERT( old == NULL ); } if (surface->config.caps & DSCAPS_STEREO) { buffer = surface->right_buffers[surface->buffer_indices[surface->flips % surface->num_buffers]]; D_DEBUG_AT( Core_Surface, " -> buffer %p\n", buffer ); if (!buffer->busy++) { CoreSurfaceBuffer *old = NULL; fusion_hash_replace( surface->frames, (void*)(long) (surface->flips * 2 + 1), buffer, NULL, (void**) &old ); D_ASSERT( old == NULL ); } } } static void release_frame( CoreSurface *surface, u32 flip_count ) { CoreSurfaceBuffer *buffer; D_DEBUG_AT( Core_Surface, "%s( %p, flip_count %u )\n", __FUNCTION__, surface, flip_count ); buffer = fusion_hash_lookup( surface->frames, (void*)(long) (flip_count * 2) ); if (buffer) { D_DEBUG_AT( Core_Surface, " -> buffer %p\n", buffer ); if (buffer->busy-- == 1 && (buffer->flags & CSBF_DECOUPLE)) dfb_surface_buffer_decouple( buffer ); fusion_hash_remove( surface->frames, (void*)(long) (flip_count * 2), NULL, NULL ); } buffer = fusion_hash_lookup( surface->frames, (void*)(long) (flip_count * 2 + 1) ); if (buffer) { D_DEBUG_AT( Core_Surface, " -> buffer %p\n", buffer ); if (buffer->busy-- == 1 && (buffer->flags & CSBF_DECOUPLE)) dfb_surface_buffer_decouple( buffer ); fusion_hash_remove( surface->frames, (void*)(long) (flip_count * 2 + 1), NULL, NULL ); } } /**********************************************************************************************************************/ static const ReactionFunc dfb_surface_globals[] = { _dfb_layer_region_surface_listener, _dfb_windowstack_background_image_listener, NULL }; static bool surface_destructor_buffers_iterator( FusionHash *hash, void *key, void *value, void *ctx ) { CoreSurface *surface = ctx; CoreSurfaceBuffer *buffer = value; int i; buffer->busy = 0; dfb_surface_buffer_decouple( buffer ); for (i = 0; i < surface->num_buffers; i++) { if (surface->buffers[i] == buffer) surface->buffers[i] = NULL; } fusion_hash_remove( surface->frames, key, NULL, NULL ); return true; } static void surface_destructor( FusionObject *object, bool zombie, void *ctx ) { int i; int num_eyes; DFBSurfaceStereoEye eye; CoreSurface *surface = (CoreSurface*) object; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "Destroying surface %p (%dx%d%s)\n", surface, surface->config.size.w, surface->config.size.h, zombie ? " ZOMBIE" : "" ); Core_Resource_RemoveSurface( surface ); CoreSurface_Deinit_Dispatch( &surface->call ); dfb_surface_lock( surface ); surface->state |= CSSF_DESTROYED; /* Announce surface destruction. */ dfb_surface_notify( surface, CSNF_DESTROY ); dfb_surface_dispatch_event( surface, DSEVT_DESTROYED ); /* Unlink palette. */ if (surface->palette) { dfb_palette_detach_global( surface->palette, &surface->palette_reaction ); dfb_palette_unlink( &surface->palette ); } while (fusion_hash_size( surface->frames ) > 0) fusion_hash_iterate( surface->frames, surface_destructor_buffers_iterator, surface ); /* Destroy the surface buffers. */ num_eyes = surface->config.caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < surface->num_buffers; i++) { if (surface->buffers[i]) { dfb_surface_buffer_decouple( surface->buffers[i] ); surface->buffers[i] = NULL; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); /* Release the system driver specific surface data. */ if (surface->data) { SHFREE( surface->shmpool, surface->data ); surface->data = NULL; } direct_serial_deinit( &surface->serial ); direct_serial_deinit( &surface->config_serial ); dfb_surface_unlock( surface ); fusion_vector_destroy( &surface->clients ); fusion_skirmish_destroy( &surface->lock ); fusion_hash_destroy( surface->frames ); D_MAGIC_CLEAR( surface ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_surface_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Surface Pool", sizeof(CoreSurface), sizeof(CoreSurfaceNotification), surface_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_surface_create( CoreDFB *core, const CoreSurfaceConfig *config, CoreSurfaceTypeFlags type, unsigned long resource_id, CorePalette *palette, CoreSurface **ret_surface ) { DFBResult ret = DFB_BUG; int i; int buffers; CoreSurface *surface; char buf[64]; int num_eyes; DFBSurfaceStereoEye eye; D_ASSERT( core != NULL ); D_FLAGS_ASSERT( type, CSTF_ALL ); D_MAGIC_ASSERT_IF( palette, CorePalette ); D_ASSERT( ret_surface != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p, %p, %p )\n", __FUNCTION__, core, config, ret_surface ); /* Create the surface object. */ surface = dfb_core_create_surface( core ); if (!surface) return DFB_FUSION; surface->data = NULL; if (config) { D_FLAGS_ASSERT( config->flags, CSCONF_ALL ); surface->config.flags = config->flags; if (config->flags & CSCONF_SIZE) { D_DEBUG_AT( Core_Surface, " -> %dx%d\n", config->size.w, config->size.h ); surface->config.size = config->size; } if (config->flags & CSCONF_FORMAT) { D_DEBUG_AT( Core_Surface, " -> %s\n", dfb_pixelformat_name( config->format ) ); surface->config.format = config->format; } if (config->flags & CSCONF_COLORSPACE) { D_DEBUG_AT( Core_Surface, " -> %s\n", dfb_colorspace_name( config->colorspace ) ); surface->config.colorspace = config->colorspace; } if (config->flags & CSCONF_CAPS) { D_DEBUG_AT( Core_Surface, " -> caps 0x%08x\n", config->caps ); surface->config.caps = config->caps & ~DSCAPS_ROTATED; } if (config->flags & CSCONF_PREALLOCATED) { D_DEBUG_AT( Core_Surface, " -> prealloc %p [%u]\n", config->preallocated[0].addr, config->preallocated[0].pitch ); direct_memcpy( surface->config.preallocated, config->preallocated, sizeof(config->preallocated) ); surface->config.preallocated_pool_id = config->preallocated_pool_id; type |= CSTF_PREALLOCATED; } } if (surface->config.caps & DSCAPS_SYSTEMONLY) surface->type = (type & ~CSTF_EXTERNAL) | CSTF_INTERNAL; else if (surface->config.caps & DSCAPS_VIDEOONLY) surface->type = (type & ~CSTF_INTERNAL) | CSTF_EXTERNAL; else surface->type = type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); if (surface->config.caps & DSCAPS_SHARED) surface->type |= CSTF_SHARED; surface->resource_id = resource_id; if (surface->config.caps & DSCAPS_TRIPLE) buffers = 3; else if (surface->config.caps & DSCAPS_DOUBLE) buffers = 2; else { buffers = 1; surface->config.caps &= ~DSCAPS_ROTATED; } surface->notifications = CSNF_ALL & ~CSNF_FLIP; surface->alpha_ramp[0] = 0x00; surface->alpha_ramp[1] = 0x55; surface->alpha_ramp[2] = 0xaa; surface->alpha_ramp[3] = 0xff; if (surface->config.caps & DSCAPS_STATIC_ALLOC) surface->config.min_size = surface->config.size; surface->shmpool = dfb_core_shmpool( core ); direct_serial_init( &surface->serial ); direct_serial_init( &surface->config_serial ); direct_serial_increase( &surface->config_serial ); fusion_vector_init( &surface->clients, 2, surface->shmpool ); snprintf( buf, sizeof(buf), "Surface %dx%d %s %s", surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), dfb_colorspace_name( surface->config.colorspace ) ); fusion_ref_set_name( &surface->object.ref, buf ); fusion_skirmish_init2( &surface->lock, buf, dfb_core_world( core ), fusion_config->secure_fusion ); fusion_reactor_direct( surface->object.reactor, false ); fusion_hash_create( surface->shmpool, HASH_INT, HASH_PTR, 7, &surface->frames ); D_MAGIC_SET( surface, CoreSurface ); if (dfb_config->warn.flags & DCWF_CREATE_SURFACE && dfb_config->warn.create_surface.min_size.w <= surface->config.size.w && dfb_config->warn.create_surface.min_size.h <= surface->config.size.h) D_WARN( "create-surface %4dx%4d %6s, buffers %d, caps 0x%08x, type 0x%08x", surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), buffers, surface->config.caps, surface->type ); if (palette) { dfb_surface_set_palette( surface, palette ); } else if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) { ret = dfb_surface_init_palette( core, surface ); if (ret) goto error; } dfb_surface_lock( surface ); /* Create the surface buffers. */ num_eyes = config->caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < buffers; i++) { ret = dfb_surface_buffer_create( core, surface, (eye == DSSE_RIGHT) ? CSBF_RIGHT : CSBF_NONE, i, &surface->buffers[i] ); if (ret) { D_DERROR( ret, "Core/Surface: Error creating surface buffer!\n" ); dfb_surface_unlock( surface ); goto error; } dfb_surface_buffer_globalize( surface->buffers[i] ); if (eye == DSSE_LEFT) surface->num_buffers++; switch (i) { case 0: surface->buffer_indices[DSBR_FRONT] = i; case 1: surface->buffer_indices[DSBR_BACK] = i; case 2: surface->buffer_indices[DSBR_IDLE] = i; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); dfb_surface_unlock( surface ); CoreSurface_Init_Dispatch( core, surface, &surface->call ); /* Activate the object. */ fusion_object_activate( &surface->object ); if (dfb_config->surface_clear) dfb_surface_clear_buffers( surface ); /* Return the new surface. */ *ret_surface = surface; D_DEBUG_AT( Core_Surface, " -> %p\n", surface ); return DFB_OK; error: num_eyes = config->caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < MAX_SURFACE_BUFFERS; i++) { if (surface->buffers[i]) { dfb_surface_buffer_decouple( surface->buffers[i] ); surface->buffers[i] = NULL; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); /* Release the system driver specific surface data. */ if (surface->data) { SHFREE( surface->shmpool, surface->data ); surface->data = NULL; } fusion_skirmish_destroy( &surface->lock ); direct_serial_deinit( &surface->serial ); direct_serial_deinit( &surface->config_serial ); fusion_hash_destroy( surface->frames ); D_MAGIC_CLEAR( surface ); fusion_object_destroy( &surface->object ); return ret; } DFBResult dfb_surface_create_simple ( CoreDFB *core, int width, int height, DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, DFBSurfaceCapabilities caps, CoreSurfaceTypeFlags type, unsigned long resource_id, CorePalette *palette, CoreSurface **ret_surface ) { CoreSurfaceConfig surface_config; D_ASSERT( core != NULL ); D_ASSERT( ret_surface != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s, %p )\n", __FUNCTION__, core, width, height, dfb_pixelformat_name( format ), ret_surface ); surface_config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS; surface_config.size.w = width; surface_config.size.h = height; surface_config.format = format; surface_config.colorspace = colorspace; surface_config.caps = caps; return CoreDFB_CreateSurface( core, &surface_config, type, resource_id, palette, ret_surface ); } DFBResult dfb_surface_init_palette( CoreDFB *core, CoreSurface *surface ) { DFBResult ret; CorePalette *palette; D_DEBUG_AT( Core_Surface, "%s( %p, %p )\n", __FUNCTION__, core, surface ); ret = dfb_palette_create( core, 1 << DFB_COLOR_BITS_PER_PIXEL( surface->config.format ), surface->config.colorspace, &palette ); if (ret) { D_DERROR( ret, "Core/Surface: Error creating palette!\n" ); return ret; } switch (surface->config.format) { case DSPF_LUT8: dfb_palette_generate_rgb332_map( palette ); break; case DSPF_ALUT44: dfb_palette_generate_rgb121_map( palette ); break; default: break; } dfb_surface_set_palette( surface, palette ); dfb_palette_unref( palette ); return DFB_OK; } DFBResult dfb_surface_notify( CoreSurface *surface, CoreSurfaceNotificationFlags flags ) { DFBResult ret; CoreSurfaceNotification notification; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_FLAGS_ASSERT( flags, CSNF_ALL ); D_DEBUG_AT( Core_Surface, "%s( %p [%u] )\n", __FUNCTION__, surface, surface->object.id ); direct_serial_increase( &surface->serial ); if (!(surface->state & CSSF_DESTROYED)) { if (!(surface->notifications & flags)) return DFB_OK; } notification.flags = flags; notification.surface = surface; ret = dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals ); return ret; } DFBResult dfb_surface_notify_display( CoreSurface *surface, CoreSurfaceBuffer *buffer ) { DFBResult ret; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); ret = dfb_surface_notify_display2( surface, dfb_surface_buffer_index( buffer ) ); return ret; } DFBResult dfb_surface_notify_display2( CoreSurface *surface, int index ) { DFBResult ret; CoreSurfaceNotification notification; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( index >= 0 ); D_DEBUG_AT( Core_Surface, "%s( %p, %d )\n", __FUNCTION__, surface, index ); notification.flags = CSNF_DISPLAY; notification.surface = surface; notification.index = index; ret = dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals ); return ret; } DFBResult dfb_surface_notify_frame( CoreSurface *surface, unsigned int flip_count ) { DFBResult ret; CoreSurfaceNotification notification; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_Surface_Updates, "%s( %p, count %u )\n", __FUNCTION__, surface, flip_count ); direct_serial_increase( &surface->serial ); notification.flags = CSNF_FRAME; notification.surface = surface; notification.flip_count = flip_count; ret = dfb_surface_dispatch_channel( surface, CSCH_FRAME, ¬ification, sizeof(notification), dfb_surface_globals ); return ret; } DFBResult dfb_surface_pool_notify( CoreSurface *surface, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, CoreSurfaceNotificationFlags flags ) { DFBResult ret; CoreSurfaceNotification notification; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_ASSERT( buffer->surface == surface ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( allocation->buffer == buffer ); D_FLAGS_ASSERT( flags, CSNF_ALL ); D_ASSERT( flags == CSNF_BUFFER_ALLOCATION_DESTROY ); D_DEBUG_AT( Core_Surface, "%s( %p [%u] )\n", __FUNCTION__, surface, surface->object.id ); if (!(surface->state & CSSF_DESTROYED)) { if (!(surface->notifications & flags)) return DFB_OK; } /* Prepares and sends a notification message that a change is about to happen to the specified surface buffer pool allocation. The notification message will be received by all pocesses that have listeners attached to the associated CoreSurface's reactor. A copy of all the data needed by the listeners is done in order to wait for all the listeners to complete before the buffer allocation is destroyed along with all of its underlying data structures. */ notification.flags = flags; notification.surface = surface; notification.buffer_no_access = buffer; notification.surface_data = surface->data; notification.surface_object_id = surface->object.id; D_DEBUG_AT( Core_Surface, " -> notifying of surface buffer allocation destruction\n" ); ret = dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals ); return ret; } DFBResult dfb_surface_flip( CoreSurface *surface, bool swap ) { DFBResult ret; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p, %sswap )\n", __FUNCTION__, surface, swap ? "" : "no " ); ret = dfb_surface_flip_buffers( surface, swap ); return ret; } DFBResult dfb_surface_flip_buffers( CoreSurface *surface, bool swap ) { unsigned int back, front; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_Surface, "%s( %p, %sswap )\n", __FUNCTION__, surface, swap ? "" : "no " ); if (surface->num_buffers == 0) return DFB_SUSPENDED; back = (surface->flips + DSBR_BACK) % surface->num_buffers; front = (surface->flips + DSBR_FRONT) % surface->num_buffers; D_ASSERT( surface->buffer_indices[back] < surface->num_buffers ); D_ASSERT( surface->buffer_indices[front] < surface->num_buffers ); if (surface->buffers[surface->buffer_indices[back]]->policy != surface->buffers[surface->buffer_indices[front]]->policy || (surface->config.caps & DSCAPS_ROTATED)) return DFB_UNSUPPORTED; if (swap) { int tmp = surface->buffer_indices[back]; surface->buffer_indices[back] = surface->buffer_indices[front]; surface->buffer_indices[front] = tmp; } else surface->flips++; D_DEBUG_AT( Core_Surface, " -> flips %u\n", surface->flips ); dfb_surface_notify( surface, CSNF_FLIP ); return DFB_OK; } DFBResult dfb_surface_dispatch_event( CoreSurface *surface, DFBSurfaceEventType type ) { DFBResult ret; DFBSurfaceEvent event; D_MAGIC_ASSERT( surface, CoreSurface ); event.clazz = DFEC_SURFACE; event.type = type; event.surface_id = surface->object.id; event.time_stamp = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); ret = dfb_surface_dispatch_channel( surface, CSCH_EVENT, &event, sizeof(DFBSurfaceEvent), NULL ); return ret; } DFBResult dfb_surface_dispatch_update( CoreSurface *surface, const DFBRegion *update, const DFBRegion *update_right, long long timestamp, DFBSurfaceFlipFlags flags ) { DFBResult ret; DFBSurfaceEvent event; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_Surface_Updates, "%s( %p [%u], %p / %p, timestamp %lld )\n", __FUNCTION__, surface, surface->object.id, update, update_right, timestamp ); event.clazz = DFEC_SURFACE; event.type = DSEVT_UPDATE; event.surface_id = surface->object.id; event.flip_count = surface->flips; event.flip_flags = flags; event.time_stamp = timestamp ?: direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); surface->last_frame_time = event.time_stamp; D_DEBUG_AT( Core_Surface_Updates, " -> flip count %u\n", event.flip_count ); if (update) { D_DEBUG_AT( Core_Surface_Updates, " -> updated %4d,%4d-%4dx%4d (left)\n", DFB_RECTANGLE_VALS_FROM_REGION( update ) ); event.update = *update; } else { event.update.x1 = 0; event.update.y1 = 0; event.update.x2 = surface->config.size.w - 1; event.update.y2 = surface->config.size.h - 1; } if (update_right) { D_DEBUG_AT( Core_Surface_Updates, " -> updated %4d,%4d-%4dx%4d (right)\n", DFB_RECTANGLE_VALS_FROM_REGION( update_right ) ); event.update_right = *update_right; } else { event.update_right.x1 = 0; event.update_right.y1 = 0; event.update_right.x2 = surface->config.size.w - 1; event.update_right.y2 = surface->config.size.h - 1; } ret = dfb_surface_dispatch_channel( surface, CSCH_EVENT, &event, sizeof(DFBSurfaceEvent), NULL ); if (ret) return ret; D_DEBUG_AT( Core_Surface_Updates, " -> clients %d\n", fusion_vector_size( &surface->clients ) ); if (fusion_vector_is_empty( &surface->clients )) { surface->flips_acked = surface->flips; dfb_surface_notify_frame( surface, surface->flips_acked ); } else keep_frame( surface ); return DFB_OK; } DFBResult dfb_surface_check_acks( CoreSurface *surface ) { int i; CoreSurfaceClient *client; u32 count; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_Surface_Updates, "%s( %p [%u] )\n", __FUNCTION__, surface, surface->object.id ); count = surface->flips; fusion_vector_foreach (client, i, surface->clients) { D_DEBUG_AT( Core_Surface_Updates, " -> client %p [%u] (acked %u)\n", client, client->object.id, client->flip_count ); if (client->flip_count < count) count = client->flip_count; } D_DEBUG_AT( Core_Surface_Updates, " -> lowest count %u (acked %u)\n", count, surface->flips_acked ); if (count > surface->flips_acked) { for (; surface->flips_acked < count; surface->flips_acked++) release_frame( surface, surface->flips_acked ); dfb_surface_notify_frame( surface, surface->flips_acked ); } return DFB_OK; } DFBResult dfb_surface_reconfig( CoreSurface *surface, const CoreSurfaceConfig *config ) { DFBResult ret; int i; int buffers; int num_eyes; DFBSurfaceStereoEye eye; CoreSurfaceConfig new_config; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( config != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s -> %dx%d %s )\n", __FUNCTION__, surface, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), (config->flags & CSCONF_SIZE) ? config->size.w : surface->config.size.w, (config->flags & CSCONF_SIZE) ? config->size.h : surface->config.size.h, (config->flags & CSCONF_FORMAT) ? dfb_pixelformat_name( config->format ) : dfb_pixelformat_name( surface->config.format ) ); if (config->flags & CSCONF_PREALLOCATED) return DFB_UNSUPPORTED; if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; if (surface->type & CSTF_PREALLOCATED) { fusion_skirmish_dismiss( &surface->lock ); return DFB_UNSUPPORTED; } if ((config->flags == CSCONF_SIZE || ((config->flags == (CSCONF_SIZE | CSCONF_FORMAT)) && (config->format == surface->config.format))) && config->size.w <= surface->config.min_size.w && config->size.h <= surface->config.min_size.h) { surface->config.size = config->size; direct_serial_increase( &surface->config_serial ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } new_config = surface->config; if (config->flags & CSCONF_SIZE) new_config.size = config->size; if (config->flags & CSCONF_FORMAT) new_config.format = config->format; if (config->flags & CSCONF_COLORSPACE) new_config.colorspace = config->colorspace; if (config->flags & CSCONF_CAPS) new_config.caps = config->caps & ~DSCAPS_ROTATED; if (new_config.caps & DSCAPS_SYSTEMONLY) surface->type = (surface->type & ~CSTF_EXTERNAL) | CSTF_INTERNAL; else if (new_config.caps & DSCAPS_VIDEOONLY) surface->type = (surface->type & ~CSTF_INTERNAL) | CSTF_EXTERNAL; else surface->type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); if (new_config.caps & DSCAPS_TRIPLE) buffers = 3; else if (new_config.caps & DSCAPS_DOUBLE) buffers = 2; else { buffers = 1; new_config.caps &= ~DSCAPS_ROTATED; } ret = Core_Resource_CheckSurfaceUpdate( surface, &new_config ); if (ret) return ret; direct_serial_increase( &surface->config_serial ); /* Destroy the surface buffers. */ num_eyes = surface->config.caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < surface->num_buffers; i++) { if (surface->buffers[i]) { dfb_surface_buffer_decouple( surface->buffers[i] ); surface->buffers[i] = NULL; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); surface->num_buffers = 0; surface->flips++; Core_Resource_UpdateSurface( surface, &new_config ); surface->config = new_config; /* Recreate the surface buffers. */ num_eyes = new_config.caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < buffers; i++) { CoreSurfaceBuffer *buffer; ret = dfb_surface_buffer_create( core_dfb, surface, (eye == DSSE_RIGHT) ? CSBF_RIGHT : CSBF_NONE, i, &buffer ); if (ret) { D_DERROR( ret, "Core/Surface: Error creating surface buffer!\n" ); goto error; } dfb_surface_buffer_globalize( buffer ); surface->buffers[i] = buffer; if (eye == DSSE_LEFT) surface->num_buffers++; switch (i) { case 0: surface->buffer_indices[DSBR_FRONT] = i; case 1: surface->buffer_indices[DSBR_BACK] = i; case 2: surface->buffer_indices[DSBR_IDLE] = i; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); while (fusion_hash_size( surface->frames ) > 0) fusion_hash_iterate( surface->frames, surface_destructor_buffers_iterator, surface ); dfb_surface_notify( surface, CSNF_SIZEFORMAT ); if (dfb_config->surface_clear) dfb_surface_clear_buffers( surface ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; error: D_UNIMPLEMENTED(); fusion_skirmish_dismiss( &surface->lock ); return ret; } DFBResult dfb_surface_reformat( CoreSurface *surface, int width, int height, DFBSurfacePixelFormat format ) { CoreSurfaceConfig config; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( width > 0 ); D_ASSERT( height > 0 ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); config.flags = CSCONF_SIZE | CSCONF_FORMAT; config.size.w = width; config.size.h = height; config.format = format; return dfb_surface_reconfig( surface, &config ); } DFBResult dfb_surface_destroy_buffers( CoreSurface *surface ) { int i; int num_eyes; DFBSurfaceStereoEye eye; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; if (surface->type & CSTF_PREALLOCATED) { fusion_skirmish_dismiss( &surface->lock ); return DFB_UNSUPPORTED; } /* Destroy the surface buffers. */ num_eyes = surface->config.caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < surface->num_buffers; i++) { if (surface->buffers[i]) { dfb_surface_buffer_decouple( surface->buffers[i] ); surface->buffers[i] = NULL; } } } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); surface->num_buffers = 0; fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_deallocate_buffers( CoreSurface *surface ) { int i; int num_eyes; DFBSurfaceStereoEye eye; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; if (surface->type & CSTF_PREALLOCATED) { fusion_skirmish_dismiss( &surface->lock ); return DFB_UNSUPPORTED; } /* Deallocate the surface buffers. */ num_eyes = surface->config.caps & DSCAPS_STEREO ? 2 : 1; for (eye = DSSE_LEFT; num_eyes > 0; num_eyes--, eye = DSSE_RIGHT) { dfb_surface_set_stereo_eye( surface, eye ); for (i = 0; i < surface->num_buffers; i++) dfb_surface_buffer_deallocate( surface->buffers[i] ); } dfb_surface_set_stereo_eye( surface, DSSE_LEFT ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_destroy( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; dfb_surface_deallocate_buffers( surface ); surface->state |= CSSF_DESTROYED; fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_lock_buffer( CoreSurface *surface, DFBSurfaceBufferRole role, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *ret_lock ) { DFBResult ret; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p, accessor 0x%02x, access 0x%02x, role %u) <- %dx%d %s\n", __FUNCTION__, surface, accessor, access, role, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ) ); ret = CoreSurface_PreLockBuffer2( surface, role, dfb_surface_get_stereo_eye( surface ), accessor, access, true, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* Lock the allocation. */ dfb_surface_buffer_lock_init( ret_lock, accessor, access ); ret = dfb_surface_pool_lock( allocation->pool, allocation, ret_lock ); if (ret) { D_DERROR( ret, "Core/Surface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( ret_lock ); dfb_surface_allocation_unref( allocation ); return ret; } return DFB_OK; } DFBResult dfb_surface_lock_buffer2( CoreSurface *surface, DFBSurfaceBufferRole role, u32 flip_count, DFBSurfaceStereoEye eye, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *ret_lock ) { DFBResult ret; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p, accessor 0x%02x, access 0x%02x, role %u, count %u, eye %u ) <- %dx%d %s\n", __FUNCTION__, surface, accessor, access, role, flip_count, eye, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ) ); ret = CoreSurface_PreLockBuffer3( surface, role, flip_count, eye, accessor, access, true, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* Lock the allocation. */ dfb_surface_buffer_lock_init( ret_lock, accessor, access ); ret = dfb_surface_pool_lock( allocation->pool, allocation, ret_lock ); if (ret) { D_DERROR( ret, "Core/Surface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( ret_lock ); dfb_surface_allocation_unref( allocation ); return ret; } return DFB_OK; } DFBResult dfb_surface_unlock_buffer( CoreSurface *surface, CoreSurfaceBufferLock *lock ) { DFBResult ret; D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); ret = dfb_surface_buffer_unlock( lock ); return ret; } DFBResult dfb_surface_read_buffer( CoreSurface *surface, DFBSurfaceBufferRole role, void *destination, int pitch, const DFBRectangle *rect ) { DFBResult ret; int y; int bytes; DFBRectangle rectangle; DFBSurfacePixelFormat format; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( destination != NULL ); D_ASSERT( pitch > 0 ); DFB_RECTANGLE_ASSERT_IF( rect ); D_DEBUG_AT( Core_Surface, "%s( %p, %p, %d )\n", __FUNCTION__, surface, destination, pitch ); /* Determine area. */ rectangle.x = 0; rectangle.y = 0; rectangle.w = surface->config.size.w; rectangle.h = surface->config.size.h; if (rect && (!dfb_rectangle_intersect( &rectangle, rect ) || !DFB_RECTANGLE_EQUAL( rectangle, *rect ))) return DFB_INVAREA; /* Calculate bytes per read line. */ format = surface->config.format; bytes = DFB_BYTES_PER_LINE( format, rectangle.w ); D_DEBUG_AT( Core_Surface, " -> %4d,%4d-%4dx%4d (%s)\n", DFB_RECTANGLE_VALS( &rectangle ), dfb_pixelformat_name( format ) ); ret = CoreSurface_PreLockBuffer2( surface, role, dfb_surface_get_stereo_eye( surface ), CSAID_CPU, CSAF_READ, false, &allocation ); if (ret == DFB_NOALLOCATION) { for (y = 0; y < rectangle.h; y++) { memset( destination, 0, bytes ); destination += pitch; } return DFB_OK; } if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* Try reading from allocation directly... */ ret = dfb_surface_pool_read( allocation->pool, allocation, destination, pitch, &rectangle ); if (ret) { /* ...otherwise use fallback method via locking if possible. */ if (allocation->access[CSAID_CPU] & CSAF_READ) { CoreSurfaceBufferLock lock; /* Lock the allocation. */ dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ ); ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); if (ret) { D_DERROR( ret, "Core/Surface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); dfb_surface_allocation_unref( allocation ); return ret; } /* Move to start of read. */ lock.addr += DFB_BYTES_PER_LINE( format, rectangle.x ) + rectangle.y * lock.pitch; /* Copy the data. */ for (y = 0; y < rectangle.h; y++) { direct_memcpy( destination, lock.addr, bytes ); destination += pitch; lock.addr += lock.pitch; } /* Unlock the allocation. */ ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock ); if (ret) D_DERROR( ret, "Core/Surface: Unlocking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); } } dfb_surface_allocation_unref( allocation ); return DFB_OK; } DFBResult dfb_surface_write_buffer( CoreSurface *surface, DFBSurfaceBufferRole role, const void *source, int pitch, const DFBRectangle *rect ) { DFBResult ret; DFBRectangle rectangle; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( pitch > 0 || source == NULL ); DFB_RECTANGLE_ASSERT_IF( rect ); D_DEBUG_AT( Core_Surface, "%s( %p, %p, %d )\n", __FUNCTION__, surface, source, pitch ); /* Determine area. */ rectangle.x = 0; rectangle.y = 0; rectangle.w = surface->config.size.w; rectangle.h = surface->config.size.h; if (rect) { if (!dfb_rectangle_intersect( &rectangle, rect )) { D_DEBUG_AT( Core_Surface, " -> no intersection!\n" ); return DFB_INVAREA; } if (!DFB_RECTANGLE_EQUAL( rectangle, *rect )) { D_DEBUG_AT( Core_Surface, " -> got clipped to %4d,%4d-%4dx%4d!\n", DFB_RECTANGLE_VALS( &rectangle ) ); return DFB_INVAREA; } } D_DEBUG_AT( Core_Surface, " -> %4d,%4d-%4dx%4d (%s)\n", DFB_RECTANGLE_VALS( &rectangle ), dfb_pixelformat_name( surface->config.format ) ); ret = CoreSurface_PreLockBuffer2( surface, role, dfb_surface_get_stereo_eye( surface ), CSAID_CPU, CSAF_WRITE, false, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* Try writing to allocation directly... */ ret = source ? dfb_surface_pool_write( allocation->pool, allocation, source, pitch, &rectangle ) : DFB_UNSUPPORTED; if (ret) { /* ...otherwise use fallback method via locking if possible. */ if (allocation->access[CSAID_CPU] & CSAF_WRITE) { int y; int bytes; DFBSurfacePixelFormat format; CoreSurfaceBufferLock lock; /* Calculate bytes per written line. */ format = surface->config.format; bytes = DFB_BYTES_PER_LINE( format, rectangle.w ); /* Lock the allocation. */ dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_WRITE ); ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); if (ret) { D_DERROR( ret, "Core/Surface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); dfb_surface_allocation_unref( allocation ); return ret; } /* Move to start of write. */ lock.addr += DFB_BYTES_PER_LINE( format, rectangle.x ) + rectangle.y * lock.pitch; /* Copy the data. */ for (y = 0; y < rectangle.h; y++) { if (source) { direct_memcpy( lock.addr, source, bytes ); source += pitch; } else memset( lock.addr, 0, bytes ); lock.addr += lock.pitch; } /* Unlock the allocation. */ ret = dfb_surface_pool_unlock( allocation->pool, allocation, &lock ); if (ret) D_DERROR( ret, "Core/Surface: Unlocking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); } } dfb_surface_allocation_unref( allocation ); return DFB_OK; } DFBResult dfb_surface_clear_buffers( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (surface->num_buffers == 0) return DFB_SUSPENDED; if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; dfb_gfx_clear( surface, DSBR_FRONT ); if (surface->config.caps & DSCAPS_FLIPPING) dfb_gfx_clear( surface, DSBR_BACK ); if (surface->config.caps & DSCAPS_TRIPLE) dfb_gfx_clear( surface, DSBR_IDLE ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_dump_buffer( CoreSurface *surface, DFBSurfaceBufferRole role, const char *path, const char *prefix ) { DFBResult ret; CoreSurfaceBuffer *buffer; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( path != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; if (surface->num_buffers == 0) { fusion_skirmish_dismiss( &surface->lock ); return DFB_SUSPENDED; } buffer = dfb_surface_get_buffer( surface, role ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); ret = buffer->allocs.count ? dfb_surface_buffer_dump( buffer, path, prefix ) : DFB_BUFFEREMPTY; fusion_skirmish_dismiss( &surface->lock ); return ret; } DFBResult dfb_surface_dump_buffer2( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *path, const char *prefix ) { DFBResult ret; int num = -1; int i, n; int len = (path ? strlen( path ) : 0) + (prefix ? strlen( prefix ) : 0) + 40; char filename[len]; char head[30]; bool rgb = false; bool alpha = false; size_t bytes; CorePalette *palette = NULL; CoreSurfaceAllocation *allocation; CoreSurfaceBufferLock lock; DirectFile fd_p, fd_g; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( path != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); ret = CoreSurface_PreLockBuffer2( surface, role, eye, CSAID_CPU, CSAF_READ, true, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_Surface, " -> PreLockBuffer returned allocation %p (%s)\n", allocation, allocation->pool->desc.name ); /* Lock the allocation. */ dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ ); ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); if (ret) { D_DERROR( ret, "Core/Surface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &lock ); dfb_surface_allocation_unref( allocation ); return ret; } /* Check pixel format. */ switch (lock.buffer->config.format) { case DSPF_LUT8: palette = surface->palette; if (!palette) { D_BUG( "no palette" ); dfb_surface_buffer_unlock( &lock ); return DFB_BUG; } if (dfb_palette_ref( palette )) { dfb_surface_buffer_unlock( &lock ); return DFB_FUSION; } rgb = true; /* fall through */ case DSPF_A8: alpha = true; break; case DSPF_ARGB: case DSPF_ABGR: case DSPF_ARGB1555: case DSPF_RGBA5551: case DSPF_ARGB2554: case DSPF_ARGB4444: case DSPF_AiRGB: case DSPF_ARGB8565: case DSPF_AYUV: case DSPF_AVYU: alpha = true; /* fall through */ case DSPF_RGB332: case DSPF_RGB444: case DSPF_RGB555: case DSPF_BGR555: case DSPF_RGB16: case DSPF_RGB24: case DSPF_BGR24: case DSPF_RGB32: case DSPF_YUY2: case DSPF_UYVY: case DSPF_VYU: case DSPF_I420: case DSPF_YV12: case DSPF_NV12: case DSPF_NV21: case DSPF_Y42B: case DSPF_YV16: case DSPF_NV16: case DSPF_NV61: case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: rgb = true; break; default: D_ERROR( "Core/Surface: Surface dump for format '%s' is not implemented!\n", dfb_pixelformat_name( lock.buffer->config.format ) ); dfb_surface_buffer_unlock( &lock ); return DFB_UNSUPPORTED; } if (prefix) { /* Find the lowest unused index. */ while (++num < 10000) { snprintf( filename, len, "%s/%s_%04d.ppm", path, prefix, num ); ret = direct_access( filename, F_OK ); if (ret) { snprintf( filename, len, "%s/%s_%04d.pgm", path, prefix, num ); ret = direct_access( filename, F_OK ); if (ret) break; } } if (num == 10000) { D_ERROR( "Core/Surface: Could not find an unused index for surface dump!\n" ); dfb_surface_buffer_unlock( &lock ); if (palette) dfb_palette_unref( palette ); return DFB_FAILURE; } } /* Create a file with the found index. */ if (rgb) { if (prefix) snprintf( filename, len, "%s/%s_%04d.ppm", path, prefix, num ); else snprintf( filename, len, "%s.ppm", path ); ret = direct_file_open( &fd_p, filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); if (ret) { D_DERROR( ret, "Core/Surface: Could not open '%s'!\n", filename ); dfb_surface_buffer_unlock( &lock ); if (palette) dfb_palette_unref( palette ); return ret; } } /* Create a graymap for the alpha channel using the found index. */ if (alpha) { if (prefix) snprintf( filename, len, "%s/%s_%04d.pgm", path, prefix, num ); else snprintf( filename, len, "%s.pgm", path ); ret = direct_file_open( &fd_g, filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); if (ret) { D_DERROR( ret, "Core/Surface: Could not open '%s'!\n", filename ); dfb_surface_buffer_unlock( &lock ); if (palette) dfb_palette_unref( palette ); if (rgb) { direct_file_close( &fd_p ); if (prefix) snprintf( filename, len, "%s/%s_%04d.ppm", path, prefix, num ); else snprintf( filename, len, "%s.ppm", path ); direct_unlink( filename ); } return ret; } } if (rgb) { /* Write the pixmap header. */ snprintf( head, sizeof(head), "P6\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); direct_file_write( &fd_p, head, strlen( head ), &bytes ); } /* Write the graymap header. */ if (alpha) { snprintf( head, sizeof(head), "P5\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); direct_file_write( &fd_g, head, strlen( head ), &bytes ); } /* Write the pixmap (and graymap) data. */ for (i = 0; i < surface->config.size.h; i++) { int n3; /* Prepare one row. */ u8 *srces[3] = { NULL, NULL, NULL }; int pitches[3] = { 0, 0, 0 }; u8 *src8; dfb_surface_get_data_offsets( &surface->config, lock.addr, lock.pitch, 0, i, 3, srces, pitches ); src8 = srces[0]; /* Write color buffer to pixmap file. */ if (rgb) { u8 buf_p[surface->config.size.w*3]; if (lock.buffer->config.format == DSPF_LUT8) { for (n = 0, n3 = 0; n < surface->config.size.w; n++, n3 += 3) { buf_p[n3+0] = palette->entries[src8[n]].r; buf_p[n3+1] = palette->entries[src8[n]].g; buf_p[n3+2] = palette->entries[src8[n]].b; } } else dfb_convert_to_rgb24( lock.buffer->config.format, lock.buffer->config.colorspace, srces[0], pitches[0], srces[1], pitches[1], srces[2], pitches[2], surface->config.size.h, buf_p, surface->config.size.w * 3, surface->config.size.w, 1 ); direct_file_write( &fd_p, buf_p, surface->config.size.w * 3, &bytes ); } /* Write alpha buffer to graymap file. */ if (alpha) { u8 buf_g[surface->config.size.w]; if (lock.buffer->config.format == DSPF_LUT8) { for (n = 0; n < surface->config.size.w; n++) buf_g[n] = palette->entries[src8[n]].a; } else dfb_convert_to_a8( lock.buffer->config.format, srces[0], pitches[0], surface->config.size.h, buf_g, surface->config.size.w, surface->config.size.w, 1 ); direct_file_write( &fd_g, buf_g, surface->config.size.w, &bytes ); } } /* Unlock the surface buffer. */ dfb_surface_buffer_unlock( &lock ); /* Release the palette. */ if (palette) dfb_palette_unref( palette ); /* Close pixmap file. */ if (rgb) direct_file_close( &fd_p ); /* Close graymap file. */ if (alpha) direct_file_close( &fd_g ); return DFB_OK; } DFBResult dfb_surface_dump_raw_buffer( CoreSurface *surface, DFBSurfaceBufferRole role, const char *path, const char *prefix ) { DFBResult ret; CoreSurfaceBuffer *buffer; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( path != NULL ); D_ASSERT( prefix != NULL ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (surface->num_buffers == 0) return DFB_SUSPENDED; if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; buffer = dfb_surface_get_buffer( surface, role ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); ret = dfb_surface_buffer_dump_raw( buffer, path, prefix ); fusion_skirmish_dismiss( &surface->lock ); return ret; } DFBResult dfb_surface_set_palette( CoreSurface *surface, CorePalette *palette ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_MAGIC_ASSERT_IF( palette, CorePalette ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; if (surface->palette != palette) { if (surface->palette) { dfb_palette_detach_global( surface->palette, &surface->palette_reaction ); dfb_palette_unlink( &surface->palette ); } if (palette) { dfb_palette_link( &surface->palette, palette ); dfb_palette_attach_global( palette, DFB_SURFACE_PALETTE_LISTENER, surface, &surface->palette_reaction ); } dfb_surface_notify( surface, CSNF_PALETTE_CHANGE ); } fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_set_field( CoreSurface *surface, int field ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; surface->field = field; dfb_surface_notify( surface, CSNF_FIELD ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } DFBResult dfb_surface_set_alpha_ramp( CoreSurface *surface, u8 a0, u8 a1, u8 a2, u8 a3 ) { D_MAGIC_ASSERT( surface, CoreSurface ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (fusion_skirmish_prevail( &surface->lock )) return DFB_FUSION; surface->alpha_ramp[0] = a0; surface->alpha_ramp[1] = a1; surface->alpha_ramp[2] = a2; surface->alpha_ramp[3] = a3; dfb_surface_notify( surface, CSNF_ALPHA_RAMP ); fusion_skirmish_dismiss( &surface->lock ); return DFB_OK; } CoreSurfaceBuffer * dfb_surface_get_buffer( CoreSurface *surface, DFBSurfaceBufferRole role ) { D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_ASSERT( surface->num_buffers > 0 ); D_ASSERT( role == DSBR_FRONT || role == DSBR_BACK || role == DSBR_IDLE ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); return surface->buffers[surface->buffer_indices[role % surface->num_buffers]]; } CoreSurfaceBuffer * dfb_surface_get_buffer2( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ) { D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_ASSERT( surface->num_buffers > 0 ); D_ASSERT( role == DSBR_FRONT || role == DSBR_BACK || role == DSBR_IDLE ); D_ASSERT( eye == DSSE_LEFT || eye == DSSE_RIGHT ); D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, surface ); if (eye == DSSE_LEFT) return surface->left_buffers[surface->buffer_indices[role % surface->num_buffers]]; return surface->right_buffers[surface->buffer_indices[role % surface->num_buffers]]; } CoreSurfaceBuffer * dfb_surface_get_buffer3( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, u32 flip_count ) { CoreSurfaceBuffer *buffer; D_MAGIC_ASSERT( surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &surface->lock ); D_ASSERT( surface->num_buffers > 0 ); D_ASSERT( role == DSBR_FRONT || role == DSBR_BACK || role == DSBR_IDLE ); D_ASSERT( eye == DSSE_LEFT || eye == DSSE_RIGHT ); D_DEBUG_AT( Core_Surface, "%s( %p, role %u, eye %u, flip_count %u )\n", __FUNCTION__, surface, role, eye, flip_count ); if (eye == DSSE_LEFT) { buffer = fusion_hash_lookup( surface->frames, (void*)(long) ((flip_count + role) * 2) ); return buffer ?: surface->left_buffers[surface->buffer_indices[(flip_count + role) % surface->num_buffers]]; } buffer = fusion_hash_lookup( surface->frames, (void*)(long) ((flip_count + role) * 2 + 1) ); return buffer ?: surface->right_buffers[surface->buffer_indices[(flip_count + role) % surface->num_buffers]]; } ReactionResult _dfb_surface_palette_listener( const void *msg_data, void *ctx ) { const CorePaletteNotification *notification = msg_data; CoreSurface *surface = ctx; if (notification->flags & CPNF_DESTROY) return RS_REMOVE; if (notification->flags & CPNF_ENTRIES) { if (fusion_skirmish_prevail( &surface->lock )) return RS_OK; dfb_surface_notify( surface, CSNF_PALETTE_UPDATE ); fusion_skirmish_dismiss( &surface->lock ); } return RS_OK; } ================================================ FILE: src/core/surface.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_H__ #define __CORE__SURFACE_H__ #include #include #include #include /**********************************************************************************************************************/ typedef enum { CSSF_NONE = 0x00000000, /* None of these. */ CSSF_DESTROYED = 0x00000001, /* Surface is being or has been destroyed. */ CSSF_ALL = 0x00000001 /* All of these. */ } CoreSurfaceStateFlags; typedef enum { CSCONF_NONE = 0x00000000, /* none of these */ CSCONF_SIZE = 0x00000001, /* set size */ CSCONF_FORMAT = 0x00000002, /* set format */ CSCONF_CAPS = 0x00000004, /* set capabilities */ CSCONF_COLORSPACE = 0x00000008, /* set color space */ CSCONF_PREALLOCATED = 0x00000010, /* data has been preallocated */ CSCONF_ALL = 0x0000001F /* all of these */ } CoreSurfaceConfigFlags; struct __DFB_CoreSurfaceConfig { CoreSurfaceConfigFlags flags; DFBDimension size; DFBSurfacePixelFormat format; DFBSurfaceColorSpace colorspace; DFBSurfaceCapabilities caps; struct { void *addr; unsigned long phys; unsigned long offset; unsigned int pitch; void *handle; } preallocated[MAX_SURFACE_BUFFERS]; CoreSurfacePoolID preallocated_pool_id; DFBDimension min_size; DFBSurfaceHintFlags hints; }; typedef enum { CSTF_NONE = 0x00000000, /* none of these */ CSTF_LAYER = 0x00000001, /* surface for layer */ CSTF_WINDOW = 0x00000002, /* surface for window */ CSTF_CURSOR = 0x00000004, /* surface for cursor */ CSTF_FONT = 0x00000008, /* surface for font */ CSTF_SHARED = 0x00000010, /* accessable by other processes */ CSTF_INTERNAL = 0x00000100, /* system memory */ CSTF_EXTERNAL = 0x00000200, /* video memory */ CSTF_PREALLOCATED = 0x00000400, /* preallocated memory */ CSTF_ALL = 0x0000071F /* all of these */ } CoreSurfaceTypeFlags; typedef enum { CSNF_NONE = 0x00000000, /* none of these */ CSNF_SIZEFORMAT = 0x00000001, /* width, height, format */ CSNF_DESTROY = 0x00000008, /* surface is about to be destroyed */ CSNF_FLIP = 0x00000010, /* surface buffer pointer swapped */ CSNF_FIELD = 0x00000020, /* active (displayed) field switched */ CSNF_PALETTE_CHANGE = 0x00000040, /* another palette has been set */ CSNF_PALETTE_UPDATE = 0x00000080, /* current palette has been altered */ CSNF_ALPHA_RAMP = 0x00000100, /* alpha ramp was modified */ CSNF_DISPLAY = 0x00000200, /* surface buffer displayed */ CSNF_FRAME = 0x00000400, /* flip count ack */ CSNF_BUFFER_ALLOCATION_DESTROY = 0x00000800, /* buffer allocation about to be destroyed */ CSNF_ALL = 0x00000FF9 /* all of these */ } CoreSurfaceNotificationFlags; struct __DFB_CoreSurface { FusionObject object; int magic; FusionSkirmish lock; CoreSurfaceStateFlags state; CoreSurfaceConfig config; CoreSurfaceTypeFlags type; unsigned long resource_id; /* layer id, window id, or user specified */ int rotation; CoreSurfaceNotificationFlags notifications; DirectSerial serial; int field; u8 alpha_ramp[4]; CoreSurfaceBuffer **buffers; CoreSurfaceBuffer *left_buffers[MAX_SURFACE_BUFFERS]; CoreSurfaceBuffer *right_buffers[MAX_SURFACE_BUFFERS]; int num_buffers; int buffer_indices[MAX_SURFACE_BUFFERS]; u32 flips; CorePalette *palette; GlobalReaction palette_reaction; FusionSHMPoolShared *shmpool; void *data; /* shared system driver-specific data */ FusionCall call; FusionVector clients; u32 flips_acked; DFBFrameTimeConfig frametime_config; long long last_frame_time; FusionHash *frames; DirectSerial config_serial; }; /**********************************************************************************************************************/ typedef enum { CSAF_NONE = 0x00000000, /* none of these */ CSAF_READ = 0x00000001, /* accessor may read */ CSAF_WRITE = 0x00000002, /* accessor may write */ CSAF_SHARED = 0x00000010, /* other processes can read/write at the same time (shared mapping) */ CSAF_ALL = 0x00000013 /* all of these */ } CoreSurfaceAccessFlags; typedef enum { CSCH_EVENT = 0x00000001, /* DFEC_SURFACE DFBSurfaceEvent */ CSCH_FRAME = 0x00000002, /* CSNF_FRAME CoreSurfaceNotification */ } CoreSurfaceChannel; typedef struct { CoreSurfaceNotificationFlags flags; CoreSurface *surface; /* The following field is used only by the CSNF_DISPLAY message. */ int index; /* The following fields are used only by the CSNF_BUFFER_ALLOCATION_DESTROY message. */ CoreSurfaceBuffer *buffer_no_access; /* Pointer to associated CoreSurfaceBuffer being destroyed. */ void *surface_data; /* CoreSurface's shared driver specific data. */ int surface_object_id; /* CoreSurface's Fusion ID. */ unsigned int flip_count; } CoreSurfaceNotification; /**********************************************************************************************************************/ /* * Creates a pool of surface objects. */ FusionObjectPool *dfb_surface_pool_create ( const FusionWorld *world ); /* * Generates dfb_surface_ref(), dfb_surface_attach() etc. */ FUSION_OBJECT_METHODS( CoreSurface, dfb_surface ) typedef enum { DFB_LAYER_REGION_SURFACE_LISTENER = 0x00000000, DFB_WINDOWSTACK_BACKGROUND_IMAGE_LISTENER = 0x00000001 } DFB_SURFACE_GLOBALS; /**********************************************************************************************************************/ DFBResult dfb_surface_create ( CoreDFB *core, const CoreSurfaceConfig *config, CoreSurfaceTypeFlags type, unsigned long resource_id, CorePalette *palette, CoreSurface **ret_surface ); DFBResult dfb_surface_create_simple ( CoreDFB *core, int width, int height, DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, DFBSurfaceCapabilities caps, CoreSurfaceTypeFlags type, unsigned long resource_id, CorePalette *palette, CoreSurface **ret_surface ); DFBResult dfb_surface_init_palette ( CoreDFB *core, CoreSurface *surface ); DFBResult dfb_surface_notify ( CoreSurface *surface, CoreSurfaceNotificationFlags flags ); DFBResult dfb_surface_notify_display ( CoreSurface *surface, CoreSurfaceBuffer *buffer ); DFBResult dfb_surface_notify_display2 ( CoreSurface *surface, int index ); DFBResult dfb_surface_notify_frame ( CoreSurface *surface, unsigned int flip_count ); DFBResult dfb_surface_pool_notify ( CoreSurface *surface, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, CoreSurfaceNotificationFlags flags ); DFBResult dfb_surface_flip ( CoreSurface *surface, bool swap ); DFBResult dfb_surface_flip_buffers ( CoreSurface *surface, bool swap ); DFBResult dfb_surface_dispatch_event ( CoreSurface *surface, DFBSurfaceEventType type ); DFBResult dfb_surface_dispatch_update ( CoreSurface *surface, const DFBRegion *update, const DFBRegion *update_right, long long timestamp, DFBSurfaceFlipFlags flags ); DFBResult dfb_surface_check_acks ( CoreSurface *surface ); DFBResult dfb_surface_reconfig ( CoreSurface *surface, const CoreSurfaceConfig *config ); DFBResult dfb_surface_reformat ( CoreSurface *surface, int width, int height, DFBSurfacePixelFormat format ); DFBResult dfb_surface_destroy_buffers ( CoreSurface *surface ); DFBResult dfb_surface_deallocate_buffers( CoreSurface *surface ); DFBResult dfb_surface_destroy ( CoreSurface *surface ); DFBResult dfb_surface_lock_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *ret_lock ); DFBResult dfb_surface_lock_buffer2 ( CoreSurface *surface, DFBSurfaceBufferRole role, u32 flip_count, DFBSurfaceStereoEye eye, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *ret_lock ); DFBResult dfb_surface_unlock_buffer ( CoreSurface *surface, CoreSurfaceBufferLock *lock ); DFBResult dfb_surface_read_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role, void *destination, int pitch, const DFBRectangle *rect ); DFBResult dfb_surface_write_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role, const void *source, int pitch, const DFBRectangle *rect ); DFBResult dfb_surface_clear_buffers ( CoreSurface *surface ); DFBResult dfb_surface_dump_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role, const char *path, const char *prefix ); DFBResult dfb_surface_dump_buffer2 ( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *path, const char *prefix ); DFBResult dfb_surface_dump_raw_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role, const char *path, const char *prefix ); DFBResult dfb_surface_set_palette ( CoreSurface *surface, CorePalette *palette ); DFBResult dfb_surface_set_field ( CoreSurface *surface, int field ); DFBResult dfb_surface_set_alpha_ramp ( CoreSurface *surface, u8 a0, u8 a1, u8 a2, u8 a3 ); CoreSurfaceBuffer *dfb_surface_get_buffer ( CoreSurface *surface, DFBSurfaceBufferRole role ); CoreSurfaceBuffer *dfb_surface_get_buffer2 ( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye ); CoreSurfaceBuffer *dfb_surface_get_buffer3 ( CoreSurface *surface, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, u32 flip_count ); /* * Global reaction, listen to the palette's surface. */ ReactionResult _dfb_surface_palette_listener ( const void *msg_data, void *ctx ); /**********************************************************************************************************************/ static __inline__ DirectResult dfb_surface_lock( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); return fusion_skirmish_prevail( &surface->lock ); } static __inline__ DirectResult dfb_surface_trylock( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); return fusion_skirmish_swoop( &surface->lock ); } static __inline__ DirectResult dfb_surface_unlock( CoreSurface *surface ) { D_MAGIC_ASSERT( surface, CoreSurface ); return fusion_skirmish_dismiss( &surface->lock ); } static __inline__ void dfb_surface_get_data_offsets( const CoreSurfaceConfig *config, const void *data, int pitch, int x, int y, unsigned int num, u8 **pointers, int *pitches ) { D_ASSERT( config != NULL ); D_ASSERT( data != NULL ); D_ASSERT( pitch > 0 ); D_ASSERT( x >= 0 ); D_ASSERT( x < config->size.w ); D_ASSERT( y >= 0 ); D_ASSERT( y < config->size.h ); D_ASSERT( !num || (num && pointers && pitches) ); if (!num) return; switch (config->format) { case DSPF_NV12: case DSPF_NV21: case DSPF_NV16: case DSPF_NV61: case DSPF_NV24: case DSPF_NV42: if (num < 2) return; break; case DSPF_I420: case DSPF_YV12: case DSPF_Y42B: case DSPF_YV16: case DSPF_Y444: case DSPF_YV24: if (num < 3) return; break; default: if (num < 1) return; break; } if (config->caps & DSCAPS_SEPARATED) { if (y & 1) y += config->size.h; y >>= 1; } switch (config->format) { case DSPF_NV12: case DSPF_NV21: pitches[1] = pitch; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y / 2 + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_NV16: case DSPF_NV61: pitches[1] = pitch; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_NV24: case DSPF_NV42: pitches[1] = pitch; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x ); break; case DSPF_I420: pitches[1] = pitches[2] = pitch / 2; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y / 2 + DFB_BYTES_PER_LINE( config->format, x / 2 ); pointers[2] = (u8*) data + pitch * config->size.h + pitches[1] * config->size.h / 2 + pitches[2] * y / 2 + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_YV12: pitches[1] = pitches[2] = pitch / 2; pointers[2] = (u8*) data + pitch * config->size.h + pitches[2] * y / 2 + DFB_BYTES_PER_LINE( config->format, x / 2 ); pointers[1] = (u8*) data + pitch * config->size.h + pitches[2] * config->size.h / 2 + pitches[1] * y / 2 + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_Y42B: pitches[1] = pitches[2] = pitch / 2; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x / 2 ); pointers[2] = (u8*) data + pitch * config->size.h + pitches[1] * config->size.h + pitches[2] * y + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_YV16: pitches[1] = pitches[2] = pitch / 2; pointers[2] = (u8*) data + pitch * config->size.h + pitches[2] * y + DFB_BYTES_PER_LINE( config->format, x / 2 ); pointers[1] = (u8*) data + pitch * config->size.h + pitches[2] * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x / 2 ); break; case DSPF_Y444: pitches[1] = pitches[2] = pitch; pointers[1] = (u8*) data + pitch * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x ); pointers[2] = (u8*) data + pitch * config->size.h + pitches[1] * config->size.h + pitches[2] * y + DFB_BYTES_PER_LINE( config->format, x ); break; case DSPF_YV24: pitches[1] = pitches[2] = pitch; pointers[2] = (u8*) data + pitch * config->size.h + pitches[2] * y + DFB_BYTES_PER_LINE( config->format, x ); pointers[1] = (u8*) data + pitch * config->size.h + pitches[2] * config->size.h + pitches[1] * y + DFB_BYTES_PER_LINE( config->format, x ); break; default: break; } pointers[0] = (u8*) data + pitch * y + DFB_BYTES_PER_LINE( config->format, x ); pitches[0] = pitch; } static __inline__ void dfb_surface_calc_buffer_size( CoreSurface *surface, int byte_align, int pixel_align, int *ret_pitch, int *ret_size ) { DFBSurfacePixelFormat format; int width; int pitch; D_MAGIC_ASSERT( surface, CoreSurface ); format = surface->config.format; width = direct_util_align( surface->config.size.w, pixel_align ); pitch = direct_util_align( DFB_BYTES_PER_LINE( format, width ), byte_align ); if (ret_pitch) *ret_pitch = pitch; if (ret_size) *ret_size = pitch * DFB_PLANE_MULTIPLY( format, surface->config.size.h ); } #endif ================================================ FILE: src/core/surface_allocation.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_SurfAllocation, "Core/SurfAllocation", "DirectFB Core Surface Allocation" ); /**********************************************************************************************************************/ static void surface_allocation_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreSurfaceAllocation *allocation = (CoreSurfaceAllocation*) object; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_SurfAllocation, "Destroying allocation %p (%d%s)\n", allocation, allocation->size, zombie ? " ZOMBIE" : "" ); CoreSurfaceAllocation_Deinit_Dispatch( &allocation->call ); if (!D_FLAGS_IS_SET( allocation->flags, CSALF_INITIALIZING )) { if (allocation->surface) dfb_surface_lock( allocation->surface ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); dfb_surface_pool_deallocate( allocation->pool, allocation ); if (allocation->surface) dfb_surface_unlock( allocation->surface ); } if (allocation->data) SHFREE( allocation->pool->shmpool, allocation->data ); direct_serial_deinit( &allocation->serial ); D_MAGIC_CLEAR( allocation ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_surface_allocation_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Surface Allocation Pool", sizeof(CoreSurfaceAllocation), sizeof(CoreSurfaceAllocationNotification), surface_allocation_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_surface_allocation_create( CoreDFB *core, CoreSurfaceBuffer *buffer, CoreSurfacePool *pool, CoreSurfaceAllocation **ret_allocation ) { CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( pool != NULL ); D_ASSERT( ret_allocation != NULL ); D_DEBUG_AT( Core_SurfAllocation, "%s( %dx%d %s )\n", __FUNCTION__, buffer->config.size.w, buffer->config.size.h, dfb_pixelformat_name( buffer->config.format ) ); /* Create the allocation object. */ allocation = dfb_core_create_surface_allocation( core ); if (!allocation) return DFB_FUSION; allocation->buffer = buffer; allocation->surface = buffer->surface; allocation->pool = pool; allocation->flags = CSALF_INITIALIZING; allocation->access = pool->desc.access; allocation->config = buffer->config; allocation->type = buffer->type; allocation->resource_id = buffer->resource_id; allocation->index = buffer->index; allocation->buffer_id = buffer->object.id; if (pool->alloc_data_size) { allocation->data = SHCALLOC( pool->shmpool, 1, pool->alloc_data_size ); if (!allocation->data) { fusion_object_destroy( &allocation->object ); return D_OOSHM(); } } direct_serial_init( &allocation->serial ); fusion_ref_add_permissions( &allocation->object.ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL ); CoreSurfaceAllocation_Init_Dispatch( core, allocation, &allocation->call ); D_MAGIC_SET( allocation, CoreSurfaceAllocation ); /* Activate the object. */ fusion_object_activate( &allocation->object ); /* Return the new allocation. */ *ret_allocation = allocation; D_DEBUG_AT( Core_SurfAllocation, " -> %p\n", allocation ); return DFB_OK; } DFBResult dfb_surface_allocation_decouple( CoreSurfaceAllocation *allocation ) { int i; int locks; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *alloc; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( allocation->surface, CoreSurface ); D_ASSERT( allocation->surface == allocation->buffer->surface ); D_DEBUG_AT( Core_SurfAllocation, "%s( %p )\n", __FUNCTION__, allocation ); buffer = allocation->buffer; /* Indicate that this surface buffer pool allocation is about to be destroyed. */ dfb_surface_pool_notify( allocation->surface, buffer, allocation, CSNF_BUFFER_ALLOCATION_DESTROY ); allocation->buffer = NULL; allocation->surface = NULL; fusion_vector_remove( &buffer->allocs, fusion_vector_index_of( &buffer->allocs, allocation ) ); locks = dfb_surface_allocation_locks( allocation ); if (!locks) { if (allocation->accessed[CSAID_GPU] & (CSAF_READ | CSAF_WRITE)) /* Wait for the operation to finish. */ dfb_gfxcard_wait_serial( &allocation->gfx_serial ); dfb_surface_pool_deallocate( allocation->pool, allocation ); } /* Reset 'read' allocation pointer of buffer. */ if (buffer->read == allocation) buffer->read = NULL; /* Update 'written' allocation pointer of buffer. */ if (buffer->written == allocation) { /* Reset pointer first. */ buffer->written = NULL; /* Iterate through remaining allocations. */ fusion_vector_foreach (alloc, i, buffer->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( alloc ); /* Check if allocation is up to date and set it as 'written' allocation. */ if (direct_serial_check( &alloc->serial, &buffer->serial )) { buffer->written = alloc; break; } } } dfb_surface_allocation_unlink( &allocation ); return DFB_OK; } static void transfer_buffer( const CoreSurfaceConfig *config, const char *src, char *dst, int srcpitch, int dstpitch ) { int i; D_DEBUG_AT( Core_SurfAllocation, "%s( %p, %p [%d] -> %p [%d] ) <- %d\n", __FUNCTION__, config, src, srcpitch, dst, dstpitch, config->size.h ); D_ASSERT( src != NULL ); D_ASSERT( dst != NULL ); D_ASSERT( srcpitch > 0 ); D_ASSERT( dstpitch > 0 ); D_ASSERT( srcpitch >= DFB_BYTES_PER_LINE( config->format, config->size.w ) ); D_ASSERT( dstpitch >= DFB_BYTES_PER_LINE( config->format, config->size.w ) ); for (i = 0; i < config->size.h; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w ) ); src += srcpitch; dst += dstpitch; } switch (config->format) { case DSPF_I420: case DSPF_YV12: for (i = 0; i < config->size.h; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w / 2 ) ); src += srcpitch / 2; dst += dstpitch / 2; } break; case DSPF_NV12: case DSPF_NV21: for (i = 0; i < config->size.h / 2; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w ) ); src += srcpitch; dst += dstpitch; } break; case DSPF_Y42B: case DSPF_YV16: for (i = 0; i < config->size.h * 2; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w / 2 ) ); src += srcpitch / 2; dst += dstpitch / 2; } break; case DSPF_NV16: case DSPF_NV61: for (i = 0; i < config->size.h; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w ) ); src += srcpitch; dst += dstpitch; } break; case DSPF_Y444: case DSPF_YV24: for (i = 0; i < config->size.h * 2; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w ) ); src += srcpitch; dst += dstpitch; } break; case DSPF_NV24: case DSPF_NV42: for (i = 0; i < config->size.h; i++) { direct_memcpy( dst, src, DFB_BYTES_PER_LINE( config->format, config->size.w * 2 ) ); src += srcpitch; dst += dstpitch; } break; default: break; } } static DFBResult allocation_update_copy( CoreSurfaceAllocation *allocation, CoreSurfaceAllocation *source ) { DFBResult ret; CoreSurfaceBufferLock src; CoreSurfaceBufferLock dst; D_DEBUG_AT( Core_SurfAllocation, "%s( %p )\n", __FUNCTION__, allocation ); D_ASSERT( allocation != source ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); /* Lock the source allocation. */ dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); dfb_surface_pool_prelock( source->pool, source, CSAID_CPU, CSAF_READ ); ret = dfb_surface_pool_lock( source->pool, source, &src ); if (ret) { D_DERROR( ret, "Core/SurfAllocation: Could not lock source for transfer!\n" ); dfb_surface_buffer_lock_deinit( &src ); return ret; } /* Lock the destination allocation. */ dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); dfb_surface_pool_prelock( allocation->pool, allocation, CSAID_CPU, CSAF_WRITE ); allocation->accessed[CSAID_CPU] |= CSAF_WRITE; source->accessed[CSAID_CPU] |= CSAF_READ; ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); if (ret) { D_DERROR( ret, "Core/SurfAllocation: Could not lock destination for transfer!\n" ); dfb_surface_pool_unlock( source->pool, source, &src ); dfb_surface_buffer_lock_deinit( &dst ); dfb_surface_buffer_lock_deinit( &src ); return ret; } transfer_buffer( &allocation->config, (char*) src.addr, (char*) dst.addr, src.pitch, dst.pitch ); dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); dfb_surface_pool_unlock( source->pool, source, &src ); dfb_surface_buffer_lock_deinit( &dst ); dfb_surface_buffer_lock_deinit( &src ); return DFB_OK; } static DFBResult allocation_update_write( CoreSurfaceAllocation *allocation, CoreSurfaceAllocation *source ) { DFBResult ret; CoreSurfaceBufferLock src; D_DEBUG_AT( Core_SurfAllocation, "%s( %p )\n", __FUNCTION__, allocation ); D_ASSERT( allocation != source ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); /* Lock the source allocation. */ dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); dfb_surface_pool_prelock( source->pool, source, CSAID_CPU, CSAF_READ ); source->accessed[CSAID_CPU] |= source->accessed[CSAID_CPU]; ret = dfb_surface_pool_lock( source->pool, source, &src ); if (ret) { D_DERROR( ret, "Core/SurfAllocation: Could not lock source for transfer!\n" ); dfb_surface_buffer_lock_deinit( &src ); return ret; } /* Write to the destination allocation. */ ret = dfb_surface_pool_write( allocation->pool, allocation, (char*) src.addr, src.pitch, NULL ); if (ret) D_DERROR( ret, "Core/SurfAllocation: Could not write from destination allocation!\n" ); dfb_surface_pool_unlock( source->pool, source, &src ); dfb_surface_buffer_lock_deinit( &src ); return ret; } static DFBResult allocation_update_read( CoreSurfaceAllocation *allocation, CoreSurfaceAllocation *source ) { DFBResult ret; CoreSurfaceBufferLock dst; D_DEBUG_AT( Core_SurfAllocation, "%s( %p )\n", __FUNCTION__, allocation ); D_ASSERT( allocation != source ); D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); /* Lock the destination allocation. */ dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); dfb_surface_pool_prelock( allocation->pool, allocation, CSAID_CPU, CSAF_WRITE ); allocation->accessed[CSAID_CPU] |= CSAF_READ; ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); if (ret) { D_DERROR( ret, "Core/SurfAllocation: Could not lock destination for transfer!\n" ); dfb_surface_buffer_lock_deinit( &dst ); return ret; } /* Read from the source allocation. */ ret = dfb_surface_pool_read( source->pool, source, dst.addr, dst.pitch, NULL ); if (ret) D_DERROR( ret, "Core/SurfAllocation: Could not read from source allocation!\n" ); dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); dfb_surface_buffer_lock_deinit( &dst ); return ret; } DFBResult dfb_surface_allocation_update( CoreSurfaceAllocation *allocation, CoreSurfaceAccessFlags access ) { DFBResult ret; int i; CoreSurfaceAllocation *alloc; CoreSurfaceBuffer *buffer; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->buffer, CoreSurfaceBuffer ); D_FLAGS_ASSERT( access, CSAF_ALL ); D_DEBUG_AT( Core_SurfAllocation, "%s( %p )\n", __FUNCTION__, allocation ); buffer = allocation->buffer; D_MAGIC_ASSERT( buffer->surface, CoreSurface ); FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); if (direct_serial_update( &allocation->serial, &buffer->serial ) && buffer->written) { CoreSurfaceAllocation *source = buffer->written; D_ASSUME( allocation != source ); D_DEBUG_AT( Core_SurfAllocation, " -> alloc/written buffer %p/%p\n", allocation->buffer, source->buffer ); D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); D_ASSERT( source->buffer == allocation->buffer ); D_DEBUG_AT( Core_SurfAllocation, " -> updating allocation %p from %p...\n", allocation, source ); ret = dfb_surface_pool_bridges_transfer( buffer, source, allocation, NULL, 0 ); if (ret) { if ((source->access[CSAID_CPU] & CSAF_READ) && (allocation->access[CSAID_CPU] & CSAF_WRITE)) ret = allocation_update_copy( allocation, source ); else if (source->access[CSAID_CPU] & CSAF_READ) ret = allocation_update_write( allocation, source ); else if (allocation->access[CSAID_CPU] & CSAF_WRITE) ret = allocation_update_read( allocation, source ); else { D_WARN( "allocation update: '%s' -> '%s'", source->pool->desc.name, allocation->pool->desc.name ); D_UNIMPLEMENTED(); ret = DFB_UNSUPPORTED; } } if (ret) { D_DERROR( ret, "Core/SurfAllocation: Updating allocation failed!\n" ); return ret; } } if (access & CSAF_WRITE) { D_DEBUG_AT( Core_SurfAllocation, " -> increasing serial...\n" ); direct_serial_increase( &buffer->serial ); direct_serial_copy( &allocation->serial, &buffer->serial ); buffer->written = allocation; buffer->read = NULL; /* Zap volatile allocations (freed when no longer up to date). */ fusion_vector_foreach (alloc, i, buffer->allocs) { D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); if (alloc != allocation && (alloc->flags & CSALF_VOLATILE)) { dfb_surface_allocation_decouple( alloc ); i--; } } } else buffer->read = allocation; /* Zap all other allocations. */ if (dfb_config->thrifty_surface_buffers) { buffer->written = buffer->read = allocation; fusion_vector_foreach (alloc, i, buffer->allocs) { D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); /* Don't zap preallocated which would not really free up memory, but just loose the handle. */ if (alloc != allocation && !(alloc->flags & (CSALF_PREALLOCATED | CSALF_MUCKOUT))) { dfb_surface_allocation_decouple( alloc ); i--; } } } return DFB_OK; } DFBResult dfb_surface_allocation_dump( CoreSurfaceAllocation *allocation, const char *directory, const char *prefix, bool raw ) { DFBResult ret = DFB_OK; CoreSurfacePool *pool; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->pool, CoreSurfacePool ); D_ASSERT( directory != NULL ); D_DEBUG_AT( Core_SurfAllocation, "%s( %p, '%s', '%s' )\n", __FUNCTION__, allocation, directory, prefix ); pool = allocation->pool; if (D_FLAGS_IS_SET( pool->desc.caps, CSPCAPS_READ )) { int pitch; int size; void *buf; dfb_surface_calc_buffer_size( allocation->surface, 4, 1, &pitch, &size ); buf = D_MALLOC( size ); if (!buf) return D_OOM(); ret = dfb_surface_pool_read( pool, allocation, buf, pitch, NULL ); if (ret == DFB_OK) ret = dfb_surface_buffer_dump_type_locked2( allocation->buffer, directory, prefix, raw, buf, pitch ); D_FREE( buf ); } else { CoreSurfaceBufferLock lock; dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ ); /* Lock the surface buffer, get the data pointer and pitch. */ ret = dfb_surface_pool_lock( pool, allocation, &lock ); if (ret) { dfb_surface_buffer_lock_deinit( &lock ); return ret; } ret = dfb_surface_buffer_dump_type_locked( allocation->buffer, directory, prefix, raw, &lock ); /* Unlock the surface buffer. */ dfb_surface_pool_unlock( allocation->pool, allocation, &lock ); dfb_surface_buffer_lock_deinit( &lock ); } return ret; } ================================================ FILE: src/core/surface_allocation.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_ALLOCATION_H__ #define __CORE__SURFACE_ALLOCATION_H__ #include /**********************************************************************************************************************/ typedef enum { CSALF_NONE = 0x00000000, /* None of these. */ CSALF_INITIALIZING = 0x00000001, /* Allocation is being initialized. */ CSALF_VOLATILE = 0x00000002, /* Allocation should be freed when no longer up to date. */ CSALF_PREALLOCATED = 0x00000004, /* Preallocated memory, don't zap when "thrifty-surface-buffers" is active. */ CSALF_MUCKOUT = 0x00001000, /* Indicates surface pool being in the progress of mucking out this and possibly other allocations to have enough space for a new allocation to be made. */ CSALF_DEALLOCATED = 0x00002000, /* Decoupled and deallocated surface buffer allocation. */ CSALF_ALL = 0x00003007 /* All of these. */ } CoreSurfaceAllocationFlags; struct __DFB_CoreSurfaceAllocation { FusionObject object; int magic; DirectSerial serial; /* Equals serial of buffer if content is up to date. */ CoreSurfaceBuffer *buffer; /* Surface buffer owning this allocation. */ CoreSurface *surface; /* Surface owning the buffer of this allocation. */ CoreSurfacePool *pool; /* Surface pool providing the allocation. */ void *data; /* Pool's private data for this allocation. */ int size; /* Amount of data used by this allocation. */ unsigned long offset; /* Offset within address range of pool if contiguous. */ CoreSurfaceAllocationFlags flags; /* Configuration and state flags. */ const CoreSurfaceAccessFlags *access; /* Possible access flags (pointer to pool description). */ CoreSurfaceAccessFlags accessed[CSAID_NUM]; /* Access since last synchronization. */ CoreSurfaceConfig config; /* Configuration of its surface at the time of the allocation creation. */ CoreSurfaceTypeFlags type; /* Classification of the surface. */ unsigned long resource_id; /* layer id, window id, or user specified */ int index; /* index of surface buffer */ CoreGraphicsSerial gfx_serial; /* graphics serial */ FusionCall call; /* dispatch */ FusionObjectID buffer_id; /* buffer id */ }; #if D_DEBUG_ENABLED #define CORE_SURFACE_ALLOCATION_ASSERT(alloc) \ do { \ D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); \ D_ASSERT( (alloc)->size >= 0 ); \ D_FLAGS_ASSERT( (alloc)->flags, CSALF_ALL ); \ D_FLAGS_ASSERT( (alloc)->access[CSAID_CPU], CSAF_ALL ); \ D_FLAGS_ASSERT( (alloc)->access[CSAID_GPU], CSAF_ALL ); \ D_FLAGS_ASSERT( (alloc)->accessed[CSAID_CPU], CSAF_ALL ); \ D_FLAGS_ASSERT( (alloc)->accessed[CSAID_GPU], CSAF_ALL ); \ D_ASSUME( (alloc)->size > 0 ); \ } while (0) #else #define CORE_SURFACE_ALLOCATION_ASSERT(alloc) \ do { \ } while (0) #endif /**********************************************************************************************************************/ typedef enum { CSANF_NONE = 0x00000000, CSANF_DEALLOCATED = 0x00000001, CSANF_ALL = 0x00000001 } CoreSurfaceAllocationNotificationFlags; typedef struct { CoreSurfaceAllocationNotificationFlags flags; } CoreSurfaceAllocationNotification; /**********************************************************************************************************************/ /* * Creates a pool of surface allocation objects. */ FusionObjectPool *dfb_surface_allocation_pool_create( const FusionWorld *world ); /* * Generates dfb_surface_allocation_ref(), dfb_surface_allocation_attach() etc. */ FUSION_OBJECT_METHODS( CoreSurfaceAllocation, dfb_surface_allocation ) /**********************************************************************************************************************/ DFBResult dfb_surface_allocation_create ( CoreDFB *core, CoreSurfaceBuffer *buffer, CoreSurfacePool *pool, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_surface_allocation_decouple ( CoreSurfaceAllocation *allocation ); DFBResult dfb_surface_allocation_update ( CoreSurfaceAllocation *allocation, CoreSurfaceAccessFlags access ); DFBResult dfb_surface_allocation_dump ( CoreSurfaceAllocation *allocation, const char *directory, const char *prefix, bool raw ); /**********************************************************************************************************************/ static __inline__ int dfb_surface_allocation_locks( CoreSurfaceAllocation *allocation ) { int refs; fusion_ref_stat( &allocation->object.ref, &refs ); D_ASSERT( refs > 0 ); return refs - 1; } #endif ================================================ FILE: src/core/surface_buffer.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_SurfBuffer, "Core/SurfBuffer", "DirectFB Core Surface Buffer" ); /**********************************************************************************************************************/ static void surface_buffer_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreSurfaceAllocation *allocation; unsigned int i; CoreSurfaceBuffer *buffer = (CoreSurfaceBuffer*) object; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( Core_SurfBuffer, "Destroying buffer %p (%dx%d%s)\n", buffer, buffer->config.size.w, buffer->config.size.h, zombie ? " ZOMBIE" : "" ); D_DEBUG_AT( Core_SurfBuffer, " -> allocs %d\n", buffer->allocs.count ); if (buffer->surface) dfb_surface_lock( buffer->surface ); fusion_vector_foreach_reverse (allocation, i, buffer->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( allocation ); dfb_surface_allocation_decouple( allocation ); } if (buffer->surface) dfb_surface_unlock( buffer->surface ); fusion_vector_destroy( &buffer->allocs ); direct_serial_deinit( &buffer->serial ); D_MAGIC_CLEAR( buffer ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_surface_buffer_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Surface Buffer Pool", sizeof(CoreSurfaceBuffer), sizeof(CoreSurfaceBufferNotification), surface_buffer_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_surface_buffer_create( CoreDFB *core, CoreSurface *surface, CoreSurfaceBufferFlags flags, int index, CoreSurfaceBuffer **ret_buffer ) { DFBResult ret; CoreSurfaceBuffer *buffer; D_MAGIC_ASSERT( surface, CoreSurface ); D_FLAGS_ASSERT( flags, CSBF_ALL ); D_ASSERT( ret_buffer != NULL ); D_DEBUG_AT( Core_SurfBuffer, "%s( %s )\n", __FUNCTION__, dfb_pixelformat_name( surface->config.format ) ); /* Create the buffer object. */ buffer = dfb_core_create_surface_buffer( core ); if (!buffer) return DFB_FUSION; direct_serial_init( &buffer->serial ); direct_serial_increase( &buffer->serial ); buffer->surface = surface; buffer->flags = flags; buffer->config = surface->config; buffer->type = surface->type; buffer->resource_id = surface->resource_id; buffer->index = index; if (buffer->config.caps & DSCAPS_VIDEOONLY) buffer->policy = CSP_VIDEOONLY; else if (buffer->config.caps & DSCAPS_SYSTEMONLY) buffer->policy = CSP_SYSTEMONLY; else buffer->policy = CSP_VIDEOLOW; fusion_vector_init( &buffer->allocs, 2, buffer->surface->shmpool ); fusion_object_set_lock( &buffer->object, &buffer->surface->lock ); fusion_ref_add_permissions( &buffer->object.ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL ); D_MAGIC_SET( buffer, CoreSurfaceBuffer ); if (buffer->type & CSTF_PREALLOCATED) { CoreSurfacePool *pool; CoreSurfaceAllocation *allocation; ret = dfb_surface_pools_lookup( buffer->config.preallocated_pool_id, &pool ); if (ret) { fusion_object_destroy( &buffer->object ); return ret; } ret = dfb_surface_pool_allocate( pool, buffer, NULL, 0, &allocation ); if (ret) { fusion_object_destroy( &buffer->object ); return ret; } dfb_surface_allocation_update( allocation, CSAF_WRITE ); } /* Activate the object. */ fusion_object_activate( &buffer->object ); /* Return the new buffer. */ *ret_buffer = buffer; D_DEBUG_AT( Core_SurfBuffer, " -> %p\n", buffer ); return DFB_OK; } DFBResult dfb_surface_buffer_decouple( CoreSurfaceBuffer *buffer ) { D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p )\n", __FUNCTION__, buffer ); buffer->flags |= CSBF_DECOUPLE; if (!buffer->busy) { dfb_surface_buffer_deallocate( buffer ); buffer->surface = NULL; dfb_surface_buffer_unlink( &buffer ); } return DFB_OK; } DFBResult dfb_surface_buffer_deallocate( CoreSurfaceBuffer *buffer ) { CoreSurfaceAllocation *allocation; int i; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p ) <- %dx%d\n", __FUNCTION__, buffer, buffer->config.size.w, buffer->config.size.h ); fusion_vector_foreach_reverse (allocation, i, buffer->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( allocation ); dfb_surface_allocation_decouple( allocation ); } return DFB_OK; } CoreSurfaceAllocation * dfb_surface_buffer_find_allocation( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags flags, bool lock ) { int i; CoreSurfaceAllocation *allocation; CoreSurfaceAllocation *uptodate = NULL; CoreSurfaceAllocation *outdated = NULL; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p )\n", __FUNCTION__, buffer ); FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); /* For preallocated surfaces, when the client specified DSCAPS_STATIC_ALLOC, it is forced to always get the same preallocated buffer again on each lock. */ if (buffer->type & CSTF_PREALLOCATED && buffer->config.caps & DSCAPS_STATIC_ALLOC) { if (buffer->surface->object.identity == Core_GetIdentity()) { D_DEBUG_AT( Core_SurfBuffer, " -> DSCAPS_STATIC_ALLOC, returning preallocated buffer\n" ); D_ASSERT( buffer->allocs.count > 0 ); allocation = buffer->allocs.elements[0]; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_ASSERT( allocation->flags & CSALF_PREALLOCATED ); /* Return if allocation has required flags. */ if (D_FLAGS_ARE_SET( allocation->access[accessor], flags )) return allocation; } } /* Prefer allocations which are up to date. */ fusion_vector_foreach (allocation, i, buffer->allocs) { if (lock && allocation->flags & CSALF_PREALLOCATED) { if (!(allocation->access[accessor] & CSAF_SHARED)) { D_DEBUG_AT( Core_SurfBuffer, " -> non-shared preallocated buffer, surface identity %lu, core identity %lu\n", buffer->surface->object.identity, Core_GetIdentity() ); /* If this is a non-shared preallocated allocation and the lock is not for the creator, we need to skip it and possibly allocate/update in a different pool. */ if (buffer->surface->object.identity != Core_GetIdentity()) continue; } } else if (Core_GetIdentity() != FUSION_ID_MASTER && !(allocation->access[accessor] & CSAF_SHARED)) { D_DEBUG_AT( Core_SurfBuffer, " -> refusing allocation for slave from non-shared pool!\n" ); continue; } if (direct_serial_check( &allocation->serial, &buffer->serial )) { /* Return immediately if up to date allocation has required flags. */ if (D_FLAGS_ARE_SET( allocation->access[accessor], flags )) return allocation; /* Remember up to date allocation in case none has supported flags. */ uptodate = allocation; } else if (D_FLAGS_ARE_SET( allocation->access[accessor], flags )) { /* Remember outdated allocation which has supported flags. */ outdated = allocation; } } /* In case of a lock the flags are mandatory and the outdated allocation has to be used. */ if (lock) return outdated; /* Otherwise we can still prefer the up to date allocation. */ return uptodate ?: outdated; } CoreSurfaceAllocation * dfb_surface_buffer_find_allocation_key( CoreSurfaceBuffer *buffer, const char *key ) { int i; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p )\n", __FUNCTION__, buffer ); FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); fusion_vector_foreach (allocation, i, buffer->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( allocation ); if (dfb_surface_pool_check_key( allocation->pool, buffer, key, 0 ) == DFB_OK) return allocation; } return NULL; } DFBResult dfb_surface_buffer_lock( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *lock ) { DFBResult ret; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( accessor >= CSAID_CPU ); D_FLAGS_ASSERT( access, CSAF_ALL ); D_ASSERT( lock != NULL ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p )\n", __FUNCTION__, lock ); FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); D_ASSUME( accessor < CSAID_NUM ); if (accessor >= CSAID_ANY) { D_UNIMPLEMENTED(); return DFB_UNIMPLEMENTED; } if (accessor < 0 || accessor >= CSAID_NUM) return DFB_INVARG; if (direct_log_domain_check( &Core_SurfBuffer )) { D_DEBUG_AT( Core_SurfBuffer, "%s( %p, 0x%02x, %p ) <- %dx%d %s [%d]\n", __FUNCTION__, buffer, access, lock, buffer->config.size.w, buffer->config.size.h, dfb_pixelformat_name( buffer->config.format ), dfb_surface_buffer_index(buffer) ); switch (accessor) { case CSAID_CPU: D_DEBUG_AT( Core_SurfBuffer, " -> CPU %s%s\n", (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); break; case CSAID_GPU: D_DEBUG_AT( Core_SurfBuffer, " -> GPU %s%s\n", (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); break; case CSAID_LAYER0: case CSAID_LAYER1: case CSAID_LAYER2: case CSAID_LAYER3: case CSAID_LAYER4: case CSAID_LAYER5: case CSAID_LAYER6: case CSAID_LAYER7: case CSAID_LAYER8: case CSAID_LAYER9: case CSAID_LAYER10: case CSAID_LAYER11: case CSAID_LAYER12: case CSAID_LAYER13: case CSAID_LAYER14: case CSAID_LAYER15: D_DEBUG_AT( Core_SurfBuffer, " -> LAYER %u %s%s\n", accessor - CSAID_LAYER0, (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); break; default: D_DEBUG_AT( Core_SurfBuffer, " -> OTHER\n" ); break; } if (access & CSAF_SHARED) D_DEBUG_AT( Core_SurfBuffer, " -> SHARED\n" ); } D_DEBUG_AT( Core_SurfBuffer, " -> calling PreLockBuffer( %p )...\n", buffer ); /* Run all code that modifies shared memory in master process. */ ret = CoreSurface_PreLockBuffer( buffer->surface, buffer, accessor, access, &allocation ); if (ret) return ret; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_SurfBuffer, " -> PreLockBuffer() returned allocation %p ('%s')\n", allocation, allocation->pool->desc.name ); /* Lock the allocation. */ dfb_surface_buffer_lock_init( lock, accessor, access ); ret = dfb_surface_pool_lock( allocation->pool, allocation, lock ); if (ret) { D_DERROR( ret, "Core/SurfBuffer: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( lock ); dfb_surface_allocation_unref( allocation ); return ret; } return DFB_OK; } DFBResult dfb_surface_buffer_unlock( CoreSurfaceBufferLock *lock ) { DFBResult ret; CoreSurfacePool *pool; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p )\n", __FUNCTION__, lock ); allocation = lock->allocation; CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_MAGIC_ASSERT( allocation->pool, CoreSurfacePool ); pool = allocation->pool; ret = dfb_surface_pool_unlock( pool, lock->allocation, lock ); if (ret) { D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation in '%s' failed!\n", pool->desc.name ); return ret; } dfb_surface_buffer_lock_reset( lock ); dfb_surface_buffer_lock_deinit( lock ); dfb_surface_allocation_unref( allocation ); return DFB_OK; } DFBResult dfb_surface_buffer_dump_type_locked( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix, bool raw, CoreSurfaceBufferLock *lock ) { CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); CORE_SURFACE_ALLOCATION_ASSERT( lock->allocation ); return dfb_surface_buffer_dump_type_locked2( buffer, directory, prefix, raw, lock->addr, lock->pitch ); } DFBResult dfb_surface_buffer_dump_type_locked2( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix, bool raw, void *addr, int pitch ) { DFBResult ret; int num = -1; int i, n; int len = (directory ? strlen( directory ) : 0) + (prefix ? strlen( prefix ) : 0) + 40; char filename[len]; char head[30]; bool rgb = false; bool alpha = false; char rgb_ext[4]; size_t bytes; CorePalette *palette = NULL; DirectFile fd_p, fd_g; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( directory != NULL ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p, %p )\n", __FUNCTION__, buffer, directory, prefix ); /* Check pixel format. */ switch (buffer->config.format) { case DSPF_LUT8: case DSPF_ALUT8: palette = buffer->surface->palette; if (!palette) { D_BUG( "no palette" ); return DFB_BUG; } if (dfb_palette_ref( palette )) return DFB_FUSION; rgb = true; /* fall through */ case DSPF_A8: alpha = true; break; case DSPF_ARGB: case DSPF_ABGR: case DSPF_ARGB1555: case DSPF_RGBA5551: case DSPF_ARGB2554: case DSPF_ARGB4444: case DSPF_AiRGB: case DSPF_ARGB8565: case DSPF_AYUV: case DSPF_AVYU: alpha = true; /* fall through */ case DSPF_RGB332: case DSPF_RGB444: case DSPF_RGB555: case DSPF_BGR555: case DSPF_RGB16: case DSPF_RGB24: case DSPF_BGR24: case DSPF_RGB32: case DSPF_YUY2: case DSPF_UYVY: case DSPF_VYU: case DSPF_I420: case DSPF_YV12: case DSPF_NV12: case DSPF_NV21: case DSPF_Y42B: case DSPF_YV16: case DSPF_NV16: case DSPF_NV61: case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: rgb = true; break; default: D_ERROR( "Core/SurfBuffer: Surface dump for format '%s' is not implemented!\n", dfb_pixelformat_name( buffer->config.format ) ); return DFB_UNSUPPORTED; } /* Setup the file extension depending on whether we want the output in RAW format or not. */ snprintf( rgb_ext, D_ARRAY_SIZE(rgb_ext), (raw == true) ? "raw" : "ppm" ); if (prefix) { /* Find the lowest unused index. */ while (++num < 10000) { snprintf( filename, len, "%s/%s_%04d.%s", directory, prefix, num, rgb_ext ); ret = direct_access( filename, F_OK ); if (ret) { snprintf( filename, len, "%s/%s_%04d.pgm", directory, prefix, num ); ret = direct_access( filename, F_OK ); if (ret) break; } } if (num == 10000) { D_ERROR( "Core/SurfBuffer: Could not find an unused index for surface dump!\n" ); if (palette) dfb_palette_unref( palette ); return DFB_FAILURE; } } /* Create a file with the found index. */ if (rgb) { if (prefix) snprintf( filename, len, "%s/%s_%04d.%s", directory, prefix, num, rgb_ext ); else snprintf( filename, len, "%s.%s", directory, rgb_ext ); ret = direct_file_open( &fd_p, filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); if (ret) { D_DERROR( ret, "Core/SurfBuffer: Could not open '%s'!\n", filename ); if (palette) dfb_palette_unref( palette ); return ret; } } /* Create a graymap for the alpha channel using the found index. */ if (alpha && !raw) { if (prefix) snprintf( filename, len, "%s/%s_%04d.pgm", directory, prefix, num ); else snprintf( filename, len, "%s.pgm", directory ); ret = direct_file_open( &fd_g, filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); if (ret) { D_DERROR( ret, "Core/SurfBuffer: Could not open '%s'!\n", filename ); if (palette) dfb_palette_unref( palette ); if (rgb) { direct_file_close( &fd_p ); snprintf( filename, len, "%s/%s_%04d.%s", directory, prefix, num, rgb_ext ); direct_unlink( filename ); } return ret; } } /* Only write the header if we are not dumping a raw image. */ if (!raw) { if (rgb) { /* Write the pixmap header. */ snprintf( head, sizeof(head), "P6\n%d %d\n255\n", buffer->config.size.w, buffer->config.size.h ); direct_file_write( &fd_p, head, strlen( head ), &bytes ); } /* Write the graymap header. */ if (alpha) { snprintf( head, sizeof(head), "P5\n%d %d\n255\n", buffer->config.size.w, buffer->config.size.h ); direct_file_write( &fd_g, head, strlen( head ), &bytes ); } } /* Write the pixmap (and graymap) data. */ for (i = 0; i < buffer->config.size.h; i++) { int n3; /* Prepare one row. */ u8 *srces[3] = { NULL, NULL, NULL }; int pitches[3] = { 0, 0, 0 }; u8 *src8; dfb_surface_get_data_offsets( &buffer->config, addr, pitch, 0, i, 3, srces, pitches ); src8 = srces[0]; /* Write color buffer to pixmap file. */ if (rgb) { if (raw) { u8 buf_p[buffer->config.size.w*4]; if (buffer->config.format == DSPF_LUT8) { for (n = 0, n3 = 0; n < buffer->config.size.w; n++, n3 += 4) { buf_p[n3+0] = palette->entries[src8[n]].r; buf_p[n3+1] = palette->entries[src8[n]].g; buf_p[n3+2] = palette->entries[src8[n]].b; buf_p[n3+3] = palette->entries[src8[n]].a; } } else dfb_convert_to_argb( buffer->config.format, buffer->config.colorspace, srces[0], pitches[0], srces[1], pitches[1], srces[2], pitches[2], buffer->config.size.h, (u32*) (&buf_p[0]), buffer->config.size.w * 4, buffer->config.size.w, 1 ); direct_file_write( &fd_p, buf_p, buffer->config.size.w * 4, &bytes ); } else { u8 buf_p[buffer->config.size.w*3]; if (buffer->config.format == DSPF_LUT8) { for (n = 0, n3 = 0; n < buffer->config.size.w; n++, n3 += 3) { buf_p[n3+0] = palette->entries[src8[n]].r; buf_p[n3+1] = palette->entries[src8[n]].g; buf_p[n3+2] = palette->entries[src8[n]].b; } } else dfb_convert_to_rgb24( buffer->config.format, buffer->config.colorspace, srces[0], pitches[0], srces[1], pitches[1], srces[2], pitches[2], buffer->config.size.h, buf_p, buffer->config.size.w * 3, buffer->config.size.w, 1 ); direct_file_write( &fd_p, buf_p, buffer->config.size.w * 3, &bytes ); } } /* Write alpha buffer to graymap file. */ if (alpha && !raw) { u8 buf_g[buffer->config.size.w]; if (buffer->config.format == DSPF_LUT8) { for (n = 0; n < buffer->config.size.w; n++) buf_g[n] = palette->entries[src8[n]].a; } else dfb_convert_to_a8( buffer->config.format, srces[0], pitches[0], buffer->config.size.h, buf_g, buffer->config.size.w, buffer->config.size.w, 1 ); direct_file_write( &fd_g, buf_g, buffer->config.size.w, &bytes ); } } /* Release the palette. */ if (palette) dfb_palette_unref( palette ); /* Close pixmap file. */ if (rgb) direct_file_close( &fd_p ); /* Close graymap file. */ if (alpha && !raw) direct_file_close( &fd_g ); return DFB_OK; } static DFBResult dfb_surface_buffer_dump_type( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix, bool raw ) { DFBResult ret; CoreSurfaceBufferLock lock; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_ASSERT( directory != NULL ); D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p, %p )\n", __FUNCTION__, buffer, directory, prefix ); /* Lock the surface buffer, get the data pointer and pitch. */ ret = dfb_surface_buffer_lock( buffer, CSAID_CPU, CSAF_READ, &lock ); if (ret) return ret; ret = dfb_surface_buffer_dump_type_locked( buffer, directory, prefix, raw, &lock ); /* Unlock the surface buffer. */ dfb_surface_buffer_unlock( &lock ); return ret; } DFBResult dfb_surface_buffer_dump( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix ) { return dfb_surface_buffer_dump_type( buffer, directory, prefix, false ); } DFBResult dfb_surface_buffer_dump_raw( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix ) { return dfb_surface_buffer_dump_type( buffer, directory, prefix, true ); } ================================================ FILE: src/core/surface_buffer.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_BUFFER_H__ #define __CORE__SURFACE_BUFFER_H__ #include /**********************************************************************************************************************/ typedef enum { CSP_SYSTEMONLY = 0x00000000, /* Never try to swap into video memory. */ CSP_VIDEOLOW = 0x00000001, /* Try to store in video memory, low priority. */ CSP_VIDEOHIGH = 0x00000002, /* Try to store in video memory, high priority. */ CSP_VIDEOONLY = 0x00000003 /* Always and only store in video memory. */ } CoreSurfacePolicy; typedef enum { CSBF_NONE = 0x00000000, /* None of these. */ CSBF_DECOUPLE = 0x00000002, /* Buffer is about to be deallocated and removed from surface. */ CSBF_RIGHT = 0x00000004, /* Buffer is for right eye. */ CSBF_ALL = 0x00000006 /* All of these. */ } CoreSurfaceBufferFlags; struct __DFB_CoreSurfaceBuffer { FusionObject object; int magic; DirectSerial serial; /* Increased when content is written. */ CoreSurfaceAllocation *written; /* Allocation with the last write access. */ CoreSurfaceAllocation *read; /* Allocation with the last read access. */ CoreSurface *surface; /* Surface owning this surface buffer. */ CoreSurfacePolicy policy; /* Policy of its surface. */ CoreSurfaceBufferFlags flags; /* Configuration and state flags. */ FusionVector allocs; /* Allocations within surface pools. */ CoreSurfaceConfig config; /* Configuration of its surface at the time of the buffer creation */ CoreSurfaceTypeFlags type; /* Classification of the surface. */ unsigned long resource_id; /* layer id, window id, or user specified */ int index; /* index of surface buffer */ unsigned int busy; /* busy buffer */ FusionObjectID surface_id; /* surface id */ }; struct __DFB_CoreSurfaceBufferLock { int magic; /* Must be valid before calling dfb_surface_pool_lock(). */ CoreSurfaceAccessorID accessor; /* Accessor ID. */ CoreSurfaceAccessFlags access; /* Access flags. */ CoreSurfaceBuffer *buffer; /* Set by dfb_surface_pool_lock(). */ CoreSurfaceAllocation *allocation; /* Allocation of a surface buffer. */ void *addr; /* address of buffer */ unsigned long phys; /* physical address */ unsigned long offset; /* framebuffer offset */ unsigned int pitch; /* pitch of buffer */ void *handle; /* handle */ }; #if D_DEBUG_ENABLED #define CORE_SURFACE_BUFFER_LOCK_ASSERT(lock) \ do { \ D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); \ D_FLAGS_ASSERT( (lock)->access, CSAF_ALL ); \ if ((lock)->allocation) { \ D_ASSERT( (lock)->pitch > 0 || ((lock)->addr == NULL && (lock)->phys == 0) ); \ D_ASSUME( (lock)->addr != NULL || (lock)->phys != 0 || (lock)->offset != ~0 || (lock)->handle != NULL );\ D_ASSUME( (lock)->offset == (lock)->allocation->offset || (lock)->offset == ~0 ); \ } \ else { \ D_ASSERT( (lock)->buffer == NULL ); \ D_ASSERT( (lock)->addr == NULL ); \ D_ASSERT( (lock)->phys == 0 ); \ D_ASSERT( (lock)->offset == ~0 ); \ D_ASSERT( (lock)->pitch == 0 ); \ D_ASSERT( (lock)->handle == NULL ); \ } \ } while (0) #else #define CORE_SURFACE_BUFFER_LOCK_ASSERT(lock) \ do { \ } while (0) #endif /**********************************************************************************************************************/ typedef enum { CSBNF_NONE = 0x00000000 } CoreSurfaceBufferNotificationFlags; typedef struct { CoreSurfaceBufferNotificationFlags flags; } CoreSurfaceBufferNotification; /**********************************************************************************************************************/ /* * Creates a pool of surface buffer objects. */ FusionObjectPool *dfb_surface_buffer_pool_create ( const FusionWorld *world ); /* * Generates dfb_surface_buffer_ref(), dfb_surface_buffer_attach() etc. */ FUSION_OBJECT_METHODS( CoreSurfaceBuffer, dfb_surface_buffer ) /**********************************************************************************************************************/ DFBResult dfb_surface_buffer_create ( CoreDFB *core, CoreSurface *surface, CoreSurfaceBufferFlags flags, int index, CoreSurfaceBuffer **ret_buffer ); DFBResult dfb_surface_buffer_decouple ( CoreSurfaceBuffer *buffer ); DFBResult dfb_surface_buffer_deallocate ( CoreSurfaceBuffer *buffer ); CoreSurfaceAllocation *dfb_surface_buffer_find_allocation ( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags flags, bool lock ); CoreSurfaceAllocation *dfb_surface_buffer_find_allocation_key( CoreSurfaceBuffer *buffer, const char *key ); DFBResult dfb_surface_buffer_lock ( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceBufferLock *ret_lock ); DFBResult dfb_surface_buffer_unlock ( CoreSurfaceBufferLock *lock ); DFBResult dfb_surface_buffer_dump_type_locked ( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix, bool raw, CoreSurfaceBufferLock *lock ); DFBResult dfb_surface_buffer_dump_type_locked2 ( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix, bool raw, void *addr, int pitch ); DFBResult dfb_surface_buffer_dump ( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix ); DFBResult dfb_surface_buffer_dump_raw ( CoreSurfaceBuffer *buffer, const char *directory, const char *prefix ); /**********************************************************************************************************************/ static __inline__ void dfb_surface_buffer_lock_reset( CoreSurfaceBufferLock *lock ) { D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); lock->buffer = NULL; lock->allocation = NULL; lock->addr = NULL; lock->phys = 0; lock->offset = ~0; lock->pitch = 0; lock->handle = 0; } static __inline__ void dfb_surface_buffer_lock_init( CoreSurfaceBufferLock *lock, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ) { D_MAGIC_SET_ONLY( lock, CoreSurfaceBufferLock ); lock->accessor = accessor; lock->access = access; dfb_surface_buffer_lock_reset( lock ); } static __inline__ void dfb_surface_buffer_lock_deinit( CoreSurfaceBufferLock *lock ) { D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); lock->accessor = CSAID_NONE; lock->access = CSAF_NONE; D_MAGIC_CLEAR( lock ); } static __inline__ int dfb_surface_buffer_index( CoreSurfaceBuffer *buffer ) { D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); return buffer->index; } #endif ================================================ FILE: src/core/surface_client.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Core_SurfClient, "Core/SurfClient", "DirectFB Core Surface Client" ); /**********************************************************************************************************************/ static void surface_client_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreSurfaceClient *client = (CoreSurfaceClient*) object; CoreSurface *surface; int index; D_MAGIC_ASSERT( client, CoreSurfaceClient ); D_MAGIC_ASSERT( client->surface, CoreSurface ); surface = client->surface; D_DEBUG_AT( Core_SurfClient, "Destroying client %p (%dx%d%s)\n", client, surface->config.size.w, surface->config.size.h, zombie ? " ZOMBIE" : "" ); CoreSurfaceClient_Deinit_Dispatch( &client->call ); dfb_surface_lock( surface ); index = fusion_vector_index_of( &surface->clients, client ); D_ASSERT( index >= 0 ); fusion_vector_remove( &surface->clients, index ); dfb_surface_check_acks( surface ); dfb_surface_unlock( surface ); dfb_surface_unlink( &client->surface ); D_MAGIC_CLEAR( client ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_surface_client_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Surface Client Pool", sizeof(CoreSurfaceClient), sizeof(CoreSurfaceClientNotification), surface_client_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_surface_client_create( CoreDFB *core, CoreSurface *surface, CoreSurfaceClient **ret_client ) { DFBResult ret; CoreSurfaceClient *client; D_MAGIC_ASSERT( surface, CoreSurface ); D_ASSERT( ret_client != NULL ); D_DEBUG_AT( Core_SurfClient, "%s( %p %dx%d %s )\n", __FUNCTION__, surface, surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ) ); /* Create the client object. */ client = dfb_core_create_surface_client( core ); if (!client) return DFB_FUSION; ret = dfb_surface_link( &client->surface, surface ); if (ret) { fusion_object_destroy( &client->object ); return ret; } D_MAGIC_SET( client, CoreSurfaceClient ); CoreSurfaceClient_Init_Dispatch( core, client, &client->call ); dfb_surface_lock( surface ); client->flip_count = surface->flips; fusion_vector_add( &surface->clients, client ); dfb_surface_unlock( surface ); /* Activate the object. */ fusion_object_activate( &client->object ); /* Return the new client. */ *ret_client = client; D_DEBUG_AT( Core_SurfClient, " -> %p\n", client ); return DFB_OK; } ================================================ FILE: src/core/surface_client.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_CLIENT_H__ #define __CORE__SURFACE_CLIENT_H__ #include #include /**********************************************************************************************************************/ struct __DFB_CoreSurfaceClient { FusionObject object; int magic; CoreSurface *surface; FusionCall call; u32 flip_count; DFBFrameTimeConfig frametime_config; }; /**********************************************************************************************************************/ typedef enum { CSCNF_NONE = 0x00000000, } CoreSurfaceClientNotificationFlags; typedef struct { CoreSurfaceClientNotificationFlags flags; } CoreSurfaceClientNotification; /**********************************************************************************************************************/ /* * Creates a pool of surface client objects. */ FusionObjectPool *dfb_surface_client_pool_create( const FusionWorld *world ); /* * Generates dfb_surface_client_ref(), dfb_surface_client_attach() etc. */ FUSION_OBJECT_METHODS( CoreSurfaceClient, dfb_surface_client ) /**********************************************************************************************************************/ DFBResult dfb_surface_client_create ( CoreDFB *core, CoreSurface *surface, CoreSurfaceClient **ret_client ); #endif ================================================ FILE: src/core/surface_core.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Surface, "Core/SurfaceCore", "DirectFB Surface Core" ); /**********************************************************************************************************************/ DFB_CORE_PART( surface_core, SurfaceCore ); /**********************************************************************************************************************/ #if FUSION_BUILD_MULTI extern const SurfacePoolFuncs sharedSurfacePoolFuncs; extern const SurfacePoolFuncs sharedSecureSurfacePoolFuncs; #else /* FUSION_BUILD_MULTI */ extern const SurfacePoolFuncs localSurfacePoolFuncs; #endif /* FUSION_BUILD_MULTI */ extern const SurfacePoolFuncs preallocSurfacePoolFuncs; extern const SurfacePoolBridgeFuncs preallocSurfacePoolBridgeFuncs; static DFBEnumerationResult alloc_callback( CoreSurfaceAllocation *allocation, void *ctx ) { CoreSurfaceBuffer *buffer; const char *role = "???"; const char *uptodate = " ? "; int allocs = 0; D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); buffer = allocation->buffer; if (buffer) { CoreSurface *surface; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); surface = buffer->surface; if (surface) { int base; D_MAGIC_ASSERT( surface, CoreSurface ); base = surface->flips % surface->num_buffers; role = (buffer->index == (base + DSBR_FRONT) % surface->num_buffers) ? "front" : (buffer->index == (base + DSBR_BACK) % surface->num_buffers) ? "back" : (buffer->index == (base + DSBR_IDLE) % surface->num_buffers) ? "idle" : ""; uptodate = direct_serial_check(&allocation->serial, &buffer->serial) ? " * " : " "; allocs = fusion_vector_size( &buffer->allocs ); } } printf( "%3u ", allocation->object.id ); printf( "%3u ", allocation->buffer_id ); printf( "%9lu %8d ", allocation->offset, allocation->size ); printf( "%4d x %4d ", allocation->config.size.w, allocation->config.size.h ); printf( "%8s ", dfb_pixelformat_name( allocation->config.format ) ); printf( " %-5s %s", role, uptodate ); printf( "%d %2lu ", allocs, allocation->resource_id ); if (allocation->type & CSTF_SHARED) printf( "SHARED " ); else printf( "PRIVATE " ); if (allocation->type & CSTF_LAYER) printf( "LAYER " ); if (allocation->type & CSTF_WINDOW) printf( "WINDOW " ); if (allocation->type & CSTF_CURSOR) printf( "CURSOR " ); if (allocation->type & CSTF_FONT) printf( "FONT " ); printf( " " ); if (allocation->type & CSTF_INTERNAL) printf( "INTERNAL " ); if (allocation->type & CSTF_EXTERNAL) printf( "EXTERNAL " ); printf( " " ); if (allocation->config.caps & DSCAPS_SYSTEMONLY) printf( "system only " ); if (allocation->config.caps & DSCAPS_VIDEOONLY) printf( "video only " ); if (allocation->config.caps & DSCAPS_INTERLACED) printf( "interlaced " ); if (allocation->config.caps & DSCAPS_DOUBLE) printf( "double " ); if (allocation->config.caps & DSCAPS_TRIPLE) printf( "triple " ); if (allocation->config.caps & DSCAPS_PREMULTIPLIED) printf( "premultiplied" ); printf( " ref 0x%04x\n", (unsigned int) allocation->object.ref.multi.id ); char buf[64]; snprintf( buf, sizeof(buf), "dfb_surface_allocation_%u_%u", allocation->object.id, allocation->buffer_id ); dfb_surface_allocation_dump( allocation, ".", buf, false ); return DFENUM_OK; } static DFBEnumerationResult surface_pool_callback( CoreSurfacePool *pool, void *ctx ) { int length; printf( "\n" ); printf( "--------------------[ Surface Buffer Allocations in %s ]--------------------%n\n", pool->desc.name, &length ); printf( "ID BID Offset Length Width Height Format Role Up nA ID Usage Type / Storage / Caps\n" ); while (length--) putc( '-', stdout ); printf( "\n" ); dfb_surface_pool_enumerate( pool, alloc_callback, NULL ); return DFENUM_OK; } static void dump_surface_pools( void ) { dfb_surface_pools_enumerate( surface_pool_callback, NULL ); } static DirectSignalHandlerResult dfb_surface_core_dump_handler( int num, void *addr, void *ctx ) { dump_surface_pools(); return DSHR_OK; } static DFBResult dfb_surface_core_initialize( CoreDFB *core, DFBSurfaceCore *data, DFBSurfaceCoreShared *shared ) { DFBResult ret; D_DEBUG_AT( Core_Surface, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; #if FUSION_BUILD_MULTI if (fusion_config->secure_fusion) { ret = dfb_surface_pool_initialize2( core, &sharedSecureSurfacePoolFuncs, data, &shared->surface_pool ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register 'shared' surface pool!\n" ); return ret; } } else { ret = dfb_surface_pool_initialize2( core, &sharedSurfacePoolFuncs, data, &shared->surface_pool ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register 'shared' surface pool!\n" ); return ret; } } #else /* FUSION_BUILD_MULTI */ ret = dfb_surface_pool_initialize2( core, &localSurfacePoolFuncs, data, &shared->surface_pool ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register 'local' surface pool!\n" ); return ret; } #endif /* FUSION_BUILD_MULTI */ ret = dfb_surface_pool_initialize2( core, &preallocSurfacePoolFuncs, data, &shared->prealloc_pool ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register 'prealloc' surface pool!\n" ); dfb_surface_pool_destroy( shared->surface_pool ); return ret; } ret = dfb_surface_pool_bridge_initialize( core, &preallocSurfacePoolBridgeFuncs, data, &shared->prealloc_pool_bridge ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register 'prealloc' surface pool bridge!\n" ); dfb_surface_pool_destroy( shared->prealloc_pool ); dfb_surface_pool_destroy( shared->surface_pool ); return ret; } ret = direct_signal_handler_add( DIRECT_SIGNAL_DUMP_STACK, dfb_surface_core_dump_handler, data, &data->dump_signal_handler ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register surface core signal handler!\n" ); dfb_surface_pool_bridge_destroy( shared->prealloc_pool_bridge ); dfb_surface_pool_destroy( shared->prealloc_pool ); dfb_surface_pool_destroy( shared->surface_pool ); return ret; } D_MAGIC_SET( data, DFBSurfaceCore ); D_MAGIC_SET( shared, DFBSurfaceCoreShared ); return DFB_OK; } static DFBResult dfb_surface_core_join( CoreDFB *core, DFBSurfaceCore *data, DFBSurfaceCoreShared *shared ) { DFBResult ret; D_DEBUG_AT( Core_Surface, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBSurfaceCoreShared ); data->core = core; data->shared = shared; #if FUSION_BUILD_MULTI if (fusion_config->secure_fusion) dfb_surface_pool_join2( core, shared->surface_pool, &sharedSecureSurfacePoolFuncs, data ); else dfb_surface_pool_join2( core, shared->surface_pool, &sharedSurfacePoolFuncs, data ); #else /* FUSION_BUILD_MULTI */ dfb_surface_pool_join2( core, shared->surface_pool, &localSurfacePoolFuncs, data ); #endif /* FUSION_BUILD_MULTI */ dfb_surface_pool_join2( core, shared->prealloc_pool, &preallocSurfacePoolFuncs, data ); dfb_surface_pool_bridge_join( core, shared->prealloc_pool_bridge, &preallocSurfacePoolBridgeFuncs, data ); ret = direct_signal_handler_add( DIRECT_SIGNAL_DUMP_STACK, dfb_surface_core_dump_handler, data, &data->dump_signal_handler ); if (ret) { D_DERROR( ret, "Core/SurfaceCore: Could not register surface core signal handler!\n" ); dfb_surface_pool_bridge_leave( shared->prealloc_pool_bridge ); dfb_surface_pool_leave( shared->prealloc_pool ); dfb_surface_pool_leave( shared->surface_pool ); return ret; } D_MAGIC_SET( data, DFBSurfaceCore ); return DFB_OK; } static DFBResult dfb_surface_core_shutdown( DFBSurfaceCore *data, bool emergency ) { DFBSurfaceCoreShared *shared; D_DEBUG_AT( Core_Surface, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBSurfaceCore ); D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); shared = data->shared; direct_signal_handler_remove( data->dump_signal_handler ); dfb_surface_pool_bridge_destroy( shared->prealloc_pool_bridge ); dfb_surface_pool_destroy( shared->prealloc_pool ); dfb_surface_pool_destroy( shared->surface_pool ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_surface_core_leave( DFBSurfaceCore *data, bool emergency ) { DFBSurfaceCoreShared *shared; D_DEBUG_AT( Core_Surface, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBSurfaceCore ); D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); shared = data->shared; direct_signal_handler_remove( data->dump_signal_handler ); dfb_surface_pool_bridge_leave( shared->prealloc_pool_bridge ); dfb_surface_pool_leave( shared->prealloc_pool ); dfb_surface_pool_leave( shared->surface_pool ); D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_surface_core_suspend( DFBSurfaceCore *data ) { D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBSurfaceCore ); D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); return DFB_OK; } static DFBResult dfb_surface_core_resume( DFBSurfaceCore *data ) { D_DEBUG_AT( Core_Surface, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBSurfaceCore ); D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); return DFB_OK; } ================================================ FILE: src/core/surface_core.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_CORE_H__ #define __CORE__SURFACE_CORE_H__ #include /**********************************************************************************************************************/ typedef struct { int magic; CoreSurfacePool *surface_pool; CoreSurfacePool *prealloc_pool; CoreSurfacePoolBridge *prealloc_pool_bridge; } DFBSurfaceCoreShared; typedef struct __DFB_DFBSurfaceCore { int magic; CoreDFB *core; DFBSurfaceCoreShared *shared; DirectSignalHandler *dump_signal_handler; } DFBSurfaceCore; #endif ================================================ FILE: src/core/surface_pool.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_SurfacePool, "Core/SurfacePool", "DirectFB Core Surface Pool" ); D_DEBUG_DOMAIN( Core_SurfPoolLock, "Core/SurfPoolLock", "DirectFB Core Surface Pool Lock" ); /**********************************************************************************************************************/ static int pool_count; static const SurfacePoolFuncs *pool_funcs[MAX_SURFACE_POOLS]; static void *pool_locals[MAX_SURFACE_POOLS]; static CoreSurfacePool *pool_array[MAX_SURFACE_POOLS]; static unsigned int pool_order[MAX_SURFACE_POOLS]; static __inline__ const SurfacePoolFuncs * get_funcs( const CoreSurfacePool *pool ) { D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( pool->pool_id >= 0 ); D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); D_ASSERT( pool_funcs[pool->pool_id] != NULL ); /* Return function table of the pool. */ return pool_funcs[pool->pool_id]; } static __inline__ void * get_local( const CoreSurfacePool *pool ) { D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( pool->pool_id >= 0 ); D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); /* Return local data of the pool. */ return pool_locals[pool->pool_id]; } static DFBResult init_pool ( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs, void *ctx ); static void insert_pool_local( CoreSurfacePool *pool ); static void remove_pool_local( CoreSurfacePoolID pool_id ); static void remove_allocation( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation_in ); static DFBResult backup_allocation( CoreSurfaceAllocation *allocation_in ); /**********************************************************************************************************************/ DFBResult dfb_surface_pool_initialize( CoreDFB *core, const SurfacePoolFuncs *funcs, CoreSurfacePool **ret_pool ) { return dfb_surface_pool_initialize2( core, funcs, dfb_system_data(), ret_pool ); } DFBResult dfb_surface_pool_initialize2( CoreDFB *core, const SurfacePoolFuncs *funcs, void *ctx, CoreSurfacePool **ret_pool ) { DFBResult ret; CoreSurfacePool *pool; FusionSHMPoolShared *shmpool; /* Check against pool limit. */ if (pool_count == MAX_SURFACE_POOLS) { D_ERROR( "Core/SurfacePool: Maximum number of pools (%d) reached!\n", MAX_SURFACE_POOLS ); return DFB_LIMITEXCEEDED; } D_ASSERT( core != NULL ); D_ASSERT( funcs != NULL ); D_ASSERT( ret_pool != NULL ); D_ASSERT( pool_funcs[pool_count] == NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p )\n", __FUNCTION__, funcs ); shmpool = dfb_core_shmpool( core ); /* Allocate pool structure. */ pool = SHCALLOC( shmpool, 1, sizeof(CoreSurfacePool) ); if (!pool) return D_OOSHM(); /* Assign a pool ID. */ pool->pool_id = pool_count++; /* Remember shared memory pool. */ pool->shmpool = shmpool; /* Set function table of the pool. */ pool_funcs[pool->pool_id] = funcs; /* Add to global pool list. */ pool_array[pool->pool_id] = pool; D_MAGIC_SET( pool, CoreSurfacePool ); ret = init_pool( core, pool, funcs, ctx ); if (ret) { pool_funcs[pool->pool_id] = NULL; pool_array[pool->pool_id] = NULL; pool_count--; D_MAGIC_CLEAR( pool ); SHFREE( shmpool, pool ); return ret; } /* Set default backup pool being the shared memory surface pool. */ if (!pool->backup && pool_count > 1) pool->backup = pool_array[0]; /* Insert new pool into priority order. */ insert_pool_local( pool ); /* Return the new pool. */ *ret_pool = pool; return DFB_OK; } DFBResult dfb_surface_pool_join( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs ) { return dfb_surface_pool_join2( core, pool, funcs, dfb_system_data() ); } DFBResult dfb_surface_pool_join2( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs, void *ctx ) { DFBResult ret; D_ASSERT( core != NULL ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); D_ASSERT( pool->pool_id == pool_count ); D_ASSERT( pool_funcs[pool->pool_id] == NULL ); D_ASSERT( funcs != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u], %p )\n", __FUNCTION__, pool, pool->pool_id, funcs ); /* Enforce same order as initialization to be used during join. */ if (pool->pool_id != pool_count) { D_ERROR( "Core/SurfacePool: Wrong order of joining pools, got %u, should be %d!\n", pool->pool_id, pool_count ); return DFB_BUG; } /* Allocate local pool data. */ if (pool->pool_local_data_size && !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size ))) return D_OOM(); /* Set function table of the pool. */ pool_funcs[pool->pool_id] = funcs; /* Add to global pool list. */ pool_array[pool->pool_id] = pool; /* Adjust pool count. */ if (pool_count < pool->pool_id + 1) pool_count = pool->pool_id + 1; funcs = get_funcs( pool ); if (funcs->JoinPool) { ret = funcs->JoinPool( core, pool, pool->data, get_local(pool), ctx ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Joining '%s' failed!\n", pool->desc.name ); if (pool_locals[pool->pool_id]) { D_FREE( pool_locals[pool->pool_id] ); pool_locals[pool->pool_id] = NULL; } pool_array[pool->pool_id] = NULL; pool_array[pool->pool_id] = NULL; pool_count--; return ret; } } /* Insert new pool into priority order. */ insert_pool_local( pool ); return DFB_OK; } DFBResult dfb_surface_pool_destroy( CoreSurfacePool *pool ) { const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( pool->pool_id >= 0 ); D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); D_ASSERT( pool_array[pool->pool_id] == pool ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u - %s] )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name ); funcs = get_funcs( pool ); if (funcs->DestroyPool) funcs->DestroyPool( pool, pool->data, get_local(pool) ); /* Free shared pool data. */ if (pool->data) SHFREE( pool->shmpool, pool->data ); /* Free local pool data and remove from lists. */ remove_pool_local( pool->pool_id ); fusion_skirmish_destroy( &pool->lock ); fusion_vector_destroy( &pool->allocs ); D_MAGIC_CLEAR( pool ); SHFREE( pool->shmpool, pool ); return DFB_OK; } DFBResult dfb_surface_pool_leave( CoreSurfacePool *pool ) { const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( pool->pool_id >= 0 ); D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); D_ASSERT( pool_array[pool->pool_id] == pool ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u - %s] )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name ); funcs = get_funcs( pool ); if (funcs->LeavePool) funcs->LeavePool( pool, pool->data, get_local(pool) ); /* Free local pool data and remove from lists. */ remove_pool_local( pool->pool_id ); return DFB_OK; } DFBResult dfb_surface_pools_prealloc( const DFBSurfaceDescription *description, CoreSurfaceConfig *config ) { DFBResult ret; int i; CoreSurfaceTypeFlags type; D_ASSERT( description != NULL ); D_ASSERT( config != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, description, config ); type = CSTF_PREALLOCATED; if (description->flags & DSDESC_CAPS) { if (description->caps & DSCAPS_SYSTEMONLY) type |= CSTF_INTERNAL; if (description->caps & DSCAPS_VIDEOONLY) type |= CSTF_EXTERNAL; } D_DEBUG_AT( Core_SurfacePool, " -> type 0x%03x required\n", type ); for (i = 0; i < pool_count; i++) { CoreSurfacePool *pool; D_ASSERT( pool_order[i] >= 0 ); D_ASSERT( pool_order[i] < pool_count ); pool = pool_array[pool_order[i]]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); if (D_FLAGS_ARE_SET( pool->desc.types, type )) { const SurfacePoolFuncs *funcs; D_DEBUG_AT( Core_SurfacePool, " -> [%u - %s] 0x%02x 0x%03x (%u)\n", pool->pool_id, pool->desc.name, pool->desc.caps, pool->desc.types, pool->desc.priority ); funcs = get_funcs( pool ); if (funcs->PreAlloc) { ret = funcs->PreAlloc( pool, pool->data, get_local(pool), description, config ); if (ret == DFB_OK) { config->preallocated_pool_id = pool->pool_id; return DFB_OK; } } } } return DFB_UNSUPPORTED; } DFBResult dfb_surface_pools_negotiate( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfacePool **ret_pools, unsigned int max_pools, unsigned int *ret_num ) { DFBResult ret; int i; unsigned int num = 0; CoreSurface *surface; CoreSurfaceTypeFlags type; unsigned int free_count = 0; CoreSurfacePool *free_pools[pool_count]; unsigned int oom_count = 0; CoreSurfacePool *oom_pools[pool_count]; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( accessor >= CSAID_CPU ); D_ASSERT( ret_pools != NULL ); D_ASSERT( max_pools > 0 ); D_ASSERT( ret_num != NULL ); surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%s], 0x%02x, 0x%02x, max %u )\n", __FUNCTION__, buffer, dfb_pixelformat_name( surface->config.format ), accessor, access, max_pools ); D_ASSUME( accessor < CSAID_NUM ); if (accessor >= CSAID_ANY) { D_UNIMPLEMENTED(); return DFB_UNIMPLEMENTED; } if (accessor < 0 || accessor >= CSAID_NUM) return DFB_INVARG; type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); switch (buffer->policy) { case CSP_SYSTEMONLY: type |= CSTF_INTERNAL; break; case CSP_VIDEOONLY: type |= CSTF_EXTERNAL; break; default: break; } D_DEBUG_AT( Core_SurfacePool, " -> 0x%02x 0x%03x required\n", access, type ); if (access & CSAF_READ) D_DEBUG_AT( Core_SurfacePool, " -> READ\n" ); if (access & CSAF_WRITE) D_DEBUG_AT( Core_SurfacePool, " -> WRITE\n" ); if (access & CSAF_SHARED) D_DEBUG_AT( Core_SurfacePool, " -> SHARED\n" ); if (type & CSTF_LAYER) D_DEBUG_AT( Core_SurfacePool, " -> LAYER\n" ); if (type & CSTF_WINDOW) D_DEBUG_AT( Core_SurfacePool, " -> WINDOW\n" ); if (type & CSTF_CURSOR) D_DEBUG_AT( Core_SurfacePool, " -> CURSOR\n" ); if (type & CSTF_FONT) D_DEBUG_AT( Core_SurfacePool, " -> FONT\n" ); if (type & CSTF_SHARED) D_DEBUG_AT( Core_SurfacePool, " -> SHARED\n" ); if (type & CSTF_INTERNAL) D_DEBUG_AT( Core_SurfacePool, " -> INTERNAL\n" ); if (type & CSTF_EXTERNAL) D_DEBUG_AT( Core_SurfacePool, " -> EXTERNAL\n" ); if (type & CSTF_PREALLOCATED) D_DEBUG_AT( Core_SurfacePool, " -> PREALLOCATED\n" ); for (i = 0; i < pool_count; i++) { CoreSurfacePool *pool; D_ASSERT( pool_order[i] >= 0 ); D_ASSERT( pool_order[i] < pool_count ); pool = pool_array[pool_order[i]]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfacePool, " -> [%u - %s] 0x%02x 0x%03x (%u), 0x%02x\n", pool->pool_id, pool->desc.name, pool->desc.caps, pool->desc.types, pool->desc.priority, pool->desc.access[accessor] ); if (Core_GetIdentity() != FUSION_ID_MASTER && !(pool->desc.access[accessor] & CSAF_SHARED)) { D_DEBUG_AT( Core_SurfacePool, " -> refusing allocation for slave in non-shared pool!\n" ); continue; } if (D_FLAGS_ARE_SET( pool->desc.access[accessor], access ) && D_FLAGS_ARE_SET( pool->desc.types, type & ~CSTF_PREALLOCATED )) { const SurfacePoolFuncs *funcs; D_DEBUG_AT( Core_SurfacePool, " -> [%u - %s] 0x%02x 0x%03x (%u)\n", pool->pool_id, pool->desc.name, pool->desc.caps, pool->desc.types, pool->desc.priority ); funcs = get_funcs( pool ); ret = funcs->TestConfig ? funcs->TestConfig( pool, pool->data, get_local(pool), buffer, &surface->config ) : DFB_OK; switch (ret) { case DFB_OK: D_DEBUG_AT( Core_SurfacePool, " => OK\n" ); free_pools[free_count++] = pool; break; case DFB_NOVIDEOMEMORY: D_DEBUG_AT( Core_SurfacePool, " => OUT OF MEMORY\n" ); oom_pools[oom_count++] = pool; break; default: D_DEBUG_AT( Core_SurfacePool, " => %s\n", DirectFBErrorString( ret ) ); continue; } } } D_DEBUG_AT( Core_SurfacePool, " -> %u pools available\n", free_count ); D_DEBUG_AT( Core_SurfacePool, " -> %u pools out of memory\n", oom_count ); for (i = 0; i < free_count && num < max_pools; i++) ret_pools[num++] = free_pools[i]; for (i = 0; i < oom_count && num < max_pools; i++) ret_pools[num++] = oom_pools[i]; *ret_num = num; return free_count ? DFB_OK : oom_count ? DFB_NOVIDEOMEMORY : DFB_UNSUPPORTED; } DFBResult dfb_surface_pools_enumerate( CoreSurfacePoolCallback callback, void *ctx ) { int i; D_ASSERT( callback != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, callback, ctx ); for (i = 0; i < pool_count; i++) { CoreSurfacePool *pool = pool_array[i]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); if (callback( pool, ctx ) == DFENUM_CANCEL) break; } return DFB_OK; } DFBResult dfb_surface_pools_lookup( CoreSurfacePoolID pool_id, CoreSurfacePool **ret_pool ) { int i; D_ASSERT( ret_pool != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( [%u], %p )\n", __FUNCTION__, pool_id, ret_pool ); for (i = 0; i < pool_count; i++) { CoreSurfacePool *pool = pool_array[i]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); if (pool->pool_id == pool_id) { *ret_pool = pool; return DFB_OK; } } return DFB_IDNOTFOUND; } DFBResult dfb_surface_pools_allocate( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; int i; CoreSurface *surface; CoreSurfaceAllocation *allocation = NULL; CoreSurfacePool *pools[pool_count]; unsigned int num_pools; D_UNUSED_P( surface ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( accessor >= CSAID_CPU ); D_FLAGS_ASSERT( access, CSAF_ALL ); D_ASSERT( ret_allocation != NULL ); surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, 0x%x )\n", __FUNCTION__, buffer, access ); D_DEBUG_AT( Core_SurfacePool, " -> %dx%d %s - %s%s%s%s%s%s%s%s\n", surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), (surface->type & CSTF_SHARED) ? "SHARED" : "PRIVATE", (surface->type & CSTF_LAYER) ? " LAYER" : "", (surface->type & CSTF_WINDOW) ? " WINDOW" : "", (surface->type & CSTF_CURSOR) ? " CURSOR" : "", (surface->type & CSTF_FONT) ? " FONT" : "", (surface->type & CSTF_INTERNAL) ? " INTERNAL" : "", (surface->type & CSTF_EXTERNAL) ? " EXTERNAL" : "", (surface->type & CSTF_PREALLOCATED) ? " PREALLOCATED" : "" ); D_ASSUME( accessor < CSAID_NUM ); if (accessor >= CSAID_ANY) { D_UNIMPLEMENTED(); return DFB_UNIMPLEMENTED; } if (accessor < 0 || accessor >= CSAID_NUM) return DFB_INVARG; /* Build a list of possible pools being free or out of memory. */ ret = dfb_surface_pools_negotiate( buffer, accessor, access, pools, pool_count, &num_pools ); if (ret && ret != DFB_NOVIDEOMEMORY) { D_DEBUG_AT( Core_SurfacePool, " -> negotiation failed!\n" ); return ret; } /* Try to do the allocation in one of the pools. */ for (i = 0; i < num_pools; i++) { CoreSurfacePool *pool = pools[i]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); ret = dfb_surface_pool_allocate( pool, buffer, NULL, 0, &allocation ); if (ret == DFB_OK) break; /* When an error other than out of memory happens. */ if (ret != DFB_NOVIDEOMEMORY) { D_DEBUG_AT( Core_SurfacePool, " -> allocation in '%s' failed!\n", pool->desc.name ); /* Forget about the pool for now. */ pools[i] = NULL; } } /* Check if none of the pools could do the allocation. */ if (!allocation) { /* Try to find a pool with older allocations to muck out. */ for (i = 0; i < num_pools; i++) { CoreSurfacePool *pool = pools[i]; /* Pools with non-oom errors were sorted out above. */ if (!pool) continue; D_MAGIC_ASSERT( pool, CoreSurfacePool ); ret = dfb_surface_pool_displace( pool, buffer, &allocation ); if (ret == DFB_OK) break; } } if (!allocation) { D_DEBUG_AT( Core_SurfacePool, " -> allocation failed!\n" ); return DFB_FAILURE; } CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation ); *ret_allocation = allocation; return DFB_OK; } DFBResult dfb_surface_pools_allocate_key( CoreSurfaceBuffer *buffer, const char *key, u64 handle, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; int i; CoreSurface *surface; CoreSurfaceAllocation *allocation = NULL; D_UNUSED_P( surface ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( key != NULL ); D_ASSERT( ret_allocation != NULL ); surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, key '%s', handle 0x%08llx )\n", __FUNCTION__, buffer, key, (unsigned long long) handle ); for (i = 0; i < pool_count; i++) { CoreSurfacePool *pool; D_ASSERT( pool_order[i] >= 0 ); D_ASSERT( pool_order[i] < pool_count ); pool = pool_array[pool_order[i]]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); if (D_FLAGS_ARE_SET( pool->desc.types, buffer->type & ~(CSTF_PREALLOCATED | CSTF_INTERNAL | CSTF_EXTERNAL) )) { D_DEBUG_AT( Core_SurfacePool, " -> [%u - %s] 0x%02x 0x%03x (%u)\n", pool->pool_id, pool->desc.name, pool->desc.caps, pool->desc.types, pool->desc.priority ); ret = dfb_surface_pool_check_key( pool, buffer, key, handle ); if (ret == DFB_OK) break; } } if (i < pool_count) { CoreSurfacePool *pool; pool = pool_array[pool_order[i]]; D_MAGIC_ASSERT( pool, CoreSurfacePool ); ret = dfb_surface_pool_allocate( pool, buffer, key, handle, &allocation ); if (ret) { D_DEBUG_AT( Core_SurfacePool, " -> dfb_surface_pool_allocate() failed\n" ); } else { D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); *ret_allocation = allocation; } } else { D_DEBUG_AT( Core_SurfacePool, " -> no pool found for key!\n" ); ret = DFB_UNSUPPORTED; } return ret; } DFBResult dfb_surface_pool_check_key( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, const char *key, u64 handle ) { DFBResult ret = DFB_UNSUPPORTED; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_ASSERT( key != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p, key '%s', handle 0x%08llx )\n", __FUNCTION__, pool, buffer, key, (unsigned long long) handle ); funcs = get_funcs( pool ); if (funcs->CheckKey) { ret = funcs->CheckKey( pool, pool->data, get_local(pool), buffer, key, handle ); D_DEBUG_AT( Core_SurfacePool, " -> %s\n", DirectFBErrorString( ret ) ); } else D_DEBUG_AT( Core_SurfacePool, " -> no support for keys!\n" ); return ret; } DFBResult dfb_surface_pool_allocate( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, const char *key, u64 handle, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret; CoreSurface *surface; CoreSurfaceAllocation *allocation = NULL; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( ret_allocation != NULL ); surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, buffer ); funcs = get_funcs( pool ); ret = dfb_surface_allocation_create( core_dfb, buffer, pool, &allocation ); if (ret) return ret; if (fusion_skirmish_prevail( &pool->lock )) { ret = DFB_FUSION; goto error; } if (dfb_config->warn.flags & DCWF_ALLOCATE_BUFFER && dfb_config->warn.allocate_buffer.min_size.w <= surface->config.size.w && dfb_config->warn.allocate_buffer.min_size.h <= surface->config.size.h) D_WARN( "allocate-buffer %4dx%4d %6s, surface-caps 0x%08x, key '%s'", surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( buffer->config.format ), surface->config.caps, key ?: "(none)" ); if (key) { D_ASSERT( funcs->AllocateKey != NULL ); ret = funcs->AllocateKey( pool, pool->data, get_local(pool), buffer, key, handle, allocation, allocation->data ); } else { D_ASSERT( funcs->AllocateBuffer != NULL ); ret = funcs->AllocateBuffer( pool, pool->data, get_local(pool), buffer, allocation, allocation->data ); } if (ret) { allocation->flags |= CSALF_DEALLOCATED; fusion_skirmish_dismiss( &pool->lock ); goto error; } D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation ); D_FLAGS_CLEAR( allocation->flags, CSALF_INITIALIZING ); fusion_vector_add( &buffer->allocs, allocation ); fusion_vector_add( &pool->allocs, allocation ); /* Mark the CoreSurfaceAllocation as having been read and written to by the CPU because it is possible that the CPU cache after the allocation has some data due to a read/write performed as part of allocation. */ allocation->accessed[CSAID_CPU] |= CSAF_READ | CSAF_WRITE; dfb_surface_allocation_globalize( allocation ); fusion_skirmish_dismiss( &pool->lock ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); *ret_allocation = allocation; return DFB_OK; error: dfb_surface_allocation_unref( allocation ); return ret; } DFBResult dfb_surface_pool_deallocate( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation ) { DFBResult ret; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); if (allocation->flags & CSALF_DEALLOCATED) { D_DEBUG_AT( Core_SurfacePool, " -> already deallocated\n" ); return DFB_OK; } funcs = get_funcs( pool ); D_ASSERT( funcs->DeallocateBuffer != NULL ); if (fusion_skirmish_prevail( &pool->lock )) return DFB_FUSION; ret = funcs->DeallocateBuffer( pool, pool->data, get_local(pool), allocation->buffer, allocation, allocation->data ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Could not deallocate buffer!\n" ); fusion_skirmish_dismiss( &pool->lock ); return ret; } remove_allocation( pool, allocation ); allocation->flags |= CSALF_DEALLOCATED; CoreSurfaceAllocationNotification notification; notification.flags = CSANF_DEALLOCATED; dfb_surface_allocation_dispatch( allocation, ¬ification, NULL ); fusion_skirmish_dismiss( &pool->lock ); return DFB_OK; } DFBResult dfb_surface_pool_displace( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation **ret_allocation ) { DFBResult ret, ret_lock = DFB_OK; int i, retries = 3; CoreSurface *surface; CoreSurfaceAllocation *allocation; const SurfacePoolFuncs *funcs; D_UNUSED_P( surface ); D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( buffer->surface, CoreSurface ); D_ASSERT( ret_allocation != NULL ); surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &surface->lock ); D_DEBUG_AT( Core_SurfacePool, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, buffer ); funcs = get_funcs( pool ); if (fusion_skirmish_prevail( &pool->lock )) return DFB_FUSION; /* Check for integrated method to muck out older allocations for a new one. */ if (funcs->MuckOut) { ret = funcs->MuckOut( pool, pool->data, get_local(pool), buffer ); if (ret) { fusion_skirmish_dismiss( &pool->lock ); return ret; } } else { D_UNIMPLEMENTED(); } retry: fusion_vector_foreach (allocation, i, pool->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( allocation ); if (allocation->flags & CSALF_MUCKOUT) { CoreSurface *alloc_surface; CoreSurfaceBuffer *alloc_buffer; alloc_buffer = allocation->buffer; D_MAGIC_ASSERT( alloc_buffer, CoreSurfaceBuffer ); alloc_surface = alloc_buffer->surface; D_MAGIC_ASSERT( alloc_surface, CoreSurface ); D_DEBUG_AT( Core_SurfacePool, " <= %p %5dk, %lu\n", allocation, allocation->size / 1024, allocation->offset ); ret = dfb_surface_trylock( alloc_surface ); if (ret) { D_WARN( "could not lock surface (%s)", DirectFBErrorString( ret ) ); ret_lock = ret; continue; } /* Ensure mucked out allocation is backed up to another pool. */ ret = backup_allocation( allocation ); if (ret) { D_WARN( "could not backup allocation (%s)", DirectFBErrorString( ret ) ); dfb_surface_unlock( alloc_surface ); goto error; } /* Deallocate mucked out allocation. */ dfb_surface_allocation_decouple( allocation ); i--; dfb_surface_unlock( alloc_surface ); } } if (ret_lock) { if (retries--) goto retry; ret = DFB_LOCKED; goto error; } else ret = dfb_surface_pool_allocate( pool, buffer, NULL, 0, ret_allocation ); fusion_skirmish_dismiss( &pool->lock ); return ret; error: fusion_vector_foreach (allocation, i, pool->allocs) { CORE_SURFACE_ALLOCATION_ASSERT( allocation ); if (allocation->flags & CSALF_MUCKOUT) allocation->flags &= ~CSALF_MUCKOUT; } fusion_skirmish_dismiss( &pool->lock ); return ret; } DFBResult dfb_surface_pool_prelock( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ) { DFBResult ret; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); funcs = get_funcs( pool ); if (funcs->PreLock) { ret = funcs->PreLock( pool, pool->data, get_local(pool), allocation, allocation->data, accessor, access ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Could not prelock allocation!\n" ); return ret; } } return DFB_OK; } DFBResult dfb_surface_pool_lock( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceBufferLock *lock ) { DFBResult ret; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); D_ASSERT( lock->buffer == NULL ); funcs = get_funcs( pool ); D_ASSERT( funcs->Lock != NULL ); lock->allocation = allocation; lock->buffer = allocation->buffer; ret = funcs->Lock( pool, pool->data, get_local(pool), allocation, allocation->data, lock ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Could not lock allocation!\n" ); dfb_surface_buffer_lock_reset( lock ); return ret; } return DFB_OK; } DFBResult dfb_surface_pool_unlock( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceBufferLock *lock ) { DFBResult ret; const SurfacePoolFuncs *funcs; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); D_ASSERT( lock->allocation == allocation ); funcs = get_funcs( pool ); D_ASSERT( funcs->Unlock != NULL ); ret = funcs->Unlock( pool, pool->data, get_local(pool), allocation, allocation->data, lock ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Could not unlock allocation!\n" ); return ret; } dfb_surface_buffer_lock_reset( lock ); return DFB_OK; } DFBResult dfb_surface_pool_read( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, void *data, int pitch, const DFBRectangle *rect ) { DFBResult ret; const SurfacePoolFuncs *funcs; CoreSurface *surface; DFBRectangle area; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); D_ASSERT( data != NULL ); D_ASSERT( pitch >= 0 ); DFB_RECTANGLE_ASSERT_IF( rect ); funcs = get_funcs( pool ); D_ASSERT( funcs != NULL ); if (!funcs->Read) return DFB_UNSUPPORTED; surface = allocation->surface; D_MAGIC_ASSERT( surface, CoreSurface ); area.x = 0; area.y = 0; area.w = surface->config.size.w; area.h = surface->config.size.h; if (rect && !dfb_rectangle_intersect( &area, rect )) return DFB_INVAREA; ret = funcs->Read( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area ); if (ret) D_DERROR( ret, "Core/SurfacePool: Could not read from allocation!\n" ); return ret; } DFBResult dfb_surface_pool_write( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, const void *data, int pitch, const DFBRectangle *rect ) { DFBResult ret; const SurfacePoolFuncs *funcs; CoreSurface *surface; DFBRectangle area; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%u - %s], %p )\n", __FUNCTION__, pool, pool->pool_id, pool->desc.name, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); D_ASSERT( data != NULL ); D_ASSERT( pitch >= 0 ); DFB_RECTANGLE_ASSERT_IF( rect ); funcs = get_funcs( pool ); if (!funcs->Write) return DFB_UNSUPPORTED; surface = allocation->surface; D_MAGIC_ASSERT( surface, CoreSurface ); area.x = 0; area.y = 0; area.w = surface->config.size.w; area.h = surface->config.size.h; if (rect && !dfb_rectangle_intersect( &area, rect )) return DFB_INVAREA; ret = funcs->Write( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area ); if (ret) D_DERROR( ret, "Core/SurfacePool: Could not write to allocation!\n" ); return ret; } DFBResult dfb_surface_pool_enumerate ( CoreSurfacePool *pool, CoreSurfaceAllocCallback callback, void *ctx ) { int i; CoreSurfaceAllocation *allocation; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( callback != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p, %p )\n", __FUNCTION__, pool, callback, ctx ); fusion_vector_foreach (allocation, i, pool->allocs) { if (callback( allocation, ctx ) == DFENUM_CANCEL) break; } return DFB_OK; } /**********************************************************************************************************************/ static DFBResult init_pool( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs, void *ctx ) { DFBResult ret; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_ASSERT( funcs != NULL ); D_ASSERT( funcs->InitPool != NULL ); D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, pool, funcs ); if (funcs->PoolDataSize) pool->pool_data_size = funcs->PoolDataSize(); if (funcs->PoolLocalDataSize) pool->pool_local_data_size = funcs->PoolLocalDataSize(); if (funcs->AllocationDataSize) pool->alloc_data_size = funcs->AllocationDataSize(); /* Allocate shared pool data. */ if (pool->pool_data_size) { pool->data = SHCALLOC( pool->shmpool, 1, pool->pool_data_size ); if (!pool->data) return D_OOSHM(); } /* Allocate local pool data. */ if (pool->pool_local_data_size && !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size ))) { SHFREE( pool->shmpool, pool->data ); return D_OOM(); } fusion_vector_init( &pool->allocs, 4, pool->shmpool ); ret = funcs->InitPool( core, pool, pool->data, get_local(pool), ctx, &pool->desc ); if (ret) { D_DERROR( ret, "Core/SurfacePool: Initializing '%s' failed!\n", pool->desc.name ); if (pool_locals[pool->pool_id]) { D_FREE( pool_locals[pool->pool_id] ); pool_locals[pool->pool_id] = NULL; } if (pool->data) { SHFREE( pool->shmpool, pool->data ); pool->data = NULL; } return ret; } pool->desc.caps &= ~(CSPCAPS_READ | CSPCAPS_WRITE); if (funcs->Read) pool->desc.caps |= CSPCAPS_READ; if (funcs->Write) pool->desc.caps |= CSPCAPS_WRITE; fusion_skirmish_init2( &pool->lock, pool->desc.name, dfb_core_world( core ), fusion_config->secure_fusion ); return DFB_OK; } static void insert_pool_local( CoreSurfacePool *pool ) { int i, n; for (i = 0; i < pool_count - 1; i++) { D_ASSERT( pool_order[i] >= 0 ); D_ASSERT( pool_order[i] < pool_count - 1 ); D_MAGIC_ASSERT( pool_array[pool_order[i]], CoreSurfacePool ); if (pool_array[pool_order[i]]->desc.priority < pool->desc.priority) break; } for (n = pool_count - 1; n > i; n--) { D_ASSERT( pool_order[n-1] >= 0 ); D_ASSERT( pool_order[n-1] < pool_count - 1 ); D_MAGIC_ASSERT( pool_array[pool_order[n-1]], CoreSurfacePool ); pool_order[n] = pool_order[n-1]; } pool_order[n] = pool_count - 1; for (i = 0; i < pool_count; i++) { D_DEBUG_AT( Core_SurfacePool, " %c> [%d] %p - '%s' [%u] (%u), %p\n", (i == n) ? '=' : '-', i, pool_array[pool_order[i]], pool_array[pool_order[i]]->desc.name, pool_array[pool_order[i]]->pool_id, pool_array[pool_order[i]]->desc.priority, pool_funcs[pool_order[i]] ); D_ASSERT( pool_order[i] == pool_array[pool_order[i]]->pool_id ); } } static void remove_pool_local( CoreSurfacePoolID pool_id ) { int i; /* Free local pool data. */ if (pool_locals[pool_id]) { D_FREE( pool_locals[pool_id] ); pool_locals[pool_id] = NULL; } /* Erase entries of the pool. */ pool_array[pool_id] = NULL; pool_funcs[pool_id] = NULL; while (pool_count > 0 && !pool_array[pool_count-1]) { pool_count--; for (i = 0; i < pool_count; i++) { if (pool_order[i] == pool_count) { direct_memmove( &pool_order[i], &pool_order[i+1], sizeof(pool_order[0]) * (pool_count - i) ); break; } } } } static void remove_allocation( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation_in ) { int index_pool; CoreSurfaceAllocation *allocation = allocation_in; D_MAGIC_ASSERT( pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfacePool, "%s( %p )\n", __FUNCTION__, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_ASSERT( pool == allocation->pool ); FUSION_SKIRMISH_ASSERT( &pool->lock ); /* Lookup indices within vectors. */ index_pool = fusion_vector_index_of( &pool->allocs, allocation ); D_ASSERT( index_pool >= 0 ); /* Remove allocation from buffer and pool. */ fusion_vector_remove( &pool->allocs, index_pool ); } static DFBResult backup_allocation( CoreSurfaceAllocation *allocation_in ) { DFBResult ret = DFB_OK; int i; CoreSurface *surface; CoreSurfaceAllocation *allocation = allocation_in; CoreSurfacePool *pool; CoreSurfaceBuffer *buffer; D_UNUSED_P( surface ); D_DEBUG_AT( Core_SurfacePool, "%s( %p )\n", __FUNCTION__, allocation ); CORE_SURFACE_ALLOCATION_ASSERT( allocation ); D_MAGIC_ASSERT( allocation->pool, CoreSurfacePool ); D_MAGIC_ASSERT( allocation->buffer, CoreSurfaceBuffer ); D_MAGIC_ASSERT( allocation->buffer->surface, CoreSurface ); pool = allocation->pool; buffer = allocation->buffer; surface = buffer->surface; FUSION_SKIRMISH_ASSERT( &pool->lock ); FUSION_SKIRMISH_ASSERT( &surface->lock ); /* Check if allocation is the only up to date (requiring a backup). */ if (direct_serial_check( &allocation->serial, &buffer->serial )) { CoreSurfacePool *backup_pool = pool->backup; /* First check if any of the existing allocations is up to date. */ fusion_vector_foreach (allocation, i, buffer->allocs) { D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->pool, CoreSurfacePool ); if (allocation->pool != pool && direct_serial_check( &allocation->serial, &buffer->serial )) { D_DEBUG_AT( Core_SurfacePool, " -> up to date in '%s'\n", allocation->pool->desc.name ); return DFB_OK; } } /* Try to update one of the existing allocations. */ fusion_vector_foreach (allocation, i, buffer->allocs) { D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); D_MAGIC_ASSERT( allocation->pool, CoreSurfacePool ); if (allocation->pool != pool && dfb_surface_allocation_update( allocation, CSAF_NONE ) == DFB_OK) { D_DEBUG_AT( Core_SurfacePool, " -> updated in '%s'\n", allocation->pool->desc.name ); return DFB_OK; } } /* Try the designated backup pool. */ if (backup_pool) { D_MAGIC_ASSERT( backup_pool, CoreSurfacePool ); D_DEBUG_AT( Core_SurfacePool, " -> allocating in '%s'\n", backup_pool->desc.name ); /* Allocate in backup pool. */ ret = dfb_surface_pool_allocate( backup_pool, buffer, NULL, 0, &allocation ); if (ret == DFB_OK) { /* Update new allocation. */ ret = dfb_surface_allocation_update( allocation, CSAF_NONE ); if (ret) { D_DEBUG_AT( Core_SurfacePool, " -> update failed!\n" ); dfb_surface_allocation_decouple( allocation ); } else return DFB_OK; } else D_DEBUG_AT( Core_SurfacePool, " -> allocation failed!\n" ); } } else D_DEBUG_AT( Core_SurfacePool, " -> not up to date anyhow\n" ); return ret; } ================================================ FILE: src/core/surface_pool.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_POOL_H__ #define __CORE__SURFACE_POOL_H__ #include /**********************************************************************************************************************/ typedef enum { CSPCAPS_NONE = 0x00000000, /* none of these */ CSPCAPS_PHYSICAL = 0x00000001, /* pool provides physical address to buffer */ CSPCAPS_VIRTUAL = 0x00000002, /* pool provides virtual address to buffer */ CSPCAPS_READ = 0x00000004, /* pool provides Read() function (set automatically) */ CSPCAPS_WRITE = 0x00000008, /* pool provides Write() function (set automatically) */ CSPCAPS_ALL = 0x0000000F /* all of these */ } CoreSurfacePoolCapabilities; typedef enum { CSPP_DEFAULT = 0x00000000, CSPP_PREFERED = 0x00000001, CSPP_ULTIMATE = 0x00000002 } CoreSurfacePoolPriority; #define DFB_SURFACE_POOL_DESC_NAME_LENGTH 44 typedef struct { CoreSurfacePoolCapabilities caps; CoreSurfaceAccessFlags access[CSAID_NUM]; CoreSurfaceTypeFlags types; CoreSurfacePoolPriority priority; char name[DFB_SURFACE_POOL_DESC_NAME_LENGTH]; } CoreSurfacePoolDescription; typedef struct { int (*PoolDataSize) ( void ); int (*PoolLocalDataSize) ( void ); int (*AllocationDataSize)( void ); /* * Pool init/destroy. */ DFBResult (*InitPool) ( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data, CoreSurfacePoolDescription *ret_desc ); DFBResult (*JoinPool) ( CoreDFB *core, CoreSurfacePool *pool, void *pool_data, void *pool_local, void *system_data ); DFBResult (*DestroyPool) ( CoreSurfacePool *pool, void *pool_data, void *pool_local ); DFBResult (*LeavePool) ( CoreSurfacePool *pool, void *pool_data, void *pool_local ); DFBResult (*TestConfig) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, const CoreSurfaceConfig *config ); /* * Buffer management. */ DFBResult (*AllocateBuffer) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ); DFBResult (*DeallocateBuffer) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *allocation, void *alloc_data ); /* * Locking. */ DFBResult (*Lock) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ); DFBResult (*Unlock) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceBufferLock *lock ); /* * Read/Write. */ DFBResult (*Read) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, void *destination, int pitch, const DFBRectangle *rect ); DFBResult (*Write) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, const void *source, int pitch, const DFBRectangle *rect ); /* * Muck out. */ DFBResult (*MuckOut) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer ); /* * Manage interlocks. */ DFBResult (*PreLock) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceAllocation *allocation, void *alloc_data, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ); /* * Handle preallocation. * The surface pool checks the description and extracts/generates information for the surface configuration, to be * later used in the AllocateBuffer() function. */ DFBResult (*PreAlloc) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, const DFBSurfaceDescription *description, CoreSurfaceConfig *config ); /* * Keys. */ DFBResult (*CheckKey) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, const char *key, u64 handle ); DFBResult (*AllocateKey) ( CoreSurfacePool *pool, void *pool_data, void *pool_local, CoreSurfaceBuffer *buffer, const char *key, u64 handle, CoreSurfaceAllocation *allocation, void *alloc_data ); } SurfacePoolFuncs; struct __DFB_CoreSurfacePool { int magic; FusionSkirmish lock; CoreSurfacePoolID pool_id; CoreSurfacePoolDescription desc; int pool_data_size; int pool_local_data_size; int alloc_data_size; void *data; FusionVector allocs; FusionSHMPoolShared *shmpool; CoreSurfacePool *backup; }; /**********************************************************************************************************************/ typedef DFBEnumerationResult (*CoreSurfacePoolCallback) ( CoreSurfacePool *pool, void *ctx ); typedef DFBEnumerationResult (*CoreSurfaceAllocCallback)( CoreSurfaceAllocation *allocation, void *ctx ); /**********************************************************************************************************************/ DFBResult dfb_surface_pool_initialize ( CoreDFB *core, const SurfacePoolFuncs *funcs, CoreSurfacePool **ret_pool ); DFBResult dfb_surface_pool_initialize2 ( CoreDFB *core, const SurfacePoolFuncs *funcs, void *ctx, CoreSurfacePool **ret_pool ); DFBResult dfb_surface_pool_join ( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs ); DFBResult dfb_surface_pool_join2 ( CoreDFB *core, CoreSurfacePool *pool, const SurfacePoolFuncs *funcs, void *ctx ); DFBResult dfb_surface_pool_destroy ( CoreSurfacePool *pool ); DFBResult dfb_surface_pool_leave ( CoreSurfacePool *pool ); DFBResult dfb_surface_pools_prealloc ( const DFBSurfaceDescription *description, CoreSurfaceConfig *config ); DFBResult dfb_surface_pools_negotiate ( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfacePool **ret_pools, unsigned int max_pools, unsigned int *ret_num ); DFBResult dfb_surface_pools_enumerate ( CoreSurfacePoolCallback callback, void *ctx ); DFBResult dfb_surface_pools_lookup ( CoreSurfacePoolID pool_id, CoreSurfacePool **ret_pool ); DFBResult dfb_surface_pools_allocate ( CoreSurfaceBuffer *buffer, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_surface_pools_allocate_key( CoreSurfaceBuffer *buffer, const char *key, u64 handle, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_surface_pool_check_key ( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, const char *key, u64 handle ); DFBResult dfb_surface_pool_allocate ( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, const char *key, u64 handle, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_surface_pool_deallocate ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation ); DFBResult dfb_surface_pool_displace ( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation **ret_allocation ); DFBResult dfb_surface_pool_prelock ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ); DFBResult dfb_surface_pool_lock ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceBufferLock *lock ); DFBResult dfb_surface_pool_unlock ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceBufferLock *lock ); DFBResult dfb_surface_pool_read ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, void *data, int pitch, const DFBRectangle *rect ); DFBResult dfb_surface_pool_write ( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, const void *data, int pitch, const DFBRectangle *rect ); DFBResult dfb_surface_pool_enumerate ( CoreSurfacePool *pool, CoreSurfaceAllocCallback callback, void *ctx ); #endif ================================================ FILE: src/core/surface_pool_bridge.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_SurfPoolBridge, "Core/SurfPoolBridge", "DirectFB Core Surface Pool Bridge" ); /**********************************************************************************************************************/ static int bridge_count; static const SurfacePoolBridgeFuncs *bridge_funcs[MAX_SURFACE_POOL_BRIDGES]; static void *bridge_locals[MAX_SURFACE_POOL_BRIDGES]; static CoreSurfacePoolBridge *bridge_array[MAX_SURFACE_POOL_BRIDGES]; static unsigned int bridge_order[MAX_SURFACE_POOLS]; static __inline__ const SurfacePoolBridgeFuncs * get_funcs( const CoreSurfacePoolBridge *bridge ) { D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge->bridge_id >= 0 ); D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); D_ASSERT( bridge_funcs[bridge->bridge_id] != NULL ); /* Return function table of the bridge. */ return bridge_funcs[bridge->bridge_id]; } static __inline__ void * get_local( const CoreSurfacePoolBridge *bridge ) { D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge->bridge_id >= 0 ); D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); /* Return local data of the bridge. */ return bridge_locals[bridge->bridge_id]; } static DFBResult init_bridge ( CoreDFB *core, CoreSurfacePoolBridge *bridge, const SurfacePoolBridgeFuncs *funcs, void *ctx ); static void insert_bridge_local( CoreSurfacePoolBridge *bridge ); static void remove_bridge_local( CoreSurfacePoolBridgeID bridge_id ); /**********************************************************************************************************************/ DFBResult dfb_surface_pool_bridge_initialize( CoreDFB *core, const SurfacePoolBridgeFuncs *funcs, void *ctx, CoreSurfacePoolBridge **ret_bridge ) { DFBResult ret; CoreSurfacePoolBridge *bridge; FusionSHMPoolShared *shmpool; D_ASSERT( core != NULL ); D_ASSERT( bridge_funcs[bridge_count] == NULL ); D_ASSERT( funcs != NULL ); D_ASSERT( ret_bridge != NULL ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, funcs, ctx ); /* Check against bridge limit. */ if (bridge_count == MAX_SURFACE_POOL_BRIDGES) { D_ERROR( "Core/SurfacePoolBridge: Maximum number of bridges (%d) reached!\n", MAX_SURFACE_POOL_BRIDGES ); return DFB_LIMITEXCEEDED; } shmpool = dfb_core_shmpool( core ); /* Allocate bridge structure. */ bridge = SHCALLOC( shmpool, 1, sizeof(CoreSurfacePoolBridge) ); if (!bridge) return D_OOSHM(); /* Assign a bridge ID. */ bridge->bridge_id = bridge_count++; /* Remember shared memory pool. */ bridge->shmpool = shmpool; /* Set function table of the bridge. */ bridge_funcs[bridge->bridge_id] = funcs; /* Add to global bridge list. */ bridge_array[bridge->bridge_id] = bridge; D_MAGIC_SET( bridge, CoreSurfacePoolBridge ); ret = init_bridge( core, bridge, funcs, ctx ); if (ret) { bridge_funcs[bridge->bridge_id] = NULL; bridge_array[bridge->bridge_id] = NULL; bridge_count--; D_MAGIC_CLEAR( bridge ); SHFREE( shmpool, bridge ); return ret; } /* Insert new bridge into priority order. */ insert_bridge_local( bridge ); /* Return the new bridge. */ *ret_bridge = bridge; return DFB_OK; } DFBResult dfb_surface_pool_bridge_join( CoreDFB *core, CoreSurfacePoolBridge *bridge, const SurfacePoolBridgeFuncs *funcs, void *ctx ) { DFBResult ret; D_ASSERT( core != NULL ); D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); D_ASSERT( bridge->bridge_id == bridge_count ); D_ASSERT( bridge_funcs[bridge->bridge_id] == NULL ); D_ASSERT( funcs != NULL ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%u - %s], %p, %p )\n", __FUNCTION__, bridge, bridge->bridge_id, bridge->desc.name, funcs, ctx ); /* Enforce same order as initialization to be used during join. */ if (bridge->bridge_id != bridge_count) { D_ERROR( "Core/SurfacePoolBridge: Wrong order of joining bridges, got %u, should be %d!\n", bridge->bridge_id, bridge_count ); return DFB_BUG; } /* Allocate local bridge data. */ if (bridge->bridge_local_data_size && !(bridge_locals[bridge->bridge_id] = D_CALLOC( 1, bridge->bridge_local_data_size ))) return D_OOM(); /* Set function table of the bridge. */ bridge_funcs[bridge->bridge_id] = funcs; /* Add to global bridge list. */ bridge_array[bridge->bridge_id] = bridge; /* Adjust bridge count. */ if (bridge_count < bridge->bridge_id + 1) bridge_count = bridge->bridge_id + 1; funcs = get_funcs( bridge ); if (funcs->JoinPoolBridge) { ret = funcs->JoinPoolBridge( core, bridge, bridge->data, get_local(bridge), ctx ); if (ret) { D_DERROR( ret, "Core/SurfacePoolBridge: Joining '%s' failed!\n", bridge->desc.name ); if (bridge_locals[bridge->bridge_id]) { D_FREE( bridge_locals[bridge->bridge_id] ); bridge_locals[bridge->bridge_id] = NULL; } bridge_array[bridge->bridge_id] = NULL; bridge_funcs[bridge->bridge_id] = NULL; bridge_count--; return ret; } } /* Insert new bridge into priority order. */ insert_bridge_local( bridge ); return DFB_OK; } DFBResult dfb_surface_pool_bridge_destroy( CoreSurfacePoolBridge *bridge ) { const SurfacePoolBridgeFuncs *funcs; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge->bridge_id >= 0 ); D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); D_ASSERT( bridge_array[bridge->bridge_id] == bridge ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%u - %s] )\n", __FUNCTION__, bridge, bridge->bridge_id, bridge->desc.name ); funcs = get_funcs( bridge ); if (funcs->DestroyPoolBridge) funcs->DestroyPoolBridge( bridge, bridge->data, get_local(bridge) ); /* Free shared bridge data. */ if (bridge->data) SHFREE( bridge->shmpool, bridge->data ); /* Free local pool data and remove from lists. */ remove_bridge_local( bridge->bridge_id ); fusion_skirmish_destroy( &bridge->lock ); D_MAGIC_CLEAR( bridge ); SHFREE( bridge->shmpool, bridge ); return DFB_OK; } DFBResult dfb_surface_pool_bridge_leave( CoreSurfacePoolBridge *bridge ) { const SurfacePoolBridgeFuncs *funcs; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( bridge->bridge_id >= 0 ); D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); D_ASSERT( bridge_array[bridge->bridge_id] == bridge ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%u - %s] )\n", __FUNCTION__, bridge, bridge->bridge_id, bridge->desc.name ); funcs = get_funcs( bridge ); if (funcs->LeavePoolBridge) funcs->LeavePoolBridge( bridge, bridge->data, get_local(bridge) ); /* Free local pool data and remove from lists. */ remove_bridge_local( bridge->bridge_id ); return DFB_OK; } DFBResult dfb_surface_pool_bridges_enumerate( CoreSurfacePoolBridgeCallback callback, void *ctx ) { int i; D_ASSERT( callback != NULL ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, callback, ctx ); for (i = 0; i < bridge_count; i++) { CoreSurfacePoolBridge *bridge = bridge_array[i]; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); if (callback( bridge, ctx ) == DFENUM_CANCEL) break; } return DFB_OK; } static DFBResult allocate_transfer( CoreSurfacePoolBridge *bridge, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *from, CoreSurfaceAllocation *to, const DFBRectangle *rects, unsigned int num_rects, CoreSurfacePoolTransfer **ret_transfer ) { CoreSurfacePoolTransfer *transfer; unsigned int alloc_size; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); CORE_SURFACE_ALLOCATION_ASSERT( from ); CORE_SURFACE_ALLOCATION_ASSERT( to ); D_ASSERT( rects != NULL ); D_ASSERT( num_rects > 0 ); D_ASSERT( ret_transfer != NULL ); alloc_size = sizeof(CoreSurfacePoolTransfer) + num_rects * sizeof(DFBRectangle) + bridge->transfer_data_size; transfer = SHCALLOC( bridge->shmpool, 1, alloc_size ); if (!transfer) return D_OOSHM(); transfer->bridge = bridge; transfer->buffer = buffer; transfer->from = from; transfer->to = to; transfer->rects = (DFBRectangle*) (transfer + 1); if (bridge->transfer_data_size) transfer->data = transfer->rects + num_rects; transfer->num_rects = num_rects; direct_memcpy( transfer->rects, rects, num_rects * sizeof(DFBRectangle) ); D_MAGIC_SET( transfer, CoreSurfacePoolTransfer ); *ret_transfer = transfer; return DFB_OK; } static void deallocate_transfer( CoreSurfacePoolTransfer *transfer ) { CoreSurfacePoolBridge *bridge; D_MAGIC_ASSERT( transfer, CoreSurfacePoolTransfer ); D_MAGIC_ASSERT( transfer->bridge, CoreSurfacePoolBridge ); bridge = transfer->bridge; D_MAGIC_CLEAR( transfer ); SHFREE( bridge->shmpool, transfer ); } DFBResult dfb_surface_pool_bridges_transfer( CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *from, CoreSurfaceAllocation *to, const DFBRectangle *rects, unsigned int num_rects ) { DFBResult ret; int i; DFBRectangle rect; CoreSurfacePoolBridge *bridge = NULL; const SurfacePoolBridgeFuncs *funcs; CoreSurfacePoolTransfer *transfer = NULL; D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); CORE_SURFACE_ALLOCATION_ASSERT( from ); CORE_SURFACE_ALLOCATION_ASSERT( to ); D_ASSERT( rects != NULL || num_rects == 0 ); D_ASSERT( num_rects > 0 || rects == NULL ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %dx%d %s, %p -> %p, %u rects )\n", __FUNCTION__, buffer, buffer->config.size.w, buffer->config.size.h, dfb_pixelformat_name( buffer->surface->config.format ), from, to, num_rects ); if (!rects) { rect.x = rect.y = 0; rect.w = buffer->config.size.w; rect.h = buffer->config.size.h; rects = ▭ num_rects = 1; } for (i = 0; i < bridge_count; i++) { D_ASSERT( bridge_order[i] >= 0 ); D_ASSERT( bridge_order[i] < bridge_count ); bridge = bridge_array[bridge_order[i]]; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); funcs = get_funcs( bridge ); D_ASSERT( funcs->CheckTransfer != NULL ); ret = funcs->CheckTransfer( bridge, bridge->data, get_local(bridge), buffer, from, to ); if (ret) bridge = NULL; else break; } if (!bridge) return DFB_UNSUPPORTED; D_DEBUG_AT( Core_SurfPoolBridge, " -> using '%s'\n", bridge->desc.name ); ret = allocate_transfer( bridge, buffer, from, to, rects, num_rects, &transfer ); if (ret) return ret; D_ASSERT( funcs->StartTransfer != NULL ); D_DEBUG_AT( Core_SurfPoolBridge, " -> start...\n" ); #if defined(__GNUC__) && __GNUC__ >= 10 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" #endif ret = funcs->StartTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data ); #if defined __GNUC__ && __GNUC__ >= 10 #pragma GCC diagnostic pop #endif if (ret) { D_DERROR( ret, "Core/SurfacePoolBridge: Starting transfer via '%s' failed!\n", bridge->desc.name ); } else if (funcs->FinishTransfer) { D_DEBUG_AT( Core_SurfPoolBridge, " -> finish...\n" ); ret = funcs->FinishTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data ); if (ret) D_DERROR( ret, "Core/SurfacePoolBridge: Finishing transfer via '%s' failed!\n", bridge->desc.name ); } deallocate_transfer( transfer ); return ret; } /**********************************************************************************************************************/ static DFBResult init_bridge( CoreDFB *core, CoreSurfacePoolBridge *bridge, const SurfacePoolBridgeFuncs *funcs, void *ctx ) { DFBResult ret; D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); D_ASSERT( funcs != NULL ); D_ASSERT( funcs->InitPoolBridge != NULL ); D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, bridge, funcs ); if (funcs->PoolBridgeDataSize) bridge->bridge_data_size = funcs->PoolBridgeDataSize(); if (funcs->PoolBridgeLocalDataSize) bridge->bridge_local_data_size = funcs->PoolBridgeLocalDataSize(); if (funcs->PoolTransferDataSize) bridge->transfer_data_size = funcs->PoolTransferDataSize(); /* Allocate shared bridge data. */ if (bridge->bridge_data_size) { bridge->data = SHCALLOC( bridge->shmpool, 1, bridge->bridge_data_size ); if (!bridge->data) return D_OOSHM(); } /* Allocate local bridge data. */ if (bridge->bridge_local_data_size && !(bridge_locals[bridge->bridge_id] = D_CALLOC( 1, bridge->bridge_local_data_size ))) { SHFREE( bridge->shmpool, bridge->data ); return D_OOM(); } ret = funcs->InitPoolBridge( core, bridge, bridge->data, get_local(bridge), ctx, &bridge->desc ); if (ret) { D_DERROR( ret, "Core/SurfacePoolBridge: Initializing '%s' failed!\n", bridge->desc.name ); if (bridge_locals[bridge->bridge_id]) { D_FREE( bridge_locals[bridge->bridge_id] ); bridge_locals[bridge->bridge_id] = NULL; } if (bridge->data) { SHFREE( bridge->shmpool, bridge->data ); bridge->data = NULL; } return ret; } fusion_skirmish_init2( &bridge->lock, bridge->desc.name, dfb_core_world( core ), fusion_config->secure_fusion ); return DFB_OK; } static void insert_bridge_local( CoreSurfacePoolBridge *bridge ) { int i, n; for (i = 0; i < bridge_count - 1; i++) { D_ASSERT( bridge_order[i] >= 0 ); D_ASSERT( bridge_order[i] < bridge_count - 1 ); D_MAGIC_ASSERT( bridge_array[bridge_order[i]], CoreSurfacePoolBridge ); if (bridge_array[bridge_order[i]]->desc.priority < bridge->desc.priority) break; } for (n = bridge_count - 1; n > i; n--) { D_ASSERT( bridge_order[n-1] >= 0 ); D_ASSERT( bridge_order[n-1] < bridge_count - 1 ); D_MAGIC_ASSERT( bridge_array[bridge_order[n-1]], CoreSurfacePoolBridge ); bridge_order[n] = bridge_order[n-1]; } bridge_order[n] = bridge_count - 1; for (i = 0; i < bridge_count; i++) { D_DEBUG_AT( Core_SurfPoolBridge, " %c> [%d] %p [%u - %s] (%u), %p\n", (i == n) ? '=' : '-', i, bridge_array[bridge_order[i]], bridge_array[bridge_order[i]]->bridge_id, bridge_array[bridge_order[i]]->desc.name, bridge_array[bridge_order[i]]->desc.priority, bridge_funcs[bridge_order[i]] ); D_ASSERT( bridge_order[i] == bridge_array[bridge_order[i]]->bridge_id ); } } static void remove_bridge_local( CoreSurfacePoolBridgeID bridge_id ) { int i; /* Free local bridge data. */ if (bridge_locals[bridge_id]) { D_FREE( bridge_locals[bridge_id] ); bridge_locals[bridge_id] = NULL; } /* Erase entries of the bridge. */ bridge_array[bridge_id] = NULL; bridge_funcs[bridge_id] = NULL; while (bridge_count > 0 && !bridge_array[bridge_count-1]) { bridge_count--; for (i = 0; i < bridge_count; i++) { if (bridge_order[i] == bridge_count) { direct_memmove( &bridge_order[i], &bridge_order[i+1], sizeof(bridge_order[0]) * (bridge_count - i) ); break; } } } } ================================================ FILE: src/core/surface_pool_bridge.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SURFACE_POOL_BRIDGE_H__ #define __CORE__SURFACE_POOL_BRIDGE_H__ #include /**********************************************************************************************************************/ typedef enum { CSPBCAPS_NONE = 0x00000000, /* none of these */ CSPBCAPS_ALL = 0x00000000 /* all of these */ } CoreSurfacePoolBridgeCapabilities; #define DFB_SURFACE_POOL_BRIDGE_DESC_NAME_LENGTH 44 typedef struct { CoreSurfacePoolBridgeCapabilities caps; char name[DFB_SURFACE_POOL_BRIDGE_DESC_NAME_LENGTH]; CoreSurfacePoolPriority priority; } CoreSurfacePoolBridgeDescription; typedef struct { DirectLink link; int magic; CoreSurfacePoolBridge *bridge; CoreSurfaceBuffer *buffer; CoreSurfaceAllocation *from; CoreSurfaceAllocation *to; DFBRectangle *rects; unsigned int num_rects; void *data; } CoreSurfacePoolTransfer; typedef struct { int (*PoolBridgeDataSize) ( void ); int (*PoolBridgeLocalDataSize)( void ); int (*PoolTransferDataSize) ( void ); /* * Bridge init/destroy. */ DFBResult (*InitPoolBridge) ( CoreDFB *core, CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, void *ctx, CoreSurfacePoolBridgeDescription *ret_desc ); DFBResult (*JoinPoolBridge) ( CoreDFB *core, CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, void *ctx ); DFBResult (*DestroyPoolBridge) ( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local ); DFBResult (*LeavePoolBridge) ( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local ); /* * Probe. */ DFBResult (*CheckTransfer) ( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *from, CoreSurfaceAllocation *to ); /* * Transfer. */ DFBResult (*StartTransfer) ( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfacePoolTransfer *transfer, void *transfer_data ); DFBResult (*FinishTransfer) ( CoreSurfacePoolBridge *bridge, void *bridge_data, void *bridge_local, CoreSurfacePoolTransfer *transfer, void *transfer_data ); } SurfacePoolBridgeFuncs; struct __DFB_CoreSurfacePoolBridge { int magic; FusionSkirmish lock; CoreSurfacePoolBridgeID bridge_id; CoreSurfacePoolBridgeDescription desc; int bridge_data_size; int bridge_local_data_size; int transfer_data_size; void *data; FusionSHMPoolShared *shmpool; DirectLink *transfers; }; /**********************************************************************************************************************/ typedef DFBEnumerationResult (*CoreSurfacePoolBridgeCallback)( CoreSurfacePoolBridge *bridge, void *ctx ); /**********************************************************************************************************************/ DFBResult dfb_surface_pool_bridge_initialize( CoreDFB *core, const SurfacePoolBridgeFuncs *funcs, void *ctx, CoreSurfacePoolBridge **ret_bridge ); DFBResult dfb_surface_pool_bridge_join ( CoreDFB *core, CoreSurfacePoolBridge *pool, const SurfacePoolBridgeFuncs *funcs, void *ctx ); DFBResult dfb_surface_pool_bridge_destroy ( CoreSurfacePoolBridge *bridge ); DFBResult dfb_surface_pool_bridge_leave ( CoreSurfacePoolBridge *bridge ); DFBResult dfb_surface_pool_bridges_enumerate( CoreSurfacePoolBridgeCallback callback, void *ctx ); DFBResult dfb_surface_pool_bridges_transfer ( CoreSurfaceBuffer *buffer, CoreSurfaceAllocation *from, CoreSurfaceAllocation *to, const DFBRectangle *rects, unsigned int num_rects ); #endif ================================================ FILE: src/core/system.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( Core_System, "Core/System", "DirectFB Core System" ); DEFINE_MODULE_DIRECTORY( dfb_core_systems, "systems", DFB_CORE_SYSTEM_ABI_VERSION ); /**********************************************************************************************************************/ typedef struct { int magic; CoreSystemInfo system_info; } DFBSystemCoreShared; typedef struct { int magic; CoreDFB *core; DFBSystemCoreShared *shared; } DFBSystemCore; DFB_CORE_PART( system_core, SystemCore ); /**********************************************************************************************************************/ static CoreSystemInfo system_info; static DirectModuleEntry *system_module = NULL; static const CoreSystemFuncs *system_funcs = NULL; static void *system_data = NULL; static DFBResult dfb_system_core_initialize( CoreDFB *core, DFBSystemCore *data, DFBSystemCoreShared *shared ) { DFBResult ret; D_DEBUG_AT( Core_System, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; shared->system_info = system_info; /* Initialize system module. */ ret = system_funcs->Initialize( core, &system_data ); if (ret) return ret; D_MAGIC_SET( data, DFBSystemCore ); D_MAGIC_SET( shared, DFBSystemCoreShared ); return DFB_OK; } static DFBResult dfb_system_core_join( CoreDFB *core, DFBSystemCore *data, DFBSystemCoreShared *shared ) { DFBResult ret; D_DEBUG_AT( Core_System, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBSystemCoreShared ); data->core = core; data->shared = shared; if (strcmp( shared->system_info.name, system_info.name )) { D_ERROR( "Core/System: Running system '%s' doesn't match system '%s'!\n", shared->system_info.name, system_info.name ); return DFB_UNSUPPORTED; } if (shared->system_info.version.major != system_info.version.major || shared->system_info.version.minor != system_info.version.minor) { D_ERROR( "Core/System: Running system version '%d.%d' doesn't match version '%d.%d'!\n", shared->system_info.version.major, shared->system_info.version.minor, system_info.version.major, system_info.version.minor ); return DFB_UNSUPPORTED; } /* Join system module. */ ret = system_funcs->Join( core, &system_data ); if (ret) return ret; D_MAGIC_SET( data, DFBSystemCore ); return DFB_OK; } static DFBResult dfb_system_core_shutdown( DFBSystemCore *data, bool emergency ) { DFBResult ret; DFBSystemCoreShared *shared; D_UNUSED_P( shared ); D_DEBUG_AT( Core_System, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBSystemCore ); D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); shared = data->shared; /* Shutdown system module. */ ret = system_funcs->Shutdown( emergency ); /* Unload the module. */ direct_module_unref( system_module ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); system_data = NULL; system_funcs = NULL; system_module = NULL; return ret; } static DFBResult dfb_system_core_leave( DFBSystemCore *data, bool emergency ) { DFBResult ret; D_DEBUG_AT( Core_System, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBSystemCore ); D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); ret = system_funcs->Leave( emergency ); /* Unload the module. */ direct_module_unref( system_module ); D_MAGIC_CLEAR( data ); system_data = NULL; system_funcs = NULL; system_module = NULL; return ret; } static DFBResult dfb_system_core_suspend( DFBSystemCore *data ) { D_DEBUG_AT( Core_System, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBSystemCore ); D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); system_funcs->Suspend(); return DFB_OK; } static DFBResult dfb_system_core_resume( DFBSystemCore *data ) { D_DEBUG_AT( Core_System, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBSystemCore ); D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); system_funcs->Resume(); return DFB_OK; } /**********************************************************************************************************************/ DFBResult dfb_system_lookup() { DirectModuleEntry *module; D_DEBUG_AT( Core_System, "%p()\n", __FUNCTION__ ); direct_modules_explore_directory( &dfb_core_systems ); direct_list_foreach (module, dfb_core_systems.entries) { const CoreSystemFuncs *funcs; D_DEBUG_AT( Core_System, "module %p\n", module ); D_DEBUG_AT( Core_System, " name '%s'\n", module->name ); D_DEBUG_AT( Core_System, " refs %d\n", module->refs ); D_DEBUG_AT( Core_System, " loaded %d\n", module->loaded ); D_DEBUG_AT( Core_System, " disabled %d\n", module->disabled ); D_DEBUG_AT( Core_System, " dynamic %d\n", module->dynamic ); D_DEBUG_AT( Core_System, " file '%s'\n", module->file ); funcs = direct_module_ref( module ); if (!funcs) continue; if (!system_module || (!dfb_config->system || !strcasecmp( dfb_config->system, module->name ))) { if (system_module) direct_module_unref( system_module ); system_module = module; system_funcs = funcs; memset( &system_info, 0, sizeof(system_info) ); funcs->GetSystemInfo( &system_info ); } else direct_module_unref( module ); } if (!system_module) { D_ERROR( "Core/System: No system found!\n" ); return DFB_NOIMPL; } return DFB_OK; } CoreSystemCapabilities dfb_system_caps() { return system_info.caps; } void * dfb_system_data() { return system_data; } VideoMode * dfb_system_modes() { D_ASSERT( system_funcs != NULL ); return system_funcs->GetModes(); } VideoMode * dfb_system_current_mode() { D_ASSERT( system_funcs != NULL ); return system_funcs->GetCurrentMode(); } DFBResult dfb_system_thread_init() { D_ASSERT( system_funcs != NULL ); return system_funcs->ThreadInit(); } bool dfb_system_input_filter( CoreInputDevice *device, DFBInputEvent *event ) { D_ASSERT( system_funcs != NULL ); return system_funcs->InputFilter( device, event ); } volatile void * dfb_system_map_mmio( unsigned int offset, int length ) { D_ASSERT( system_funcs != NULL ); return system_funcs->MapMMIO( offset, length ); } void dfb_system_unmap_mmio( volatile void *addr, int length ) { D_ASSERT( system_funcs != NULL ); system_funcs->UnmapMMIO( addr, length ); } unsigned int dfb_system_get_accelerator() { D_ASSERT( system_funcs != NULL ); return system_funcs->GetAccelerator(); } unsigned long dfb_system_video_memory_physical( unsigned int offset ) { D_ASSERT( system_funcs != NULL ); return system_funcs->VideoMemoryPhysical( offset ); } void * dfb_system_video_memory_virtual( unsigned int offset ) { D_ASSERT( system_funcs != NULL ); return system_funcs->VideoMemoryVirtual( offset ); } unsigned int dfb_system_videoram_length() { D_ASSERT( system_funcs != NULL ); return system_funcs->VideoRamLength(); } void dfb_system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ) { int bus = -1, dev = -1, func = -1; D_ASSERT( system_funcs != NULL ); system_funcs->GetBusID( &bus, &dev, &func ); if (ret_bus) *ret_bus = bus; if (ret_dev) *ret_dev = dev; if (ret_func) *ret_func = func; } void dfb_system_get_deviceid( unsigned int *ret_vendor_id, unsigned int *ret_device_id ) { unsigned int vendor_id = 0, device_id = 0; D_ASSERT( system_funcs != NULL ); system_funcs->GetDeviceID( &vendor_id, &device_id ); if (ret_vendor_id) *ret_vendor_id = vendor_id; if (ret_device_id) *ret_device_id = device_id; } ================================================ FILE: src/core/system.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__SYSTEM_H__ #define __CORE__SYSTEM_H__ #include #include #include DECLARE_MODULE_DIRECTORY( dfb_core_systems ); /**********************************************************************************************************************/ #define DFB_CORE_SYSTEM_ABI_VERSION 10 #define DFB_CORE_SYSTEM_INFO_NAME_LENGTH 60 #define DFB_CORE_SYSTEM_INFO_VENDOR_LENGTH 80 #define DFB_CORE_SYSTEM_INFO_URL_LENGTH 120 #define DFB_CORE_SYSTEM_INFO_LICENSE_LENGTH 40 typedef struct { int major; /* major version */ int minor; /* minor version */ } CoreSystemVersion; typedef enum { CSCAPS_NONE = 0x00000000, /* None of these. */ CSCAPS_ACCELERATION = 0x00000001, /* HW acceleration supported, so probe graphics drivers. */ CSCAPS_PREFER_SHM = 0x00000002, /* Prefer shared memory surface pool over local memory pool. */ CSCAPS_SECURE_FUSION = 0x00000004, /* Fusion needs to be in secure fusion mode. */ CSCAPS_ALWAYS_INDIRECT = 0x00000008, /* All calls need to be indirect. */ CSCAPS_SYSMEM_EXTERNAL = 0x00000010, /* Make system memory surface pools have CSTF_EXTERNAL support. */ CSCAPS_NOTIFY_DISPLAY = 0x00000040, /* Call dfb_surface_notify_display2() when appropriate. */ CSCAPS_ALL = 0x0000005F /* All of these. */ } CoreSystemCapabilities; typedef struct { CoreSystemVersion version; CoreSystemCapabilities caps; char name[DFB_CORE_SYSTEM_INFO_NAME_LENGTH]; /* Name of system driver */ char vendor[DFB_CORE_SYSTEM_INFO_VENDOR_LENGTH]; /* Vendor (or author) of the driver */ char url[DFB_CORE_SYSTEM_INFO_URL_LENGTH]; /* URL for driver updates */ char license[DFB_CORE_SYSTEM_INFO_LICENSE_LENGTH]; /* License, e.g. 'LGPL' or 'proprietary' */ } CoreSystemInfo; typedef struct { void (*GetSystemInfo) ( CoreSystemInfo *info ); DFBResult (*Initialize) ( CoreDFB *core, void **data ); DFBResult (*Join) ( CoreDFB *core, void **data ); DFBResult (*Shutdown) ( bool emergency ); DFBResult (*Leave) ( bool emergency ); DFBResult (*Suspend) ( void ); DFBResult (*Resume) ( void ); VideoMode *(*GetModes) ( void ); VideoMode *(*GetCurrentMode) ( void ); /* * Called at the beginning of a new thread. */ DFBResult (*ThreadInit) ( void ); /* * Called upon incoming input events. * Return true to drop the event, e.g. after doing special handling of it. */ bool (*InputFilter) ( CoreInputDevice *device, DFBInputEvent *event ); /* * Graphics drivers call this function to get access to MMIO regions: * 'offset': offset from MMIO base (default offset is 0) * 'length': length of mapped region (-1 uses default length) * Returns the virtual address or NULL if mapping failed. */ volatile void *(*MapMMIO) ( unsigned int offset, int length ); /* * Graphics drivers call this function to unmap MMIO regions: * 'addr': virtual address of mapped region * 'length': length of mapped region (-1 uses default length) */ void (*UnmapMMIO) ( volatile void *addr, int length ); unsigned int (*GetAccelerator) ( void ); unsigned long (*VideoMemoryPhysical)( unsigned int offset ); void *(*VideoMemoryVirtual) ( unsigned int offset ); unsigned int (*VideoRamLength) ( void ); void (*GetBusID) ( int *ret_bus, int *ret_dev, int *ret_func ); void (*GetDeviceID) ( unsigned int *ret_vendor_id, unsigned int *ret_device_id ); } CoreSystemFuncs; /**********************************************************************************************************************/ DFBResult dfb_system_lookup ( void ); CoreSystemCapabilities dfb_system_caps ( void ); void *dfb_system_data ( void ); VideoMode *dfb_system_modes ( void ); VideoMode *dfb_system_current_mode ( void ); DFBResult dfb_system_thread_init ( void ); bool dfb_system_input_filter ( CoreInputDevice *device, DFBInputEvent *event ); volatile void *dfb_system_map_mmio ( unsigned int offset, int length ); void dfb_system_unmap_mmio ( volatile void *addr, int length ); unsigned int dfb_system_get_accelerator ( void ); unsigned long dfb_system_video_memory_physical( unsigned int offset ); void *dfb_system_video_memory_virtual ( unsigned int offset ); unsigned int dfb_system_videoram_length ( void ); void dfb_system_get_busid ( int *ret_bus, int *ret_dev, int *ret_func ); void dfb_system_get_deviceid ( unsigned int *ret_vendor_id, unsigned int *ret_device_id ); #endif ================================================ FILE: src/core/video_mode.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__VIDEO_MODE_H__ #define __CORE__VIDEO_MODE_H__ /**********************************************************************************************************************/ typedef struct _VideoMode { int xres; int yres; int bpp; int pixclock; int left_margin; int right_margin; int upper_margin; int lower_margin; int hsync_len; int vsync_len; int hsync_high; int vsync_high; int csync_high; int laced; int doubled; int sync_on_green; int external_sync; int broadcast; struct _VideoMode *next; } VideoMode; #endif ================================================ FILE: src/core/windows.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Windows, "Core/Windows", "DirectFB Core Windows" ); D_DEBUG_DOMAIN( Core_Windows_Events, "Core/Windows/Events", "DirectFB Core Windows Events" ); /**********************************************************************************************************************/ typedef struct { DirectLink link; CoreWindow *window; int x; int y; } BoundWindow; static const ReactionFunc dfb_window_globals[] = { NULL }; /**********************************************************************************************************************/ static void window_destructor( FusionObject *object, bool zombie, void *ctx ) { CoreWindow *window = (CoreWindow*) object; CoreWindowStack *stack = window->stack; D_ASSUME( window->stack != NULL ); D_DEBUG_AT( Core_Windows, "Destroying window %p (%4d,%4d-%4dx%4d%s)\n", window, DFB_RECTANGLE_VALS( &window->config.bounds ), zombie ? " ZOMBIE" : "" ); if (!stack) { /* Destroy the object. */ fusion_object_destroy( object ); return; } CoreWindow_Deinit_Dispatch( &window->call ); dfb_windowstack_lock( stack ); dfb_window_destroy( window ); if (window->cursor.surface) dfb_surface_unlink( &window->cursor.surface ); if (window->caps & DWCAPS_SUBWINDOW) { int index; CoreWindow *toplevel; toplevel = window->toplevel; D_ASSERT( toplevel != NULL ); index = fusion_vector_index_of( &toplevel->subwindows, window ); D_ASSERT( index >= 0 ); fusion_vector_remove( &toplevel->subwindows, index ); window->toplevel = NULL; } else { CoreWindow *sub; int i; fusion_vector_foreach (sub, i, window->subwindows) { sub->toplevel = NULL; } fusion_vector_destroy( &window->subwindows ); } dfb_windowstack_unlock( stack ); /* Unlink the primary region of the context. */ if (window->primary_region) dfb_layer_region_unlink( &window->primary_region ); D_MAGIC_CLEAR( window ); /* Destroy the object. */ fusion_object_destroy( object ); } FusionObjectPool * dfb_window_pool_create( const FusionWorld *world ) { FusionObjectPool *pool; pool = fusion_object_pool_create( "Window Pool", sizeof(CoreWindow), sizeof(DFBWindowEvent), window_destructor, NULL, world ); return pool; } /**********************************************************************************************************************/ DFBResult dfb_window_create_region( CoreWindow *window, CoreLayerContext *context, CoreSurface *window_surface, DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, DFBSurfaceCapabilities surface_caps, CoreLayerRegion **ret_region, CoreSurface **ret_surface ) { DFBResult ret; CoreLayerRegionConfig config; CoreLayerRegion *region; CoreSurface *surface = window_surface; CoreSurfaceConfig scon; D_ASSERT( window != NULL ); D_ASSERT( context != NULL ); D_ASSERT( ret_region != NULL ); D_ASSERT( ret_surface != NULL ); memset( &config, 0, sizeof(CoreLayerRegionConfig) ); config.width = window->config.bounds.w; config.height = window->config.bounds.h; config.format = format; config.colorspace = colorspace; config.options = context->config.options & DLOP_FLICKER_FILTERING; config.source = (DFBRectangle) { 0, 0, config.width, config.height }; config.dest = window->config.bounds; config.opacity = 0; config.alpha_ramp[0] = 0x00; config.alpha_ramp[1] = 0x55; config.alpha_ramp[2] = 0xaa; config.alpha_ramp[3] = 0xff; if (surface_caps & DSCAPS_DOUBLE) config.buffermode = DLBM_BACKVIDEO; else if (surface_caps & DSCAPS_TRIPLE) config.buffermode = DLBM_TRIPLE; else config.buffermode = DLBM_FRONTONLY; if (((context->config.options & DLOP_ALPHACHANNEL) || (window->config.options & DWOP_ALPHACHANNEL)) && DFB_PIXELFORMAT_HAS_ALPHA( format )) config.options |= DLOP_ALPHACHANNEL; config.options |= DLOP_OPACITY; config.surface_caps = surface_caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED); ret = dfb_layer_region_create( context, ®ion ); if (ret) return ret; region->config.keep_buffers = true; do { ret = dfb_layer_region_set_configuration( region, &config, CLRCF_ALL ); if (ret) { if (config.options & DLOP_OPACITY) config.options &= ~DLOP_OPACITY; else if (config.options & DLOP_ALPHACHANNEL) config.options = (config.options & ~DLOP_ALPHACHANNEL) | DLOP_OPACITY; else { D_DERROR( ret, "Core/Windows: Unable to set region configuration!\n" ); dfb_layer_region_unref( region ); return ret; } } } while (ret); if (!surface) { scon.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS; scon.size.w = config.width; scon.size.h = config.height; scon.format = format; scon.colorspace = colorspace; scon.caps = surface_caps | DSCAPS_VIDEOONLY; ret = dfb_surface_create( core_dfb, &scon, CSTF_SHARED | CSTF_LAYER, context->layer_id, NULL, &surface ); if (ret) { dfb_layer_region_unref( region ); return ret; } } ret = dfb_layer_region_set_surface( region, surface, false ); if (ret) { dfb_surface_unref( surface ); dfb_layer_region_unref( region ); return ret; } if (!window_surface) { ret = dfb_layer_region_enable( region ); if (ret) { dfb_surface_unref( surface ); dfb_layer_region_unref( region ); return ret; } } *ret_region = region; *ret_surface = surface; return DFB_OK; } static DFBResult init_subwindow( CoreWindow *window, CoreWindowStack *stack, DFBWindowID toplevel_id ) { DFBResult ret; CoreWindow *toplevel; /* Lookup top level window. */ ret = dfb_wm_window_lookup( stack, toplevel_id, &toplevel ); if (ret) return ret; /* Make sure chosen top level window is not a sub window. */ if (toplevel->caps & DWCAPS_SUBWINDOW) { D_ASSERT( toplevel->toplevel != NULL ); D_ASSERT( toplevel->toplevel_id != 0 ); return DFB_INVARG; } else { D_ASSERT( toplevel->toplevel == NULL ); D_ASSERT( toplevel->toplevel_id == 0 ); } /* Link top level window into sub window structure. */ window->toplevel = toplevel; if (ret) return ret; /* Add window to sub window list of top level window. */ ret = fusion_vector_add( &toplevel->subwindows, window ); if (ret) { dfb_window_unlink( &window->toplevel ); return ret; } return DFB_OK; } static ReactionResult window_surface_react( const void *msg_data, void *ctx ) { const DFBSurfaceEvent *evt = msg_data; CoreWindow *window = ctx; D_DEBUG_AT( Core_Windows, "%s( %p ) <- type %06x\n", __FUNCTION__, evt, evt->type ); D_DEBUG_AT( Core_Windows, " -> surface id %u\n", evt->surface_id ); if (evt->type == DSEVT_UPDATE) { D_DEBUG_AT( Core_Windows, " -> updated %4d,%4d-%4dx%4d (left)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update ) ); D_DEBUG_AT( Core_Windows, " -> updated %4d,%4d-%4dx%4d (right)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update_right ) ); D_DEBUG_AT( Core_Windows, " -> flip count %u\n", evt->flip_count ); D_DEBUG_AT( Core_Windows, " -> time stamp %lld\n", evt->time_stamp ); D_DEBUG_AT( Core_Windows, " -> window %p\n", window ); if (direct_log_domain_check( &Core_Windows )) { dfb_surface_lock( window->surface ); CoreSurfaceBuffer *buffer; D_UNUSED_P( buffer ); buffer = dfb_surface_get_buffer3( window->surface, DSBR_FRONT, DSSE_LEFT, evt->flip_count ); D_DEBUG_AT( Core_Windows, " -> buffer %p\n", buffer ); dfb_surface_unlock( window->surface ); } /* Lock the window stack. */ if (dfb_windowstack_lock( window->stack )) return RS_OK; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( window->stack ); return RS_OK; } window->surface_flip_count = evt->flip_count; if (!dfb_config->single_window || fusion_vector_size( &window->stack->visible_windows ) != 1) { D_DEBUG_AT( Core_Windows, " -> dispatching update to window manager\n" ); dfb_wm_update_window( window, &evt->update, &evt->update_right, DSFLIP_NONE ); } CoreSurfaceClient_FrameAck( window->surface_client, evt->flip_count ); /* Unlock the window stack. */ dfb_windowstack_unlock( window->stack ); } else if (evt->type == DSEVT_DESTROYED) return RS_REMOVE; return RS_OK; } DFBResult dfb_window_create( CoreWindowStack *stack, const DFBWindowDescription *desc, CoreWindow **ret_window ) { DFBResult ret; CoreSurface *surface; DFBWindowSurfacePolicy policy = DWSP_SYSTEMONLY; CoreLayer *layer; CoreLayerContext *context; CoreWindow *window; CardCapabilities card_caps; CoreWindowConfig config; DFBWindowCapabilities caps; DFBSurfaceCapabilities surface_caps; DFBSurfacePixelFormat pixelformat; DFBSurfaceColorSpace colorspace; DFBWindowID toplevel_id; D_ASSERT( stack != NULL ); D_ASSERT( stack->context != NULL ); D_ASSERT( desc != NULL ); D_ASSERT( desc->width > 0 ); D_ASSERT( desc->height > 0 ); D_ASSERT( ret_window != NULL ); D_DEBUG_AT( Core_Windows, "%s( %p )\n", __FUNCTION__, stack ); if (desc->width > 4096 || desc->height > 4096) { D_DEBUG_AT( Core_Windows, " -> limit exceeded (%dx%d / 4096x4096)\n", desc->width, desc->height ); return DFB_LIMITEXCEEDED; } /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) { D_DEBUG_AT( Core_Windows, " -> window stack lock failed!\n" ); return DFB_FUSION; } context = stack->context; layer = dfb_layer_at( context->layer_id ); D_DEBUG_AT( Core_Windows, " -> caps 0x%08x\n", desc->caps ); caps = desc->caps; pixelformat = desc->pixelformat; colorspace = desc->colorspace; surface_caps = desc->surface_caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_DOUBLE | DSCAPS_STATIC_ALLOC | DSCAPS_PREMULTIPLIED | DSCAPS_TRIPLE | DSCAPS_SYSTEMONLY | DSCAPS_VIDEOONLY | DSCAPS_DEPTH | DSCAPS_GL ); toplevel_id = (desc->flags & DWDESC_TOPLEVEL_ID) ? desc->toplevel_id : 0; if (toplevel_id != 0) caps |= DWCAPS_SUBWINDOW; else caps &= ~DWCAPS_SUBWINDOW; if (caps & DWCAPS_STEREO) surface_caps |= DSCAPS_STEREO; if (!dfb_config->translucent_windows) { caps &= ~DWCAPS_ALPHACHANNEL; } /* Choose pixel format. */ if (caps & DWCAPS_ALPHACHANNEL) { if (pixelformat == DSPF_UNKNOWN) { if (context->config.flags & DLCONF_PIXELFORMAT) pixelformat = context->config.pixelformat; if (!DFB_PIXELFORMAT_HAS_ALPHA( pixelformat )) pixelformat = DSPF_ARGB; } else if (!DFB_PIXELFORMAT_HAS_ALPHA( pixelformat )) { D_DEBUG_AT( Core_Windows, " -> pixelformat '%s' has no alpha!\n", dfb_pixelformat_name( pixelformat ) ); dfb_windowstack_unlock( stack ); return DFB_INVARG; } } else if (pixelformat == DSPF_UNKNOWN) { if (context->config.flags & DLCONF_PIXELFORMAT) pixelformat = context->config.pixelformat; else { D_WARN( "layer config has no pixel format, using RGB16" ); pixelformat = DSPF_RGB16; } } /* Set the color space. */ if (colorspace == DSCS_UNKNOWN) { colorspace = DFB_COLORSPACE_DEFAULT( pixelformat ); } else if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, pixelformat )) { D_DEBUG_AT( Core_Windows, " -> colorspace '%s' is not compatible with pixelformat '%s'!\n", dfb_colorspace_name(colorspace), dfb_pixelformat_name( pixelformat ) ); dfb_windowstack_unlock( stack ); return DFB_INVARG; } /* Choose window surface policy. */ if ((surface_caps & DSCAPS_VIDEOONLY) || (context->config.buffermode == DLBM_WINDOWS)) { policy = DWSP_VIDEOONLY; } else if (!(surface_caps & DSCAPS_SYSTEMONLY) && context->config.buffermode != DLBM_BACKSYSTEM) { /* Use the explicitly specified policy. */ if (dfb_config->window_policy != -1) { policy = dfb_config->window_policy; } else { /* Examine the hardware capabilities. */ dfb_gfxcard_get_capabilities( &card_caps ); if (card_caps.accel & DFXL_BLIT) { if ((card_caps.blitting & DSBLIT_BLEND_ALPHACHANNEL) || !(caps & DWCAPS_ALPHACHANNEL)) policy = DWSP_VIDEOHIGH; } } } dfb_surface_caps_apply_policy( policy, &surface_caps ); if (caps & DWCAPS_DOUBLEBUFFER) { if (!(surface_caps & DSCAPS_TRIPLE)) surface_caps |= DSCAPS_DOUBLE; } memset( &config, 0, sizeof(CoreWindowConfig) ); config.bounds.x = desc->posx; config.bounds.y = desc->posy; config.bounds.w = desc->width; config.bounds.h = desc->height; config.stacking = (desc->flags & DWDESC_STACKING) ? desc->stacking : DWSC_MIDDLE; config.events = DWET_ALL & ~DWET_UPDATE; /* Auto enable blending for ARGB only, not indexed. */ if ((caps & DWCAPS_ALPHACHANNEL) && DFB_PIXELFORMAT_HAS_ALPHA( pixelformat ) && !DFB_PIXELFORMAT_IS_INDEXED( pixelformat )) config.options |= DWOP_ALPHACHANNEL; /* Override automatic settings. */ if (desc->flags & DWDESC_OPTIONS) config.options = desc->options; /* Create the window object. */ window = dfb_core_create_window( layer->core ); if (!window) { D_DEBUG_AT( Core_Windows, " -> core window create failed!\n" ); dfb_windowstack_unlock( stack ); return DFB_FUSION; } window->id = ++stack->id_pool; window->caps = caps | DWCAPS_NOFOCUS; window->requested_caps = caps; window->stack = stack; window->config = config; window->config.association = (desc->flags & DWDESC_PARENT) ? desc->parent_id : 0; window->config.cursor_flags = DWCF_INVISIBLE; window->toplevel_id = toplevel_id; window->policy = policy; if (desc->flags & DWDESC_RESOURCE_ID) window->resource_id = desc->resource_id; D_MAGIC_SET( window, CoreWindow ); ret = dfb_wm_preconfigure_window( stack, window ); if (ret) { D_DEBUG_AT( Core_Windows, " -> window preconfigure failed!\n" ); D_MAGIC_CLEAR( window ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } /* Window manager may have changed values. */ config = window->config; caps = window->caps; /* Initialize sub window. */ if (caps & DWCAPS_SUBWINDOW) { ret = init_subwindow( window, stack, toplevel_id ); if (ret) { D_DEBUG_AT( Core_Windows, " -> sub window init failed!\n" ); D_MAGIC_CLEAR( window ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } } else { /* Initialize top level window. */ fusion_vector_init( &window->subwindows, 3, stack->shmpool ); /* In case window manager forbids sub window request, clear the toplevel window ID. */ window->toplevel_id = 0; } if (dfb_config->warn.flags & DCWF_CREATE_WINDOW) D_WARN( "create-window %4dx%4d %6s, caps 0x%08x, surface-caps 0x%08x, ID %u", window->config.bounds.w, window->config.bounds.h, dfb_pixelformat_name( pixelformat ), window->caps, surface_caps, window->id ); /* Create the window's surface using the layer's palette if possible. */ if (!(caps & (DWCAPS_INPUTONLY | DWCAPS_COLOR))) { if (context->config.buffermode == DLBM_WINDOWS) { CoreLayerRegion *region = NULL; /* Create a region for the window. */ ret = dfb_window_create_region( window, context, NULL, pixelformat, colorspace, surface_caps, ®ion, &surface ); if (ret) { D_DEBUG_AT( Core_Windows, " -> region create failed!\n" ); D_MAGIC_CLEAR( window ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } /* Link the region into the window structure. */ dfb_layer_region_link( &window->region, region ); dfb_layer_region_unref( region ); /* Link the surface into the window structure. */ dfb_surface_link( &window->surface, surface ); dfb_surface_unref( surface ); } else { CoreLayerRegion *region; /* Get the primary region of the layer context. */ ret = dfb_layer_context_get_primary_region( context, true, ®ion ); if (ret) { D_DEBUG_AT( Core_Windows, " -> primary region get failed!\n" ); D_MAGIC_CLEAR( window ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } /* Link the primary region into the window structure. */ dfb_layer_region_link( &window->primary_region, region ); dfb_layer_region_unref( region ); D_DEBUG_AT( Core_Windows, " -> %dx%d %s %s\n", window->config.bounds.w, window->config.bounds.h, dfb_pixelformat_name( pixelformat ), (policy == DWSP_VIDEOONLY) ? "VIDEOONLY" : (policy == DWSP_SYSTEMONLY) ? "SYSTEMONLY" : "AUTO VIDEO" ); /* Give the window manager a chance to provide its own surface. */ if (!window->surface) { /* Create the surface for the window. */ ret = dfb_surface_create_simple( layer->core, config.bounds.w, config.bounds.h, pixelformat, colorspace, surface_caps, CSTF_SHARED | CSTF_WINDOW, desc->flags & DWDESC_RESOURCE_ID ? desc->resource_id : window->id, region->surface ? region->surface->palette : NULL, &surface ); if (ret) { D_DEBUG_AT( Core_Windows, " -> surface create failed!\n" ); D_DERROR( ret, "Core/Windows: Failed to create window surface!\n" ); D_MAGIC_CLEAR( window ); dfb_layer_region_unlink( &window->primary_region ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } /* Link the surface into the window structure. */ dfb_surface_link( &window->surface, surface ); dfb_surface_unref( surface ); } /* Create the surface client. */ ret = CoreSurface_CreateClient( window->surface, &window->surface_client ); if (ret) { D_WARN( "failed to create surface client" ); return ret; } /* Attach the surface event listener. */ dfb_surface_attach_channel( window->surface, CSCH_EVENT, window_surface_react, window, &window->surface_event_reaction ); } } else D_DEBUG_AT( Core_Windows, " -> %dx%d => INPUTONLY\n", window->config.bounds.w, window->config.bounds.h ); D_DEBUG_AT( Core_Windows, " -> %p\n", window ); /* Pass the new window to the window manager. */ ret = dfb_wm_add_window( stack, window ); if (ret) { D_DEBUG_AT( Core_Windows, " -> window add failed!\n" ); D_DERROR( ret, "Core/Windows: Failed to add window to manager!\n" ); D_MAGIC_CLEAR( window ); if (window->surface) dfb_surface_unlink( &window->surface ); if (window->primary_region) dfb_layer_region_unlink( &window->primary_region ); if (window->region) dfb_layer_region_unlink( &window->region ); fusion_object_destroy( &window->object ); dfb_windowstack_unlock( stack ); return ret; } /* Indicate that initialization is complete. */ D_FLAGS_SET( window->flags, CWF_INITIALIZED ); CoreWindow_Init_Dispatch( layer->core, window, &window->call ); /* Activate the object. */ fusion_object_activate( &window->object ); fusion_reactor_direct( window->object.reactor, true ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); /* Return the new window. */ *ret_window = window; D_DEBUG_AT( Core_Windows, " -> %p\n", window ); return DFB_OK;; } void dfb_window_destroy( CoreWindow *window ) { int i; DFBWindowEvent evt; CoreWindowStack *stack; BoundWindow *bound, *next; CoreWindow *subwindow; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( DFB_WINDOW_INITIALIZED( window ) ); D_ASSUME( window->stack != NULL ); D_DEBUG_AT( Core_Windows, "%s( %p ) <- %4d,%4d-%4dx%4d\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); stack = window->stack; if (!stack) return; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return; /* Destroy sub windows first. */ fusion_vector_foreach_reverse (subwindow, i, window->subwindows) { D_ASSERT( subwindow != NULL ); D_ASSERT( DFB_WINDOW_INITIALIZED( subwindow ) ); dfb_window_destroy( subwindow ); } /* Avoid multiple destructions. */ if (DFB_WINDOW_DESTROYED( window )) { D_DEBUG_AT( Core_Windows, " -> %p already destroyed\n", window ); dfb_windowstack_unlock( stack ); return; } /* Unbind bound windows. */ direct_list_foreach_safe (bound, next, window->bound_windows) { direct_list_remove( &window->bound_windows, &bound->link ); bound->window->boundto = NULL; SHFREE( stack->shmpool, bound ); } /* Unbind this window. */ if (window->boundto) dfb_window_unbind( window->boundto, window ); /* Make sure the window is no longer visible. */ dfb_window_set_opacity( window, 0 ); /* Stop managing the window. */ dfb_wm_remove_window( stack, window ); /* Indicate destruction. */ D_FLAGS_SET( window->flags, CWF_DESTROYED ); /* Hardware allocated. */ if (window->region) { /* Disable region (removing it from hardware). */ dfb_layer_region_disable( window->region ); /* Unlink from structure. */ dfb_layer_region_unlink( &window->region ); } /* Unlink the window's surface. */ if (window->surface) { dfb_surface_client_unref( window->surface_client ); /* Detach the surface event listener. */ dfb_surface_detach( window->surface, &window->surface_event_reaction ); dfb_surface_destroy_buffers( window->surface ); dfb_surface_unlink( &window->surface ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); /* Notify listeners. */ evt.type = DWET_DESTROYED; dfb_window_post_event( window, &evt ); } DFBResult dfb_window_change_stacking( CoreWindow *window, DFBWindowStackingClass stacking ) { DFBResult ret; CoreWindowStack *stack; CoreLayerContext *context; CoreWindowConfig config; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); D_ASSERT( window->stack->context != NULL ); stack = window->stack; context = stack->context; if (!(dfb_config->layers[context->layer_id].stacking & (1 << stacking))) { D_ERROR( "Core/Windows: Cannot change the stacking class!\n" ); return DFB_INVARG; } /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.stacking = stacking; /* Let the window manager do its work. */ ret = dfb_wm_set_window_config( window, &config, DWCONF_STACKING ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_type_hint( CoreWindow *window, DFBWindowTypeHint type_hint ) { DFBResult ret; CoreWindowStack *stack; CoreWindowConfig config; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.type_hint = type_hint; /* Let the window manager do its work. */ ret = dfb_wm_set_window_config( window, &config, DWCONF_TYPE_HINT ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_change_hint_flags( CoreWindow *window, DFBWindowHintFlags clear, DFBWindowHintFlags set ) { DFBResult ret; CoreWindowStack *stack; CoreWindowConfig config; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.hint_flags = (window->config.hint_flags & ~clear) | set; /* Let the window manager do its work. */ ret = dfb_wm_set_window_config( window, &config, DWCONF_HINT_FLAGS ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_raise( CoreWindow *window ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, window, 1 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_lower( CoreWindow *window ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, window, -1 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_raisetotop( CoreWindow *window ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, NULL, 1 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_lowertobottom( CoreWindow *window ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, NULL, 0 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_putatop( CoreWindow *window, CoreWindow *lower ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, lower, 1 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_putbelow( CoreWindow *window, CoreWindow *upper ) { DFBResult ret; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( window->stack != NULL ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Let the window manager do its work. */ ret = dfb_wm_restack_window( window, upper, -1 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_config( CoreWindow *window, const CoreWindowConfig *config, DFBWindowConfigFlags flags ) { DFBResult ret; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } ret = dfb_wm_set_window_config( window, config, flags ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_cursor_shape( CoreWindow *window, CoreSurface *shape, int hot_x, int hot_y ) { DFBResult ret; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } window->cursor.hot_x = hot_x; window->cursor.hot_y = hot_y; if (window->cursor.surface) dfb_surface_unlink( &window->cursor.surface ); if (shape) { ret = dfb_surface_link( &window->cursor.surface, shape ); if (ret == DFB_OK) { if (window->flags & CWF_FOCUSED) dfb_windowstack_cursor_set_shape( stack, shape, hot_x, hot_y ); } } else ret = DFB_OK; /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } static DFBResult move_window( CoreWindow *window, int x, int y ) { DFBResult ret; CoreWindowConfig config; BoundWindow *bound; D_MAGIC_ASSERT( window, CoreWindow ); config.bounds.x = x; config.bounds.y = y; ret = dfb_wm_set_window_config( window, &config, DWCONF_POSITION ); if (ret) return ret; direct_list_foreach (bound, window->bound_windows) { move_window( bound->window, window->config.bounds.x + bound->x, window->config.bounds.y + bound->y ); } return DFB_OK; } DFBResult dfb_window_move( CoreWindow *window, int x, int y, bool relative ) { DFBResult ret; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (window->boundto) { dfb_windowstack_unlock( stack ); return DFB_UNSUPPORTED; } if (relative) { x += window->config.bounds.x; y += window->config.bounds.y; } if (x == window->config.bounds.x && y == window->config.bounds.y) { dfb_windowstack_unlock( stack ); return DFB_OK; } ret = move_window( window, x, y ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_bounds( CoreWindow *window, int x, int y, int width, int height ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; int old_x; int old_y; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } old_x = window->config.bounds.x; old_y = window->config.bounds.y; if (window->boundto) { if (old_x != x || old_y != y) { dfb_windowstack_unlock( stack ); return DFB_UNSUPPORTED; } } config.bounds.x = x; config.bounds.y = y; config.bounds.w = width; config.bounds.h = height; if (window->config.bounds.x == x && window->config.bounds.y == y && window->config.bounds.w == width && window->config.bounds.h == height) { dfb_windowstack_unlock( stack ); return DFB_OK; } ret = dfb_wm_set_window_config( window, &config, DWCONF_POSITION | DWCONF_SIZE ); if (ret) { dfb_windowstack_unlock( stack ); return ret; } if (old_x != x || old_y != y) { BoundWindow *bound; direct_list_foreach (bound, window->bound_windows) { move_window( bound->window, window->config.bounds.x + bound->x, window->config.bounds.y + bound->y ); } } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_window_resize( CoreWindow *window, int width, int height ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( width > 0 ); D_ASSERT( height > 0 ); if (width > 4096 || height > 4096) return DFB_LIMITEXCEEDED; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (window->config.bounds.w == width && window->config.bounds.h == height) { dfb_windowstack_unlock( stack ); return DFB_OK; } config.bounds.w = width; config.bounds.h = height; ret = dfb_wm_set_window_config( window, &config, DWCONF_SIZE ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_bind( CoreWindow *window, CoreWindow *source, int x, int y ) { DFBResult ret; CoreWindowStack *stack = window->stack; BoundWindow *bound; D_MAGIC_ASSERT( window, CoreWindow ); if (window == source) return DFB_UNSUPPORTED; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (DFB_WINDOW_DESTROYED( source )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } bound = SHCALLOC( stack->shmpool, 1, sizeof(BoundWindow) ); if (!bound) { dfb_windowstack_unlock( stack ); return DFB_NOSHAREDMEMORY; } if (source->boundto) dfb_window_unbind( source->boundto, source ); ret = move_window( source, window->config.bounds.x + x, window->config.bounds.y + y ); if (ret) { SHFREE( stack->shmpool, bound ); dfb_windowstack_unlock( stack ); return ret; } bound->window = source; bound->x = x; bound->y = y; direct_list_append( &window->bound_windows, &bound->link ); source->boundto = window; dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_window_unbind( CoreWindow *window, CoreWindow *source ) { CoreWindowStack *stack = window->stack; BoundWindow *bound; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (DFB_WINDOW_DESTROYED( source )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (source->boundto != window) { dfb_windowstack_unlock( stack ); return DFB_UNSUPPORTED; } direct_list_foreach (bound, window->bound_windows) { if (bound->window == source) { direct_list_remove( &window->bound_windows, &bound->link ); bound->window->boundto = NULL; SHFREE( stack->shmpool, bound ); break; } } if (!bound) D_BUG( "window not found" ); dfb_windowstack_unlock( stack ); return bound ? DFB_OK : DFB_ITEMNOTFOUND; } DFBResult dfb_window_set_color( CoreWindow *window, DFBColor color ) { DFBResult ret; DFBColor cc; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } cc = window->config.color; if ((cc.a == color.a) && (cc.r == color.r) && (cc.g == color.g) && (cc.b == color.b)) { dfb_windowstack_unlock( stack ); return DFB_OK; } config.color = color; ret = dfb_wm_set_window_config( window, &config, DWCONF_COLOR ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_colorkey( CoreWindow *window, u32 color_key ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (window->config.color_key == color_key) { dfb_windowstack_unlock( stack ); return DFB_OK; } config.color_key = color_key; ret = dfb_wm_set_window_config( window, &config, DWCONF_COLOR_KEY ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_opacity( CoreWindow *window, u8 opacity ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } if (window->config.opacity == opacity) { dfb_windowstack_unlock( stack ); return DFB_OK; } config.opacity = opacity; ret = dfb_wm_set_window_config( window, &config, DWCONF_OPACITY ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_change_options( CoreWindow *window, DFBWindowOptions disable, DFBWindowOptions enable ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSUME( disable | enable ); if (!disable && !enable) return DFB_OK; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.options = (window->config.options & ~disable) | enable; ret = dfb_wm_set_window_config( window, &config, DWCONF_OPTIONS ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_opaque( CoreWindow *window, const DFBRegion *region ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); DFB_REGION_ASSERT_IF( region ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.opaque.x1 = 0; config.opaque.y1 = 0; config.opaque.x2 = window->config.bounds.w - 1; config.opaque.y2 = window->config.bounds.h - 1; if (region && !dfb_region_region_intersect( &config.opaque, region )) ret = DFB_INVAREA; else ret = dfb_wm_set_window_config( window, &config, DWCONF_OPAQUE ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_change_events( CoreWindow *window, DFBWindowEventType disable, DFBWindowEventType enable ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSUME( disable | enable ); if (!disable && !enable) return DFB_OK; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.events = (window->config.events & ~disable) | enable; ret = dfb_wm_set_window_config( window, &config, DWCONF_EVENTS ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_key_selection( CoreWindow *window, DFBWindowKeySelection selection, const DFBInputDeviceKeySymbol *keys, unsigned int num_keys ) { DFBResult ret; CoreWindowConfig config; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( selection == DWKS_ALL || selection == DWKS_NONE || selection == DWKS_LIST ); D_ASSERT( keys != NULL || selection != DWKS_LIST ); D_ASSERT( num_keys > 0 || selection != DWKS_LIST ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } config.key_selection = selection; config.keys = (DFBInputDeviceKeySymbol*) keys; config.num_keys = num_keys; ret = dfb_wm_set_window_config( window, &config, DWCONF_KEY_SELECTION ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_change_grab( CoreWindow *window, CoreWMGrabTarget target, bool grab ) { DFBResult ret; CoreWMGrab wmgrab; CoreWindowStack *stack; D_MAGIC_ASSERT( window, CoreWindow ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } wmgrab.target = target; if (grab) ret = dfb_wm_grab( window, &wmgrab ); else ret = dfb_wm_ungrab( window, &wmgrab ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_grab_key( CoreWindow *window, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ) { DFBResult ret; CoreWMGrab grab; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } grab.target = CWMGT_KEY; grab.symbol = symbol; grab.modifiers = modifiers; ret = dfb_wm_grab( window, &grab ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_ungrab_key( CoreWindow *window, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ) { DFBResult ret; CoreWMGrab grab; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } grab.target = CWMGT_KEY; grab.symbol = symbol; grab.modifiers = modifiers; ret = dfb_wm_ungrab( window, &grab ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } static bool core_window_filter( CoreWindow *window, const DFBWindowEvent *event ) { D_MAGIC_ASSERT( window, CoreWindow ); switch (event->type) { case DWET_GOTFOCUS: D_FLAGS_SET( window->flags, CWF_FOCUSED ); break; case DWET_LOSTFOCUS: D_FLAGS_CLEAR( window->flags, CWF_FOCUSED ); break; case DWET_ENTER: D_FLAGS_SET( window->flags, CWF_ENTERED ); break; case DWET_LEAVE: D_FLAGS_CLEAR( window->flags, CWF_ENTERED ); break; default: break; } return false; } void dfb_window_post_event( CoreWindow *window, DFBWindowEvent *event ) { D_MAGIC_ASSERT( window, CoreWindow ); D_ASSERT( event != NULL ); D_ASSUME( !DFB_WINDOW_DESTROYED( window ) || event->type == DWET_DESTROYED ); switch (event->type) { case DWET_BUTTONDOWN: case DWET_BUTTONUP: D_DEBUG_AT( Core_Windows_Events, "%s( %p [%u] )\n", __FUNCTION__, window, window->object.id ); D_DEBUG_AT( Core_Windows_Events, " -> TYPE 0x%08x\n", event->type ); D_DEBUG_AT( Core_Windows_Events, " -> BUTTON%s\n", event->type == DWET_BUTTONDOWN ? "DOWN" : "UP" ); D_DEBUG_AT( Core_Windows_Events, " => button %u\n", event->button ); D_DEBUG_AT( Core_Windows_Events, " => x, y %d,%d\n", event->x, event->y ); D_DEBUG_AT( Core_Windows_Events, " => cx, cy %d,%d\n", event->cx, event->cy ); break; default: break; } if (!(event->type & window->config.events)) return; long long timestamp_us = direct_clock_get_abs_micros(); event->clazz = DFEC_WINDOW; event->window_id = window->id; event->timestamp.tv_sec = timestamp_us / 1000000; event->timestamp.tv_usec = timestamp_us % 1000000; if (!core_window_filter( window, event )) dfb_window_dispatch( window, event, dfb_window_globals ); } DFBResult dfb_window_send_configuration( CoreWindow *window ) { DFBWindowEvent event; D_MAGIC_ASSERT( window, CoreWindow ); D_ASSUME( !DFB_WINDOW_DESTROYED( window ) ); event.type = DWET_POSITION_SIZE; event.x = window->config.bounds.x; event.y = window->config.bounds.y; event.w = window->config.bounds.w; event.h = window->config.bounds.h; dfb_window_post_event( window, &event ); return DFB_OK; } DFBResult dfb_window_request_focus( CoreWindow *window ) { DFBResult ret; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } ret = dfb_wm_request_focus( window ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_window_set_rotation( CoreWindow *window, int rotation ) { DFBResult ret; CoreWindowStack *stack = window->stack; D_MAGIC_ASSERT( window, CoreWindow ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); stack = window->stack; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Never call WM after destroying the window. */ if (DFB_WINDOW_DESTROYED( window )) { dfb_windowstack_unlock( stack ); return DFB_DESTROYED; } /* Do nothing if the rotation didn't change. */ if (window->config.rotation != rotation) { CoreWindowConfig config; switch (rotation) { case 0: case 90: case 180: case 270: config.rotation = rotation; dfb_wm_set_window_config( window, &config, DWCONF_ROTATION ); break; default: ret = DFB_UNSUPPORTED; } } else ret = DFB_OK; /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } ================================================ FILE: src/core/windows.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__WINDOWS_H__ #define __CORE__WINDOWS_H__ #include #include #include /**********************************************************************************************************************/ typedef enum { CWF_NONE = 0x00000000, CWF_INITIALIZED = 0x00000001, CWF_FOCUSED = 0x00000002, CWF_ENTERED = 0x00000004, CWF_DESTROYED = 0x00000008, CWF_INSERTED = 0x00000010, CWF_ALL = 0x0000001F } CoreWindowFlags; #define DFB_WINDOW_INITIALIZED(w) ((w)->flags & CWF_INITIALIZED) #define DFB_WINDOW_FOCUSED(w) ((w)->flags & CWF_FOCUSED) #define DFB_WINDOW_ENTERED(w) ((w)->flags & CWF_ENTERED) #define DFB_WINDOW_DESTROYED(w) ((w)->flags & CWF_DESTROYED) #define DFB_WINDOW_INSERTED(w) ((w)->flags & CWF_INSERTED) struct __DFB_CoreWindowConfig { DFBRectangle bounds; int opacity; DFBWindowStackingClass stacking; DFBWindowOptions options; DFBWindowEventType events; DFBColor color; u32 color_key; DFBRegion opaque; int z; DFBWindowKeySelection key_selection; DFBInputDeviceKeySymbol *keys; unsigned int num_keys; DFBWindowGeometry src_geometry; DFBWindowGeometry dst_geometry; int rotation; DFBWindowID association; unsigned long application_id; DFBWindowCursorFlags cursor_flags; DFBDimension cursor_resolution; DFBWindowTypeHint type_hint; DFBWindowHintFlags hint_flags; }; struct __DFB_CoreWindow { FusionObject object; int magic; DFBWindowID id; /* window id */ CoreWindowFlags flags; /* state flags */ DFBWindowCapabilities caps; /* window capabilities, to enable blending etc. */ CoreWindowConfig config; /* current window configuration. */ CoreSurface *surface; /* backing store surface */ CoreWindowStack *stack; /* window stack the window belongs */ CoreLayerRegion *primary_region; /* default region of context */ CoreLayerRegion *region; /* hardware allocated window */ void *window_data; /* private data of window manager */ DirectLink *bound_windows; /* list of bound windows */ CoreWindow *boundto; /* window to which this window is bound (window binding) */ DFBWindowID toplevel_id; /* toplevel window id, in case of a sub window */ CoreWindow *toplevel; /* top level window */ FusionVector subwindows; /* list of sub windows (only valid for top level windows) */ CoreWindow *subfocus; /* which of the sub windows has the focus */ unsigned long resource_id; /* resource id */ FusionCall call; /* dispatch */ struct { int hot_x; /* x position of cursor hot spot */ int hot_y; /* y position of cursor hot spot */ CoreSurface *surface; /* cursor shape surface */ } cursor; DFBWindowCapabilities requested_caps; /* original caps from application upon window creation */ CoreSurfaceClient *surface_client; /* surface client */ Reaction surface_event_reaction; /* surface event reaction for CSCH_EVENT */ u32 surface_flip_count; /* surface flip count */ DFBWindowSurfacePolicy policy; /* window surface swapping policy */ }; /**********************************************************************************************************************/ #define TRANSLUCENT_WINDOW(w) ((w)->config.opacity < 0xff || \ (w)->config.options & (DWOP_ALPHACHANNEL | DWOP_COLORKEYING)) #define VISIBLE_WINDOW(w) (!((w)->caps & DWCAPS_INPUTONLY) && \ (w)->config.opacity > 0 && !DFB_WINDOW_DESTROYED((w))) /**********************************************************************************************************************/ /* * Creates a pool of window objects. */ FusionObjectPool *dfb_window_pool_create ( const FusionWorld *world ); /* * Generates dfb_window_ref(), dfb_window_attach() etc. */ FUSION_OBJECT_METHODS( CoreWindow, dfb_window ) /**********************************************************************************************************************/ /* * Create a region and configure it optionally using the passed window_surface. */ DFBResult dfb_window_create_region ( CoreWindow *window, CoreLayerContext *context, CoreSurface *window_surface, DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, DFBSurfaceCapabilities surface_caps, CoreLayerRegion **ret_region, CoreSurface **ret_surface ); /* * Create a window on a given stack. */ DFBResult dfb_window_create ( CoreWindowStack *stack, const DFBWindowDescription *desc, CoreWindow **ret_window ); /* * Deinitialize a window and remove it from the window stack. */ void dfb_window_destroy ( CoreWindow *window ); /* * Change stacking class. */ DFBResult dfb_window_change_stacking ( CoreWindow *window, DFBWindowStackingClass stacking ); /* * Set window type hint. */ DFBResult dfb_window_set_type_hint ( CoreWindow *window, DFBWindowTypeHint type_hint ); /* * Change window hint flags. */ DFBResult dfb_window_change_hint_flags ( CoreWindow *window, DFBWindowHintFlags clear, DFBWindowHintFlags set ); /* * Move a window up one step in window stack. */ DFBResult dfb_window_raise ( CoreWindow *window ); /* * Move a window down one step in window stack. */ DFBResult dfb_window_lower ( CoreWindow *window ); /* * Make a window the first (topmost) window in the window stack. */ DFBResult dfb_window_raisetotop ( CoreWindow *window ); /* * Make a window the last (downmost) window in the window stack. */ DFBResult dfb_window_lowertobottom ( CoreWindow *window ); /* * Stack a window on top of another one. */ DFBResult dfb_window_putatop ( CoreWindow *window, CoreWindow *lower ); /* * Stack a window below another one. */ DFBResult dfb_window_putbelow ( CoreWindow *window, CoreWindow *upper ); /* * Change window configuration. */ DFBResult dfb_window_set_config ( CoreWindow *window, const CoreWindowConfig *config, DFBWindowConfigFlags flags ); /* * Change window cursor. */ DFBResult dfb_window_set_cursor_shape ( CoreWindow *window, CoreSurface *shape, int hot_x, int hot_y ); /* * Move a window relative to its current position. */ DFBResult dfb_window_move ( CoreWindow *window, int x, int y, bool relative ); /* * Set window position and size. */ DFBResult dfb_window_set_bounds ( CoreWindow *window, int x, int y, int width, int height ); /* * Resize a window. */ DFBResult dfb_window_resize ( CoreWindow *window, int width, int height ); /* * Bind a window to this window. */ DFBResult dfb_window_bind ( CoreWindow *window, CoreWindow *source, int x, int y ); /* * Unbind a window from this window. */ DFBResult dfb_window_unbind ( CoreWindow *window, CoreWindow *source ); /* * Set window color. */ DFBResult dfb_window_set_color ( CoreWindow *window, DFBColor color ); /* * Set window color key. */ DFBResult dfb_window_set_colorkey ( CoreWindow *window, u32 color_key ); /* * Set window global alpha factor. */ DFBResult dfb_window_set_opacity ( CoreWindow *window, u8 opacity ); /* * Set window options. */ DFBResult dfb_window_change_options ( CoreWindow *window, DFBWindowOptions disable, DFBWindowOptions enable ); /* * Disable alpha channel blending for one region of a window. */ DFBResult dfb_window_set_opaque ( CoreWindow *window, const DFBRegion *region ); /* * Manipulate the window event mask. */ DFBResult dfb_window_change_events ( CoreWindow *window, DFBWindowEventType disable, DFBWindowEventType enable ); /* * Select a mode for filtering keys on a focused window. */ DFBResult dfb_window_set_key_selection ( CoreWindow *window, DFBWindowKeySelection selection, const DFBInputDeviceKeySymbol *keys, unsigned int num_keys ); /* * Enable/disable a grabbing target of a window. */ DFBResult dfb_window_change_grab ( CoreWindow *window, CoreWMGrabTarget target, bool grab ); /* * Grab a specific key for this window. */ DFBResult dfb_window_grab_key ( CoreWindow *window, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ); /* * Ungrab a specific key for this window. */ DFBResult dfb_window_ungrab_key ( CoreWindow *window, DFBInputDeviceKeySymbol symbol, DFBInputDeviceModifierMask modifiers ); /* * Post an event. */ void dfb_window_post_event ( CoreWindow *window, DFBWindowEvent *event ); /* * Post a DWET_POSITION_SIZE event to request configuration. */ DFBResult dfb_window_send_configuration( CoreWindow *window ); /* * Request a window to gain focus. */ DFBResult dfb_window_request_focus ( CoreWindow *window ); /* * Set window rotation. */ DFBResult dfb_window_set_rotation ( CoreWindow *window, int rotation ); /**********************************************************************************************************************/ static __inline__ void dfb_surface_caps_apply_policy( DFBWindowSurfacePolicy policy, DFBSurfaceCapabilities *caps ) { switch (policy) { case DWSP_SYSTEMONLY: *caps = (DFBSurfaceCapabilities) ((*caps & ~DSCAPS_VIDEOONLY) | DSCAPS_SYSTEMONLY); break; case DWSP_VIDEOONLY: *caps = (DFBSurfaceCapabilities) ((*caps & ~DSCAPS_SYSTEMONLY) | DSCAPS_VIDEOONLY); break; default: *caps = (DFBSurfaceCapabilities) (*caps & ~(DSCAPS_SYSTEMONLY | DSCAPS_VIDEOONLY)); break; } } #endif ================================================ FILE: src/core/windowstack.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_WindowStack, "Core/WindowStack", "DirectFB Core WindowStack" ); /**********************************************************************************************************************/ typedef struct { DirectLink link; void *ctx; } Stack_Container; typedef struct { DirectLink link; DFBInputDeviceID id; Reaction reaction; } StackDevice; static DirectLink *stack_containers = NULL; static DirectMutex stack_containers_lock = DIRECT_MUTEX_INITIALIZER(); static void stack_containers_add( CoreWindowStack *stack ) { Stack_Container *container; D_DEBUG_AT( Core_WindowStack, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &stack_containers_lock ); container = D_CALLOC( 1, sizeof(Stack_Container) ); if (!container) { D_OOM(); } container->ctx = stack; direct_list_append( &stack_containers, &container->link ); direct_mutex_unlock( &stack_containers_lock ); } static void stack_containers_remove( CoreWindowStack *stack ) { Stack_Container *container, *next; D_DEBUG_AT( Core_WindowStack, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &stack_containers_lock ); direct_list_foreach_safe (container, next, stack_containers) { if (stack == container->ctx) { direct_list_remove( &stack_containers, &container->link ); D_FREE( container ); } } direct_mutex_unlock( &stack_containers_lock ); } static DFBEnumerationResult stack_attach_device( CoreInputDevice *device, void *ctx ) { StackDevice *dev; CoreWindowStack *stack = ctx; D_MAGIC_ASSERT( stack, CoreWindowStack ); dev = SHCALLOC( stack->shmpool, 1, sizeof(StackDevice) ); if (!dev) { D_ERROR( "Core/WindowStack: Could not allocate "_ZU" bytes!\n", sizeof(StackDevice) ); return DFENUM_CANCEL; } dev->id = dfb_input_device_id( device ); direct_list_prepend( &stack->devices, &dev->link ); dfb_input_attach( device, _dfb_windowstack_inputdevice_listener, ctx, &dev->reaction ); return DFENUM_OK; } void stack_containers_attach_device( CoreInputDevice *device ) { Stack_Container *stack_container; D_DEBUG_AT( Core_WindowStack, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &stack_containers_lock ); direct_list_foreach (stack_container, stack_containers) { stack_attach_device( device, stack_container->ctx ); } direct_mutex_unlock( &stack_containers_lock ); } static DFBEnumerationResult stack_detach_device( CoreInputDevice *device, void *ctx ) { DirectLink *link; CoreWindowStack *stack = ctx; D_ASSERT( stack != NULL ); D_ASSERT( device != NULL ); link = stack->devices; while (link) { DirectLink *next = link->next; StackDevice *dev = (StackDevice*) link; if (dfb_input_device_id( device ) == dev->id) { direct_list_remove( &stack->devices, &dev->link ); dfb_input_detach( device, &dev->reaction ); SHFREE( stack->shmpool, dev ); return DFENUM_OK; } link = next; } return DFENUM_CANCEL; } void stack_containers_detach_device( CoreInputDevice *device ) { Stack_Container *stack_container; D_DEBUG_AT( Core_WindowStack, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &stack_containers_lock ); direct_list_foreach (stack_container, stack_containers) { stack_detach_device( device, stack_container->ctx ); } direct_mutex_unlock( &stack_containers_lock ); } /**********************************************************************************************************************/ CoreWindowStack* dfb_windowstack_create( CoreLayerContext *context ) { DFBResult ret; CoreWindowStack *stack; CoreLayer *layer; DFBWindowSurfacePolicy policy = DWSP_SYSTEMONLY; D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, context ); D_ASSERT( context != NULL ); layer = dfb_layer_at( context->layer_id ); /* Allocate window stack data (completely shared). */ stack = SHCALLOC( context->shmpool, 1, sizeof(CoreWindowStack) ); if (!stack) { D_OOSHM(); return NULL; } stack->shmpool = context->shmpool; /* Store context which we belong to. */ stack->context = context; /* Set default acceleration. */ stack->cursor.numerator = 2; stack->cursor.denominator = 1; stack->cursor.threshold = 4; /* Choose cursor surface policy. */ if (context->config.buffermode != DLBM_BACKSYSTEM) { CardCapabilities card_caps; /* Use the explicitly specified policy. */ if (dfb_config->window_policy != -1) policy = dfb_config->window_policy; else { /* Examine the hardware capabilities. */ dfb_gfxcard_get_capabilities( &card_caps ); if (card_caps.accel & DFXL_BLIT && card_caps.blitting & DSBLIT_BLEND_ALPHACHANNEL) policy = DWSP_VIDEOHIGH; } } stack->cursor.policy = policy; /* Set default background mode. */ stack->bg.mode = DLBM_DONTCARE; stack->bg.color_index = -1; D_MAGIC_SET( stack, CoreWindowStack ); /* Initialize window manager */ ret = dfb_wm_init_stack( stack ); if (ret) { D_MAGIC_CLEAR( stack ); SHFREE( context->shmpool, stack ); return NULL; } if (dfb_config->single_window) fusion_vector_init( &stack->visible_windows, 23, stack->shmpool ); /* Attach to all input devices. */ dfb_input_enumerate_devices( stack_attach_device, stack, DICAPS_ALL ); stack_containers_add( stack ); CoreWindowStack_Init_Dispatch( layer->core, stack, &stack->call ); D_DEBUG_AT( Core_WindowStack, " -> %p\n", stack ); return stack; } void dfb_windowstack_detach_devices( CoreWindowStack *stack ) { DirectLink *link; D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); D_MAGIC_ASSERT( stack, CoreWindowStack ); stack_containers_remove( stack ); link = stack->devices; while (link) { DirectLink *next = link->next; StackDevice *device = (StackDevice*) link; dfb_input_detach( dfb_input_device_at( device->id ), &device->reaction ); SHFREE( stack->shmpool, device ); link = next; } } void dfb_windowstack_destroy( CoreWindowStack *stack ) { D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Unlink cursor surface. */ if (stack->cursor.surface) dfb_surface_unlink( &stack->cursor.surface ); /* Shutdown window manager. */ if (stack->flags & CWSF_INITIALIZED) dfb_wm_close_stack( stack ); /* Detach listener from background surface and unlink it. */ if (stack->bg.image) { dfb_surface_detach_global( stack->bg.image, &stack->bg.image_reaction ); dfb_surface_unlink( &stack->bg.image ); } CoreWindowStack_Deinit_Dispatch( &stack->call ); /* Deallocate shared stack data. */ if (stack->stack_data) { SHFREE( stack->shmpool, stack->stack_data ); stack->stack_data = NULL; } D_MAGIC_CLEAR( stack ); /* Free stack data. */ SHFREE( stack->shmpool, stack ); } void dfb_windowstack_resize( CoreWindowStack *stack, int width, int height, int rotation ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d, %d )\n", __FUNCTION__, stack, width, height, rotation ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return; /* Store the width and height of the stack. */ stack->width = width; stack->height = height; /* Store the rotation of the stack. */ stack->rotation = rotation; switch (stack->rotation) { default: D_BUG( "invalid rotation %d", stack->rotation ); case 0: stack->rotated_blit = DSBLIT_NOFX; stack->rotated_width = stack->width; stack->rotated_height = stack->height; break; case 90: stack->rotated_blit = DSBLIT_ROTATE90; stack->rotated_width = stack->height; stack->rotated_height = stack->width; break; case 180: stack->rotated_blit = DSBLIT_ROTATE180; stack->rotated_width = stack->width; stack->rotated_height = stack->height; break; case 270: stack->rotated_blit = DSBLIT_ROTATE270; stack->rotated_width = stack->height; stack->rotated_height = stack->width; break; } /* Setup new cursor clipping region. */ stack->cursor.region.x1 = 0; stack->cursor.region.y1 = 0; stack->cursor.region.x2 = width - 1; stack->cursor.region.y2 = height - 1; /* Notify the window manager. */ dfb_wm_resize_stack( stack, width, height ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); } DirectResult dfb_windowstack_lock( CoreWindowStack *stack ) { D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->context != NULL ); return dfb_layer_context_lock( stack->context ); } DirectResult dfb_windowstack_unlock( CoreWindowStack *stack ) { D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->context != NULL ); return dfb_layer_context_unlock( stack->context ); } DFBResult dfb_windowstack_repaint_all( CoreWindowStack *stack ) { DFBResult ret; DFBRegion region; D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; region.x1 = 0; region.y1 = 0; region.x2 = stack->rotated_width - 1; region.y2 = stack->rotated_height - 1; ret = dfb_wm_update_stack( stack, ®ion, 0 ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return ret; } DFBResult dfb_windowstack_set_background_mode ( CoreWindowStack *stack, DFBDisplayLayerBackgroundMode mode ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %u )\n", __FUNCTION__, stack, mode ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Nothing to do if mode is the same. */ if (mode != stack->bg.mode) { /* A surface is required for DLBM_IMAGE and DLBM_TILE modes. */ if ((mode == DLBM_IMAGE || mode == DLBM_TILE) && !stack->bg.image) { dfb_windowstack_unlock( stack ); return DFB_MISSINGIMAGE; } /* Set new mode. */ stack->bg.mode = mode; /* Force an update of the window stack. */ if (mode != DLBM_DONTCARE) dfb_windowstack_repaint_all( stack ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_set_background_image( CoreWindowStack *stack, CoreSurface *image ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, stack, image ); D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( image != NULL ); if (!(image->type & CSTF_SHARED)) return DFB_INVARG; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Nothing to do if image is the same. */ if (stack->bg.image != image) { /* Detach listener from old surface and unlink it. */ if (stack->bg.image) { dfb_surface_detach_global( stack->bg.image, &stack->bg.image_reaction ); dfb_surface_unlink( &stack->bg.image ); } /* Link surface object. */ dfb_surface_link( &stack->bg.image, image ); /* Attach listener to new surface. */ dfb_surface_attach_global( image, DFB_WINDOWSTACK_BACKGROUND_IMAGE_LISTENER, stack, &stack->bg.image_reaction ); } /* Force an update of the window stack. */ if (stack->bg.mode == DLBM_IMAGE || stack->bg.mode == DLBM_TILE) dfb_windowstack_repaint_all( stack ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_set_background_color( CoreWindowStack *stack, const DFBColor *color ) { D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( color != NULL ); D_DEBUG_AT( Core_WindowStack, " -> 0x%02x%02x%02x%02x\n", color->a, color->r, color->g, color->b ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Nothing to do if color is the same. */ if (!DFB_COLOR_EQUAL( stack->bg.color, *color )) { /* Set new color. */ stack->bg.color = *color; /* Force an update of the window stack. */ if (stack->bg.mode == DLBM_COLOR) dfb_windowstack_repaint_all( stack ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_set_background_color_index( CoreWindowStack *stack, int index ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %d )\n", __FUNCTION__, stack, index ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; /* Nothing to do if color is the same. */ if (stack->bg.color_index != index) { /* Set new color index. */ stack->bg.color_index = index; /* Force an update of the window stack. */ if (stack->bg.mode == DLBM_COLOR) dfb_windowstack_repaint_all( stack ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } static DFBResult create_cursor_surface( CoreWindowStack *stack, int width, int height ) { DFBResult ret; CoreSurface *surface; CoreLayer *layer; CoreLayerContext *context; DFBSurfaceCapabilities surface_caps = DSCAPS_PREMULTIPLIED; D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d )\n", __FUNCTION__, stack, width, height ); D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->context != NULL ); D_ASSERT( stack->cursor.surface == NULL ); context = stack->context; layer = dfb_layer_at( context->layer_id ); D_ASSERT( layer != NULL ); stack->cursor.x = stack->width / 2; stack->cursor.y = stack->height / 2; stack->cursor.hot.x = 0; stack->cursor.hot.y = 0; stack->cursor.size.w = width; stack->cursor.size.h = height; stack->cursor.opacity = 0xff; if (context->config.buffermode == DLBM_WINDOWS) D_WARN( "cursor not yet visible with DLBM_WINDOWS" ); if (dfb_config->cursor_videoonly) surface_caps |= DSCAPS_VIDEOONLY; dfb_surface_caps_apply_policy( stack->cursor.policy, &surface_caps ); /* Create the cursor surface. */ ret = dfb_surface_create_simple( layer->core, width, height, DSPF_ARGB, DSCS_RGB, surface_caps, CSTF_SHARED | CSTF_CURSOR, dfb_config->cursor_resource_id, NULL, &surface ); if (ret) { D_ERROR( "Core/WindowStack: Failed to create surface for software cursor!\n" ); return ret; } dfb_surface_globalize( surface ); stack->cursor.surface = surface; return DFB_OK; } static DFBResult load_default_cursor( CoreWindowStack *stack ) { DFBResult ret; int i, j; CoreSurfaceBufferLock lock; void *data; u32 *tmp_data; D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); D_MAGIC_ASSERT( stack, CoreWindowStack ); if (!stack->cursor.surface) { /* Create the cursor surface for the default shape. */ ret = create_cursor_surface( stack, 40, 40 ); if (ret) return ret; } else { stack->cursor.hot.x = 0; stack->cursor.hot.y = 0; stack->cursor.size.w = 40; stack->cursor.size.h = 40; } /* Lock the cursor surface. */ ret = dfb_surface_lock_buffer( stack->cursor.surface, DSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock ); if (ret) { D_ERROR( "Core/WindowStack: cannot lock the cursor surface!\n" ); return ret; } data = lock.addr; /* Fill the cursor surface. */ direct_memcpy( data, cursor_data, 40 * lock.pitch ); for (i = 0; i < 40; i++) { #ifdef WORDS_BIGENDIAN j = MIN( 40, lock.pitch / 4 ); tmp_data = data; while (j--) { *tmp_data = (*tmp_data & 0xff000000) >> 24 | (*tmp_data & 0x00ff0000) >> 8 | (*tmp_data & 0x0000ff00) << 8 | (*tmp_data & 0x000000ff) << 24; ++tmp_data; } #endif j = MIN( 40, lock.pitch / 4 ); tmp_data = data; while (j--) { u32 s = *tmp_data; u32 a = (s >> 24) + 1; *tmp_data = ((((s & 0x00ff00ff) * a) >> 8) & 0x00ff00ff) | ((((s & 0x0000ff00) * a) >> 8) & 0x0000ff00) | (s & 0xff000000); ++tmp_data; } data += lock.pitch; } dfb_surface_unlock_buffer( stack->cursor.surface, &lock ); return ret; } DFBResult dfb_windowstack_cursor_enable( CoreWindowStack *stack, bool enable ) { DFBResult ret; D_DEBUG_AT( Core_WindowStack, "%s( %p, %s )\n", __FUNCTION__, stack, enable ? "enable" : "disable" ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; stack->cursor.set = true; if (dfb_config->no_cursor || stack->cursor.enabled == enable) { dfb_windowstack_unlock( stack ); return DFB_OK; } if (enable && !stack->cursor.surface) { ret = load_default_cursor( stack ); if (ret) { dfb_windowstack_unlock( stack ); return ret; } } /* Keep state. */ stack->cursor.enabled = enable; /* Notify WM. */ dfb_wm_update_cursor( stack, enable ? CCUF_ENABLE : CCUF_DISABLE ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_cursor_set_opacity( CoreWindowStack *stack, u8 opacity ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, 0x%02x )\n", __FUNCTION__, stack, opacity ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; if (stack->cursor.opacity != opacity) { /* Set new opacity. */ stack->cursor.opacity = opacity; /* Notify WM. */ if (stack->cursor.enabled) dfb_wm_update_cursor( stack, CCUF_OPACITY ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_cursor_set_shape( CoreWindowStack *stack, CoreSurface *shape, int hot_x, int hot_y ) { DFBResult ret; CoreCursorUpdateFlags flags = CCUF_SHAPE; D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, %d, %d )\n", __FUNCTION__, stack, shape, hot_x, hot_y ); D_MAGIC_ASSERT( stack, CoreWindowStack ); if (dfb_config->no_cursor) return DFB_OK; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; if (!shape) { if (stack->cursor.surface && (stack->cursor.size.w != 40 || stack->cursor.size.h != 40)) { /* Resize the cursor surface to the size of the default shape. */ dfb_surface_reformat( stack->cursor.surface, 40, 40, DSPF_ARGB ); /* Notify about new size. */ flags |= CCUF_SIZE; } } else if (!stack->cursor.surface) { D_DEBUG_AT( Core_WindowStack, " -> size %dx%d\n", shape->config.size.w, shape->config.size.h ); D_ASSUME( !stack->cursor.enabled ); /* Create the cursor surface for the shape. */ ret = create_cursor_surface( stack, shape->config.size.w, shape->config.size.h ); if (ret) { dfb_windowstack_unlock( stack ); return ret; } } else if (stack->cursor.size.w != shape->config.size.w || stack->cursor.size.h != shape->config.size.h) { D_DEBUG_AT( Core_WindowStack, " -> new size %dx%d\n", shape->config.size.w, shape->config.size.h ); /* Resize the cursor surface to the size of shape. */ dfb_surface_reformat( stack->cursor.surface, shape->config.size.w, shape->config.size.h, DSPF_ARGB ); stack->cursor.size.w = shape->config.size.w; stack->cursor.size.h = shape->config.size.h; /* Notify about new size. */ flags |= CCUF_SIZE; } if (stack->cursor.hot.x != hot_x || stack->cursor.hot.y != hot_y) { stack->cursor.hot.x = hot_x; stack->cursor.hot.y = hot_y; /* Notify about new position. */ flags |= CCUF_POSITION; } if (!shape) { /* Create the cursor surface if necessary and fill it with the default shape. */ load_default_cursor( stack ); } else { /* Copy the content of the new shape. */ dfb_gfx_copy_stereo( shape, DSSE_LEFT, stack->cursor.surface, DSSE_LEFT, NULL, 0, 0, false ); stack->cursor.surface->config.caps = (stack->cursor.surface->config.caps & ~DSCAPS_PREMULTIPLIED) | (shape->config.caps & DSCAPS_PREMULTIPLIED); } /* Notify WM. */ if (stack->cursor.enabled) dfb_wm_update_cursor( stack, flags ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_cursor_warp( CoreWindowStack *stack, int x, int y ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d )\n", __FUNCTION__, stack, x, y ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; if (x < 0) x = 0; else if (x > stack->width - 1) x = stack->width - 1; if (y < 0) y = 0; else if (y > stack->height - 1) y = stack->height - 1; if (stack->cursor.x != x || stack->cursor.y != y) { stack->cursor.x = x; stack->cursor.y = y; /* Notify WM. */ if (stack->cursor.enabled) dfb_wm_update_cursor( stack, CCUF_POSITION ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_cursor_set_acceleration( CoreWindowStack *stack, int numerator, int denominator, int threshold ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d, %d )\n", __FUNCTION__, stack, numerator, denominator, threshold ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; stack->cursor.numerator = numerator; stack->cursor.denominator = denominator; stack->cursor.threshold = threshold; /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } DFBResult dfb_windowstack_get_cursor_position( CoreWindowStack *stack, int *ret_x, int *ret_y ) { D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, %p )\n", __FUNCTION__, stack, ret_x, ret_y ); D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSUME( ret_x != NULL || ret_y != NULL ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return DFB_FUSION; if (ret_x) *ret_x = stack->cursor.x; if (ret_y) *ret_y = stack->cursor.y; /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); return DFB_OK; } static void WindowStack_Input_Flush( CoreWindowStack *stack ) { if (!stack->motion_x.type && !stack->motion_y.type) return; /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) return; /* Call the window manager to dispatch the event. */ if (dfb_layer_context_active( stack->context )) { if (stack->motion_x.type && stack->motion_y.type) stack->motion_x.flags |= DIEF_FOLLOW; if (stack->motion_x.type) dfb_wm_process_input( stack, &stack->motion_x ); if (stack->motion_y.type) dfb_wm_process_input( stack, &stack->motion_y ); } /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); stack->motion_x.type = DIET_UNKNOWN; stack->motion_y.type = DIET_UNKNOWN; stack->motion_cleanup = NULL; stack->motion_ts = 0; } static void WindowStack_Input_AddAbsolute( CoreWindowStack *stack, DFBInputEvent *target, const DFBInputEvent *event ) { *target = *event; target->flags &= ~DIEF_FOLLOW; } static void WindowStack_Input_AddRelative( CoreWindowStack *stack, DFBInputEvent *target, const DFBInputEvent *event ) { int axisrel = 0; if (target->type) axisrel = target->axisrel; *target = *event; target->axisrel += axisrel; target->flags &= ~DIEF_FOLLOW; } static void WindowStack_Input_Add( CoreWindowStack *stack, const DFBInputEvent *event ) { long long ts = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); if ((stack->motion_x.type && stack->motion_x.device_id != event->device_id) || (stack->motion_y.type && stack->motion_y.device_id != event->device_id) || ts - stack->motion_ts > 10000) WindowStack_Input_Flush( stack ); if (!stack->motion_ts) stack->motion_ts = ts; switch (event->type) { case DIET_AXISMOTION: switch (event->axis) { case DIAI_X: if (event->flags & DIEF_AXISABS) WindowStack_Input_AddAbsolute( stack, &stack->motion_x, event ); else WindowStack_Input_AddRelative( stack, &stack->motion_x, event ); break; case DIAI_Y: if (event->flags & DIEF_AXISABS) WindowStack_Input_AddAbsolute( stack, &stack->motion_y, event ); else WindowStack_Input_AddRelative( stack, &stack->motion_y, event ); break; default: break; } break; default: break; } } static void WindowStack_Input_DispatchCleanup( void *ctx ) { CoreWindowStack *stack = ctx; WindowStack_Input_Flush( stack ); /* Decrease the layer context's reference count. */ dfb_layer_context_unref( stack->context ); } ReactionResult _dfb_windowstack_inputdevice_listener( const void *msg_data, void *ctx ) { DFBResult ret; const DFBInputEvent *event = msg_data; CoreWindowStack *stack = ctx; int num = 0; /* Dynamically increase/decrease the ref to the layer context when using the layer context. This will prevent the layer context from being destroyed when it is being used. */ D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, event, stack ); D_ASSERT( event != NULL ); D_MAGIC_ASSERT( stack, CoreWindowStack ); /* Make sure the layer context's reference count is non-zero. If it is, return early and indicate that the listener should be removed. In this scenario, this prevents the object_reference_watcher() from being called more than once triggered by the reference count changing from 1 to 0 again. */ if (dfb_layer_context_ref_stat( stack->context, &num ) || num == 0) return RS_REMOVE; /* Increase the layer context's reference count. */ if (dfb_layer_context_ref( stack->context )) return RS_REMOVE; switch (event->type) { case DIET_AXISMOTION: switch (event->axis) { case DIAI_X: case DIAI_Y: WindowStack_Input_Add( stack, event ); if (!stack->motion_cleanup) { ret = fusion_dispatch_cleanup_add( dfb_core_world( core_dfb ), WindowStack_Input_DispatchCleanup, stack, &stack->motion_cleanup ); if (ret) { D_DERROR( ret, "Core/WindowStack: Failed to add dispatch cleanup!\n" ); dfb_layer_context_unref( stack->context ); return RS_OK; } } else dfb_layer_context_unref( stack->context ); return RS_OK; default: break; } break; default: break; } WindowStack_Input_Flush( stack ); /* Lock the window stack. */ if (dfb_windowstack_lock( stack )) { dfb_layer_context_unref( stack->context ); return RS_REMOVE; } /* Call the window manager to dispatch the event. */ if (dfb_layer_context_active( stack->context )) dfb_wm_process_input( stack, event ); /* Unlock the window stack. */ dfb_windowstack_unlock( stack ); /* Decrease the layer context's reference count. */ if (!stack->motion_cleanup) dfb_layer_context_unref( stack->context ); return RS_OK; } ReactionResult _dfb_windowstack_background_image_listener( const void *msg_data, void *ctx ) { const CoreSurfaceNotification *notification = msg_data; CoreWindowStack *stack = ctx; D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, notification, stack ); D_ASSERT( notification != NULL ); D_MAGIC_ASSERT( stack, CoreWindowStack ); if (notification->flags & CSNF_DESTROY) { D_ERROR( "Core/WindowStack: Surface for background vanished!\n" ); return RS_REMOVE; } if (notification->flags & (CSNF_FLIP | CSNF_SIZEFORMAT)) dfb_windowstack_repaint_all( stack ); return RS_OK; } ================================================ FILE: src/core/windowstack.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__WINDOWSTACK_H__ #define __CORE__WINDOWSTACK_H__ #include #include #include #include #include /**********************************************************************************************************************/ typedef enum { CWSF_NONE = 0x00000000, CWSF_INITIALIZED = 0x00000001, CWSF_ACTIVATED = 0x00000002, CWSF_ALL = 0x00000003 } CoreWindowStackFlags; struct __DFB_CoreWindowStack { DirectLink link; int magic; CoreLayerContext *context; /* layer context */ int width; /* stack width */ int height; /* stack height */ int rotation; /* stack rotation */ int rotated_width; /* stack rotated width */ int rotated_height; /* stack rotated height */ DFBSurfaceBlittingFlags rotated_blit; /* stack rotated blitting flag */ DFBWindowID id_pool; /* window id pool */ struct { int enabled; /* cursor enabled */ int x, y; /* cursor position */ DFBDimension size; /* cursor shape size */ DFBPoint hot; /* cursor hot spot */ CoreSurface *surface; /* cursor shape */ u8 opacity; /* cursor opacity */ DFBRegion region; /* cursor is clipped by this region */ int numerator; /* cursor acceleration factor numerator */ int denominator; /* cursor acceleration factor denominator */ int threshold; /* cursor acceleration threshold */ bool set; /* cursor enable/disable has been called at least one time */ DFBWindowSurfacePolicy policy; /* cursor surface policy */ } cursor; struct { DFBDisplayLayerBackgroundMode mode; /* background handling mode */ DFBColor color; /* color for solid background mode */ int color_index; /* color index for solid background mode */ CoreSurface *image; /* surface for background image mode */ GlobalReaction image_reaction; /* global reaction for background image */ } bg; DirectLink *devices; /* input devices attached to the stack */ bool hw_mode; /* recompositing is done by hardware */ void *stack_data; /* private data of window manager */ FusionSHMPoolShared *shmpool; /* shared memory pool */ CoreWindowStackFlags flags; /* state flags */ FusionCall call; /* dispatch */ FusionDispatchCleanup *motion_cleanup; /* motion input dispatch cleanup */ DFBInputEvent motion_x; /* x motion */ DFBInputEvent motion_y; /* y motion */ long long motion_ts; /* micros */ FusionVector visible_windows; /* list of visible windows */ }; /**********************************************************************************************************************/ /* * Create a window stack, initialize it and attach input devices for input events. */ CoreWindowStack *dfb_windowstack_create ( CoreLayerContext *context ); /* * Detach input devices. */ void dfb_windowstack_detach_devices ( CoreWindowStack *stack ); /* * Destroy a window stack. */ void dfb_windowstack_destroy ( CoreWindowStack *stack ); /* * Resize a window stack. */ void dfb_windowstack_resize ( CoreWindowStack *stack, int width, int height, int rotation ); /* * Prohibit access to the window stack data (wait until stack is accessible). */ DirectResult dfb_windowstack_lock ( CoreWindowStack *stack ); /* * Allow access to the window stack data. */ DirectResult dfb_windowstack_unlock ( CoreWindowStack *stack ); /* * Repaints all window on a window stack. */ DFBResult dfb_windowstack_repaint_all ( CoreWindowStack *stack ); /* * Background handling. */ DFBResult dfb_windowstack_set_background_mode ( CoreWindowStack *stack, DFBDisplayLayerBackgroundMode mode ); DFBResult dfb_windowstack_set_background_image ( CoreWindowStack *stack, CoreSurface *image ); DFBResult dfb_windowstack_set_background_color ( CoreWindowStack *stack, const DFBColor *color ); DFBResult dfb_windowstack_set_background_color_index ( CoreWindowStack *stack, int index ); /* * Cursor control. */ DFBResult dfb_windowstack_cursor_enable ( CoreWindowStack *stack, bool enable ); DFBResult dfb_windowstack_cursor_set_opacity ( CoreWindowStack *stack, u8 opacity ); DFBResult dfb_windowstack_cursor_set_shape ( CoreWindowStack *stack, CoreSurface *shape, int hot_x, int hot_y ); DFBResult dfb_windowstack_cursor_warp ( CoreWindowStack *stack, int x, int y ); DFBResult dfb_windowstack_cursor_set_acceleration ( CoreWindowStack *stack, int numerator, int denominator, int threshold ); DFBResult dfb_windowstack_get_cursor_position ( CoreWindowStack *stack, int *ret_x, int *ret_y ); /* * Global reaction, listen to input device events. */ ReactionResult _dfb_windowstack_inputdevice_listener ( const void *msg_data, void *ctx ); /* * Global reaction, listen to the background image. */ ReactionResult _dfb_windowstack_background_image_listener( const void *msg_data, void *ctx ); #endif ================================================ FILE: src/core/wm.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_WM, "Core/WM", "DirectFB Core WM" ); DEFINE_MODULE_DIRECTORY( dfb_wm_modules, "wm", DFB_CORE_WM_ABI_VERSION ); /**********************************************************************************************************************/ typedef struct { int magic; int abi; char *name; CoreWMInfo info; void *data; FusionSHMPoolShared *shmpool; FusionReactor *reactor; } DFBWMCoreShared; typedef struct { int magic; CoreDFB *core; DFBWMCoreShared *shared; DirectModuleEntry *module; const CoreWMFuncs *funcs; void *data; } DFBWMCore; DFB_CORE_PART( wm_core, WMCore ); /**********************************************************************************************************************/ static DFBWMCore *wm_local = NULL; static DFBWMCoreShared *wm_shared = NULL; static DFBResult load_module( const char *name ) { DirectModuleEntry *module; D_ASSERT( wm_local != NULL ); direct_modules_explore_directory( &dfb_wm_modules ); direct_list_foreach (module, dfb_wm_modules.entries) { const CoreWMFuncs *funcs; funcs = direct_module_ref( module ); if (!funcs) continue; if (!name || !strcasecmp( name, module->name )) { if (wm_local->module) direct_module_unref( wm_local->module ); wm_local->module = module; wm_local->funcs = funcs; } else direct_module_unref( module ); } if (!wm_local->module) { if (name) D_ERROR( "Core/WM: Window manager module '%s' not found!\n", name ); else D_ERROR( "Core/WM: No window manager module found!\n" ); return DFB_NOIMPL; } return DFB_OK; } static DFBResult dfb_wm_core_initialize( CoreDFB *core, DFBWMCore *data, DFBWMCoreShared *shared ) { DFBResult ret; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); data->core = core; data->shared = shared; wm_local = data; wm_shared = shared; wm_shared->shmpool = dfb_core_shmpool( core ); /* Set ABI version for the session. */ wm_shared->abi = DFB_CORE_WM_ABI_VERSION; /* Load the module. */ ret = load_module( dfb_config->wm ); if (ret) goto error; D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->GetWMInfo != NULL ); D_ASSERT( wm_local->funcs->Initialize != NULL ); funcs = wm_local->funcs; /* Query module information. */ funcs->GetWMInfo( &wm_shared->info ); D_INFO( "DirectFB/Core/WM: %s %d.%d (%s)\n", wm_shared->info.name, wm_shared->info.version.major, wm_shared->info.version.minor, wm_shared->info.vendor ); /* Store module name in shared memory. */ wm_shared->name = SHSTRDUP( wm_shared->shmpool, wm_local->module->name ); if (!wm_shared->name) { ret = D_OOSHM(); goto error; } /* Allocate shared window manager data. */ if (wm_shared->info.wm_shared_size) { wm_shared->data = SHCALLOC( wm_shared->shmpool, 1, wm_shared->info.wm_shared_size ); if (!wm_shared->data) { ret = D_OOSHM(); goto error; } } /* Allocate local window manager data. */ if (wm_shared->info.wm_data_size) { wm_local->data = D_CALLOC( 1, wm_shared->info.wm_data_size ); if (!wm_local->data) { ret = D_OOM(); goto error; } } wm_shared->reactor = fusion_reactor_new( 0, "WM", dfb_core_world( core ) ); fusion_reactor_direct( wm_shared->reactor, false ); fusion_reactor_add_permissions( wm_shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH ); /* Initialize window manager. */ ret = funcs->Initialize( core, wm_local->data, wm_shared->data ); if (ret) { D_DERROR( ret, "Core/WM: Could not initialize window manager!\n" ); goto error; } D_MAGIC_SET( data, DFBWMCore ); D_MAGIC_SET( wm_shared, DFBWMCoreShared ); return DFB_OK; error: if (wm_local->data) D_FREE( wm_local->data ); if (wm_shared->data) SHFREE( wm_shared->shmpool, wm_shared->data ); if (wm_shared->name) SHFREE( wm_shared->shmpool, wm_shared->name ); wm_local = NULL; wm_shared = NULL; return ret; } static DFBResult dfb_wm_core_join( CoreDFB *core, DFBWMCore *data, DFBWMCoreShared *shared ) { DFBResult ret; CoreWMInfo info; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %p, %p )\n", __FUNCTION__, core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBWMCoreShared ); data->core = core; data->shared = shared; wm_local = data; wm_shared = shared; /* Check binary version numbers. */ if (wm_shared->abi != DFB_CORE_WM_ABI_VERSION) { D_ERROR( "Core/WM: ABI version of running WM module (%d) doesn't match %d!\n", wm_shared->abi, DFB_CORE_WM_ABI_VERSION ); ret = DFB_VERSIONMISMATCH; goto error; } /* Load the module that is used by the running session. */ ret = load_module( wm_shared->name ); if (ret) goto error; D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->GetWMInfo != NULL ); D_ASSERT( wm_local->funcs->Join != NULL ); funcs = wm_local->funcs; /* Query module information. */ funcs->GetWMInfo( &info ); if (wm_shared->info.version.major != info.version.major || wm_shared->info.version.minor != info.version.minor) { D_ERROR( "Core/WM: Running WM module version '%d.%d' doesn't match version '%d.%d'!\n", wm_shared->info.version.major, wm_shared->info.version.minor, info.version.major, info.version.minor ); ret = DFB_VERSIONMISMATCH; goto error; } /* Allocate window manager data. */ if (wm_shared->info.wm_data_size) { wm_local->data = D_CALLOC( 1, wm_shared->info.wm_data_size ); if (!wm_local->data) { ret = D_OOM(); goto error; } } /* Join window manager. */ ret = funcs->Join( core, wm_local->data, wm_shared->data ); if (ret) { D_DERROR( ret, "Core/WM: Could not join window manager!\n" ); goto error; } D_MAGIC_SET( data, DFBWMCore ); return DFB_OK; error: if (wm_local->data) D_FREE( wm_local->data ); wm_local = NULL; wm_shared = NULL; return ret; } static DFBResult dfb_wm_core_shutdown( DFBWMCore *data, bool emergency ) { DFBResult ret; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBWMCore ); D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Shutdown != NULL ); D_ASSERT( wm_shared == data->shared ); funcs = wm_local->funcs; fusion_reactor_destroy( wm_shared->reactor ); /* Shutdown window manager. */ ret = funcs->Shutdown( emergency, wm_local->data, wm_shared->data ); /* Unload the module. */ direct_module_unref( wm_local->module ); #if !FUSION_BUILD_MULTI fusion_reactor_free( wm_shared->reactor ); #endif /* FUSION_BUILD_MULTI */ fusion_reactor_free( wm_shared->reactor ); /* Deallocate local window manager data. */ if (wm_local->data) D_FREE( wm_local->data ); /* Deallocate shared window manager data. */ if (wm_shared->data) SHFREE( wm_shared->shmpool, wm_shared->data ); /* Free module name in shared memory. */ SHFREE( wm_shared->shmpool, wm_shared->name ); D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( wm_shared ); wm_local = NULL; wm_shared = NULL; return ret; } static DFBResult dfb_wm_core_leave( DFBWMCore *data, bool emergency ) { DFBResult ret; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %semergency )\n", __FUNCTION__, data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBWMCore ); D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Leave != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; /* Leave window manager. */ ret = funcs->Leave( emergency, wm_local->data, wm_shared->data ); /* Unload the module. */ direct_module_unref( wm_local->module ); /* Deallocate local window manager data. */ if (wm_local->data) D_FREE( wm_local->data ); wm_local = NULL; wm_shared = NULL; D_MAGIC_CLEAR( data ); return ret; } static DFBResult dfb_wm_core_suspend( DFBWMCore *data ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBWMCore ); D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Suspend != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; return funcs->Suspend( wm_local->data, wm_shared->data ); } static DFBResult dfb_wm_core_resume( DFBWMCore *data ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, data ); D_MAGIC_ASSERT( data, DFBWMCore ); D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Resume != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; return funcs->Resume( wm_local->data, wm_shared->data ); } /**********************************************************************************************************************/ static bool dfb_wm_layer_context_callback( FusionObjectPool *pool, FusionObject *object, void *ctx ) { CoreLayerContext *context = (CoreLayerContext*) object; CoreWindowStackFlags flags = (CoreWindowStackFlags)(long) ctx; D_DEBUG_AT( Core_WM, " -> ref context %p...\n", context ); dfb_layer_context_ref( context ); dfb_layer_context_lock( context ); if (context->stack) { if ((context->stack->flags & CWSF_ACTIVATED) & flags) dfb_wm_set_active( context->stack, false ); if ((context->stack->flags & CWSF_INITIALIZED) & flags) dfb_wm_close_stack( context->stack ); } dfb_layer_context_unlock( context ); D_DEBUG_AT( Core_WM, " -> unref context %p...\n", context ); dfb_layer_context_unref( context ); return true; } DFBResult dfb_wm_deactivate_all_stacks( void *data ) { DFBWMCore *local = data; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, local ); D_MAGIC_ASSERT( local, DFBWMCore ); D_MAGIC_ASSERT( local->shared, DFBWMCoreShared ); dfb_core_enum_layer_contexts( local->core, dfb_wm_layer_context_callback, (void*)(long) CWSF_ACTIVATED ); return DFB_OK; } DFBResult dfb_wm_close_all_stacks( void *data ) { DFBWMCore *local = data; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, local ); D_MAGIC_ASSERT( local, DFBWMCore ); D_MAGIC_ASSERT( local->shared, DFBWMCoreShared ); dfb_core_enum_layer_contexts( local->core, dfb_wm_layer_context_callback, (void*)(long) CWSF_INITIALIZED ); return DFB_OK; } typedef struct { ReactionFunc func; void *ctx; Reaction *reaction; } AttachContext; static void convert_config( DFBWindowConfig *config, const CoreWindowConfig *from ) { config->bounds = from->bounds; config->opacity = from->opacity; config->stacking = from->stacking; config->options = from->options; config->events = from->events; config->association = from->association; config->color_key = from->color_key; config->opaque = from->opaque; config->color = from->color; config->key_selection = DWKS_ALL; config->cursor_flags = from->cursor_flags; config->cursor_resolution = from->cursor_resolution; config->src_geometry = from->src_geometry; config->dst_geometry = from->dst_geometry; config->rotation = from->rotation; config->application_id = from->application_id; config->stereo_depth = from->z; } static void convert_state( DFBWindowState *state, CoreWindowFlags flags ) { state->flags = DWSTATE_NONE; if (flags & CWF_INSERTED) state->flags |= DWSTATE_INSERTED; if (flags & CWF_FOCUSED) state->flags |= DWSTATE_FOCUSED; if (flags & CWF_ENTERED) state->flags |= DWSTATE_ENTERED; } static DFBEnumerationResult wm_window_attach_callback( CoreWindow *window, void *ctx ) { AttachContext *attach_ctx = ctx; CoreWM_WindowAdd add; memset( &add, 0, sizeof(add ) ); add.info.window_id = window->id; add.info.caps = window->caps; add.info.resource_id = window->resource_id; convert_config( &add.info.config, &window->config ); convert_state( &add.info.state, window->flags ); attach_ctx->func( &add, attach_ctx->ctx ); return DFENUM_OK; } static bool dfb_wm_layer_context_WINDOW_ADD_callback( FusionObjectPool *pool, FusionObject *object, void *ctx ) { DFBResult ret; AttachContext *attach_ctx = ctx; CoreLayerContext *context = (CoreLayerContext*) object; dfb_layer_context_lock( context ); if (context->stack) { ret = dfb_wm_enum_windows( context->stack, wm_window_attach_callback, attach_ctx ); if (ret) D_DERROR( ret, "Core/WM: Could not enumerate windows" ); ret = fusion_reactor_attach_channel( wm_shared->reactor, CORE_WM_WINDOW_ADD, attach_ctx->func, attach_ctx->ctx, attach_ctx->reaction ); if (ret) D_DERROR( ret, "Core/WM: Could not attach to reactor" ); } dfb_layer_context_unlock( context ); return true; } DFBResult dfb_wm_attach( CoreDFB *core, int channel, ReactionFunc func, void *ctx, Reaction *reaction ) { D_ASSERT( wm_shared != NULL ); if (channel == CORE_WM_WINDOW_ADD) { AttachContext attach_ctx = { func, ctx, reaction }; if (dfb_core_is_master( core )) dfb_core_enum_layer_contexts( core, dfb_wm_layer_context_WINDOW_ADD_callback, &attach_ctx ); } return fusion_reactor_attach_channel( wm_shared->reactor, channel, func, ctx, reaction ); } DFBResult dfb_wm_detach( CoreDFB *core, Reaction *reaction ) { D_ASSERT( wm_shared != NULL ); return fusion_reactor_detach( wm_shared->reactor, reaction ); } static DFBResult dfb_wm_dispatch( CoreDFB *core, int channel, const void *data, int size ) { D_ASSERT( wm_shared != NULL ); return fusion_reactor_dispatch_channel( wm_shared->reactor, channel, data, size, true, NULL ); } DFBResult dfb_wm_dispatch_WindowAdd( CoreDFB *core, CoreWindow *window ) { pid_t pid = 0; CoreWM_WindowAdd add; fusion_get_fusionee_pid( core->world, window->object.identity, &pid ); add.info.window_id = window->id; add.info.caps = window->caps; add.info.resource_id = window->resource_id; add.info.process_id = pid; add.info.instance_id = window->object.identity; convert_config( &add.info.config, &window->config ); convert_state( &add.info.state, window->flags ); return dfb_wm_dispatch( core, CORE_WM_WINDOW_ADD, &add, sizeof(add) ); } DFBResult dfb_wm_dispatch_WindowRemove( CoreDFB *core, CoreWindow *window ) { CoreWM_WindowRemove remove; remove.window_id = window->id; return dfb_wm_dispatch( core, CORE_WM_WINDOW_REMOVE, &remove, sizeof(remove) ); } DFBResult dfb_wm_dispatch_WindowConfig( CoreDFB *core, CoreWindow *window, DFBWindowConfigFlags flags ) { CoreWM_WindowConfig config; config.window_id = window->id; config.flags = flags; convert_config( &config.config, &window->config ); return dfb_wm_dispatch( core, CORE_WM_WINDOW_CONFIG, &config, sizeof(config) ); } DFBResult dfb_wm_dispatch_WindowState( CoreDFB *core, CoreWindow *window ) { CoreWM_WindowState state; state.window_id = window->id; convert_state( &state.state, window->flags ); return dfb_wm_dispatch( core, CORE_WM_WINDOW_STATE, &state, sizeof(state) ); } DFBResult dfb_wm_dispatch_WindowRestack( CoreDFB *core, CoreWindow *window, unsigned int index ) { CoreWM_WindowRestack restack; restack.window_id = window->id; restack.index = index; return dfb_wm_dispatch( core, CORE_WM_WINDOW_RESTACK, &restack, sizeof(restack) ); } DFBResult dfb_wm_dispatch_WindowFocus( CoreDFB *core, CoreWindow *window ) { CoreWM_WindowFocus focus; focus.window_id = window->id; return dfb_wm_dispatch( core, CORE_WM_WINDOW_FOCUS, &focus, sizeof(focus) ); } void * dfb_wm_get_data() { D_ASSERT( wm_local != NULL ); return wm_local->data; } DFBResult dfb_wm_post_init( CoreDFB *core ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->PostInit != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; return funcs->PostInit( wm_local->data, wm_shared->data ); } DFBResult dfb_wm_init_stack( CoreWindowStack *stack ) { DFBResult ret; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->InitStack != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( !(stack->flags & CWSF_INITIALIZED) ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); /* Allocate shared stack data. */ if (wm_shared->info.stack_data_size) { if (stack->stack_data) SHFREE( stack->shmpool, stack->stack_data ); stack->stack_data = SHCALLOC( stack->shmpool, 1, wm_shared->info.stack_data_size ); if (!stack->stack_data) { return D_OOSHM(); } } /* Window manager specific initialization. */ ret = funcs->InitStack( stack, wm_local->data, stack->stack_data ); if (ret) { if (stack->stack_data) { SHFREE( wm_shared->shmpool, stack->stack_data ); stack->stack_data = NULL; } return ret; } stack->flags |= CWSF_INITIALIZED; return DFB_OK; } DFBResult dfb_wm_close_stack( CoreWindowStack *stack ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->CloseStack != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSUME( stack->flags & CWSF_INITIALIZED ); if (!(stack->flags & CWSF_INITIALIZED)) { D_ASSUME( !(stack->flags & CWSF_ACTIVATED) ); return DFB_OK; } D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); /* Deactivate before deinitialization. */ if (stack->flags & CWSF_ACTIVATED) dfb_wm_set_active( stack, false ); /* Clear flag and remove stack first, because CloseStack() may cause the stack to be destroyed. */ stack->flags &= ~CWSF_INITIALIZED; /* Window manager specific deinitialization. */ return funcs->CloseStack( stack, wm_local->data, stack->stack_data ); } DFBResult dfb_wm_set_active( CoreWindowStack *stack, bool active ) { DFBResult ret; const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %sactive )\n", __FUNCTION__, stack, active ? "" : "in" ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->SetActive != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); if (active) { D_ASSUME( !(stack->flags & CWSF_ACTIVATED) ); if (stack->flags & CWSF_ACTIVATED) return DFB_OK; ret = funcs->SetActive( stack, wm_local->data, stack->stack_data, true ); stack->flags |= CWSF_ACTIVATED; } else { D_ASSUME( stack->flags & CWSF_ACTIVATED ); if (!(stack->flags & CWSF_ACTIVATED)) return DFB_OK; ret = funcs->SetActive( stack, wm_local->data, stack->stack_data, false ); stack->flags &= ~CWSF_ACTIVATED; } return ret; } DFBResult dfb_wm_resize_stack( CoreWindowStack *stack, int width, int height ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %dx%d )\n", __FUNCTION__, stack, width, height ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->ResizeStack != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); /* Notify window manager about the new size. */ return funcs->ResizeStack( stack, wm_local->data, stack->stack_data, width, height ); } DFBResult dfb_wm_process_input( CoreWindowStack *stack, const DFBInputEvent *event ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %p )\n", __FUNCTION__, stack, event ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->ProcessInput != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( event != NULL ); /* Dispatch input event via window manager. */ return funcs->ProcessInput( stack, wm_local->data, stack->stack_data, event ); } DFBResult dfb_wm_flush_keys( CoreWindowStack *stack ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->FlushKeys != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); return funcs->FlushKeys( stack, wm_local->data, stack->stack_data ); } DFBResult dfb_wm_window_at( CoreWindowStack *stack, int x, int y, CoreWindow **ret_window ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %d,%d )\n", __FUNCTION__, stack, x, y ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->WindowAt != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( ret_window != NULL ); return funcs->WindowAt( stack, wm_local->data, stack->stack_data, x, y, ret_window ); } DFBResult dfb_wm_window_lookup( CoreWindowStack *stack, DFBWindowID window_id, CoreWindow **ret_window ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %u )\n", __FUNCTION__, stack, window_id ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->WindowLookup != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( ret_window != NULL ); return funcs->WindowLookup( stack, wm_local->data, stack->stack_data, window_id, ret_window ); } DFBResult dfb_wm_enum_windows( CoreWindowStack *stack, CoreWMWindowCallback callback, void *callback_ctx ) { const CoreWMFuncs *funcs; D_DEBUG_AT( Core_WM, "%s( %p, %p, %p )\n", __FUNCTION__, stack, callback, callback_ctx ); D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->EnumWindows != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( callback != NULL ); return funcs->EnumWindows( stack, wm_local->data, stack->stack_data, callback, callback_ctx ); } DFBResult dfb_wm_get_insets( CoreWindowStack *stack, CoreWindow *window, DFBInsets *ret_insets ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->GetInsets != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_ASSERT( ret_insets != NULL ); return funcs->GetInsets( stack, window, ret_insets ); } DFBResult dfb_wm_preconfigure_window( CoreWindowStack *stack, CoreWindow *window ) { DFBResult ret; void *window_data = NULL; const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->PreConfigureWindow != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); /* Allocate shared window data. */ if (wm_shared->info.window_data_size) { window_data = SHCALLOC( wm_shared->shmpool, 1, wm_shared->info.window_data_size ); if (!window_data) { return D_OOSHM(); } } /* Keep shared window data. */ window->window_data = window_data; /* Tell window manager about the new window. */ ret = funcs->PreConfigureWindow( stack, wm_local->data, stack->stack_data, window, window_data ); if (ret) { if (window_data) { SHFREE( wm_shared->shmpool, window_data ); window->window_data = NULL; } return ret; } return DFB_OK; } DFBResult dfb_wm_add_window( CoreWindowStack *stack, CoreWindow *window ) { DFBResult ret; const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->AddWindow != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); /* Tell window manager about the new window. */ ret = funcs->AddWindow( stack, wm_local->data, stack->stack_data, window, window->window_data ); if (ret) { if (window->window_data) SHFREE( wm_shared->shmpool, window->window_data ); return ret; } return DFB_OK; } DFBResult dfb_wm_remove_window( CoreWindowStack *stack, CoreWindow *window ) { DFBResult ret; const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->RemoveWindow != NULL ); D_ASSERT( wm_shared != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); /* Remove window from window manager. */ ret = funcs->RemoveWindow( stack, wm_local->data, stack->stack_data, window, window->window_data ); /* Deallocate shared stack data. */ if (window->window_data) { SHFREE( wm_shared->shmpool, window->window_data ); window->window_data = NULL; } return ret; } DFBResult dfb_wm_set_window_property( CoreWindowStack *stack, CoreWindow *window, const char *key, void *value, void **ret_old_value ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->SetWindowProperty != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_ASSERT( key != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d, '%s' = %p )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ), key, value ); return funcs->SetWindowProperty( stack, wm_local->data, stack->stack_data, window, window->window_data, key, value, ret_old_value ); } DFBResult dfb_wm_get_window_property( CoreWindowStack *stack, CoreWindow *window, const char *key, void **ret_value ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->GetWindowProperty != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_ASSERT( key != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d, '%s' )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ), key ); return funcs->GetWindowProperty( stack, wm_local->data, stack->stack_data, window, window->window_data, key, ret_value ); } DFBResult dfb_wm_remove_window_property( CoreWindowStack *stack, CoreWindow *window, const char *key, void **ret_value ) { DFBResult ret; const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->RemoveWindowProperty != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_ASSERT( window != NULL ); D_ASSERT( key != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %p, %4d,%4d-%4dx%4d, '%s' )\n", __FUNCTION__, stack, window, DFB_RECTANGLE_VALS( &window->config.bounds ), key ); ret = funcs->RemoveWindowProperty( stack, wm_local->data, stack->stack_data, window, window->window_data, key, ret_value ); return ret; } static void apply_geometry( const DFBWindowGeometry *geometry, const DFBRegion *clip, const DFBWindowGeometry *parent, DFBRectangle *ret_rect ) { int width, height; D_ASSERT( geometry != NULL ); DFB_REGION_ASSERT( clip ); D_ASSERT( ret_rect != NULL ); if (!geometry) return; width = clip->x2 - clip->x1 + 1; height = clip->y2 - clip->y1 + 1; switch (geometry->mode) { case DWGM_DEFAULT: D_DEBUG_AT( Core_WM, " -- DEFAULT\n" ); *ret_rect = DFB_RECTANGLE_INIT_FROM_REGION( clip ); D_DEBUG_AT( Core_WM, " -> [%4d,%4d-%4dx%4d]\n", DFB_RECTANGLE_VALS( ret_rect ) ); return; case DWGM_FOLLOW: D_ASSERT( parent != NULL ); D_DEBUG_AT( Core_WM, " -- FOLLOW\n" ); apply_geometry( parent, clip, NULL, ret_rect ); break; case DWGM_RECTANGLE: D_DEBUG_AT( Core_WM, " -- RECTANGLE [%4d,%4d-%4dx%4d]\n", DFB_RECTANGLE_VALS( &geometry->rectangle ) ); *ret_rect = geometry->rectangle; ret_rect->x += clip->x1; ret_rect->y += clip->y1; break; case DWGM_LOCATION: D_DEBUG_AT( Core_WM, " -- LOCATION [%.3f,%.3f-%.3fx%.3f]\n", geometry->location.x, geometry->location.y, geometry->location.w, geometry->location.h ); ret_rect->x = (int) (geometry->location.x * width + 0.5f) + clip->x1; ret_rect->y = (int) (geometry->location.y * height + 0.5f) + clip->y1; ret_rect->w = (int) (geometry->location.w * width + 0.5f); ret_rect->h = (int) (geometry->location.h * height + 0.5f); break; default: D_BUG( "invalid geometry mode %u", geometry->mode ); return; } D_DEBUG_AT( Core_WM, " -> %4d,%4d-%4dx%4d / clip %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( ret_rect ), DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); if (!dfb_rectangle_intersect_by_region( ret_rect, clip )) { D_WARN( "invalid geometry" ); dfb_rectangle_from_region( ret_rect, clip ); } D_DEBUG_AT( Core_WM, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( ret_rect ) ); } DFBResult dfb_wm_set_window_config( CoreWindow *window, const CoreWindowConfig *config, DFBWindowConfigFlags flags ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->SetWindowConfig != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_ASSERT( config != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d, %p, 0x%x )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ), config, flags ); if (dfb_config->single_window) { bool single_add = false; bool single_remove = false; bool single_update = false; CoreWindow *config_window = window; if (flags & DWCONF_OPACITY) { if (config->opacity != 0) { if (window->config.opacity == 0) { if (fusion_vector_size( &window->stack->visible_windows ) == 0) { single_add = true; single_update = true; } else if (fusion_vector_size( &window->stack->visible_windows ) == 1) { config_window = fusion_vector_at( &window->stack->visible_windows, 0 ); single_remove = true; } fusion_vector_add( &window->stack->visible_windows, window ); } } else if (window->config.opacity != 0) { if (fusion_vector_size( &window->stack->visible_windows ) == 2) { single_add = true; single_update = true; } else if (fusion_vector_size( &window->stack->visible_windows ) == 1) { config_window = fusion_vector_at( &window->stack->visible_windows, 0 ); single_remove = true; } int idx = fusion_vector_index_of( &window->stack->visible_windows, window ); D_ASSERT( idx >= 0 ); fusion_vector_remove( &window->stack->visible_windows, idx ); } } if (fusion_vector_size( &window->stack->visible_windows ) == 1) single_update = true; if (single_remove) { D_DEBUG_AT( Core_WM, " -> single window optimisation: removing window %p\n", config_window ); dfb_layer_region_disable( config_window->region ); dfb_layer_region_enable( config_window->stack->context->primary.region ); dfb_windowstack_repaint_all( config_window->stack ); } else { if (single_add) { D_DEBUG_AT( Core_WM, " -> single window optimisation: adding window %p\n", config_window ); if (!config_window->region) { DFBResult ret; CoreLayerRegion *region = NULL; CoreSurface *surface = config_window->surface; /* Create a region for the window. */ ret = dfb_window_create_region( config_window, config_window->stack->context, surface, surface->config.format, surface->config.colorspace, surface->config.caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_DEPTH | DSCAPS_SYSTEMONLY | DSCAPS_VIDEOONLY | DSCAPS_STATIC_ALLOC | DSCAPS_TRIPLE | DSCAPS_GL), ®ion, &surface ); if (ret) { D_DEBUG_AT( Core_WM, " -> region create failed!\n" ); int idx = fusion_vector_index_of( &config_window->stack->visible_windows, config_window ); D_ASSERT( idx >= 0 ); fusion_vector_remove( &config_window->stack->visible_windows, idx ); } else { D_ASSERT( config_window->surface == surface ); /* Link the region into the window structure. */ dfb_layer_region_link( &config_window->region, region ); dfb_layer_region_unref( region ); /* Link the surface into the window structure. */ dfb_surface_link( &config_window->surface, surface ); dfb_surface_unref( surface ); } } if (config_window->region) { if (config_window->stack->context->primary.region->state & CLRSF_ENABLED) dfb_layer_region_disable( config_window->stack->context->primary.region ); dfb_layer_region_enable( config_window->region ); } } if (single_update) { CoreLayerRegionConfig region_config = config_window->region->config; CoreLayerRegionConfigFlags region_flags = CLRCF_NONE; D_DEBUG_AT( Core_WM, " -> single window optimisation: updating window %p\n", config_window ); if (flags & DWCONF_OPACITY) { region_flags |= CLRCF_OPACITY; region_config.opacity = config->opacity; } if (flags & DWCONF_POSITION) { region_flags |= CLRCF_DEST; region_config.dest.x = config->bounds.x; region_config.dest.y = config->bounds.y; } if (flags & DWCONF_SIZE) { region_flags |= (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_DEST); region_config.width = config_window->surface->config.size.w; region_config.height = config_window->surface->config.size.h; region_config.dest.w = config->bounds.w; region_config.dest.h = config->bounds.h; } if (flags & DWCONF_DST_GEOMETRY) { DFBRegion clip = DFB_REGION_INIT_FROM_RECTANGLE( &config->bounds ); region_flags |= CLRCF_DEST; apply_geometry( &config->dst_geometry, &clip, NULL, ®ion_config.dest ); } if (flags & DWCONF_SRC_GEOMETRY) { DFBRegion clip = { 0, 0, config_window->surface->config.size.w - 1, config_window->surface->config.size.h - 1 }; region_flags |= CLRCF_SOURCE; apply_geometry( &config->src_geometry, &clip, NULL, ®ion_config.source ); } if (region_flags != CLRCF_NONE) dfb_layer_region_set_configuration( config_window->region, ®ion_config, region_flags ); } } } return funcs->SetWindowConfig( window, wm_local->data, window->window_data, config, flags ); } DFBResult dfb_wm_restack_window( CoreWindow *window, CoreWindow *relative, int relation ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->RestackWindow != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_ASSERT( relative == NULL || relative == window || relation != 0 ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d, %p, %d )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ), relative, relation ); return funcs->RestackWindow( window, wm_local->data, window->window_data, relative, relative ? relative->window_data : NULL, relation ); } DFBResult dfb_wm_grab( CoreWindow *window, CoreWMGrab *grab ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Grab != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_ASSERT( grab != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d, %u )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ), grab->target ); return funcs->Grab( window, wm_local->data, window->window_data, grab ); } DFBResult dfb_wm_ungrab( CoreWindow *window, CoreWMGrab *grab ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->Ungrab != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_ASSERT( grab != NULL ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d, %u )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ), grab->target ); return funcs->Ungrab( window, wm_local->data, window->window_data, grab ); } DFBResult dfb_wm_request_focus( CoreWindow *window ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->RequestFocus != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); return funcs->RequestFocus( window, wm_local->data, window->window_data ); } DFBResult dfb_wm_begin_updates( CoreWindow *window, const DFBRegion *update ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->BeginUpdates != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d )\n", __FUNCTION__, window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); return funcs->BeginUpdates( window, wm_local->data, window->window_data, update ); } DFBResult dfb_wm_set_cursor_position( CoreWindow *window, int x, int y ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->SetCursorPosition != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); D_DEBUG_AT( Core_WM, "%s( %p %4d,%4d )\n", __FUNCTION__, window, x, y ); return funcs->SetCursorPosition( window, wm_local->data, window->window_data, x, y ); } DFBResult dfb_wm_update_stack( CoreWindowStack *stack, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->UpdateStack != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); DFB_REGION_ASSERT( region ); D_DEBUG_AT( Core_WM, "%s( %p, %4d,%4d-%4dx%4d, 0x%x )\n", __FUNCTION__, stack, DFB_RECTANGLE_VALS_FROM_REGION( region ), flags ); return funcs->UpdateStack( stack, wm_local->data, stack->stack_data, region, flags ); } DFBResult dfb_wm_update_window( CoreWindow *window, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ) { bool stereo; const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->UpdateWindow != NULL ); funcs = wm_local->funcs; D_ASSERT( window != NULL ); D_MAGIC_ASSERT( window->stack, CoreWindowStack ); D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); DFB_REGION_ASSERT_IF( left_region ); DFB_REGION_ASSERT_IF( right_region ); stereo = window->caps & DWCAPS_STEREO; D_DEBUG_AT( Core_WM, "%s( %p, %u, %4d,%4d-%4dx%4d )\n", __FUNCTION__, window, window->object.id, DFB_RECTANGLE_VALS( &window->config.bounds ) ); if (left_region) D_DEBUG_AT( Core_WM, " -> %s[%4d,%4d-%4dx%4d]\n", stereo ? "Left: " : "", DFB_RECTANGLE_VALS_FROM_REGION( left_region ) ); if (right_region && stereo) D_DEBUG_AT( Core_WM, " -> Right: [%4d,%4d-%4dx%4d]\n", DFB_RECTANGLE_VALS_FROM_REGION( right_region ) ); D_DEBUG_AT( Core_WM, " -> flags: 0x%04x\n", flags ); return funcs->UpdateWindow( window, wm_local->data, window->window_data, left_region, right_region, flags ); } DFBResult dfb_wm_update_cursor( CoreWindowStack *stack, CoreCursorUpdateFlags flags ) { const CoreWMFuncs *funcs; D_ASSERT( wm_local != NULL ); D_ASSERT( wm_local->funcs != NULL ); D_ASSERT( wm_local->funcs->UpdateCursor != NULL ); funcs = wm_local->funcs; D_MAGIC_ASSERT( stack, CoreWindowStack ); D_ASSERT( stack->flags & CWSF_INITIALIZED ); D_MAGIC_ASSERT( stack->context, CoreLayerContext ); FUSION_SKIRMISH_ASSERT( &stack->context->lock ); D_FLAGS_ASSERT( flags, CCUF_ALL ); if (dfb_config->no_cursor) return DFB_OK; return funcs->UpdateCursor( stack, wm_local->data, stack->stack_data, flags ); } ================================================ FILE: src/core/wm.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__WM_H__ #define __CORE__WM_H__ #include #include #include #include DECLARE_MODULE_DIRECTORY( dfb_wm_modules ); /**********************************************************************************************************************/ #define DFB_CORE_WM_ABI_VERSION 10 #define DFB_CORE_WM_INFO_NAME_LENGTH 60 #define DFB_CORE_WM_INFO_VENDOR_LENGTH 80 #define DFB_CORE_WM_INFO_URL_LENGTH 120 #define DFB_CORE_WM_INFO_LICENSE_LENGTH 40 typedef struct { int major; /* major version */ int minor; /* minor version */ } CoreWMVersion; typedef struct { CoreWMVersion version; char name[DFB_CORE_WM_INFO_NAME_LENGTH]; /* Name of WM module */ char vendor[DFB_CORE_WM_INFO_VENDOR_LENGTH]; /* Vendor (or author) of the module */ char url[DFB_CORE_WM_INFO_URL_LENGTH]; /* URL for module updates */ char license[DFB_CORE_WM_INFO_LICENSE_LENGTH]; /* License, e.g. 'LGPL' or 'proprietary' */ unsigned int wm_data_size; /* WM local data size to allocate */ unsigned int wm_shared_size; /* WM shared data size to allocate */ unsigned int stack_data_size; /* WM shared stack data size to allocate */ unsigned int window_data_size; /* WM shared window data size to allocate */ } CoreWMInfo; typedef struct { CoreWMGrabTarget target; DFBInputDeviceKeySymbol symbol; DFBInputDeviceModifierMask modifiers; } CoreWMGrab; typedef enum { CCUF_NONE = 0x00000000, CCUF_ENABLE = 0x00000001, CCUF_DISABLE = 0x00000002, CCUF_POSITION = 0x00000010, CCUF_SIZE = 0x00000020, CCUF_SHAPE = 0x00000040, CCUF_OPACITY = 0x00000080, CCUF_ALL = 0x000000F3 } CoreCursorUpdateFlags; typedef DFBEnumerationResult (*CoreWMWindowCallback)( CoreWindow *window, void *ctx ); typedef struct { void (*GetWMInfo) ( CoreWMInfo *info ); DFBResult (*Initialize) ( CoreDFB *core, void *wm_data, void *shared_data ); DFBResult (*Join) ( CoreDFB *core, void *wm_data, void *shared_data ); DFBResult (*Shutdown) ( bool emergency, void *wm_data, void *shared_data ); DFBResult (*Leave) ( bool emergency, void *wm_data, void *shared_data ); DFBResult (*Suspend) ( void *wm_data, void *shared_data ); DFBResult (*Resume) ( void *wm_data, void *shared_data ); DFBResult (*PostInit) ( void *wm_data, void *shared_data ); DFBResult (*InitStack) ( CoreWindowStack *stack, void *wm_data, void *stack_data ); DFBResult (*CloseStack) ( CoreWindowStack *stack, void *wm_data, void *stack_data ); DFBResult (*SetActive) ( CoreWindowStack *stack, void *wm_data, void *stack_data, bool active ); DFBResult (*ResizeStack) ( CoreWindowStack *stack, void *wm_data, void *stack_data, int width, int height ); DFBResult (*ProcessInput) ( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBInputEvent *event ); DFBResult (*FlushKeys) ( CoreWindowStack *stack, void *wm_data, void *stack_data ); DFBResult (*WindowAt) ( CoreWindowStack *stack, void *wm_data, void *stack_data, int x, int y, CoreWindow **ret_window ); DFBResult (*WindowLookup) ( CoreWindowStack *stack, void *wm_data, void *stack_data, DFBWindowID window_id, CoreWindow **ret_window ); DFBResult (*EnumWindows) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWMWindowCallback callback, void *callback_ctx ); DFBResult (*SetWindowProperty) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void *value, void **old_value ); DFBResult (*GetWindowProperty) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **value ); DFBResult (*RemoveWindowProperty)( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **value ); DFBResult (*GetInsets) ( CoreWindowStack *stack, CoreWindow *window, DFBInsets *insets ); DFBResult (*PreConfigureWindow) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); DFBResult (*AddWindow) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); DFBResult (*RemoveWindow) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); DFBResult (*SetWindowConfig) ( CoreWindow *window, void *wm_data, void *window_data, const CoreWindowConfig *config, DFBWindowConfigFlags flags ); DFBResult (*RestackWindow) ( CoreWindow *window, void *wm_data, void *window_data, CoreWindow *relative, void *relative_data, int relation ); DFBResult (*Grab) ( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ); DFBResult (*Ungrab) ( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ); DFBResult (*RequestFocus) ( CoreWindow *window, void *wm_data, void *window_data ); DFBResult (*BeginUpdates) ( CoreWindow *window, void *wm_data, void *window_data, const DFBRegion *update ); DFBResult (*SetCursorPosition) ( CoreWindow *window, void *wm_data, void *window_data, int x, int y ); DFBResult (*UpdateStack) ( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBRegion *region, DFBSurfaceFlipFlags flags ); DFBResult (*UpdateWindow) ( CoreWindow *window, void *wm_data, void *window_data, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ); DFBResult (*UpdateCursor) ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreCursorUpdateFlags flags ); } CoreWMFuncs; typedef enum { CORE_WM_WINDOW_ADD = 0x00000001, CORE_WM_WINDOW_REMOVE = 0x00000002, CORE_WM_WINDOW_CONFIG = 0x00000003, CORE_WM_WINDOW_STATE = 0x00000004, CORE_WM_WINDOW_RESTACK = 0x00000005, CORE_WM_WINDOW_FOCUS = 0x00000006, CORE_WM_NUM_CHANNELS = 0x00000007 } CoreWMChannels; typedef struct { DFBWindowInfo info; } CoreWM_WindowAdd; typedef struct { DFBWindowID window_id; } CoreWM_WindowRemove; typedef struct { DFBWindowID window_id; DFBWindowConfig config; DFBWindowConfigFlags flags; } CoreWM_WindowConfig; typedef struct { DFBWindowID window_id; DFBWindowState state; } CoreWM_WindowState; typedef struct { DFBWindowID window_id; unsigned int index; } CoreWM_WindowRestack; typedef struct { DFBWindowID window_id; } CoreWM_WindowFocus; /**********************************************************************************************************************/ DFBResult dfb_wm_deactivate_all_stacks ( void *data ); DFBResult dfb_wm_close_all_stacks ( void *data ); DFBResult dfb_wm_attach ( CoreDFB *core, int channel, ReactionFunc func, void *ctx, Reaction *reaction ); DFBResult dfb_wm_detach ( CoreDFB *core, Reaction *reaction ); DFBResult dfb_wm_dispatch_WindowAdd ( CoreDFB *core, CoreWindow *window ); DFBResult dfb_wm_dispatch_WindowRemove ( CoreDFB *core, CoreWindow *window ); DFBResult dfb_wm_dispatch_WindowConfig ( CoreDFB *core, CoreWindow *window, DFBWindowConfigFlags flags ); DFBResult dfb_wm_dispatch_WindowState ( CoreDFB *core, CoreWindow *window ); DFBResult dfb_wm_dispatch_WindowRestack( CoreDFB *core, CoreWindow *window, unsigned int index ); DFBResult dfb_wm_dispatch_WindowFocus ( CoreDFB *core, CoreWindow *window ); void *dfb_wm_get_data ( void ); DFBResult dfb_wm_post_init ( CoreDFB *core ); DFBResult dfb_wm_init_stack ( CoreWindowStack *stack ); DFBResult dfb_wm_close_stack ( CoreWindowStack *stack ); DFBResult dfb_wm_set_active ( CoreWindowStack *stack, bool active ); DFBResult dfb_wm_resize_stack ( CoreWindowStack *stack, int width, int height ); DFBResult dfb_wm_process_input ( CoreWindowStack *stack, const DFBInputEvent *event ); DFBResult dfb_wm_flush_keys ( CoreWindowStack *stack ); DFBResult dfb_wm_window_at ( CoreWindowStack *stack, int x, int y, CoreWindow **ret_window ); DFBResult dfb_wm_window_lookup ( CoreWindowStack *stack, DFBWindowID window_id, CoreWindow **ret_window ); DFBResult dfb_wm_enum_windows ( CoreWindowStack *stack, CoreWMWindowCallback callback, void *callback_ctx ); DFBResult dfb_wm_get_insets ( CoreWindowStack *stack, CoreWindow *window, DFBInsets *ret_insets ); DFBResult dfb_wm_preconfigure_window ( CoreWindowStack *stack, CoreWindow *window ); DFBResult dfb_wm_add_window ( CoreWindowStack *stack, CoreWindow *window ); DFBResult dfb_wm_remove_window ( CoreWindowStack *stack, CoreWindow *window ); DFBResult dfb_wm_set_window_property ( CoreWindowStack *stack, CoreWindow *window, const char *key, void *value, void **ret_old_value ); DFBResult dfb_wm_get_window_property ( CoreWindowStack *stack, CoreWindow *window, const char *key, void **ret_value ); DFBResult dfb_wm_remove_window_property( CoreWindowStack *stack, CoreWindow *window, const char *key, void **ret_value ); DFBResult dfb_wm_set_window_config ( CoreWindow *window, const CoreWindowConfig *config, DFBWindowConfigFlags flags ); DFBResult dfb_wm_restack_window ( CoreWindow *window, CoreWindow *relative, int relation ); DFBResult dfb_wm_grab ( CoreWindow *window, CoreWMGrab *grab ); DFBResult dfb_wm_ungrab ( CoreWindow *window, CoreWMGrab *grab ); DFBResult dfb_wm_request_focus ( CoreWindow *window ); DFBResult dfb_wm_begin_updates ( CoreWindow *window, const DFBRegion *update ); DFBResult dfb_wm_set_cursor_position ( CoreWindow *window, int x, int y ); DFBResult dfb_wm_update_stack ( CoreWindowStack *stack, const DFBRegion *region, DFBSurfaceFlipFlags flags ); DFBResult dfb_wm_update_window ( CoreWindow *window, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ); DFBResult dfb_wm_update_cursor ( CoreWindowStack *stack, CoreCursorUpdateFlags flags ); #endif ================================================ FILE: src/core/wm_module.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __CORE__WM_MODULE_H__ #define __CORE__WM_MODULE_H__ #include /**********************************************************************************************************************/ static void wm_get_info ( CoreWMInfo *info ); static DFBResult wm_initialize ( CoreDFB *core, void *wm_data, void *shared_data ); static DFBResult wm_join ( CoreDFB *core, void *wm_data, void *shared_data ); static DFBResult wm_shutdown ( bool emergency, void *wm_data, void *shared_data ); static DFBResult wm_leave ( bool emergency, void *wm_data, void *shared_data ); static DFBResult wm_suspend ( void *wm_data, void *shared_data ); static DFBResult wm_resume ( void *wm_data, void *shared_data ); static DFBResult wm_post_init ( void *wm_data, void *shared_data ); static DFBResult wm_init_stack ( CoreWindowStack *stack, void *wm_data, void *stack_data ); static DFBResult wm_close_stack ( CoreWindowStack *stack, void *wm_data, void *stack_data ); static DFBResult wm_set_active ( CoreWindowStack *stack, void *wm_data, void *stack_data, bool active ); static DFBResult wm_resize_stack ( CoreWindowStack *stack, void *wm_data, void *stack_data, int width, int height ); static DFBResult wm_process_input ( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBInputEvent *event ); static DFBResult wm_flush_keys ( CoreWindowStack *stack, void *wm_data, void *stack_data ); static DFBResult wm_window_at ( CoreWindowStack *stack, void *wm_data, void *stack_data, int x, int y, CoreWindow **ret_window ); static DFBResult wm_window_lookup ( CoreWindowStack *stack, void *wm_data, void *stack_data, DFBWindowID window_id, CoreWindow **ret_window ); static DFBResult wm_enum_windows ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWMWindowCallback callback, void *callback_ctx ); static DFBResult wm_get_insets ( CoreWindowStack *stack, CoreWindow *window, DFBInsets *insets ); static DFBResult wm_preconfigure_window ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); static DFBResult wm_set_window_property ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void *value, void **ret_old_value ); static DFBResult wm_get_window_property ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **ret_value ); static DFBResult wm_remove_window_property( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data, const char *key, void **ret_value ); static DFBResult wm_add_window ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); static DFBResult wm_remove_window ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreWindow *window, void *window_data ); static DFBResult wm_set_window_config ( CoreWindow *window, void *wm_data, void *window_data, const CoreWindowConfig *config, DFBWindowConfigFlags flags ); static DFBResult wm_restack_window ( CoreWindow *window, void *wm_data, void *window_data, CoreWindow *relative, void *relative_data, int relation ); static DFBResult wm_grab ( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ); static DFBResult wm_ungrab ( CoreWindow *window, void *wm_data, void *window_data, CoreWMGrab *grab ); static DFBResult wm_request_focus ( CoreWindow *window, void *wm_data, void *window_data ); static DFBResult wm_begin_updates ( CoreWindow *window, void *wm_data, void *window_data, const DFBRegion *update ); static DFBResult wm_set_cursor_position ( CoreWindow *window, void *wm_data, void *window_data, int x, int y ); static DFBResult wm_update_stack ( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBRegion *region, DFBSurfaceFlipFlags flags ); static DFBResult wm_update_window ( CoreWindow *window, void *wm_data, void *window_data, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ); static DFBResult wm_update_cursor ( CoreWindowStack *stack, void *wm_data, void *stack_data, CoreCursorUpdateFlags flags ); static CoreWMFuncs wm_funcs = { .GetWMInfo = wm_get_info, .Initialize = wm_initialize, .Join = wm_join, .Shutdown = wm_shutdown, .Leave = wm_leave, .Suspend = wm_suspend, .Resume = wm_resume, .PostInit = wm_post_init, .InitStack = wm_init_stack, .CloseStack = wm_close_stack, .SetActive = wm_set_active, .ResizeStack = wm_resize_stack, .ProcessInput = wm_process_input, .FlushKeys = wm_flush_keys, .WindowAt = wm_window_at, .WindowLookup = wm_window_lookup, .EnumWindows = wm_enum_windows, .GetInsets = wm_get_insets, .PreConfigureWindow = wm_preconfigure_window, .SetWindowProperty = wm_set_window_property, .GetWindowProperty = wm_get_window_property, .RemoveWindowProperty = wm_remove_window_property, .AddWindow = wm_add_window, .RemoveWindow = wm_remove_window, .SetWindowConfig = wm_set_window_config, .RestackWindow = wm_restack_window, .Grab = wm_grab, .Ungrab = wm_ungrab, .RequestFocus = wm_request_focus, .BeginUpdates = wm_begin_updates, .SetCursorPosition = wm_set_cursor_position, .UpdateStack = wm_update_stack, .UpdateWindow = wm_update_window, .UpdateCursor = wm_update_cursor }; #define DFB_WINDOW_MANAGER(shortname) \ \ __dfb_constructor__ \ void \ directfb_##shortname##_ctor( void ) \ { \ direct_modules_register( &dfb_wm_modules, \ DFB_CORE_WM_ABI_VERSION, \ #shortname, \ &wm_funcs ); \ } #endif ================================================ FILE: src/directfb.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB_Main, "DirectFB/Main", "DirectFB Main Functions" ); /**********************************************************************************************************************/ IDirectFB *idirectfb_singleton = NULL; static DirectMutex idirectfb_lock; static DirectOnce idirectfb_init_once = DIRECT_ONCE_INIT(); const unsigned int directfb_major_version = DIRECTFB_MAJOR_VERSION; const unsigned int directfb_minor_version = DIRECTFB_MINOR_VERSION; const unsigned int directfb_micro_version = DIRECTFB_MICRO_VERSION; #if !DIRECT_BUILD_CTORS void __D_init_all( void ); void __Fusion_init_all( void ); void __DFB_init_all( void ); #endif /**********************************************************************************************************************/ const char * DirectFBCheckVersion( unsigned int required_major, unsigned int required_minor, unsigned int required_micro ) { if (required_major > DIRECTFB_MAJOR_VERSION) return "DirectFB version too old (major mismatch)"; if (required_major < DIRECTFB_MAJOR_VERSION) return "DirectFB version too new (major mismatch)"; if (required_minor > DIRECTFB_MINOR_VERSION) return "DirectFB version too old (minor mismatch)"; if (required_minor < DIRECTFB_MINOR_VERSION) return "DirectFB version too new (minor mismatch)"; if (required_micro > DIRECTFB_MICRO_VERSION) return "DirectFB version too old (micro mismatch)"; return NULL; } const char * DirectFBUsageString() { return dfb_config_usage; } DFBResult DirectFBInit( int *argc, char **argv[] ) { DFBResult ret; #if !DIRECT_BUILD_CTORS if (!dfb_config) { __D_init_all(); __Fusion_init_all(); __DFB_init_all(); } #endif ret = dfb_config_init( argc, argv ); if (ret) return ret; return DFB_OK; } DFBResult DirectFBSetOption( const char *name, const char *value ) { DFBResult ret; D_DEBUG_AT( DirectFB_Main, "%s( '%s', '%s' )\n", __FUNCTION__, name, value ); if (!dfb_config) { D_ERROR( "DirectFB/Main: DirectFBInit() has to be called before DirectFBSetOption()!\n" ); return DFB_INIT; } if (!name) return DFB_INVARG; ret = dfb_config_set( name, value ); if (ret) return ret; return DFB_OK; } static void init_once( void ) { direct_recursive_mutex_init( &idirectfb_lock ); } DFBResult DirectFBCreate( IDirectFB **ret_interface ) { DFBResult ret; IDirectFB *dfb; D_DEBUG_AT( DirectFB_Main, "%s( %p )\n", __FUNCTION__, ret_interface ); if (!dfb_config) { D_ERROR( "DirectFB/Main: DirectFBInit() has to be called before DirectFBCreate()!\n" ); return DFB_INIT; } if (!ret_interface) return DFB_INVARG; if (idirectfb_singleton) { D_DEBUG_AT( DirectFB_Main, " -> using singleton %p\n", idirectfb_singleton ); idirectfb_singleton->AddRef( idirectfb_singleton ); *ret_interface = idirectfb_singleton; return DFB_OK; } direct_initialize(); if (!(direct_config->quiet & DMT_BANNER) && dfb_config->banner) { direct_log_printf( NULL, "\n" " ~~~~~~~~~~~~~~~~~~~~~~~~~~| DirectFB %d.%d.%d %s |~~~~~~~~~~~~~~~~~~~~~~~~~~\n" " (c) 2017-2025 DirectFB2 Open Source Project (fork of DirectFB)\n" " (c) 2012-2016 DirectFB integrated media GmbH\n" " (c) 2001-2016 The world wide DirectFB Open Source Community\n" " (c) 2000-2004 Convergence (integrated media) GmbH\n" " ----------------------------------------------------------------\n" "\n", DIRECTFB_MAJOR_VERSION, DIRECTFB_MINOR_VERSION, DIRECTFB_MICRO_VERSION, DIRECTFB_VERSION_VENDOR ); } direct_once( &idirectfb_init_once, init_once ); direct_mutex_lock( &idirectfb_lock ); if (idirectfb_singleton) { D_DEBUG_AT( DirectFB_Main, " -> using (new) singleton %p\n", idirectfb_singleton ); idirectfb_singleton->AddRef( idirectfb_singleton ); *ret_interface = idirectfb_singleton; direct_mutex_unlock( &idirectfb_lock ); return DFB_OK; } DIRECT_ALLOCATE_INTERFACE( dfb, IDirectFB ); D_DEBUG_AT( DirectFB_Main, " -> setting singleton to %p (was %p)\n", dfb, idirectfb_singleton ); idirectfb_singleton = dfb; ret = IDirectFB_Construct( dfb ); if (ret) { D_DEBUG_AT( DirectFB_Main, " -> resetting singleton to NULL!\n" ); idirectfb_singleton = NULL; direct_mutex_unlock( &idirectfb_lock ); return ret; } direct_mutex_unlock( &idirectfb_lock ); ret = IDirectFB_WaitInitialised( dfb ); if (ret) { idirectfb_singleton = NULL; dfb->Release( dfb ); return ret; } D_DEBUG_AT( DirectFB_Main, " -> done\n" ); *ret_interface = dfb; return DFB_OK; } DFBResult DirectFBError( const char *msg, DFBResult result ) { if (msg) direct_log_printf( NULL, "(!) DirectFBError [%s]: %s\n", msg, DirectFBErrorString( result ) ); else direct_log_printf( NULL, "(!) DirectFBError: %s\n", DirectFBErrorString( result ) ); return result; } const char * DirectFBErrorString( DFBResult result ) { return DirectResultString( result ); } DFBResult DirectFBErrorFatal( const char *msg, DFBResult result ) { DirectFBError( msg, result ); exit( result ); } ================================================ FILE: src/directfb_result.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static const char *DFBResult__strings[DFB__RESULT_END - DFB__RESULT_BASE]; static DirectResultType DFBResult__type = { 0, 0, DFB__RESULT_BASE, DFBResult__strings, D_ARRAY_SIZE(DFBResult__strings) }; void DFBResult__init( void ) { DFBResult__strings[0] = "DFBResult"; DFBResult__strings[D_RESULT_INDEX(DFB_NOVIDEOMEMORY)] = "There's not enough video memory."; DFBResult__strings[D_RESULT_INDEX(DFB_MISSINGFONT)] = "No font has been set."; DFBResult__strings[D_RESULT_INDEX(DFB_MISSINGIMAGE)] = "No image has been set."; DFBResult__strings[D_RESULT_INDEX(DFB_NOALLOCATION)] = "No allocation."; DFBResult__strings[D_RESULT_INDEX(DFB_NOBUFFER)] = "No buffer."; DirectResultTypeRegister( &DFBResult__type ); } void DFBResult__deinit( void ) { DirectResultTypeUnregister( &DFBResult__type ); } ================================================ FILE: src/directfb_result.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DIRECTFB_RESULT_H__ #define __DIRECTFB_RESULT_H__ /**********************************************************************************************************************/ void DFBResult__init ( void ); void DFBResult__deinit( void ); #endif ================================================ FILE: src/display/idirectfbdisplaylayer.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Layer, "IDirectFBDisplayLayer", "IDirectFBDisplayLayer Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBDisplayLayer */ typedef struct { int ref; /* reference counter */ DFBDisplayLayerDescription desc; /* description of the layer's caps */ DFBDisplayLayerCooperativeLevel level; /* current cooperative level */ CoreScreen *screen; /* layer's screen */ CoreLayer *layer; /* the layer object */ CoreLayerContext *context; /* shared or exclusive context */ CoreLayerRegion *region; /* primary region of the context */ CoreWindowStack *stack; /* stack of shared context */ DFBBoolean switch_exclusive; /* switch to exclusive context after creation */ CoreDFB *core; IDirectFB *idirectfb; } IDirectFBDisplayLayer_data; /**********************************************************************************************************************/ static void IDirectFBDisplayLayer_Destruct( IDirectFBDisplayLayer *thiz ) { IDirectFBDisplayLayer_data *data = thiz->priv; D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); D_DEBUG_AT( Layer, " -> unref region...\n" ); dfb_layer_region_unref( data->region ); D_DEBUG_AT( Layer, " -> unref context...\n" ); dfb_layer_context_unref( data->context ); DIRECT_DEALLOCATE_INTERFACE( thiz ); D_DEBUG_AT( Layer, " -> done\n" ); } static DirectResult IDirectFBDisplayLayer_AddRef( IDirectFBDisplayLayer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBDisplayLayer_Release( IDirectFBDisplayLayer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBDisplayLayer_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetID( IDirectFBDisplayLayer *thiz, DFBDisplayLayerID *ret_layer_id ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_layer_id) return DFB_INVARG; *ret_layer_id = dfb_layer_id_translated( data->layer ); return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetDescription( IDirectFBDisplayLayer *thiz, DFBDisplayLayerDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->desc; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetSourceDescriptions( IDirectFBDisplayLayer *thiz, DFBDisplayLayerSourceDescription *ret_descriptions ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_descriptions) return DFB_INVARG; if (!D_FLAGS_IS_SET( data->desc.caps, DLCAPS_SOURCES )) return DFB_UNSUPPORTED; for (i = 0; i < data->desc.sources; i++) dfb_layer_get_source_info( data->layer, i, &ret_descriptions[i] ); return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetCurrentOutputField( IDirectFBDisplayLayer *thiz, int *ret_field ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); return CoreLayer_GetCurrentOutputField( data->layer, ret_field ); } static DFBResult IDirectFBDisplayLayer_GetSurface( IDirectFBDisplayLayer *thiz, IDirectFBSurface **ret_interface ) { DFBResult ret; CoreLayerRegion *region; IDirectFBSurface *iface; IDirectFBSurface_data *surface_data; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; if (data->level == DLSCL_SHARED) { D_WARN( "letting unprivileged GetSurface() call pass until cooperative level handling is finished" ); } ret = CoreLayerContext_GetPrimaryRegion( data->context, true, ®ion ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Layer_Construct( iface, NULL, NULL, NULL, region, DSCAPS_NONE, data->core, data->idirectfb ); surface_data = iface->priv; if (!surface_data) return DFB_DEAD; /* Only perform single buffered clearing using a background when configured to do so and when the display layer region is frozen. */ if (region->config.buffermode == DLBM_FRONTONLY && data->level != DLSCL_SHARED && D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { /* If a window stack is available, give it the opportunity to render the background (optionally based on configuration) and flip the display layer so it is visible. Otherwise, just directly flip the display layer and make it visible. */ if (data->stack) { CoreWindowStack_RepaintAll( data->stack ); } else { CoreSurface_Flip2( surface_data->surface, DFB_FALSE, NULL, NULL, DSFLIP_NONE, -1 ); } } *ret_interface = ret ? NULL : iface; dfb_layer_region_unref( region ); return ret; } static DFBResult IDirectFBDisplayLayer_GetScreen( IDirectFBDisplayLayer *thiz, IDirectFBScreen **ret_interface ) { DFBResult ret; IDirectFBScreen *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBScreen ); ret = IDirectFBScreen_Construct( iface, data->screen ); *ret_interface = ret ? NULL : iface; return ret; } static DFBResult IDirectFBDisplayLayer_SetCooperativeLevel( IDirectFBDisplayLayer *thiz, DFBDisplayLayerCooperativeLevel level ) { DFBResult ret; CoreLayerContext *context; CoreLayerRegion *region; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == level) return DFB_OK; switch (level) { case DLSCL_SHARED: case DLSCL_ADMINISTRATIVE: if (data->level == DLSCL_EXCLUSIVE) { ret = CoreLayer_GetPrimaryContext( data->layer, false, &context ); if (ret) return ret; ret = CoreLayerContext_GetPrimaryRegion( context, true, ®ion ); if (ret) { dfb_layer_context_unref( context ); return ret; } dfb_layer_region_unref( data->region ); dfb_layer_context_unref( data->context ); data->context = context; data->region = region; data->stack = dfb_layer_context_windowstack( data->context ); } break; case DLSCL_EXCLUSIVE: ret = CoreLayer_CreateContext( data->layer, &context ); if (ret) return ret; if (data->switch_exclusive) { ret = CoreLayer_ActivateContext( data->layer, context ); if (ret) { dfb_layer_context_unref( context ); return ret; } } ret = CoreLayerContext_GetPrimaryRegion( context, true, ®ion ); if (ret) { dfb_layer_context_unref( context ); return ret; } dfb_layer_region_unref( data->region ); dfb_layer_context_unref( data->context ); data->context = context; data->region = region; data->stack = dfb_layer_context_windowstack( data->context ); break; default: return DFB_INVARG; } data->level = level; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetConfiguration( IDirectFBDisplayLayer *thiz, DFBDisplayLayerConfig *ret_config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_config) return DFB_INVARG; return dfb_layer_context_get_configuration( data->context, ret_config ); } static DFBResult IDirectFBDisplayLayer_TestConfiguration( IDirectFBDisplayLayer *thiz, const DFBDisplayLayerConfig *config, DFBDisplayLayerConfigFlags *ret_failed ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!config) return DFB_INVARG; if (((config->flags & DLCONF_WIDTH) && (config->width < 0)) || ((config->flags & DLCONF_HEIGHT) && (config->height < 0))) return DFB_INVARG; return CoreLayerContext_TestConfiguration( data->context, config, ret_failed ); } static DFBResult IDirectFBDisplayLayer_SetConfiguration( IDirectFBDisplayLayer *thiz, const DFBDisplayLayerConfig *config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!config) return DFB_INVARG; if (((config->flags & DLCONF_WIDTH) && (config->width < 0)) || ((config->flags & DLCONF_HEIGHT) && (config->height < 0))) return DFB_INVARG; switch (data->level) { case DLSCL_EXCLUSIVE: case DLSCL_ADMINISTRATIVE: return CoreLayerContext_SetConfiguration( data->context, config ); default: break; } return DFB_ACCESSDENIED; } static DFBResult IDirectFBDisplayLayer_SetScreenLocation( IDirectFBDisplayLayer *thiz, float x, float y, float width, float height ) { DFBLocation location = { x, y, width, height }; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!D_FLAGS_IS_SET( data->desc.caps, DLCAPS_SCREEN_LOCATION )) return DFB_UNSUPPORTED; if (width <= 0 || height <= 0) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetScreenLocation( data->context, &location ); } static DFBResult IDirectFBDisplayLayer_SetScreenPosition( IDirectFBDisplayLayer *thiz, int x, int y ) { DFBPoint position; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p, %d,%d )\n", __FUNCTION__, thiz, x, y ); if (!D_FLAGS_IS_SET( data->desc.caps, DLCAPS_SCREEN_POSITION )) return DFB_UNSUPPORTED; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; position.x = x; position.y = y; return CoreLayerContext_SetScreenPosition( data->context, &position ); } static DFBResult IDirectFBDisplayLayer_SetScreenRectangle( IDirectFBDisplayLayer *thiz, int x, int y, int width, int height ) { DFBRectangle rect = { x, y, width, height }; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!D_FLAGS_IS_SET( data->desc.caps, DLCAPS_SCREEN_LOCATION )) return DFB_UNSUPPORTED; if (width <= 0 || height <= 0) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetScreenRectangle( data->context, &rect ); } static DFBResult IDirectFBDisplayLayer_GetStereoDepth( IDirectFBDisplayLayer *thiz, bool *follow_video, int *ret_z ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!(data->context->config.options & DLOP_LR_MONO) && !(data->context->config.options & DLOP_STEREO)) return DFB_INVARG; if (!ret_z || !follow_video) return DFB_INVARG; return dfb_layer_context_get_stereo_depth( data->context, follow_video, ret_z ); } static DFBResult IDirectFBDisplayLayer_SetStereoDepth( IDirectFBDisplayLayer *thiz, bool follow_video, int z ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!follow_video && (z < -DLSO_FIXED_LIMIT || z > DLSO_FIXED_LIMIT)) return DFB_INVARG; if (!(data->context->config.options & DLOP_LR_MONO) && !(data->context->config.options & DLOP_STEREO)) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetStereoDepth( data->context, follow_video, z ); } static DFBResult IDirectFBDisplayLayer_SetOpacity( IDirectFBDisplayLayer *thiz, u8 opacity ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetOpacity( data->context, opacity ); } static DFBResult IDirectFBDisplayLayer_SetSourceRectangle( IDirectFBDisplayLayer *thiz, int x, int y, int width, int height ) { DFBRectangle source = { x, y, width, height }; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (x < 0 || y < 0 || width <= 0 || height <= 0) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetSourceRectangle( data->context, &source ); } static DFBResult IDirectFBDisplayLayer_SetFieldParity( IDirectFBDisplayLayer *thiz, int field ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level != DLSCL_EXCLUSIVE) return DFB_ACCESSDENIED; return CoreLayerContext_SetFieldParity( data->context, field ); } static DFBResult IDirectFBDisplayLayer_SetClipRegions( IDirectFBDisplayLayer *thiz, const DFBRegion *regions, int num_regions, DFBBoolean positive ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!regions || num_regions < 1) return DFB_INVARG; if (num_regions > data->desc.clip_regions) return DFB_UNSUPPORTED; if (data->level != DLSCL_EXCLUSIVE) return DFB_ACCESSDENIED; return CoreLayerContext_SetClipRegions( data->context, regions, num_regions, positive ); } static DFBResult IDirectFBDisplayLayer_SetSrcColorKey( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b ) { DFBColorKey key; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; key.r = r; key.g = g; key.b = b; key.index = -1; return CoreLayerContext_SetSrcColorKey( data->context, &key ); } static DFBResult IDirectFBDisplayLayer_SetDstColorKey( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b ) { DFBColorKey key; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; key.r = r; key.g = g; key.b = b; key.index = -1; return CoreLayerContext_SetDstColorKey( data->context, &key ); } static DFBResult IDirectFBDisplayLayer_GetLevel( IDirectFBDisplayLayer *thiz, int *ret_level ) { DFBResult ret; int lvl; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_level) return DFB_INVARG; ret = dfb_layer_get_level( data->layer, &lvl ); if (ret) return ret; *ret_level = lvl; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_SetLevel( IDirectFBDisplayLayer *thiz, int level ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!D_FLAGS_IS_SET( data->desc.caps, DLCAPS_LEVELS )) return DFB_UNSUPPORTED; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayer_SetLevel( data->layer, level ); } static DFBResult IDirectFBDisplayLayer_SetBackgroundMode( IDirectFBDisplayLayer *thiz, DFBDisplayLayerBackgroundMode mode ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; switch (mode) { case DLBM_DONTCARE: case DLBM_COLOR: case DLBM_IMAGE: case DLBM_TILE: break; default: return DFB_INVARG; } if (!data->stack) return DFB_OK; return CoreWindowStack_BackgroundSetMode( data->stack, mode ); } static DFBResult IDirectFBDisplayLayer_SetBackgroundImage( IDirectFBDisplayLayer *thiz, IDirectFBSurface *surface ) { IDirectFBSurface_data *surface_data; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!surface) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; surface_data = surface->priv; if (!surface_data) return DFB_DEAD; if (!surface_data->surface) return DFB_DESTROYED; if (!data->stack) return DFB_OK; CoreGraphicsStateClient_Flush( &surface_data->state_client ); return CoreWindowStack_BackgroundSetImage( data->stack, surface_data->surface ); } static DFBResult IDirectFBDisplayLayer_SetBackgroundColor( IDirectFBDisplayLayer *thiz, u8 r, u8 g, u8 b, u8 a ) { DFBColor color = { a, r, g, b }; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; return CoreWindowStack_BackgroundSetColor( data->stack, &color ); } static DFBResult IDirectFBDisplayLayer_GetColorAdjustment( IDirectFBDisplayLayer *thiz, DFBColorAdjustment *ret_adj ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_adj) return DFB_INVARG; return dfb_layer_context_get_coloradjustment( data->context, ret_adj ); } static DFBResult IDirectFBDisplayLayer_SetColorAdjustment( IDirectFBDisplayLayer *thiz, const DFBColorAdjustment *adj ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!adj || (adj->flags & ~DCAF_ALL)) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!adj->flags) return DFB_OK; return CoreLayerContext_SetColorAdjustment( data->context, adj ); } static DFBResult IDirectFBDisplayLayer_CreateWindow( IDirectFBDisplayLayer *thiz, const DFBWindowDescription *desc, IDirectFBWindow **ret_interface ) { CoreWindow *window; DFBResult ret; DFBWindowDescription wd; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) memset( &wd, 0, sizeof(wd) ); wd.flags = DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_POSX | DWDESC_POSY; wd.width = (desc->flags & DWDESC_WIDTH) ? desc->width : 480; wd.height = (desc->flags & DWDESC_HEIGHT) ? desc->height : 300; wd.posx = (desc->flags & DWDESC_POSX) ? desc->posx : 100; wd.posy = (desc->flags & DWDESC_POSY) ? desc->posy : 100; D_DEBUG_AT( Layer, "%s( %p ) <- %4d,%4d-%4dx%4d )\n", __FUNCTION__, thiz, wd.posx, wd.posy, wd.width, wd.height ); if (wd.width < 1 || wd.width > 4096 || wd.height < 1 || wd.height > 4096) return DFB_INVARG; if (desc->flags & DWDESC_CAPS) { if ((desc->caps & ~DWCAPS_ALL) || !ret_interface) return DFB_INVARG; wd.flags |= DWDESC_CAPS; wd.caps = desc->caps; } if (desc->flags & DWDESC_PIXELFORMAT) { wd.flags |= DWDESC_PIXELFORMAT; wd.pixelformat = desc->pixelformat; } if (desc->flags & DWDESC_COLORSPACE) { wd.flags |= DWDESC_COLORSPACE; wd.colorspace = desc->colorspace; } if (desc->flags & DWDESC_SURFACE_CAPS) { wd.flags |= DWDESC_SURFACE_CAPS; wd.surface_caps = desc->surface_caps; } if (desc->flags & DWDESC_PARENT) { wd.flags |= DWDESC_PARENT; wd.parent_id = desc->parent_id; } if (desc->flags & DWDESC_OPTIONS) { wd.flags |= DWDESC_OPTIONS; wd.options = desc->options; } if (desc->flags & DWDESC_STACKING) { wd.flags |= DWDESC_STACKING; wd.stacking = desc->stacking; } if (desc->flags & DWDESC_RESOURCE_ID) { wd.flags |= DWDESC_RESOURCE_ID; wd.resource_id = desc->resource_id; } if (desc->flags & DWDESC_TOPLEVEL_ID) { wd.flags |= DWDESC_TOPLEVEL_ID; wd.toplevel_id = desc->toplevel_id; } ret = CoreLayerContext_CreateWindow( data->context, &wd, &window ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBWindow ); return IDirectFBWindow_Construct( *ret_interface, window, data->layer, data->core, data->idirectfb, true ); } static DFBResult IDirectFBDisplayLayer_GetWindow( IDirectFBDisplayLayer *thiz, DFBWindowID window_id, IDirectFBWindow **ret_interface ) { DFBResult ret; CoreWindow *window; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p, id %u )\n", __FUNCTION__, thiz, window_id ); if (!ret_interface) return DFB_INVARG; /* IDirectFBWindow_Construct won't ref it, so we don't unref it */ ret = CoreLayerContext_FindWindow( data->context, window_id, &window ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBWindow ); return IDirectFBWindow_Construct( *ret_interface, window, data->layer, data->core, data->idirectfb, false ); } static DFBResult IDirectFBDisplayLayer_EnableCursor( IDirectFBDisplayLayer *thiz, int enable ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; return CoreWindowStack_CursorEnable( data->stack, enable ); } static DFBResult IDirectFBDisplayLayer_GetCursorPosition( IDirectFBDisplayLayer *thiz, int *ret_x, int *ret_y ) { DFBResult ret; DFBPoint point; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_x && !ret_y) return DFB_INVARG; if (!data->stack) return DFB_ACCESSDENIED; ret = CoreWindowStack_CursorGetPosition( data->stack, &point ); if (ret) return ret; if (ret_x) *ret_x = point.x; if (ret_y) *ret_y = point.y; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_WarpCursor( IDirectFBDisplayLayer *thiz, int x, int y ) { DFBPoint point = { x, y }; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; return CoreWindowStack_CursorWarp( data->stack, &point ); } static DFBResult IDirectFBDisplayLayer_SetCursorAcceleration( IDirectFBDisplayLayer *thiz, int numerator, int denominator, int threshold ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (numerator < 0 || denominator < 1 || threshold < 0) return DFB_INVARG; if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; return CoreWindowStack_CursorSetAcceleration( data->stack, numerator, denominator, threshold ); } static DFBResult IDirectFBDisplayLayer_SetCursorShape( IDirectFBDisplayLayer *thiz, IDirectFBSurface *shape, int hot_x, int hot_y ) { DFBPoint hotspot; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; if (shape) { IDirectFBSurface_data *shape_data = shape->priv; if (!shape_data) return DFB_DEAD; if (!shape_data->surface) return DFB_DESTROYED; if (hot_x < 0 || hot_y < 0 || hot_x >= shape_data->surface->config.size.w || hot_y >= shape_data->surface->config.size.h) return DFB_INVARG; hotspot.x = hot_x; hotspot.y = hot_y; return CoreWindowStack_CursorSetShape( data->stack, shape_data->surface, &hotspot ); } else { hotspot.x = 0; hotspot.y = 0; return CoreWindowStack_CursorSetShape( data->stack, NULL, &hotspot ); } } static DFBResult IDirectFBDisplayLayer_SetCursorOpacity( IDirectFBDisplayLayer *thiz, u8 opacity ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; if (!data->stack) return DFB_OK; return CoreWindowStack_CursorSetOpacity( data->stack, opacity ); } static DFBResult IDirectFBDisplayLayer_WaitForSync( IDirectFBDisplayLayer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); return CoreLayer_WaitVSync( data->layer ); } static DFBResult IDirectFBDisplayLayer_SwitchContext( IDirectFBDisplayLayer *thiz, DFBBoolean exclusive ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!exclusive && data->level == DLSCL_EXCLUSIVE) { DFBResult ret; CoreLayerContext *context; ret = CoreLayer_GetPrimaryContext( data->layer, false, &context ); if (ret) return ret; CoreLayer_ActivateContext( data->layer, context ); dfb_layer_context_unref( context ); } else CoreLayer_ActivateContext( data->layer, data->context ); data->switch_exclusive = exclusive; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_SetRotation( IDirectFBDisplayLayer *thiz, int rotation ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->level == DLSCL_SHARED) return DFB_ACCESSDENIED; return CoreLayerContext_SetRotation( data->context, rotation ); } static DFBResult IDirectFBDisplayLayer_GetRotation( IDirectFBDisplayLayer *thiz, int *ret_rotation ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_rotation) return DFB_INVARG; *ret_rotation = data->context->rotation; return DFB_OK; } static DFBResult IDirectFBDisplayLayer_GetWindowByResourceID( IDirectFBDisplayLayer *thiz, unsigned long resource_id, IDirectFBWindow **ret_interface ) { DFBResult ret; CoreWindow *window; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; ret = CoreLayerContext_FindWindowByResourceID( data->context, resource_id, &window ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBWindow ); return IDirectFBWindow_Construct( *ret_interface, window, data->layer, data->core, data->idirectfb, false ); } static DFBResult IDirectFBDisplayLayer_SetSurface( IDirectFBDisplayLayer *thiz, IDirectFBSurface *surface ) { IDirectFBSurface_data *surface_data; DIRECT_INTERFACE_GET_DATA( IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); if (!surface) return DFB_INVARG; if (data->level != DLSCL_EXCLUSIVE) return DFB_ACCESSDENIED; surface_data = surface->priv; if (!surface_data) return DFB_DEAD; return CoreLayerRegion_SetSurface( data->region, surface_data->surface ); } DFBResult IDirectFBDisplayLayer_Construct( IDirectFBDisplayLayer *thiz, CoreLayer *layer, CoreDFB *core, IDirectFB *idirectfb ) { DFBResult ret; CoreLayerContext *context; CoreLayerRegion *region; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBDisplayLayer ) D_DEBUG_AT( Layer, "%s( %p )\n", __FUNCTION__, thiz ); ret = CoreLayer_GetPrimaryContext( layer, true, &context ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ) return ret; } ret = CoreLayerContext_GetPrimaryRegion( context, true, ®ion ); if (ret) { dfb_layer_context_unref( context ); DIRECT_DEALLOCATE_INTERFACE( thiz ) return ret; } data->ref = 1; data->layer = layer; data->core = core; data->idirectfb = idirectfb; data->screen = layer->screen; data->context = context; data->region = region; data->stack = dfb_layer_context_windowstack( context ); data->switch_exclusive = DFB_TRUE; dfb_layer_get_description( data->layer, &data->desc ); thiz->AddRef = IDirectFBDisplayLayer_AddRef; thiz->Release = IDirectFBDisplayLayer_Release; thiz->GetID = IDirectFBDisplayLayer_GetID; thiz->GetDescription = IDirectFBDisplayLayer_GetDescription; thiz->GetSourceDescriptions = IDirectFBDisplayLayer_GetSourceDescriptions; thiz->GetCurrentOutputField = IDirectFBDisplayLayer_GetCurrentOutputField; thiz->GetSurface = IDirectFBDisplayLayer_GetSurface; thiz->GetScreen = IDirectFBDisplayLayer_GetScreen; thiz->SetCooperativeLevel = IDirectFBDisplayLayer_SetCooperativeLevel; thiz->GetConfiguration = IDirectFBDisplayLayer_GetConfiguration; thiz->TestConfiguration = IDirectFBDisplayLayer_TestConfiguration; thiz->SetConfiguration = IDirectFBDisplayLayer_SetConfiguration; thiz->SetScreenLocation = IDirectFBDisplayLayer_SetScreenLocation; thiz->SetScreenPosition = IDirectFBDisplayLayer_SetScreenPosition; thiz->SetScreenRectangle = IDirectFBDisplayLayer_SetScreenRectangle; thiz->GetStereoDepth = IDirectFBDisplayLayer_GetStereoDepth; thiz->SetStereoDepth = IDirectFBDisplayLayer_SetStereoDepth; thiz->SetOpacity = IDirectFBDisplayLayer_SetOpacity; thiz->SetSourceRectangle = IDirectFBDisplayLayer_SetSourceRectangle; thiz->SetFieldParity = IDirectFBDisplayLayer_SetFieldParity; thiz->SetClipRegions = IDirectFBDisplayLayer_SetClipRegions; thiz->SetSrcColorKey = IDirectFBDisplayLayer_SetSrcColorKey; thiz->SetDstColorKey = IDirectFBDisplayLayer_SetDstColorKey; thiz->GetLevel = IDirectFBDisplayLayer_GetLevel; thiz->SetLevel = IDirectFBDisplayLayer_SetLevel; thiz->SetBackgroundMode = IDirectFBDisplayLayer_SetBackgroundMode; thiz->SetBackgroundImage = IDirectFBDisplayLayer_SetBackgroundImage; thiz->SetBackgroundColor = IDirectFBDisplayLayer_SetBackgroundColor; thiz->GetColorAdjustment = IDirectFBDisplayLayer_GetColorAdjustment; thiz->SetColorAdjustment = IDirectFBDisplayLayer_SetColorAdjustment; thiz->CreateWindow = IDirectFBDisplayLayer_CreateWindow; thiz->GetWindow = IDirectFBDisplayLayer_GetWindow; thiz->EnableCursor = IDirectFBDisplayLayer_EnableCursor; thiz->GetCursorPosition = IDirectFBDisplayLayer_GetCursorPosition; thiz->WarpCursor = IDirectFBDisplayLayer_WarpCursor; thiz->SetCursorAcceleration = IDirectFBDisplayLayer_SetCursorAcceleration; thiz->SetCursorShape = IDirectFBDisplayLayer_SetCursorShape; thiz->SetCursorOpacity = IDirectFBDisplayLayer_SetCursorOpacity; thiz->WaitForSync = IDirectFBDisplayLayer_WaitForSync; thiz->SwitchContext = IDirectFBDisplayLayer_SwitchContext; thiz->SetRotation = IDirectFBDisplayLayer_SetRotation; thiz->GetRotation = IDirectFBDisplayLayer_GetRotation; thiz->GetWindowByResourceID = IDirectFBDisplayLayer_GetWindowByResourceID; thiz->SetSurface = IDirectFBDisplayLayer_SetSurface; return DFB_OK; } ================================================ FILE: src/display/idirectfbdisplaylayer.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBDISPLAYLAYER_H__ #define __DISPLAY__IDIRECTFBDISPLAYLAYER_H__ #include /* * initializes interface struct and private data */ DFBResult IDirectFBDisplayLayer_Construct( IDirectFBDisplayLayer *thiz, CoreLayer *layer, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/display/idirectfbpalette.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include D_DEBUG_DOMAIN( Palette, "IDirectFBPalette", "IDirectFBPalette Interface" ); /**********************************************************************************************************************/ static void IDirectFBPalette_Destruct( IDirectFBPalette *thiz ) { IDirectFBPalette_data *data = thiz->priv; D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (data->palette) dfb_palette_unref( data->palette ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBPalette_AddRef( IDirectFBPalette *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBPalette_Release( IDirectFBPalette *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBPalette_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBPalette_GetCapabilities( IDirectFBPalette *thiz, DFBPaletteCapabilities *ret_caps ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!ret_caps) return DFB_INVARG; *ret_caps = DPCAPS_NONE; return DFB_OK; } static DFBResult IDirectFBPalette_GetSize( IDirectFBPalette *thiz, unsigned int *ret_size ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!ret_size) return DFB_INVARG; *ret_size = data->palette->num_entries; return DFB_OK; } static DFBResult IDirectFBPalette_SetEntries( IDirectFBPalette *thiz, const DFBColor *entries, unsigned int num_entries, unsigned int offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!entries || offset + num_entries > data->palette->num_entries) return DFB_INVARG; return CorePalette_SetEntries( data->palette, entries, num_entries, offset ); } static DFBResult IDirectFBPalette_GetEntries( IDirectFBPalette *thiz, DFBColor *ret_entries, unsigned int num_entries, unsigned int offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!ret_entries || offset + num_entries > data->palette->num_entries) return DFB_INVARG; direct_memcpy( ret_entries, data->palette->entries + offset, num_entries * sizeof(DFBColor) ); return DFB_OK; } static DFBResult IDirectFBPalette_FindBestMatch( IDirectFBPalette *thiz, u8 r, u8 g, u8 b, u8 a, unsigned int *ret_index ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_index) return DFB_INVARG; if (!data->palette) return DFB_DESTROYED; *ret_index = dfb_palette_search( data->palette, r, g, b, a ); return DFB_OK; } static DFBResult IDirectFBPalette_CreateCopy( IDirectFBPalette *thiz, IDirectFBPalette **ret_interface ) { DFBResult ret; IDirectFBPalette *iface; CorePalette *palette = NULL; DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!ret_interface) return DFB_INVARG; ret = CoreDFB_CreatePalette( data->core, data->palette->num_entries, data->palette->colorspace, &palette ); if (ret) return ret; CorePalette_SetEntries( palette, data->palette->entries, palette->num_entries, 0 ); DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBPalette ); ret = IDirectFBPalette_Construct( iface, palette, data->core ); dfb_palette_unref( palette ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFBPalette_SetEntriesYUV( IDirectFBPalette *thiz, const DFBColorYUV *entries, unsigned int num_entries, unsigned int offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!entries || offset + num_entries > data->palette->num_entries) return DFB_INVARG; return CorePalette_SetEntriesYUV( data->palette, entries, num_entries, offset ); } static DFBResult IDirectFBPalette_GetEntriesYUV( IDirectFBPalette *thiz, DFBColorYUV *ret_entries, unsigned int num_entries, unsigned int offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->palette) return DFB_DESTROYED; if (!ret_entries || offset + num_entries > data->palette->num_entries) return DFB_INVARG; direct_memcpy( ret_entries, data->palette->entries_yuv + offset, num_entries * sizeof(DFBColorYUV) ); return DFB_OK; } static DFBResult IDirectFBPalette_FindBestMatchYUV( IDirectFBPalette *thiz, u8 y, u8 u, u8 v, u8 a, unsigned int *ret_index ) { int r, g, b; DIRECT_INTERFACE_GET_DATA( IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_index) return DFB_INVARG; if (!data->palette) return DFB_DESTROYED; if (data->palette->colorspace == DSCS_BT601) YCBCR_TO_RGB_BT601( y, u, v, r, g, b ); else if (data->palette->colorspace == DSCS_RGB || data->palette->colorspace == DSCS_BT709) YCBCR_TO_RGB_BT709( y, u, v, r, g, b ); else if (data->palette->colorspace == DSCS_BT2020) YCBCR_TO_RGB_BT2020( y, u, v, r, g, b ); else r = g = b = 0; *ret_index = dfb_palette_search( data->palette, r, g, b, a ); return DFB_OK; } DFBResult IDirectFBPalette_Construct( IDirectFBPalette *thiz, CorePalette *palette, CoreDFB *core ) { DFBResult ret; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBPalette ) D_DEBUG_AT( Palette, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_palette_ref( palette ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } data->ref = 1; data->palette = palette; data->core = core; thiz->AddRef = IDirectFBPalette_AddRef; thiz->Release = IDirectFBPalette_Release; thiz->GetCapabilities = IDirectFBPalette_GetCapabilities; thiz->GetSize = IDirectFBPalette_GetSize; thiz->SetEntries = IDirectFBPalette_SetEntries; thiz->GetEntries = IDirectFBPalette_GetEntries; thiz->FindBestMatch = IDirectFBPalette_FindBestMatch; thiz->CreateCopy = IDirectFBPalette_CreateCopy; thiz->SetEntriesYUV = IDirectFBPalette_SetEntriesYUV; thiz->GetEntriesYUV = IDirectFBPalette_GetEntriesYUV; thiz->FindBestMatchYUV = IDirectFBPalette_FindBestMatchYUV; return DFB_OK; } ================================================ FILE: src/display/idirectfbpalette.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBPALETTE_H__ #define __DISPLAY__IDIRECTFBPALETTE_H__ #include /* * private data struct of IDirectFBPalette */ typedef struct { int ref; /* reference counter */ CorePalette *palette; /* the palette object */ CoreDFB *core; } IDirectFBPalette_data; /* * initializes interface struct and private data */ DFBResult IDirectFBPalette_Construct( IDirectFBPalette *thiz, CorePalette *palette, CoreDFB *core ); #endif ================================================ FILE: src/display/idirectfbscreen.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Screen, "IDirectFBScreen", "IDirectFBScreen Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBScreen */ typedef struct { int ref; /* reference counter */ CoreScreen *screen; /* the screen object */ DFBScreenID id; /* screen id */ DFBScreenDescription desc; /* description of the display encoder capabilities */ } IDirectFBScreen_data; static DFBResult PatchMixerConfig ( DFBScreenMixerConfig *patched, const DFBScreenMixerConfig *patch ); static DFBResult PatchEncoderConfig( DFBScreenEncoderConfig *patched, const DFBScreenEncoderConfig *patch ); static DFBResult PatchOutputConfig ( DFBScreenOutputConfig *patched, const DFBScreenOutputConfig *patch ); typedef struct { CoreScreen *screen; DFBDisplayLayerCallback callback; void *callback_ctx; } EnumDisplayLayers_Context; static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer *layer, void *ctx ); /**********************************************************************************************************************/ static void IDirectFBScreen_Destruct( IDirectFBScreen *thiz ) { D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBScreen_AddRef( IDirectFBScreen *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBScreen_Release( IDirectFBScreen *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBScreen_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBScreen_GetID( IDirectFBScreen *thiz, DFBScreenID *ret_screen_id ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_screen_id) return DFB_INVARG; *ret_screen_id = data->id; return DFB_OK; } static DFBResult IDirectFBScreen_GetDescription( IDirectFBScreen *thiz, DFBScreenDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->desc; return DFB_OK; } static DFBResult IDirectFBScreen_GetSize( IDirectFBScreen *thiz, int *ret_width, int *ret_height ) { DFBResult ret; DFBDimension size; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_width && !ret_height) return DFB_INVARG; ret = CoreScreen_GetScreenSize( data->screen, &size ); if (ret) return ret; if (ret_width) *ret_width = size.w; if (ret_height) *ret_height = size.h; return DFB_OK; } static DFBResult IDirectFBScreen_EnumDisplayLayers( IDirectFBScreen *thiz, DFBDisplayLayerCallback callback, void *callbackdata ) { EnumDisplayLayers_Context context; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!callback) return DFB_INVARG; context.screen = data->screen; context.callback = callback; context.callback_ctx = callbackdata; dfb_layers_enumerate( EnumDisplayLayers_Callback, &context ); return DFB_OK; } static DFBResult IDirectFBScreen_SetPowerMode( IDirectFBScreen *thiz, DFBScreenPowerMode mode ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); switch (mode) { case DSPM_ON: case DSPM_STANDBY: case DSPM_SUSPEND: case DSPM_OFF: break; default: return DFB_INVARG; } return CoreScreen_SetPowerMode( data->screen, mode ); } static DFBResult IDirectFBScreen_WaitForSync( IDirectFBScreen *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); return CoreScreen_WaitVSync( data->screen ); } static DFBResult IDirectFBScreen_GetMixerDescriptions( IDirectFBScreen *thiz, DFBScreenMixerDescription *ret_descriptions ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_descriptions) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_MIXERS)) return DFB_UNSUPPORTED; for (i = 0; i < data->desc.mixers; i++) dfb_screen_get_mixer_info( data->screen, i, &ret_descriptions[i] ); return DFB_OK; } static DFBResult IDirectFBScreen_GetMixerConfiguration( IDirectFBScreen *thiz, int mixer, DFBScreenMixerConfig *ret_config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_config) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_MIXERS)) return DFB_UNSUPPORTED; if (mixer < 0 || mixer >= data->desc.mixers) return DFB_INVARG; return dfb_screen_get_mixer_config( data->screen, mixer, ret_config ); } static DFBResult IDirectFBScreen_TestMixerConfiguration( IDirectFBScreen *thiz, int mixer, const DFBScreenMixerConfig *config, DFBScreenMixerConfigFlags *ret_failed ) { DFBResult ret; DFBScreenMixerConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSMCONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_MIXERS)) return DFB_UNSUPPORTED; if (mixer < 0 || mixer >= data->desc.mixers) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_mixer_config( data->screen, mixer, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchMixerConfig( &patched, config ); if (ret) return ret; /* Test the patched configuration. */ return CoreScreen_TestMixerConfig( data->screen, mixer, &patched, ret_failed ); } static DFBResult IDirectFBScreen_SetMixerConfiguration( IDirectFBScreen *thiz, int mixer, const DFBScreenMixerConfig *config ) { DFBResult ret; DFBScreenMixerConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSMCONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_MIXERS)) return DFB_UNSUPPORTED; if (mixer < 0 || mixer >= data->desc.mixers) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_mixer_config( data->screen, mixer, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchMixerConfig( &patched, config ); if (ret) return ret; /* Set the patched configuration. */ return CoreScreen_SetMixerConfig( data->screen, mixer, &patched ); } static DFBResult IDirectFBScreen_GetEncoderDescriptions( IDirectFBScreen *thiz, DFBScreenEncoderDescription *ret_descriptions ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_descriptions) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_ENCODERS)) return DFB_UNSUPPORTED; for (i = 0; i < data->desc.encoders; i++) dfb_screen_get_encoder_info( data->screen, i, &ret_descriptions[i] ); return DFB_OK; } static DFBResult IDirectFBScreen_GetEncoderConfiguration( IDirectFBScreen *thiz, int encoder, DFBScreenEncoderConfig *ret_config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_config) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_ENCODERS)) return DFB_UNSUPPORTED; if (encoder < 0 || encoder >= data->desc.encoders) return DFB_INVARG; return dfb_screen_get_encoder_config( data->screen, encoder, ret_config ); } static DFBResult IDirectFBScreen_TestEncoderConfiguration( IDirectFBScreen *thiz, int encoder, const DFBScreenEncoderConfig *config, DFBScreenEncoderConfigFlags *ret_failed ) { DFBResult ret; DFBScreenEncoderConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSECONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_ENCODERS)) return DFB_UNSUPPORTED; if (encoder < 0 || encoder >= data->desc.encoders) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_encoder_config( data->screen, encoder, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchEncoderConfig( &patched, config ); if (ret) return ret; /* Test the patched configuration. */ return CoreScreen_TestEncoderConfig( data->screen, encoder, &patched, ret_failed ); } static DFBResult IDirectFBScreen_SetEncoderConfiguration( IDirectFBScreen *thiz, int encoder, const DFBScreenEncoderConfig *config ) { DFBResult ret; DFBScreenEncoderConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSECONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_ENCODERS)) return DFB_UNSUPPORTED; if (encoder < 0 || encoder >= data->desc.encoders) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_encoder_config( data->screen, encoder, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchEncoderConfig( &patched, config ); if (ret) return ret; /* Set the patched configuration. */ return CoreScreen_SetEncoderConfig( data->screen, encoder, &patched ); } static DFBResult IDirectFBScreen_GetOutputDescriptions( IDirectFBScreen *thiz, DFBScreenOutputDescription *ret_descriptions ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_descriptions) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_OUTPUTS)) return DFB_UNSUPPORTED; for (i = 0; i < data->desc.outputs; i++) dfb_screen_get_output_info( data->screen, i, &ret_descriptions[i] ); return DFB_OK; } static DFBResult IDirectFBScreen_GetOutputConfiguration( IDirectFBScreen *thiz, int output, DFBScreenOutputConfig *ret_config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_config) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_OUTPUTS)) return DFB_UNSUPPORTED; if (output < 0 || output >= data->desc.outputs) return DFB_INVARG; return dfb_screen_get_output_config( data->screen, output, ret_config ); } static DFBResult IDirectFBScreen_TestOutputConfiguration( IDirectFBScreen *thiz, int output, const DFBScreenOutputConfig *config, DFBScreenOutputConfigFlags *ret_failed ) { DFBResult ret; DFBScreenOutputConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSOCONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_OUTPUTS)) return DFB_UNSUPPORTED; if (output < 0 || output >= data->desc.outputs) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_output_config( data->screen, output, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchOutputConfig( &patched, config ); if (ret) return ret; /* Test the patched configuration. */ return CoreScreen_TestOutputConfig( data->screen, output, &patched, ret_failed ); } static DFBResult IDirectFBScreen_SetOutputConfiguration( IDirectFBScreen *thiz, int output, const DFBScreenOutputConfig *config ) { DFBResult ret; DFBScreenOutputConfig patched; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); if (!config || (config->flags & ~DSOCONF_ALL)) return DFB_INVARG; if (!(data->desc.caps & DSCCAPS_OUTPUTS)) return DFB_UNSUPPORTED; if (output < 0 || output >= data->desc.outputs) return DFB_INVARG; /* Get the current configuration. */ ret = dfb_screen_get_output_config( data->screen, output, &patched ); if (ret) return ret; /* Patch the configuration. */ ret = PatchOutputConfig( &patched, config ); if (ret) return ret; /* Set the patched configuration. */ return CoreScreen_SetOutputConfig( data->screen, output, &patched ); } static DFBResult IDirectFBScreen_GetVSyncCount( IDirectFBScreen *thiz, unsigned long *ret_count ) { DFBResult ret; u64 count; DIRECT_INTERFACE_GET_DATA( IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); D_ASSERT( ret_count != NULL ); ret = CoreScreen_GetVSyncCount( data->screen, &count ); if (ret) return ret; *ret_count = count; return DFB_OK; } DFBResult IDirectFBScreen_Construct( IDirectFBScreen *thiz, CoreScreen *screen ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBScreen ) D_DEBUG_AT( Screen, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->screen = screen; data->id = dfb_screen_id_translated( screen ); dfb_screen_get_info( screen, NULL, &data->desc ); thiz->AddRef = IDirectFBScreen_AddRef; thiz->Release = IDirectFBScreen_Release; thiz->GetID = IDirectFBScreen_GetID; thiz->GetDescription = IDirectFBScreen_GetDescription; thiz->GetSize = IDirectFBScreen_GetSize; thiz->EnumDisplayLayers = IDirectFBScreen_EnumDisplayLayers; thiz->SetPowerMode = IDirectFBScreen_SetPowerMode; thiz->WaitForSync = IDirectFBScreen_WaitForSync; thiz->GetMixerDescriptions = IDirectFBScreen_GetMixerDescriptions; thiz->GetMixerConfiguration = IDirectFBScreen_GetMixerConfiguration; thiz->TestMixerConfiguration = IDirectFBScreen_TestMixerConfiguration; thiz->SetMixerConfiguration = IDirectFBScreen_SetMixerConfiguration; thiz->GetEncoderDescriptions = IDirectFBScreen_GetEncoderDescriptions; thiz->GetEncoderConfiguration = IDirectFBScreen_GetEncoderConfiguration; thiz->TestEncoderConfiguration = IDirectFBScreen_TestEncoderConfiguration; thiz->SetEncoderConfiguration = IDirectFBScreen_SetEncoderConfiguration; thiz->GetOutputDescriptions = IDirectFBScreen_GetOutputDescriptions; thiz->GetOutputConfiguration = IDirectFBScreen_GetOutputConfiguration; thiz->TestOutputConfiguration = IDirectFBScreen_TestOutputConfiguration; thiz->SetOutputConfiguration = IDirectFBScreen_SetOutputConfiguration; thiz->GetVSyncCount = IDirectFBScreen_GetVSyncCount; return DFB_OK; } /**********************************************************************************************************************/ static DFBResult PatchMixerConfig( DFBScreenMixerConfig *patched, const DFBScreenMixerConfig *patch ) { /* Check for unsupported flags. */ if (patch->flags & ~patched->flags) return DFB_UNSUPPORTED; if (patch->flags & DSMCONF_TREE) patched->tree = patch->tree; if (patch->flags & DSMCONF_LEVEL) patched->level = patch->level; if (patch->flags & DSMCONF_LAYERS) patched->layers = patch->layers; if (patch->flags & DSMCONF_BACKGROUND) patched->background = patch->background; return DFB_OK; } static DFBResult PatchEncoderConfig( DFBScreenEncoderConfig *patched, const DFBScreenEncoderConfig *patch ) { /* Check for unsupported flags. */ if (patch->flags & ~patched->flags) return DFB_UNSUPPORTED; if (patch->flags & DSECONF_RESOLUTION) patched->resolution = patch->resolution; if (patch->flags & DSECONF_FREQUENCY) patched->frequency = patch->frequency; /* If you have set a DSECONF_TV_STANDARD, this will override the resolution and frequency chosen above.*/ if (patch->flags & DSECONF_TV_STANDARD) { patched->tv_standard = patch->tv_standard; switch (patched->tv_standard) { case DSETV_PAL: case DSETV_PAL_BG: case DSETV_PAL_I: case DSETV_PAL_N: case DSETV_PAL_NC: patched->resolution = DSOR_720_576; patched->frequency = DSEF_50HZ; break; case DSETV_PAL_60: case DSETV_PAL_M: patched->resolution = DSOR_720_480; patched->frequency = DSEF_59_94HZ; break; case DSETV_SECAM: patched->resolution = DSOR_720_576; patched->frequency = DSEF_50HZ; break; case DSETV_NTSC: case DSETV_NTSC_M_JPN: case DSETV_NTSC_443: patched->resolution = DSOR_720_480; patched->frequency = DSEF_59_94HZ; break; default: break; } } if (patch->flags & DSECONF_TEST_PICTURE) patched->test_picture = patch->test_picture; if (patch->flags & DSECONF_MIXER) patched->mixer = patch->mixer; if (patch->flags & DSECONF_OUT_SIGNALS) patched->out_signals = patch->out_signals; if (patch->flags & DSECONF_SCANMODE) patched->scanmode = patch->scanmode; if (patch->flags & DSECONF_TEST_COLOR) patched->test_color = patch->test_color; if (patch->flags & DSECONF_ADJUSTMENT) patched->adjustment = patch->adjustment; if (patch->flags & DSECONF_CONNECTORS) patched->out_connectors = patch->out_connectors; if (patch->flags & DSECONF_SLOW_BLANKING) patched->slow_blanking = patch->slow_blanking; if (patch->flags & DSECONF_FRAMING) patched->framing = patch->framing; if (patch->flags & DSECONF_ASPECT_RATIO) patched->aspect_ratio = patch->aspect_ratio; return DFB_OK; } static DFBResult PatchOutputConfig( DFBScreenOutputConfig *patched, const DFBScreenOutputConfig *patch ) { /* Check for unsupported flags. */ if (patch->flags & ~patched->flags) return DFB_UNSUPPORTED; if (patch->flags & DSOCONF_ENCODER) patched->encoder = patch->encoder; if (patch->flags & DSOCONF_SIGNALS) patched->out_signals = patch->out_signals; if (patch->flags & DSOCONF_CONNECTORS) patched->out_connectors = patch->out_connectors; if (patch->flags & DSOCONF_SLOW_BLANKING) patched->slow_blanking = patch->slow_blanking; if (patch->flags & DSOCONF_RESOLUTION) patched->resolution = patch->resolution; return DFB_OK; } static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer *layer, void *ctx ) { DFBDisplayLayerDescription desc; DFBDisplayLayerID id; EnumDisplayLayers_Context *context = ctx; if (layer->screen != context->screen) return DFENUM_OK; id = dfb_layer_id_translated( layer ); if (dfb_config->primary_only && id != DLID_PRIMARY) return DFENUM_OK; dfb_layer_get_description( layer, &desc ); return context->callback( id, desc, context->callback_ctx ); } ================================================ FILE: src/display/idirectfbscreen.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBSCREEN_H__ #define __DISPLAY__IDIRECTFBSCREEN_H__ #include /* * initializes interface struct and private data */ DFBResult IDirectFBScreen_Construct( IDirectFBScreen *thiz, CoreScreen *screen ); #endif ================================================ FILE: src/display/idirectfbsurface.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Surface, "IDirectFBSurface", "IDirectFBSurface Interface" ); D_DEBUG_DOMAIN( Surface_Updates, "IDirectFBSurface/Updates", "IDirectFBSurface Interface Updates" ); /**********************************************************************************************************************/ static DFBResult register_prealloc( IDirectFBSurface_data *data ) { DFBResult ret; unsigned int i; if (data->surface->config.caps & DSCAPS_TRIPLE) data->memory_permissions_count = 3; else if (data->surface->config.caps & DSCAPS_DOUBLE) data->memory_permissions_count = 2; else data->memory_permissions_count = 1; for (i = 0; i < data->memory_permissions_count; i++) { ret = dfb_core_memory_permissions_add( data->core, CMPF_READ | CMPF_WRITE, data->surface->config.preallocated[i].addr, data->surface->config.preallocated[i].pitch * DFB_PLANE_MULTIPLY( data->surface->config.format, data->surface->config.size.h ), &data->memory_permissions[i] ); if (ret) goto error; } return DFB_OK; error: for (--i; i >= 0; i--) dfb_core_memory_permissions_remove( data->core, data->memory_permissions[i] ); data->memory_permissions_count = 0; return ret; } static DFBResult unregister_prealloc( IDirectFBSurface_data *data ) { unsigned int i; for (i = 0; i < data->memory_permissions_count; i++) dfb_core_memory_permissions_remove( data->core, data->memory_permissions[i] ); data->memory_permissions_count = 0; return DFB_OK; } /**********************************************************************************************************************/ void IDirectFBSurface_Destruct( IDirectFBSurface *thiz ) { IDirectFBSurface_data *data = thiz->priv; IDirectFBSurface *parent; unsigned int i; D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); direct_mutex_lock( &data->children_lock ); while (data->children_free) { IDirectFBSurface_data *child_data; IDirectFBSurface *child; child_data = (IDirectFBSurface_data*) data->children_free; direct_list_remove( &data->children_free, &child_data->link ); direct_mutex_unlock( &data->children_lock ); child = child_data->thiz; child->Release( child ); direct_mutex_lock( &data->children_lock ); } direct_mutex_unlock( &data->children_lock ); if (data->memory_permissions_count) { CoreDFB_WaitIdle( data->core ); unregister_prealloc( data ); } else CoreGraphicsStateClient_Flush( &data->state_client ); if (data->surface_client) dfb_surface_client_unref( data->surface_client ); parent = data->parent; if (parent) { IDirectFBSurface_data *parent_data; D_MAGIC_ASSERT( parent, DirectInterface ); parent_data = parent->priv; D_ASSERT( parent_data != NULL ); direct_mutex_lock( &parent_data->children_lock ); direct_list_remove( &parent_data->children_data, &data->link ); direct_mutex_unlock( &parent_data->children_lock ); } if (data->surface) { dfb_surface_detach( data->surface, &data->reaction ); dfb_surface_detach( data->surface, &data->reaction_frame ); } CoreGraphicsStateClient_Deinit( &data->state_client ); dfb_state_stop_drawing( &data->state ); dfb_state_set_destination( &data->state, NULL ); dfb_state_set_source( &data->state, NULL ); dfb_state_set_source_mask( &data->state, NULL ); dfb_state_set_source2( &data->state, NULL ); dfb_state_destroy( &data->state ); if (data->font) data->font->Release( data->font ); if (data->surface) { if (data->locked) dfb_surface_unlock_buffer( data->surface, &data->lock ); dfb_surface_unref( data->surface ); } for (i = 0; i < data->local_buffer_count; i++) { if (data->allocations[i]) { dfb_surface_allocation_unref( data->allocations[i] ); data->allocations[i] = NULL; } } direct_mutex_deinit( &data->children_lock ); direct_waitqueue_deinit( &data->back_buffer_wq ); direct_mutex_deinit( &data->back_buffer_lock ); direct_mutex_deinit( &data->surface_client_lock ); DIRECT_DEALLOCATE_INTERFACE( thiz ); if (parent) parent->Release( parent ); } static DirectResult IDirectFBSurface_AddRef( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBSurface_Release( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (data->ref == 1 && data->parent && dfb_config->subsurface_caching) { IDirectFBSurface_data *parent_data; D_MAGIC_ASSERT( data->parent, DirectInterface ); parent_data = data->parent->priv; D_ASSERT( parent_data != NULL ); direct_mutex_lock( &parent_data->children_lock ); direct_list_remove( &parent_data->children_data, &data->link ); direct_list_append( &parent_data->children_free, &data->link ); direct_mutex_unlock( &parent_data->children_lock ); } if (--data->ref == 0) IDirectFBSurface_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBSurface_GetCapabilities( IDirectFBSurface *thiz, DFBSurfaceCapabilities *ret_caps ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_caps) return DFB_INVARG; *ret_caps = data->caps; return DFB_OK; } static DFBResult IDirectFBSurface_GetPosition( IDirectFBSurface *thiz, int *ret_x, int *ret_y ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_x && !ret_y) return DFB_INVARG; if (ret_x) *ret_x = data->area.wanted.x; if (ret_y) *ret_y = data->area.wanted.y; return DFB_OK; } static DFBResult IDirectFBSurface_GetSize( IDirectFBSurface *thiz, int *ret_width, int *ret_height ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_width && !ret_height) return DFB_INVARG; if (ret_width) *ret_width = data->area.wanted.w; if (ret_height) *ret_height = data->area.wanted.h; return DFB_OK; } static DFBResult IDirectFBSurface_GetVisibleRectangle( IDirectFBSurface *thiz, DFBRectangle *ret_rect ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_rect) return DFB_INVARG; ret_rect->x = data->area.current.x - data->area.wanted.x; ret_rect->y = data->area.current.y - data->area.wanted.y; ret_rect->w = data->area.current.w; ret_rect->h = data->area.current.h; return DFB_OK; } static DFBResult IDirectFBSurface_GetPixelFormat( IDirectFBSurface *thiz, DFBSurfacePixelFormat *ret_pixelformat ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!ret_pixelformat) return DFB_INVARG; *ret_pixelformat = data->surface->config.format; return DFB_OK; } static DFBResult IDirectFBSurface_GetColorSpace( IDirectFBSurface *thiz, DFBSurfaceColorSpace *ret_colorspace ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!ret_colorspace) return DFB_INVARG; *ret_colorspace = data->surface->config.colorspace; return DFB_OK; } static DFBResult IDirectFBSurface_GetAccelerationMask( IDirectFBSurface *thiz, IDirectFBSurface *source, DFBAccelerationMask *ret_mask ) { DFBResult ret; DFBAccelerationMask mask; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!ret_mask) return DFB_INVARG; if (source) { IDirectFBSurface_data *src_data = source->priv; dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_source2( &data->state, data->surface ); } ret = CoreGraphicsStateClient_GetAccelerationMask( &data->state_client, &mask ); if (ret) return ret; /* Check text rendering function. */ if (data->font) { IDirectFBFont_data *font_data = data->font->priv; if (dfb_gfxcard_drawstring_check_state( font_data->font, &data->state, &data->state_client, DSTF_NONE )) mask |= DFXL_DRAWSTRING; } *ret_mask = mask; return DFB_OK; } static DFBResult IDirectFBSurface_GetPalette( IDirectFBSurface *thiz, IDirectFBPalette **ret_interface ) { DFBResult ret; CorePalette *palette; IDirectFBPalette *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->surface->palette) return DFB_UNSUPPORTED; if (!ret_interface) return DFB_INVARG; ret = CoreSurface_GetPalette( data->surface, &palette ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBPalette ); ret = IDirectFBPalette_Construct( iface, palette, data->core ); if (ret) goto out; *ret_interface = iface; out: dfb_palette_unref( palette ); return ret; } static DFBResult IDirectFBSurface_SetPalette( IDirectFBSurface *thiz, IDirectFBPalette *palette ) { IDirectFBPalette_data *palette_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!palette) return DFB_INVARG; if (!DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) return DFB_UNSUPPORTED; palette_data = palette->priv; if (!palette_data) return DFB_DEAD; if (!palette_data->palette) return DFB_DESTROYED; CoreSurface_SetPalette( data->surface, palette_data->palette ); return DFB_OK; } static DFBResult IDirectFBSurface_SetAlphaRamp( IDirectFBSurface *thiz, u8 a0, u8 a1, u8 a2, u8 a3 ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; CoreSurface_SetAlphaRamp( data->surface, a0, a1, a2, a3 ); return DFB_OK; } static DFBResult IDirectFBSurface_GetStereoEye( IDirectFBSurface *thiz, DFBSurfaceStereoEye *ret_eye ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, ret_eye ); if (!data->surface) return DFB_DESTROYED; if (!(data->surface->config.caps & DSCAPS_STEREO)) return DFB_UNSUPPORTED; *ret_eye = data->src_eye; return DFB_OK; } static DFBResult IDirectFBSurface_SetStereoEye( IDirectFBSurface *thiz, DFBSurfaceStereoEye eye ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %u )\n", __FUNCTION__, thiz, eye ); if (!data->surface) return DFB_DESTROYED; if (!(data->surface->config.caps & DSCAPS_STEREO)) return DFB_UNSUPPORTED; dfb_state_set_to( &data->state, DSBR_BACK, eye ); data->src_eye = eye; return DFB_OK; } static DFBResult IDirectFBSurface_Lock( IDirectFBSurface *thiz, DFBSurfaceLockFlags flags, void **ret_ptr, int *ret_pitch ) { DFBResult ret; long long ts, ts2; DFBSurfaceBufferRole role = DSBR_FRONT; CoreSurfaceAccessFlags access = CSAF_NONE; D_UNUSED_P( ts ); D_UNUSED_P( ts2 ); DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (data->locked) return DFB_LOCKED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (!flags || !ret_ptr || !ret_pitch) return DFB_INVARG; if (flags & DSLF_READ) access |= CSAF_READ; if (flags & DSLF_WRITE) { access |= CSAF_WRITE; role = DSBR_BACK; } CoreGraphicsStateClient_Flush( &data->state_client ); if (direct_log_domain_check( &Surface )) ts = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); unsigned int index = (data->local_flip_count + role) % data->local_buffer_count; CoreSurfaceAllocation *allocation = data->allocations[index]; if (allocation) { D_DEBUG_AT( Surface, " -> having allocation %p\n", allocation ); if (!allocation->buffer || !direct_serial_check( &allocation->serial, &allocation->buffer->serial )) { D_DEBUG_AT( Surface, " -> outdated!\n" ); dfb_surface_allocation_ref( allocation ); data->allocations[index] = allocation = NULL; } } if (!allocation) { D_DEBUG_AT( Surface, " -> getting allocation from %p\n", data->surface ); ret = CoreSurface_PreLockBuffer3( data->surface, role, data->local_flip_count, data->src_eye, CSAID_CPU, access, true, &allocation ); if (ret) return ret; data->allocations[index] = allocation; } ret = dfb_surface_allocation_ref( allocation ); if (ret) { D_DERROR( ret, "IDirectFBSurface: Ref'ing allocation in '%s' failed!\n", allocation->pool->desc.name ); return ret; } /* Lock the allocation. */ dfb_surface_buffer_lock_init( &data->lock, CSAID_CPU, access ); D_DEBUG_AT( Surface, " -> locking %p\n", allocation ); ret = dfb_surface_pool_lock( allocation->pool, allocation, &data->lock ); if (ret) { D_DERROR( ret, "IDirectFBSurface: Locking allocation in '%s' failed!\n", allocation->pool->desc.name ); dfb_surface_buffer_lock_deinit( &data->lock ); return ret; } if (direct_log_domain_check( &Surface )) { ts2 = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); D_DEBUG_AT( Surface, " -> locking took %lld us\n", ts2 - ts ); } data->locked = true; *ret_ptr = data->lock.addr + data->lock.pitch * data->area.current.y + DFB_BYTES_PER_LINE( data->surface->config.format, data->area.current.x ); *ret_pitch = data->lock.pitch; return DFB_OK; } static DFBResult IDirectFBSurface_GetFramebufferOffset( IDirectFBSurface *thiz, int *offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->locked) return DFB_ACCESSDENIED; if (!data->lock.phys) { /* The surface is probably in a system buffer if there's no physical address. */ return DFB_UNSUPPORTED; } if (!offset) return DFB_INVARG; *offset = data->lock.offset; return DFB_OK; } static DFBResult IDirectFBSurface_Unlock( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (data->locked) { dfb_surface_unlock_buffer( data->surface, &data->lock ); data->locked = false; } return DFB_OK; } DFBResult IDirectFBSurface_Flip( IDirectFBSurface *thiz, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { DFBResult ret = DFB_OK; DFBRegion reg; bool dispatched = false; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, thiz, region, flags ); if (!data->surface) return DFB_DESTROYED; if (data->locked) return DFB_LOCKED; if (!data->area.current.w || !data->area.current.h || (region && (region->x1 > region->x2 || region->y1 > region->y2))) return DFB_INVAREA; if (data->flip_func) return data->flip_func( data->flip_func_ctx ); IDirectFBSurface_StopAll( data ); if (data->parent) { IDirectFBSurface_data *parent_data; parent_data = data->parent->priv; if (!parent_data) return DFB_DEAD; if (parent_data) { /* Signal end of sequence of operations. */ dfb_state_lock( &parent_data->state ); dfb_state_stop_drawing( &parent_data->state ); dfb_state_unlock( &parent_data->state ); } } dfb_region_from_rectangle( ®, &data->area.current ); if (region) { DFBRegion clip = DFB_REGION_INIT_TRANSLATED( region, data->area.wanted.x, data->area.wanted.y ); if (!dfb_region_region_intersect( ®, &clip )) return DFB_INVAREA; } D_DEBUG_AT( Surface, " -> flip %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( ® ) ); CoreGraphicsStateClient_Flush( &data->state_client ); if (dfb_config->force_frametime && !data->current_frame_time) thiz->GetFrameTime( thiz, &data->current_frame_time ); if (data->surface->config.caps & DSCAPS_FLIPPING) { if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && reg.x1 == 0 && reg.y1 == 0 && reg.x2 == data->surface->config.size.w - 1 && reg.y2 == data->surface->config.size.h - 1)) { if (!(flags & DSFLIP_UPDATE)) ++data->local_flip_count; dfb_state_set_destination_2( &data->state, data->surface, data->local_flip_count ); ret = CoreSurface_DispatchUpdate( data->surface, DFB_FALSE, ®, NULL, flags, data->current_frame_time, data->local_flip_count ); dispatched = true; } } if (!dispatched) ret = CoreSurface_Flip2( data->surface, DFB_FALSE, ®, NULL, flags, data->current_frame_time ); data->current_frame_time = 0; if (ret) return ret; if (!(flags & DSFLIP_NOWAIT)) IDirectFBSurface_WaitForBackBuffer( data ); return DFB_OK; } DFBResult IDirectFBSurface_FlipStereo( IDirectFBSurface *thiz, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ) { DFBResult ret = DFB_OK; DFBRegion l_reg, r_reg; bool dispatched = false; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, %p, 0x%08x )\n", __FUNCTION__, thiz, left_region, right_region, flags ); if (!data->surface) return DFB_DESTROYED; if (!(data->surface->config.caps & DSCAPS_STEREO)) return DFB_UNSUPPORTED; if (data->locked) return DFB_LOCKED; if (!data->area.current.w || !data->area.current.h || (left_region && (left_region->x1 > left_region->x2 || left_region->y1 > left_region->y2)) || (right_region && (right_region->x1 > right_region->x2 || right_region->y1 > right_region->y2))) return DFB_INVAREA; IDirectFBSurface_StopAll( data ); if (data->parent) { IDirectFBSurface_data *parent_data; parent_data = data->parent->priv; if (!parent_data) return DFB_DEAD; if (parent_data) { /* Signal end of sequence of operations. */ dfb_state_lock( &parent_data->state ); dfb_state_stop_drawing( &parent_data->state ); dfb_state_unlock( &parent_data->state ); } } dfb_region_from_rectangle( &l_reg, &data->area.current ); dfb_region_from_rectangle( &r_reg, &data->area.current ); if (left_region) { DFBRegion clip = DFB_REGION_INIT_TRANSLATED( left_region, data->area.wanted.x, data->area.wanted.y ); if (!dfb_region_region_intersect( &l_reg, &clip )) return DFB_INVAREA; } if (right_region) { DFBRegion clip = DFB_REGION_INIT_TRANSLATED( right_region, data->area.wanted.x, data->area.wanted.y ); if (!dfb_region_region_intersect( &r_reg, &clip )) return DFB_INVAREA; } D_DEBUG_AT( Surface, " -> flip stereo left: %4d,%4d-%4dx%4d right: %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( &l_reg ), DFB_RECTANGLE_VALS_FROM_REGION( &r_reg ) ); CoreGraphicsStateClient_Flush( &data->state_client ); if (dfb_config->force_frametime && !data->current_frame_time) thiz->GetFrameTime( thiz, &data->current_frame_time ); if (data->surface->config.caps & DSCAPS_FLIPPING) { if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && l_reg.x1 == 0 && l_reg.y1 == 0 && l_reg.x2 == data->surface->config.size.w - 1 && l_reg.y2 == data->surface->config.size.h - 1 && r_reg.x1 == 0 && r_reg.y1 == 0 && r_reg.x2 == data->surface->config.size.w - 1 && r_reg.y2 == data->surface->config.size.h - 1)) { if (!(flags & DSFLIP_UPDATE)) ++data->local_flip_count; ret = CoreSurface_DispatchUpdate( data->surface, DFB_FALSE, &l_reg, &r_reg, flags, data->current_frame_time, data->local_flip_count ); dispatched = true; } } if (!dispatched) ret = CoreSurface_Flip2( data->surface, DFB_FALSE, &l_reg, &r_reg, flags, data->current_frame_time ); dfb_state_set_destination_2( &data->state, data->surface, data->local_flip_count ); data->current_frame_time = 0; if (ret) return ret; if (!(flags & DSFLIP_NOWAIT)) IDirectFBSurface_WaitForBackBuffer( data ); return DFB_OK; } static DFBResult IDirectFBSurface_SetField( IDirectFBSurface *thiz, int field ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!(data->surface->config.caps & DSCAPS_INTERLACED)) return DFB_UNSUPPORTED; if (field < 0 || field > 1) return DFB_INVARG; CoreSurface_SetField( data->surface, field ); return DFB_OK; } static DFBResult IDirectFBSurface_Clear( IDirectFBSurface *thiz, u8 r, u8 g, u8 b, u8 a ) { DFBColor old_color; unsigned int old_index; DFBSurfaceDrawingFlags old_flags; DFBSurfaceRenderOptions old_options; DFBColor color = { a, r, g, b }; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, 0x%08x )\n", __FUNCTION__, thiz, (unsigned int) PIXEL_ARGB( a, r, g, b ) ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; /* Save current color and drawing flags. */ old_color = data->state.color; old_index = data->state.color_index; old_flags = data->state.drawingflags; old_options = data->state.render_options; /* Set drawing flags. */ dfb_state_set_drawing_flags( &data->state, DSDRAW_NOFX ); /* Set render options. */ dfb_state_set_render_options( &data->state, DSRO_NONE ); /* Set color. */ if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) dfb_state_set_color_index( &data->state, dfb_palette_search( data->surface->palette, r, g, b, a ) ); dfb_state_set_color( &data->state, &color ); /* Fill the visible rectangle. */ CoreGraphicsStateClient_FillRectangles( &data->state_client, &data->area.current, 1 ); /* Restore drawing flags. */ dfb_state_set_drawing_flags( &data->state, old_flags ); /* Restore render options. */ dfb_state_set_render_options( &data->state, old_options ); /* Restore color. */ if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) dfb_state_set_color_index( &data->state, old_index ); dfb_state_set_color( &data->state, &old_color ); return DFB_OK; } static DFBResult IDirectFBSurface_SetClip( IDirectFBSurface *thiz, const DFBRegion *clip ) { DFBRegion newclip; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, clip ); D_DEBUG_AT( Surface, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &data->area.wanted ) ); if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (clip) { newclip = DFB_REGION_INIT_TRANSLATED( clip, data->area.wanted.x, data->area.wanted.y ); D_DEBUG_AT( Surface, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( &newclip ) ); if (!dfb_unsafe_region_rectangle_intersect( &newclip, &data->area.wanted )) return DFB_INVARG; D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( &newclip ) ); data->clip_set = true; data->clip_wanted = newclip; if (!dfb_region_rectangle_intersect( &newclip, &data->area.current )) return DFB_INVAREA; } else { dfb_region_from_rectangle( &newclip, &data->area.current ); data->clip_set = false; } D_DEBUG_AT( Surface, " -> clip %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( &newclip ) ); dfb_state_set_clip( &data->state, &newclip ); return DFB_OK; } static DFBResult IDirectFBSurface_GetClip( IDirectFBSurface *thiz, DFBRegion *ret_clip ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (!ret_clip) return DFB_INVARG; *ret_clip = DFB_REGION_INIT_TRANSLATED( &data->state.clip, -data->area.wanted.x, -data->area.wanted.y ); D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( ret_clip ) ); return DFB_OK; } static DFBResult IDirectFBSurface_SetColor( IDirectFBSurface *thiz, u8 r, u8 g, u8 b, u8 a ) { DFBColor color = { a, r, g, b }; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, color 0x%08x )\n", __FUNCTION__, thiz, (unsigned int) PIXEL_ARGB( a, r, g, b ) ); if (!data->surface) return DFB_DESTROYED; dfb_state_set_color( &data->state, &color ); if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) dfb_state_set_color_index( &data->state, dfb_palette_search( data->surface->palette, r, g, b, a ) ); data->state.colors[0] = data->state.color; data->state.color_indices[0] = data->state.color_index; return DFB_OK; } static DFBResult IDirectFBSurface_SetColorIndex( IDirectFBSurface *thiz, unsigned int index ) { CorePalette *palette; DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, color index %3u )\n", __FUNCTION__, thiz, index ); if (!data->surface) return DFB_DESTROYED; if (!DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) return DFB_UNSUPPORTED; palette = data->surface->palette; if (!palette) return DFB_UNSUPPORTED; if (index > palette->num_entries) return DFB_INVARG; ret = CoreGraphicsStateClient_SetColorAndIndex( &data->state_client, &palette->entries[index], index ); if (ret) return ret; dfb_state_set_color( &data->state, &palette->entries[index] ); dfb_state_set_color_index( &data->state, index ); data->state.colors[0] = data->state.color; data->state.color_indices[0] = data->state.color_index; return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcBlendFunction( IDirectFBSurface *thiz, DFBSurfaceBlendFunction function ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %u )\n", __FUNCTION__, thiz, function ); switch (function) { case DSBF_ZERO: case DSBF_ONE: case DSBF_SRCCOLOR: case DSBF_INVSRCCOLOR: case DSBF_SRCALPHA: case DSBF_INVSRCALPHA: case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: case DSBF_DESTCOLOR: case DSBF_INVDESTCOLOR: case DSBF_SRCALPHASAT: dfb_state_set_src_blend( &data->state, function ); return DFB_OK; default: break; } return DFB_INVARG; } static DFBResult IDirectFBSurface_SetDstBlendFunction( IDirectFBSurface *thiz, DFBSurfaceBlendFunction function ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %u )\n", __FUNCTION__, thiz, function ); switch (function) { case DSBF_ZERO: case DSBF_ONE: case DSBF_SRCCOLOR: case DSBF_INVSRCCOLOR: case DSBF_SRCALPHA: case DSBF_INVSRCALPHA: case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: case DSBF_DESTCOLOR: case DSBF_INVDESTCOLOR: case DSBF_SRCALPHASAT: dfb_state_set_dst_blend( &data->state, function ); return DFB_OK; default: break; } return DFB_INVARG; } static DFBResult IDirectFBSurface_SetPorterDuff( IDirectFBSurface *thiz, DFBSurfacePorterDuffRule rule ) { DFBSurfaceBlendFunction src; DFBSurfaceBlendFunction dst; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %u )\n", __FUNCTION__, thiz, rule ); switch (rule) { case DSPD_NONE: src = DSBF_SRCALPHA; dst = DSBF_INVSRCALPHA; break; case DSPD_CLEAR: src = DSBF_ZERO; dst = DSBF_ZERO; break; case DSPD_SRC: src = DSBF_ONE; dst = DSBF_ZERO; break; case DSPD_SRC_OVER: src = DSBF_ONE; dst = DSBF_INVSRCALPHA; break; case DSPD_DST_OVER: src = DSBF_INVDESTALPHA; dst = DSBF_ONE; break; case DSPD_SRC_IN: src = DSBF_DESTALPHA; dst = DSBF_ZERO; break; case DSPD_DST_IN: src = DSBF_ZERO; dst = DSBF_SRCALPHA; break; case DSPD_SRC_OUT: src = DSBF_INVDESTALPHA; dst = DSBF_ZERO; break; case DSPD_DST_OUT: src = DSBF_ZERO; dst = DSBF_INVSRCALPHA; break; case DSPD_SRC_ATOP: src = DSBF_DESTALPHA; dst = DSBF_INVSRCALPHA; break; case DSPD_DST_ATOP: src = DSBF_INVDESTALPHA; dst = DSBF_SRCALPHA; break; case DSPD_ADD: src = DSBF_ONE; dst = DSBF_ONE; break; case DSPD_XOR: src = DSBF_INVDESTALPHA; dst = DSBF_INVSRCALPHA; break; case DSPD_DST: src = DSBF_ZERO; dst = DSBF_ONE; break; default: return DFB_INVARG; } dfb_state_set_src_blend( &data->state, src ); dfb_state_set_dst_blend( &data->state, dst ); return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcColorKey( IDirectFBSurface *thiz, u8 r, u8 g, u8 b ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; data->src_key.r = r; data->src_key.g = g; data->src_key.b = b; if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) data->src_key.value = dfb_palette_search( data->surface->palette, r, g, b, 0x80 ); else { DFBColor color = { 0, r, g, b }; data->src_key.value = dfb_pixel_from_color( data->surface->config.format, data->surface->config.colorspace, &color ); } return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcColorKeyIndex( IDirectFBSurface *thiz, unsigned int index ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) return DFB_UNSUPPORTED; if (!data->surface->palette) return DFB_UNSUPPORTED; if (index > data->surface->palette->num_entries) return DFB_INVARG; data->src_key.r = data->surface->palette->entries[index].r; data->src_key.g = data->surface->palette->entries[index].g; data->src_key.b = data->surface->palette->entries[index].b; data->src_key.value = index; return DFB_OK; } static DFBResult IDirectFBSurface_SetDstColorKey( IDirectFBSurface *thiz, u8 r, u8 g, u8 b ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; data->dst_key.r = r; data->dst_key.g = g; data->dst_key.b = b; if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) data->dst_key.value = dfb_palette_search( data->surface->palette, r, g, b, 0x80 ); else { DFBColor color = { 0, r, g, b }; data->dst_key.value = dfb_pixel_from_color( data->surface->config.format, data->surface->config.colorspace, &color ); } dfb_state_set_dst_colorkey( &data->state, data->dst_key.value ); return DFB_OK; } static DFBResult IDirectFBSurface_SetDstColorKeyIndex( IDirectFBSurface *thiz, unsigned int index ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) return DFB_UNSUPPORTED; if (!data->surface->palette) return DFB_UNSUPPORTED; if (index > data->surface->palette->num_entries) return DFB_INVARG; data->dst_key.r = data->surface->palette->entries[index].r; data->dst_key.g = data->surface->palette->entries[index].g; data->dst_key.b = data->surface->palette->entries[index].b; data->dst_key.value = index; dfb_state_set_dst_colorkey( &data->state, data->dst_key.value ); return DFB_OK; } static DFBResult IDirectFBSurface_SetBlittingFlags( IDirectFBSurface *thiz, DFBSurfaceBlittingFlags flags ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, 0x%08x )\n", __FUNCTION__, thiz, flags ); dfb_state_set_blitting_flags( &data->state, flags ); return DFB_OK; } static DFBResult IDirectFBSurface_Blit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, int x, int y ) { DFBRectangle srect; DFBPoint p; IDirectFBSurface_data *src_data; int dx = x; int dy = y; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, source %p, source_rect %p, %d,%d )\n", __FUNCTION__, thiz, source, source_rect, dx, dy ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!source) return DFB_INVARG; src_data = source->priv; if (!src_data->area.current.w || !src_data->area.current.h) return DFB_INVAREA; if (source_rect) { D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d <- %4d,%4d\n", 0, dx, dy, source_rect->w, source_rect->h, source_rect->x, source_rect->y ); if (source_rect->w < 1 || source_rect->h < 1) return DFB_OK; srect = *source_rect; srect.x += src_data->area.wanted.x; srect.y += src_data->area.wanted.y; if (!dfb_rectangle_intersect( &srect, &src_data->area.current )) return DFB_INVAREA; dx += srect.x - (source_rect->x + src_data->area.wanted.x); dy += srect.y - (source_rect->y + src_data->area.wanted.y); } else { srect = src_data->area.current; dx += srect.x - src_data->area.wanted.x; dy += srect.y - src_data->area.wanted.y; } CoreGraphicsStateClient_Flush( &src_data->state_client ); if (src_data->surface_client) { direct_mutex_lock( &data->surface_client_lock ); D_DEBUG_AT( Surface, " -> blit client surface (flip count %u)\n", src_data->surface_client_flip_count ); dfb_state_set_source_2( &data->state, src_data->surface, src_data->surface_client_flip_count ); } else dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); p.x = data->area.wanted.x + dx; p.y = data->area.wanted.y + dy; CoreGraphicsStateClient_Blit( &data->state_client, &srect, &p, 1 ); if (src_data->surface_client) direct_mutex_unlock( &data->surface_client_lock ); return DFB_OK; } static DFBResult IDirectFBSurface_TileBlit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, int x, int y ) { DFBRectangle srect; DFBPoint p1, p2; IDirectFBSurface_data *src_data; int dx = x; int dy = y; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, source %p, source_rect %p, %d,%d )\n", __FUNCTION__, thiz, source, source_rect, dx, dy ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!source) return DFB_INVARG; src_data = source->priv; if (!src_data->area.current.w || !src_data->area.current.h) return DFB_INVAREA; if (source_rect) { D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d <- %4d,%4d\n", 0, dx, dy, source_rect->w, source_rect->h, source_rect->x, source_rect->y ); if (source_rect->w < 1 || source_rect->h < 1) return DFB_OK; srect = *source_rect; srect.x += src_data->area.wanted.x; srect.y += src_data->area.wanted.y; if (!dfb_rectangle_intersect( &srect, &src_data->area.current )) return DFB_INVAREA; dx += srect.x - (source_rect->x + src_data->area.wanted.x); dy += srect.y - (source_rect->y + src_data->area.wanted.y); } else { srect = src_data->area.current; dx += srect.x - src_data->area.wanted.x; dy += srect.y - src_data->area.wanted.y; } CoreGraphicsStateClient_Flush( &src_data->state_client ); dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); dx %= srect.w; if (dx > 0) dx -= srect.w; dy %= srect.h; if (dy > 0) dy -= srect.h; dx += data->area.wanted.x; dy += data->area.wanted.y; p1.x = dx; p1.y = dy; p2.x = dx + data->area.wanted.w + srect.w - 1; p2.y = dy + data->area.wanted.h + srect.h - 1; CoreGraphicsStateClient_TileBlit( &data->state_client, &srect, &p1, &p2, 1 ); return DFB_OK; } static DFBResult IDirectFBSurface_BatchBlit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rects, const DFBPoint *dest_points, int num ) { int i, dx, dy, sx, sy; DFBRectangle *rects; DFBPoint *points; IDirectFBSurface_data *src_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, source %p, source_rects %p, dest_points %p, num %d )\n", __FUNCTION__, thiz, source, source_rects, dest_points, num ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!source || !source_rects || !dest_points || num < 1) return DFB_INVARG; src_data = source->priv; if (!src_data->area.current.w || !src_data->area.current.h) { return DFB_INVAREA; } dx = data->area.wanted.x; dy = data->area.wanted.y; sx = src_data->area.wanted.x; sy = src_data->area.wanted.y; rects = alloca( sizeof(DFBRectangle) * num ); points = alloca( sizeof(DFBPoint) * num ); direct_memcpy( rects, source_rects, sizeof(DFBRectangle) * num ); direct_memcpy( points, dest_points, sizeof(DFBPoint) * num ); for (i = 0; i < num; i++) { rects[i].x += sx; rects[i].y += sy; points[i].x += dx; points[i].y += dy; if (!dfb_rectangle_intersect( &rects[i], &src_data->area.current )) rects[i].w = rects[i].h = 0; points[i].x += rects[i].x - (source_rects[i].x + sx); points[i].y += rects[i].y - (source_rects[i].y + sy); D_DEBUG_AT( Surface, " -> [%3d] %4d,%4d-%dx%4d -> %4d,%4d\n", i, DFB_RECTANGLE_VALS( &source_rects[i] ), dest_points[i].x, dest_points[i].y ); } CoreGraphicsStateClient_Flush( &src_data->state_client ); dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); CoreGraphicsStateClient_Blit( &data->state_client, rects, points, num ); return DFB_OK; } static DFBResult IDirectFBSurface_BatchStretchBlit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rects, const DFBRectangle *dest_rects, int num ); static DFBResult IDirectFBSurface_StretchBlit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rect, const DFBRectangle *dest_rect ) { DFBRectangle srect, drect; if (!source) return DFB_INVARG; if (source_rect) srect = *source_rect; else { IDirectFBSurface_data *src_data = source->priv; srect = (DFBRectangle) { 0, 0, src_data->area.wanted.w, src_data->area.wanted.h }; } if (dest_rect) drect = *dest_rect; else { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) drect = (DFBRectangle) { 0, 0, data->area.wanted.w, data->area.wanted.h }; } return IDirectFBSurface_BatchStretchBlit( thiz, source, &srect, &drect, 1 ); } #define SET_VERTEX(v,X,Y,Z,W,S,T) \ do { \ (v)->x = X; \ (v)->y = Y; \ (v)->z = Z; \ (v)->w = W; \ (v)->s = S; \ (v)->t = T; \ } while (0) static DFBResult IDirectFBSurface_TextureTriangles( IDirectFBSurface *thiz, IDirectFBSurface *texture, const DFBVertex *vertices, const int *indices, int num, DFBTriangleFormation formation ) { int i; DFBVertex *translated; IDirectFBSurface_data *src_data; bool src_sub; float x0 = 0; float y0 = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!texture || !vertices || num < 3) return DFB_INVARG; src_data = texture->priv; if ((src_sub = (src_data->caps & DSCAPS_SUBSURFACE))) { D_ONCE( "sub surface texture with repeated mapping" ); x0 = data->area.wanted.x; y0 = data->area.wanted.y; } switch (formation) { case DTTF_LIST: if (num % 3) return DFB_INVARG; break; case DTTF_STRIP: case DTTF_FAN: break; default: return DFB_INVARG; } translated = alloca( num * sizeof(DFBVertex) ); if (!translated) return DFB_NOSYSTEMMEMORY; if (src_sub) { float oowidth = 1.0f / src_data->surface->config.size.w; float ooheight = 1.0f / src_data->surface->config.size.h; float s0 = src_data->area.wanted.x * oowidth; float t0 = src_data->area.wanted.y * ooheight; float fs = src_data->area.wanted.w * oowidth; float ft = src_data->area.wanted.h * ooheight; for (i = 0; i < num; i++) { const DFBVertex *in = &vertices[indices ? indices[i] : i]; DFBVertex *out = &translated[i]; SET_VERTEX( out, x0 + in->x, y0 + in->y, in->z, in->w, s0 + fs * in->s, t0 + ft * in->t ); } } else { if (indices) { for (i = 0; i < num; i++) { const DFBVertex *in = &vertices[indices[i]]; DFBVertex *out = &translated[i]; SET_VERTEX( out, x0 + in->x, y0 + in->y, in->z, in->w, in->s, in->t ); } } else { direct_memcpy( translated, vertices, num * sizeof(DFBVertex) ); for (i = 0; i < num; i++) { translated[i].x += x0; translated[i].y += y0; } } } CoreGraphicsStateClient_Flush( &src_data->state_client ); dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); CoreGraphicsStateClient_TextureTriangles( &data->state_client, translated, num, formation ); return DFB_OK; } static DFBResult IDirectFBSurface_SetDrawingFlags( IDirectFBSurface *thiz, DFBSurfaceDrawingFlags flags ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, 0x%08x )\n", __FUNCTION__, thiz, flags ); dfb_state_set_drawing_flags( &data->state, flags ); return DFB_OK; } static DFBResult IDirectFBSurface_FillRectangle( IDirectFBSurface *thiz, int x, int y, int w, int h ) { DFBRectangle rect = { x, y, w, h }; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d\n", 0, x, y, w, h ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (w <= 0 || h <= 0) return DFB_INVARG; rect.x += data->area.wanted.x; rect.y += data->area.wanted.y; CoreGraphicsStateClient_FillRectangles( &data->state_client, &rect, 1 ); return DFB_OK; } static DFBResult IDirectFBSurface_DrawRectangle( IDirectFBSurface *thiz, int x, int y, int w, int h ) { DFBRectangle rect = { x, y, w, h }; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d\n", 0, x, y, w, h ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (w <= 0 || h <= 0) return DFB_INVARG; rect.x += data->area.wanted.x; rect.y += data->area.wanted.y; CoreGraphicsStateClient_DrawRectangles( &data->state_client, &rect, 1 ); return DFB_OK; } static DFBResult IDirectFBSurface_DrawLine( IDirectFBSurface *thiz, int x1, int y1, int x2, int y2 ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4d,%4d\n", 0, x1, y1, x2, y2 ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if ((x1 == x2 || y1 == y2) && !(data->state.render_options & DSRO_MATRIX)) { DFBRectangle rect; if (x1 <= x2) { rect.x = x1; rect.w = x2 - x1 + 1; } else { rect.x = x2; rect.w = x1 - x2 + 1; } if (y1 <= y2) { rect.y = y1; rect.h = y2 - y1 + 1; } else { rect.y = y2; rect.h = y1 - y2 + 1; } rect.x += data->area.wanted.x; rect.y += data->area.wanted.y; CoreGraphicsStateClient_FillRectangles( &data->state_client, &rect, 1 ); } else { DFBRegion line = { x1, y1, x2, y2 }; line.x1 += data->area.wanted.x; line.x2 += data->area.wanted.x; line.y1 += data->area.wanted.y; line.y2 += data->area.wanted.y; CoreGraphicsStateClient_DrawLines( &data->state_client, &line, 1 ); } return DFB_OK; } static DFBResult IDirectFBSurface_DrawLines( IDirectFBSurface *thiz, const DFBRegion *lines, unsigned int num_lines ) { unsigned int i; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p [%u] )\n", __FUNCTION__, thiz, lines, num_lines ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!lines || !num_lines) return DFB_INVARG; /* Check if all lines are either horizontal or vertical. */ for (i = 0; i < num_lines; i++) { if (lines[i].x1 != lines[i].x2 && lines[i].y1 != lines[i].y2) break; } /* Use real line drawing. */ if (i < num_lines) { DFBRegion *local_lines = alloca( sizeof(DFBRegion) * num_lines ); if (data->area.wanted.x || data->area.wanted.y) { for (i = 0; i < num_lines; i++) { local_lines[i].x1 = lines[i].x1 + data->area.wanted.x; local_lines[i].x2 = lines[i].x2 + data->area.wanted.x; local_lines[i].y1 = lines[i].y1 + data->area.wanted.y; local_lines[i].y2 = lines[i].y2 + data->area.wanted.y; } } else /* Clipping may modify lines, so we copy them. */ direct_memcpy( local_lines, lines, sizeof(DFBRegion) * num_lines ); CoreGraphicsStateClient_DrawLines( &data->state_client, local_lines, num_lines ); } /* Optimized rectangle drawing. */ else { DFBRectangle *local_rects = alloca( sizeof(DFBRectangle) * num_lines ); for (i = 0; i < num_lines; i++) { /* Vertical line. */ if (lines[i].x1 == lines[i].x2) { local_rects[i].x = data->area.wanted.x + lines[i].x1; local_rects[i].y = data->area.wanted.y + MIN( lines[i].y1, lines[i].y2 ); local_rects[i].w = 1; local_rects[i].h = ABS( lines[i].y2 - lines[i].y1 ) + 1; } /* Horizontal line. */ else { local_rects[i].x = data->area.wanted.x + MIN( lines[i].x1, lines[i].x2 ); local_rects[i].y = data->area.wanted.y + lines[i].y1; local_rects[i].w = ABS( lines[i].x2 - lines[i].x1 ) + 1; local_rects[i].h = 1; } } CoreGraphicsStateClient_FillRectangles( &data->state_client, local_rects, num_lines ); } return DFB_OK; } static DFBResult IDirectFBSurface_FillTriangle( IDirectFBSurface *thiz, int x1, int y1, int x2, int y2, int x3, int y3 ) { DFBTriangle tri = { x1, y1, x2, y2, x3, y3 }; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4d,%4d-%4d,%4d\n", 0, x1, y1, x2, y2, x3, y3 ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; tri.x1 += data->area.wanted.x; tri.y1 += data->area.wanted.y; tri.x2 += data->area.wanted.x; tri.y2 += data->area.wanted.y; tri.x3 += data->area.wanted.x; tri.y3 += data->area.wanted.y; CoreGraphicsStateClient_FillTriangles( &data->state_client, &tri, 1 ); return DFB_OK; } static DFBResult IDirectFBSurface_FillRectangles( IDirectFBSurface *thiz, const DFBRectangle *rects, unsigned int num_rects ) { unsigned int i; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p [%u] )\n", __FUNCTION__, thiz, rects, num_rects ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!rects || !num_rects) return DFB_INVARG; if (data->area.wanted.x || data->area.wanted.y) { DFBRectangle *local_rects; bool malloced = (num_rects > 256); if (malloced) local_rects = D_MALLOC( sizeof(DFBRectangle) * num_rects ); else local_rects = alloca( sizeof(DFBRectangle) * num_rects ); for (i = 0; i < num_rects; i++) { local_rects[i].x = rects[i].x + data->area.wanted.x; local_rects[i].y = rects[i].y + data->area.wanted.y; local_rects[i].w = rects[i].w; local_rects[i].h = rects[i].h; } for (i = 0; i < num_rects; i += 200) { CoreGraphicsStateClient_FillRectangles( &data->state_client, &local_rects[i], MIN( 200, num_rects - i ) ); } if (malloced) D_FREE( local_rects ); } else { for (i = 0; i < num_rects; i += 200) { CoreGraphicsStateClient_FillRectangles( &data->state_client, &rects[i], MIN( 200, num_rects - i ) ); } } return DFB_OK; } static DFBResult IDirectFBSurface_FillSpans( IDirectFBSurface *thiz, int y, const DFBSpan *spans, unsigned int num_spans ) { DFBSpan *local_spans = alloca( sizeof(DFBSpan) * num_spans ); DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!spans || !num_spans) return DFB_INVARG; if (data->area.wanted.x || data->area.wanted.y) { unsigned int i; for (i = 0; i < num_spans; i++) { local_spans[i].x = spans[i].x + data->area.wanted.x; local_spans[i].w = spans[i].w; } } else /* Clipping may modify spans, so we copy them. */ direct_memcpy( local_spans, spans, sizeof(DFBSpan) * num_spans ); CoreGraphicsStateClient_FillSpans( &data->state_client, y + data->area.wanted.y, local_spans, num_spans ); return DFB_OK; } static DFBResult IDirectFBSurface_FillTriangles( IDirectFBSurface *thiz, const DFBTriangle *tris, unsigned int num_tris ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!tris || !num_tris) return DFB_INVARG; if (data->area.wanted.x || data->area.wanted.y) { unsigned int i; DFBTriangle *local_tris; bool malloced = (num_tris > 170); if (malloced) local_tris = D_MALLOC( sizeof(DFBTriangle) * num_tris ); else local_tris = alloca( sizeof(DFBTriangle) * num_tris ); for (i = 0; i < num_tris; i++) { local_tris[i].x1 = tris[i].x1 + data->area.wanted.x; local_tris[i].y1 = tris[i].y1 + data->area.wanted.y; local_tris[i].x2 = tris[i].x2 + data->area.wanted.x; local_tris[i].y2 = tris[i].y2 + data->area.wanted.y; local_tris[i].x3 = tris[i].x3 + data->area.wanted.x; local_tris[i].y3 = tris[i].y3 + data->area.wanted.y; } CoreGraphicsStateClient_FillTriangles( &data->state_client, local_tris, num_tris ); if (malloced) D_FREE( local_tris ); } else CoreGraphicsStateClient_FillTriangles( &data->state_client, tris, num_tris ); return DFB_OK; } static DFBResult IDirectFBSurface_SetFont( IDirectFBSurface *thiz, IDirectFBFont *font ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, font ); if (data->font != font) { if (font) { IDirectFBFont_data *font_data; ret = font->AddRef( font ); if (ret) return ret; font_data = font->priv; if (!font_data) return DFB_DEAD; if (font_data) data->encoding = font_data->encoding; } if (data->font) data->font->Release( data->font ); data->font = font; } return DFB_OK; } static DFBResult IDirectFBSurface_GetFont( IDirectFBSurface *thiz, IDirectFBFont **ret_interface ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; if (!data->font) { *ret_interface = NULL; return DFB_MISSINGFONT; } ret = data->font->AddRef( data->font ); if (ret) return ret; *ret_interface = data->font; return DFB_OK; } static DFBResult IDirectFBSurface_DrawString( IDirectFBSurface *thiz, const char *text, int bytes, int x, int y, DFBSurfaceTextFlags flags ) { IDirectFBFont_data *font_data; unsigned int layers = 1; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %d, %d,%d, 0x%x )\n", __FUNCTION__, thiz, bytes, x, y, flags ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!data->font) return DFB_MISSINGFONT; if (!text) return DFB_INVARG; if (bytes < 0) bytes = strlen( text ); if (bytes == 0) return DFB_OK; font_data = data->font->priv; if (!font_data) return DFB_DEAD; if (!font_data) return DFB_DESTROYED; if (core_dfb->shutdown_running) return DFB_OK; if (flags & DSTF_OUTLINE) { if (!(font_data->font->attributes & DFFA_OUTLINED)) return DFB_UNSUPPORTED; layers = 2; } if (!(flags & DSTF_TOP)) { x += font_data->font->ascender * font_data->font->up_unit_x; y += font_data->font->ascender * font_data->font->up_unit_y; if (flags & DSTF_BOTTOM) { x -= font_data->font->descender * font_data->font->up_unit_x; y -= font_data->font->descender * font_data->font->up_unit_y; } } if (flags & (DSTF_RIGHT | DSTF_CENTER)) { DFBResult ret; int i, num, kx, ky; int xsize = 0; int ysize = 0; unsigned int prev = 0; unsigned int indices[bytes]; dfb_font_lock( font_data->font ); /* Decode string to character indices. */ ret = dfb_font_decode_text( font_data->font, data->encoding, text, bytes, indices, &num ); if (ret) { dfb_font_unlock( font_data->font ); return ret; } /* Calculate string width. */ for (i = 0; i < num; i++) { unsigned int current = indices[i]; CoreGlyphData *glyph; if (dfb_font_get_glyph_data( font_data->font, current, 0, &glyph ) == DFB_OK) { xsize += glyph->xadvance; ysize += glyph->yadvance; if (prev && font_data->font->GetKerning && font_data->font->GetKerning( font_data->font, prev, current, &kx, &ky ) == DFB_OK) { xsize += kx << 8; ysize += ky << 8; } } prev = current; } dfb_font_unlock( font_data->font ); /* Justify. */ if (flags & DSTF_RIGHT) { x -= xsize >> 8; y -= ysize >> 8; } else if (flags & DSTF_CENTER) { x -= xsize >> 9; y -= ysize >> 9; } } dfb_gfxcard_drawstring( (const unsigned char*) text, bytes, data->encoding, data->area.wanted.x + x, data->area.wanted.y + y, font_data->font, layers, &data->state_client, flags ); return DFB_OK; } static DFBResult IDirectFBSurface_DrawGlyph( IDirectFBSurface *thiz, unsigned int character, int x, int y, DFBSurfaceTextFlags flags ) { DFBResult ret; int l; IDirectFBFont_data *font_data; CoreGlyphData *glyph[DFB_FONT_MAX_LAYERS]; unsigned int index; unsigned int layers = 1; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, 0x%x, %d,%d, 0x%x )\n", __FUNCTION__, thiz, character, x, y, flags ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!data->font) return DFB_MISSINGFONT; if (!character) return DFB_INVARG; font_data = data->font->priv; if (!font_data) return DFB_DEAD; if (!font_data) return DFB_DESTROYED; if (core_dfb->shutdown_running) return DFB_OK; if (flags & DSTF_OUTLINE) { if (!(font_data->font->attributes & DFFA_OUTLINED)) return DFB_UNSUPPORTED; layers = 2; } dfb_font_lock( font_data->font ); ret = dfb_font_decode_character( font_data->font, data->encoding, character, &index ); if (ret) { dfb_font_unlock( font_data->font ); return ret; } for (l = 0; l < layers; l++) { ret = dfb_font_get_glyph_data( font_data->font, index, l, &glyph[l] ); if (ret) { dfb_font_unlock( font_data->font ); return ret; } } if (!(flags & DSTF_TOP)) { x += font_data->font->ascender * font_data->font->up_unit_x; y += font_data->font->ascender * font_data->font->up_unit_y; if (flags & DSTF_BOTTOM) { x -= font_data->font->descender * font_data->font->up_unit_x; y -= font_data->font->descender * font_data->font->up_unit_y; } } if (flags & (DSTF_RIGHT | DSTF_CENTER)) { if (flags & DSTF_RIGHT) { x -= glyph[0]->xadvance; y -= glyph[0]->yadvance; } else if (flags & DSTF_CENTER) { x -= glyph[0]->xadvance >> 1; y -= glyph[0]->yadvance >> 1; } } dfb_gfxcard_drawglyph( glyph, data->area.wanted.x + x, data->area.wanted.y + y, font_data->font, layers, &data->state_client, flags ); dfb_font_unlock( font_data->font ); return DFB_OK; } static DFBResult IDirectFBSurface_SetEncoding( IDirectFBSurface *thiz, DFBTextEncodingID encoding ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %u )\n", __FUNCTION__, thiz, encoding ); data->encoding = encoding; return DFB_OK; } static DFBResult IDirectFBSurface_GetSubSurface( IDirectFBSurface *thiz, const DFBRectangle *rect, IDirectFBSurface **ret_interface ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!ret_interface) return DFB_INVARG; direct_mutex_lock( &data->children_lock ); if (data->children_free) { IDirectFBSurface_data *child_data; child_data = (IDirectFBSurface_data*) data->children_free; direct_list_remove( &data->children_free, &child_data->link ); direct_list_append( &data->children_data, &child_data->link ); direct_mutex_unlock( &data->children_lock ); *ret_interface = child_data->thiz; ret = (*ret_interface)->MakeSubSurface( *ret_interface, thiz, rect ); if (ret) { direct_mutex_unlock( &data->children_lock ); return ret; } return DFB_OK; } direct_mutex_unlock( &data->children_lock ); DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBSurface ); if (rect || data->limit_set) { DFBRectangle wanted, granted; /* Compute wanted rectangle. */ if (rect) { wanted = *rect; wanted.x += data->area.wanted.x; wanted.y += data->area.wanted.y; if (wanted.w <= 0 || wanted.h <= 0) { wanted.w = 0; wanted.h = 0; } } else { wanted = data->area.wanted; } /* Compute granted rectangle. */ granted = wanted; dfb_rectangle_intersect( &granted, &data->area.granted ); ret = IDirectFBSurface_Construct( *ret_interface, thiz, &wanted, &granted, &data->area.insets, data->surface, data->caps | DSCAPS_SUBSURFACE, data->core, data->idirectfb ); } else { ret = IDirectFBSurface_Construct( *ret_interface, thiz, NULL, NULL, &data->area.insets, data->surface, data->caps | DSCAPS_SUBSURFACE, data->core, data->idirectfb ); } return ret; } static DFBResult IDirectFBSurface_GetGL( IDirectFBSurface *thiz, IDirectFBGL **ret_interface ) { DFBResult ret; DirectInterfaceFuncs *funcs = NULL; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (!ret_interface) return DFB_INVARG; ret = DirectGetInterface( &funcs, "IDirectFBGL", NULL, DirectProbeInterface, thiz ); if (ret) return ret; ret = funcs->Allocate( (void**) ret_interface ); if (ret) return ret; ret = funcs->Construct( *ret_interface, thiz, data->idirectfb ); if (ret) *ret_interface = NULL; return ret; } static DFBResult IDirectFBSurface_Dump( IDirectFBSurface *thiz, const char *directory, const char *prefix ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->caps & DSCAPS_SUBSURFACE) { D_ONCE( "sub surface dumping not supported" ); return DFB_UNSUPPORTED; } if (!directory) return DFB_INVARG; CoreGraphicsStateClient_Flush( &data->state_client ); return dfb_surface_dump_buffer2( data->surface, DSBR_FRONT, DSSE_LEFT, directory, prefix ); } static DFBResult IDirectFBSurface_DisableAcceleration( IDirectFBSurface *thiz, DFBAccelerationMask mask ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (D_FLAGS_INVALID( mask, DFXL_ALL )) return DFB_INVARG; data->state.disabled = mask; return DFB_OK; } static DFBResult IDirectFBSurface_ReleaseSource( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); dfb_state_set_source( &data->state, NULL ); dfb_state_set_source_mask( &data->state, NULL ); dfb_state_set_source2( &data->state, NULL ); CoreGraphicsStateClient_ReleaseSource( &data->state_client ); return DFB_OK; } static DFBResult IDirectFBSurface_SetIndexTranslation( IDirectFBSurface *thiz, const int *indices, int num_indices ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) if (!data->surface) return DFB_DESTROYED; if (!DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) return DFB_UNSUPPORTED; if (!indices && num_indices > 0) return DFB_INVAREA; if (num_indices < 0 || num_indices > 256) return DFB_INVARG; return dfb_state_set_index_translation( &data->state, indices, num_indices ); } static DFBResult IDirectFBSurface_SetRenderOptions( IDirectFBSurface *thiz, DFBSurfaceRenderOptions options ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); dfb_state_set_render_options( &data->state, options ); return DFB_OK; } static DFBResult IDirectFBSurface_SetMatrix( IDirectFBSurface *thiz, const s32 *matrix ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, matrix ); if (!matrix) return DFB_INVARG; dfb_state_set_matrix( &data->state, matrix ); return DFB_OK; } static DFBResult IDirectFBSurface_SetSourceMask( IDirectFBSurface *thiz, IDirectFBSurface *mask, int x, int y, DFBSurfaceMaskFlags flags ) { DFBResult ret; DFBPoint offset = { x, y }; IDirectFBSurface_data *mask_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, %d,%d, 0x%04x )\n", __FUNCTION__, thiz, mask, x, y, flags ); if (!mask || flags & ~DSMF_ALL) return DFB_INVARG; mask_data = mask->priv; if (!mask_data) return DFB_DEAD; if (!mask_data) return DFB_DESTROYED; if (!mask_data->surface) return DFB_DESTROYED; CoreGraphicsStateClient_Flush( &mask_data->state_client ); ret = dfb_state_set_source_mask( &data->state, mask_data->surface ); if (ret) return ret; dfb_state_set_source_mask_vals( &data->state, &offset, flags ); return DFB_OK; } static DFBResult IDirectFBSurface_MakeSubSurface( IDirectFBSurface *thiz, IDirectFBSurface *from, const DFBRectangle *rect ) { DFBRectangle wanted, granted; DFBRectangle full_rect; IDirectFBSurface_data *from_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!from) return DFB_INVARG; from_data = from->priv; if (!from_data) return DFB_DEAD; if (!from_data) return DFB_DESTROYED; /* Check if CoreSurface is the same. */ if (from_data->surface != data->surface) return DFB_UNSUPPORTED; full_rect.x = 0; full_rect.y = 0; full_rect.w = data->surface->config.size.w; full_rect.h = data->surface->config.size.h; if (rect || from_data->limit_set) { /* Compute wanted rectangle. */ if (rect) { wanted = *rect; wanted.x += from_data->area.wanted.x; wanted.y += from_data->area.wanted.y; if (wanted.w <= 0 || wanted.h <= 0) { wanted.w = 0; wanted.h = 0; } } else { wanted = from_data->area.wanted; } /* Compute granted rectangle. */ granted = wanted; dfb_rectangle_intersect( &granted, &from_data->area.granted ); } else { wanted = full_rect; granted = full_rect; } data->caps |= DSCAPS_SUBSURFACE; data->area.wanted = wanted; data->area.granted = granted; data->area.current = data->area.granted; dfb_rectangle_intersect( &data->area.current, &full_rect ); data->state.clip.x1 = data->area.current.x; data->state.clip.y1 = data->area.current.y; data->state.clip.x2 = data->area.current.x + (data->area.current.w ?: 1) - 1; data->state.clip.y2 = data->area.current.y + (data->area.current.h ?: 1) - 1; data->state.modified |= SMF_CLIP; return DFB_OK; } static DFBResult IDirectFBSurface_Write( IDirectFBSurface *thiz, const DFBRectangle *rect, const void *ptr, int pitch ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, %p [%d] )\n", __FUNCTION__, thiz, rect, ptr, pitch ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!rect || !ptr || pitch < DFB_BYTES_PER_LINE(data->surface->config.format, rect->w ) ) return DFB_INVARG; D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( rect ) ); return dfb_surface_write_buffer( data->surface, DSBR_BACK, ptr, pitch, rect ); } static DFBResult IDirectFBSurface_Read( IDirectFBSurface *thiz, const DFBRectangle *rect, void *ptr, int pitch ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, %p [%d] )\n", __FUNCTION__, thiz, rect, ptr, pitch ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!rect || !ptr || pitch < DFB_BYTES_PER_LINE(data->surface->config.format, rect->w ) ) return DFB_INVARG; D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( rect ) ); return dfb_surface_read_buffer( data->surface, DSBR_FRONT, ptr, pitch, rect ); } static DFBResult IDirectFBSurface_SetColors( IDirectFBSurface *thiz, const DFBColorID *ids, const DFBColor *colors, unsigned int num ) { unsigned int i; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p, %p, %u )\n", __FUNCTION__, thiz, ids, colors, num ); if (!data->surface) return DFB_DESTROYED; for (i = 0; i < num; i++) { D_DEBUG_AT( Surface, " -> [%u] id %u = %02x %02x %02x %02x\n", i, ids[i], colors[i].a, colors[i].r, colors[i].g, colors[i].b ); if (ids[i] >= DFB_COLOR_IDS_MAX) return DFB_INVARG; data->state.colors[ids[i]] = colors[i]; if (DFB_PIXELFORMAT_IS_INDEXED( data->surface->config.format )) data->state.color_indices[ids[i]] = dfb_palette_search( data->surface->palette, colors[i].r, colors[i].g, colors[i].b, colors[i].a ); } dfb_state_set_color( &data->state, &data->state.colors[0] ); dfb_state_set_color_index( &data->state, data->state.color_indices[0] ); return DFB_OK; } static DFBResult IDirectFBSurface_BatchBlit2( IDirectFBSurface *thiz, IDirectFBSurface *source, IDirectFBSurface *source2, const DFBRectangle *source_rects, const DFBPoint *dest_points, const DFBPoint *source2_points, int num ) { int i, dx, dy, sx, sy, sx2, sy2; DFBRectangle *rects; DFBPoint *points; DFBPoint *points2; IDirectFBSurface_data *src_data; IDirectFBSurface_data *src2_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!source || !source2 || !source_rects || !dest_points || !source2_points || num < 1) return DFB_INVARG; src_data = source->priv; if (!src_data->area.current.w || !src_data->area.current.h) return DFB_INVAREA; src2_data = source2->priv; if (!src2_data->area.current.w || !src2_data->area.current.h) return DFB_INVAREA; dx = data->area.wanted.x; dy = data->area.wanted.y; sx = src_data->area.wanted.x; sy = src_data->area.wanted.y; sx2 = src2_data->area.wanted.x; sy2 = src2_data->area.wanted.y; rects = alloca( sizeof(DFBRectangle) * num ); points = alloca( sizeof(DFBPoint) * num ); points2 = alloca( sizeof(DFBPoint) * num ); direct_memcpy( rects, source_rects, sizeof(DFBRectangle) * num ); direct_memcpy( points, dest_points, sizeof(DFBPoint) * num ); direct_memcpy( points2, source2_points, sizeof(DFBPoint) * num ); for (i = 0; i < num; i++) { DFBRectangle rect2; rects[i].x += sx; rects[i].y += sy; points[i].x += dx; points[i].y += dy; points2[i].x += sx2; points2[i].y += sy2; if (!dfb_rectangle_intersect( &rects[i], &src_data->area.current )) rects[i].w = rects[i].h = 0; else { points[i].x += rects[i].x - (source_rects[i].x + sx); points[i].y += rects[i].y - (source_rects[i].y + sy); points2[i].x += rects[i].x - (source_rects[i].x + sx); points2[i].y += rects[i].y - (source_rects[i].y + sy); rect2.x = points2[i].x; rect2.y = points2[i].y; rect2.w = rects[i].w; rect2.h = rects[i].h; if (!dfb_rectangle_intersect( &rect2, &src2_data->area.current )) rects[i].w = rects[i].h = 0; points[i].x += rect2.x - points2[i].x; points[i].y += rect2.y - points2[i].y; points2[i].x += rect2.x - points2[i].x; points2[i].y += rect2.y - points2[i].y; rects[i].w = rect2.w; rects[i].h = rect2.h; } } CoreGraphicsStateClient_Flush( &src_data->state_client ); CoreGraphicsStateClient_Flush( &src2_data->state_client ); dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_source2( &data->state, src2_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); CoreGraphicsStateClient_Blit2( &data->state_client, rects, points, points2, num ); return DFB_OK; } static DFBResult IDirectFBSurface_GetPhysicalAddress( IDirectFBSurface *thiz, unsigned long *addr ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) if (!data->surface) return DFB_DESTROYED; if (!data->locked) return DFB_ACCESSDENIED; if (!data->lock.phys) { /* The surface is probably in a system buffer if there's no physical address. */ return DFB_UNSUPPORTED; } if (!addr) return DFB_INVARG; *addr = data->lock.phys; return DFB_OK; } static DFBResult IDirectFBSurface_FillTrapezoids( IDirectFBSurface *thiz, const DFBTrapezoid *traps, unsigned int num_traps ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!traps || !num_traps) return DFB_INVARG; if (data->area.wanted.x || data->area.wanted.y) { unsigned int i; DFBTrapezoid *local_traps; bool malloced = (num_traps > 170); if (malloced) local_traps = D_MALLOC( sizeof(DFBTrapezoid) * num_traps ); else local_traps = alloca( sizeof(DFBTrapezoid) * num_traps ); for (i = 0; i < num_traps; i++) { local_traps[i].x1 = traps[i].x1 + data->area.wanted.x; local_traps[i].y1 = traps[i].y1 + data->area.wanted.y; local_traps[i].w1 = traps[i].w1; local_traps[i].x2 = traps[i].x2 + data->area.wanted.x; local_traps[i].y2 = traps[i].y2 + data->area.wanted.y; local_traps[i].w2 = traps[i].w2; } CoreGraphicsStateClient_FillTrapezoids( &data->state_client, local_traps, num_traps ); if (malloced) D_FREE( local_traps ); } else CoreGraphicsStateClient_FillTrapezoids( &data->state_client, traps, num_traps ); return DFB_OK; } static DFBResult IDirectFBSurface_FillQuadrangles( IDirectFBSurface *thiz, const DFBPoint *points, unsigned int num_points ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!points || !num_points) return DFB_INVARG; if (data->area.wanted.x || data->area.wanted.y) { unsigned int i; DFBPoint *local_points = alloca( sizeof(DFBPoint) * num_points ); for (i = 0; i < num_points; i++) { local_points[i].x = points[i].x + data->area.wanted.x; local_points[i].y = points[i].y + data->area.wanted.y; } CoreGraphicsStateClient_FillQuadrangles( &data->state_client, local_points, num_points ); } else CoreGraphicsStateClient_FillQuadrangles( &data->state_client, points, num_points ); return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcColorKeyExtended( IDirectFBSurface *thiz, const DFBColorKeyExtended *colorkey_extended ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); dfb_state_set_src_colorkey_extended( &data->state, colorkey_extended ); return DFB_OK; } static DFBResult IDirectFBSurface_SetDstColorKeyExtended( IDirectFBSurface *thiz, const DFBColorKeyExtended *colorkey_extended ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); dfb_state_set_dst_colorkey_extended( &data->state, colorkey_extended ); return DFB_OK; } static DFBResult IDirectFBSurface_DrawMonoGlyphs( IDirectFBSurface *thiz, const void *glyphs[], const DFBMonoGlyphAttributes *attributes, const DFBPoint *dest_points, unsigned int num ) { int i, dx, dy; DFBPoint *points; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!glyphs || !attributes || !dest_points || num < 1) return DFB_INVARG; dx = data->area.wanted.x; dy = data->area.wanted.y; points = alloca( sizeof(DFBPoint) * num ); for (i = 0; i < num; i++) { points[i].x = dest_points[i].x + dx; points[i].y = dest_points[i].y + dy; } dfb_gfxcard_draw_mono_glyphs( glyphs, attributes, points, num, &data->state ); return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcColorMatrix( IDirectFBSurface *thiz, const s32 *matrix ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, matrix ); if (!matrix) return DFB_INVARG; dfb_state_set_src_colormatrix( &data->state, matrix ); return DFB_OK; } static DFBResult IDirectFBSurface_SetSrcConvolution( IDirectFBSurface *thiz, const DFBConvolutionFilter *filter ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, filter ); if (!filter) return DFB_INVARG; dfb_state_set_src_convolution( &data->state, filter ); return DFB_OK; } static DFBResult IDirectFBSurface_GetID( IDirectFBSurface *thiz, DFBSurfaceID *ret_surface_id ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!ret_surface_id) return DFB_INVARG; *ret_surface_id = data->surface->object.id; return DFB_OK; } static DFBResult IDirectFBSurface_AllowAccess( IDirectFBSurface *thiz, const char *executable ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; return CoreDFB_AllowSurface( data->core, data->surface, executable, strlen( executable ) + 1 ); } static DFBResult IDirectFBSurface_CreateEventBuffer( IDirectFBSurface *thiz, IDirectFBEventBuffer **ret_interface ) { IDirectFBEventBuffer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBEventBuffer ); IDirectFBEventBuffer_Construct( iface, NULL, NULL ); IDirectFBEventBuffer_AttachSurface( iface, data->surface ); *ret_interface = iface; return DFB_OK; } static DFBResult IDirectFBSurface_AttachEventBuffer( IDirectFBSurface *thiz, IDirectFBEventBuffer *buffer ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; IDirectFBEventBuffer_AttachSurface( buffer, data->surface ); return DFB_OK; } static DFBResult IDirectFBSurface_DetachEventBuffer( IDirectFBSurface *thiz, IDirectFBEventBuffer *buffer ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); return IDirectFBEventBuffer_DetachSurface( buffer, data->surface ); } static DFBResult IDirectFBSurface_BatchStretchBlit( IDirectFBSurface *thiz, IDirectFBSurface *source, const DFBRectangle *source_rects, const DFBRectangle *dest_rects, int num ) { int i, dx, dy, sx, sy; DFBRectangle *srects, *drects; IDirectFBSurface_data *src_data; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, %d )\n", __FUNCTION__, thiz, num ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->locked) return DFB_LOCKED; if (!source || !source_rects || !dest_rects || num < 1) return DFB_INVARG; src_data = source->priv; if (!src_data->area.current.w || !src_data->area.current.h) return DFB_INVAREA; dx = data->area.wanted.x; dy = data->area.wanted.y; sx = src_data->area.wanted.x; sy = src_data->area.wanted.y; srects = alloca( sizeof(DFBRectangle) * num ); drects = alloca( sizeof(DFBRectangle) * num ); direct_memcpy( srects, source_rects, sizeof(DFBRectangle) * num ); direct_memcpy( drects, dest_rects, sizeof(DFBRectangle) * num ); for (i = 0; i < num; ++i) { DFBRectangle orig_src; if (drects[i].w < 1 || drects[i].h < 1) { drects[i].w = 0; drects[i].h = 0; continue; } drects[i].x += dx; drects[i].y += dy; if (srects[i].w < 1 || srects[i].h < 1) return DFB_INVARG; srects[i].x += sx; srects[i].y += sy; /* Clipping of the source rectangle must be applied to the destination. */ orig_src = srects[i]; if (!dfb_rectangle_intersect( &srects[i], &src_data->area.current )) { srects[i].w = srects[i].h = 0; drects[i].w = drects[i].h = 0; continue; } if (srects[i].x != orig_src.x) drects[i].x += (int) ( (srects[i].x - orig_src.x) * (drects[i].w / (float) orig_src.w) + 0.5f); if (srects[i].y != orig_src.y) drects[i].y += (int) ( (srects[i].y - orig_src.y) * (drects[i].h / (float) orig_src.h) + 0.5f); if (srects[i].w != orig_src.w) drects[i].w = D_ICEIL( drects[i].w * (srects[i].w / (float) orig_src.w) ); if (srects[i].h != orig_src.h) drects[i].h = D_ICEIL( drects[i].h * (srects[i].h / (float) orig_src.h) ); D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d <- %4d,%4d-%4dx%4d\n", i, drects[i].x, drects[i].y, drects[i].w, drects[i].h, srects[i].x, srects[i].y, srects[i].w, srects[i].h ); } CoreGraphicsStateClient_Flush( &src_data->state_client ); dfb_state_set_source( &data->state, src_data->surface ); dfb_state_set_from( &data->state, DSBR_FRONT, src_data->src_eye ); /* Fetch the source color key from the source if necessary. */ if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); CoreGraphicsStateClient_StretchBlit( &data->state_client, srects, drects, num ); return DFB_OK; } static DFBResult IDirectFBSurface_MakeClient( IDirectFBSurface *thiz ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p [%u] )\n", __FUNCTION__, data->surface, data->surface->object.id ); if (data->surface_client) { D_DEBUG_AT( Surface, " -> already client!\n" ); return DFB_BUSY; } ret = CoreSurface_CreateClient( data->surface, &data->surface_client ); if (ret) return ret; return DFB_OK; } static DFBResult IDirectFBSurface_FrameAck( IDirectFBSurface *thiz, u32 flip_count ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface_Updates, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface_client) return DFB_UNSUPPORTED; direct_mutex_lock( &data->surface_client_lock ); D_DEBUG_AT( Surface_Updates, " -> surface %p [%u]\n", data->surface, data->surface->object.id ); D_DEBUG_AT( Surface_Updates, " -> flip count %u\n", flip_count ); data->surface_client_flip_count = flip_count; CoreSurfaceClient_FrameAck( data->surface_client, flip_count ); direct_mutex_unlock( &data->surface_client_lock ); return DFB_OK; } static DFBResult IDirectFBSurface_DumpRaw( IDirectFBSurface *thiz, const char *directory, const char *prefix ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; if (!data->area.current.w || !data->area.current.h) return DFB_INVAREA; if (data->caps & DSCAPS_SUBSURFACE) { D_ONCE( "sub surface dumping not supported" ); return DFB_UNSUPPORTED; } if (!directory) return DFB_INVARG; return dfb_surface_dump_raw_buffer( data->surface, DSBR_FRONT, directory, prefix ); } static DFBResult IDirectFBSurface_GetFrameTime( IDirectFBSurface *thiz, long long *ret_micros ) { long long now; long long interval = 0; long long max = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface_Updates, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->surface) return DFB_DESTROYED; interval = data->surface->frametime_config.interval; D_DEBUG_AT( Surface_Updates, " -> surface interval: %lld\n", interval ); D_DEBUG_AT( Surface_Updates, " -> config flags: 0x%08x\n", data->frametime_config.flags ); if (data->surface->frametime_config.flags & DFTCF_MAX_ADVANCE) max = data->surface->frametime_config.max_advance; if (data->frametime_config.flags & DFTCF_INTERVAL) { interval = data->frametime_config.interval; D_DEBUG_AT( Surface_Updates, " -> local configured interval: %lld\n", interval ); } if (data->frametime_config.flags & DFTCF_MAX_ADVANCE) max = data->frametime_config.max_advance; if (!interval) { interval = dfb_config->screen_frame_interval; D_DEBUG_AT( Surface_Updates, " -> using fallback default interval: %lld\n", interval ); } if (!max) max = dfb_config->max_frame_advance; data->current_frame_time += interval; now = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); if (now > data->current_frame_time) data->current_frame_time = now; else if (max) { while (data->current_frame_time - now > max) { D_DEBUG_AT( Surface_Updates, " -> sleeping for %lld us...\n", data->current_frame_time - now - max ); direct_thread_sleep( data->current_frame_time - now - max ); now = direct_clock_get_time( DIRECT_CLOCK_MONOTONIC ); } } D_DEBUG_AT( Surface_Updates, " -> %lld, %lld ahead\n", data->current_frame_time, data->current_frame_time - now ); if (ret_micros) *ret_micros = data->current_frame_time; return DFB_OK; } static DFBResult IDirectFBSurface_SetFrameTimeConfig( IDirectFBSurface *thiz, const DFBFrameTimeConfig *config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface_Updates, "%s( %p )\n", __FUNCTION__, thiz ); if (config) { if (config->flags & DFTCF_INTERVAL) D_DEBUG_AT( Surface_Updates, " -> interval: %lld\n", config->interval ); if (config->flags & DFTCF_MAX_ADVANCE) D_DEBUG_AT( Surface_Updates, " -> max_advance: %lld\n", config->max_advance ); data->frametime_config = *config; } else memset( &data->frametime_config, 0, sizeof(data->frametime_config) ); return DFB_OK; } static DFBResult IDirectFBSurface_Allocate( IDirectFBSurface *thiz, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, u64 handle, IDirectFBSurfaceAllocation **ret_interface ) { DFBResult ret; CoreSurfaceAllocation *allocation; IDirectFBSurfaceAllocation *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, role %u, eye %u, key '%s', handle 0x%08llx )\n", __FUNCTION__, thiz, role, eye, key, (unsigned long long) handle ); ret = CoreSurface_Allocate( data->surface, role, eye, key, strlen( key ) + 1, handle, &allocation ); if (ret) { D_DERROR( ret, "IDirectFBSurface: CoreSurface_Allocate( role %u, eye %u, key '%s', handle 0x%08llx ) failed!\n", role, eye, key, (unsigned long long) handle ); return ret; } DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurfaceAllocation ); if (iface) ret = IDirectFBSurfaceAllocation_Construct( iface, allocation, thiz ); else ret = DFB_NOSYSTEMMEMORY; if (ret) goto out; *ret_interface = iface; out: dfb_surface_allocation_unref( allocation ); return ret; } static DFBResult IDirectFBSurface_GetAllocation( IDirectFBSurface *thiz, DFBSurfaceBufferRole role, DFBSurfaceStereoEye eye, const char *key, IDirectFBSurfaceAllocation **ret_interface ) { DFBResult ret; CoreSurfaceAllocation *allocation; IDirectFBSurfaceAllocation *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, role %u, eye %u, key '%s' )\n", __FUNCTION__, thiz, role, eye, key ); ret = CoreSurface_GetAllocation( data->surface, role, eye, key, strlen( key ) + 1, &allocation ); if (ret) { D_DERROR( ret, "IDirectFBSurface: CoreSurface_GetAllocation( role %u, eye %u, key '%s' ) failed!\n", role, eye, key ); return ret; } DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurfaceAllocation ); if (iface) ret = IDirectFBSurfaceAllocation_Construct( iface, allocation, thiz ); else ret = DFB_NOSYSTEMMEMORY; if (ret) goto out; *ret_interface = iface; out: dfb_surface_allocation_unref( allocation ); return ret; } static DFBResult IDirectFBSurface_GetAllocations( IDirectFBSurface *thiz, const char *key, unsigned int max_num, unsigned int *ret_num, IDirectFBSurfaceAllocation **ret_interface_left, IDirectFBSurfaceAllocation **ret_interface_right ) { DFBResult ret; int i; unsigned int num; IDirectFBSurfaceAllocation *left[MAX_SURFACE_BUFFERS]; IDirectFBSurfaceAllocation *right[MAX_SURFACE_BUFFERS]; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p, key '%s', max %u )\n", __FUNCTION__, thiz, key, max_num ); if (!key || max_num < 1 || !ret_num || (!ret_interface_left && !ret_interface_right)) return DFB_INVARG; num = data->surface->num_buffers; if (num > max_num) num = max_num; memset( left, 0, num * sizeof(left[0]) ); memset( right, 0, num * sizeof(right[0]) ); for (i = 0; i < num; i++) { if (ret_interface_left) { ret = thiz->GetAllocation( thiz, i, DSSE_LEFT, key, &left[i] ); if (ret) goto error; } if (ret_interface_right) { ret = thiz->GetAllocation( thiz, i, DSSE_RIGHT, key, &right[i] ); if (ret) goto error; } } for (i = 0; i < num; i++) { if (ret_interface_left) ret_interface_left[i] = left[i]; if (ret_interface_right) ret_interface_right[i] = right[i]; } *ret_num = num; return DFB_OK; error: for (i = num - 1; i >= 0; i--) { if (right[i]) right[i]->Release( right[i] ); if (left[i]) left[i]->Release( left[i] ); } return ret; } static DFBResult IDirectFBSurface_Flush( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); CoreGraphicsStateClient_Flush( &data->state_client ); return DFB_OK; } static ReactionResult IDirectFBSurface_React( const void *msg_data, void *ctx ) { const CoreSurfaceNotification *notification = msg_data; IDirectFBSurface *thiz = ctx; IDirectFBSurface_data *data = thiz->priv; D_DEBUG_AT( Surface, "%s( %p, %p ) <- surface %p\n", __FUNCTION__, notification, thiz, data->surface ); if (notification->flags & CSNF_DESTROY) { if (data->surface) { D_WARN( "surface destroyed" ); data->surface = NULL; } return RS_REMOVE; } if (notification->flags & CSNF_SIZEFORMAT) { unsigned int i; DFBRectangle rect = { 0, 0, data->surface->config.size.w, data->surface->config.size.h }; dfb_rectangle_subtract( &rect, &data->area.insets ); if (data->limit_set) { data->area.current = data->area.granted; dfb_rectangle_intersect( &data->area.current, &rect ); } else data->area.wanted = data->area.granted = data->area.current = rect; /* Reset clip. */ if (data->clip_set) thiz->SetClip( thiz, &data->clip_wanted ); else thiz->SetClip( thiz, NULL ); for (i = 0; i < data->local_buffer_count; i++) { if (data->allocations[i]) { dfb_surface_allocation_unref( data->allocations[i] ); data->allocations[i] = NULL; } } data->local_buffer_count = data->surface->num_buffers; } return RS_OK; } static ReactionResult IDirectFBSurface_FrameReact( const void *msg_data, void *ctx ) { const CoreSurfaceNotification *notification = msg_data; IDirectFBSurface *thiz = ctx; IDirectFBSurface_data *data = thiz->priv; D_DEBUG_AT( Surface_Updates, "%s( %p, %p ) <- surface %p\n", __FUNCTION__, notification, thiz, data->surface ); if (notification->flags & CSNF_FRAME) { direct_mutex_lock( &data->back_buffer_lock ); D_DEBUG_AT( Surface_Updates, " -> got frame ack %u\n", notification->flip_count ); data->frame_ack = notification->flip_count; if (data->local_flip_count < notification->flip_count) { D_DEBUG_AT( Surface_Updates, " -> local count (%u) lower than frame ack (%u)\n", data->local_flip_count, notification->flip_count ); data->local_flip_count = notification->flip_count; } direct_waitqueue_broadcast( &data->back_buffer_wq ); direct_mutex_unlock( &data->back_buffer_lock ); } return RS_OK; } DFBResult IDirectFBSurface_Construct( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *wanted, DFBRectangle *granted, DFBInsets *insets, CoreSurface *surface, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *idirectfb ) { DFBResult ret; DFBRectangle rect = { 0, 0, surface->config.size.w, surface->config.size.h }; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBSurface ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_surface_ref( surface ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } data->ref = 1; data->thiz = thiz; data->surface = surface; data->caps = caps | surface->config.caps; data->core = core; data->idirectfb = idirectfb; data->frame_ack = surface->flips; data->src_eye = DSSE_LEFT; data->local_flip_count = surface->flips; data->local_buffer_count = surface->num_buffers; if (parent) { IDirectFBSurface_data *parent_data; if (parent->AddRef( parent )) { dfb_surface_unref( surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_FAILURE; } parent_data = parent->priv; if (!parent_data) { dfb_surface_unref( surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_DEAD; } if (!parent_data) { dfb_surface_unref( surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_DESTROYED; } direct_mutex_lock( &parent_data->children_lock ); direct_list_append( &parent_data->children_data, &data->link ); direct_mutex_unlock( &parent_data->children_lock ); data->parent = parent; } direct_mutex_init( &data->children_lock ); direct_waitqueue_init( &data->back_buffer_wq ); direct_mutex_init( &data->back_buffer_lock ); direct_mutex_init( &data->surface_client_lock ); /* The area insets. */ if (insets) { data->area.insets = *insets; dfb_rectangle_subtract( &rect, insets ); } /* The area that was requested. */ if (wanted) data->area.wanted = *wanted; else data->area.wanted = rect; /* The area that will never be exceeded. */ if (granted) data->area.granted = *granted; else data->area.granted = data->area.wanted; /* The currently accessible rectangle. */ data->area.current = data->area.granted; dfb_rectangle_intersect( &data->area.current, &rect ); D_DEBUG_AT( Surface, " -> wanted %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &data->area.wanted ) ); D_DEBUG_AT( Surface, " -> granted %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &data->area.granted ) ); D_DEBUG_AT( Surface, " -> current %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( &data->area.current ) ); /* Whether granted rectangle is meaningful. */ data->limit_set = (granted != NULL); dfb_state_init( &data->state, core ); dfb_state_set_destination_2( &data->state, surface, data->local_flip_count ); data->state.clip.x1 = data->area.current.x; data->state.clip.y1 = data->area.current.y; data->state.clip.x2 = data->area.current.x + (data->area.current.w ?: 1) - 1; data->state.clip.y2 = data->area.current.y + (data->area.current.h ?: 1) - 1; data->state.modified = SMF_ALL; ret = CoreGraphicsStateClient_Init( &data->state_client, &data->state ); if (ret) { dfb_state_destroy( &data->state ); if (parent) parent->Release( parent ); dfb_surface_unref( surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } if (data->surface->config.flags & CSCONF_PREALLOCATED) { ret = register_prealloc( data ); if (ret) { CoreGraphicsStateClient_Deinit( &data->state_client ); dfb_state_destroy( &data->state ); if (parent) parent->Release( parent ); dfb_surface_unref( surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } } dfb_surface_attach( surface, IDirectFBSurface_React, thiz, &data->reaction ); dfb_surface_attach_channel( surface, CSCH_FRAME, IDirectFBSurface_FrameReact, thiz, &data->reaction_frame ); thiz->AddRef = IDirectFBSurface_AddRef; thiz->Release = IDirectFBSurface_Release; thiz->GetCapabilities = IDirectFBSurface_GetCapabilities; thiz->GetPosition = IDirectFBSurface_GetPosition; thiz->GetSize = IDirectFBSurface_GetSize; thiz->GetVisibleRectangle = IDirectFBSurface_GetVisibleRectangle; thiz->GetPixelFormat = IDirectFBSurface_GetPixelFormat; thiz->GetColorSpace = IDirectFBSurface_GetColorSpace; thiz->GetAccelerationMask = IDirectFBSurface_GetAccelerationMask; thiz->GetPalette = IDirectFBSurface_GetPalette; thiz->SetPalette = IDirectFBSurface_SetPalette; thiz->SetAlphaRamp = IDirectFBSurface_SetAlphaRamp; thiz->GetStereoEye = IDirectFBSurface_GetStereoEye; thiz->SetStereoEye = IDirectFBSurface_SetStereoEye; thiz->Lock = IDirectFBSurface_Lock; thiz->GetFramebufferOffset = IDirectFBSurface_GetFramebufferOffset; thiz->Unlock = IDirectFBSurface_Unlock; thiz->Flip = IDirectFBSurface_Flip; thiz->FlipStereo = IDirectFBSurface_FlipStereo; thiz->SetField = IDirectFBSurface_SetField; thiz->Clear = IDirectFBSurface_Clear; thiz->SetClip = IDirectFBSurface_SetClip; thiz->GetClip = IDirectFBSurface_GetClip; thiz->SetColor = IDirectFBSurface_SetColor; thiz->SetColorIndex = IDirectFBSurface_SetColorIndex; thiz->SetSrcBlendFunction = IDirectFBSurface_SetSrcBlendFunction; thiz->SetDstBlendFunction = IDirectFBSurface_SetDstBlendFunction; thiz->SetPorterDuff = IDirectFBSurface_SetPorterDuff; thiz->SetSrcColorKey = IDirectFBSurface_SetSrcColorKey; thiz->SetSrcColorKeyIndex = IDirectFBSurface_SetSrcColorKeyIndex; thiz->SetDstColorKey = IDirectFBSurface_SetDstColorKey; thiz->SetDstColorKeyIndex = IDirectFBSurface_SetDstColorKeyIndex; thiz->SetBlittingFlags = IDirectFBSurface_SetBlittingFlags; thiz->Blit = IDirectFBSurface_Blit; thiz->TileBlit = IDirectFBSurface_TileBlit; thiz->BatchBlit = IDirectFBSurface_BatchBlit; thiz->StretchBlit = IDirectFBSurface_StretchBlit; thiz->TextureTriangles = IDirectFBSurface_TextureTriangles; thiz->SetDrawingFlags = IDirectFBSurface_SetDrawingFlags; thiz->FillRectangle = IDirectFBSurface_FillRectangle; thiz->DrawRectangle = IDirectFBSurface_DrawRectangle; thiz->DrawLine = IDirectFBSurface_DrawLine; thiz->DrawLines = IDirectFBSurface_DrawLines; thiz->FillTriangle = IDirectFBSurface_FillTriangle; thiz->FillRectangles = IDirectFBSurface_FillRectangles; thiz->FillSpans = IDirectFBSurface_FillSpans; thiz->FillTriangles = IDirectFBSurface_FillTriangles; thiz->SetFont = IDirectFBSurface_SetFont; thiz->GetFont = IDirectFBSurface_GetFont; thiz->DrawString = IDirectFBSurface_DrawString; thiz->DrawGlyph = IDirectFBSurface_DrawGlyph; thiz->SetEncoding = IDirectFBSurface_SetEncoding; thiz->GetSubSurface = IDirectFBSurface_GetSubSurface; thiz->GetGL = IDirectFBSurface_GetGL; thiz->Dump = IDirectFBSurface_Dump; thiz->DisableAcceleration = IDirectFBSurface_DisableAcceleration; thiz->ReleaseSource = IDirectFBSurface_ReleaseSource; thiz->SetIndexTranslation = IDirectFBSurface_SetIndexTranslation; thiz->SetRenderOptions = IDirectFBSurface_SetRenderOptions; thiz->SetMatrix = IDirectFBSurface_SetMatrix; thiz->SetSourceMask = IDirectFBSurface_SetSourceMask; thiz->MakeSubSurface = IDirectFBSurface_MakeSubSurface; thiz->Write = IDirectFBSurface_Write; thiz->Read = IDirectFBSurface_Read; thiz->SetColors = IDirectFBSurface_SetColors; thiz->BatchBlit2 = IDirectFBSurface_BatchBlit2; thiz->GetPhysicalAddress = IDirectFBSurface_GetPhysicalAddress; thiz->FillTrapezoids = IDirectFBSurface_FillTrapezoids; thiz->FillQuadrangles = IDirectFBSurface_FillQuadrangles; thiz->SetSrcColorKeyExtended = IDirectFBSurface_SetSrcColorKeyExtended; thiz->SetDstColorKeyExtended = IDirectFBSurface_SetDstColorKeyExtended; thiz->DrawMonoGlyphs = IDirectFBSurface_DrawMonoGlyphs; thiz->SetSrcColorMatrix = IDirectFBSurface_SetSrcColorMatrix; thiz->SetSrcConvolution = IDirectFBSurface_SetSrcConvolution; thiz->GetID = IDirectFBSurface_GetID; thiz->AllowAccess = IDirectFBSurface_AllowAccess; thiz->CreateEventBuffer = IDirectFBSurface_CreateEventBuffer; thiz->AttachEventBuffer = IDirectFBSurface_AttachEventBuffer; thiz->DetachEventBuffer = IDirectFBSurface_DetachEventBuffer; thiz->BatchStretchBlit = IDirectFBSurface_BatchStretchBlit; thiz->MakeClient = IDirectFBSurface_MakeClient; thiz->FrameAck = IDirectFBSurface_FrameAck; thiz->DumpRaw = IDirectFBSurface_DumpRaw; thiz->GetFrameTime = IDirectFBSurface_GetFrameTime; thiz->SetFrameTimeConfig = IDirectFBSurface_SetFrameTimeConfig; thiz->Allocate = IDirectFBSurface_Allocate; thiz->GetAllocation = IDirectFBSurface_GetAllocation; thiz->GetAllocations = IDirectFBSurface_GetAllocations; thiz->Flush = IDirectFBSurface_Flush; return DFB_OK; } void IDirectFBSurface_StopAll( IDirectFBSurface_data *data ) { if (!dfb_config->startstop) return; if (data->children_data) { IDirectFBSurface_data *child; direct_mutex_lock( &data->children_lock ); direct_list_foreach (child, data->children_data) { IDirectFBSurface_StopAll( child ); } direct_mutex_unlock( &data->children_lock ); } /* Signal end of sequence of operations. */ dfb_state_lock( &data->state ); dfb_state_stop_drawing( &data->state ); dfb_state_unlock( &data->state ); } void IDirectFBSurface_WaitForBackBuffer( IDirectFBSurface_data *data ) { D_DEBUG_AT( Surface_Updates, "%s( %p [%u] )\n", __FUNCTION__, data, data->surface->object.id ); D_DEBUG_AT( Surface_Updates, " -> surface %u, notify %u\n", data->local_flip_count, data->frame_ack ); direct_mutex_lock( &data->back_buffer_lock ); if (data->surface->flips_acked > data->frame_ack) data->frame_ack = data->surface->flips_acked; while (data->local_flip_count - data->frame_ack >= data->local_buffer_count - 1) { D_DEBUG_AT( Surface_Updates, " -> waiting for back buffer... (surface %u, notify %u)\n", data->local_flip_count, data->frame_ack ); if (data->local_buffer_count <= 1) break; direct_waitqueue_wait( &data->back_buffer_wq, &data->back_buffer_lock ); } D_DEBUG_AT( Surface_Updates, " -> done\n" ); direct_mutex_unlock( &data->back_buffer_lock ); } ================================================ FILE: src/display/idirectfbsurface.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBSURFACE_H__ #define __DISPLAY__IDIRECTFBSURFACE_H__ #include #include typedef DFBResult (*FlipFunc)( void *ctx ); /* * private data struct of IDirectFBSurface */ typedef struct { DirectLink link; int ref; /* reference counter */ DFBSurfaceCapabilities caps; /* capabilities */ struct { /* 'wanted' is passed to GetSubSurface(), it doesn't matter if it's too large or has negative starting coordinates as long as it intersects with the 'granted' rectangle of the parent. 'wanted' should be seen as the origin for operations on that surface. Non sub surfaces have a 'wanted' rectangle of '{ 0, 0, width, height }'. 'wanted' is calculated just once during surface creation. */ DFBRectangle wanted; /* 'granted' is the intersection of the 'wanted' rectangle and the 'granted' one of the parent. If they do not intersect, DFB_INVAREA is returned. For non sub surfaces it's the same as the 'wanted' rectangle, because it is the rectangle describing the whole surface. 'granted' is calculated just once during surface creation. */ DFBRectangle granted; /* 'current' is the intersection of the 'granted' rectangle and the surface extents. SetClip() and many other functions are limited by this. This way sub surface area information is preserved during surface resizing, e.g. when resizing a window. Calling SetClip() with NULL causes the clipping region to exactly cover the 'current' rectangle, also the flag 'clip_set' is cleared causing the clipping region to be set to the new 'current' after resizing. If SetClip() is called with a clipping region specified, an intersection is done with the 'wanted' rectangle that is then stored in 'clip_wanted' and 'clip_set' is set. However, if there is no intersection, DFB_INVARG is returned, otherwise another intersection is made with the 'current' rectangle and gets applied to the surface's state. Each resize, after the 'current' rectangle is updated, the clipping region is set to NULL or 'clip_wanted' depending on 'clip_set'. This way even clipping regions are restored or extended automatically. It's now possible to create a fullscreen primary and call SetVideoMode() with different resolutions or pixelformats several times without the need for updating the primary surface by recreating it. */ DFBRectangle current; /* 'insets' is actually set by the window manager. */ DFBInsets insets; } area; bool limit_set; /* granted rectangle set */ bool clip_set; /* fixed clip set, SetClip() called with clip != NULL */ DFBRegion clip_wanted; /* last region passed to SetClip() intersected by wanted area, only valid if clip_set != 0 */ CoreSurface *surface; /* buffer to show */ bool locked; /* which buffer is locked */ CoreSurfaceBufferLock lock; /* lock for allocation */ IDirectFBFont *font; /* font to use */ CardState state; /* render state to use */ DFBTextEncodingID encoding; /* text encoding */ struct { u8 r; /* red component */ u8 g; /* green component */ u8 b; /* blue component */ u32 value; /* r/g/b in surface's format */ } src_key; struct { u8 r; /* red component */ u8 g; /* green component */ u8 b; /* blue component */ u32 value; /* r/g/b in surface's format */ } dst_key; Reaction reaction; /* surface reaction */ Reaction reaction_frame; /* frame reaction for CSCH_FRAME */ CoreDFB *core; IDirectFB *idirectfb; IDirectFBSurface *thiz; IDirectFBSurface *parent; DirectLink *children_data; DirectLink *children_free; DirectMutex children_lock; CoreGraphicsStateClient state_client; CoreMemoryPermission *memory_permissions[3]; unsigned int memory_permissions_count; DirectWaitQueue back_buffer_wq; DirectMutex back_buffer_lock; unsigned int frame_ack; CoreSurfaceClient *surface_client; unsigned int surface_client_flip_count; DirectMutex surface_client_lock; DFBSurfaceStereoEye src_eye; long long current_frame_time; DFBFrameTimeConfig frametime_config; unsigned int local_flip_count; unsigned int local_buffer_count; CoreSurfaceAllocation *allocations[MAX_SURFACE_BUFFERS]; FlipFunc flip_func; void *flip_func_ctx; } IDirectFBSurface_data; /* * initializes interface struct and private data */ DFBResult IDirectFBSurface_Construct ( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *req_rect, DFBRectangle *clip_rect, DFBInsets *insets, CoreSurface *surface, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *idirectfb ); /* * destroys surface(s) and frees private data */ void IDirectFBSurface_Destruct ( IDirectFBSurface *thiz ); /* * flips surface buffers */ DFBResult IDirectFBSurface_Flip ( IDirectFBSurface *thiz, const DFBRegion *region, DFBSurfaceFlipFlags flags ); /* * flips left and right buffers */ DFBResult IDirectFBSurface_FlipStereo ( IDirectFBSurface *thiz, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ); /* * stops all drawing */ void IDirectFBSurface_StopAll ( IDirectFBSurface_data *data ); /* * waits for the back buffer */ void IDirectFBSurface_WaitForBackBuffer( IDirectFBSurface_data *data ); #endif ================================================ FILE: src/display/idirectfbsurface_layer.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Surface, "IDirectFBSurfaceL", "IDirectFBSurface_Layer Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBSurface_Layer */ typedef struct { IDirectFBSurface_data base; /* base surface implementation */ CoreLayerRegion *region; /* the region this surface belongs to */ } IDirectFBSurface_Layer_data; /**********************************************************************************************************************/ static void IDirectFBSurface_Layer_Destruct( IDirectFBSurface *thiz ) { IDirectFBSurface_Layer_data *data = thiz->priv; D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); dfb_layer_region_unref( data->region ); IDirectFBSurface_Destruct( thiz ); } static DirectResult IDirectFBSurface_Layer_Release( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Layer ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->base.ref == 0) IDirectFBSurface_Layer_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBSurface_Layer_Flip( IDirectFBSurface *thiz, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { DFBResult ret; DFBRegion reg; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Layer ) D_DEBUG_AT( Surface, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, thiz, region, flags ); if (!data->base.surface) return DFB_DESTROYED; if (data->base.locked) return DFB_LOCKED; if (!data->base.area.current.w || !data->base.area.current.h || (region && (region->x1 > region->x2 || region->y1 > region->y2))) return DFB_INVAREA; if (data->base.flip_func) return data->base.flip_func( data->base.flip_func_ctx ); IDirectFBSurface_StopAll( &data->base ); if (data->base.parent) { IDirectFBSurface_data *parent_data; parent_data = data->base.parent->priv; if (!parent_data) return DFB_DEAD; if (parent_data) { /* Signal end of sequence of operations. */ dfb_state_lock( &parent_data->state ); dfb_state_stop_drawing( &parent_data->state ); dfb_state_unlock( &parent_data->state ); } } dfb_region_from_rectangle( ®, &data->base.area.current ); if (region) { DFBRegion clip = DFB_REGION_INIT_TRANSLATED( region, data->base.area.wanted.x, data->base.area.wanted.y ); if (!dfb_region_region_intersect( ®, &clip )) return DFB_INVAREA; } D_DEBUG_AT( Surface, " -> flip %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( ® ) ); CoreGraphicsStateClient_Flush( &data->base.state_client ); switch (data->region->config.buffermode) { case DLBM_TRIPLE: case DLBM_BACKVIDEO: if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && reg.x1 == 0 && reg.y1 == 0 && reg.x2 == data->base.surface->config.size.w - 1 && reg.y2 == data->base.surface->config.size.h - 1)) if (!(flags & DSFLIP_UPDATE)) ++data->base.local_flip_count; break; default: break; } ret = CoreSurface_Flip2( data->base.surface, DFB_FALSE, ®, ®, flags, data->base.current_frame_time ); if (ret) { ret = CoreLayerRegion_FlipUpdate2( data->region, ®, ®, data->region->surface->flips, flags, data->base.current_frame_time ); if (ret) return ret; } IDirectFBSurface_WaitForBackBuffer( &data->base ); return DFB_OK; } static DFBResult IDirectFBSurface_Layer_FlipStereo( IDirectFBSurface *thiz, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ) { DFBResult ret; DFBRegion l_reg, r_reg; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Layer ) D_DEBUG_AT( Surface, "%s( %p, %p, %p, 0x%08x )\n", __FUNCTION__, thiz, left_region, right_region, flags ); if (!data->base.surface) return DFB_DESTROYED; if (!(data->base.surface->config.caps & DSCAPS_STEREO)) return DFB_UNSUPPORTED; if (data->base.locked) return DFB_LOCKED; if (!data->base.area.current.w || !data->base.area.current.h || (left_region && (left_region->x1 > left_region->x2 || left_region->y1 > left_region->y2)) || (right_region && (right_region->x1 > right_region->x2 || right_region->y1 > right_region->y2))) return DFB_INVAREA; IDirectFBSurface_StopAll( &data->base ); if (data->base.parent) { IDirectFBSurface_data *parent_data; parent_data = data->base.parent->priv; if (!parent_data) return DFB_DEAD; if (parent_data) { /* Signal end of sequence of operations. */ dfb_state_lock( &parent_data->state ); dfb_state_stop_drawing( &parent_data->state ); dfb_state_unlock( &parent_data->state ); } } dfb_region_from_rectangle( &l_reg, &data->base.area.current ); dfb_region_from_rectangle( &r_reg, &data->base.area.current ); if (left_region) { DFBRegion clip; clip = DFB_REGION_INIT_TRANSLATED( left_region, data->base.area.wanted.x, data->base.area.wanted.y ); if (!dfb_region_region_intersect( &l_reg, &clip )) return DFB_INVAREA; } if (right_region) { DFBRegion clip; clip = DFB_REGION_INIT_TRANSLATED( right_region, data->base.area.wanted.x, data->base.area.wanted.y ); if (!dfb_region_region_intersect( &r_reg, &clip )) return DFB_INVAREA; } D_DEBUG_AT( Surface, " -> flip stereo left: %4d,%4d-%4dx%4d right: %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( &l_reg ), DFB_RECTANGLE_VALS_FROM_REGION( &r_reg ) ); CoreGraphicsStateClient_Flush( &data->base.state_client ); if (data->base.surface->config.caps & DSCAPS_FLIPPING) { if ((flags & DSFLIP_SWAP) || (!(flags & DSFLIP_BLIT) && l_reg.x1 == 0 && l_reg.y1 == 0 && l_reg.x2 == data->base.surface->config.size.w - 1 && l_reg.y2 == data->base.surface->config.size.h - 1 && r_reg.x1 == 0 && r_reg.y1 == 0 && r_reg.x2 == data->base.surface->config.size.w - 1 && r_reg.y2 == data->base.surface->config.size.h - 1)) if (!(flags & DSFLIP_UPDATE)) ++data->base.local_flip_count; } ret = CoreSurface_Flip2( data->base.surface, DFB_FALSE, &l_reg, &r_reg, flags, data->base.current_frame_time ); if (ret) { ret = CoreLayerRegion_FlipUpdate2( data->region, &l_reg, &r_reg, data->region->surface->flips, flags, data->base.current_frame_time ); if (ret) return ret; } IDirectFBSurface_WaitForBackBuffer( &data->base ); return DFB_OK; } static DFBResult IDirectFBSurface_Layer_GetSubSurface( IDirectFBSurface *thiz, const DFBRectangle *rect, IDirectFBSurface **ret_interface ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Layer ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->base.surface) return DFB_DESTROYED; if (!ret_interface) return DFB_INVARG; direct_mutex_lock( &data->base.children_lock ); if (data->base.children_free) { IDirectFBSurface_data *child_data; child_data = (IDirectFBSurface_data*) data->base.children_free; direct_list_remove( &data->base.children_free, &child_data->link ); direct_list_append( &data->base.children_data, &child_data->link ); direct_mutex_unlock( &data->base.children_lock ); *ret_interface = child_data->thiz; ret = (*ret_interface)->MakeSubSurface( *ret_interface, thiz, rect ); if (ret) { direct_mutex_unlock( &data->base.children_lock ); return ret; } return DFB_OK; } direct_mutex_unlock( &data->base.children_lock ); DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBSurface ); if (rect || data->base.limit_set) { DFBRectangle wanted, granted; /* Compute wanted rectangle. */ if (rect) { wanted = *rect; wanted.x += data->base.area.wanted.x; wanted.y += data->base.area.wanted.y; if (wanted.w <= 0 || wanted.h <= 0) { wanted.w = 0; wanted.h = 0; } } else { wanted = data->base.area.wanted; } /* Compute granted rectangle. */ granted = wanted; dfb_rectangle_intersect( &granted, &data->base.area.granted ); ret = IDirectFBSurface_Layer_Construct( *ret_interface, thiz, &wanted, &granted, data->region, data->base.caps | DSCAPS_SUBSURFACE, data->base.core, data->base.idirectfb ); } else { ret = IDirectFBSurface_Layer_Construct( *ret_interface, thiz, NULL, NULL, data->region, data->base.caps | DSCAPS_SUBSURFACE, data->base.core, data->base.idirectfb ); } return ret; } DFBResult IDirectFBSurface_Layer_Construct( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *wanted, DFBRectangle *granted, CoreLayerRegion *region, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *dfb ) { DFBResult ret; CoreSurface *surface; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBSurface_Layer ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_layer_region_ref( region ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ret = CoreLayerRegion_GetSurface( region, &surface ); if (ret) { dfb_layer_region_unref( region ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ret = IDirectFBSurface_Construct( thiz, parent, wanted, granted, NULL, surface, surface->config.caps | caps, core, dfb ); if (ret) { dfb_surface_unref( surface ); dfb_layer_region_unref( region ); return ret; } dfb_surface_unref( surface ); data->region = region; thiz->Release = IDirectFBSurface_Layer_Release; thiz->Flip = IDirectFBSurface_Layer_Flip; thiz->FlipStereo = IDirectFBSurface_Layer_FlipStereo; thiz->GetSubSurface = IDirectFBSurface_Layer_GetSubSurface; return DFB_OK; } ================================================ FILE: src/display/idirectfbsurface_layer.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBSURFACE_LAYER_H__ #define __DISPLAY__IDIRECTFBSURFACE_LAYER_H__ #include /* * calls base surface constructor, reallocates private data and overloads functions of the interface */ DFBResult IDirectFBSurface_Layer_Construct( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *req_rect, DFBRectangle *clip_rect, CoreLayerRegion *region, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/display/idirectfbsurface_window.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( Surface, "IDirectFBSurfaceW", "IDirectFBSurface_Window Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBSurface_Window */ typedef struct { IDirectFBSurface_data base; /* base surface implementation */ CoreWindow *window; /* the window object */ DirectThread *flip_thread; /* thread for non-flipping primary surfaces, to make changes visible */ } IDirectFBSurface_Window_data; /**********************************************************************************************************************/ static void IDirectFBSurface_Window_Destruct( IDirectFBSurface *thiz ) { IDirectFBSurface_Window_data *data = thiz->priv; D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (data->flip_thread) { direct_thread_cancel( data->flip_thread ); direct_thread_join( data->flip_thread ); direct_thread_destroy( data->flip_thread ); } dfb_window_unref( data->window ); IDirectFBSurface_Destruct( thiz ); } static DirectResult IDirectFBSurface_Window_Release( IDirectFBSurface *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Window ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->base.ref == 0) IDirectFBSurface_Window_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBSurface_Window_Flip( IDirectFBSurface *thiz, const DFBRegion *region, DFBSurfaceFlipFlags flags ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Window ) D_DEBUG_AT( Surface, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, thiz, region, flags ); ret = IDirectFBSurface_Flip( thiz, region, flags ); if (ret) return ret; if (!data->window->config.opacity && data->base.caps & DSCAPS_PRIMARY) { CoreWindowConfig config = { .opacity = 0xff }; return CoreWindow_SetConfig( data->window, &config, NULL, 0, DWCONF_OPACITY ); } return DFB_OK; } static DFBResult IDirectFBSurface_Window_FlipStereo( IDirectFBSurface *thiz, const DFBRegion *left_region, const DFBRegion *right_region, DFBSurfaceFlipFlags flags ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Window ) D_DEBUG_AT( Surface, "%s( %p, %p, %p, 0x%08x )\n", __FUNCTION__, thiz, left_region, right_region, flags ); ret = IDirectFBSurface_FlipStereo( thiz, left_region, right_region, flags ); if (ret) return ret; if (!data->window->config.opacity && data->base.caps & DSCAPS_PRIMARY) { CoreWindowConfig config = { .opacity = 0xff }; return CoreWindow_SetConfig( data->window, &config, NULL, 0, DWCONF_OPACITY ); } return DFB_OK; } static DFBResult IDirectFBSurface_Window_GetSubSurface( IDirectFBSurface *thiz, const DFBRectangle *rect, IDirectFBSurface **ret_interface ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurface_Window ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->base.surface || !data->window || !data->window->surface) return DFB_DESTROYED; if (!ret_interface) return DFB_INVARG; direct_mutex_lock( &data->base.children_lock ); if (data->base.children_free) { IDirectFBSurface_data *child_data; child_data = (IDirectFBSurface_data*) data->base.children_free; direct_list_remove( &data->base.children_free, &child_data->link ); direct_list_append( &data->base.children_data, &child_data->link ); direct_mutex_unlock( &data->base.children_lock ); *ret_interface = child_data->thiz; ret = (*ret_interface)->MakeSubSurface( *ret_interface, thiz, rect ); if (ret) { direct_mutex_unlock( &data->base.children_lock ); return ret; } return DFB_OK; } direct_mutex_unlock( &data->base.children_lock ); DIRECT_ALLOCATE_INTERFACE( *ret_interface, IDirectFBSurface ); if (rect || data->base.limit_set) { DFBRectangle wanted, granted; /* Compute wanted rectangle. */ if (rect) { wanted = *rect; wanted.x += data->base.area.wanted.x; wanted.y += data->base.area.wanted.y; if (wanted.w <= 0 || wanted.h <= 0) { wanted.w = 0; wanted.h = 0; } } else { wanted = data->base.area.wanted; } /* Compute granted rectangle. */ granted = wanted; dfb_rectangle_intersect( &granted, &data->base.area.granted ); ret = IDirectFBSurface_Window_Construct( *ret_interface, thiz, &wanted, &granted, data->window, data->base.caps | DSCAPS_SUBSURFACE, data->base.core, data->base.idirectfb ); } else { ret = IDirectFBSurface_Window_Construct( *ret_interface, thiz, NULL, NULL, data->window, data->base.caps | DSCAPS_SUBSURFACE, data->base.core, data->base.idirectfb ); } return ret; } static void * IDirectFBSurface_Window_Flipping( DirectThread *thread, void *arg ) { IDirectFBSurface *thiz = arg; IDirectFBSurface_Window_data *data; D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_ASSERT( thiz != NULL ); data = thiz->priv; D_ASSERT( data != NULL ); while (data->base.surface && data->window->surface) { direct_thread_testcancel( thread ); thiz->Flip( thiz, NULL, DSFLIP_NONE ); direct_thread_sleep( 40000 ); } return NULL; } DFBResult IDirectFBSurface_Window_Construct( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *wanted, DFBRectangle *granted, CoreWindow *window, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *dfb ) { DFBResult ret; DFBInsets insets; CoreSurface *surface; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBSurface_Window ) D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); D_MAGIC_ASSERT( window, CoreWindow ); ret = CoreWindow_GetInsets( window, &insets ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ret = CoreWindow_GetSurface( window, &surface ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } ret = IDirectFBSurface_Construct( thiz, parent, wanted, granted, &insets, surface, caps, core, dfb ); dfb_surface_unref( surface ); if (ret) return ret; ret = dfb_window_ref( window ); if (ret) { IDirectFBSurface_Destruct( thiz ); return ret; } data->window = window; /* Create an auto flipping thread if the application requested a (primary) surface that doesn't need to be flipped. Window surfaces even need to be flipped when they are single buffered. */ if (!(caps & DSCAPS_FLIPPING) && !(caps & DSCAPS_SUBSURFACE)) { if (dfb_config->autoflip_window) data->flip_thread = direct_thread_create( DTT_DEFAULT, IDirectFBSurface_Window_Flipping, thiz, "SurfWin Flipping" ); else D_WARN( "non-flipping window surface and no 'autoflip-window' option used" ); } thiz->Release = IDirectFBSurface_Window_Release; thiz->Flip = IDirectFBSurface_Window_Flip; thiz->FlipStereo = IDirectFBSurface_Window_FlipStereo; thiz->GetSubSurface = IDirectFBSurface_Window_GetSubSurface; return DFB_OK; } ================================================ FILE: src/display/idirectfbsurface_window.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBSURFACE_WINDOW_H__ #define __DISPLAY__IDIRECTFBSURFACE_WINDOW_H__ #include /* * calls base surface constructor, reallocates private data and overloads functions of the interface */ DFBResult IDirectFBSurface_Window_Construct( IDirectFBSurface *thiz, IDirectFBSurface *parent, DFBRectangle *req_rect, DFBRectangle *clip_rect, CoreWindow *window, DFBSurfaceCapabilities caps, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/display/idirectfbsurfaceallocation.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( SurfaceAllocation, "IDirectFBSurfaceAllocation", "IDirectFBSurfaceAllocation Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBSurfaceAllocation */ typedef struct { int ref; /* reference counter */ CoreSurfaceAllocation *allocation; /* the allocation object */ IDirectFBSurface *idirectfbsurface; /* the surface interface object */ CoreSurfaceBufferLock lock; /* lock for the allocation */ } IDirectFBSurfaceAllocation_data; /**********************************************************************************************************************/ static void IDirectFBSurfaceAllocation_Destruct( IDirectFBSurfaceAllocation *thiz ) { IDirectFBSurfaceAllocation_data *data = thiz->priv; D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); if (data->lock.allocation) { dfb_surface_pool_unlock( data->lock.allocation->pool, data->lock.allocation, &data->lock ); dfb_surface_buffer_lock_reset( &data->lock ); } if (data->allocation) dfb_surface_allocation_unref( data->allocation ); dfb_surface_buffer_lock_deinit( &data->lock ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBSurfaceAllocation_AddRef( IDirectFBSurfaceAllocation *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBSurfaceAllocation_Release( IDirectFBSurfaceAllocation *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBSurfaceAllocation_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBSurfaceAllocation_GetDescription( IDirectFBSurfaceAllocation *thiz, DFBSurfaceDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->allocation) return DFB_DESTROYED; if (!ret_desc) return DFB_INVARG; ret_desc->flags = DSDESC_HINTS; ret_desc->hints = DSHF_NONE; if (data->allocation->type & CSTF_LAYER) ret_desc->hints |= DSHF_LAYER; return DFB_OK; } static DFBResult IDirectFBSurfaceAllocation_GetHandle( IDirectFBSurfaceAllocation *thiz, u64 *ret_handle ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->allocation) return DFB_DESTROYED; if (!ret_handle) return DFB_INVARG; /* Lock the allocation. */ if (!data->lock.allocation) { ret = dfb_surface_pool_lock( data->allocation->pool, data->allocation, &data->lock ); if (ret) { D_DERROR( ret, "IDirectFBSurfaceAllocation: Locking allocation failed!\n" ); return ret; } } *ret_handle = (u64)(long) data->lock.handle; return DFB_OK; } static DFBResult IDirectFBSurfaceAllocation_GetPitch( IDirectFBSurfaceAllocation *thiz, int *ret_pitch ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->allocation) return DFB_DESTROYED; if (!ret_pitch) return DFB_INVARG; /* Lock the allocation. */ if (!data->lock.allocation) { ret = dfb_surface_pool_lock( data->allocation->pool, data->allocation, &data->lock ); if (ret) { D_DERROR( ret, "IDirectFBSurfaceAllocation: Locking allocation failed!\n" ); return ret; } } *ret_pitch = data->lock.pitch; return DFB_OK; } static DFBResult IDirectFBSurfaceAllocation_Updated( IDirectFBSurfaceAllocation *thiz, const DFBBox *updates, unsigned int num_updates ) { DIRECT_INTERFACE_GET_DATA( IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p, updates %p, num %u )\n", __FUNCTION__, thiz, updates, num_updates ); if (!data->allocation) return DFB_DESTROYED; if (!updates && num_updates > 0) return DFB_INVARG; return CoreSurfaceAllocation_Updated( data->allocation, updates, num_updates ); } DFBResult IDirectFBSurfaceAllocation_Construct( IDirectFBSurfaceAllocation *thiz, CoreSurfaceAllocation *allocation, IDirectFBSurface *idirectfbsurface ) { DFBResult ret; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBSurfaceAllocation ) D_DEBUG_AT( SurfaceAllocation, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_surface_allocation_ref( allocation ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } data->ref = 1; data->allocation = allocation; data->idirectfbsurface = idirectfbsurface; dfb_surface_buffer_lock_init( &data->lock, CSAID_CPU, CSAF_READ | CSAF_WRITE ); thiz->AddRef = IDirectFBSurfaceAllocation_AddRef; thiz->Release = IDirectFBSurfaceAllocation_Release; thiz->GetDescription = IDirectFBSurfaceAllocation_GetDescription; thiz->GetHandle = IDirectFBSurfaceAllocation_GetHandle; thiz->GetPitch = IDirectFBSurfaceAllocation_GetPitch; thiz->Updated = IDirectFBSurfaceAllocation_Updated; return DFB_OK; } ================================================ FILE: src/display/idirectfbsurfaceallocation.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DISPLAY__IDIRECTFBSURFACEALLOCATION_H__ #define __DISPLAY__IDIRECTFBSURFACEALLOCATION_H__ #include /* * initializes interface struct and private data */ DFBResult IDirectFBSurfaceAllocation_Construct( IDirectFBSurfaceAllocation *thiz, CoreSurfaceAllocation *allocation, IDirectFBSurface *idirectfbsurface ); #endif ================================================ FILE: src/gfx/clip.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( GFX_Clipping, "GFX/Clipping", "DirectFB Graphics Clipping" ); /**********************************************************************************************************************/ #define REGION_CODE(x,y,cx1,cx2,cy1,cy2) ( ((y) > (cy2) ? 8 : 0) | \ ((y) < (cy1) ? 4 : 0) | \ ((x) > (cx2) ? 2 : 0) | \ ((x) < (cx1) ? 1 : 0) ) DFBBoolean dfb_clip_line( const DFBRegion *clip, DFBRegion *line ) { unsigned char region_code1 = REGION_CODE( line->x1, line->y1, clip->x1, clip->x2, clip->y1, clip->y2 ); unsigned char region_code2 = REGION_CODE( line->x2, line->y2, clip->x1, clip->x2, clip->y1, clip->y2 ); D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); while (region_code1 | region_code2) { /* Line completely outside the clipping rectangle. */ if (region_code1 & region_code2) return DFB_FALSE; if (region_code1) { if (region_code1 & 8) { /* divide line at bottom */ line->x1 = line->x1 +(line->x2-line->x1) * (clip->y2 - line->y1) / (line->y2-line->y1); line->y1 = clip->y2; } else if (region_code1 & 4) { /* divide line at top */ line->x1 = line->x1 +(line->x2-line->x1) * (clip->y1 - line->y1) / (line->y2-line->y1); line->y1 = clip->y1; } else if (region_code1 & 2) { /* divide line at right */ line->y1 = line->y1 +(line->y2-line->y1) * (clip->x2 - line->x1) / (line->x2-line->x1); line->x1 = clip->x2; } else if (region_code1 & 1) { /* divide line at right */ line->y1 = line->y1 +(line->y2-line->y1) * (clip->x1 - line->x1) / (line->x2-line->x1); line->x1 = clip->x1; } region_code1 = REGION_CODE( line->x1, line->y1, clip->x1, clip->x2, clip->y1, clip->y2 ); } else { if (region_code2 & 8) { /* divide line at bottom */ line->x2 = line->x1 +(line->x2-line->x1) * (clip->y2 - line->y1) / (line->y2-line->y1); line->y2 = clip->y2; } else if (region_code2 & 4) { /* divide line at top */ line->x2 = line->x1 +(line->x2-line->x1) * (clip->y1 - line->y1) / (line->y2-line->y1); line->y2 = clip->y1; } else if (region_code2 & 2) { /* divide line at right */ line->y2 = line->y1 +(line->y2-line->y1) * (clip->x2 - line->x1) / (line->x2-line->x1); line->x2 = clip->x2; } else if (region_code2 & 1) { /* divide line at right */ line->y2 = line->y1 +(line->y2-line->y1) * (clip->x1 - line->x1) / (line->x2-line->x1); line->x2 = clip->x1; } region_code2 = REGION_CODE( line->x2, line->y2, clip->x1, clip->x2, clip->y1, clip->y2 ); } } D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4d,%4d\n", DFB_LINE_VALS( line ) ); /* Successfully clipped or clipping not neccessary. */ return DFB_TRUE; } DFBBoolean dfb_clip_rectangle( const DFBRegion *clip, DFBRectangle *rect ) { D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); if ((clip->x1 >= rect->x + rect->w) || (clip->x2 < rect->x) || (clip->y1 >= rect->y + rect->h) || (clip->y2 < rect->y)) return DFB_FALSE; if (clip->x1 > rect->x) { rect->w += rect->x - clip->x1; rect->x = clip->x1; } if (clip->y1 > rect->y) { rect->h += rect->y - clip->y1; rect->y = clip->y1; } if (clip->x2 < rect->x + rect->w - 1) rect->w = clip->x2 - rect->x + 1; if (clip->y2 < rect->y + rect->h - 1) rect->h = clip->y2 - rect->y + 1; D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( rect ) ); return DFB_TRUE; } DFBBoolean dfb_clip_triangle( const DFBRegion *clip, const DFBTriangle *tri, DFBPoint p[6], int *num ) { DFBRegion edges[3]; int num_edges; int i, n; DFBPoint p1 = { 0, 0 }, p2 = { 0, 0 }; D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); /* Initialize edges. */ edges[0].x1 = tri->x1; edges[0].y1 = tri->y1; edges[0].x2 = tri->x2; edges[0].y2 = tri->y2; edges[1].x1 = tri->x2; edges[1].y1 = tri->y2; edges[1].x2 = tri->x3; edges[1].y2 = tri->y3; edges[2].x1 = tri->x3; edges[2].y1 = tri->y3; edges[2].x2 = tri->x1; edges[2].y2 = tri->y1; num_edges = 3; for (i = 0; i < num_edges; i++) { DFBRegion *reg = &edges[i]; DFBRegion line; bool i1, i2; /* Clip the edge to the clipping region. */ line = *reg; if (dfb_clip_line( clip, &line )) { *reg = line; continue; } /* If the edge doesn't intersect clipping region, then intersect the edge with the diagonals of the clipping * rectangle. * If intersection point exits, add the nearest corner of the clipping region to the list of vertices. */ /* Diagonal (x1,y1) (x2,y2). */ line = (DFBRegion) { clip->x1, clip->y1, clip->x2, clip->y2 }; i1 = dfb_line_segment_intersect( &line, reg, &p1.x, &p1.y ); if (i1) { /* Get nearest corner. */ if (p1.x <= clip->x1 || p1.y <= clip->y1) { p1.x = clip->x1; p1.y = clip->y1; } else { p1.x = clip->x2; p1.y = clip->y2; } } /* Diagonal (x2,y1) (x1,y2). */ line = (DFBRegion) { clip->x2, clip->y1, clip->x1, clip->y2 }; i2 = dfb_line_segment_intersect( &line, reg, &p2.x, &p2.y ); if (i2) { /* Get nearest corner. */ if (p2.x >= clip->x2 || p2.y <= clip->y1) { p2.x = clip->x2; p2.y = clip->y1; } else { p2.x = clip->x1; p2.y = clip->y2; } } if (i1 && i2) { reg->x1 = p1.x; reg->y1 = p1.y; reg->x2 = p2.x; reg->y2 = p2.y; } else if (i1) { reg->x1 = reg->x2 = p1.x; reg->y1 = reg->y2 = p1.y; } else if (i2) { reg->x1 = reg->x2 = p2.x; reg->y1 = reg->y2 = p2.y; } else { /* Redudant edge. */ memmove( reg, &edges[i+1], (num_edges - i - 1) * sizeof(DFBRegion) ); num_edges--; i--; } } if (num_edges < 1) { *num = 0; return DFB_FALSE; } /* Get vertices from edges. */ p[0].x = edges[0].x1; p[0].y = edges[0].y1; n = 1; if (edges[0].x2 != edges[0].x1 || edges[0].y2 != edges[0].y1) { p[1].x = edges[0].x2; p[1].y = edges[0].y2; n++; } for (i = 1; i < num_edges; i++) { if (edges[i].x1 != p[n-1].x || edges[i].y1 != p[n-1].y) { p[n].x = edges[i].x1; p[n].y = edges[i].y1; n++; } if (edges[i].x2 != p[n-1].x || edges[i].y2 != p[n-1].y) { p[n].x = edges[i].x2; p[n].y = edges[i].y2; n++; } } if (p[n-1].x == p[0].x && p[n-1].y == p[0].y) n--; *num = n; D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4d,%4d-%4d,%4d\n", DFB_TRIANGLE_VALS( tri ) ); /* Actually fail if the number of vertices is below 3. */ return (n >= 3); } DFBEdgeFlags dfb_clip_edges( const DFBRegion *clip, DFBRectangle *rect ) { DFBEdgeFlags flags = DFEF_ALL; if ((clip->x1 >= rect->x + rect->w) || (clip->x2 < rect->x) || (clip->y1 >= rect->y + rect->h) || (clip->y2 < rect->y)) return DFEF_NONE; if (clip->x1 > rect->x) { rect->w += rect->x - clip->x1; rect->x = clip->x1; flags &= ~DFEF_LEFT; } if (clip->y1 > rect->y) { rect->h += rect->y - clip->y1; rect->y = clip->y1; flags &= ~DFEF_TOP; } if (clip->x2 < rect->x + rect->w - 1) { rect->w = clip->x2 - rect->x + 1; flags &= ~DFEF_RIGHT; } if (clip->y2 < rect->y + rect->h - 1) { rect->h = clip->y2 - rect->y + 1; flags &= ~DFEF_BOTTOM; } return flags; } void dfb_build_clipped_rectangle_outlines( DFBRectangle *rect, const DFBRegion *clip, DFBRectangle *ret_outlines, int *ret_num ) { DFBEdgeFlags edges = dfb_clip_edges( clip, rect ); int t = (edges & DFEF_TOP ? 1 : 0); int tb = t + (edges & DFEF_BOTTOM ? 1 : 0); int num = 0; D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); DFB_RECTANGLE_ASSERT( rect ); D_ASSERT( ret_outlines != NULL ); D_ASSERT( ret_num != NULL ); if (edges & DFEF_TOP) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y; out->w = rect->w; out->h = 1; } if (rect->h > t) { if (edges & DFEF_BOTTOM) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y + rect->h - 1; out->w = rect->w; out->h = 1; } if (rect->h > tb) { if (edges & DFEF_LEFT) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x; out->y = rect->y + t; out->w = 1; out->h = rect->h - tb; } if (rect->w > 1 || !(edges & DFEF_LEFT)) { if (edges & DFEF_RIGHT) { DFBRectangle *out = &ret_outlines[num++]; out->x = rect->x + rect->w - 1; out->y = rect->y + t; out->w = 1; out->h = rect->h - tb; } } } } *ret_num = num; } void dfb_clip_blit( const DFBRegion *clip, DFBRectangle *srect, int *dx, int *dy ) { D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); if (clip->x1 > *dx) { srect->w = MIN( (clip->x2 - clip->x1) + 1, (*dx + srect->w) - clip->x1 ); srect->x += clip->x1 - *dx; *dx = clip->x1; } else if (clip->x2 < *dx + srect->w - 1) { srect->w = clip->x2 - *dx + 1; } if (clip->y1 > *dy) { srect->h = MIN( (clip->y2 - clip->y1) + 1, (*dy + srect->h) - clip->y1 ); srect->y += clip->y1 - *dy; *dy = clip->y1; } else if (clip->y2 < *dy + srect->h - 1) { srect->h = clip->y2 - *dy + 1; } D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4dx%4d\n -> %4d,%4d", DFB_RECTANGLE_VALS( srect ), *dx, *dy ); } void dfb_clip_stretchblit( const DFBRegion *clip, DFBRectangle *srect, DFBRectangle *drect ) { DFBRectangle orig_dst = *drect; D_DEBUG_AT( GFX_Clipping, "%s()\n", __FUNCTION__ ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); dfb_clip_rectangle( clip, drect ); if (drect->x != orig_dst.x) srect->x += (drect->x - orig_dst.x) * (srect->w / (float) orig_dst.w); if (drect->y != orig_dst.y) srect->y += (drect->y - orig_dst.y) * (srect->h / (float) orig_dst.h); if (drect->w != orig_dst.w) srect->w = srect->w * (drect->w / (float) orig_dst.w); if (drect->h != orig_dst.h) srect->h = srect->h * (drect->h / (float) orig_dst.h); D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( srect ), DFB_RECTANGLE_VALS( drect ) ); } void dfb_clip_blit_flipped_rotated( const DFBRegion *clip, DFBRectangle *srect, DFBRectangle *drect, DFBSurfaceBlittingFlags flags ) { DFBRegion dest = DFB_REGION_INIT_FROM_RECTANGLE( drect ); DFBRegion clipped = dest; D_DEBUG_AT( GFX_Clipping, "%s( 0x%08x )\n", __FUNCTION__, flags ); D_DEBUG_AT( GFX_Clipping, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( clip ) ); D_ASSERT( !(flags & (DSBLIT_ROTATE270 | DSBLIT_ROTATE180)) ); if (flags & DSBLIT_ROTATE90) { D_ASSERT( srect->w == drect->h ); D_ASSERT( srect->h == drect->w ); } else { D_ASSERT( srect->w == drect->w ); D_ASSERT( srect->h == drect->h ); } dfb_region_region_intersect( &clipped, clip ); dfb_rectangle_from_region( drect, &clipped ); switch (flags & (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL | DSBLIT_ROTATE90)) { case DSBLIT_NOFX: srect->x += clipped.x1 - dest.x1; srect->y += clipped.y1 - dest.y1; break; case DSBLIT_FLIP_HORIZONTAL: srect->x += dest.x2 - clipped.x2; srect->y += clipped.y1 - dest.y1; break; case DSBLIT_FLIP_VERTICAL: srect->x += clipped.x1 - dest.x1; srect->y += dest.y2 - clipped.y2; break; case DSBLIT_ROTATE90: srect->x += dest.y2 - clipped.y2; srect->y += clipped.x1 - dest.x1; break; case (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL): /* ROTATE180 */ srect->x += dest.x2 - clipped.x2; srect->y += dest.y2 - clipped.y2; break; case (DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL | DSBLIT_FLIP_HORIZONTAL): /* ROTATE270 */ srect->x += clipped.y1 - dest.y1; srect->y += dest.x2 - clipped.x2; break; case (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL): srect->x += clipped.y1 - dest.y1; srect->y += clipped.x1 - dest.x1; break; case (DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL): srect->x += dest.y2 - clipped.y2; srect->y += dest.x2 - clipped.x2; break; } if (flags & DSBLIT_ROTATE90) { srect->w = drect->h; srect->h = drect->w; } else { srect->w = drect->w; srect->h = drect->h; } D_DEBUG_AT( GFX_Clipping, " -> %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( srect ), DFB_RECTANGLE_VALS( drect ) ); } ================================================ FILE: src/gfx/clip.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GFX__CLIP_H__ #define __GFX__CLIP_H__ #include /**********************************************************************************************************************/ typedef enum { DFEF_NONE = 0x00000000, DFEF_LEFT = 0x00000001, DFEF_RIGHT = 0x00000002, DFEF_TOP = 0x00000004, DFEF_BOTTOM = 0x00000008, DFEF_ALL = 0x0000000F } DFBEdgeFlags; /**********************************************************************************************************************/ /* * Clip the line to the clipping region. * Return true if at least one pixel of the line resides in the region. */ DFBBoolean dfb_clip_line ( const DFBRegion *clip, DFBRegion *line ); /* * Clip the rectangle to the clipping region. * Return true if there was an intersection with the clipping region. */ DFBBoolean dfb_clip_rectangle ( const DFBRegion *clip, DFBRectangle *rect ); /* * Clip the triangle to the clipping region. * Return true if the triangle if visible within the region. * The vertices of the polygon resulting from intersection are returned in 'buf'. The number of vertices is at least 3. */ DFBBoolean dfb_clip_triangle ( const DFBRegion *clip, const DFBTriangle *tri, DFBPoint buf[6], int *num ); /* * Clip the rectangle to the clipping region. * Return a flag for each edge that wasn't cut off. */ DFBEdgeFlags dfb_clip_edges ( const DFBRegion *clip, DFBRectangle *rect ); /* * Get the outlines of a clipped rectangle. */ void dfb_build_clipped_rectangle_outlines( DFBRectangle *rect, const DFBRegion *clip, DFBRectangle *ret_outlines, int *ret_num ); /* * Clip the blitting request to the clipping region. This includes adjustment of source and destination coordinates. */ void dfb_clip_blit ( const DFBRegion *clip, DFBRectangle *srect, int *dx, int *dy ); /* * Clip the stretch blit request to the clipping region. * This includes adjustment of source and destination coordinates based on the scaling factor. */ void dfb_clip_stretchblit ( const DFBRegion *clip, DFBRectangle *srect, DFBRectangle *drect ); /* * Clip the blitting request to the clipping region. This includes adjustment of source and destination coordinates. * In contrast to dfb_clip_blit() this also honors DSBLIT_ROTATE_ and DSBLIT_FLIP_ blitting flags. */ void dfb_clip_blit_flipped_rotated ( const DFBRegion *clip, DFBRectangle *srect, DFBRectangle *drect, DFBSurfaceBlittingFlags flags ); /**********************************************************************************************************************/ /* * Check if a clip ot the rectangle is needed. */ static __inline__ DFBBoolean dfb_clip_needed( const DFBRegion *clip, DFBRectangle *rect ) { return ((clip->x1 > rect->x) || (clip->y1 > rect->y) || (clip->x2 < rect->x + rect->w - 1) || (clip->y2 < rect->y + rect->h - 1)) ? DFB_TRUE : DFB_FALSE; } /* * Check if requested blitting lies outside of the clipping region. * Return true if blitting may need to be performed. */ static __inline__ DFBBoolean dfb_clip_blit_precheck( const DFBRegion *clip, int w, int h, int dx, int dy ) { if (w < 1 || h < 1 || (clip->x1 >= dx + w) || (clip->x2 < dx) || (clip->y1 >= dy + h) || (clip->y2 < dy)) return DFB_FALSE; return DFB_TRUE; } #endif ================================================ FILE: src/gfx/convert.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( GFX_Converter, "GFX/Converter", "DirectFB Graphics Converter" ); /**********************************************************************************************************************/ /* lookup tables for 2/3bit to 8bit color conversion */ static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; #define EXPAND_1to8(v) ((v) ? 0xff : 0x00) #define EXPAND_2to8(v) lookup2to8[v] #define EXPAND_3to8(v) lookup3to8[v] #define EXPAND_4to8(v) (((v) << 4) | (v) ) #define EXPAND_5to8(v) (((v) << 3) | ((v) >> 2)) #define EXPAND_6to8(v) (((v) << 2) | ((v) >> 4)) #define EXPAND_7to8(v) (((v) << 1) | ((v) >> 6)) #define YCBCR_TO_RGB(y,cb,cr,r,g,b) \ if (colorspace == DSCS_BT601) \ YCBCR_TO_RGB_BT601(y,cb,cr,r,g,b); \ else if (colorspace == DSCS_BT709) \ YCBCR_TO_RGB_BT709(y,cb,cr,r,g,b); \ else if (colorspace == DSCS_BT2020) \ YCBCR_TO_RGB_BT2020(y,cb,cr,r,g,b); \ else { \ r = g = b = 0; \ } #define RGB_TO_YCBCR(r,g,b,y,cb,cr) \ if (colorspace == DSCS_BT601) \ RGB_TO_YCBCR_BT601(r,g,b,y,cb,cr); \ else if (colorspace == DSCS_BT709) \ RGB_TO_YCBCR_BT709(r,g,b,y,cb,cr); \ else if (colorspace == DSCS_BT2020) \ RGB_TO_YCBCR_BT2020(r,g,b,y,cb,cr); \ else { \ y = 16; \ cb = cr = 128; \ } /**********************************************************************************************************************/ void dfb_pixel_to_color( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, unsigned long pixel, DFBColor *ret_color ) { D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } ret_color->a = 0xff; switch (format) { case DSPF_RGB332: ret_color->r = EXPAND_3to8( (pixel & 0xe0) >> 5 ); ret_color->g = EXPAND_3to8( (pixel & 0x1c) >> 2 ); ret_color->b = EXPAND_2to8( pixel & 0x03 ); break; case DSPF_ARGB1555: ret_color->a = EXPAND_1to8( pixel >> 15 ); case DSPF_RGB555: ret_color->r = EXPAND_5to8( (pixel & 0x7c00) >> 10 ); ret_color->g = EXPAND_5to8( (pixel & 0x03e0) >> 5 ); ret_color->b = EXPAND_5to8( pixel & 0x001f ); break; case DSPF_BGR555: ret_color->r = EXPAND_5to8( pixel & 0x001f ); ret_color->g = EXPAND_5to8( (pixel & 0x03e0) >> 5 ); ret_color->b = EXPAND_5to8( (pixel & 0x7c00) >> 10 ); break; case DSPF_ARGB2554: ret_color->a = EXPAND_2to8( pixel >> 14 ); ret_color->r = EXPAND_5to8( (pixel & 0x3e00) >> 9 ); ret_color->g = EXPAND_5to8( (pixel & 0x01f0) >> 4 ); ret_color->b = EXPAND_4to8( pixel & 0x000f ); break; case DSPF_ARGB4444: ret_color->a = EXPAND_4to8( pixel >> 12 ); case DSPF_RGB444: ret_color->r = EXPAND_4to8( (pixel & 0x0f00) >> 8 ); ret_color->g = EXPAND_4to8( (pixel & 0x00f0) >> 4 ); ret_color->b = EXPAND_4to8( pixel & 0x000f ); break; case DSPF_RGBA4444: ret_color->r = EXPAND_4to8( pixel >> 12 ); ret_color->g = EXPAND_4to8( (pixel & 0x0f00) >> 8 ); ret_color->b = EXPAND_4to8( (pixel & 0x00f0) >> 4 ); ret_color->a = EXPAND_4to8( pixel & 0x000f ); break; case DSPF_ARGB8565: ret_color->a = pixel >> 16; case DSPF_RGB16: ret_color->r = EXPAND_5to8( (pixel & 0xf800) >> 11 ); ret_color->g = EXPAND_6to8( (pixel & 0x07e0) >> 5 ); ret_color->b = EXPAND_5to8( pixel & 0x001f ); break; case DSPF_ARGB1666: case DSPF_ARGB6666: ret_color->a = (format = DSPF_ARGB1666) ? EXPAND_1to8( (pixel & 0x040000) >> 18 ) : EXPAND_6to8( (pixel & 0xfc0000) >> 18 ); case DSPF_RGB18: ret_color->r = EXPAND_6to8( (pixel & 0x03f000) >> 12 ); ret_color->g = EXPAND_6to8( (pixel & 0x000fc0) >> 6 ); ret_color->b = EXPAND_6to8( pixel & 0x00003f ); break; case DSPF_ARGB: ret_color->a = pixel >> 24; case DSPF_RGB24: case DSPF_RGB32: ret_color->r = (pixel & 0xff0000) >> 16; ret_color->g = (pixel & 0x00ff00) >> 8; ret_color->b = pixel & 0x0000ff; break; case DSPF_ABGR: ret_color->a = pixel >> 24; case DSPF_BGR24: ret_color->b = (pixel & 0xff0000) >> 16; ret_color->g = (pixel & 0x00ff00) >> 8; ret_color->r = pixel & 0x0000ff; break; case DSPF_AiRGB: ret_color->a = (pixel >> 24) ^ 0xff; ret_color->r = (pixel & 0xff0000) >> 16; ret_color->g = (pixel & 0x00ff00) >> 8; ret_color->b = pixel & 0x0000ff; break; case DSPF_RGBA5551: ret_color->a = EXPAND_1to8( pixel & 1 ); ret_color->r = EXPAND_5to8( (pixel & 0xf800) >> 11 ); ret_color->g = EXPAND_5to8( (pixel & 0x07c0) >> 6 ); ret_color->b = EXPAND_5to8( (pixel & 0x003e) >> 1 ); break; case DSPF_RGBAF88871: ret_color->a = EXPAND_7to8( (pixel & 0x000000fe) >> 1 ); ret_color->r = (pixel & 0xff000000) >> 24; ret_color->g = (pixel & 0x00ff0000) >> 16; ret_color->b = (pixel & 0x0000ff00) >> 8; break; case DSPF_AYUV: ret_color->a = pixel >> 24; YCBCR_TO_RGB( (pixel & 0xff0000) >> 16, (pixel & 0x00ff00) >> 8, pixel & 0x0000ff, ret_color->r, ret_color->g, ret_color->b ); break; case DSPF_AVYU: ret_color->a = pixel >> 24; case DSPF_VYU: YCBCR_TO_RGB( (pixel & 0x00ff00) >> 8, pixel & 0x0000ff, (pixel & 0xff0000) >> 16, ret_color->r, ret_color->g, ret_color->b ); break; case DSPF_YUY2: #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( (pixel & 0x00ff0000) >> 16, (pixel & 0xff000000) >> 24, (pixel & 0x0000ff00) >> 8, ret_color->r, ret_color->g, ret_color->b ); #else YCBCR_TO_RGB( (pixel & 0x00ff0000) >> 16, (pixel & 0x0000ff00) >> 8, (pixel & 0xff000000) >> 24, ret_color->r, ret_color->g, ret_color->b ); #endif break; case DSPF_UYVY: #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( (pixel & 0xff000000) >> 24, (pixel & 0x00ff0000) >> 16, pixel & 0x000000ff, ret_color->r, ret_color->g, ret_color->b ); #else YCBCR_TO_RGB( (pixel & 0xff000000) >> 24, pixel & 0x000000ff, (pixel & 0x00ff0000) >> 16, ret_color->r, ret_color->g, ret_color->b ); #endif break; case DSPF_I420: case DSPF_Y42B: case DSPF_Y444: YCBCR_TO_RGB( (pixel & 0xff0000) >> 16, (pixel & 0x00ff00) >> 8, pixel & 0x0000ff, ret_color->r, ret_color->g, ret_color->b ); break; case DSPF_YV12: case DSPF_YV16: case DSPF_YV24: YCBCR_TO_RGB( (pixel & 0xff0000) >> 16, pixel & 0x0000ff, (pixel & 0x00ff00) >> 8, ret_color->r, ret_color->g, ret_color->b ); break; case DSPF_A8: ret_color->a = pixel; /* fall through */ default: ret_color->r = 0; ret_color->g = 0; ret_color->b = 0; } } unsigned long dfb_pixel_from_color( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const DFBColor *color ) { u32 y, cb, cr; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return 0; } switch (format) { case DSPF_RGB332: return PIXEL_RGB332( color->r, color->g, color->b ); case DSPF_ARGB1555: return PIXEL_ARGB1555( color->a, color->r, color->g, color->b ); case DSPF_RGB555: return PIXEL_RGB555( color->r, color->g, color->b ); case DSPF_BGR555: return PIXEL_BGR555( color->r, color->g, color->b ); case DSPF_ARGB2554: return PIXEL_ARGB2554( color->a, color->r, color->g, color->b ); case DSPF_ARGB4444: return PIXEL_ARGB4444( color->a, color->r, color->g, color->b ); case DSPF_RGB444: return PIXEL_RGB444( color->r, color->g, color->b ); case DSPF_RGBA4444: return PIXEL_RGBA4444( color->a, color->r, color->g, color->b ); case DSPF_ARGB8565: return PIXEL_ARGB8565( color->a, color->r, color->g, color->b ); case DSPF_RGB16: return PIXEL_RGB16( color->r, color->g, color->b ); case DSPF_ARGB1666: return PIXEL_ARGB1666( color->a, color->r, color->g, color->b ); case DSPF_ARGB6666: return PIXEL_ARGB6666( color->a, color->r, color->g, color->b ); case DSPF_RGB18: return PIXEL_RGB18( color->r, color->g, color->b ); case DSPF_ARGB: return PIXEL_ARGB( color->a, color->r, color->g, color->b ); case DSPF_RGB24: return PIXEL_RGB32( color->r, color->g, color->b ) & 0xffffff; case DSPF_BGR24: return PIXEL_RGB32( color->b, color->g, color->r ) & 0xffffff; case DSPF_RGB32: return PIXEL_RGB32( color->r, color->g, color->b ) & 0xffffff; case DSPF_ABGR: return PIXEL_ABGR( color->a, color->r, color->g, color->b ); case DSPF_AiRGB: return PIXEL_AiRGB( color->a, color->r, color->g, color->b ); case DSPF_RGBA5551: return PIXEL_RGBA5551( color->a, color->r, color->g, color->b ); case DSPF_RGBAF88871: return PIXEL_RGBAF88871( color->a, color->r, color->g, color->b ); case DSPF_AYUV: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); return PIXEL_AYUV( color->a, y, cb, cr ); case DSPF_AVYU: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); return PIXEL_AVYU( color->a, y, cb, cr ); case DSPF_VYU: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); return PIXEL_VYU( y, cb, cr ); case DSPF_YUY2: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); #ifdef WORDS_BIGENDIAN return PIXEL_YUY2_BE( y, cb, cr ); #else return PIXEL_YUY2_LE( y, cb, cr ); #endif case DSPF_UYVY: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); #ifdef WORDS_BIGENDIAN return PIXEL_UYVY_BE( y, cb, cr ); #else return PIXEL_UYVY_LE( y, cb, cr ); #endif case DSPF_I420: case DSPF_Y42B: case DSPF_Y444: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); return y << 16 | (cb << 8) | cr; case DSPF_YV12: case DSPF_YV16: case DSPF_YV24: RGB_TO_YCBCR( color->r, color->g, color->b, y, cb, cr ); return y << 16 | (cr << 8) | cb; case DSPF_A8: return color->a; default: if (DFB_PIXELFORMAT_IS_INDEXED( format )) D_ONCE( "palette format" ); else D_WARN( "unknown format 0x%08x", (unsigned int) format ); } return 0x55555555; } void dfb_pixel_to_components( DFBSurfacePixelFormat format, unsigned long pixel, u8 *a, u8 *c2, /* either Y or R */ u8 *c1, /* either U or G */ u8 *c0 ) /* either V or B */ { D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); *a = 0xff; switch (format) { case DSPF_RGB332: *c2 = EXPAND_3to8( (pixel & 0xe0) >> 5 ); *c1 = EXPAND_3to8( (pixel & 0x1c) >> 2 ); *c0 = EXPAND_2to8( pixel & 0x03 ); break; case DSPF_ARGB1555: *a = EXPAND_1to8( pixel >> 15 ); case DSPF_RGB555: *c2 = EXPAND_5to8( (pixel & 0x7c00) >> 10 ); *c1 = EXPAND_5to8( (pixel & 0x03e0) >> 5 ); *c0 = EXPAND_5to8( pixel & 0x001f ); break; case DSPF_BGR555: *c2 = EXPAND_5to8( pixel & 0x001f ); *c1 = EXPAND_5to8( (pixel & 0x03e0) >> 5 ); *c0 = EXPAND_5to8( (pixel & 0x7c00) >> 10 ); break; case DSPF_ARGB2554: *a = EXPAND_2to8( pixel >> 14 ); *c2 = EXPAND_5to8( (pixel & 0x3e00) >> 9 ); *c1 = EXPAND_5to8( (pixel & 0x01f0) >> 4 ); *c0 = EXPAND_4to8( pixel & 0x000f ); break; case DSPF_ARGB4444: *a = EXPAND_4to8( pixel >> 12 ); case DSPF_RGB444: *c2 = EXPAND_4to8( (pixel & 0x0f00) >> 8 ); *c1 = EXPAND_4to8( (pixel & 0x00f0) >> 4 ); *c0 = EXPAND_4to8( (pixel & 0x000f) ); break; case DSPF_RGBA4444: *c2 = EXPAND_4to8( pixel >> 12 ); *c1 = EXPAND_4to8( (pixel & 0x0f00) >> 8 ); *c0 = EXPAND_4to8( (pixel & 0x00f0) >> 4 ); *a = EXPAND_4to8( (pixel & 0x000f) ); break; case DSPF_RGB16: *c2 = EXPAND_5to8( (pixel & 0xf800) >> 11 ); *c1 = EXPAND_6to8( (pixel & 0x07e0) >> 5 ); *c0 = EXPAND_5to8( pixel & 0x001f ); break; case DSPF_ARGB: *a = pixel >> 24; case DSPF_RGB24: case DSPF_RGB32: *c2 = (pixel & 0xff0000) >> 16; *c1 = (pixel & 0x00ff00) >> 8; *c0 = pixel & 0x0000ff; break; case DSPF_ABGR: *a = pixel >> 24; case DSPF_BGR24: *c0 = (pixel & 0xff0000) >> 16; *c1 = (pixel & 0x00ff00) >> 8; *c2 = pixel & 0x0000ff; break; case DSPF_AiRGB: *a = (pixel >> 24) ^ 0xff; *c2 = (pixel & 0xff0000) >> 16; *c1 = (pixel & 0x00ff00) >> 8; *c0 = pixel & 0x0000ff; break; case DSPF_AYUV: *a = pixel >> 24; *c2 = (pixel & 0xff0000) >> 16; *c1 = (pixel & 0x00ff00) >> 8; *c0 = pixel & 0x0000ff; break; case DSPF_YUY2: #ifdef WORDS_BIGENDIAN *c2 = pixel & 0xff; *c1 = pixel >> 24; *c0 = (pixel & 0xff00) >> 8; #else *c2 = pixel & 0xff; *c1 = (pixel & 0xff00) >> 8; *c0 = pixel >> 24; #endif break; case DSPF_UYVY: #ifdef WORDS_BIGENDIAN *c2 = (pixel & 0xff00) >> 8; *c1 = (pixel & 0xff0000) >> 16; *c0 = pixel & 0xff; #else *c2 = (pixel & 0xff00) >> 8; *c1 = pixel & 0xff; *c0 = (pixel & 0xff0000) >> 16; #endif break; case DSPF_I420: case DSPF_YV12: case DSPF_Y42B: case DSPF_YV16: case DSPF_Y444: case DSPF_YV24: *c2 = pixel & 0xff; *c1 = (pixel & 0xff00) >> 8; *c0 = (pixel & 0xff0000) >> 16; break; default: *c2 = 0; *c1 = 0; *c0 = 0; } } void dfb_convert_to_rgb16( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u16 *dst, int dpitch, int width, int height ) { const int dp2 = dpitch / 2; int x; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } switch (format) { case DSPF_RGB16: while (height--) { direct_memcpy( dst, src, width * 2 ); src += spitch; dst += dp2; } break; case DSPF_NV16: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV61: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV24: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0 ; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV42: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0 ; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_UYVY: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x += 2) { int r, g, b; int y0, y1, cb, cr; y1 = src32[x/2] >> 24; cr = (src32[x/2] >> 16) & 0xff; y0 = (src32[x/2] >> 8) & 0xff; cb = src32[x/2] & 0xff; YCBCR_TO_RGB( y0, cb, cr, r, g, b ); dst[x] = PIXEL_RGB16( r, g, b ); YCBCR_TO_RGB( y1, cb, cr, r, g, b ); dst[x+1] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_RGB444: case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB16( EXPAND_4to8( (src16[x] & 0x0f00) >> 8 ), EXPAND_4to8( (src16[x] & 0x00f0) >> 4 ), EXPAND_4to8( src16[x] & 0x000f ) ); src += spitch; dst += dp2; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB16( EXPAND_4to8( (src16[x] & 0xf000) >> 12 ), EXPAND_4to8( (src16[x] & 0x0f00) >> 8 ), EXPAND_4to8( (src16[x] & 0x00f0) >> 4 ) ); src += spitch; dst += dp2; } break; case DSPF_RGB555: case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ((src16[x] & 0x7c00) << 1) | ((src16[x] & 0x03e0) << 1) | ((src16[x] & 0x0200) >> 4) | (src16[x] & 0x001f); src += spitch; dst += dp2; } break; case DSPF_BGR555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ((src16[x] & 0x7c00) >> 10) | ((src16[x] & 0x03e0) << 1) | ((src16[x] & 0x001f) << 11); src += spitch; dst += dp2; } break; case DSPF_RGB32: case DSPF_ARGB: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB16( (src32[x] & 0xff0000) >> 16, (src32[x] & 0x00ff00) >> 8, src32[x] & 0x0000ff ); src += spitch; dst += dp2; } break; case DSPF_ABGR: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB16( src32[x] & 0x0000ff, (src32[x] & 0x00ff00) >> 8, (src32[x] & 0xff0000) >> 16 ); src += spitch; dst += dp2; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB16( (src32[x] & 0xff000000) >> 24, (src32[x] & 0x00ff0000) >> 16, (src32[x] & 0x0000ff00) >> 8 ); src += spitch; dst += dp2; } break; case DSPF_AYUV: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 16) & 0xff, (src32[x] >> 8) & 0xff, src32[x] & 0xff, r, g, b ); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 8) & 0xff, src32[x] & 0xff, (src32[x] >> 16) & 0xff, r, g, b ); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_VYU: while (height--) { const u8 *src8 = src; int x3; for (x = 0, x3 = 0; x < width; x++, x3 += 3) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x3+1], src8[x3+2], src8[x3], r, g, b ); #else YCBCR_TO_RGB( src8[x3+1], src8[x3], src8[x3+2], r, g, b ); #endif dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = (src16[x] & 0xf800) | (src16[x] & 0x07c0) | ((src16[x] & 0x0400) >> 5) | ((src16[x] & 0x003e) >> 1); src += spitch; dst += dp2; } break; case DSPF_ARGB8565: ++height; while (--height) { const u8 *src8 = src; for (x = 0; x < width; x++) #ifdef WORDS_BIGENDIAN dst[x] = (src8[x*3+1] << 8) | src8[x*3+2]; #else dst[x] = (src8[x*3+1] << 8) | src8[x*3+0]; #endif src += spitch; dst += dp2; } break; case DSPF_I420: case DSPF_YV12: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; src_cb += (height % 2) ? 0 : scbpitch; src_cr += (height % 2) ? 0 : scrpitch; dst += dp2; } break; case DSPF_Y42B: case DSPF_YV16: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; src_cb += scbpitch; src_cr += scrpitch; dst += dp2; } break; case DSPF_Y444: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + surface_height * spitch; const u8 *cr = src + 2 * surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_YV24: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + 2 * surface_height * spitch; const u8 *cr = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB16( r, g, b ); } src += spitch; dst += dp2; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_rgb555( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u16 *dst, int dpitch, int width, int height ) { const int dp2 = dpitch / 2; int x; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } switch (format) { case DSPF_RGB555: case DSPF_ARGB1555: while (height--) { direct_memcpy( dst, src, width * 2 ); src += spitch; dst += dp2; } break; case DSPF_NV16: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV61: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV24: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_NV42: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_RGB444: case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB555( EXPAND_4to8( (src16[x] & 0x0f00) >> 8 ), EXPAND_4to8( (src16[x] & 0x00f0) >> 4 ), EXPAND_4to8( src16[x] & 0x000f ) ); src += spitch; dst += dp2; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB555( EXPAND_4to8( (src16[x] & 0xf000) >> 12 ), EXPAND_4to8( (src16[x] & 0x0f00) >> 8 ), EXPAND_4to8( (src16[x] & 0x00f0) >> 4 ) ); src += spitch; dst += dp2; } break; case DSPF_RGB16: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ((src16[x] & 0xffc0) >> 1) | (src16[x] & 0x001f); src += spitch; dst += dp2; } break; case DSPF_BGR555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ((src16[x] & 0x7c00) >> 10) | (src16[x] & 0x03e0) | ((src16[x] & 0x001f) << 10); src += spitch; dst += dp2; } break; case DSPF_RGB32: case DSPF_ARGB: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB555( (src32[x] & 0xff0000) >> 16, (src32[x] & 0x00ff00) >> 8, src32[x] & 0x0000ff ); src += spitch; dst += dp2; } break; case DSPF_ABGR: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB555( src32[x] & 0x0000ff, (src32[x] & 0x00ff00) >> 8, (src32[x] & 0xff0000) >> 16); src += spitch; dst += dp2; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB555( (src32[x] & 0xff000000) >> 24, (src32[x] & 0x00ff0000) >> 16, (src32[x] & 0x0000ff00) >> 8 ); src += spitch; dst += dp2; } break; case DSPF_AYUV: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 16) & 0xff, (src32[x] >> 8) & 0xff, src32[x] & 0xff, r, g, b ); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = src16[x] >> 1; src += spitch; dst += dp2; } break; case DSPF_ARGB8565: ++height; while (--height) { const u8 *src8 = src; for (x = 0; x < width; x++) { u32 pixel = (src8[x*3+1] << 8) | src8[x*3+2]; dst[x] = ARGB8565_TO_ARGB1555( pixel ); } src += spitch; dst += dp2; } break; case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 8) & 0xff, src32[x] & 0xff, (src32[x] >> 16) & 0xff, r, g, b ); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_VYU: while (height--) { const u8 *src8 = src; int x3; for (x = 0, x3 = 0; x < width; x++, x3 += 3) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x3+1], src8[x3+2], src8[x3], r, g, b ); #else YCBCR_TO_RGB( src8[x3+1], src8[x3], src8[x3+2], r, g, b ); #endif dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_I420: case DSPF_YV12: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; src_cb += (height % 2) ? 0 : scbpitch; src_cr += (height % 2) ? 0 : scrpitch; dst += dp2; } break; case DSPF_Y42B: case DSPF_YV16: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; src_cb += scbpitch; src_cr += scrpitch; dst += dp2; } break; case DSPF_Y444: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + surface_height * spitch; const u8 *cr = src + 2 * surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; case DSPF_YV24: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + 2 * surface_height * spitch; const u8 *cr = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB555( r, g, b ); } src += spitch; dst += dp2; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_rgb32( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u32 *dst, int dpitch, int width, int height ) { const int dp4 = dpitch / 4; int x; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } switch (format) { case DSPF_RGB32: case DSPF_ARGB: while (height--) { direct_memcpy( dst, src, width * 4 ); src += spitch; dst += dp4; } break; case DSPF_ABGR: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB32( src32[x] & 0x0000ff, (src32[x] & 0x00ff00) >> 8, (src32[x] & 0xff0000) >> 16 ); src += spitch; dst += dp4; } break; case DSPF_RGB24: while (height--) { const u8 *src8 = src; for (x = 0; x < width; x++) #ifdef WORDS_BIGENDIAN dst[x] = (src8[x*3+0] << 16) | (src8[x*3+1] << 8) | src8[x*3+2]; #else dst[x] = (src8[x*3+2] << 16) | (src8[x*3+1] << 8) | src8[x*3+0]; #endif src += spitch; dst += dp4; } break; case DSPF_BGR24: while (height--) { const u8 *src8 = src; for (x = 0; x < width; x++) #ifdef WORDS_BIGENDIAN dst[x] = (src8[x*3+2] << 16) | (src8[x*3+1] << 8) | src8[x*3+0]; #else dst[x] = (src8[x*3+0] << 16) | (src8[x*3+1] << 8) | src8[x*3+2]; #endif src += spitch; dst += dp4; } break; case DSPF_AYUV: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 16) & 0xff, (src32[x] >> 8) & 0xff, src32[x] & 0xff, r, g, b ); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV16: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV61: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV24: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #endif dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV42: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #endif dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_RGB444: case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ARGB4444_TO_RGB32( src16[x] ); src += spitch; dst += dp4; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = RGBA4444_TO_RGB32( src16[x] ); src += spitch; dst += dp4; } break; case DSPF_RGB555: case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB32( ((src16[x] & 0x7c00) >> 7) | ((src16[x] & 0x7000) >> 12), ((src16[x] & 0x03e0) >> 2) | ((src16[x] & 0x0380) >> 7), ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2) ); src += spitch; dst += dp4; } break; case DSPF_BGR555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB32( ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2), ((src16[x] & 0x03e0) >> 2) | ((src16[x] & 0x0380) >> 7), ((src16[x] & 0x7c00) >> 7) | ((src16[x] & 0x7000) >> 12) ); src += spitch; dst += dp4; } break; case DSPF_RGB16: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB32( ((src16[x] & 0xf800) >> 8) | ((src16[x] & 0xe000) >> 13), ((src16[x] & 0x07e0) >> 3) | ((src16[x] & 0x0600) >> 9), ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2) ); src += spitch; dst += dp4; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_RGB32( ((src16[x] & 0xf800) >> 8) | ((src16[x] & 0xe000) >> 13), ((src16[x] & 0x07c0) >> 3) | ((src16[x] & 0x0700) >> 8), ((src16[x] & 0x003e) << 2) | ((src16[x] & 0x0038) >> 3) ); src += spitch; dst += dp4; } break; case DSPF_ARGB8565: ++height; while (--height) { const u8 *src8 = src; for (x = 0; x < width; x++) { u8 r, g, b; r = EXPAND_5to8( src8[x*3+1] >> 3 ); g = EXPAND_6to8( (src8[x*3+1] << 5) | (src8[x*3+2] >> 3) ); b = EXPAND_5to8( src8[x*3+2] & 0x1f ); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = (src32[x] & 0xffffff00) >> 8; src += spitch; dst += dp4; } break; case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 8) & 0xff, src32[x] & 0xff, (src32[x] >> 16) & 0xff, r, g, b ); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_VYU: while (height--) { const u8 *src8 = src; int x3; for (x = 0, x3 = 0; x < width; x++, x3 += 3) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x3+1], src8[x3+2], src8[x3], r, g, b ); #else YCBCR_TO_RGB( src8[x3+1], src8[x3], src8[x3+2], r, g, b ); #endif dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_I420: case DSPF_YV12: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; src_cb += (height % 2) ? 0 : scbpitch; src_cr += (height % 2) ? 0 : scrpitch; dst += dp4; } break; case DSPF_Y42B: case DSPF_YV16: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; src_cb += scbpitch; src_cr += scrpitch; dst += dp4; } break; case DSPF_Y444: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + surface_height * spitch; const u8 *cr = src + 2 * surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_YV24: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + 2 * surface_height * spitch; const u8 *cr = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_RGB32( r, g, b ); } src += spitch; dst += dp4; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_argb( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u32 *dst, int dpitch, int width, int height ) { const int dp4 = dpitch / 4; int x; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } switch (format) { case DSPF_ARGB: while (height--) { direct_memcpy( dst, src, width * 4 ); src += spitch; dst += dp4; } break; case DSPF_ABGR: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( (src32[x] & 0xff000000) >> 24, src32[x] & 0x000000ff, (src32[x] & 0x0000ff00) >> 8, (src32[x] & 0x00ff0000) >> 16 ); src += spitch; dst += dp4; } break; case DSPF_RGB32: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = src32[x] | 0xff000000; src += spitch; dst += dp4; } break; case DSPF_RGB24: while (height--) { const u8 *src8 = src; for (x = 0; x < width; x++) #ifdef WORDS_BIGENDIAN dst[x] = (src8[x*3+0] << 16) | (src8[x*3+1] << 8) | src8[x*3+2] | 0xff000000; #else dst[x] = (src8[x*3+2] << 16) | (src8[x*3+1] << 8) | src8[x*3+0] | 0xff000000; #endif src += spitch; dst += dp4; } break; case DSPF_BGR24: while (height--) { const u8 *src8 = src; for (x = 0; x < width; x++) #ifdef WORDS_BIGENDIAN dst[x] = (src8[x*3+2] << 16) | (src8[x*3+1] << 8) | src8[x*3+0] | 0xff000000; #else dst[x] = (src8[x*3+0] << 16) | (src8[x*3+1] << 8) | src8[x*3+1] | 0xff000000; #endif src += spitch; dst += dp4; } break; case DSPF_AYUV: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 16) & 0xff, (src32[x] >> 8) & 0xff, src32[x] & 0xff, r, g, b ); dst[x] = PIXEL_ARGB( src32[x] >> 24, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV16: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #endif dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV61: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x>>1] & 0xff, src16[x>>1] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x>>1] >> 8, src16[x>>1] & 0xff, r, g, b ); #endif dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV24: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #endif dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_NV42: while (height--) { const u8 *src8 = src; const u16 *src16 = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x], src16[x] & 0xff, src16[x] >> 8, r, g, b ); #else YCBCR_TO_RGB( src8[x], src16[x] >> 8, src16[x] & 0xff, r, g, b ); #endif dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = ARGB4444_TO_ARGB( src16[x] ); src += spitch; dst += dp4; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = RGBA4444_TO_ARGB( src16[x] ); src += spitch; dst += dp4; } break; case DSPF_RGB444: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( 0xff, ((src16[x] & 0x0f00) >> 4) | ((src16[x] & 0x0f00) >> 8), (src16[x] & 0x00f0) | ((src16[x] & 0x00f0) >> 4), ((src16[x] & 0x000f) << 4) | (src16[x] & 0x000f) ); src += spitch; dst += dp4; } break; case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( (src16[x] & 0x8000) ? 0xff : 0x00, ((src16[x] & 0x7c00) >> 7) | ((src16[x] & 0x7000) >> 12), ((src16[x] & 0x03e0) >> 2) | ((src16[x] & 0x0380) >> 7), ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2) ); src += spitch; dst += dp4; } break; case DSPF_RGB555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( 0xff, ((src16[x] & 0x7c00) >> 7) | ((src16[x] & 0x7000) >> 12), ((src16[x] & 0x03e0) >> 2) | ((src16[x] & 0x0380) >> 7), ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2) ); src += spitch; dst += dp4; } break; case DSPF_BGR555: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( 0xff, ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2), ((src16[x] & 0x03e0) >> 2) | ((src16[x] & 0x0380) >> 7), ((src16[x] & 0x7c00) >> 7) | ((src16[x] & 0x7000) >> 12) ); src += spitch; dst += dp4; } break; case DSPF_RGB16: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( 0xff, ((src16[x] & 0xf800) >> 8) | ((src16[x] & 0xe000) >> 13), ((src16[x] & 0x07e0) >> 3) | ((src16[x] & 0x0600) >> 9), ((src16[x] & 0x001f) << 3) | ((src16[x] & 0x001c) >> 2) ); src += spitch; dst += dp4; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( (src16[x] & 0x1) ? 0xff : 0x00, ((src16[x] & 0xf800) >> 8) | ((src16[x] & 0xe000) >> 13), ((src16[x] & 0x07c0) >> 3) | ((src16[x] & 0x0700) >> 8), ((src16[x] & 0x003e) << 2) | ((src16[x] & 0x0038) >> 3) ); src += spitch; dst += dp4; } break; case DSPF_ARGB8565: ++height; while (--height) { const u8 *src8 = src; for (x = 0; x < width; x++) { u8 r, g, b; r = EXPAND_5to8( src8[x*3+1] >> 3 ); g = EXPAND_6to8( (src8[x*3+1] << 5) | (src8[x*3+2] >> 3) ); b = EXPAND_5to8( src8[x*3+2] & 0x1f ); dst[x] = PIXEL_ARGB( src8[x*3], r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) dst[x] = PIXEL_ARGB( EXPAND_7to8( (src32[x] & 0x000000fe) >> 1 ), (src32[x] & 0xff000000) >> 24, (src32[x] & 0x00ff0000) >> 16, (src32[x] & 0x0000ff00) >> 8 ); src += spitch; dst += dp4; } break; case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( (src32[x] >> 8) & 0xff, src32[x] & 0xff, (src32[x] >> 16) & 0xff, r, g, b ); dst[x] = PIXEL_ARGB( (src32[x] >> 24), r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_VYU: while (height--) { const u8 *src8 = src; int x3; for (x = 0, x3 = 0; x < width; x++, x3 += 3) { int r, g, b; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[x3+1], src8[x3+2], src8[x3], r, g, b ); #else YCBCR_TO_RGB( src8[x3+1], src8[x3], src8[x3+2], r, g, b ); #endif dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_I420: case DSPF_YV12: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; src_cb += (height % 2) ? 0 : scbpitch; src_cr += (height % 2) ? 0 : scrpitch; dst += dp4; } break; case DSPF_Y42B: case DSPF_YV16: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y, *cb, *cr, r, g, b ); ++y; cb += (x & 1); cr += (x & 1); dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; src_cb += scbpitch; src_cr += scrpitch; dst += dp4; } break; case DSPF_Y444: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + surface_height * spitch; const u8 *cr = src + 2 * surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; case DSPF_YV24: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + 2 * surface_height * spitch; const u8 *cr = src + surface_height * spitch; for (x = 0; x < width; x++) { int r, g, b; YCBCR_TO_RGB( *y++, *cb++, *cr++, r, g, b ); dst[x] = PIXEL_ARGB( 0xff, r, g, b ); } src += spitch; dst += dp4; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_rgb24( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u8 *dst, int dpitch, int width, int height ) { int n, n3; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); if (!DFB_COLORSPACE_IS_COMPATIBLE( colorspace, format )) { D_ONCE( "incompatible colorspace" ); return; } switch (format) { case DSPF_A8: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = src8[n]; dst[n3+1] = src8[n]; dst[n3+2] = src8[n]; } src += spitch; dst += dpitch; } break; case DSPF_AiRGB: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src32[n] & 0xff0000) >> 16; dst[n3+1] = (src32[n] & 0x00ff00) >> 8; dst[n3+2] = src32[n] & 0x0000ff; } src += spitch; dst += dpitch; } break; case DSPF_ARGB: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src32[n] & 0xff0000) >> 16; dst[n3+1] = (src32[n] & 0x00ff00) >> 8; dst[n3+2] = src32[n] & 0x0000ff; } src += spitch; dst += dpitch; } break; case DSPF_ABGR: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = src32[n] & 0x0000ff; dst[n3+1] = (src32[n] & 0x00ff00) >> 8; dst[n3+2] = (src32[n] & 0xff0000) >> 16; } src += spitch; dst += dpitch; } break; case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0x7c00) >> 7; dst[n3+1] = (src16[n] & 0x03e0) >> 2; dst[n3+2] = (src16[n] & 0x001f) << 3; } src += spitch; dst += dpitch; } break; case DSPF_RGB555: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0x7c00) >> 7; dst[n3+1] = (src16[n] & 0x03e0) >> 2; dst[n3+2] = (src16[n] & 0x001f) << 3; } src += spitch; dst += dpitch; } break; case DSPF_BGR555: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+2] = (src16[n] & 0x7c00) >> 7; dst[n3+1] = (src16[n] & 0x03e0) >> 2; dst[n3+0] = (src16[n] & 0x001f) << 3; } src += spitch; dst += dpitch; } break; case DSPF_ARGB2554: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0x3e00) >> 6; dst[n3+1] = (src16[n] & 0x01f0) >> 1; dst[n3+2] = (src16[n] & 0x000f) << 4; } src += spitch; dst += dpitch; } break; case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0x0f00) >> 4; dst[n3+1] = src16[n] & 0x00f0; dst[n3+2] = (src16[n] & 0x000f) << 4; } src += spitch; dst += dpitch; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0xf000) >> 8; dst[n3+1] = (src16[n] & 0x0f00) >> 4; dst[n3+2] = src16[n] & 0x00f0; } src += spitch; dst += dpitch; } break; case DSPF_RGB444: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0x0f00) >> 4; dst[n3+1] = src16[n] & 0x00f0; dst[n3+2] = (src16[n] & 0x000f) << 4; } src += spitch; dst += dpitch; } break; case DSPF_RGB332: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = EXPAND_3to8( src8[n] >> 5 ); dst[n3+1] = EXPAND_3to8( (src8[n] >> 2) & 0x07 ); dst[n3+2] = EXPAND_2to8( src8[n] & 0x03 ); } src += spitch; dst += dpitch; } break; case DSPF_RGB16: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src16[n] & 0xf800) >> 8; dst[n3+1] = (src16[n] & 0x07e0) >> 3; dst[n3+2] = (src16[n] & 0x001f) << 3; } src += spitch; dst += dpitch; } break; case DSPF_RGB24: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN dst[n3+0] = src8[n3+0]; dst[n3+1] = src8[n3+1]; dst[n3+2] = src8[n3+2]; #else dst[n3+0] = src8[n3+2]; dst[n3+1] = src8[n3+1]; dst[n3+2] = src8[n3+0]; #endif } src += spitch; dst += dpitch; } break; case DSPF_BGR24: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN dst[n3+0] = src8[n3+2]; dst[n3+1] = src8[n3+1]; dst[n3+2] = src8[n3+0]; #else dst[n3+0] = src8[n3+0]; dst[n3+1] = src8[n3+1]; dst[n3+2] = src8[n3+2]; #endif } src += spitch; dst += dpitch; } break; case DSPF_RGB32: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src32[n] & 0xff0000) >> 16; dst[n3+1] = (src32[n] & 0x00ff00) >> 8; dst[n3+2] = src32[n] & 0x0000ff; } src += spitch; dst += dpitch; } break; case DSPF_ARGB8565: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN dst[n3+0] = src8[n3+1] & 0xf8; dst[n3+1] = ((src8[n3+1] & 0x07) << 5) | ((src8[n3+2] & 0xe0) >> 3); dst[n3+2] = (src8[n3+2] & 0x1f) << 3; #else dst[n3+0] = src8[n3+1] & 0xf8; dst[n3+1] = ((src8[n3+1] & 0x07) << 5) | ((src8[n3+0] & 0xe0) >> 3); dst[n3+2] = (src8[n3+0] & 0x1f) << 3; #endif } src += spitch; dst += dpitch; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = (src32[n] & 0xff000000) >> 24; dst[n3+1] = (src32[n] & 0x00ff0000) >> 16; dst[n3+2] = (src32[n] & 0x0000ff00) >> 8; } src += spitch; dst += dpitch; } break; case DSPF_AYUV: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { u32 y, cb, cr; y = (src32[n] & 0xff0000) >> 16; cb = (src32[n] & 0x00ff00) >> 8; cr = src32[n] & 0x0000ff; #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( y, cb, cr, dst[n3+0], dst[n3+1], dst[n3+2] ); #else YCBCR_TO_RGB( y, cb, cr, dst[n3+2], dst[n3+1], dst[n3+0] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { u32 y, cb, cr; cr = (src32[n] & 0xff0000) >> 16; y = (src32[n] & 0x00ff00) >> 8; cb = src32[n] & 0x0000ff; YCBCR_TO_RGB( y, cb, cr, dst[n3+0], dst[n3+1], dst[n3+2] ); } src += spitch; dst += dpitch; } break; case DSPF_VYU: while (height--) { const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[n3+1], src8[n3+2], src8[n3+0], dst[n3+0], dst[n3+1], dst[n3+2] ); #else YCBCR_TO_RGB( src8[n3+1], src8[n3+0], src8[n3+2], dst[n3+0], dst[n3+1], dst[n3+2] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_YUY2: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width / 2; n++, n3 += 6) { u32 y0, cb, y1, cr; y0 = src32[n] & 0x000000ff; cb = (src32[n] & 0x0000ff00) >> 8; y1 = (src32[n] & 0x00ff0000) >> 16; cr = (src32[n] & 0xff000000) >> 24; YCBCR_TO_RGB( y0, cb, cr, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( y1, cb, cr, dst[n3+3], dst[n3+4], dst[n3+5] ); } src += spitch; dst += dpitch; } break; case DSPF_UYVY: while (height--) { const u32 *src32 = src; for (n = 0, n3 = 0; n < width / 2; n++, n3 += 6) { u32 y0, cb, y1, cr; cb = src32[n] & 0x000000ff; y0 = (src32[n] & 0x0000ff00) >> 8; cr = (src32[n] & 0x00ff0000) >> 16; y1 = (src32[n] & 0xff000000) >> 24; YCBCR_TO_RGB( y0, cb, cr, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( y1, cb, cr, dst[n3+3], dst[n3+4], dst[n3+5] ); } src += spitch; dst += dpitch; } break; case DSPF_NV16: while (height--) { const u16 *cbcr = src + surface_height * spitch; const u8 *src8 = src; for (n = 0, n3 = 0; n < width / 2; n++, n3 += 6) { #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[n*2+0], cbcr[n] >> 8, cbcr[n] & 0xff, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( src8[n*2+1], cbcr[n] >> 8, cbcr[n] & 0xff, dst[n3+3], dst[n3+4], dst[n3+5] ); #else YCBCR_TO_RGB( src8[n*2+0], cbcr[n] & 0xff, cbcr[n] >> 8, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( src8[n*2+1], cbcr[n] & 0xff, cbcr[n] >> 8, dst[n3+3], dst[n3+4], dst[n3+5] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_NV61: while (height--) { const u16 *crcb = src + surface_height * spitch; const u8 *src8 = src; for (n = 0, n3 = 0; n < width / 2; n++, n3 += 6) { #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[n*2+0], crcb[n] & 0xff, crcb[n] >> 8, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( src8[n*2+1], crcb[n] & 0xff, crcb[n] >> 8, dst[n3+3], dst[n3+4], dst[n3+5] ); #else YCBCR_TO_RGB( src8[n*2+0], crcb[n] >> 8, crcb[n] & 0xff, dst[n3+0], dst[n3+1], dst[n3+2] ); YCBCR_TO_RGB( src8[n*2+1], crcb[n] >> 8, crcb[n] & 0xff, dst[n3+3], dst[n3+4], dst[n3+5] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_NV24: while (height--) { const u16 *cbcr = src + surface_height * spitch; const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[n], cbcr[n] >> 8, cbcr[n] & 0xff, dst[n3+0], dst[n3+1], dst[n3+2] ); #else YCBCR_TO_RGB( src8[n], cbcr[n] & 0xff, cbcr[n] >> 8, dst[n3+0], dst[n3+1], dst[n3+2] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_NV42: while (height--) { const u16 *crcb = src + surface_height * spitch; const u8 *src8 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN YCBCR_TO_RGB( src8[n], crcb[n] & 0xff, crcb[n] >> 8, dst[n3+0], dst[n3+1], dst[n3+2] ); #else YCBCR_TO_RGB( src8[n], crcb[n] >> 8, crcb[n] & 0xff, dst[n3+0], dst[n3+1], dst[n3+2] ); #endif } src += spitch; dst += dpitch; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { dst[n3+0] = ((src16[n] & 0xf800) >> 8) | ((src16[n] & 0xe000) >> 13); dst[n3+1] = ((src16[n] & 0x07c0) >> 3) | ((src16[n] & 0x0700) >> 8); dst[n3+2] = ((src16[n] & 0x003e) << 2) | ((src16[n] & 0x0038) >> 3); } src += spitch; dst += dpitch; } break; case DSPF_I420: case DSPF_YV12: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { YCBCR_TO_RGB( *y, *cb, *cr, dst[n3+0], dst[n3+1], dst[n3+2] ); ++y; cb += (n & 1); cr += (n & 1); } src += spitch; src_cb += (height % 2) ? 0 : scbpitch; src_cr += (height % 2) ? 0 : scrpitch; dst += dpitch; } break; case DSPF_Y42B: case DSPF_YV16: ++height; while (--height) { const u8 *y = src; const u8 *cb = src_cb; const u8 *cr = src_cr; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { YCBCR_TO_RGB( *y, *cb, *cr, dst[n3+0], dst[n3+1], dst[n3+2] ); ++y; cb += (n & 1); cr += (n & 1); } src += spitch; src_cb += scbpitch; src_cr += scrpitch; dst += dpitch; } break; case DSPF_Y444: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + surface_height * spitch; const u8 *cr = src + 2 * surface_height * spitch; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { YCBCR_TO_RGB( *y++, *cb++, *cr++, dst[n3+0], dst[n3+1], dst[n3+2] ); } src += spitch; dst += dpitch; } break; case DSPF_YV24: ++height; while (--height) { const u8 *y = src; const u8 *cb = src + 2 * surface_height * spitch; const u8 *cr = src + surface_height * spitch; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { YCBCR_TO_RGB( *y++, *cb++, *cr++, dst[n3+0], dst[n3+1], dst[n3+2] ); } src += spitch; dst += dpitch; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_a8( DFBSurfacePixelFormat format, const void *src, int spitch, int surface_height, u8 *dst, int dpitch, int width, int height ) { int n; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); switch (format) { case DSPF_A8: while (height--) { const u8 *src8 = src; direct_memcpy( dst, src8, width ); src += spitch; dst += dpitch; } break; case DSPF_AiRGB: while (height--) { const u32 *src32 = src; for (n = 0; n < width; n++) { dst[n] = ~(src32[n] >> 24); } src += spitch; dst += dpitch; } break; case DSPF_ARGB: case DSPF_ABGR: case DSPF_AYUV: case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (n = 0; n < width; n++) { dst[n] = src32[n] >> 24; } src += spitch; dst += dpitch; } break; case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (n = 0; n < width; n++) { dst[n] = (src16[n] & 0x8000) ? 0xff : 0x00; } src += spitch; dst += dpitch; } break; case DSPF_ARGB2554: while (height--) { const u16 *src16 = src; for (n = 0; n < width; n++) { switch (src16[n] >> 14) { case 0: dst[n] = 0x00; break; case 1: dst[n] = 0x55; break; case 2: dst[n] = 0xaa; break; case 3: dst[n] = 0xff; break; } } src += spitch; dst += dpitch; } break; case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (n = 0; n < width; n++) { dst[n] = src16[n] >> 12; dst[n] |= dst[n] << 4; } src += spitch; dst += dpitch; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (n = 0; n < width; n++) { dst[n] = EXPAND_4to8( src16[n] & 0xf ); } src += spitch; dst += dpitch; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (n = 0; n < width; n++) { dst[n] = EXPAND_1to8( src16[n] & 0x1 ); } src += spitch; dst += dpitch; } break; case DSPF_ARGB8565: while (height--) { const u8 *src8 = src; int n3; for (n = 0, n3 = 0; n < width; n++, n3 += 3) { #ifdef WORDS_BIGENDIAN dst[n] = src8[n3+0]; #else dst[n] = src8[n3+2]; #endif } src += spitch; dst += dpitch; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (n = 0; n < width; n++) { dst[n] = EXPAND_7to8( (src32[n] & 0x000000fe) >> 1 ); } src += spitch; dst += dpitch; } break; default: D_ONCE( "unsupported format" ); } } void dfb_convert_to_a4( DFBSurfacePixelFormat format, const void *src, int spitch, int surface_height, u8 *dst, int dpitch, int width, int height ) { const int w2 = width / 2; int x, n; D_DEBUG_AT( GFX_Converter, "%s()\n", __FUNCTION__ ); D_ASSUME( (width & 1) == 0 ); switch (format) { case DSPF_A8: while (height--) { const u8 *src8 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = (src8[n] & 0xf0) | ((src8[n+1] & 0xf0) >> 4); src += spitch; dst += dpitch; } break; case DSPF_ARGB4444: while (height--) { const u16 *src16 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = ((src16[n] & 0xf000) >> 8) | (src16[n+1] >> 12); src += spitch; dst += dpitch; } break; case DSPF_RGBA4444: while (height--) { const u16 *src16 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = ((src16[n] & 0x000f) << 4) | (src16[n+1] & 0x000f); src += spitch; dst += dpitch; } break; case DSPF_ARGB1555: while (height--) { const u16 *src16 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = ((src16[n] & 0x8000) ? 0xf0 : 0) | ((src16[n+1] & 0x8000) ? 0x0f : 0); src += spitch; dst += dpitch; } break; case DSPF_ARGB: case DSPF_ABGR: case DSPF_AYUV: case DSPF_AVYU: while (height--) { const u32 *src32 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = ((src32[n] & 0xf0000000) >> 24) | ((src32[n+1] & 0xf0000000) >> 28); src += spitch; dst += dpitch; } break; case DSPF_RGBA5551: while (height--) { const u16 *src16 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = ((src16[n] & 0x1) ? 0xf0 : 0) | ((src16[n+1] & 0x1) ? 0x0f : 0); src += spitch; dst += dpitch; } break; case DSPF_ARGB8565: while (height--) { const u8 *src8 = src; for (x = 0, n = 0; x < w2; x++, n += 6) { #ifdef WORDS_BIGENDIAN dst[x] = (src8[n+0] & 0xf0) | (src8[n+3] & 0xf0 >> 4); #else dst[x] = (src8[n+2] & 0xf0) | (src8[n+5] & 0xf0 >> 4); #endif } src += spitch; dst += dpitch; } break; case DSPF_RGBAF88871: while (height--) { const u32 *src32 = src; for (x = 0, n = 0; x < w2; x++, n += 2) dst[x] = (src32[n] & 0x000000f0) | ((src32[n+1] & 0x000000f0) >> 4); src += spitch; dst += dpitch; } break; default: if (DFB_PIXELFORMAT_HAS_ALPHA( format )) D_ONCE( "unsupported format" ); } } ================================================ FILE: src/gfx/convert.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GFX__CONVERT_H__ #define __GFX__CONVERT_H__ #include #include /**********************************************************************************************************************/ /* pixel packing */ #define PIXEL_RGB332(r,g,b) ( ((r) & 0xe0) | \ (((g) & 0xe0) >> 3) | \ (((b) & 0xc0) >> 6) ) #define PIXEL_ARGB1555(a,r,g,b) ( (((a) & 0x80) << 8) | \ (((r) & 0xf8) << 7) | \ (((g) & 0xf8) << 2) | \ (((b) & 0xf8) >> 3) ) #define PIXEL_RGBA5551(a,r,g,b) ( (((a) & 0x80) >> 7) | \ (((r) & 0xf8) << 8) | \ (((g) & 0xf8) << 3) | \ (((b) & 0xf8) >> 2) ) #define PIXEL_RGB555(r,g,b) ( (((r) & 0xf8) << 7) | \ (((g) & 0xf8) << 2) | \ (((b) & 0xf8) >> 3) ) #define PIXEL_BGR555(r,g,b) ( (((b) & 0xf8) << 7) | \ (((g) & 0xf8) << 2) | \ (((r) & 0xf8) >> 3) ) #define PIXEL_ARGB2554(a,r,g,b) ( (((a) & 0xc0) << 8) | \ (((r) & 0xf8) << 6) | \ (((g) & 0xf8) << 1) | \ (((b) & 0xf0) >> 4) ) #define PIXEL_ARGB4444(a,r,g,b) ( (((a) & 0xf0) << 8) | \ (((r) & 0xf0) << 4) | \ ((g) & 0xf0) | \ (((b) & 0xf0) >> 4) ) #define PIXEL_RGBA4444(a,r,g,b) ( (((r) & 0xf0) << 8) | \ (((g) & 0xf0) << 4) | \ ((b) & 0xf0) | \ (((a) & 0xf0) >> 4) ) #define PIXEL_RGB444(r,g,b) ( (((r) & 0xf0) << 4) | \ ((g) & 0xf0) | \ (((b) & 0xf0) >> 4) ) #define PIXEL_RGB16(r,g,b) ( (((r) & 0xf8) << 8) | \ (((g) & 0xfc) << 3) | \ (((b) & 0xf8) >> 3) ) #define PIXEL_RGB18(r,g,b) ( (((r) & 0xfc) << 10) | \ (((g) & 0xfc) << 4) | \ (((b) & 0xfc) >> 2) ) #define PIXEL_RGB32(r,g,b) ( (0xff << 24) | \ ((r) << 16) | \ ((g) << 8) | \ (b) ) #define PIXEL_ARGB(a,r,g,b) ( ((a) << 24) | \ ((r) << 16) | \ ((g) << 8) | \ (b) ) #define PIXEL_ABGR(a,r,g,b) ( ((a) << 24) | \ ((b) << 16) | \ ((g) << 8) | \ (r) ) #define PIXEL_ARGB8565(a,r,g,b) ( ((a) << 16) | \ PIXEL_RGB16( r, g, b ) ) #define PIXEL_ARGB1666(a,r,g,b) ( (((a) & 0x80) << 11) | \ (((r) & 0xfc) << 10) | \ (((g) & 0xfc) << 4) | \ (((b) & 0xfc) >> 2) ) #define PIXEL_ARGB6666(a,r,g,b) ( (((a) & 0xfc) << 16) | \ (((r) & 0xfc) << 10) | \ (((g) & 0xfc) << 4) | \ (((b) & 0xfc) >> 2) ) #define PIXEL_AYUV(a,y,u,v) ( ((a) << 24) | \ ((y) << 16) | \ ((u) << 8) | \ (v) ) #define PIXEL_AVYU(a,y,u,v) ( ((a) << 24) | \ ((v) << 16) | \ ((y) << 8) | \ (u) ) #define PIXEL_AiRGB(a,r,g,b) ( (((a) ^ 0xff) << 24) | \ ((r) << 16) | \ ((g) << 8) | \ (b) ) #define PIXEL_RGBAF88871(a,r,g,b) ( ((r) << 24) | \ ((g) << 16) | \ ((b) << 8) | \ ((a) & ~1 ) ) #define PIXEL_YUY2_BE(y,u,v) ( ((u) << 24) | \ ((y) << 16) | \ ((v) << 8) | \ (y) ) #define PIXEL_UYVY_BE(y,u,v) ( ((y) << 24) | \ ((u) << 16) | \ ((y) << 8) | \ (v) ) #define PIXEL_YUY2_LE(y,u,v) ( ((v) << 24) | \ ((y) << 16) | \ ((u) << 8) | \ (y) ) #define PIXEL_UYVY_LE(y,u,v) ( ((y) << 24) | \ ((v) << 16) | \ ((y) << 8) | \ (u) ) #define PIXEL_VYU(y,u,v) ( ((v) << 16) | \ ((y) << 8) | \ (u) ) /* packed pixel conversions */ #define ARGB1555_TO_RGB332(pixel) ( (((pixel) & 0x7000) >> 7) | \ (((pixel) & 0x0380) >> 5) | \ (((pixel) & 0x0018) >> 3) ) #define ARGB1555_TO_ARGB2554(pixel) ( ((pixel) & 0x8000) | \ (((pixel) & 0x7fff) >> 1) ) #define ARGB1555_TO_ARGB4444(pixel) ( (((pixel) & 0x8000) ? 0xf000 : 0 ) | \ (((pixel) & 0x7800) >> 3) | \ (((pixel) & 0x03c0) >> 2) | \ (((pixel) & 0x0018) >> 1) ) #define ARGB1555_TO_RGBA4444(pixel) ( (((pixel) & 0x8000) ? 0x000f : 0 ) | \ (((pixel) & 0x7800) << 1) | \ (((pixel) & 0x03c0) << 2) | \ (((pixel) & 0x0018) << 3) ) #define ARGB1555_TO_RGB16(pixel) ( (((pixel) & 0x7c00) << 1) | \ (((pixel) & 0x03e0) << 1) | \ ((pixel) & 0x001f) ) #define ARGB1555_TO_ARGB8565(pixel) ( (((pixel) & 0x8000) ? 0x00ff0000 : 0) | \ ARGB1555_TO_RGB16( pixel ) ) #define ARGB1555_TO_RGB32(pixel) ( (((pixel) & 0x7c00) << 9) | \ (((pixel) & 0x03e0) << 6) | \ (((pixel) & 0x001f) << 3) ) #define ARGB1555_TO_ARGB(pixel) ( (((pixel) & 0x8000) ? 0xff000000 : 0) | \ (((pixel) & 0x7c00) << 9) | \ (((pixel) & 0x03e0) << 6) | \ (((pixel) & 0x001f) << 3) ) #define ARGB1555_TO_RGB555(pixel) ( (((pixel) & 0x7c00) << 9) | \ (((pixel) & 0x03e0) << 6) | \ (((pixel) & 0x001f) << 3) ) #define ARGB1555_TO_RGB444(pixel) ( (((pixel) & 0x7800) >> 3) | \ (((pixel) & 0x03c0) >> 2) | \ (((pixel) & 0x001e) >> 1) ) /* xRGB to xxRRGGBB, so xRxx left 3, xRGx left 2, xxGB left 1, xxxB */ #define ARGB4444_TO_RGB32(pixel) ( (((pixel) & 0x0f00) << 12) | \ (((pixel) & 0x0ff0) << 8) | \ (((pixel) & 0x00ff) << 4) | \ ((pixel) & 0x000f) ) /* RGBx to xxRRGGBB, so Rxxx left 2, RGxx left 1, xGBx, xxBx right 1 */ #define RGBA4444_TO_RGB32(pixel) ( (((pixel) & 0xf000) << 8) | \ (((pixel) & 0xff00) << 4) | \ ((pixel) & 0x0ff0) | \ (((pixel) & 0x00f0) >> 4) ) /* ARGB to AARRGGBB, so Axxx left 4, ARxx left 3, xRGx left 2, xxGB left 1, xxxB */ #define ARGB4444_TO_ARGB(pixel) ( (((pixel) & 0xf000) << 16) | \ (((pixel) & 0xff00) << 12) | \ (((pixel) & 0x0ff0) << 8) | \ (((pixel) & 0x00ff) << 4) | \ ((pixel) & 0x000f) ) /* RGBA to AARRGGBB, so Rxxx left 2, RGxx left 1, xGBx, xxBx right 1, A to the left */ #define RGBA4444_TO_ARGB(pixel) ( (((pixel) & 0x000f) << 28) | \ (((pixel) & 0x000f) << 24) | \ (((pixel) & 0xf000) << 8) | \ (((pixel) & 0xff00) << 4) | \ ((pixel) & 0x0ff0) | \ (((pixel) & 0x00f0) >> 4) ) #define RGB16_TO_RGB332(pixel) ( (((pixel) & 0xe000) >> 8) | \ (((pixel) & 0x0700) >> 6) | \ (((pixel) & 0x0018) >> 3) ) #define RGB16_TO_ARGB1555(pixel) ( 0x8000 | \ (((pixel) & 0xf800) >> 1) | \ (((pixel) & 0x07c0) >> 1) | \ ((pixel) & 0x001f) ) #define RGB16_TO_ARGB2554(pixel) ( 0xc000 | \ (((pixel) & 0xf800) >> 2) | \ (((pixel) & 0x07c0) >> 2) | \ (((pixel) & 0x001f) >> 1) ) #define RGB16_TO_ARGB4444(pixel) ( 0xf000 | \ (((pixel) & 0xf000) >> 4) | \ (((pixel) & 0x0780) >> 3) | \ (((pixel) & 0x001e) >> 1) ) #define RGB16_TO_RGBA4444(pixel) ( 0x000f | \ ((pixel) & 0xf000) | \ (((pixel) & 0x0780) << 1) | \ (((pixel) & 0x001e) << 3) ) #define RGB16_TO_ARGB8565(pixel) ( 0xff0000 | \ ((pixel) & 0xffff) ) #define RGB16_TO_RGB32(pixel) ( (((pixel) & 0xf800) << 8) | \ (((pixel) & 0x07e0) << 5) | \ (((pixel) & 0x001f) << 3) ) #define RGB16_TO_ARGB(pixel) ( 0xff000000 | \ (((pixel) & 0xf800) << 8) | \ (((pixel) & 0x07e0) << 5) | \ (((pixel) & 0x001f) << 3) ) #define RGB16_TO_RGB555(pixel) ( (((pixel) & 0xf800) >> 1) | \ (((pixel) & 0x07c0) >> 1) | \ ((pixel) & 0x001f) ) #define RGB16_TO_BGR555(pixel) ( (((pixel) & 0xf800) >> 12) | \ (((pixel) & 0x07c0) >> 1) | \ (((pixel) & 0x001f) << 10 ) ) #define RGB16_TO_RGB444(pixel) ( (((pixel) & 0xf000) >> 4) | \ (((pixel) & 0x0780) >> 3) | \ (((pixel) & 0x001f) >> 1) ) #define ARGB8565_TO_RGB332(pixel) ( RGB16_TO_RGB332( pixel ) ) #define ARGB8565_TO_ARGB1555(pixel) ( (((pixel) & 0x800000) >> 16) | \ (((pixel) & 0x00f800) >> 1) | \ (((pixel) & 0x0007c0) >> 1) | \ ((pixel) & 0x00001f) ) #define ARGB8565_TO_ARGB2554(pixel) ( (((pixel) & 0xc00000) >> 16) | \ (((pixel) & 0x00f800) >> 2) | \ (((pixel) & 0x0007c0) >> 2) | \ (((pixel) & 0x00001f) >> 1) ) #define ARGB8565_TO_ARGB4444(pixel) ( (((pixel) & 0xf00000) >> 16) | \ (((pixel) & 0x00f000) >> 4) | \ (((pixel) & 0x000780) >> 3) | \ (((pixel) & 0x00001f) >> 1) ) #define ARGB8565_TO_RGB16(pixel) ( (pixel) & 0xffff ) #define ARGB8565_TO_RGB32(pixel) ( RGB16_TO_RGB32( pixel ) ) #define ARGB8565_TO_ARGB(pixel) ( (((pixel) & 0xff0000) << 8) | \ (((pixel) & 0x00f800) << 8) | \ (((pixel) & 0x0007e0) << 5) | \ (((pixel) & 0x00001f) << 3) ) #define RGB18_TO_ARGB(pixel) ( 0xff000000 | \ (((pixel) & 0xfc00) << 10) | \ (((pixel) & 0x3f00) << 4) | \ (((pixel) & 0x00fc) << 2) ) #define RGB32_TO_ARGB1555(pixel) ( 0x8000 | \ (((pixel) & 0xf80000) >> 9) | \ (((pixel) & 0x00f800) >> 6) | \ (((pixel) & 0x0000f8) >> 3) ) #define RGB32_TO_ARGB2554(pixel) ( 0xc000 | \ (((pixel) & 0xf80000) >> 10) | \ (((pixel) & 0x00f800) >> 7) | \ (((pixel) & 0x0000f0) >> 4) ) #define RGB32_TO_ARGB4444(pixel) ( 0xf000 | \ (((pixel) & 0xf00000) >> 12) | \ (((pixel) & 0x00f000) >> 8) | \ (((pixel) & 0x0000f0) >> 4) ) #define RGB32_TO_RGBA4444(pixel) ( 0x000f | \ (((pixel) & 0xf00000) >> 8) | \ (((pixel) & 0x00f000) >> 4) | \ ((pixel) & 0x0000f0) ) #define RGB32_TO_ARGB8565(pixel) ( 0xff0000 | \ (((pixel) & 0xf80000) >> 8) | \ (((pixel) & 0x00fc00) >> 5) | \ (((pixel) & 0x0000f8) >> 3) ) #define RGB32_TO_ARGB1555(pixel) ( 0x8000 | \ (((pixel) & 0xf80000) >> 9) | \ (((pixel) & 0x00f800) >> 6) | \ (((pixel) & 0x0000f8) >> 3) ) #define RGB32_TO_ARGB(pixel) ( 0xff000000 | (pixel) ) #define ARGB_TO_RGB332(pixel) ( (((pixel) & 0x00e00000) >> 16) | \ (((pixel) & 0x0000e000) >> 11) | \ (((pixel) & 0x000000c0) >> 6) ) #define ARGB_TO_ARGB1555(pixel) ( (((pixel) & 0x80000000) >> 16) | \ (((pixel) & 0x00f80000) >> 9) | \ (((pixel) & 0x0000f800) >> 6) | \ (((pixel) & 0x000000f8) >> 3) ) #define ARGB_TO_RGBA5551(pixel) ( (((pixel) & 0x80000000) >> 31) | \ (((pixel) & 0x00f80000) >> 8) | \ (((pixel) & 0x0000f800) >> 5) | \ (((pixel) & 0x000000f8) >> 2) ) #define ARGB_TO_ARGB2554(pixel) ( (((pixel) & 0xc0000000) >> 16) | \ (((pixel) & 0x00f80000) >> 10) | \ (((pixel) & 0x0000f800) >> 7) | \ (((pixel) & 0x000000f0) >> 4) ) #define ARGB_TO_ARGB4444(pixel) ( (((pixel) & 0xf0000000) >> 16) | \ (((pixel) & 0x00f00000) >> 12) | \ (((pixel) & 0x0000f000) >> 8) | \ (((pixel) & 0x000000f0) >> 4) ) #define ARGB_TO_RGBA4444(pixel) ( (((pixel) & 0xf0000000) >> 28) | \ (((pixel) & 0x00f00000) >> 8) | \ (((pixel) & 0x0000f000) >> 4) | \ (((pixel) & 0x000000f0) ) ) #define ARGB_TO_ARGB1666(pixel) ( (((pixel) & 0x80000000) >> 8) | \ (((pixel) & 0x00fc0000) >> 6) | \ (((pixel) & 0x0000fc00) >> 4) | \ (((pixel) & 0x000000fc) >> 2) ) #define ARGB_TO_ARGB6666(pixel) ( (((pixel) & 0xfc000000) >> 8) | \ (((pixel) & 0x00fc0000) >> 6) | \ (((pixel) & 0x0000fc00) >> 4) | \ (((pixel) & 0x000000fc) >> 2) ) #define ARGB_TO_ARGB8565(pixel) ( (((pixel) & 0xff000000) >> 8) | \ (((pixel) & 0x00f80000) >> 8) | \ (((pixel) & 0x0000fc00) >> 5) | \ (((pixel) & 0x000000f8) >> 3) ) #define ARGB_TO_RGB18(pixel) ( (((pixel) & 0x00fc0000) >> 6) | \ (((pixel) & 0x0000fc00) >> 4) | \ (((pixel) & 0x000000fc) >> 2) ) #define ARGB_TO_RGB16(pixel) ( (((pixel) & 0x00f80000) >> 8) | \ (((pixel) & 0x0000fc00) >> 5) | \ (((pixel) & 0x000000f8) >> 3) ) #define ARGB_TO_RGB444(pixel) ( (((pixel) & 0x00f00000) >> 12) | \ (((pixel) & 0x0000f000) >> 8) | \ (((pixel) & 0x000000f0) >> 4) ) #define ARGB_TO_RGB555(pixel) ( (((pixel) & 0x00f80000) >> 9) | \ (((pixel) & 0x0000f800) >> 6) | \ (((pixel) & 0x000000f8) >> 3) ) #define ARGB_TO_BGR555(pixel) ( (((pixel) & 0x00f80000) >> 19) | \ (((pixel) & 0x0000f800) >> 6) | \ (((pixel) & 0x000000f8) << 7) ) #define ARGB_TO_ABGR(pixel) ( ((pixel) & 0xff00ff00) | \ (((pixel) & 0x000000ff) << 16) | \ (((pixel) & 0x00ff0000) >> 16) ) #define ARGB_TO_RGBAF88871(pixel) ( (((pixel) & 0x00ffffff) << 8 ) | \ (((pixel) & 0xfe000000) >> 24) ) /* RGB <-> YCbCr conversion */ #define YCBCR_TO_RGB_BT601(y,cb,cr,r,g,b) \ do { \ int _y = (y) - 16; \ int _cb = (cb) - 128; \ int _cr = (cr) - 128; \ \ int _r = (298 * _y + 409 * _cr + 128) >> 8; \ int _g = (298 * _y - 100 * _cb - 208 * _cr + 128) >> 8; \ int _b = (298 * _y + 516 * _cb + 128) >> 8; \ \ (r) = CLAMP( _r, 0, 255 ); \ (g) = CLAMP( _g, 0, 255 ); \ (b) = CLAMP( _b, 0, 255 ); \ } while (0) #define RGB_TO_YCBCR_BT601(r,g,b,y,cb,cr) \ do { \ int _r = (r), _g = (g), _b = (b); \ \ (y) = ( 66 * _r + 129 * _g + 25 * _b + 16 * 256 + 128) >> 8; \ (cb) = ( - 38 * _r - 74 * _g + 112 * _b + 128 * 256 + 128) >> 8; \ (cr) = ( 112 * _r - 94 * _g - 18 * _b + 128 * 256 + 128) >> 8; \ } while (0) #define YCBCR_TO_RGB_BT709(y,cb,cr,r,g,b) \ do { \ int _y = (y) - 16; \ int _cb = (cb) - 128; \ int _cr = (cr) - 128; \ \ int _r = (298 * _y + 459 * _cr + 128) >> 8; \ int _g = (298 * _y - 55 * _cb - 136 * _cr + 128) >> 8; \ int _b = (298 * _y + 541 * _cb + 128) >> 8; \ \ (r) = CLAMP( _r, 0, 255 ); \ (g) = CLAMP( _g, 0, 255 ); \ (b) = CLAMP( _b, 0, 255 ); \ } while (0) #define RGB_TO_YCBCR_BT709(r,g,b,y,cb,cr) \ do { \ int _r = (r), _g = (g), _b = (b); \ \ (y) = ( 47 * _r + 157 * _g + 16 * _b + 16 * 256 + 128) >> 8; \ (cb) = ( - 26 * _r - 87 * _g + 112 * _b + 128 * 256 + 128) >> 8; \ (cr) = ( 112 * _r - 102 * _g - 10 * _b + 128 * 256 + 128) >> 8; \ } while (0) #define YCBCR_TO_RGB_BT2020(y,cb,cr,r,g,b) \ do { \ int _y = (y) - 16; \ int _cb = (cb) - 128; \ int _cr = (cr) - 128; \ \ int _r = (298 * _y + 430 * _cr + 128) >> 8; \ int _g = (298 * _y - 48 * _cb - 167 * _cr + 128) >> 8; \ int _b = (298 * _y + 548 * _cb + 128) >> 8; \ \ (r) = CLAMP( _r, 0, 255 ); \ (g) = CLAMP( _g, 0, 255 ); \ (b) = CLAMP( _b, 0, 255 ); \ } while (0) #define RGB_TO_YCBCR_BT2020(r,g,b,y,cb,cr) \ do { \ int _r = (r), _g = (g), _b = (b); \ \ (y) = ( 58 * _r + 149 * _g + 13 * _b + 16 * 256 + 128) >> 8; \ (cb) = ( - 31 * _r - 81 * _g + 112 * _b + 128 * 256 + 128) >> 8; \ (cr) = ( 112 * _r - 103 * _g - 9 * _b + 128 * 256 + 128) >> 8; \ } while (0) /**********************************************************************************************************************/ void dfb_pixel_to_color ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, unsigned long pixel, DFBColor *ret_color ); unsigned long dfb_pixel_from_color ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const DFBColor *color ); void dfb_pixel_to_components( DFBSurfacePixelFormat format, unsigned long pixel, u8 *a, u8 *c2, u8 *c1, u8 *c0 ); void dfb_convert_to_rgb16 ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u16 *dst, int dpitch, int width, int height ); void dfb_convert_to_rgb555 ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u16 *dst, int dpitch, int width, int height ); void dfb_convert_to_rgb32 ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u32 *dst, int dpitch, int width, int height ); void dfb_convert_to_argb ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u32 *dst, int dpitch, int width, int height ); void dfb_convert_to_rgb24 ( DFBSurfacePixelFormat format, DFBSurfaceColorSpace colorspace, const void *src, int spitch, const void *src_cb, int scbpitch, const void *src_cr, int scrpitch, int surface_height, u8 *dst, int dpitch, int width, int height ); void dfb_convert_to_a8 ( DFBSurfacePixelFormat format, const void *src, int spitch, int surface_height, u8 *dst, int dpitch, int width, int height ); void dfb_convert_to_a4 ( DFBSurfacePixelFormat format, const void *src, int spitch, int surface_height, u8 *dst, int dpitch, int width, int height ); /**********************************************************************************************************************/ static __inline__ u32 dfb_color_to_argb( const DFBColor *color ) { return (color->a << 24) | (color->r << 16) | (color->g << 8) | color->b; } static __inline__ void dfb_argb_to_rgb332( const u32 *src, u8 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGB332( argb ); } } static __inline__ void dfb_argb_to_argb1555( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_ARGB1555( argb ); } } static __inline__ void dfb_argb_to_rgba5551( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGBA5551( argb ); } } static __inline__ void dfb_argb_to_argb2554( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_ARGB2554( argb ); } } static __inline__ void dfb_argb_to_argb4444( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_ARGB4444( argb ); } } static __inline__ void dfb_argb_to_rgba4444( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 rgba = src[i]; dst[i] = ARGB_TO_RGBA4444( rgba ); } } static __inline__ void dfb_argb_to_argb1666be( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB1666( argb ); dst[++j] = (d >> 16) & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = d & 0xff; } } static __inline__ void dfb_argb_to_argb1666le( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB1666( argb ); dst[++j] = d & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = (d >> 16) & 0xff; } } static __inline__ void dfb_argb_to_argb6666be( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB6666( argb ); dst[++j] = (d >> 16) & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = d & 0xff; } } static __inline__ void dfb_argb_to_argb6666le( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB6666( argb ); dst[++j] = d & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = (d >> 16) & 0xff; } } static __inline__ void dfb_argb_to_argb8565be( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB8565( argb ); dst[++j] = (d >> 16) & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = d & 0xff; } } static __inline__ void dfb_argb_to_argb8565le( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_ARGB8565( argb ); dst[++j] = d & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = (d >> 16) & 0xff; } } static __inline__ void dfb_argb_to_rgb18be( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_RGB18( argb ); dst[++j] = (d >> 16) & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = d & 0xff; } } static __inline__ void dfb_argb_to_rgb18le( const u32 *src, u8 *dst, int len ) { int i = -1, j = -1; while (++i < len) { u32 argb = src[i]; u32 d = ARGB_TO_RGB18( argb ); dst[++j] = d & 0xff; dst[++j] = (d >> 8) & 0xff; dst[++j] = (d >> 16) & 0xff; } } static __inline__ void dfb_argb_to_rgb16( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGB16( argb ); } } static __inline__ void dfb_argb_to_rgb444( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGB444( argb ); } } static __inline__ void dfb_argb_to_rgb555( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGB555( argb ); } } static __inline__ void dfb_argb_to_bgr555( const u32 *src, u16 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_BGR555( argb ); } } static __inline__ void dfb_argb_to_abgr( const u32 *src, u32 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_ABGR( argb ); } } static __inline__ void dfb_argb_to_rgbaf88871( const u32 *src, u32 *dst, int len ) { int i; for (i = 0; i < len; i++) { u32 argb = src[i]; dst[i] = ARGB_TO_RGBAF88871( argb ); } } static __inline__ void dfb_argb_to_a8( const u32 *src, u8 *dst, int len ) { int i; for (i = 0; i < len; i++) dst[i] = src[i] >> 24; } #endif ================================================ FILE: src/gfx/generic/duffs_device.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __DUFFS_DEVICE_H__ #define __DUFFS_DEVICE_H__ #define DUFF_1() \ case 1: \ SET_PIXEL( D[0], S[0] ); #define DUFF_2() \ case 3: \ SET_PIXEL( D[2], S[2] ); \ case 2: \ SET_PIXEL( D[1], S[1] ); \ DUFF_1() #define DUFF_3() \ case 7: \ SET_PIXEL( D[6], S[6] ); \ case 6: \ SET_PIXEL( D[5], S[5] ); \ case 5: \ SET_PIXEL( D[4], S[4] ); \ case 4: \ SET_PIXEL( D[3], S[3] ); \ DUFF_2() #define DUFF_4() \ case 15: \ SET_PIXEL( D[14], S[14] ); \ case 14: \ SET_PIXEL( D[13], S[13] ); \ case 13: \ SET_PIXEL( D[12], S[12] ); \ case 12: \ SET_PIXEL( D[11], S[11] ); \ case 11: \ SET_PIXEL( D[10], S[10] ); \ case 10: \ SET_PIXEL( D[9], S[9] ); \ case 9: \ SET_PIXEL( D[8], S[8] ); \ case 8: \ SET_PIXEL( D[7], S[7] ); \ DUFF_3() #define SET_PIXEL_DUFFS_DEVICE_N(D,S,w,n) \ do { \ while (w) { \ int l = w & ((1 << n) - 1); \ switch (l) { \ default: \ l = (1 << n); \ SET_PIXEL( D[(1< #include #include #include #include #include #include #include #include /**********************************************************************************************************************/ /* lookup tables for 2/3bit to 8bit color conversion */ static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; #define EXPAND_1to8(v) ((v) ? 0xff : 0x00) #define EXPAND_2to8(v) lookup2to8[v] #define EXPAND_3to8(v) lookup3to8[v] #define EXPAND_4to8(v) (((v) << 4) | (v) ) #define EXPAND_5to8(v) (((v) << 3) | ((v) >> 2)) #define EXPAND_6to8(v) (((v) << 2) | ((v) >> 4)) #define EXPAND_7to8(v) (((v) << 1) | ((v) >> 6)) /**********************************************************************************************************************/ /* ARGB1555 / RGB555 / BGR555 / RGBA5551 */ #define RGB_MASK 0x7fff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_15 #define Bop_PFI_OP_Aop_PFI(op) Bop_15_##op##_Aop #include "template_colorkey_16.h" /* RGB16 */ #define RGB_MASK 0xffff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_16 #define Bop_PFI_OP_Aop_PFI(op) Bop_16_##op##_Aop #include "template_colorkey_16.h" /* RGB24 / BGR24 / VYU */ #define RGB_MASK 0xffffff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_24_24 #define Bop_PFI_OP_Aop_PFI(op) Bop_24_24_##op##_Aop #include "template_colorkey_24.h" /* RGB32 / ARGB / ABGR / AiRGB / AYUV / AVYU */ #define RGB_MASK 0x00ffffff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_32 #define Bop_PFI_OP_Aop_PFI(op) Bop_32_##op##_Aop #include "template_colorkey_32.h" /* ARGB2554 */ #define RGB_MASK 0x3fff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_14 #define Bop_PFI_OP_Aop_PFI(op) Bop_14_##op##_Aop #include "template_colorkey_16.h" /* ARGB4444 / RGB444 */ #define RGB_MASK 0x0fff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_12 #define Bop_PFI_OP_Aop_PFI(op) Bop_12_##op##_Aop #include "template_colorkey_16.h" /* RGBA4444 */ #define RGB_MASK 0xfff0 #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_12vv #define Bop_PFI_OP_Aop_PFI(op) Bop_12vv_##op##_Aop #include "template_colorkey_16.h" /* ARGB1666 / ARGB6666 / RGB18 */ #define RGB_MASK 0x03ffff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_24_18 #define Bop_PFI_OP_Aop_PFI(op) Bop_24_18_##op##_Aop #include "template_colorkey_24.h" /* ARGB8565 */ #define RGB_MASK 0x00ffff #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_24_16 #define Bop_PFI_OP_Aop_PFI(op) Bop_24_16_##op##_Aop #include "template_colorkey_24.h" /* RGBAF88871 */ #define RGB_MASK 0xffffff00 #define Cop_OP_Aop_PFI(op) Cop_##op##_Aop_32_24 #define Bop_PFI_OP_Aop_PFI(op) Bop_32_24_##op##_Aop #include "template_colorkey_32.h" /**********************************************************************************************************************/ /* ARGB1555 */ #define EXPAND_Ato8(a) EXPAND_1to8( a ) #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_5to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB1555( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb1555_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb1555 #define A_SHIFT 15 #define R_SHIFT 10 #define G_SHIFT 5 #define B_SHIFT 0 #define A_MASK 0x8000 #define R_MASK 0x7c00 #define G_MASK 0x03e0 #define B_MASK 0x001f #include "template_acc_16.h" /* RGB16 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_6to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB16( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgb16_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgb16 #define A_SHIFT 0 #define R_SHIFT 11 #define G_SHIFT 5 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0xf800 #define G_MASK 0x07e0 #define B_MASK 0x001f #include "template_acc_16.h" /* RGB24 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB32( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgb24_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgb24 #define A_SHIFT 0 #define R_SHIFT 16 #define G_SHIFT 8 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0xff0000 #define G_MASK 0x00ff00 #define B_MASK 0x0000ff #include "template_acc_24.h" /* BGR24 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB32( b, g, r ) #define Sop_PFI_OP_Dacc(op) Sop_bgr24_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_bgr24 #define A_SHIFT 0 #define B_SHIFT 16 #define G_SHIFT 8 #define R_SHIFT 0 #define A_MASK 0 #define B_MASK 0xff0000 #define G_MASK 0x00ff00 #define R_MASK 0x0000ff #include "template_acc_24.h" /* RGB32 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB32( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgb32_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgb32 #define A_SHIFT 0 #define R_SHIFT 16 #define G_SHIFT 8 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0x00ff0000 #define G_MASK 0x0000ff00 #define B_MASK 0x000000ff #include "template_acc_32.h" /* ARGB */ #define EXPAND_Ato8(a) (a) #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb #define A_SHIFT 24 #define R_SHIFT 16 #define G_SHIFT 8 #define B_SHIFT 0 #define A_MASK 0xff000000 #define R_MASK 0x00ff0000 #define G_MASK 0x0000ff00 #define B_MASK 0x000000ff #include "template_acc_32.h" /* ABGR */ #define EXPAND_Ato8(a) (a) #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_ABGR( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_abgr_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_abgr #define A_SHIFT 24 #define B_SHIFT 16 #define G_SHIFT 8 #define R_SHIFT 0 #define A_MASK 0xff000000 #define B_MASK 0x00ff0000 #define G_MASK 0x0000ff00 #define R_MASK 0x000000ff #include "template_acc_32.h" /* AiRGB */ #define EXPAND_Ato8(a) ((a) ^ 0xff) #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_AiRGB( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_airgb_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_airgb #define A_SHIFT 24 #define R_SHIFT 16 #define G_SHIFT 8 #define B_SHIFT 0 #define A_MASK 0xff000000 #define R_MASK 0x00ff0000 #define G_MASK 0x0000ff00 #define B_MASK 0x000000ff #include "template_acc_32.h" /* ARGB2554 */ #define EXPAND_Ato8(a) EXPAND_2to8( a ) #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_5to8( g ) #define EXPAND_Bto8(b) EXPAND_4to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB2554( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb2554_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb2554 #define A_SHIFT 14 #define R_SHIFT 9 #define G_SHIFT 4 #define B_SHIFT 0 #define A_MASK 0xc000 #define R_MASK 0x3e00 #define G_MASK 0x01f0 #define B_MASK 0x000f #include "template_acc_16.h" /* ARGB4444 */ #define EXPAND_Ato8(a) EXPAND_4to8( a ) #define EXPAND_Rto8(r) EXPAND_4to8( r ) #define EXPAND_Gto8(g) EXPAND_4to8( g ) #define EXPAND_Bto8(b) EXPAND_4to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB4444( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb4444_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb4444 #define A_SHIFT 12 #define R_SHIFT 8 #define G_SHIFT 4 #define B_SHIFT 0 #define A_MASK 0xf000 #define R_MASK 0x0f00 #define G_MASK 0x00f0 #define B_MASK 0x000f #include "template_acc_16.h" /* RGBA4444 */ #define EXPAND_Ato8(a) EXPAND_4to8( a ) #define EXPAND_Rto8(r) EXPAND_4to8( r ) #define EXPAND_Gto8(g) EXPAND_4to8( g ) #define EXPAND_Bto8(b) EXPAND_4to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGBA4444( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgba4444_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgba4444 #define A_SHIFT 0 #define R_SHIFT 12 #define G_SHIFT 8 #define B_SHIFT 4 #define A_MASK 0x000f #define R_MASK 0xf000 #define G_MASK 0x0f00 #define B_MASK 0x00f0 #include "template_acc_16.h" /* ARGB1666 */ #define EXPAND_Ato8(a) EXPAND_1to8( a ) #define EXPAND_Rto8(r) EXPAND_6to8( r ) #define EXPAND_Gto8(g) EXPAND_6to8( g ) #define EXPAND_Bto8(b) EXPAND_6to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB1666( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb1666_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb1666 #define A_SHIFT 18 #define R_SHIFT 12 #define G_SHIFT 6 #define B_SHIFT 0 #define A_MASK 0x040000 #define R_MASK 0x03f000 #define G_MASK 0x000fc0 #define B_MASK 0x00003f #include "template_acc_24.h" /* ARGB6666 */ #define EXPAND_Ato8(a) EXPAND_6to8( a ) #define EXPAND_Rto8(r) EXPAND_6to8( r ) #define EXPAND_Gto8(g) EXPAND_6to8( g ) #define EXPAND_Bto8(b) EXPAND_6to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB6666( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb6666_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb6666 #define A_SHIFT 18 #define R_SHIFT 12 #define G_SHIFT 6 #define B_SHIFT 0 #define A_MASK 0xfc0000 #define R_MASK 0x03f000 #define G_MASK 0x000fc0 #define B_MASK 0x00003f #include "template_acc_24.h" /* RGB18 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) EXPAND_6to8( r ) #define EXPAND_Gto8(g) EXPAND_6to8( g ) #define EXPAND_Bto8(b) EXPAND_6to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB18( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgb18_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgb18 #define A_SHIFT 0 #define R_SHIFT 12 #define G_SHIFT 6 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0x03f000 #define G_MASK 0x000fc0 #define B_MASK 0x00003f #include "template_acc_24.h" /* RGB444 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) EXPAND_4to8( r ) #define EXPAND_Gto8(g) EXPAND_4to8( g ) #define EXPAND_Bto8(b) EXPAND_4to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB444( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_xrgb4444_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_xrgb4444 #define A_SHIFT 0 #define R_SHIFT 8 #define G_SHIFT 4 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0x0f00 #define G_MASK 0x00f0 #define B_MASK 0x000f #include "template_acc_16.h" /* RGB555 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_5to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGB555( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_xrgb1555_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_xrgb1555 #define A_SHIFT 0 #define R_SHIFT 10 #define G_SHIFT 5 #define B_SHIFT 0 #define A_MASK 0 #define R_MASK 0x7c00 #define G_MASK 0x03e0 #define B_MASK 0x001f #include "template_acc_16.h" /* BGR555 */ #define EXPAND_Ato8(a) 0xff #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_5to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_BGR555( r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_xbgr1555_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_xbgr1555 #define A_SHIFT 0 #define B_SHIFT 10 #define G_SHIFT 5 #define R_SHIFT 0 #define A_MASK 0 #define B_MASK 0x7c00 #define G_MASK 0x03e0 #define R_MASK 0x001f #include "template_acc_16.h" /* RGBA5551 */ #define EXPAND_Ato8(a) EXPAND_1to8( a ) #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_5to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_RGBA5551( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgba5551_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgba5551 #define A_SHIFT 0 #define R_SHIFT 11 #define G_SHIFT 6 #define B_SHIFT 1 #define A_MASK 0x0001 #define R_MASK 0xf800 #define G_MASK 0x07c0 #define B_MASK 0x003e #include "template_acc_16.h" /* ARGB8565 */ #define EXPAND_Ato8(a) (a) #define EXPAND_Rto8(r) EXPAND_5to8( r ) #define EXPAND_Gto8(g) EXPAND_6to8( g ) #define EXPAND_Bto8(b) EXPAND_5to8( b ) #define PIXEL_OUT(a,r,g,b) PIXEL_ARGB8565( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_argb8565_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_argb8565 #define A_SHIFT 16 #define R_SHIFT 11 #define G_SHIFT 5 #define B_SHIFT 0 #define A_MASK 0xff0000 #define R_MASK 0x00f800 #define G_MASK 0x0007e0 #define B_MASK 0x00001f #include "template_acc_24.h" /* RGBAF88871 */ #define EXPAND_Ato8(a) EXPAND_7to8(a) #define EXPAND_Rto8(r) (r) #define EXPAND_Gto8(g) (g) #define EXPAND_Bto8(b) (b) #define PIXEL_OUT(a,r,g,b) PIXEL_RGBAF88871( a, r, g, b ) #define Sop_PFI_OP_Dacc(op) Sop_rgbaf88871_##op##_Dacc #define Sacc_OP_Aop_PFI(op) Sacc_##op##_Aop_rgbaf88871 #define A_SHIFT 1 #define R_SHIFT 24 #define G_SHIFT 16 #define B_SHIFT 8 #define A_MASK 0x000000fe #define R_MASK 0xff000000 #define G_MASK 0x00ff0000 #define B_MASK 0x0000ff00 #include "template_acc_32.h" /**********************************************************************************************************************/ /* Whether pixelformat is YUV or not. */ static const bool is_ycbcr[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = false, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = true, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = false, }; /********************************************************************************************************************** ********************************* Cop_to_Aop_PFI ********************************************************************* **********************************************************************************************************************/ static void Cop_to_Aop_16( GenefxState *gfxs ) { int l; int w = gfxs->length; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 DCop = ((Cop << 16) | Cop); if (((long) D) & 2) { u16* tmp = (u16*) D; --w; *tmp = Cop; D = (u32*) (tmp + 1); } l = w >> 1; while (l) { *D = DCop; ++D; --l; } if (w & 1) *((u16*) D) = (u16) Cop; } static void Cop_to_Aop_24( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; while (--w) { #ifdef WORDS_BIGENDIAN D[0] = (Cop >> 16) & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = Cop & 0xff; #else D[0] = Cop & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = (Cop >> 16) & 0xff; #endif D += 3; } } static void Cop_to_Aop_32( GenefxState *gfxs ) { int w = gfxs->length; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; while (w) { if (!(w % 8)) { *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; w -= 8; } else if (!(w % 4)) { *D++ = Cop; *D++ = Cop; *D++ = Cop; *D++ = Cop; w -= 4; } else if (!(w % 2)) { *D++ = Cop; *D++ = Cop; w -= 2; } else { *D++ = Cop; --w; } } } static void Cop_to_Aop_8( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->Cop, gfxs->length ); } static void Cop_to_Aop_yuv422( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; if ((long) D & 2) { #ifdef WORDS_BIGENDIAN *D++ = Cop & 0xffff; #else *D++ = Cop >> 16; #endif --w; } for (l = w >> 1; l--;) { *((u32*) D) = Cop; D += 2; } if (w & 1) { #ifdef WORDS_BIGENDIAN *D = Cop >> 16; #else *D = Cop & 0xffff; #endif } } static void Cop_to_Aop_i420( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); if (gfxs->AopY & 1) { memset( gfxs->Aop[1], gfxs->CbCop, gfxs->length >> 1 ); memset( gfxs->Aop[2], gfxs->CrCop, gfxs->length >> 1 ); } } static void Cop_to_Aop_nv12( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); if (gfxs->AopY & 1) { int w = (gfxs->length >> 1) + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CbCop | (gfxs->CrCop << 8); while (--w) *D++ = Cop; } } static void Cop_to_Aop_nv16( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CbCop | (gfxs->CrCop << 8); memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); while (--w) *D++ = Cop; } static void Cop_to_Aop_nv21( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); if (gfxs->AopY & 1) { int w = (gfxs->length >> 1) + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CrCop | (gfxs->CbCop << 8); while (--w) *D++ = Cop; } } static void Cop_to_Aop_18( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; while (--w) { D[0] = Cop; D[1] = Cop >> 8; D[2] = Cop >> 16; D += 3; } } static void Cop_to_Aop_y444( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); memset( gfxs->Aop[1], gfxs->CbCop, gfxs->length ); memset( gfxs->Aop[2], gfxs->CrCop, gfxs->length ); } static void Cop_to_Aop_argb8565( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; while (--w) { #ifdef WORDS_BIGENDIAN D[0] = (Cop >> 16) & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = Cop & 0xff; #else D[0] = Cop & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = (Cop >> 16) & 0xff; #endif D += 3; } } static void Cop_to_Aop_vyu( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; while (--w) { #ifdef WORDS_BIGENDIAN D[0] = gfxs->CrCop; D[1] = gfxs->YCop; D[2] = gfxs->CbCop; #else D[0] = gfxs->CbCop; D[1] = gfxs->YCop; D[2] = gfxs->CrCop; #endif D += 3; } } static void Cop_to_Aop_y42b( GenefxState *gfxs ) { memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); memset( gfxs->Aop[1], gfxs->CbCop, gfxs->length / 2 ); memset( gfxs->Aop[2], gfxs->CrCop, gfxs->length / 2 ); } static void Cop_to_Aop_nv61( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CrCop | (gfxs->CbCop << 8); memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); while (--w) *D++ = Cop; } static void Cop_to_Aop_nv24( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CbCop | (gfxs->CrCop << 8); memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); while (--w) *D++ = Cop; } static void Cop_to_Aop_nv42( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *D = gfxs->Aop[1]; u16 Cop = gfxs->CrCop | (gfxs->CbCop << 8); memset( gfxs->Aop[0], gfxs->YCop, gfxs->length ); while (--w) *D++ = Cop; } static GenefxFunc Cop_to_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Cop_to_Aop_24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Cop_to_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Cop_to_Aop_yuv422, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Cop_to_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Cop_to_Aop_yuv422, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Cop_to_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Cop_to_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Cop_to_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Cop_to_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Cop_to_Aop_nv12, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Cop_to_Aop_nv16, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Cop_to_Aop_nv21, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Cop_to_Aop_18, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Cop_to_Aop_18, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Cop_to_Aop_18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Cop_to_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Cop_to_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Cop_to_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Cop_to_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Cop_to_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Cop_to_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Cop_to_Aop_nv61, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Cop_to_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Cop_to_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Cop_to_Aop_nv24, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Cop_to_Aop_nv42, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Cop_to_Aop_24, }; /********************************************************************************************************************** ********************************* Cop_toK_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Cop_toK_Aop_8( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { if (Dkey == *D) *D = Cop; ++D; } } static void Cop_toK_Aop_yuv422( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; if ((long) D & 2) { #ifdef WORDS_BIGENDIAN if (*D == (Dkey & 0xffff)) *D = Cop & 0xffff; #else if (*D == (Dkey >> 16)) *D = Cop >> 16; #endif ++D; --w; } for (l = w >> 1; l--;) { if (*((u32*) D) == Dkey) *((u32*) D) = Cop; D += 2; } if (w & 1) { #ifdef WORDS_BIGENDIAN if (*D == (Dkey >> 16)) *D = Cop >> 16; #else if (*D == (Dkey & 0xffff)) *D = Cop & 0xffff; #endif } } static void Cop_toK_Aop_alut44( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { if (Dkey == (*D & 0x0f)) *D = Cop; ++D; } } static void Cop_toK_Aop_y444( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (Dkey == (u32) ((dy << 16) | (du << 8) | dv)) { *Dy = (Cop >> 16) & 0xff; *Du = (Cop >> 8) & 0xff; *Dv = Cop & 0xff; } ++Dy; ++Du; ++Dv; } } static void Cop_toK_Aop_avyu( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { if ((*D & 0x00ffffff) == Dkey) *D = Cop; ++D; } } static GenefxFunc Cop_toK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Cop_toK_Aop_15, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Cop_toK_Aop_16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Cop_toK_Aop_24_24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Cop_toK_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Cop_toK_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Cop_toK_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Cop_toK_Aop_yuv422, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Cop_toK_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Cop_toK_Aop_yuv422, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Cop_toK_Aop_8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Cop_toK_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Cop_toK_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Cop_toK_Aop_14, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Cop_toK_Aop_12, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Cop_toK_Aop_12vv, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Cop_toK_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Cop_toK_Aop_24_18, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Cop_toK_Aop_24_18, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Cop_toK_Aop_24_18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Cop_toK_Aop_12, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Cop_toK_Aop_15, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Cop_toK_Aop_15, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Cop_toK_Aop_15, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Cop_toK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Cop_toK_Aop_24_16, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Cop_toK_Aop_avyu, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Cop_toK_Aop_24_24, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Cop_toK_Aop_32, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Cop_toK_Aop_32_24, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Cop_toK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Cop_toK_Aop_24_24, }; /********************************************************************************************************************** ********************************* Sop_PFI_to_Dacc ******************************************************************** **********************************************************************************************************************/ static void Sop_a8_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D->RGB.a = *S++; D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; } } static void Sop_yuy2_to_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { u32 s = *S++; D[0].YUV.a = D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.y = (s & 0x00ff0000) >> 16; D[1].YUV.y = s & 0x000000ff; D[0].YUV.u = D[1].YUV.u = (s & 0xff000000) >> 24; D[0].YUV.v = D[1].YUV.v = (s & 0x0000ff00) >> 8; #else D[0].YUV.y = s & 0x000000ff; D[1].YUV.y = (s & 0x00ff0000) >> 16; D[0].YUV.u = D[1].YUV.u = (s & 0x0000ff00) >> 8; D[0].YUV.v = D[1].YUV.v = (s & 0xff000000) >> 24; #endif D += 2; } if (gfxs->length & 1) { u16 s = *((u16*) S); D->YUV.a = 0xff; D->YUV.y = s & 0xff; D->YUV.u = s >> 8; D->YUV.v = 0x00; } } static void Sop_rgb332_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { u8 s = *S++; D->RGB.a = 0xff; D->RGB.r = EXPAND_3to8( s >> 5 ); D->RGB.g = EXPAND_3to8( (s & 0x1c) >> 2 ); D->RGB.b = EXPAND_2to8( s & 0x03 ); ++D; } } static void Sop_uyvy_to_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { u32 s = *S++; D[0].YUV.a = D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.y = (s & 0xff000000) >> 24; D[1].YUV.y = (s & 0x0000ff00) >> 8; D[0].YUV.u = D[1].YUV.u = (s & 0x00ff0000) >> 16; D[0].YUV.v = D[1].YUV.v = s & 0x000000ff; #else D[0].YUV.y = (s & 0x0000ff00) >> 8; D[1].YUV.y = (s & 0xff000000) >> 24; D[0].YUV.u = D[1].YUV.u = s & 0x000000ff; D[0].YUV.v = D[1].YUV.v = (s & 0x00ff0000) >> 16; #endif D += 2; } if (gfxs->length & 1) { u16 s = *((u16*) S); D->YUV.a = 0xff; D->YUV.y = s >> 8; D->YUV.u = s & 0xff; D->YUV.v = 0x00; } } static void Sop_i420_to_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D[1].YUV.a = D[0].YUV.a = 0xff; D[0].YUV.y = Sy[0]; D[1].YUV.y = Sy[1]; D[1].YUV.u = D[0].YUV.u = Su[0]; D[1].YUV.v = D[0].YUV.v = Sv[0]; Sy += 2; ++Su; ++Sv; D += 2; } } static void Sop_lut8_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = *S++; D->RGB.a = entries[s].a; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; ++D; } } static void Sop_alut44_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = *S++; D->RGB.a = s & 0xf0; s &= 0x0f; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; ++D; } } static void Sop_nv12_to_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u8 *Sy = gfxs->Sop[0]; u16 *Suv = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D[1].YUV.a = D[0].YUV.a = 0xff; D[0].YUV.y = Sy[0]; D[1].YUV.y = Sy[1]; D[1].YUV.u = D[0].YUV.u = Suv[0] & 0xff; D[1].YUV.v = D[0].YUV.v = Suv[0] >> 8; Sy += 2; ++Suv; D += 2; } } static void Sop_nv21_to_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u8 *Sy = gfxs->Sop[0]; u16 *Svu = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D[1].YUV.a = D[0].YUV.a = 0xff; D[0].YUV.y = Sy[0]; D[1].YUV.y = Sy[1]; D[1].YUV.u = D[0].YUV.u = Svu[0] >> 8; D[1].YUV.v = D[0].YUV.v = Svu[0] & 0xff; Sy += 2; ++Svu; D += 2; } } static void Sop_ayuv_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { u32 s = *S++; D->YUV.a = s >> 24; D->YUV.y = (s >> 16) & 0xff; D->YUV.u = (s >> 8) & 0xff; D->YUV.v = s & 0xff; ++D; } } static void Sop_a4_to_Dacc( GenefxState *gfxs ) { int i, n; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; for (i = 0, n = 0; i < gfxs->length; i += 2, n++) { int left = S[n] & 0xf0; int right = S[n] & 0x0f; D[i].RGB.a = left | (left >> 4); D[i].RGB.r = 0xff; D[i].RGB.g = 0xff; D[i].RGB.b = 0xff; D[i+1].RGB.a = right | (right << 4); D[i+1].RGB.r = 0xff; D[i+1].RGB.g = 0xff; D[i+1].RGB.b = 0xff; } } static void Sop_y444_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D->YUV.a = 0xff; D->YUV.y = *Sy++; D->YUV.u = *Su++; D->YUV.v = *Sv++; ++D; } } static void Sop_avyu_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { u32 s = *S++; D->YUV.a = s >> 24; D->YUV.v = (s >> 16) & 0xff; D->YUV.y = (s >> 8) & 0xff; D->YUV.u = s & 0xff; ++D; } } static void Sop_vyu_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { #ifdef WORDS_BIGENDIAN D->YUV.a = 0xff; D->YUV.v = S[0]; D->YUV.y = S[1]; D->YUV.u = S[2]; #else D->YUV.a = 0xff; D->YUV.v = S[2]; D->YUV.y = S[1]; D->YUV.u = S[0]; #endif S += 3; ++D; } } static void Sop_nv24_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Suv = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D[0].YUV.a = 0xff; D[0].YUV.y = *Sy++; D[0].YUV.u = Suv[0] & 0xff; D[0].YUV.v = Suv[0] >> 8; ++Suv; D++; } } static void Sop_nv42_to_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Svu = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; while (--w) { D[0].YUV.a = 0xff; D[0].YUV.y = *Sy++; D[0].YUV.u = Svu[0] >> 8; D[0].YUV.v = Svu[0] & 0xff; ++Svu; D++; } } static GenefxFunc Sop_PFI_to_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sop_a8_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sop_yuy2_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sop_rgb332_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sop_uyvy_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Sop_i420_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Sop_i420_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sop_lut8_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sop_alut44_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sop_nv12_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sop_nv12_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sop_nv21_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Sop_ayuv_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = Sop_a4_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb1666_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb6666_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sop_y444_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sop_avyu_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sop_vyu_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Sop_i420_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sop_nv21_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Sop_i420_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sop_y444_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sop_nv24_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sop_nv42_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_to_Dacc, }; /********************************************************************************************************************** ********************************* Sop_PFI_Kto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_a8_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; /* No color to key. */ while (--w) { D->RGB.a = *S++; D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; } } static void Sop_yuy2_Kto_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; u32 Skey0 = gfxs->Skey & 0xff00ffff; u32 Skey1 = gfxs->Skey & 0xffffff00; #ifdef WORDS_BIGENDIAN #define S0_MASK 0xffffff00 #define S1_MASK 0xff00ffff #else #define S0_MASK 0xff00ffff #define S1_MASK 0xffffff00 #endif while (--w) { u32 s = *S++; if (s != Skey) { u32 cb, cr; #ifdef WORDS_BIGENDIAN cb = (s & 0xff000000) >> 24; cr = (s & 0x0000ff00) >> 8; #else cb = (s & 0x0000ff00) >> 8; cr = (s & 0xff000000) >> 24; #endif if ((s & S0_MASK) != Skey0) { D[0].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.y = (s & 0x00ff0000) >> 16; #else D[0].YUV.y = s & 0x000000ff; #endif D[0].YUV.u = cb; D[0].YUV.v = cr; } else D[0].YUV.a = 0xf000; if ((s & S1_MASK) != Skey1) { D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[1].YUV.y = s & 0x000000ff; #else D[1].YUV.y = (s & 0x00ff0000) >> 16; #endif D[1].YUV.u = cb; D[1].YUV.v = cr; } else D[1].YUV.a = 0xf000; } D += 2; } if (gfxs->length & 1) { u16 s = *((u16*) S); if (s != Skey0) { D->YUV.a = 0xff; D->YUV.y = s & 0xff; D->YUV.u = s >> 8; D->YUV.v = 0x00; } else D->YUV.a = 0xf000; } #undef S0_MASK #undef S1_MASK } static void Sop_rgb332_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; while (--w) { u8 s = *S++; if (s != Skey) { D->RGB.a = 0xff; D->RGB.r = EXPAND_3to8( s >> 5 ); D->RGB.g = EXPAND_3to8( (s & 0x1c) >> 2 ); D->RGB.b = EXPAND_2to8( s & 0x03 ); } else D->RGB.a = 0xf000; ++D; } } static void Sop_uyvy_Kto_Dacc( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; u32 Skey0 = gfxs->Skey & 0x00ffffff; u32 Skey1 = gfxs->Skey & 0xffff00ff; #ifdef WORDS_BIGENDIAN #define S0_MASK 0xffff00ff #define S1_MASK 0x00ffffff #else #define S0_MASK 0x00ffffff #define S1_MASK 0xffff00ff #endif while (--w) { u32 s = *S++; if (s != Skey) { u32 cb, cr; #ifdef WORDS_BIGENDIAN cb = (s & 0x00ff0000) >> 16; cr = s & 0x000000ff; #else cb = s & 0x000000ff; cr = (s & 0x00ff0000) >> 16; #endif if ((s & S0_MASK) != Skey0) { D[0].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.y = (s & 0xff000000) >> 24; #else D[0].YUV.y = (s & 0x0000ff00) >> 8; #endif D[0].YUV.u = cb; D[0].YUV.v = cr; } else D[0].YUV.a = 0xf000; if ((s & S1_MASK) != Skey1) { D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[1].YUV.y = (s & 0x0000ff00) >> 8; #else D[1].YUV.y = (s & 0xff000000) >>24; #endif D[1].YUV.u = cb; D[1].YUV.v = cr; } else D[1].YUV.a = 0xf000; } D += 2; } if (gfxs->length & 1) { u16 s = *((u16*) S); if (s != Skey0) { D->YUV.a = 0xff; D->YUV.y = s >> 8; D->YUV.u = s & 0xff; D->YUV.v = 0x00; } else D->YUV.a = 0xf000; } #undef S0_MASK #undef S1_MASK } static void Sop_lut8_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = *S++; if (s != Skey) { D->RGB.a = entries[s].a; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; } else D->RGB.a = 0xf000; ++D; } } static void Sop_alut44_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = *S++; if ((s & 0x0f) != Skey) { D->RGB.a = ((s & 0xf0) >> 4) | (s & 0xf0); s &= 0x0f; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; } else D->RGB.a = 0xf000; ++D; } } static void Sop_y444_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; while (--w) { u8 sy = *Sy++; u8 su = *Su++; u8 sv = *Sv++; if (Skey != (u32) ((sy << 16) | (su << 8) | sv)) { D->YUV.a = 0xff; D->YUV.y = sy; D->YUV.u = su; D->YUV.v = sv; } else D->YUV.a = 0xf000; ++D; } } static void Sop_avyu_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; while (--w) { u32 s = *S++; if ((s & 0x00ffffff) != Skey) { D->YUV.a = (s & 0xff000000) >> 24; D->YUV.v = (s & 0x00ff0000) >> 16; D->YUV.y = (s & 0x0000ff00) >> 8; D->YUV.u = s & 0x000000ff; } else D->YUV.a = 0xf000; ++D; } } static void Sop_vyu_Kto_Dacc( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; while (--w) { #ifdef WORDS_BIGENDIAN u32 s = S[0] << 16 | S[1] << 8 | S[2]; #else u32 s = S[2] << 16 | S[1] << 8 | S[0]; #endif if (Skey != s) { #ifdef WORDS_BIGENDIAN D->YUV.a = 0xff; D->YUV.v = S[0]; D->YUV.y = S[1]; D->YUV.u = S[2]; #else D->YUV.a = 0xff; D->YUV.v = S[2]; D->YUV.y = S[1]; D->YUV.u = S[0]; #endif } else D->YUV.a = 0xf000; S += 3; ++D; } } static GenefxFunc Sop_PFI_Kto_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sop_a8_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sop_yuy2_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sop_rgb332_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sop_uyvy_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sop_lut8_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sop_alut44_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb6666_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb1666_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sop_y444_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sop_avyu_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sop_vyu_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sop_y444_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_Kto_Dacc, }; /********************************************************************************************************************** ********************************* Sop_PFI_Sto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_a8_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u8 s = S[i>>16]; D->RGB.a = s; D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; i += SperD; } } static void Sop_yuy2_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>17]; D[0].YUV.a = D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.u = D[1].YUV.u = (s & 0xff000000) >> 24; D[0].YUV.v = D[1].YUV.v = (s & 0x0000ff00) >> 8; #else D[0].YUV.u = D[1].YUV.u = (s & 0x0000ff00) >> 8; D[0].YUV.v = D[1].YUV.v = (s & 0xff000000) >> 24; #endif D[0].YUV.y = ((u16*) S)[i>>16] & 0x00ff; D[1].YUV.y = ((u16*) S)[(i+SperD)>>16] & 0x00ff; D += 2; i += SperD << 1; } if (gfxs->length & 1) { u16 s = ((u16*) S)[i>>17]; D->YUV.a = 0xff; D->YUV.y = s & 0xff; D->YUV.u = s >> 8; D->YUV.v = 0x00; } } static void Sop_rgb332_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u8 s = S[i>>16]; D->RGB.a = 0xff; D->RGB.r = EXPAND_3to8( s >> 5 ); D->RGB.g = EXPAND_3to8( (s & 0x1c) >> 2 ); D->RGB.b = EXPAND_2to8( s & 0x03 ); ++D; i += SperD; } } static void Sop_uyvy_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>17]; D[0].YUV.a = D[1].YUV.a = 0xff; #ifdef WORDS_BIGENDIAN D[0].YUV.u = D[1].YUV.u = (s & 0x00ff0000) >> 16; D[0].YUV.v = D[1].YUV.v = s & 0x000000ff; #else D[0].YUV.u = D[1].YUV.u = s & 0x000000ff; D[0].YUV.v = D[1].YUV.v = (s & 0x00ff0000) >> 16; #endif D[0].YUV.y = (((u16*) S)[i>>16] & 0xff00) >> 8; D[1].YUV.y = (((u16*) S)[(i+SperD)>>16] & 0xff00) >> 8; D += 2; i += SperD << 1; } if (gfxs->length & 1) { u16 s = ((u16*) S)[i>>16]; D->YUV.a = 0xff; D->YUV.y = s >> 8; D->YUV.u = s & 0xff; D->YUV.v = 0x00; } } static void Sop_i420_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Su[i>>17]; D->YUV.v = Sv[i>>17]; ++D; i += SperD; } } static void Sop_lut8_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = S[i>>16]; D->RGB.a = entries[s].a; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; ++D; i += SperD; } } static void Sop_alut44_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = S[i>>16]; D->RGB.a = s & 0xf0; s &= 0x0f; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; ++D; i += SperD; } } static void Sop_nv12_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Suv = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Suv[i>>17] & 0xff; D->YUV.v = Suv[i>>17] >> 8; ++D; i += SperD; } } static void Sop_nv21_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Svu = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Svu[i>>17] >> 8; D->YUV.v = Svu[i>>17] & 0xff; ++D; i += SperD; } } static void Sop_ayuv_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>16]; D->YUV.a = (s >> 24); D->YUV.y = (s >> 16) & 0xff; D->YUV.u = (s >> 8) & 0xff; D->YUV.v = s & 0xff; ++D; i += SperD; } } static void Sop_a4_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { int j = i >> 16; u8 s = S[j>>1]; if (j & 1) D->RGB.a = (s & 0x0f) | ((s << 4) & 0xf0); else D->RGB.a = (s & 0xf0) | (s >> 4); D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; i += SperD; } } static void Sop_y444_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Su[i>>16]; D->YUV.v = Sv[i>>16]; ++D; i += SperD; } } static void Sop_avyu_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>16]; D->YUV.a = (s >> 24); D->YUV.v = (s >> 16) & 0xff; D->YUV.y = (s >> 8) & 0xff; D->YUV.u = s & 0xff; ++D; i += SperD; } } static void Sop_vyu_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { int pixelstart = (i >> 16) * 3; #ifdef WORDS_BIGENDIAN D->YUV.a = 0xff; D->YUV.v = S[pixelstart+0]; D->YUV.y = S[pixelstart+1]; D->YUV.u = S[pixelstart+2]; #else D->YUV.a = 0xff; D->YUV.v = S[pixelstart+2]; D->YUV.y = S[pixelstart+1]; D->YUV.u = S[pixelstart+0]; #endif ++D; i += SperD; } } static void Sop_nv24_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Suv = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Suv[i>>16] & 0xff; D->YUV.v = Suv[i>>16] >> 8; ++D; i += SperD; } } static void Sop_nv42_Sto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u16 *Svu = gfxs->Sop[1]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; while (--w) { D->YUV.a = 0xff; D->YUV.y = Sy[i>>16]; D->YUV.u = Svu[i>>16] >> 8; D->YUV.v = Svu[i>>16] & 0xff; ++D; i += SperD; } } static GenefxFunc Sop_PFI_Sto_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sop_a8_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sop_yuy2_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sop_rgb332_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sop_uyvy_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Sop_i420_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Sop_i420_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sop_lut8_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sop_alut44_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sop_nv12_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sop_nv12_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sop_nv21_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Sop_ayuv_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = Sop_a4_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb1666_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb6666_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sop_y444_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sop_avyu_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sop_vyu_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Sop_i420_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sop_nv21_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Sop_i420_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sop_y444_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sop_nv24_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sop_nv42_Sto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_Sto_Dacc, }; /********************************************************************************************************************** ********************************* Sop_PFI_SKto_Dacc ****************************************************************** **********************************************************************************************************************/ static void Sop_a8_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; /* No color to key. */ while (--w) { u8 s = S[i>>16]; D->RGB.a = s; D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; i += SperD; } } static void Sop_yuy2_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Ky = gfxs->Skey & 0x000000ff; #ifdef WORDS_BIGENDIAN u32 Kcb = (gfxs->Skey & 0xff000000) >> 24; u32 Kcr = (gfxs->Skey & 0x0000ff00) >> 8; #else u32 Kcb = (gfxs->Skey & 0x0000ff00) >> 8; u32 Kcr = (gfxs->Skey & 0xff000000) >> 24; #endif int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>17]; u32 y0, cb, y1, cr; #ifdef WORDS_BIGENDIAN cb = (s & 0xff000000) >> 24; cr = (s & 0x0000ff00) >> 8; #else cb = (s & 0x0000ff00) >> 8; cr = (s & 0xff000000) >> 24; #endif y0 = ((u16*) S)[i>>16] & 0x00ff; y1 = ((u16*) S)[(i+SperD)>>16] & 0x00ff; if (y0 != Ky || cb != Kcb || cr != Kcr) { D[0].YUV.a = 0xff; D[0].YUV.y = y0; D[0].YUV.u = cb; D[0].YUV.v = cr; } else D[0].YUV.a = 0xf000; if (y0 != Ky || cb != Kcb || cr != Kcr) { D[1].YUV.a = 0xff; D[1].YUV.y = y1; D[1].YUV.u = cb; D[1].YUV.v = cr; } else D[1].YUV.a = 0xf000; D += 2; i += SperD << 1; } if (gfxs->length & 1) { u16 s = ((u16*) S)[i>>16]; if (s != (Ky | (Kcb << 8))) { D->YUV.a = 0xff; D->YUV.y = s & 0xff; D->YUV.u = s >> 8; D->YUV.v = 0x00; } else D->YUV.a = 0xf000; } } static void Sop_rgb332_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u8 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u8 s = S[i>>16]; if (s != Skey) { D->RGB.a = 0xff; D->RGB.r = EXPAND_3to8( s >> 5 ); D->RGB.g = EXPAND_3to8( (s & 0x1c) >> 2 ); D->RGB.b = EXPAND_2to8( s & 0x03 ); } else D->RGB.a = 0xf000; ++D; i += SperD; } } static void Sop_uyvy_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = (gfxs->length >> 1) + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Ky = (gfxs->Skey & 0x0000ff00) >> 8; #ifdef WORDS_BIGENDIAN u32 Kcb = (gfxs->Skey & 0x00ff0000) >> 16; u32 Kcr = gfxs->Skey & 0x000000ff; #else u32 Kcb = gfxs->Skey & 0x000000ff; u32 Kcr = (gfxs->Skey & 0x00ff0000) >> 16; #endif int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>17]; u32 cb, y0, cr, y1; #ifdef WORDS_BIGENDIAN cb = (s & 0x00ff0000) >> 16; cr = s & 0x000000ff; #else cb = s & 0x000000ff; cr = (s & 0x00ff0000) >> 16; #endif y0 = (((u16*) S)[i>>16] & 0xff00) >> 8; y1 = (((u16*) S)[(i+SperD)>>16] & 0xff00) >> 8; if (y0 != Ky || cb != Kcb || cr != Kcr) { D[0].YUV.a = 0xff; D[0].YUV.y = y0; D[0].YUV.u = cb; D[0].YUV.v = cr; } else D[0].YUV.a = 0xf000; if (y0 != Ky || cb != Kcb || cr != Kcr) { D[1].YUV.a = 0xff; D[1].YUV.y = y1; D[1].YUV.u = cb; D[1].YUV.v = cr; } else D[1].YUV.a = 0xf000; D += 2; i += SperD << 1; } if (gfxs->length & 1) { u16 s = ((u16*) S)[i>>16]; if (s != (Kcb | (Ky << 8))) { D->YUV.a = 0xff; D->YUV.y = s >> 8; D->YUV.u = s & 0xff; D->YUV.v = 0x00; } else D->YUV.a = 0xf000; } } static void Sop_lut8_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = S[i>>16]; if (s != Skey) { D->RGB.a = entries[s].a; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; } else D->RGB.a = 0xf000; ++D; i += SperD; } } static void Sop_alut44_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; DFBColor *entries = gfxs->Slut->entries; while (--w) { u8 s = S[i>>16]; if ((s & 0x0f) != Skey) { D->RGB.a = ((s & 0xf0) >> 4) | (s & 0xf0); s &= 0x0f; D->RGB.r = entries[s].r; D->RGB.g = entries[s].g; D->RGB.b = entries[s].b; } else D->RGB.a = 0xf000; ++D; i += SperD; } } static void Sop_y444_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Sop[0]; u8 *Su = gfxs->Sop[1]; u8 *Sv = gfxs->Sop[2]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u8 sy = Sy[i>>16]; u8 su = Su[i>>16]; u8 sv = Sv[i>>16]; if (Skey != (u32) (sy << 16 | su << 8 | sv)) { D->YUV.a = 0xff; D->YUV.y = sy; D->YUV.u = su; D->YUV.v = sv; } else D->YUV.a = 0xff00; ++D; i += SperD; } } static void Sop_avyu_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>16]; if ((s & 0x00ffffff) != Skey) { D->YUV.a = (s & 0xff000000) >> 24; D->YUV.v = (s & 0x00ff0000) >> 16; D->YUV.y = (s & 0x0000ff00) >> 8; D->YUV.u = s & 0x000000ff; } else D->YUV.a = 0xf000; ++D; i += SperD; } } static void Sop_vyu_SKto_Dacc( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { int pixelstart = (i >> 16) * 3; #ifdef WORDS_BIGENDIAN u32 s = S[pixelstart+0] << 16 | S[pixelstart+1] << 8 | S[pixelstart+2]; #else u32 s = S[pixelstart+2] << 16 | S[pixelstart+1] << 8 | S[pixelstart+0]; #endif if (Skey != s) { #ifdef WORDS_BIGENDIAN D->YUV.a = 0xff; D->YUV.v = S[pixelstart+0]; D->YUV.y = S[pixelstart+1]; D->YUV.u = S[pixelstart+2]; #else D->YUV.a = 0xff; D->YUV.v = S[pixelstart+2]; D->YUV.y = S[pixelstart+1]; D->YUV.u = S[pixelstart+0]; #endif } else D->YUV.a = 0xf000; ++D; i += SperD; } } static GenefxFunc Sop_PFI_SKto_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sop_a8_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sop_yuy2_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sop_rgb332_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sop_uyvy_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sop_lut8_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sop_alut44_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb1666_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb6666_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sop_y444_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sop_avyu_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sop_vyu_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sop_y444_SKto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_SKto_Dacc, }; /********************************************************************************************************************** ********************************* Sop_PFI_TEX_to_Dacc **************************************************************** **********************************************************************************************************************/ static void Sop_a8_TEX_to_Dacc( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; int TperD = gfxs->TperD; while (--w) { D->RGB.a = S[(s>>16)+(t>>16)*gfxs->src_pitch]; D->RGB.r = 0xff; D->RGB.g = 0xff; D->RGB.b = 0xff; ++D; s += SperD; t += TperD; } } static GenefxFunc Sop_PFI_TEX_to_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sop_a8_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb1666_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb6666_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_TEX_to_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_TEX_to_Dacc, }; /********************************************************************************************************************** ********************************* Sop_PFI_TEX_Kto_Dacc *************************************************************** **********************************************************************************************************************/ static GenefxFunc Sop_PFI_TEX_Kto_Dacc[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sop_argb1555_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sop_rgb24_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sop_rgb32_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sop_airgb_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sop_argb2554_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sop_argb4444_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sop_rgba4444_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sop_argb1666_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sop_argb6666_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sop_rgb18_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sop_xrgb4444_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sop_xrgb1555_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sop_xbgr1555_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sop_rgba5551_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sop_argb8565_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sop_abgr_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sop_rgbaf88871_TEX_Kto_Dacc, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sop_bgr24_TEX_Kto_Dacc, }; /********************************************************************************************************************** ********************************* Sacc_to_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Sacc_to_Aop_a8( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->RGB.a & 0xf000)) { *D = (S->RGB.a & 0xff00) ? 0xff : S->RGB.a; } ++S; ++D; } } static void Sacc_to_Aop_yuy2( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; if ((long) D & 2) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.y & 0xff00) ? 0x00ff : S->YUV.y) | ((S->YUV.v & 0xff00) ? 0xff00 : (S->YUV.v << 8)); } ++S; ++D; --w; } for (l = w >> 1; l--;) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 y0, cb, y1, cr; y0 = (S[0].YUV.y & 0xff00) ? 0xff : S[0].YUV.y; y1 = (S[1].YUV.y & 0xff00) ? 0xff : S[1].YUV.y; cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = y1 | (cr << 8) | (y0 << 16) | (cb << 24); #else *((u32*) D) = y0 | (cb << 8) | (y1 << 16) | (cr << 24); #endif } else if (!(S[0].YUV.a & 0xf000)) { D[0] = ((S[0].YUV.y & 0xff00) ? 0x00ff : S[0].YUV.y) | ((S[0].YUV.u & 0xff00) ? 0xff00 : (S[0].YUV.u << 8)); } else if (!(S[1].YUV.a & 0xf000)) { D[1] = ((S[1].YUV.y & 0xff00) ? 0x00ff : S[1].YUV.y) | ((S[1].YUV.v & 0xff00) ? 0xff00 : (S[1].YUV.v << 8)); } S += 2; D += 2; } if (w & 1) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.y & 0xff00) ? 0x00ff : S->YUV.y) | ((S->YUV.u & 0xff00) ? 0xff00 : (S->YUV.u << 8)); } } } static void Sacc_to_Aop_rgb332( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->RGB.a & 0xf000)) { *D = PIXEL_RGB332( (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b ); } ++S; ++D; } } static void Sacc_to_Aop_uyvy( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; if ((long) D & 2) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.v & 0xff00) ? 0x00ff : S->YUV.v) | ((S->YUV.y & 0xff00) ? 0xff00 : (S->YUV.y << 8)); } ++S; ++D; --w; } for (l = w >> 1; l--;) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 cb, y0, cr, y1; y0 = (S[0].YUV.y & 0xff00) ? 0xff : S[0].YUV.y; y1 = (S[1].YUV.y & 0xff00) ? 0xff : S[1].YUV.y; cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = cr | (y1 << 8) | (cb << 16) | (y0 << 24); #else *((u32*) D) = cb | (y0 << 8) | (cr << 16) | (y1 << 24); #endif } else if (!(S[0].YUV.a & 0xf000)) { D[0] = ((S[0].YUV.u & 0xff00) ? 0x00ff : S[0].YUV.u) | ((S[0].YUV.y & 0xff00) ? 0xff00 : (S[0].YUV.y << 8)); } else if (!(S[1].YUV.a & 0xf000)) { D[1] = ((S[1].YUV.v & 0xff00) ? 0x00ff : S[1].YUV.v) | ((S[1].YUV.y & 0xff00) ? 0xff00 : (S[1].YUV.y << 8)); } S += 2; D += 2; } if (w & 1) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.u & 0xff00) ? 0x00ff : S->YUV.u) | ((S->YUV.y & 0xff00) ? 0xff00 : (S->YUV.y << 8)); } } } static void Sacc_to_Aop_i420( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } if (gfxs->AopY & 1) { u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; w = (gfxs->length >> 1) + 1; S = gfxs->Sacc; while (--w) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 tmp; tmp = (S[0].YUV.u + S[1].YUV.u) >> 1; if (tmp & 0xff00) tmp = 0xff; *Du = tmp; tmp = (S[0].YUV.v + S[1].YUV.v) >> 1; if (tmp & 0xff00) tmp = 0xff; *Dv = tmp; } else if (!(S[0].YUV.a & 0xf000)) { *Du = (*Du + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; *Dv = (*Dv + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; } else if (!(S[1].YUV.a & 0xf000)) { *Du = (*Du + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) >> 1; *Dv = (*Dv + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) >> 1; } S += 2; ++Du; ++Dv; } } } static void Sacc_to_Aop_lut8( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->RGB.a & 0xf000)) { *D = dfb_palette_search( gfxs->Alut, (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b, (S->RGB.a & 0xff00) ? 0xff : S->RGB.a ); } ++S; ++D; } } static void Sacc_to_Aop_alut44( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->RGB.a & 0xf000)) { *D = (S->RGB.a & 0xff00) ? 0xf0 : (S->RGB.a & 0xf0) + dfb_palette_search( gfxs->Alut, (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b, 0x80 ); } ++S; ++D; } } static void Sacc_to_Aop_nv12( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } if (gfxs->AopY & 1) { u16 *Duv = gfxs->Aop[1]; w = (gfxs->length >> 1) + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Duv = cb | (cr << 8); } else if (!(S[0].YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Duv = cb | (cr << 8); } else if (!(S[1].YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) >> 1; *Duv = cb | (cr << 8); } S += 2; ++Duv; } } } static void Sacc_to_Aop_nv16( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } w = (gfxs->length >> 1) + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Duv = cb | (cr << 8); } else if (!(S[0].YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Duv = cb | (cr << 8); } else if (!(S[1].YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) >> 1; *Duv = cb | (cr << 8); } S += 2; ++Duv; } } static void Sacc_to_Aop_nv21( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } if (gfxs->AopY & 1) { u16 *Dvu = gfxs->Aop[1]; w = (gfxs->length >> 1) + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Dvu = cr | (cb << 8); } else if (!(S[0].YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Dvu = cr | (cb << 8); } else if (!(S[1].YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) >> 1; *Dvu = cr | (cb << 8); } S += 2; ++Dvu; } } } static void Sacc_to_Aop_ayuv( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { *D = PIXEL_AYUV( (S->YUV.a & 0xff00) ? 0xff : S->YUV.a, (S->YUV.y & 0xff00) ? 0xff : S->YUV.y, (S->YUV.u & 0xff00) ? 0xff : S->YUV.u, (S->YUV.v & 0xff00) ? 0xff : S->YUV.v ); } ++S; ++D; } } static void Sacc_to_Aop_a4( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S[0].RGB.a & 0xf000) && !(S[1].RGB.a & 0xf000)) { *D = ((S[0].RGB.a & 0xff00) ? 0xf0 : (S[0].RGB.a & 0xf0)) | ((S[1].RGB.a & 0xff00) ? 0x0f : (S[1].RGB.a >> 4)); } else if (!(S[0].RGB.a & 0xf000)) { *D = (*D & 0x0f) | ((S[0].RGB.a & 0xff00) ? 0xf0 : (S[0].RGB.a & 0xf0)); } else if (!(S[1].RGB.a & 0xf000)) { *D = (*D & 0xf0) | ((S[1].RGB.a & 0xff00) ? 0x0f : (S[1].RGB.a >> 4)); } S += 2; ++D; } if (gfxs->length & 1) { if (!(S->RGB.a & 0xf000)) *D = (*D & 0x0f) | ((S->RGB.a & 0xff00) ? 0xf0 : (S->RGB.a & 0xf0)); } } static void Sacc_to_Aop_y444( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; *Du = (S->YUV.u & 0xff00) ? 0xff : S->YUV.u; *Dv = (S->YUV.v & 0xff00) ? 0xff : S->YUV.v; } ++S; ++Dy; ++Du; ++Dv; } } static void Sacc_to_Aop_avyu( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { *D = PIXEL_AVYU( (S->YUV.a & 0xff00) ? 0xff : S->YUV.a, (S->YUV.y & 0xff00) ? 0xff : S->YUV.y, (S->YUV.u & 0xff00) ? 0xff : S->YUV.u, (S->YUV.v & 0xff00) ? 0xff : S->YUV.v ); } ++S; ++D; } } static void Sacc_to_Aop_vyu( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->YUV.a & 0xf000)) { u8 y = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; u8 u = (S->YUV.u & 0xff00) ? 0xff : S->YUV.u; u8 v = (S->YUV.v & 0xff00) ? 0xff : S->YUV.v; #ifdef WORDS_BIGENDIAN D[0] = v; D[1] = y; D[2] = u; #else D[0] = u; D[1] = y; D[2] = v; #endif } ++S; D += 3; } } static void Sacc_to_Aop_y42b( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } w = (gfxs->length / 2) + 1; S = gfxs->Sacc; while (--w) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 tmp; tmp = (S[0].YUV.u + S[1].YUV.u) / 2; if (tmp & 0xff00) tmp = 0xff; *Du = tmp; tmp = (S[0].YUV.v + S[1].YUV.v) / 2; if (tmp & 0xff00) tmp = 0xff; *Dv = tmp; } else if (!(S[0].YUV.a & 0xf000)) { *Du = (*Du + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) / 2; *Dv = (*Dv + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) / 2; } else if (!(S[1].YUV.a & 0xf000)) { *Du = (*Du + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) / 2; *Dv = (*Dv + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) / 2; } S += 2; ++Du; ++Dv; } } static void Sacc_to_Aop_nv61( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Dvu = gfxs->Aop[1]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } w = (gfxs->length >> 1) + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Dvu = cr | (cb << 8); } else if (!(S[0].YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Dvu = cr | (cb << 8); } else if (!(S[1].YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S[1].YUV.u & 0xff00) ? 0xff : S[1].YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S[1].YUV.v & 0xff00) ? 0xff : S[1].YUV.v)) >> 1; *Dvu = cr | (cb << 8); } S += 2; ++Dvu; } } static void Sacc_to_Aop_nv24( GenefxState *gfxs ) { int w = gfxs->length+1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } w = gfxs->length + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Duv = cb | (cr << 8); } S++; ++Duv; } } static void Sacc_to_Aop_nv42( GenefxState *gfxs ) { int w = gfxs->length+1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Dvu = gfxs->Aop[1]; while (--w) { if (!(S->YUV.a & 0xf000)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; } ++S; ++Dy; } w = gfxs->length + 1; S = gfxs->Sacc; while (--w) { u32 cb, cr; if (!(S[0].YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S[0].YUV.u & 0xff00) ? 0xff : S[0].YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S[0].YUV.v & 0xff00) ? 0xff : S[0].YUV.v)) >> 1; *Dvu = cr | (cb << 8); } S++; ++Dvu; } } static GenefxFunc Sacc_to_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sacc_to_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sacc_to_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sacc_to_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sacc_to_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sacc_to_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sacc_to_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sacc_to_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sacc_to_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sacc_to_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Sacc_to_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Sacc_to_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sacc_to_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sacc_to_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sacc_to_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sacc_to_Aop_nv12, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sacc_to_Aop_nv16, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sacc_to_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sacc_to_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sacc_to_Aop_rgba4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sacc_to_Aop_nv21, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Sacc_to_Aop_ayuv, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = Sacc_to_Aop_a4, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sacc_to_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sacc_to_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sacc_to_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sacc_to_Aop_xrgb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sacc_to_Aop_xrgb1555, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sacc_to_Aop_xbgr1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sacc_to_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sacc_to_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sacc_to_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sacc_to_Aop_avyu, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sacc_to_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Sacc_to_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sacc_to_Aop_abgr, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sacc_to_Aop_rgbaf88871, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sacc_to_Aop_nv61, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Sacc_to_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sacc_to_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sacc_to_Aop_nv24, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sacc_to_Aop_nv42, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sacc_to_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Sacc_toK_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_toK_Aop_a8( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; while (--w) { if (!(S->RGB.a & 0xf000)) { *D = (S->RGB.a & 0xff00) ? 0xff : S->RGB.a; } ++S; ++D; } } static void Sacc_toK_Aop_yuy2( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; #ifdef WORDS_BIGENDIAN u16 Dkey0 = gfxs->Dkey >> 16; u16 Dkey1 = gfxs->Dkey & 0xffff; #else u16 Dkey0 = gfxs->Dkey & 0xffff; u16 Dkey1 = gfxs->Dkey >> 16; #endif if ((long) D & 2) { if (!(S->YUV.a & 0xf000) && (*D == Dkey1)) { *D = ((S->YUV.y & 0xff00) ? 0x00ff : S->YUV.y) | ((S->YUV.v & 0xff00) ? 0xff00 : (S->YUV.v << 8)); } ++S; ++D; --w; } for (l = w >> 1; l--;) { if (*D == Dkey) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 y0, cb, y1, cr; y0 = (S[0].YUV.y & 0xff00) ? 0xff : S[0].YUV.y; y1 = (S[1].YUV.y & 0xff00) ? 0xff : S[1].YUV.y; cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = y1 | (cr << 8) | (y0 << 16) | (cb << 24); #else *((u32*) D) = y0 | (cb << 8) | (y1 << 16) | (cr << 24); #endif } else if (!(S[0].YUV.a & 0xf000)) { D[0] = ((S[0].YUV.y & 0xff00) ? 0x00ff : S[0].YUV.y) | ((S[0].YUV.u & 0xff00) ? 0xff00 : (S[0].YUV.u << 8)); } else if (!(S[1].YUV.a & 0xf000)) { D[1] = ((S[1].YUV.y & 0xff00) ? 0x00ff : S[1].YUV.y) | ((S[1].YUV.v & 0xff00) ? 0xff00 : (S[1].YUV.v << 8)); } } S += 2; D += 2; } if (w & 1) { if (!(S->YUV.a & 0xf000) && (*D == Dkey0)) { *D = ((S->YUV.y & 0xff00) ? 0x00ff : S->YUV.y) | ((S->YUV.u & 0xff00) ? 0xff00 : (S->YUV.u << 8)); } } } static void Sacc_toK_Aop_rgb332( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; while (--w) { if (!(S->RGB.a & 0xf000) && (*D == Dkey)) { *D = PIXEL_RGB332( (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b ); } ++S; ++D; } } static void Sacc_toK_Aop_uyvy( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; #ifdef WORDS_BIGENDIAN u16 Dkey0 = gfxs->Dkey >> 16; u16 Dkey1 = gfxs->Dkey & 0xffff; #else u16 Dkey0 = gfxs->Dkey & 0xffff; u16 Dkey1 = gfxs->Dkey >> 16; #endif if ((long) D & 2) { if (!(S->YUV.a & 0xf000) && (*D == Dkey1)) { *D = ((S->YUV.v & 0xff00) ? 0x00ff : S->YUV.v) | ((S->YUV.y & 0xff00) ? 0xff00 : (S->YUV.y << 8)); } ++S; ++D; --w; } for (l = w >> 1; l--;) { if (*D == Dkey) { if (!(S[0].YUV.a & 0xf000) && !(S[1].YUV.a & 0xf000)) { u32 cb, y0, cr, y1; y0 = (S[0].YUV.y & 0xff00) ? 0xff : S[0].YUV.y; y1 = (S[1].YUV.y & 0xff00) ? 0xff : S[1].YUV.y; cb = (S[0].YUV.u + S[1].YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S[0].YUV.v + S[1].YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = cr | (y1 << 8) | (cb << 16) | (y0 << 24); #else *((u32*) D) = cb | (y0 << 8) | (cr << 16) | (y1 << 24); #endif } else if (!(S[0].YUV.a & 0xf000)) { D[0] = ((S[0].YUV.u & 0xff00) ? 0x00ff : S[0].YUV.u) | ((S[0].YUV.y & 0xff00) ? 0xff00 : (S[0].YUV.y << 8)); } else if (!(S[1].YUV.a & 0xf000)) { D[1] = ((S[1].YUV.v & 0xff00) ? 0x00ff : S[1].YUV.v) | ((S[1].YUV.y & 0xff00) ? 0xff00 : (S[1].YUV.y << 8)); } } S += 2; D += 2; } if (w & 1) { if (!(S->YUV.a & 0xf000) && (*D == Dkey0)) { *D = ((S->YUV.u & 0xff00) ? 0x00ff : S->YUV.u) | ((S->YUV.y & 0xff00) ? 0xff00 : (S->YUV.y << 8)); } } } static void Sacc_toK_Aop_lut8( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; while (--w) { if (!(S->RGB.a & 0xf000) && (*D == Dkey)) { *D = dfb_palette_search( gfxs->Alut, (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b, (S->RGB.a & 0xff00) ? 0xff : S->RGB.a ); } ++S; ++D; } } static void Sacc_toK_Aop_alut44( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; while (--w) { if (!(S->RGB.a & 0xf000) && ((*D & 0x0f) == Dkey)) { *D = (S->RGB.a & 0xff00) ? 0xf0 : (S->RGB.a & 0xf0) + dfb_palette_search( gfxs->Alut, (S->RGB.r & 0xff00) ? 0xff : S->RGB.r, (S->RGB.g & 0xff00) ? 0xff : S->RGB.g, (S->RGB.b & 0xff00) ? 0xff : S->RGB.b, 0x80 ); } ++S; ++D; } } static void Sacc_toK_Aop_y444( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Dkey = gfxs->Dkey; while (--w) { u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (!(S->YUV.a & 0xf000) && Dkey == (u32) (dy << 16 | du << 8 | dv)) { *Dy = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; *Du = (S->YUV.u & 0xff00) ? 0xff : S->YUV.u; *Dv = (S->YUV.v & 0xff00) ? 0xff : S->YUV.v; } ++S; ++Dy; ++Du; ++Dv; } } static void Sacc_toK_Aop_avyu( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; while (--w) { if (!(S->YUV.a & 0xf000) && (*D & 0x00ffffff) == Dkey) { *D = PIXEL_AVYU( (S->YUV.a & 0xff00) ? 0xff : S->YUV.a, (S->YUV.y & 0xff00) ? 0xff : S->YUV.y, (S->YUV.u & 0xff00) ? 0xff : S->YUV.u, (S->YUV.v & 0xff00) ? 0xff : S->YUV.v ); } ++S; ++D; } } static void Sacc_toK_Aop_vyu( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; while (--w) { #ifdef WORDS_BIGENDIAN u32 d = D[0] << 16 | D[1] << 8 | D[2]; #else u32 d = D[2] << 16 | D[1] << 8 | D[0]; #endif if (!(S->YUV.a & 0xf000) && Dkey == d) { u8 y = (S->YUV.y & 0xff00) ? 0xff : S->YUV.y; u8 u = (S->YUV.u & 0xff00) ? 0xff : S->YUV.u; u8 v = (S->YUV.v & 0xff00) ? 0xff : S->YUV.v; #ifdef WORDS_BIGENDIAN D[0] = v; D[1] = y; D[2] = u; #else D[0] = u; D[1] = y; D[2] = v; #endif } ++S; D += 3; } } static GenefxFunc Sacc_toK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sacc_toK_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sacc_toK_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sacc_toK_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sacc_toK_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sacc_toK_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sacc_toK_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sacc_toK_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sacc_toK_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sacc_toK_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sacc_toK_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sacc_toK_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sacc_toK_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sacc_toK_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sacc_toK_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sacc_toK_Aop_rgba4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sacc_toK_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sacc_toK_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sacc_toK_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sacc_toK_Aop_xrgb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sacc_toK_Aop_xrgb1555, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sacc_toK_Aop_xbgr1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sacc_toK_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sacc_toK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sacc_toK_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sacc_toK_Aop_avyu, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sacc_toK_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sacc_toK_Aop_abgr, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sacc_toK_Aop_rgbaf88871, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sacc_toK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sacc_toK_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Sacc_Sto_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_Sto_Aop_a8( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) *D = (S0->RGB.a & 0xff00) ? 0xff : S0->RGB.a; ++D; i += SperD; } } static void Sacc_Sto_Aop_yuy2( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; int SperD2 = gfxs->SperD << 1; if ((long) D & 2) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.y & 0xff00) ? 0x00ff : S->YUV.y) | ((S->YUV.v & 0xff00) ? 0xff00 : (S->YUV.v << 8)); } ++D; i = SperD; --w; } for (l = w >> 1; l--;) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { u32 y0, cb, y1, cr; y0 = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; y1 = (S1->YUV.y & 0xff00) ? 0xff : S1->YUV.y; cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = y1 | (cr << 8) | (y0 << 16) | (cb << 24); #else *((u32*) D) = y0 | (cb << 8) | (y1 << 16) | (cr << 24); #endif } else if (!(S0->YUV.a & 0xf000)) { D[0] = ((S0->YUV.y & 0xff00) ? 0x00ff : S0->YUV.y) | ((S0->YUV.u & 0xff00) ? 0xff00 : (S0->YUV.u << 8)); } else if (!(S1->YUV.a & 0xf000)) { D[1] = ((S1->YUV.y & 0xff00) ? 0x00ff : S1->YUV.y) | ((S1->YUV.v & 0xff00) ? 0xff00 : (S1->YUV.v << 8)); } D += 2; i += SperD2; } if (w & 1) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf00)) { *D = ((S0->YUV.y & 0xff00) ? 0x00ff : S0->YUV.y) | ((S0->YUV.u & 0xff00) ? 0xff00 : (S0->YUV.u << 8)); } } } static void Sacc_Sto_Aop_rgb332( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) { *D = PIXEL_RGB332( (S0->RGB.r & 0xff00) ? 0xff : S0->RGB.r, (S0->RGB.g & 0xff00) ? 0xff : S0->RGB.g, (S0->RGB.b & 0xff00) ? 0xff : S0->RGB.b ); } ++D; i += SperD; } } static void Sacc_Sto_Aop_uyvy( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; int SperD2 = gfxs->SperD << 1; if ((long) D & 2) { if (!(S->YUV.a & 0xf00)) { *D = ((S->YUV.v & 0xff00) ? 0x00ff : S->YUV.v) | ((S->YUV.y & 0xff00) ? 0xff00 : (S->YUV.y << 8)); } ++D; i = SperD; --w; } for (l = w >> 1; l--;) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { u32 cb, y0, cr, y1; y0 = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; y1 = (S1->YUV.y & 0xff00) ? 0xff : S1->YUV.y; cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; #ifdef WORDS_BIGENDIAN *((u32*) D) = cr | (y1 << 8) | (cb << 16) | (y0 << 24); #else *((u32*) D) = cb | (y0 << 8) | (cr << 16) | (y1 << 24); #endif } else if (!(S0->YUV.a & 0xf000)) { D[0] = ((S0->YUV.u & 0xff00) ? 0x00ff : S0->YUV.u) | ((S0->YUV.y & 0xff00) ? 0xff00 : (S0->YUV.y << 8)); } else if (!(S1->YUV.a & 0xf000)) { D[1] = ((S1->YUV.v & 0xff00) ? 0x00ff : S1->YUV.v) | ((S1->YUV.y & 0xff00) ? 0xff00 : (S1->YUV.y << 8)); } D += 2; i += SperD2; } if (w & 1) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf00)) { *D = ((S0->YUV.u & 0xff00) ? 0x00ff : S0->YUV.u) | ((S0->YUV.y & 0xff00) ? 0xff00 : (S0->YUV.y << 8)); } } } static void Sacc_Sto_Aop_i420( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } if (gfxs->AopY & 1) { u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; i = gfxs->Xphase >> 1; w = (gfxs->length >> 1) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { u32 tmp; tmp = (S0->YUV.u + S1->YUV.u) >> 1; if (tmp & 0xff00) tmp = 0xff; *Du = tmp; tmp = (S0->YUV.v + S1->YUV.v) >> 1; if (tmp & 0xff00) tmp = 0xff; *Dv = tmp; } else if (!(S0->YUV.a & 0xf000)) { *Du = (*Du + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; *Dv = (*Dv + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; } else if (!(S1->YUV.a & 0xf000)) { *Du = (*Du + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) >> 1; *Dv = (*Dv + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) >> 1; } ++Du; ++Dv; i += SperD << 1; } } } static void Sacc_Sto_Aop_lut8( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) { *D = dfb_palette_search( gfxs->Alut, (S0->RGB.r & 0xff00) ? 0xff : S0->RGB.r, (S0->RGB.g & 0xff00) ? 0xff : S0->RGB.g, (S0->RGB.b & 0xff00) ? 0xff : S0->RGB.b, (S0->RGB.a & 0xff00) ? 0xff : S0->RGB.a ); } ++D; i += SperD; } } static void Sacc_Sto_Aop_alut44( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) { *D = (S0->RGB.a & 0xff00) ? 0xf0 : (S0->RGB.a & 0xf0) + dfb_palette_search( gfxs->Alut, (S0->RGB.r & 0xff00) ? 0xff : S0->RGB.r, (S0->RGB.g & 0xff00) ? 0xff : S0->RGB.g, (S0->RGB.b & 0xff00) ? 0xff : S0->RGB.b, 0x80 ); } ++D; i += SperD; } } static void Sacc_Sto_Aop_nv12( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } if (gfxs->AopY & 1) { u16 *Duv = gfxs->Aop[1]; i = gfxs->Xphase >> 1; w = (gfxs->length >> 1) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Duv = cb | (cr << 8); } else if (!(S0->YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Duv = cb | (cr << 8); } else if (!(S1->YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) >> 1; *Duv = cb | (cr << 8); } ++Duv; i += SperD << 1; } } } static void Sacc_Sto_Aop_nv16( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } i = gfxs->Xphase >> 1; w = (gfxs->length >> 1) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Duv = cb | (cr << 8); } else if (!(S0->YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Duv = cb | (cr << 8); } else if (!(S1->YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) >> 1; *Duv = cb | (cr << 8); } ++Duv; i += SperD << 1; } } static void Sacc_Sto_Aop_nv21( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } if (gfxs->AopY & 1) { u16 *Dvu = gfxs->Aop[1]; i = gfxs->Xphase >> 1; w = (gfxs->length >> 1) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Dvu = cr | (cb << 8); } else if (!(S0->YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Dvu = cr | (cb << 8); } else if (!(S1->YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) >> 1; *Dvu = cr | (cb << 8); } ++Dvu; i += SperD << 1; } } } static void Sacc_Sto_Aop_ayuv( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *D = PIXEL_AYUV( (S0->YUV.a & 0xff00) ? 0xff : S0->YUV.a, (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y, (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u, (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v ); } ++D; i += SperD; } } static void Sacc_Sto_Aop_y444( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; *Du = (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u; *Dv = (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v; } ++Dy; ++Du; ++Dv; i += SperD; } } static void Sacc_Sto_Aop_avyu( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *D = PIXEL_AVYU( (S0->YUV.a & 0xff00) ? 0xff : S0->YUV.a, (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y, (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u, (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v ); } ++D; i += SperD; } } static void Sacc_Sto_Aop_vyu( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { u8 y = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; u8 u = (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u; u8 v = (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v; #ifdef WORDS_BIGENDIAN D[0] = v; D[1] = y; D[2] = u; #else D[0] = u; D[1] = y; D[2] = v; #endif } D += 3; i += SperD; } } static void Sacc_Sto_Aop_y42b( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } Dy++; i += SperD; } i = gfxs->Xphase / 2; w = (gfxs->length / 2) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { u32 tmp; tmp = (S0->YUV.u + S1->YUV.u) / 2; if (tmp & 0xff00) tmp = 0xff; *Du = tmp; tmp = (S0->YUV.v + S1->YUV.v) / 2; if (tmp & 0xff00) tmp = 0xff; *Dv = tmp; } else if (!(S0->YUV.a & 0xf000)) { *Du = (*Du + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) / 2; *Dv = (*Dv + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) / 2; } else if (!(S1->YUV.a & 0xf000)) { *Du = (*Du + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) / 2; *Dv = (*Dv + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) / 2; } Du++; Dv++; i += SperD << 1; } } static void Sacc_Sto_Aop_nv61( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Dvu = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } i = gfxs->Xphase >> 1; w = (gfxs->length >> 1) + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000) && !(S1->YUV.a & 0xf000)) { cb = (S0->YUV.u + S1->YUV.u) >> 1; if (cb & 0xff00) cb = 0xff; cr = (S0->YUV.v + S1->YUV.v) >> 1; if (cr & 0xff00) cr = 0xff; *Dvu = cr | (cb << 8); } else if (!(S0->YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Dvu = cr | (cb << 8); } else if (!(S1->YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S1->YUV.u & 0xff00) ? 0xff : S1->YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S1->YUV.v & 0xff00) ? 0xff : S1->YUV.v)) >> 1; *Dvu = cr | (cb << 8); } ++Dvu; i += SperD << 1; } } static void Sacc_Sto_Aop_nv24( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } i = gfxs->Xphase; w = gfxs->length + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000)) { cb = ((*Duv & 0xff) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Duv >> 8) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Duv = cb | (cr << 8); } ++Duv; i += SperD; } } static void Sacc_Sto_Aop_nv42( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u16 *Dvu = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; } ++Dy; i += SperD; } i = gfxs->Xphase; w = gfxs->length + 1; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; u32 cb, cr; if (!(S0->YUV.a & 0xf000)) { cb = ((*Dvu >> 8) + ((S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u)) >> 1; cr = ((*Dvu & 0xff) + ((S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v)) >> 1; *Dvu = cr | (cb << 8); } ++Dvu; i += SperD; } } static GenefxFunc Sacc_Sto_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sacc_Sto_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sacc_Sto_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sacc_Sto_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sacc_Sto_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sacc_Sto_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Sacc_Sto_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Sacc_Sto_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Sacc_Sto_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Sacc_Sto_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Sacc_Sto_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Sacc_Sto_Aop_i420, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Sacc_Sto_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Sacc_Sto_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sacc_Sto_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sacc_Sto_Aop_nv12, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sacc_Sto_Aop_nv16, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sacc_Sto_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sacc_Sto_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sacc_Sto_Aop_rgba4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sacc_Sto_Aop_nv21, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Sacc_Sto_Aop_ayuv, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sacc_Sto_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sacc_Sto_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sacc_Sto_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sacc_Sto_Aop_xrgb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sacc_Sto_Aop_xrgb1555, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sacc_Sto_Aop_xbgr1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sacc_Sto_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sacc_Sto_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sacc_Sto_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sacc_Sto_Aop_avyu, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sacc_Sto_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Sacc_Sto_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sacc_Sto_Aop_abgr, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sacc_Sto_Aop_rgbaf88871, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sacc_Sto_Aop_nv61, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Sacc_Sto_Aop_y42b, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sacc_Sto_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sacc_Sto_Aop_nv24, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sacc_Sto_Aop_nv42, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sacc_Sto_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Sacc_StoK_Aop_PFI ****************************************************************** **********************************************************************************************************************/ static void Sacc_StoK_Aop_y444( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Dkey = gfxs->Dkey; int SperD = gfxs->Xphase; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (!(S0->YUV.a & 0xf000) && Dkey == (u32) (dy << 16 | du << 8 | dv)) { *Dy = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; *Du = (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u; *Dv = (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v; } ++Dy; ++Du; ++Dv; i += SperD; } } static void Sacc_StoK_Aop_avyu( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->YUV.a & 0xf000) && (*D & 0x00ffffff) == Dkey) { *D = PIXEL_AYUV( (S0->YUV.a & 0xff00) ? 0xff : S0->YUV.a, (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y, (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u, (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v ); } ++D; i += SperD; } } static void Sacc_StoK_Aop_vyu( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; #ifdef WORDS_BIGENDIAN u32 d = D[0] << 16 | D[1] << 8 | D[2]; #else u32 d = D[2] << 16 | D[1] << 8 | D[0]; #endif if (!(S0->YUV.a & 0xf000) && Dkey == d) { u8 y = (S0->YUV.y & 0xff00) ? 0xff : S0->YUV.y; u8 u = (S0->YUV.u & 0xff00) ? 0xff : S0->YUV.u; u8 v = (S0->YUV.v & 0xff00) ? 0xff : S0->YUV.v; #ifdef WORDS_BIGENDIAN D[0] = v; D[1] = y; D[2] = u; #else D[0] = u; D[1] = y; D[2] = v; #endif } D += 3; i += SperD; } } static GenefxFunc Sacc_StoK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Sacc_StoK_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sacc_StoK_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Sacc_StoK_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Sacc_StoK_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sacc_StoK_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Sacc_StoK_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Sacc_StoK_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Sacc_StoK_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Sacc_StoK_Aop_rgba4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Sacc_StoK_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Sacc_StoK_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Sacc_StoK_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Sacc_StoK_Aop_xrgb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Sacc_StoK_Aop_xrgb1555, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Sacc_StoK_Aop_xbgr1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Sacc_StoK_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Sacc_StoK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Sacc_StoK_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Sacc_StoK_Aop_avyu, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Sacc_StoK_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Sacc_StoK_Aop_abgr, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Sacc_StoK_Aop_rgbaf88871, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Sacc_StoK_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Sacc_StoK_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Bop_PFI_to_Aop_PFI ***************************************************************** **********************************************************************************************************************/ static void Bop_16_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length * 2 ); } static void Bop_24_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length * 3 ); } static void Bop_32_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length * 4 ); } static void Bop_8_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); } static void Bop_i420_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); if (gfxs->AopY & 1) { direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length >> 1 ); direct_memmove( gfxs->Aop[2], gfxs->Bop[2], gfxs->length >> 1 ); } } static void Bop_nv12_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); if (gfxs->AopY & 1) direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length & ~1 ); } static void Bop_nv16_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length & ~1 ); } static void Bop_4_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length >> 1 ); } static void Bop_y444_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length ); direct_memmove( gfxs->Aop[2], gfxs->Bop[2], gfxs->length ); } static void Bop_y42b_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length / 2 ); direct_memmove( gfxs->Aop[2], gfxs->Bop[2], gfxs->length / 2 ); } static void Bop_nv24_to_Aop( GenefxState *gfxs ) { direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); direct_memmove( gfxs->Aop[1], gfxs->Bop[1], gfxs->length * 2 ); } static GenefxFunc Bop_PFI_to_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_8_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_8_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Bop_i420_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Bop_i420_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_8_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Bop_nv12_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Bop_nv16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Bop_nv12_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = Bop_4_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Bop_y42b_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Bop_nv16_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Bop_y42b_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Bop_nv24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Bop_nv24_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_to_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_toR_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_16_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { *D = *S; ++S; D += Dstep; } } static void Bop_24_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { D[0] = S[0]; D[1] = S[1]; D[2] = S[2]; S += 3; D += Dstep * 3; } } static void Bop_32_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { *D = *S; ++S; D += Dstep; } } static void Bop_8_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { *D = *S; ++S; D += Dstep; } } static void Bop_i420_toR_Aop( GenefxState *gfxs ) { Bop_8_toR_Aop( gfxs ); if (gfxs->AopY & 1) { int w = (gfxs->length >> 1) + 1; u8 *S1 = gfxs->Bop[1]; u8 *S2 = gfxs->Bop[2]; u8 *D1 = gfxs->Aop[1]; u8 *D2 = gfxs->Aop[2]; int Dstep = gfxs->Astep >> 1; while (--w) { *D1 = *S1++; *D2 = *S2++; D1 += Dstep; D2 += Dstep; } } } static void Bop_nv12_toR_Aop( GenefxState *gfxs ) { Bop_8_toR_Aop( gfxs ); if (gfxs->AopY & 1) { int w = (gfxs->length & ~1) + 1; u8 *S = gfxs->Bop[1]; u8 *D = gfxs->Aop[1]; int Dstep = gfxs->Astep; while (--w) { *D = *S++; D += Dstep; } } } static void Bop_nv16_toR_Aop( GenefxState *gfxs ) { int w = (gfxs->length & ~1) + 1; u8 *S = gfxs->Bop[1]; u8 *D = gfxs->Aop[1]; int Dstep = gfxs->Astep; Bop_8_toR_Aop( gfxs ); while (--w) { *D = *S++; D += Dstep; } } static void Bop_4_toR_Aop( GenefxState *gfxs ) { int w = (gfxs->length >> 1) + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { *D = *S; ++S; D += Dstep; } } static void Bop_y444_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; int Dstep = gfxs->Astep; while (--w) { u8 sy = *Sy++; u8 su = *Su++; u8 sv = *Sv++; *Dy = sy; *Du = su; *Dv = sv; Dy += Dstep; Du += Dstep; Dv += Dstep; } } static void Bop_y42b_toR_Aop( GenefxState *gfxs ) { Bop_8_toR_Aop( gfxs ); int w = (gfxs->length / 2) + 1; u8 *S1 = gfxs->Bop[1]; u8 *S2 = gfxs->Bop[2]; u8 *D1 = gfxs->Aop[1]; u8 *D2 = gfxs->Aop[2]; int Dstep = gfxs->Astep / 2; while (--w) { *D1 = *S1++; *D2 = *S2++; D1 += Dstep; D2 += Dstep; } } static void Bop_nv24_toR_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *S = gfxs->Bop[1]; u16 *D = gfxs->Aop[1]; int Dstep = gfxs->Astep; Bop_8_toR_Aop( gfxs ); while (--w) { *D = *S++; D += Dstep; } } static GenefxFunc Bop_PFI_toR_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_8_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_8_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Bop_i420_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Bop_i420_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_8_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Bop_nv12_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Bop_nv16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Bop_nv12_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = Bop_4_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Bop_y42b_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Bop_nv16_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Bop_y42b_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Bop_nv24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Bop_nv24_toR_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_toR_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_toK_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_yuv422_toK_Aop( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } if ((long) D & 2) { #ifdef WORDS_BIGENDIAN if (*D == (Dkey & 0xffff)) *D = *S; #else if (*D == (Dkey >> 16)) *D = *S; #endif S += Ostep; D += Ostep; --w; } if (Ostep < 0) { S--; D--; } for (l = w >> 1; l--;) { if (*D == Dkey) *D = *S; S += Ostep << 1; D += Ostep << 1; } if (w & 1) { #ifdef WORDS_BIGENDIAN if (*D == (Dkey >> 16)) *D = *S; #else if (*D == (Dkey & 0xffff)) *D = *S; #endif } } static void Bop_rgb332_toK_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Dkey = gfxs->Dkey; while (--w) { if (*D == Dkey) { *D = *S; } ++S; ++D; } } static void Bop_y444_toK_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Dkey = gfxs->Dkey; while (--w) { u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (Dkey == (u32) (dy << 16 | du << 8 | dv)) { u8 sy = *Sy; u8 su = *Su; u8 sv = *Sv; *Dy = sy; *Du = su; *Dv = sv; } ++Sy; ++Su; ++Sv; ++Dy; ++Du; ++Dv; } } static void Bop_8_toK_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Dkey = gfxs->Dkey; while (--w) { if (*D == Dkey) { *D = *S; } ++S; ++D; } } static GenefxFunc Bop_PFI_toK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_yuv422_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_rgb332_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_yuv422_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_toK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_toK_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_Kto_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_a8_Kto_Aop( GenefxState *gfxs ) { /* No color to key. */ direct_memmove( gfxs->Aop[0], gfxs->Bop[0], gfxs->length ); } static void Bop_yuv422_Kto_Aop( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } if ((long) D & 2) { u16 s = *S; #ifdef WORDS_BIGENDIAN if (s != (Skey >> 16)) *D = s; #else if (s != (Skey & 0xffff)) *D = s; #endif S += Ostep; D += Ostep; --w; } if (Ostep < 0) { S--; D--; } for (l = w >> 1; l--;) { u32 s = *((u32*) S); if (s != Skey) *((u32*) D) = s; S += Ostep << 1; D += Ostep << 1; } if (w & 1) { u16 s = *S; #ifdef WORDS_BIGENDIAN if (s != (Skey & 0xffff)) *D = s; #else if (s != (Skey >> 16)) *D = s; #endif } } /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 4 ) static void Bop_8_Kto_Aop( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; #define SET_PIXEL(d,s) \ do { \ if (s != Skey) \ d = s; \ } while (0) if (gfxs->Ostep > 0) { SET_PIXEL_DUFFS_DEVICE( D, S, w ); } else { for (i = w - 1; i >= 0; i--) if (S[i] != Skey) D[i] = S[i]; } #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static void Bop_alut44_Kto_Aop( GenefxState *gfxs ) { int w = gfxs->length +1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } while (--w) { u8 s = *S; if ((s & 0x0f) != Skey) *D = s; S += Ostep; D += Ostep; } } static void Bop_y444_Kto_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep; if (Ostep < 0) { int offset = gfxs->length - 1; Sy += offset; Su += offset; Sv += offset; Dy += offset; Du += offset; Dv += offset; } while (--w) { u8 sy = *Sy; u8 su = *Su; u8 sv = *Sv; if (Skey != (u32) (sy << 16 | su << 8 | sv)) { *Dy = sy; *Du = su; *Dv = sv; } Sy += Ostep; Su += Ostep; Sv += Ostep; Dy += Ostep; Du += Ostep; Dv += Ostep; } } static GenefxFunc Bop_PFI_Kto_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_a8_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_yuv422_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_8_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_yuv422_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_alut44_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_Kto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_Kto_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_KtoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_y444_KtoK_Aop( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int Ostep = gfxs->Ostep; if (Ostep < 0) { int offset = gfxs->length - 1; Sy += offset; Su += offset; Sv += offset; Dy += offset; Du += offset; Dv += offset; } while (--w) { u8 sy = *Sy; u8 su = *Su; u8 sv = *Sv; u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (Skey != (u32) (sy << 16 | su << 8 | sv) && Dkey == (u32) (dy << 16 | du << 8 | dv)) { *Dy = sy; *Du = su; *Dv = sv; } ++Sy; ++Su; ++Sv; ++Dy; ++Du; ++Dv; } } static GenefxFunc Bop_PFI_KtoK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_KtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_KtoK_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_Sto_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_16_Sto_Aop( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; int SperD2 = SperD << 1; if (((long) D) & 2) { *(u16*) D = *S; D = gfxs->Aop[0] + 2; i += SperD; --w; } l = w >> 1; while (l--) { #ifdef WORDS_BIGENDIAN *D++ = S[i>>16] << 16 | S[(i+SperD)>>16]; #else *D++ = (S[(i+SperD)>>16] << 16) | S[i>>16]; #endif i += SperD2; } if (w & 1) { *(u16*) D = S[i>>16]; } } static void Bop_24_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { int pixelstart = (i >> 16) * 3; *D++ = S[pixelstart+0]; *D++ = S[pixelstart+1]; *D++ = S[pixelstart+2]; i += SperD; } } static void Bop_32_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { *D++ = S[i>>16]; i += SperD; } } static void Bop_8_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { *D++ = S[i>>16]; i += SperD; } } static void Bop_yuy2_Sto_Aop( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; if ((long) D & 2) { *D++ = *S; i = SperD; --w; } for (l = w >> 1; l--;) { u32 d; d = ((u32*) S)[i>>17] & 0xff00ff00; #ifdef WORDS_BIGENDIAN d |= (S[i>>16] & 0x00ff) << 16; d |= S[(i+SperD)>>16] & 0x00ff; #else d |= S[i>>16] & 0x00ff; d |= (S[(i+SperD)>>16] & 0x00ff) << 16; #endif *((u32*) D) = d; D += 2; i += SperD << 1; } if (w & 1) *D = S[i>>16]; } static void Bop_uyvy_Sto_Aop( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; if ((long) D & 2) { *D++ = *S; i = SperD; --w; } for (l = w >> 1; l--;) { u32 d; d = ((u32*) S)[i>>17] & 0x00ff00ff; #ifdef WORDS_BIGENDIAN d |= (S[i>>16] & 0xff00) << 16; d |= (S[(i+SperD)>>16] & 0xff00); #else d |= (S[i>>16] & 0xff00); d |= (S[(i+SperD)>>16] & 0xff00) << 16; #endif *((u32*) D) = d; D += 2; i += SperD << 1; } if (w & 1) *D = S[i>>16]; } static void Bop_i420_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Dy = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { *Dy++ = Sy[i>>16]; i += SperD; } if (gfxs->AopY & 1) { u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; for (w = gfxs->length >> 1, i = 0; w--;) { *Du++ = Su[i>>16]; i += SperD; } for (w = gfxs->length >> 1, i = 0; w--;) { *Dv++ = Sv[i>>16]; i += SperD; } } } static void Bop_nv12_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length +1; u8 *Sy = gfxs->Bop[0]; u8 *Dy = gfxs->Aop[0]; int SperD = gfxs->SperD; while (--w) { *Dy++ = Sy[i>>16]; i += SperD; } if (gfxs->AopY & 1) { u16 *Suv = gfxs->Bop[1]; u16 *Duv = gfxs->Aop[1]; for (w = gfxs->length >> 1, i = 0; w--;) { *Duv++ = Suv[i>>16]; i += SperD; } } } static void Bop_nv16_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length +1; u8 *Sy = gfxs->Bop[0]; u16 *Suv = gfxs->Bop[1]; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { *Dy++ = Sy[i>>16]; i += SperD; } for (w = gfxs->length >> 1, i = 0; w--;) { *Duv++ = Suv[i>>16]; i += SperD; } } static void Bop_y444_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; int SperD = gfxs->SperD; while (--w) { u8 sy = Sy[i>>16]; u8 su = Su[i>>16]; u8 sv = Sv[i>>16]; *Dy++ = sy; *Du++ = su; *Dv++ = sv; i += SperD; } } static void Bop_y42b_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; int SperD = gfxs->SperD; while (--w) { *Dy++ = Sy[i>>16]; i += SperD; } i = 0; w = (gfxs->length / 2) + 1; while (--w) { *Du++ = Su[i>>16]; *Dv++ = Sv[i>>16]; i += SperD; } } static void Bop_nv24_Sto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u16 *Suv = gfxs->Bop[1]; u8 *Dy = gfxs->Aop[0]; u16 *Duv = gfxs->Aop[1]; int SperD = gfxs->SperD; while (--w) { *Dy++ = Sy[i>>16]; *Duv++ = Suv[i>>16]; i += SperD; } } static GenefxFunc Bop_PFI_Sto_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_8_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_yuy2_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_8_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_uyvy_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = Bop_i420_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = Bop_i420_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_8_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Bop_nv12_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Bop_nv16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Bop_nv12_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = Bop_y42b_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Bop_nv16_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = Bop_y42b_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Bop_nv24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Bop_nv24_Sto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_Sto_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_SKto_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_a8_SKto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int SperD = gfxs->SperD; /* No color to key. */ while (--w) { *D++ = S[i>>16]; i += SperD; } } static void Bop_yuy2_SKto_Aop( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; #ifdef WORDS_BIGENDIAN u16 Skey0 = gfxs->Skey >> 16; u16 Skey1 = gfxs->Skey & 0xffff; #else u16 Skey0 = gfxs->Skey & 0xffff; u16 Skey1 = gfxs->Skey >> 16; #endif int SperD = gfxs->SperD; if ((long) D & 2) { u16 s = *S; if (s != Skey0) *D = s; ++D; i = SperD; --w; } for (l = w >> 1; l--;) { u32 s; s = ((u32*) S)[i>>17] & 0xff00ff00; #ifdef WORDS_BIGENDIAN s |= (S[i>>16] & 0x00ff) << 16; s |= S[(i+SperD)>>16] & 0x00ff; #else s |= S[i>>16] & 0x00ff; s |= (S[(i+SperD)>>16] & 0x00ff) << 16; #endif if (s != Skey) *((u32*) D) = s; D += 2; i += SperD << 1; } if (w & 1) { u16 s = S[i>>16]; if (i & 0x20000) { if (s != Skey1) *D = s; } else { if (s != Skey0) *D = s; } } } static void Bop_8_SKto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u8 s = S[i>>16]; if (s != Skey) *D = s; ++D; i += SperD; } } static void Bop_uyvy_SKto_Aop( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; #ifdef WORDS_BIGENDIAN u16 Skey0 = gfxs->Skey >> 16; u16 Skey1 = gfxs->Skey & 0xffff; #else u16 Skey0 = gfxs->Skey & 0xffff; u16 Skey1 = gfxs->Skey >> 16; #endif int SperD = gfxs->SperD; if ((long) D & 2) { u16 s = *S; if (s != Skey0) *D = s; ++D; i = SperD; --w; } for (l = w >> 1; l--;) { u32 s; s = ((u32*) S)[i>>17] & 0x00ff00ff; #ifdef WORDS_BIGENDIAN s |= (S[i>>16] & 0xff00) << 16; s |= (S[(i+SperD)>>16] & 0xff00); #else s |= (S[i>>16] & 0xff00); s |= (S[(i+SperD)>>16] & 0xff00) << 16; #endif if (s != Skey) *((u32*) D) = s; D += 2; i += SperD << 1; } if (w & 1) { u16 s = S[i>>16]; if (i & 0x20000) { if (s != Skey1) *D = s; } else { if (s != Skey0) *D = s; } } } static void Bop_alut44_SKto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u8 s = S[i>>16]; if ((s & 0x0f) != Skey) *D = s; ++D; i += SperD; } } static void Bop_y444_SKto_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u8 sy = Sy[i>>16]; u8 su = Su[i>>16]; u8 sv = Sv[i>>16]; if (Skey != (u32) (sy << 16 | su << 8 | sv)) { *Dy = sy; *Du = su; *Dv = sv; } ++Dy; ++Du; ++Dv; i += SperD; } } static GenefxFunc Bop_PFI_SKto_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_a8_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_yuy2_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_8_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_uyvy_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_8_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_alut44_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_SKto_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_SKto_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_StoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_y444_StoK_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (Dkey == (u32) (dy << 16 | du << 8 | dv)) { u8 sy = Sy[i>>16]; u8 su = Su[i>>16]; u8 sv = Sv[i>>16]; *Dy = sy; *Du = su; *Dv = sv; } ++Dy; ++Du; ++Dv; i += SperD; } } static GenefxFunc Bop_PFI_StoK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_StoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_StoK_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_SKtoK_Aop_PFI ************************************************************** **********************************************************************************************************************/ static void Bop_y444_SKtoK_Aop( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *Sy = gfxs->Bop[0]; u8 *Su = gfxs->Bop[1]; u8 *Sv = gfxs->Bop[2]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { u8 sy = Sy[i>>16]; u8 su = Su[i>>16]; u8 sv = Sv[i>>16]; u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; if (Skey != (u32) (sy << 16 | su << 8 | sv) && Dkey == (u32) (dy << 16 | du << 8 | dv)) { *Dy = sy; *Du = su; *Dv = sv; } ++Dy; ++Du; ++Dv; i += SperD; } } static GenefxFunc Bop_PFI_SKtoK_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_15_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_16_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_24_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_14_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_12_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_12vv_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_18_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_18_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_18_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = Bop_12_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = Bop_15_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = Bop_15_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_15_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_y444_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_16_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_24_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_24_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_y444_SKtoK_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_24_SKtoK_Aop, }; /********************************************************************************************************************** ********************************* Bop_PFI_TEX_to_Aop_PFI ************************************************************* **********************************************************************************************************************/ static void Bop_24_TEX_to_Aop( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; int sp3 = gfxs->src_pitch / 3; int SperD = gfxs->SperD; int TperD = gfxs->TperD; while (--w) { int pixelstart = ((s >> 16) + (t >> 16) * sp3) * 3; *D++ = S[pixelstart++]; *D++ = S[pixelstart++]; *D++ = S[pixelstart]; s += SperD; t += TperD; } } static void Bop_32_TEX_to_Aop( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; int sp4 = gfxs->src_pitch / 4; int SperD = gfxs->SperD; int TperD = gfxs->TperD; while (--w) { *D++ = S[(s>>16)+(t>>16)*sp4]; s += SperD; t += TperD; } } static GenefxFunc Bop_PFI_TEX_to_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_24_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = Bop_32_TEX_to_Aop, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_24_TEX_to_Aop, }; /********************************************************************************************************************** ********************************* Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI ************************************* **********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 3 ) static void Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb16( GenefxState *gfxs ) { int w = gfxs->length; u32 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; #define SET_PIXEL(d,s) \ switch (s >> 26) { \ case 0: \ break; \ case 0x3f: \ d = ARGB_TO_RGB16( s ); \ break; \ default: \ d = (((((((s >> 8) & 0xf800) | ((s >> 3) & 0x001f)) - (d & 0xf81f)) * ((s >> 26) + 1) + \ ((d & 0xf81f) << 6) ) & 0x003e07c0) + \ (((( (s >> 5) & 0x07e0) - (d & 0x07e0)) * ((s >> 26) + 1) + \ ((d & 0x07e0) << 6) ) & 0x0001f800) \ ) >> 6; \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static void Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb32( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { u32 dp32 = *D; u32 sp32 = *S++; int salpha = (sp32 >> 25) + 1; #define rb (sp32 & 0xff00ff) #define g (sp32 & 0x00ff00) *D = ((((rb - (dp32 & 0xff00ff)) * salpha + ((dp32 & 0xff00ff) << 7)) & 0x7f807f80) + ((( g - (dp32 & 0x00ff00)) * salpha + ((dp32 & 0x00ff00) << 7)) & 0x007f8000)) >> 7; D += Dstep; #undef rb #undef g } } static void Bop_argb_blend_alphachannel_src_invsrc_Aop_argb8565( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; while (--w) { #ifdef WORDS_BIGENDIAN u16 dp16 = D[1] << 8 | D[2]; #else u16 dp16 = D[1] << 8 | D[0]; #endif u32 sp32 = *S++; int salpha = (sp32 >> 26) + 1; #define srb (((sp32 >> 8) & 0xf800) | ((sp32 >> 3) & 0x001f)) #define sg ((sp32 >> 5) & 0x07e0) #define drb (dp16 & 0xf81f) #define dg (dp16 & 0x07e0) dp16 = ((((srb - drb) * salpha + (drb << 6)) & 0x003e07c0) + ((( sg - dg) * salpha + ( dg << 6)) & 0x0001f800)) >> 6; #ifdef WORDS_BIGENDIAN D[0] = 0; D[1] = (dp16 >> 8) & 0xff; D[2] = dp16 & 0xff; #else D[0] = dp16 & 0xff; D[1] = (dp16 >> 8) & 0xff; D[2] = 0; #endif D += 3; #undef dg #undef drb #undef sg #undef srb } } static GenefxFunc Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_argb_blend_alphachannel_src_invsrc_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Bop_argb_blend_alphachannel_one_invsrc_Aop_argb ************************************ **********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 3 ) static void Bop_argb_blend_alphachannel_one_invsrc_Aop_argb( GenefxState *gfxs ) { int w = gfxs->length; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; #define SET_PIXEL(d,s) \ switch (s >> 24) { \ case 0: \ d += s; \ break; \ case 0xff: \ d = s; \ break; \ default: { \ int invsrc = 256 - (s >> 24); \ u32 Drb = ((d & 0x00ff00ff) * invsrc) >> 8; \ u32 Dag = ((d & 0xff00ff00) >> 8) * invsrc; \ d = s + (Drb & 0x00ff00ff) + (Dag & 0xff00ff00); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static GenefxFunc Bop_argb_blend_alphachannel_one_invsrc_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_argb_blend_alphachannel_one_invsrc_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_argb_blend_alphachannel_one_invsrc_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_PFI ************************* **********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 3 ) static void Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_argb( GenefxState *gfxs ) { int w = gfxs->length; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; #define SET_PIXEL(d,s) \ switch (s >> 24) { \ case 0: \ break; \ case 0xff: \ d = s; \ break; \ default: { \ int src = (s >> 24) + 1; \ int invsrc = 256 - (s >> 24); \ u32 Drb = ((d & 0x00ff00ff) * invsrc) >> 8; \ u32 Dag = ((d & 0xff00ff00) >> 8) * invsrc; \ u32 Srb = ((s & 0x00ff00ff) * src) >> 8; \ u32 Sxg = ((s & 0xff00ff00) >> 8) * src; \ d = (Srb & 0x00ff00ff) + (Sxg & 0x0000ff00) + \ (Drb & 0x00ff00ff) + (Dag & 0xff00ff00) + \ ( s & 0xff000000); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static GenefxFunc Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Bop_a8_set_alphapixel_Aop_PFI ****************************************************** **********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 3 ) static void Bop_a8_set_alphapixel_Aop_argb1555( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0x7c1f; u32 g = Cop & 0x03e0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 3) + 1; \ u32 t1 = d & 0x7c1f; \ u32 t2 = d & 0x03e0; \ d = (d & 0x8000) | \ ((s & 0x80) << 8) | \ ((((rb - t1) * a + (t1 << 5)) & 0x000f83e0) + (((g - t2) * a + (t2 << 5)) & 0x00007c00)) >> 5; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgb16( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0xf81f; u32 g = Cop & 0x07e0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 2) + 1; \ u32 t1 = d & 0xf81f; \ u32 t2 = d & 0x07e0; \ d = ((((rb - t1) * a + (t1 << 6)) & 0x003e07c0) + (((g - t2) * a + (t2 << 6)) & 0x0001f800)) >> 6; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgb24( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; #define SET_PIXEL(D,r,g,b,s) \ switch (s) { \ case 0xff: \ D[0] = b; \ D[1] = g; \ D[2] = r; \ case 0: break; \ default: { \ u16 a = s + 1; \ D[0] = ((b - D[0]) * a + (D[0] << 8)) >> 8; \ D[1] = ((g - D[1]) * a + (D[1] << 8)) >> 8; \ D[2] = ((r - D[2]) * a + (D[2] << 8)) >> 8; \ } \ } while (w > 4) { SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; w -= 4; } while (w--) { SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; } #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgb32( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0xff00ff; u32 g = Cop & 0x00ff00; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 t1 = d & 0x00ff00ff; \ u32 t2 = d & 0x0000ff00; \ d = ((((rb - t1) * a + (t1 << 8)) & 0xff00ff00) + (((g - t2) * a + (t2 << 8)) & 0x00ff0000)) >> 8; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_argb( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop | 0xff000000; u32 rb = Cop & 0x00ff00ff; u32 g = gfxs->color.g; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 a1 = 256 - s; \ u32 sa = (((d >> 24) * a1) >> 8) + s; \ d = (sa << 24) + \ (((((d & 0x00ff00ff) * a1) + (rb * a)) >> 8) & 0x00ff00ff) + \ (((((d & 0x0000ff00) >> 8) * a1) + ( g * a)) & 0x0000ff00); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_a8( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = 0xff; \ case 0: break; \ default: { \ u16 a1 = 255 - s; \ d = ((d * a1) >> 8) + s; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_yuy2( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 y = gfxs->YCop; u32 u = gfxs->CbCop; u32 v = gfxs->CrCop; #ifdef WORDS_BIGENDIAN u16 Cop0 = u | (y << 8); u16 Cop1 = v | (y << 8); #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: \ d = ((long) &(d) & 2) ? Cop1 : Cop0; \ case 0x00: break; \ default: { \ u32 a = s + 1; \ u32 t1 = d & 0xff; \ u32 t2 = d >> 8; \ if ((long) &(d) & 2) \ d = (((v - t1) * a + (t1 << 8)) >> 8) | (((y - t2) * a + (t2 << 8)) & 0xff00); \ else \ d = (((u - t1) * a + (t1 << 8)) >> 8) | (((y - t2) * a + (t2 << 8)) & 0xff00); \ } \ } #else u16 Cop0 = y | (u << 8); u16 Cop1 = y | (v << 8); #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: \ d = ((long) &(d) & 2) ? Cop1 : Cop0; \ case 0x00: break; \ default: { \ u32 a = s + 1; \ u32 t1 = d & 0xff; \ u32 t2 = d >> 8; \ if ((long) &(d) & 2) \ d = (((y - t1) * a + (t1 << 8)) >> 8) | (((v - t2) * a + (t2 << 8)) & 0xff00); \ else \ d = (((y - t1) * a + (t1 << 8)) >> 8) | (((u - t2) * a + (t2 << 8)) & 0xff00); \ } \ } #endif SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgb332( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rgb = ((Cop & 0xe0) << 16) | ((Cop & 0x1c) << 8) | (Cop & 0x03); #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 t = ((d & 0xe0) << 16) | ((d & 0x1c) << 8) | (d & 0x03); \ u32 c = ((rgb - t) * a + (t << 8)) & 0xe01c0300; \ d = (c >> 24) | ((c >> 16) & 0xff) | ((c >> 8) & 0xff); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_uyvy( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 y = gfxs->YCop; u32 u = gfxs->CbCop; u32 v = gfxs->CrCop; u16 Cop0 = u | (y << 8); u16 Cop1 = v | (y << 8); #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = ((long) &(d) & 2) ? Cop1 : Cop0; \ case 0x00: break; \ default: { \ u32 a = s + 1; \ u32 t1 = d & 0xff; \ u32 t2 = d >> 8; \ if ((long) &(d) & 2) \ d = (((v - t1) * a + (t1 << 8)) >> 8) | (((y - t2) * a + (t2 << 8)) & 0xff00); \ else \ d = (((u - t1) * a + (t1 << 8)) >> 8) | (((y - t2) * a + (t2 << 8)) & 0xff00); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_lut8( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; #define SET_PIXEL(d,s) \ if (s & 0x80) \ d = Cop; SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_alut44( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; DFBColor color = gfxs->color; DFBColor *entries = gfxs->Alut->entries; while (--w) { u16 s = *S; switch (s) { case 0xff: *D = Cop; case 0: break; default: { u16 a = s + 1; u8 d = *D; DFBColor dc = entries[d&0x0f]; u16 sa = (d & 0xf0) + s; dc.r = ((color.r - dc.r) * a + (dc.r << 8)) >> 8; dc.g = ((color.g - dc.g) * a + (dc.g << 8)) >> 8; dc.b = ((color.b - dc.b) * a + (dc.b << 8)) >> 8; if (sa & 0xff00) sa = 0xf0; *D = (sa & 0xf0) + dfb_palette_search( gfxs->Alut, dc.r, dc.g, dc.b, 0x80 ); } } ++S; ++D; } } static void Bop_a8_set_alphapixel_Aop_airgb( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0x00ff00ff; u32 g = gfxs->color.g; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 a1 = 256 - a; \ s32 sa = (d >> 24) - s; \ if (sa < 0) sa = 0; \ d = (sa << 24) + \ (((((d & 0x00ff00ff) * a1) + (rb * a)) >> 8) & 0x00ff00ff) + \ (((((d & 0x0000ff00) >> 8) * a1) + ( g * a)) & 0x0000ff00); \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_argb1666( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0x3f03f; u32 g = Cop & 0xfc0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 2) + 1; \ u32 t1 = d & 0x3f03f; \ u32 t2 = d & 0x00fc0; \ d = (d & 0x40000) | \ ((s & 0x80) << 11) | \ ((((rb - t1) * a + (t1 << 6)) & 0x00fc0fc0) + (((g - t2) * a + (t2 << 6)) & 0x0003f000)) >> 6; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_argb6666( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0x3f03f; u32 g = Cop & 0xfc0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 2) + 1; \ u32 t1 = d & 0x3f03f; \ u32 t2 = d & 0x00fc0; \ d = (d & 0xfc0000) | \ ((s & 0xfc) << 16) | \ ((((rb - t1) * a + (t1 << 6)) & 0x00fc0fc0) + (((g - t2) * a + (t2 << 6)) & 0x0003f000)) >> 6; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgb18( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0x3f03f; u32 g = Cop & 0xfc0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 2) + 1; \ u32 t1 = d & 0x3f03f; \ u32 t2 = d & 0x00fc0; \ d = ((((rb - t1) * a + (t1 << 6)) & 0x00fc0fc0) + (((g - t2) * a + (t2 << 6)) & 0x000fc000)) >> 6; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_rgba5551( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 rb = Cop & 0xf83e; u32 g = Cop & 0x07c0; #define SET_PIXEL(d,s) \ switch (s) { \ case 0xff: d = Cop; \ case 0: break; \ default: { \ u32 a = (s >> 3) + 1; \ u32 t1 = d & 0xf83e; \ u32 t2 = d & 0x07c0; \ d = (d & 0x0001) | \ ((s & 0x80) >> 7) | \ ((((rb - t1) * a + (t1 << 4)) & 0x000f83e0) + (((g - t2) * a + (t2 << 4)) & 0x00007c00)) >> 4; \ } \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_y444( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; u8 YCop = gfxs->YCop; u8 CbCop = gfxs->CbCop; u8 CrCop = gfxs->CrCop; while (--w) { u16 s = *S; switch (s) { case 0xff: *Dy = YCop; *Du = CbCop; *Dv = CrCop; case 0: break; default: { u16 a = s + 1; u8 dy = *Dy; u8 du = *Du; u8 dv = *Dv; *Dy = ((YCop - dy) * a + (dy << 8)) >> 8; *Du = ((CbCop - du) * a + (du << 8)) >> 8; *Dv = ((CrCop - dv) * a + (dv << 8)) >> 8; } } ++S; ++Dy; ++Du; ++Dv; } } static void Bop_a8_set_alphapixel_Aop_argb8565( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop | 0xff0000; u32 srb = Cop & 0xf81f; u32 sg = Cop & 0x07e0; #ifdef WORDS_BIGENDIAN #define SET_PIXEL(D,s) \ switch (s) { \ case 0xff: \ D[0] = (Cop >> 16) & 0xff; \ D[1] = (Cop >> 8) & 0xff; \ D[2] = Cop & 0xff; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 a1 = 256 - s; \ u16 d16 = D[1] << 8 | D[2]; \ u32 t1 = (d16 & 0xf81f); \ u32 t2 = (d16 & 0x07e0); \ D[0] = ((D[0] * a1) >> 8) + s; \ d16 = ((((srb - t1) * a + (t1 << 8)) & 0x00f81f00) + (((sg - t2) * a + (t2 << 8)) & 0x0007e000)) >> 8; \ D[1] = (d16 >> 8) & 0xff; \ D[2] = d16 & 0xff; \ } \ } #else #define SET_PIXEL(D,s) \ switch (s) { \ case 0xff: \ D[0] = Cop & 0xff; \ D[1] = (Cop >> 8) & 0xff; \ D[2] = (Cop >> 16) & 0xff; \ case 0: break; \ default: { \ u32 a = s + 1; \ u32 a1 = 256 - s; \ u16 d16 = D[1] << 8 | D[0]; \ u32 t1 = (d16 & 0xf81f); \ u32 t2 = (d16 & 0x07e0); \ D[2] = ((D[2] * a1) >> 8) + s; \ d16 = ((((srb - t1) * a + (t1 << 8)) & 0x00f81f00) + (((sg - t2) * a + (t2 << 8)) & 0x0007e000)) >> 8; \ D[1] = (d16 >> 8) & 0xff; \ D[0] = d16 & 0xff; \ } \ } #endif while (w > 4) { SET_PIXEL( D, *S ); D += 3; ++S; SET_PIXEL( D, *S ); D += 3; ++S; SET_PIXEL( D, *S ); D += 3; ++S; SET_PIXEL( D, *S ); D += 3; ++S; w -= 4; } while (w--) { SET_PIXEL( D, *S ); D += 3; ++S; } #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_vyu( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 YCop = gfxs->YCop; u8 CbCop = gfxs->CbCop; u8 CrCop = gfxs->CrCop; #ifdef WORDS_BIGENDIAN #define SET_PIXEL(D,y,cb,cr,s) \ switch (s) { \ case 0xff: \ D[0] = cr; \ D[1] = y; \ D[2] = cb; \ case 0: break; \ default: { \ u16 a = s + 1; \ D[0] = ((cr - D[0]) * a + (D[0] << 8)) >> 8; \ D[1] = ((y - D[1]) * a + (D[1] << 8)) >> 8; \ D[2] = ((cb - D[2]) * a + (D[2] << 8)) >> 8; \ } \ } #else #define SET_PIXEL(D,y,cb,cr,s) \ switch (s) { \ case 0xff: \ D[0] = cb; \ D[1] = y; \ D[2] = cr; \ case 0: break; \ default: { \ u16 a = s + 1; \ D[0] = ((cb - D[0]) * a + (D[0] << 8)) >> 8; \ D[1] = ((y - D[1]) * a + (D[1] << 8)) >> 8; \ D[2] = ((cr - D[2]) * a + (D[2] << 8)) >> 8; \ } \ } #endif while (w > 4) { SET_PIXEL( D, YCop, CbCop, CrCop, *S ); D += 3; ++S; SET_PIXEL( D, YCop, CbCop, CrCop, *S ); D += 3; ++S; SET_PIXEL( D, YCop, CbCop, CrCop, *S ); D += 3; ++S; SET_PIXEL( D, YCop, CbCop, CrCop, *S ); D += 3; ++S; w -= 4; } while (w--) { SET_PIXEL( D, YCop, CbCop, CrCop, *S ); D += 3; ++S; } #undef SET_PIXEL } static void Bop_a8_set_alphapixel_Aop_bgr24( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; #define SET_PIXEL(D,r,g,b,s) \ switch (s) { \ case 0xff: \ D[0] = r; \ D[1] = g; \ D[2] = b; \ case 0: break; \ default: { \ u16 a = s + 1; \ D[0] = ((r - D[0]) * a + (D[0] << 8)) >> 8; \ D[1] = ((g - D[1]) * a + (D[1] << 8)) >> 8; \ D[2] = ((b - D[2]) * a + (D[2] << 8)) >> 8; \ } \ } while (w > 4) { SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3; ++S; w -= 4; } while (w--) { SET_PIXEL( D, color.r, color.g, color.b, *S ); D += 3, ++S; } #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static GenefxFunc Bop_a8_set_alphapixel_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_a8_set_alphapixel_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_a8_set_alphapixel_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_a8_set_alphapixel_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_a8_set_alphapixel_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_a8_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_a8_set_alphapixel_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_a8_set_alphapixel_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_a8_set_alphapixel_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_a8_set_alphapixel_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_a8_set_alphapixel_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_a8_set_alphapixel_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_a8_set_alphapixel_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_a8_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_a8_set_alphapixel_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_a8_set_alphapixel_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_a8_set_alphapixel_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_a8_set_alphapixel_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_a8_set_alphapixel_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_a8_set_alphapixel_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_a8_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = Bop_a8_set_alphapixel_Aop_vyu, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_a8_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_a8_set_alphapixel_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_a8_set_alphapixel_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Bop_a1_set_alphapixel_Aop_PFI ****************************************************** **********************************************************************************************************************/ static void Bop_a1_set_alphapixel_Aop_argb1555( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0x8000; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_rgb16( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_rgb24( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[0] = color.b; D[1] = color.g; D[2] = color.r; } D += 3; } } static void Bop_a1_set_alphapixel_Aop_rgb32( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_argb( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop | 0xff000000; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_a8( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = 0xff; } } } static void Bop_a1_set_alphapixel_Aop_yuy2( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop0 = gfxs->YCop | (gfxs->CbCop << 8); u16 Cop1 = gfxs->YCop | (gfxs->CrCop << 8); for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = ((long) &D[i] & 2) ? Cop1 : Cop0; } } } static void Bop_a1_set_alphapixel_Aop_rgb332( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_uyvy( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop0 = gfxs->CbCop | (gfxs->YCop << 8); u16 Cop1 = gfxs->CrCop | (gfxs->YCop << 8); for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = ((long) &D[i] & 2) ? Cop1 : Cop0; } } } static void Bop_a1_set_alphapixel_Aop_lut8( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_alut44( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_airgb( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop & 0x00ffffff; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_argb2554( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0xc000; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_argb4444( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0xf000; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_rgba4444( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0x000f; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_argb1666( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { u32 pixel = PIXEL_ARGB1666( color.a, color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_set_alphapixel_Aop_argb6666( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { u32 pixel = PIXEL_ARGB6666( color.a, color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_set_alphapixel_Aop_rgb18( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { u32 pixel = PIXEL_RGB18( color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_set_alphapixel_Aop_rgba5551( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0x0001; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[i] = Cop; } } } static void Bop_a1_set_alphapixel_Aop_y444( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *Dy = gfxs->Aop[0]; u8 *Du = gfxs->Aop[1]; u8 *Dv = gfxs->Aop[2]; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { Dy[i] = gfxs->YCop; Du[i] = gfxs->CbCop; Dv[i] = gfxs->CrCop; } } } static void Bop_a1_set_alphapixel_Aop_argb8565( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop | 0xff0000; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { #ifdef WORDS_BIGENDIAN D[0] = (Cop >> 16) & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = Cop & 0xff; #else D[0] = Cop & 0xff; D[1] = (Cop >> 8) & 0xff; D[2] = (Cop >> 16) & 0xff; #endif } D += 3; } } static void Bop_a1_set_alphapixel_Aop_bgr24( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (0x80 >> (i & 7))) { D[0] = color.r; D[1] = color.g; D[2] = color.b; } D += 3; } } static GenefxFunc Bop_a1_set_alphapixel_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_a1_set_alphapixel_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_a1_set_alphapixel_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_a1_set_alphapixel_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_a1_set_alphapixel_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_a1_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_a1_set_alphapixel_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_a1_set_alphapixel_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_a1_set_alphapixel_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_a1_set_alphapixel_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_a1_set_alphapixel_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_a1_set_alphapixel_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_a1_set_alphapixel_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_a1_set_alphapixel_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_a1_set_alphapixel_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = Bop_a1_set_alphapixel_Aop_rgba4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_a1_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_a1_set_alphapixel_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_a1_set_alphapixel_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_a1_set_alphapixel_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = Bop_a1_set_alphapixel_Aop_rgba5551, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = Bop_a1_set_alphapixel_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = Bop_a1_set_alphapixel_Aop_argb8565, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = Bop_a1_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_a1_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = Bop_a1_set_alphapixel_Aop_y444, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_a1_set_alphapixel_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Bop_a1_lsb_set_alphapixel_Aop_PFI ************************************************** **********************************************************************************************************************/ static void Bop_a1_lsb_set_alphapixel_Aop_argb1555( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0x8000; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_rgb16( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_rgb24( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[0] = color.b; D[1] = color.g; D[2] = color.r; } D += 3; } } static void Bop_a1_lsb_set_alphapixel_Aop_rgb32( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_argb( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop | 0xff000000; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_a8( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = 0xff; } } } static void Bop_a1_lsb_set_alphapixel_Aop_yuy2( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop0 = gfxs->YCop | (gfxs->CbCop << 8); u16 Cop1 = gfxs->YCop | (gfxs->CrCop << 8); for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = ((long) &D[i] & 2) ? Cop1 : Cop0; } } } static void Bop_a1_lsb_set_alphapixel_Aop_rgb332( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_uyvy( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop0 = gfxs->CbCop | (gfxs->YCop << 8); u16 Cop1 = gfxs->CrCop | (gfxs->YCop << 8); for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = ((long) &D[i] & 2) ? Cop1 : Cop0; } } } static void Bop_a1_lsb_set_alphapixel_Aop_lut8( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_alut44( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u8 Cop = gfxs->Cop; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_airgb( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop & 0x00ffffff; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_argb2554( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0xc000; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_argb4444( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop | 0xf000; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[i] = Cop; } } } static void Bop_a1_lsb_set_alphapixel_Aop_argb1666( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { u32 pixel = PIXEL_ARGB1666( color.a, color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_lsb_set_alphapixel_Aop_argb6666( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { u32 pixel = PIXEL_ARGB6666( color.a, color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_lsb_set_alphapixel_Aop_rgb18( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { u32 pixel = PIXEL_RGB18( color.r, color.g, color.b ); D[0] = pixel; D[1] = pixel >> 8; D[2] = pixel >> 16; } D += 3; } } static void Bop_a1_lsb_set_alphapixel_Aop_bgr24( GenefxState *gfxs ) { int i; int w = gfxs->length; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; DFBColor color = gfxs->color; for (i = 0; i < w; ++i) { if (S[i>>3] & (1 << (i & 7))) { D[0] = color.r; D[1] = color.g; D[2] = color.b; } D += 3; } } static GenefxFunc Bop_a1_lsb_set_alphapixel_Aop_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = Bop_a1_lsb_set_alphapixel_Aop_argb1555, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_a1_lsb_set_alphapixel_Aop_rgb16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = Bop_a1_lsb_set_alphapixel_Aop_rgb24, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_a1_lsb_set_alphapixel_Aop_rgb32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_a1_lsb_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Bop_a1_lsb_set_alphapixel_Aop_a8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = Bop_a1_lsb_set_alphapixel_Aop_yuy2, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = Bop_a1_lsb_set_alphapixel_Aop_rgb332, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = Bop_a1_lsb_set_alphapixel_Aop_uyvy, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = Bop_a1_lsb_set_alphapixel_Aop_lut8, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = Bop_a1_lsb_set_alphapixel_Aop_alut44, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_a1_lsb_set_alphapixel_Aop_airgb, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = Bop_a1_lsb_set_alphapixel_Aop_argb2554, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = Bop_a1_lsb_set_alphapixel_Aop_argb4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = Bop_a1_lsb_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = Bop_a1_lsb_set_alphapixel_Aop_argb1666, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = Bop_a1_lsb_set_alphapixel_Aop_argb6666, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = Bop_a1_lsb_set_alphapixel_Aop_rgb18, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = Bop_a1_lsb_set_alphapixel_Aop_argb, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = Bop_a1_lsb_set_alphapixel_Aop_bgr24, }; /********************************************************************************************************************** ********************************* Bop_lut2_translate_to_Aop_lut8 ***************************************************** **********************************************************************************************************************/ static void Bop_lut2_translate_to_Aop_lut8_C( GenefxState *gfxs ) { int i; int w = gfxs->length; int l = (w + 3) / 4; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; for (i = 0; i < l; ++i, D += 4, w -= 4) { u8 index; u8 pixels = S[i]; switch (w) { default: index = (pixels & 3); if (index < gfxs->num_trans && gfxs->trans[index] >= 0) D[3] = gfxs->trans[index]; case 3: index = (pixels >> 2) & 3; if (index < gfxs->num_trans && gfxs->trans[index] >= 0) D[2] = gfxs->trans[index]; case 2: index = (pixels >> 4) & 3; if (index < gfxs->num_trans && gfxs->trans[index] >= 0) D[1] = gfxs->trans[index]; case 1: index = pixels >> 6; if (index < gfxs->num_trans && gfxs->trans[index] >= 0) D[0] = gfxs->trans[index]; } } } static GenefxFunc Bop_lut2_translate_to_Aop_lut8 = Bop_lut2_translate_to_Aop_lut8_C; /********************************************************************************************************************** ********************************* Xacc_blend ************************************************************************* **********************************************************************************************************************/ static void Xacc_blend_zero( GenefxState *gfxs ) { int i; int w = gfxs->length; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; for (i = 0; i < w; ++i) { if (!(Y[i].RGB.a & 0xf000)) X[i].RGB.a = X[i].RGB.r = X[i].RGB.g = X[i].RGB.b = 0; else X[i] = Y[i]; } } static void Xacc_blend_one( GenefxState *gfxs ) { int i; int w = gfxs->length; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; for (i = 0; i < w; ++i) { X[i] = Y[i]; } } static void Xacc_blend_srccolor( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = ((S->RGB.r + 1) * Y->RGB.r) >> 8; X->RGB.g = ((S->RGB.g + 1) * Y->RGB.g) >> 8; X->RGB.b = ((S->RGB.b + 1) * Y->RGB.b) >> 8; X->RGB.a = ((S->RGB.a + 1) * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; } } else { GenefxAccumulator Cacc = gfxs->Cacc; Cacc.RGB.r = Cacc.RGB.r + 1; Cacc.RGB.g = Cacc.RGB.g + 1; Cacc.RGB.b = Cacc.RGB.b + 1; Cacc.RGB.a = Cacc.RGB.a + 1; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = (Cacc.RGB.r * Y->RGB.r) >> 8; X->RGB.g = (Cacc.RGB.g * Y->RGB.g) >> 8; X->RGB.b = (Cacc.RGB.b * Y->RGB.b) >> 8; X->RGB.a = (Cacc.RGB.a * Y->RGB.a) >> 8; } else *X = *Y; ++X; ++Y; } } } static void Xacc_blend_invsrccolor( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = ((0x100 - S->RGB.r) * Y->RGB.r) >> 8; X->RGB.g = ((0x100 - S->RGB.g) * Y->RGB.g) >> 8; X->RGB.b = ((0x100 - S->RGB.b) * Y->RGB.b) >> 8; X->RGB.a = ((0x100 - S->RGB.a) * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; } } else { GenefxAccumulator Cacc = gfxs->Cacc; Cacc.RGB.r = 0x100 - Cacc.RGB.r; Cacc.RGB.g = 0x100 - Cacc.RGB.g; Cacc.RGB.b = 0x100 - Cacc.RGB.b; Cacc.RGB.a = 0x100 - Cacc.RGB.a; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = (Cacc.RGB.r * Y->RGB.r) >> 8; X->RGB.g = (Cacc.RGB.g * Y->RGB.g) >> 8; X->RGB.b = (Cacc.RGB.b * Y->RGB.b) >> 8; X->RGB.a = (Cacc.RGB.a * Y->RGB.a) >> 8; } else *X = *Y; ++X; ++Y; } } } static void Xacc_blend_srcalpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = S->RGB.a + 1; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; } } else { u16 Sa = gfxs->color.a + 1; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++X; ++Y; } } } static void Xacc_blend_invsrcalpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = 0x100 - S->RGB.a; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; } } else { u16 Sa = 0x100 - gfxs->color.a; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.a = (Sa * Y->RGB.a) >> 8; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; } else *X = *Y; ++X; ++Y; } } } static void Xacc_blend_dstalpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Da = D->RGB.a + 1; X->RGB.r = (Da * Y->RGB.r) >> 8; X->RGB.g = (Da * Y->RGB.g) >> 8; X->RGB.b = (Da * Y->RGB.b) >> 8; X->RGB.a = (Da * Y->RGB.a) >> 8; } else *X = *Y; ++D; ++X; ++Y; } } static void Xacc_blend_invdstalpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Da = 0x100 - D->RGB.a; X->RGB.r = (Da * Y->RGB.r) >> 8; X->RGB.g = (Da * Y->RGB.g) >> 8; X->RGB.b = (Da * Y->RGB.b) >> 8; X->RGB.a = (Da * Y->RGB.a) >> 8; } else *X = *Y; ++D; ++X; ++Y; } } static void Xacc_blend_destcolor( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = ((D->RGB.r + 1) * Y->RGB.r) >> 8; X->RGB.g = ((D->RGB.g + 1) * Y->RGB.g) >> 8; X->RGB.b = ((D->RGB.b + 1) * Y->RGB.b) >> 8; X->RGB.a = ((D->RGB.a + 1) * Y->RGB.a) >> 8; } else *X = *Y; ++D; ++X; ++Y; } } static void Xacc_blend_invdestcolor( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = ((0x100 - D->RGB.r) * Y->RGB.r) >> 8; X->RGB.g = ((0x100 - D->RGB.g) * Y->RGB.g) >> 8; X->RGB.b = ((0x100 - D->RGB.b) * Y->RGB.b) >> 8; X->RGB.a = ((0x100 - D->RGB.a) * Y->RGB.a) >> 8; } else *X = *Y; ++D; ++X; ++Y; } } static void Xacc_blend_srcalphasat( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = MIN( S->RGB.a + 1, 0x100 - D->RGB.a ); X->RGB.a = Y->RGB.a; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; } else *X = *Y; ++S; ++D; ++X; ++Y; } } else { while (--w) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = MIN( gfxs->color.a + 1, 0x100 - D->RGB.a ); X->RGB.a = Y->RGB.a; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; } else *X = *Y; ++D; ++X; ++Y; } } } static GenefxFunc Xacc_blend[] = { [DSBF_ZERO-1] = Xacc_blend_zero, [DSBF_ONE-1] = Xacc_blend_one, [DSBF_SRCCOLOR-1] = Xacc_blend_srccolor, [DSBF_INVSRCCOLOR-1] = Xacc_blend_invsrccolor, [DSBF_SRCALPHA-1] = Xacc_blend_srcalpha, [DSBF_INVSRCALPHA-1] = Xacc_blend_invsrcalpha, [DSBF_DESTALPHA-1] = Xacc_blend_dstalpha, [DSBF_INVDESTALPHA-1] = Xacc_blend_invdstalpha, [DSBF_DESTCOLOR-1] = Xacc_blend_destcolor, [DSBF_INVDESTCOLOR-1] = Xacc_blend_invdestcolor, [DSBF_SRCALPHASAT-1] = Xacc_blend_srcalphasat, }; /********************************************************************************************************************** ********************************* Dacc_modulation ******************************************************************** **********************************************************************************************************************/ static void Dacc_set_alpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; int a = gfxs->color.a; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = a; } ++D; } } static void Dacc_modulate_alpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; int a = gfxs->Cacc.RGB.a; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = (a * D->RGB.a) >> 8; } ++D; } } static void Dacc_modulate_rgb( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.r = (Cacc.RGB.r * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.g * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.b * D->RGB.b) >> 8; } ++D; } } static void Dacc_modulate_rgb_set_alpha( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; int a = gfxs->color.a; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = a; D->RGB.r = (Cacc.RGB.r * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.g * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.b * D->RGB.b) >> 8; } ++D; } } static void Dacc_modulate_argb( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = (Cacc.RGB.a * D->RGB.a) >> 8; D->RGB.r = (Cacc.RGB.r * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.g * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.b * D->RGB.b) >> 8; } ++D; } } static GenefxFunc Dacc_modulation[] = { [DSBLIT_NOFX] = NULL, [DSBLIT_BLEND_ALPHACHANNEL] = NULL, [DSBLIT_BLEND_COLORALPHA] = Dacc_set_alpha, [DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA] = Dacc_modulate_alpha, [DSBLIT_COLORIZE] = Dacc_modulate_rgb, [DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL] = Dacc_modulate_rgb, [DSBLIT_COLORIZE | DSBLIT_BLEND_COLORALPHA] = Dacc_modulate_rgb_set_alpha, [DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA] = Dacc_modulate_argb }; /********************************************************************************************************************** ********************************* Dacc_modulate_mask_alpha_from_PFI ************************************************** **********************************************************************************************************************/ static void Dacc_modulate_mask_alpha_ARGB( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; u32 *m = gfxs->Mop[0]; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = (((*m >> 24) + 1) * D->RGB.a) >> 8; } ++D; ++m; } } static void Dacc_modulate_mask_alpha_A8( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; u8 *m = gfxs->Mop[0]; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = ((*m + 1) * D->RGB.a) >> 8; } ++D; ++m; } } static GenefxFunc Dacc_modulate_mask_alpha_from_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Dacc_modulate_mask_alpha_ARGB, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = Dacc_modulate_mask_alpha_A8, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Dacc_modulate_mask_rgb_from_PFI **************************************************** **********************************************************************************************************************/ static void Dacc_modulate_mask_rgb_ARGB( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; u32 *m = gfxs->Mop[0]; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.r = ((((*m >> 16) & 0xff) + 1) * D->RGB.r) >> 8; D->RGB.g = ((((*m >> 8) & 0xff) + 1) * D->RGB.g) >> 8; D->RGB.b = ((( *m & 0xff) + 1) * D->RGB.b) >> 8; } ++D; ++m; } } static GenefxFunc Dacc_modulate_mask_rgb_from_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Dacc_modulate_mask_rgb_ARGB, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Dacc_modulate_mask_argb_from_PFI *************************************************** **********************************************************************************************************************/ static void Dacc_modulate_mask_argb_ARGB( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; u8 *m = gfxs->Mop[0]; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = (( (*m >> 24) + 1) * D->RGB.a) >> 8; D->RGB.r = ((((*m >> 16) & 0xff) + 1) * D->RGB.r) >> 8; D->RGB.g = ((((*m >> 8) & 0xff) + 1) * D->RGB.g) >> 8; D->RGB.b = ((((*m ) & 0xff) + 1) * D->RGB.b) >> 8; } ++D; ++m; } } static GenefxFunc Dacc_modulate_mask_argb_from_PFI[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Dacc_modulate_mask_argb_ARGB, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /********************************************************************************************************************** ********************************* Misc accumulator operations ******************************************************** **********************************************************************************************************************/ static void Dacc_premultiply_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { u16 Da = D->RGB.a + 1; D->RGB.r = (Da * D->RGB.r) >> 8; D->RGB.g = (Da * D->RGB.g) >> 8; D->RGB.b = (Da * D->RGB.b) >> 8; } ++D; } } static GenefxFunc Dacc_premultiply = Dacc_premultiply_C; /**********************************************************************************************************************/ static void Dacc_premultiply_color_alpha_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.r = (Cacc.RGB.a * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.a * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.a * D->RGB.b) >> 8; } ++D; } } static GenefxFunc Dacc_premultiply_color_alpha = Dacc_premultiply_color_alpha_C; /**********************************************************************************************************************/ static void Dacc_demultiply_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { u16 Da = D->RGB.a + 1; D->RGB.r = (D->RGB.r << 8) / Da; D->RGB.g = (D->RGB.g << 8) / Da; D->RGB.b = (D->RGB.b << 8) / Da; } ++D; } } static GenefxFunc Dacc_demultiply = Dacc_demultiply_C; /**********************************************************************************************************************/ static void Dacc_xor_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; DFBColor color = gfxs->color; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a ^= color.a; D->RGB.r ^= color.r; D->RGB.g ^= color.g; D->RGB.b ^= color.b; } ++D; } } static GenefxFunc Dacc_xor = Dacc_xor_C; /**********************************************************************************************************************/ static void Dacc_clamp_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { if (D->RGB.a > 0xff) D->RGB.a = 0xff; if (D->RGB.r > 0xff) D->RGB.r = 0xff; if (D->RGB.g > 0xff) D->RGB.g = 0xff; if (D->RGB.b > 0xff) D->RGB.b = 0xff; } ++D; } } static GenefxFunc Dacc_clamp = Dacc_clamp_C; /**********************************************************************************************************************/ static void Sacc_xor_Dacc_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a ^= S->RGB.a; D->RGB.r ^= S->RGB.r; D->RGB.g ^= S->RGB.g; D->RGB.b ^= S->RGB.b; } ++S; ++D; } } static GenefxFunc Sacc_xor_Dacc = Sacc_xor_Dacc_C; /**********************************************************************************************************************/ static void Cacc_to_Dacc_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; while (--w) *D++ = Cacc; } static GenefxFunc Cacc_to_Dacc = Cacc_to_Dacc_C; /**********************************************************************************************************************/ static void SCacc_add_to_Dacc_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator SCacc = gfxs->SCacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a += SCacc.RGB.a; D->RGB.r += SCacc.RGB.r; D->RGB.g += SCacc.RGB.g; D->RGB.b += SCacc.RGB.b; } ++D; } } static GenefxFunc SCacc_add_to_Dacc = SCacc_add_to_Dacc_C; /**********************************************************************************************************************/ static void Sacc_add_to_Dacc_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->RGB.a += S->RGB.a; D->RGB.r += S->RGB.r; D->RGB.g += S->RGB.g; D->RGB.b += S->RGB.b; } ++S; ++D; } } static GenefxFunc Sacc_add_to_Dacc = Sacc_add_to_Dacc_C; /**********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 3 ) static void Dacc_RGB_to_YCbCr_BT601_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.RGB.a & 0xf000)) { \ RGB_TO_YCBCR_BT601( s.RGB.r, s.RGB.g, s.RGB.b, d.YUV.y, d.YUV.u, d.YUV.v ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Dacc_RGB_to_YCbCr_BT709_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.RGB.a & 0xf000)) { \ RGB_TO_YCBCR_BT709( s.RGB.r, s.RGB.g, s.RGB.b, d.YUV.y, d.YUV.u, d.YUV.v ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Dacc_RGB_to_YCbCr_BT2020_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.RGB.a & 0xf000)) { \ RGB_TO_YCBCR_BT2020( s.RGB.r, s.RGB.g, s.RGB.b, d.YUV.y, d.YUV.u, d.YUV.v ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static GenefxFunc Dacc_RGB_to_YCbCr_BT601 = Dacc_RGB_to_YCbCr_BT601_C; static GenefxFunc Dacc_RGB_to_YCbCr_BT709 = Dacc_RGB_to_YCbCr_BT709_C; static GenefxFunc Dacc_RGB_to_YCbCr_BT2020 = Dacc_RGB_to_YCbCr_BT2020_C; /**********************************************************************************************************************/ /* change the last value to adjust the size of the device (1-4) */ #define SET_PIXEL_DUFFS_DEVICE(D,S,w) \ SET_PIXEL_DUFFS_DEVICE_N( D, S, w, 2 ) static void Dacc_YCbCr_to_RGB_BT601_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.YUV.a & 0xf000)) { \ YCBCR_TO_RGB_BT601( s.YUV.y, s.YUV.u, s.YUV.v, d.RGB.r, d.RGB.g, d.RGB.b ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Dacc_YCbCr_to_RGB_BT709_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.YUV.a & 0xf000)) { \ YCBCR_TO_RGB_BT709( s.YUV.y, s.YUV.u, s.YUV.v, d.RGB.r, d.RGB.g, d.RGB.b ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } static void Dacc_YCbCr_to_RGB_BT2020_C( GenefxState *gfxs ) { int w = gfxs->length; GenefxAccumulator *S = gfxs->Dacc; GenefxAccumulator *D = gfxs->Dacc; #define SET_PIXEL(d,s) \ if (!(s.YUV.a & 0xf000)) { \ YCBCR_TO_RGB_BT2020( s.YUV.y, s.YUV.u, s.YUV.v, d.RGB.r, d.RGB.g, d.RGB.b ); \ } SET_PIXEL_DUFFS_DEVICE( D, S, w ); #undef SET_PIXEL } #undef SET_PIXEL_DUFFS_DEVICE static GenefxFunc Dacc_YCbCr_to_RGB_BT601 = Dacc_YCbCr_to_RGB_BT601_C; static GenefxFunc Dacc_YCbCr_to_RGB_BT709 = Dacc_YCbCr_to_RGB_BT709_C; static GenefxFunc Dacc_YCbCr_to_RGB_BT2020 = Dacc_YCbCr_to_RGB_BT2020_C; /**********************************************************************************************************************/ static void Dacc_Alpha_to_YCbCr_C( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *D = gfxs->Dacc; while (--w) { if (!(D->RGB.a & 0xf000)) { D->YUV.y = 235; D->YUV.u = 128; D->YUV.v = 128; } ++D; } } static GenefxFunc Dacc_Alpha_to_YCbCr = Dacc_Alpha_to_YCbCr_C; /**********************************************************************************************************************/ static void Sop_is_Aop ( GenefxState *gfxs ) { gfxs->Sop = gfxs->Aop; gfxs->Ostep = gfxs->Astep; } static void Sop_is_Bop ( GenefxState *gfxs ) { gfxs->Sop = gfxs->Bop; gfxs->Ostep = gfxs->Bstep; } static void Slut_is_Alut( GenefxState *gfxs ) { gfxs->Slut = gfxs->Alut; } static void Slut_is_Blut( GenefxState *gfxs ) { gfxs->Slut = gfxs->Blut; } static void Sacc_is_NULL( GenefxState *gfxs ) { gfxs->Sacc = NULL; } static void Sacc_is_Aacc( GenefxState *gfxs ) { gfxs->Sacc = gfxs->Aacc; } static void Sacc_is_Bacc( GenefxState *gfxs ) { gfxs->Sacc = gfxs->Bacc; } static void Sacc_is_Tacc( GenefxState *gfxs ) { gfxs->Sacc = gfxs->Tacc; } static void Dacc_is_Aacc( GenefxState *gfxs ) { gfxs->Dacc = gfxs->Aacc; } static void Dacc_is_Bacc( GenefxState *gfxs ) { gfxs->Dacc = gfxs->Bacc; } static void Dacc_is_Tacc( GenefxState *gfxs ) { gfxs->Dacc = gfxs->Tacc; } static void Xacc_is_Bacc( GenefxState *gfxs ) { gfxs->Xacc = gfxs->Bacc; } static void Xacc_is_Tacc( GenefxState *gfxs ) { gfxs->Xacc = gfxs->Tacc; } static void Yacc_is_Aacc( GenefxState *gfxs ) { gfxs->Yacc = gfxs->Aacc; } static void Yacc_is_Bacc( GenefxState *gfxs ) { gfxs->Yacc = gfxs->Bacc; } static void Len_is_Slen ( GenefxState *gfxs ) { gfxs->length = gfxs->Slen; } static void Len_is_Dlen ( GenefxState *gfxs ) { gfxs->length = gfxs->Dlen; } #define MODULATION_FLAGS (DSBLIT_BLEND_ALPHACHANNEL | \ DSBLIT_BLEND_COLORALPHA | \ DSBLIT_COLORIZE | \ DSBLIT_DST_PREMULTIPLY | \ DSBLIT_SRC_PREMULTIPLY | \ DSBLIT_SRC_PREMULTCOLOR | \ DSBLIT_DEMULTIPLY | \ DSBLIT_XOR) /**********************************************************************************************************************/ #ifndef WORDS_BIGENDIAN #define BGR_TO_RGB16(pixel) ((((pixel) << 8) & 0xf800) | (((pixel) >> 5) & 0x07e0) | (((pixel) >> 19) & 0x001f)) /* * Fast RGB24 to RGB16 conversion. */ static void Bop_rgb24_to_Aop_rgb16_LE( GenefxState *gfxs ) { int w = gfxs->length; u8 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; while ((unsigned long) S & 3) { *D++ = PIXEL_RGB16( S[0], S[1], S[2] ); S += 3; --w; } if ((unsigned long) D & 2) { *D++ = PIXEL_RGB16( S[0], S[1], S[2] ); S += 3; --w; while (w > 1) { *(u32*) D = PIXEL_RGB16( S[0], S[1], S[2] ) | (PIXEL_RGB16( S[3], S[4], S[5] ) << 16); S += 6; D += 2; w -= 2; } } else { u32 *S32 = (u32*) S; u32 *D32 = (u32*) D; while (w > 3) { D32[0] = BGR_TO_RGB16( S32[0] ) | (BGR_TO_RGB16( (S32[0] >> 24) | (S32[1] << 8) ) << 16); D32[1] = BGR_TO_RGB16( (S32[1] >> 16) | (S32[2] << 16) ) | (BGR_TO_RGB16( S32[2] >> 8 ) << 16); S32 += 3; D32 += 2; w -= 4; } S = (u8*) S32; D = (u16*) D32; } while (w > 0) { *D++ = PIXEL_RGB16( S[0], S[1], S[2] ); S += 3; --w; } } /* * Fast RGB32 to RGB16 conversion. */ static void Bop_rgb32_to_Aop_rgb16_LE( GenefxState *gfxs ) { int w = gfxs->length; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; if ((unsigned long) D & 2) { u16 *d = (u16*) D; d[0] = ARGB_TO_RGB16( S[0] ); D = (u32*) (d + 1); ++S; --w; } while (w > 1) { D[0] = ARGB_TO_RGB16( S[0] ) | (ARGB_TO_RGB16( S[1] ) << 16); S += 2; ++D; w -= 2; } if (w > 0) { u16 *d = (u16*) D; d[0] = ARGB_TO_RGB16( S[0] ); } } #endif /* WORDS_BIGENDIAN */ /**********************************************************************************************************************/ #ifdef USE_MMX #include "generic_mmx.h" /* * patches function pointers to MMX functions */ static void gInit_MMX( void ) { /********************************* Xacc_blend *************************************/ Xacc_blend[DSBF_SRCALPHA-1] = Xacc_blend_srcalpha_MMX; Xacc_blend[DSBF_INVSRCALPHA-1] = Xacc_blend_invsrcalpha_MMX; /********************************* Dacc_modulation ********************************/ Dacc_modulation[DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA] = Dacc_modulate_argb_MMX; /********************************* Misc accumulator operations ********************/ SCacc_add_to_Dacc = SCacc_add_to_Dacc_MMX; Sacc_add_to_Dacc = Sacc_add_to_Dacc_MMX; } #endif #ifdef USE_NEON #include "generic_neon.h" /* * patches function pointers to NEON functions */ static void gInit_NEON() { /********************************* Sop_PFI_to_Dacc ********************************/ Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sop_rgb16_to_Dacc_NEON; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Sop_argb_to_Dacc_NEON; /********************************* Sacc_to_Aop_PFI ********************************/ Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Sacc_to_Aop_rgb16_NEON; /********************************* Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI */ Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb16_NEON; /********************************* Xacc_blend *************************************/ Xacc_blend[DSBF_SRCALPHA-1] = Xacc_blend_srcalpha_NEON; Xacc_blend[DSBF_INVSRCALPHA-1] = Xacc_blend_invsrcalpha_NEON; /********************************* Dacc_modulation ********************************/ Dacc_modulation[DSBLIT_COLORIZE] = Dacc_modulate_rgb_NEON; Dacc_modulation[DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL] = Dacc_modulate_rgb_NEON; Dacc_modulation[DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA] = Dacc_modulate_argb_NEON; /********************************* Misc accumulator operations ********************/ SCacc_add_to_Dacc = SCacc_add_to_Dacc_NEON; Sacc_add_to_Dacc = Sacc_add_to_Dacc_NEON; } #endif #if SIZEOF_LONG == 8 #include "generic_64.h" /* * patches function pointers to 64 bits functions */ static void gInit_64bit( void ) { /********************************* Cop_to_Aop_PFI *********************************/ Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Cop_to_Aop_32_64; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Cop_to_Aop_32_64; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Cop_to_Aop_32_64; /********************************* Bop_PFI_toK_Aop_PFI ****************************/ Bop_PFI_toK_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_rgb32_toK_Aop_64; Bop_PFI_toK_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_rgb32_toK_Aop_64; Bop_PFI_toK_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_rgb32_toK_Aop_64; /********************************* Bop_PFI_Kto_Aop_PFI ****************************/ Bop_PFI_Kto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_rgb32_Kto_Aop_64; Bop_PFI_Kto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_rgb32_Kto_Aop_64; Bop_PFI_Kto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_rgb32_Kto_Aop_64; /********************************* Bop_PFI_Sto_Aop_PFI ****************************/ Bop_PFI_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = Bop_32_Sto_Aop_64; Bop_PFI_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = Bop_32_Sto_Aop_64; Bop_PFI_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = Bop_32_Sto_Aop_64; /********************************* Misc accumulator operations ********************/ Dacc_xor = Dacc_xor_64; } #endif #ifdef WORDS_BIGENDIAN /* * patches function pointers to big endian functions */ static void gInit_BigEndian() { /********************************* Cop_to_Aop_PFI *********************************/ Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Cop_to_Aop_nv21; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Cop_to_Aop_nv61; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Cop_to_Aop_nv42; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Cop_to_Aop_nv12; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Cop_to_Aop_nv16; Cop_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Cop_to_Aop_nv24; /********************************* Sop_PFI_to_Dacc ********************************/ Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sop_nv21_to_Dacc; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sop_nv21_to_Dacc; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sop_nv42_to_Dacc; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sop_nv12_to_Dacc; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sop_nv12_to_Dacc; Sop_PFI_to_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sop_nv24_to_Dacc; /********************************* Sop_PFI_Sto_Dacc *******************************/ Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sop_nv21_Sto_Dacc; Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sop_nv21_Sto_Dacc; Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sop_nv42_Sto_Dacc; Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sop_nv12_Sto_Dacc; Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sop_nv12_Sto_Dacc; Sop_PFI_Sto_Dacc[DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sop_nv24_Sto_Dacc; /********************************* Sacc_to_Aop_PFI ********************************/ Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sacc_to_Aop_nv21; Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sacc_to_Aop_nv61; Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sacc_to_Aop_nv42; Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sacc_to_Aop_nv12; Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sacc_to_Aop_nv16; Sacc_to_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sacc_to_Aop_nv24; /********************************* Sacc_Sto_Aop_PFI *******************************/ Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = Sacc_Sto_Aop_nv21; Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = Sacc_Sto_Aop_nv61; Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = Sacc_Sto_Aop_nv42; Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = Sacc_Sto_Aop_nv12; Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = Sacc_Sto_Aop_nv16; Sacc_Sto_Aop_PFI[DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = Sacc_Sto_Aop_nv24; } #endif /**********************************************************************************************************************/ void gGetDriverInfo( GraphicsDriverInfo *driver_info ) { snprintf( driver_info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "Software Driver" ); #if SIZEOF_LONG == 8 gInit_64bit(); #endif #ifdef WORDS_BIGENDIAN gInit_BigEndian(); #endif #ifdef USE_MMX if (!dfb_config->mmx) { D_INFO( "DirectFB/Genefx: MMX disabled by option 'no-mmx'\n" ); } else { gInit_MMX(); snprintf( driver_info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "MMX Software Driver" ); D_INFO( "DirectFB/Genefx: MMX enabled\n" ); } #endif #ifdef USE_NEON if (!dfb_config->neon) { D_INFO( "DirectFB/Genefx: NEON disabled by option 'no-neon'\n" ); } else { gInit_NEON(); snprintf( driver_info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "NEON Software Driver" ); D_INFO( "DirectFB/Genefx: NEON enabled\n" ); } #endif snprintf( driver_info->vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, "DirectFB" ); driver_info->version.major = 0; driver_info->version.minor = 7; } void gGetDeviceInfo( GraphicsDeviceInfo *device_info ) { snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Software Rasterizer" ); snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "Genefx" ); device_info->caps.flags = 0; device_info->caps.accel = DFXL_NONE; device_info->caps.blitting = DSBLIT_NOFX; device_info->caps.drawing = DSDRAW_NOFX; device_info->caps.clip = 0; } static bool gAcquireCheck( CardState *state, DFBAccelerationMask accel ) { GenefxState *gfxs; CoreSurface *destination = state->destination; CoreSurface *source = state->source; CoreSurface *source_mask = state->source_mask; if (dfb_config->hardware_only) { if (dfb_config->software_warn) { if (DFB_BLITTING_FUNCTION( accel )) D_WARN( "ignoring blit (%x) from %s to %s, flags 0x%08x, funcs %u %u", accel, source ? dfb_pixelformat_name( source->config.format ) : "NULL SOURCE", destination ? dfb_pixelformat_name( destination->config.format ) : "NULL DESTINATION", state->blittingflags, state->src_blend, state->dst_blend ); else D_WARN( "ignoring draw (%x) to %s, flags 0x%08x", accel, destination ? dfb_pixelformat_name( destination->config.format ) : "NULL DESTINATION", state->drawingflags ); } return false; } if (!state->gfxs) { gfxs = D_CALLOC( 1, sizeof(GenefxState) ); if (!gfxs) { D_ERROR( "DirectFB/Genefx: Could not allocate Genefx state!\n" ); return false; } state->gfxs = gfxs; } gfxs = state->gfxs; /* Destination may have been destroyed. */ if (!destination) return false; /* Destination buffer may have been destroyed (suspended), i.e. by vt-switching. */ if (destination->num_buffers == 0) return false; /* Source may have been destroyed. */ if (DFB_BLITTING_FUNCTION( accel )) { if (!source) return false; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { if (!source_mask) return false; } } return true; } static DFBResult gAcquireLockBuffers( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; CoreSurface *destination = state->destination; CoreSurface *source = state->source; CoreSurface *source_mask = state->source_mask; CoreSurfaceAccessFlags access = CSAF_WRITE; if (core_dfb->shutdown_running) return DFB_DEAD; /* * Destination setup */ if (DFB_BLITTING_FUNCTION( accel )) { if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA | DSBLIT_DST_COLORKEY)) access |= CSAF_READ; } else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY)) access |= CSAF_READ; /* Lock destination. */ ret = dfb_surface_lock_buffer2( destination, state->to, destination->flips, state->to_eye, CSAID_CPU, access, &state->dst ); if (ret) { D_DERROR( ret, "DirectFB/Genefx: Could not lock destination!\n" ); return ret; } /* * Source setup */ if (DFB_BLITTING_FUNCTION( accel )) { /* Lock source. */ ret = dfb_surface_lock_buffer2( source, state->from, source->flips, state->from_eye, CSAID_CPU, CSAF_READ, &state->src ); if (ret) { D_DERROR( ret, "DirectFB/Genefx: Could not lock source!\n" ); dfb_surface_unlock_buffer( destination, &state->dst ); return ret; } state->flags |= CSF_SOURCE_LOCKED; /* * Mask setup */ if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { /* Lock source. */ ret = dfb_surface_lock_buffer2( source_mask, state->from, source_mask->flips, state->from_eye, CSAID_CPU, CSAF_READ, &state->src_mask ); if (ret) { D_DERROR( ret, "DirectFB/Genefx: Could not lock source mask!\n" ); dfb_surface_unlock_buffer( destination, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } return ret; } state->flags |= CSF_SOURCE_MASK_LOCKED; } } return DFB_OK; } static DFBResult gAcquireUnlockBuffers( CardState *state ) { dfb_surface_unlock_buffer( state->destination, &state->dst ); if (state->flags & CSF_SOURCE_LOCKED) { dfb_surface_unlock_buffer( state->source, &state->src ); state->flags &= ~CSF_SOURCE_LOCKED; } if (state->flags & CSF_SOURCE_MASK_LOCKED) { dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); state->flags &= ~CSF_SOURCE_MASK_LOCKED; } return DFB_OK; } static bool gAcquireSetup( CardState *state, DFBAccelerationMask accel ) { GenefxState *gfxs; GenefxFunc *funcs; int dst_pfi; int src_pfi = 0; int mask_pfi = 0; CoreSurface *destination = state->destination; CoreSurface *source = state->source; DFBColor color = state->color; bool src_ycbcr = false; bool dst_ycbcr = false; DFBSurfaceBlittingFlags simpld_blittingflags = state->blittingflags; u16 ca; dfb_simplify_blittingflags( &simpld_blittingflags ); if (!state->gfxs) { gfxs = D_CALLOC( 1, sizeof(GenefxState) ); if (!gfxs) { D_ERROR( "DirectFB/Genefx: Could not allocate Genefx state!\n" ); return false; } state->gfxs = gfxs; } gfxs = state->gfxs; funcs = gfxs->funcs; /* * Destination setup */ gfxs->dst_caps = destination->config.caps; gfxs->dst_height = destination->config.size.h; gfxs->dst_format = destination->config.format; gfxs->dst_bpp = DFB_BYTES_PER_PIXEL( gfxs->dst_format ); gfxs->dst_org[0] = state->dst.addr; gfxs->dst_pitch = state->dst.pitch; gfxs->dst_field_offset = gfxs->dst_height / 2 * gfxs->dst_pitch; dst_pfi = DFB_PIXELFORMAT_INDEX( gfxs->dst_format ); switch (gfxs->dst_format) { case DSPF_I420: gfxs->dst_org[1] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[2] = gfxs->dst_org[1] + gfxs->dst_height / 2 * gfxs->dst_pitch / 2; break; case DSPF_YV12: gfxs->dst_org[2] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[1] = gfxs->dst_org[2] + gfxs->dst_height / 2 * gfxs->dst_pitch / 2; break; case DSPF_Y42B: gfxs->dst_org[1] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[2] = gfxs->dst_org[1] + gfxs->dst_height * gfxs->dst_pitch / 2; break; case DSPF_YV16: gfxs->dst_org[2] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[1] = gfxs->dst_org[2] + gfxs->dst_height * gfxs->dst_pitch / 2; break; case DSPF_Y444: gfxs->dst_org[1] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[2] = gfxs->dst_org[1] + gfxs->dst_height * gfxs->dst_pitch; break; case DSPF_YV24: gfxs->dst_org[2] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; gfxs->dst_org[1] = gfxs->dst_org[2] + gfxs->dst_height * gfxs->dst_pitch; break; case DSPF_NV12: case DSPF_NV21: case DSPF_NV16: case DSPF_NV61: case DSPF_NV24: case DSPF_NV42: gfxs->dst_org[1] = gfxs->dst_org[0] + gfxs->dst_height * gfxs->dst_pitch; break; default: break; } /* * Source setup */ if (DFB_BLITTING_FUNCTION( accel )) { CoreSurface *source_mask = state->source_mask; gfxs->src_caps = source->config.caps; gfxs->src_height = source->config.size.h; gfxs->src_format = source->config.format; gfxs->src_bpp = DFB_BYTES_PER_PIXEL( gfxs->src_format ); gfxs->src_org[0] = state->src.addr; gfxs->src_pitch = state->src.pitch; gfxs->src_field_offset = gfxs->src_height / 2 * gfxs->src_pitch; src_pfi = DFB_PIXELFORMAT_INDEX( gfxs->src_format ); switch (gfxs->src_format) { case DSPF_I420: gfxs->src_org[1] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[2] = gfxs->src_org[1] + gfxs->src_height / 2 * gfxs->src_pitch / 2; break; case DSPF_YV12: gfxs->src_org[2] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[1] = gfxs->src_org[2] + gfxs->src_height / 2 * gfxs->src_pitch / 2; break; case DSPF_Y42B: gfxs->src_org[1] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[2] = gfxs->src_org[1] + gfxs->src_height * gfxs->src_pitch / 2; break; case DSPF_YV16: gfxs->src_org[2] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[1] = gfxs->src_org[2] + gfxs->src_height * gfxs->src_pitch / 2; break; case DSPF_Y444: gfxs->src_org[1] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[2] = gfxs->src_org[1] + gfxs->src_height * gfxs->src_pitch; break; case DSPF_YV24: gfxs->src_org[2] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; gfxs->src_org[1] = gfxs->src_org[2] + gfxs->src_height * gfxs->src_pitch; break; case DSPF_NV12: case DSPF_NV21: case DSPF_NV16: case DSPF_NV61: case DSPF_NV24: case DSPF_NV42: gfxs->src_org[1] = gfxs->src_org[0] + gfxs->src_height * gfxs->src_pitch; break; default: break; } /* * Mask setup */ if (simpld_blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { gfxs->mask_caps = source_mask->config.caps; gfxs->mask_height = source_mask->config.size.h; gfxs->mask_format = source_mask->config.format; gfxs->mask_bpp = DFB_BYTES_PER_PIXEL( gfxs->mask_format ); gfxs->mask_org[0] = state->src_mask.addr; gfxs->mask_pitch = state->src_mask.pitch; gfxs->mask_field_offset = gfxs->mask_height / 2 * gfxs->mask_pitch; mask_pfi = DFB_PIXELFORMAT_INDEX( gfxs->mask_format ); switch (gfxs->mask_format) { case DSPF_I420: gfxs->mask_org[1] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[2] = gfxs->mask_org[1] + gfxs->mask_height / 2 * gfxs->mask_pitch / 2; break; case DSPF_YV12: gfxs->mask_org[2] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[1] = gfxs->mask_org[2] + gfxs->mask_height / 2 * gfxs->mask_pitch / 2; break; case DSPF_Y42B: gfxs->mask_org[1] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[2] = gfxs->mask_org[1] + gfxs->mask_height * gfxs->mask_pitch / 2; break; case DSPF_YV16: gfxs->mask_org[2] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[1] = gfxs->mask_org[2] + gfxs->mask_height * gfxs->mask_pitch / 2; break; case DSPF_Y444: gfxs->mask_org[1] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[2] = gfxs->mask_org[1] + gfxs->mask_height * gfxs->mask_pitch; break; case DSPF_YV24: gfxs->mask_org[2] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; gfxs->mask_org[1] = gfxs->mask_org[2] + gfxs->mask_height * gfxs->mask_pitch; break; case DSPF_NV12: case DSPF_NV21: case DSPF_NV16: case DSPF_NV61: case DSPF_NV24: case DSPF_NV42: gfxs->mask_org[1] = gfxs->mask_org[0] + gfxs->mask_height * gfxs->mask_pitch; break; default: break; } } } /* Premultiply source (color). */ if (DFB_DRAWING_FUNCTION(accel) && (state->drawingflags & DSDRAW_SRC_PREMULTIPLY)) { ca = color.a + 1; color.r = (color.r * ca) >> 8; color.g = (color.g * ca) >> 8; color.b = (color.b * ca) >> 8; } gfxs->color = color; #define RGB_TO_YCBCR(r,g,b,y,cb,cr) \ if (destination->config.colorspace == DSCS_BT601) \ RGB_TO_YCBCR_BT601(r,g,b,y,cb,cr); \ else if (destination->config.colorspace == DSCS_BT709) \ RGB_TO_YCBCR_BT709(r,g,b,y,cb,cr); \ else if (destination->config.colorspace == DSCS_BT2020) \ RGB_TO_YCBCR_BT2020(r,g,b,y,cb,cr); \ else { \ y = 16; \ cb = cr = 128; \ } switch (gfxs->dst_format) { case DSPF_ARGB1555: gfxs->Cop = PIXEL_ARGB1555( color.a, color.r, color.g, color.b ); break; case DSPF_ARGB8565: gfxs->Cop = PIXEL_ARGB8565( color.a, color.r, color.g, color.b ); break; case DSPF_RGB16: gfxs->Cop = PIXEL_RGB16( color.r, color.g, color.b ); break; case DSPF_RGB18: gfxs->Cop = PIXEL_RGB18( color.r, color.g, color.b ); break; case DSPF_RGB24: gfxs->Cop = PIXEL_RGB32( color.r, color.g, color.b ); break; case DSPF_BGR24: gfxs->Cop = PIXEL_RGB32( color.b, color.g, color.r ); break; case DSPF_RGB32: gfxs->Cop = PIXEL_RGB32( color.r, color.g, color.b ); break; case DSPF_ARGB: gfxs->Cop = PIXEL_ARGB( color.a, color.r, color.g, color.b ); break; case DSPF_ABGR: gfxs->Cop = PIXEL_ABGR( color.a, color.r, color.g, color.b ); break; case DSPF_AiRGB: gfxs->Cop = PIXEL_AiRGB( color.a, color.r, color.g, color.b ); break; case DSPF_ARGB6666: gfxs->Cop = PIXEL_ARGB6666( color.a, color.r, color.g, color.b ); break; case DSPF_ARGB1666: gfxs->Cop = PIXEL_ARGB1666( color.a, color.r, color.g, color.b ); break; case DSPF_A1: gfxs->Cop = color.a >> 7; break; case DSPF_A4: gfxs->Cop = color.a >> 4; break; case DSPF_A8: gfxs->Cop = color.a; break; case DSPF_YUY2: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #ifdef WORDS_BIGENDIAN gfxs->Cop = PIXEL_YUY2_BE( gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #else gfxs->Cop = PIXEL_YUY2_LE( gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #endif break; case DSPF_RGB332: gfxs->Cop = PIXEL_RGB332( color.r, color.g, color.b ); break; case DSPF_UYVY: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #ifdef WORDS_BIGENDIAN gfxs->Cop = PIXEL_UYVY_BE( gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #else gfxs->Cop = PIXEL_UYVY_LE( gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); #endif break; case DSPF_I420: case DSPF_YV12: case DSPF_NV12: case DSPF_NV21: case DSPF_Y42B: case DSPF_YV16: case DSPF_NV16: case DSPF_NV61: case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); gfxs->Cop = gfxs->YCop; break; case DSPF_LUT1: case DSPF_LUT2: case DSPF_LUT8: gfxs->Cop = state->color_index; gfxs->Alut = destination->palette; break; case DSPF_ALUT44: gfxs->Cop = (color.a & 0xf0) + state->color_index; gfxs->Alut = destination->palette; break; case DSPF_ARGB2554: gfxs->Cop = PIXEL_ARGB2554( color.a, color.r, color.g, color.b ); break; case DSPF_ARGB4444: gfxs->Cop = PIXEL_ARGB4444( color.a, color.r, color.g, color.b ); break; case DSPF_RGBA4444: gfxs->Cop = PIXEL_RGBA4444( color.a, color.r, color.g, color.b ); break; case DSPF_AYUV: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); gfxs->Cop = PIXEL_AYUV( color.a, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); break; case DSPF_RGB444: gfxs->Cop = PIXEL_RGB444( color.r, color.g, color.b ); break; case DSPF_RGB555: gfxs->Cop = PIXEL_RGB555( color.r, color.g, color.b ); break; case DSPF_BGR555: gfxs->Cop = PIXEL_BGR555( color.r, color.g, color.b ); break; case DSPF_RGBA5551: gfxs->Cop = PIXEL_RGBA5551( color.a, color.r, color.g, color.b ); break; case DSPF_RGBAF88871: gfxs->Cop = PIXEL_RGBAF88871( color.a, color.r, color.g, color.b ); break; case DSPF_AVYU: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); gfxs->Cop = PIXEL_AVYU( color.a, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); break; case DSPF_VYU: RGB_TO_YCBCR( color.r, color.g, color.b, gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); gfxs->Cop = PIXEL_VYU( gfxs->YCop, gfxs->CbCop, gfxs->CrCop ); break; case DSPF_A1_LSB: gfxs->Cop = color.a & 1; break; default: D_ONCE( "unsupported destination format" ); return false; } #undef RGB_TO_YCBCR dst_ycbcr = is_ycbcr[DFB_PIXELFORMAT_INDEX(gfxs->dst_format)]; if (DFB_BLITTING_FUNCTION( accel )) { switch (gfxs->src_format) { case DSPF_LUT1: case DSPF_LUT2: case DSPF_LUT8: case DSPF_ALUT44: gfxs->Blut = source->palette; case DSPF_ARGB1555: case DSPF_RGBA5551: case DSPF_ARGB2554: case DSPF_ARGB4444: case DSPF_RGBA4444: case DSPF_ARGB1666: case DSPF_ARGB6666: case DSPF_ARGB8565: case DSPF_RGB16: case DSPF_RGB18: case DSPF_RGB24: case DSPF_BGR24: case DSPF_RGB32: case DSPF_ARGB: case DSPF_ABGR: case DSPF_AiRGB: case DSPF_RGB332: case DSPF_RGB444: case DSPF_RGB555: case DSPF_BGR555: case DSPF_RGBAF88871: if (dst_ycbcr && simpld_blittingflags & (DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) return false; case DSPF_A1: case DSPF_A1_LSB: case DSPF_A4: case DSPF_A8: if (DFB_PLANAR_PIXELFORMAT(gfxs->dst_format) && simpld_blittingflags & DSBLIT_DST_COLORKEY) return false; break; case DSPF_I420: case DSPF_YV12: case DSPF_NV12: case DSPF_NV21: case DSPF_Y42B: case DSPF_YV16: case DSPF_NV16: case DSPF_NV61: case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) return false; case DSPF_YUY2: case DSPF_UYVY: case DSPF_AYUV: case DSPF_AVYU: case DSPF_VYU: if (dst_ycbcr && simpld_blittingflags & (DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) return false; if (DFB_PLANAR_PIXELFORMAT(gfxs->dst_format) && simpld_blittingflags & DSBLIT_DST_COLORKEY) return false; break; default: D_ONCE( "unsupported source format" ); return false; } } src_ycbcr = is_ycbcr[DFB_PIXELFORMAT_INDEX(gfxs->src_format)]; gfxs->need_accumulator = true; gfxs->Astep = gfxs->Bstep = gfxs->Ostep = 1; switch (accel) { case DFXL_FILLRECTANGLE: case DFXL_DRAWRECTANGLE: case DFXL_DRAWLINE: case DFXL_FILLTRIANGLE: if (state->drawingflags & ~(DSDRAW_DST_COLORKEY | DSDRAW_SRC_PREMULTIPLY | DSDRAW_DST_PREMULTIPLY)) { GenefxAccumulator Cacc, SCacc; if (state->drawingflags & DSDRAW_BLEND) { if (state->src_blend == DSBF_ZERO) { if (state->dst_blend == DSBF_ZERO) { gfxs->Cop = 0; if (state->drawingflags & DSDRAW_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Cop_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Cop_to_Aop_PFI[dst_pfi]; break; } else if (state->dst_blend == DSBF_ONE) { break; } } else if (state->src_blend == DSBF_ONE && state->dst_blend == DSBF_ZERO) { if (state->drawingflags & DSDRAW_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Cop_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Cop_to_Aop_PFI[dst_pfi]; break; } } /* Load from destination. */ *funcs++ = Sop_is_Aop; if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->dst_format )) *funcs++ = Slut_is_Alut; *funcs++ = Dacc_is_Aacc; *funcs++ = Sop_PFI_to_Dacc[dst_pfi]; if (dst_ycbcr) { if (destination->config.colorspace == DSCS_BT601) *funcs++ = Dacc_YCbCr_to_RGB_BT601; else if (destination->config.colorspace == DSCS_BT709) *funcs++ = Dacc_YCbCr_to_RGB_BT709; else if (destination->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_YCbCr_to_RGB_BT2020; } /* Premultiply destination. */ if (state->drawingflags & DSDRAW_DST_PREMULTIPLY) *funcs++ = Dacc_premultiply; /* Load source (color). */ Cacc.RGB.a = color.a; Cacc.RGB.r = color.r; Cacc.RGB.g = color.g; Cacc.RGB.b = color.b; if (state->drawingflags & DSDRAW_BLEND) { /* Source blending. */ switch (state->src_blend) { case DSBF_ZERO: break; case DSBF_ONE: SCacc = Cacc; break; case DSBF_SRCCOLOR: SCacc.RGB.a = (Cacc.RGB.a * (Cacc.RGB.a + 1)) >> 8; SCacc.RGB.r = (Cacc.RGB.r * (Cacc.RGB.r + 1)) >> 8; SCacc.RGB.g = (Cacc.RGB.g * (Cacc.RGB.g + 1)) >> 8; SCacc.RGB.b = (Cacc.RGB.b * (Cacc.RGB.b + 1)) >> 8; break; case DSBF_INVSRCCOLOR: SCacc.RGB.a = (Cacc.RGB.a * (0x100 - Cacc.RGB.a)) >> 8; SCacc.RGB.r = (Cacc.RGB.r * (0x100 - Cacc.RGB.r)) >> 8; SCacc.RGB.g = (Cacc.RGB.g * (0x100 - Cacc.RGB.g)) >> 8; SCacc.RGB.b = (Cacc.RGB.b * (0x100 - Cacc.RGB.b)) >> 8; break; case DSBF_SRCALPHA: ca = color.a + 1; SCacc.RGB.a = (Cacc.RGB.a * ca) >> 8; SCacc.RGB.r = (Cacc.RGB.r * ca) >> 8; SCacc.RGB.g = (Cacc.RGB.g * ca) >> 8; SCacc.RGB.b = (Cacc.RGB.b * ca) >> 8; break; case DSBF_INVSRCALPHA: ca = 0x100 - color.a; SCacc.RGB.a = (Cacc.RGB.a * ca) >> 8; SCacc.RGB.r = (Cacc.RGB.r * ca) >> 8; SCacc.RGB.g = (Cacc.RGB.g * ca) >> 8; SCacc.RGB.b = (Cacc.RGB.b * ca) >> 8; break; case DSBF_SRCALPHASAT: *funcs++ = Sacc_is_NULL; case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: case DSBF_DESTCOLOR: case DSBF_INVDESTCOLOR: *funcs++ = Dacc_is_Bacc; *funcs++ = Cacc_to_Dacc; *funcs++ = Dacc_is_Aacc; *funcs++ = Xacc_is_Bacc; *funcs++ = Yacc_is_Bacc; *funcs++ = Xacc_blend[state->src_blend-1]; break; default: D_BUG( "unknown src_blend %u", state->src_blend ); } /* Destination blending. */ *funcs++ = Sacc_is_NULL; *funcs++ = Xacc_is_Tacc; *funcs++ = Yacc_is_Aacc; if (state->dst_blend > D_ARRAY_SIZE(Xacc_blend) || state->dst_blend < 1) D_BUG( "unknown dst_blend %u", state->dst_blend ); else *funcs++ = Xacc_blend[state->dst_blend-1]; /* Add source to destination accumulator. */ switch (state->src_blend) { case DSBF_ZERO: break; case DSBF_ONE: case DSBF_SRCCOLOR: case DSBF_INVSRCCOLOR: case DSBF_SRCALPHA: case DSBF_INVSRCALPHA: if (SCacc.RGB.a || SCacc.RGB.r || SCacc.RGB.g || SCacc.RGB.b) { *funcs++ = Dacc_is_Tacc; *funcs++ = SCacc_add_to_Dacc; } break; case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: case DSBF_DESTCOLOR: case DSBF_INVDESTCOLOR: case DSBF_SRCALPHASAT: *funcs++ = Sacc_is_Bacc; *funcs++ = Dacc_is_Tacc; *funcs++ = Sacc_add_to_Dacc; break; default: D_BUG( "unknown src_blend %u", state->src_blend ); } } /* Demultiply result. */ if (state->drawingflags & DSDRAW_DEMULTIPLY) *funcs++ = Dacc_demultiply; /* XOR destination. */ if (state->drawingflags & DSDRAW_XOR) { if (state->drawingflags & DSDRAW_BLEND) { *funcs++ = Sacc_is_Aacc; *funcs++ = Sacc_xor_Dacc; *funcs++ = Sacc_is_Tacc; if (dst_ycbcr) *funcs++ = Dacc_is_Tacc; } else { *funcs++ = Dacc_xor; *funcs++ = Sacc_is_Aacc; if (dst_ycbcr) *funcs++ = Dacc_is_Aacc; } } else if (state->drawingflags & DSDRAW_BLEND) { *funcs++ = Sacc_is_Tacc; if (dst_ycbcr) *funcs++ = Dacc_is_Tacc; } else { *funcs++ = Sacc_is_Aacc; if (dst_ycbcr) *funcs++ = Dacc_is_Aacc; } if (dst_ycbcr) { if (destination->config.colorspace == DSCS_BT601) *funcs++ = Dacc_RGB_to_YCbCr_BT601; else if (destination->config.colorspace == DSCS_BT709) *funcs++ = Dacc_RGB_to_YCbCr_BT709; else if (destination->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_RGB_to_YCbCr_BT2020; } /* Write to destination. */ if (state->drawingflags & DSDRAW_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Sacc_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Sacc_to_Aop_PFI[dst_pfi]; /* Store computed Cacc. */ gfxs->Cacc = Cacc; gfxs->SCacc = SCacc; } else { gfxs->need_accumulator = false; if (state->drawingflags & DSDRAW_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Cop_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Cop_to_Aop_PFI[dst_pfi]; } break; case DFXL_BLIT: if (simpld_blittingflags == DSBLIT_BLEND_ALPHACHANNEL && state->src_blend == DSBF_SRCALPHA && state->dst_blend == DSBF_INVSRCALPHA) { if (gfxs->src_format == DSPF_ARGB && Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI[dst_pfi]) { *funcs++ = Bop_argb_blend_alphachannel_src_invsrc_Aop_PFI[dst_pfi]; break; } } if (simpld_blittingflags == DSBLIT_BLEND_ALPHACHANNEL && state->src_blend == DSBF_ONE && state->dst_blend == DSBF_INVSRCALPHA) { if (gfxs->src_format == DSPF_ARGB && Bop_argb_blend_alphachannel_one_invsrc_Aop_PFI[dst_pfi]) { *funcs++ = Bop_argb_blend_alphachannel_one_invsrc_Aop_PFI[dst_pfi]; break; } } if (simpld_blittingflags == (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_SRC_PREMULTIPLY) && state->src_blend == DSBF_ONE && state->dst_blend == DSBF_INVSRCALPHA) { if (gfxs->src_format == DSPF_ARGB && Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_PFI[dst_pfi]) { *funcs++ = Bop_argb_blend_alphachannel_one_invsrc_premultiply_Aop_PFI[dst_pfi]; break; } } if (((simpld_blittingflags == (DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_SRC_PREMULTIPLY) && state->src_blend == DSBF_ONE) || (simpld_blittingflags == (DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL) && state->src_blend == DSBF_SRCALPHA)) && state->dst_blend == DSBF_INVSRCALPHA) { if (gfxs->src_format == DSPF_A8 && Bop_a8_set_alphapixel_Aop_PFI[dst_pfi]) { *funcs++ = Bop_a8_set_alphapixel_Aop_PFI[dst_pfi]; break; } if (gfxs->src_format == DSPF_A1 && Bop_a1_set_alphapixel_Aop_PFI[dst_pfi]) { *funcs++ = Bop_a1_set_alphapixel_Aop_PFI[dst_pfi]; break; } if (gfxs->src_format == DSPF_A1_LSB && Bop_a1_lsb_set_alphapixel_Aop_PFI[dst_pfi]) { *funcs++ = Bop_a1_lsb_set_alphapixel_Aop_PFI[dst_pfi]; break; } } #ifndef WORDS_BIGENDIAN if (simpld_blittingflags == DSBLIT_NOFX && source->config.format == DSPF_RGB24 && destination->config.format == DSPF_RGB16) { *funcs++ = Bop_rgb24_to_Aop_rgb16_LE; break; } if (simpld_blittingflags == DSBLIT_NOFX && (source->config.format == DSPF_RGB32 || source->config.format == DSPF_ARGB) && destination->config.format == DSPF_RGB16) { *funcs++ = Bop_rgb32_to_Aop_rgb16_LE; break; } #endif /* fall through */ case DFXL_TEXTRIANGLES: case DFXL_STRETCHBLIT: { int modulation = simpld_blittingflags & MODULATION_FLAGS; if (modulation || (accel == DFXL_TEXTRIANGLES && (src_pfi != dst_pfi || simpld_blittingflags)) || (simpld_blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) || ((simpld_blittingflags & DSBLIT_ROTATE90) && accel == DFXL_STRETCHBLIT)) { bool read_destination = false; bool source_needs_destination = false; bool scale_from_accumulator; /* Check if destination has to be read. */ if (simpld_blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { switch (state->src_blend) { case DSBF_DESTALPHA: case DSBF_DESTCOLOR: case DSBF_INVDESTALPHA: case DSBF_INVDESTCOLOR: case DSBF_SRCALPHASAT: source_needs_destination = true; default: ; } read_destination = source_needs_destination || (state->dst_blend != DSBF_ZERO) || (simpld_blittingflags & DSBLIT_XOR); } else if (simpld_blittingflags & DSBLIT_XOR) { read_destination = true; } scale_from_accumulator = !read_destination && (accel == DFXL_STRETCHBLIT); /* Read the destination if needed. */ if (read_destination) { *funcs++ = Sop_is_Aop; if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->dst_format )) *funcs++ = Slut_is_Alut; *funcs++ = Dacc_is_Aacc; *funcs++ = Sop_PFI_to_Dacc[dst_pfi]; if (dst_ycbcr) { if (destination->config.colorspace == DSCS_BT601) *funcs++ = Dacc_YCbCr_to_RGB_BT601; else if (destination->config.colorspace == DSCS_BT709) *funcs++ = Dacc_YCbCr_to_RGB_BT709; else if (destination->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_YCbCr_to_RGB_BT2020; } if (simpld_blittingflags & DSBLIT_DST_PREMULTIPLY) *funcs++ = Dacc_premultiply; } else if (scale_from_accumulator) { *funcs++ = Len_is_Slen; } /* Read the source */ *funcs++ = Sop_is_Bop; if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format )) *funcs++ = Slut_is_Blut; *funcs++ = Dacc_is_Bacc; if (accel == DFXL_TEXTRIANGLES) { if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; *funcs++ = Sop_PFI_TEX_Kto_Dacc[src_pfi]; } else { *funcs++ = Sop_PFI_TEX_to_Dacc[src_pfi]; } } else { if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; if (accel == DFXL_BLIT || scale_from_accumulator) *funcs++ = Sop_PFI_Kto_Dacc[src_pfi]; else *funcs++ = Sop_PFI_SKto_Dacc[src_pfi]; } else { if (accel == DFXL_BLIT || scale_from_accumulator) *funcs++ = Sop_PFI_to_Dacc[src_pfi]; else *funcs++ = Sop_PFI_Sto_Dacc[src_pfi]; } } if (src_ycbcr) { if (source->config.colorspace == DSCS_BT601) *funcs++ = Dacc_YCbCr_to_RGB_BT601; else if (source->config.colorspace == DSCS_BT709) *funcs++ = Dacc_YCbCr_to_RGB_BT709; else if (source->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_YCbCr_to_RGB_BT2020; } /* Premultiply color alpha. */ if (simpld_blittingflags & DSBLIT_SRC_PREMULTCOLOR) { gfxs->Cacc.RGB.a = color.a + 1; *funcs++ = Dacc_premultiply_color_alpha; } /* Modulate the source if requested. */ if (Dacc_modulation[modulation & (DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)]) { /* Modulation source. */ gfxs->Cacc.RGB.a = color.a + 1; gfxs->Cacc.RGB.r = color.r + 1; gfxs->Cacc.RGB.g = color.g + 1; gfxs->Cacc.RGB.b = color.b + 1; *funcs++ = Dacc_modulation[modulation & (DSBLIT_COLORIZE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)]; } /* Modulate the source with mask if requested. */ if (simpld_blittingflags & DSBLIT_SRC_MASK_ALPHA) { if (simpld_blittingflags & DSBLIT_SRC_MASK_COLOR) { if (Dacc_modulate_mask_argb_from_PFI[mask_pfi]) *funcs++ = Dacc_modulate_mask_argb_from_PFI[mask_pfi]; } else { if (Dacc_modulate_mask_alpha_from_PFI[mask_pfi]) *funcs++ = Dacc_modulate_mask_alpha_from_PFI[mask_pfi]; } } else if (simpld_blittingflags & DSBLIT_SRC_MASK_COLOR) { if (Dacc_modulate_mask_rgb_from_PFI[mask_pfi]) *funcs++ = Dacc_modulate_mask_rgb_from_PFI[mask_pfi]; } /* Premultiply (modulated) source alpha. */ if (simpld_blittingflags & DSBLIT_SRC_PREMULTIPLY) *funcs++ = Dacc_premultiply; /* Do blend functions and combine both accumulators. */ if (simpld_blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { *funcs++ = Sacc_is_Bacc; *funcs++ = Dacc_is_Aacc; if (source_needs_destination && state->dst_blend != DSBF_ONE) { /* Blend the destination. */ *funcs++ = Yacc_is_Aacc; *funcs++ = Xacc_is_Tacc; *funcs++ = Xacc_blend[state->dst_blend-1]; /* Blend the source. */ *funcs++ = Xacc_is_Bacc; *funcs++ = Yacc_is_Bacc; *funcs++ = Xacc_blend[state->src_blend-1]; } else { /* Blend the destination if needed. */ if (read_destination) { *funcs++ = Yacc_is_Aacc; *funcs++ = Xacc_is_Tacc; *funcs++ = Xacc_blend[state->dst_blend-1]; } /* Blend the source. */ *funcs++ = Xacc_is_Bacc; *funcs++ = Yacc_is_Bacc; *funcs++ = Xacc_blend[state->src_blend-1]; } /* Add the destination to the source. */ if (read_destination) { *funcs++ = Sacc_is_Tacc; *funcs++ = Dacc_is_Bacc; *funcs++ = Sacc_add_to_Dacc; } } if (simpld_blittingflags & DSBLIT_DEMULTIPLY) { *funcs++ = Dacc_is_Bacc; *funcs++ = Dacc_demultiply; } /* XOR source with destination. */ if (simpld_blittingflags & DSBLIT_XOR) { *funcs++ = Sacc_is_Aacc; *funcs++ = Dacc_is_Bacc; *funcs++ = Dacc_clamp; *funcs++ = Sacc_xor_Dacc; } if (dst_ycbcr) { *funcs++ = Dacc_is_Bacc; if (destination->config.colorspace == DSCS_BT601) *funcs++ = Dacc_RGB_to_YCbCr_BT601; else if (destination->config.colorspace == DSCS_BT709) *funcs++ = Dacc_RGB_to_YCbCr_BT709; else if (destination->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_RGB_to_YCbCr_BT2020; } /* Write source to destination. */ *funcs++ = Sacc_is_Bacc; if (scale_from_accumulator) { *funcs++ = Len_is_Dlen; if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Sacc_StoK_Aop_PFI[dst_pfi]; } else *funcs++ = Sacc_Sto_Aop_PFI[dst_pfi]; } else { if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Sacc_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Sacc_to_Aop_PFI[dst_pfi]; } } else if (simpld_blittingflags == DSBLIT_INDEX_TRANSLATION && DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format ) && DFB_PIXELFORMAT_IS_INDEXED( gfxs->dst_format )) { gfxs->trans = state->index_translation; gfxs->num_trans = state->num_translation; switch (gfxs->src_format) { case DSPF_LUT2: switch (gfxs->dst_format) { case DSPF_LUT8: *funcs++ = Bop_lut2_translate_to_Aop_lut8; break; default: D_ONCE( "no index translation to %s implemented", dfb_pixelformat_name( gfxs->dst_format ) ); break; } break; default: D_ONCE( "no index translation from %s implemented", dfb_pixelformat_name( gfxs->src_format ) ); break; } } else if (((gfxs->src_format == gfxs->dst_format && (!DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format ) || dfb_palette_equal( gfxs->Alut, gfxs->Blut ))) || ((gfxs->src_format == DSPF_I420 || gfxs->src_format == DSPF_YV12 || gfxs->src_format == DSPF_Y42B || gfxs->src_format == DSPF_YV16) && (gfxs->dst_format == DSPF_I420 || gfxs->dst_format == DSPF_YV12 || gfxs->dst_format == DSPF_Y42B || gfxs->dst_format == DSPF_YV16))) && (accel == DFXL_BLIT || !(simpld_blittingflags & (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL)))) { gfxs->need_accumulator = false; switch (accel) { case DFXL_BLIT: if (simpld_blittingflags & DSBLIT_SRC_COLORKEY && simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Skey = state->src_colorkey; gfxs->Dkey = state->dst_colorkey; *funcs++ = Bop_PFI_KtoK_Aop_PFI[dst_pfi]; } else if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; *funcs++ = Bop_PFI_Kto_Aop_PFI[dst_pfi]; } else if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Bop_PFI_toK_Aop_PFI[dst_pfi]; } else if (simpld_blittingflags & (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL)) { *funcs++ = Bop_PFI_toR_Aop_PFI[dst_pfi]; } else *funcs++ = Bop_PFI_to_Aop_PFI[dst_pfi]; break; case DFXL_STRETCHBLIT: if (simpld_blittingflags & DSBLIT_SRC_COLORKEY && simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Skey = state->src_colorkey; gfxs->Dkey = state->dst_colorkey; *funcs++ = Bop_PFI_SKtoK_Aop_PFI[dst_pfi]; } else if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; *funcs++ = Bop_PFI_SKto_Aop_PFI[dst_pfi]; } else if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Bop_PFI_StoK_Aop_PFI[dst_pfi]; } else *funcs++ = Bop_PFI_Sto_Aop_PFI[dst_pfi]; break; case DFXL_TEXTRIANGLES: *funcs++ = Bop_PFI_TEX_to_Aop_PFI[dst_pfi]; break; default: break; } } else { bool scale_from_accumulator = (src_ycbcr != dst_ycbcr) && (accel == DFXL_STRETCHBLIT); if (scale_from_accumulator) *funcs++ = Len_is_Slen; gfxs->Sop = gfxs->Bop; if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format )) *funcs++ = Slut_is_Blut; if (accel == DFXL_BLIT || scale_from_accumulator) { if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; *funcs++ = Sop_PFI_Kto_Dacc[src_pfi]; } else *funcs++ = Sop_PFI_to_Dacc[src_pfi]; } else { /* DFXL_STRETCHBLIT */ if (simpld_blittingflags & DSBLIT_SRC_COLORKEY) { gfxs->Skey = state->src_colorkey; *funcs++ = Sop_PFI_SKto_Dacc[src_pfi]; } else *funcs++ = Sop_PFI_Sto_Dacc[src_pfi]; } if (!src_ycbcr && dst_ycbcr) { if (DFB_COLOR_BITS_PER_PIXEL( gfxs->src_format )) { if (destination->config.colorspace == DSCS_BT601) *funcs++ = Dacc_RGB_to_YCbCr_BT601; else if (destination->config.colorspace == DSCS_BT709) *funcs++ = Dacc_RGB_to_YCbCr_BT709; else if (destination->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_RGB_to_YCbCr_BT2020; } else *funcs++ = Dacc_Alpha_to_YCbCr; } else if (src_ycbcr && !dst_ycbcr) { if (DFB_COLOR_BITS_PER_PIXEL( gfxs->dst_format )) { if (source->config.colorspace == DSCS_BT601) *funcs++ = Dacc_YCbCr_to_RGB_BT601; else if (source->config.colorspace == DSCS_BT709) *funcs++ = Dacc_YCbCr_to_RGB_BT709; else if (source->config.colorspace == DSCS_BT2020) *funcs++ = Dacc_YCbCr_to_RGB_BT2020; } } if (scale_from_accumulator) { *funcs++ = Len_is_Dlen; if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Sacc_StoK_Aop_PFI[dst_pfi]; } else *funcs++ = Sacc_Sto_Aop_PFI[dst_pfi]; } else { if (simpld_blittingflags & DSBLIT_DST_COLORKEY) { gfxs->Dkey = state->dst_colorkey; *funcs++ = Sacc_toK_Aop_PFI[dst_pfi]; } else *funcs++ = Sacc_to_Aop_PFI[dst_pfi]; } } break; } default: D_ONCE( "unimplemented drawing/blitting function" ); return false; } *funcs = NULL; dfb_state_update( state, state->flags & CSF_SOURCE_LOCKED ); return true; } bool gAcquire( CardState *state, DFBAccelerationMask accel ) { DFBResult ret; if (!gAcquireCheck( state, accel )) return false; /* Push our own identity for buffer locking calls (locality of accessor). */ Core_PushIdentity( 0 ); ret = gAcquireLockBuffers( state, accel ); if (ret) { Core_PopIdentity(); return false; } if (!gAcquireSetup( state, accel )) { gAcquireUnlockBuffers( state ); Core_PopIdentity(); return false; } return true; } void gRelease( CardState *state ) { gAcquireUnlockBuffers( state ); Core_PopIdentity(); } ================================================ FILE: src/gfx/generic/generic.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_H__ #define __GENERIC_H__ #include /**********************************************************************************************************************/ typedef void (*GenefxFunc)( GenefxState *gfxs ); typedef union { struct { u16 b; u16 g; u16 r; u16 a; } RGB; struct { u16 u; u16 v; u16 y; u16 a; } YUV; } GenefxAccumulator; struct __DFB_GenefxState { GenefxFunc funcs[32]; int length; /* span length */ int Slen; /* span length (source) */ int Dlen; /* span length (destination) */ void *dst_org[3]; void *src_org[3]; void *mask_org[3]; int dst_pitch; int src_pitch; int mask_pitch; int dst_bpp; int src_bpp; int mask_bpp; DFBSurfaceCapabilities dst_caps; DFBSurfaceCapabilities src_caps; DFBSurfaceCapabilities mask_caps; DFBSurfacePixelFormat dst_format; DFBSurfacePixelFormat src_format; DFBSurfacePixelFormat mask_format; int dst_height; int src_height; int mask_height; int dst_field_offset; int src_field_offset; int mask_field_offset; DFBColor color; /* * operands */ void *Aop[3]; void *Bop[3]; void *Mop[3]; u32 Cop; int Astep; int Bstep; u8 YCop; u8 CbCop; u8 CrCop; int Aop_field; int Bop_field; int Mop_field; int AopY; int BopY; int MopY; int s; int t; /* * color keys */ u32 Dkey; u32 Skey; /* * color lookup tables */ CorePalette *Alut; CorePalette *Blut; /* * accumulators */ void *ABstart; int ABsize; GenefxAccumulator *Aacc; GenefxAccumulator *Bacc; GenefxAccumulator *Tacc; /* for simultaneous S+D blending */ GenefxAccumulator Cacc; GenefxAccumulator SCacc; /* * dataflow control */ GenefxAccumulator *Xacc; /* writing pointer for blending */ GenefxAccumulator *Yacc; /* input pointer for blending */ GenefxAccumulator *Dacc; GenefxAccumulator *Sacc; void **Sop; CorePalette *Slut; int Ostep; /* for horizontal blitting direction */ int SperD; /* for scaled/texture routines only */ int TperD; /* for texture routines only */ int Xphase; /* initial value for fractional steps (zero if not clipped) */ bool need_accumulator; int *trans; int num_trans; }; /**********************************************************************************************************************/ void gGetDriverInfo( GraphicsDriverInfo *driver_info ); void gGetDeviceInfo( GraphicsDeviceInfo *device_info ); bool gAcquire ( CardState *state, DFBAccelerationMask accel ); void gRelease ( CardState *state ); #endif ================================================ FILE: src/gfx/generic/generic_64.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ static void Cop_to_Aop_32_64( GenefxState *gfxs ) { int l; int w = gfxs->length; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u64 DCop = ((u64) Cop << 32) | Cop; if ((long) D & 4) { *D++ = Cop; w--; } for (l = w >> 1; l; l--) { *((u64*) D) = DCop; D += 2; } if (w & 1) *D = Cop; } static void Bop_rgb32_toK_Aop_64( GenefxState *gfxs ) { int l; int w = gfxs->length; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; u64 DDkey = ((u64) Dkey << 32) | Dkey; if ((long) D & 4) { if ((*D & 0x00ffffff) == Dkey) *D = *S; S++; D++; w--; } for (l = w >> 1; l; l--) { u64 d = *((u64*) D); if ((d & 0x00ffffff00000000ull) == (DDkey & 0x00ffffff00000000ull)) { if ((d & 0x0000000000ffffffull) == (DDkey & 0x0000000000ffffffull)) { *((u64*) D) = *((u64*) S); } else { #ifdef WORDS_BIGENDIAN D[0] = S[0]; #else D[1] = S[1]; #endif } } else if ((d & 0x0000000000ffffffull) == (DDkey & 0x0000000000ffffffull)) { #ifdef WORDS_BIGENDIAN D[1] = S[1]; #else D[0] = S[0]; #endif } S += 2; D += 2; } if (w & 1) { if ((*D & 0x00ffffff) == Dkey) *D = *S; } } static void Bop_rgb32_Kto_Aop_64( GenefxState *gfxs ) { int l; int w = gfxs->length; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; u64 DSkey = ((u64) Skey << 32) | Skey; if ((long) D & 4) { if ((*S & 0x00ffffff) != Skey) *D = *S; S++; D++; w--; } for (l = w >> 1; l; l--) { u64 s = *((u64*) S); if ((s & 0x00ffffff00ffffffull) != DSkey) { if ((s & 0x00ffffff00000000ull) != (DSkey & 0x00ffffff00000000ull)) { if ((s & 0x0000000000ffffffull) != (DSkey & 0x0000000000ffffffull)) { *((u64*) D) = s; } else { #ifdef WORDS_BIGENDIAN D[0] = (u32) (s >> 32); #else D[1] = (u32) (s >> 32); #endif } } else { #ifdef WORDS_BIGENDIAN D[1] = (u32) s; #else D[0] = (u32) s; #endif } } S += 2; D += 2; } if (w & 1) { if ((*S & 0x00ffffff) != Skey) *D = *S; } } static void Bop_32_Sto_Aop_64( GenefxState *gfxs ) { int l; int w = gfxs->length; int i = 0; u32 *D = gfxs->Aop[0]; u32 *S = gfxs->Bop[0]; int SperD = gfxs->SperD; int SperD2 = SperD << 1; if ((long) D & 4) { *D++ = *S; i += SperD; w--; } for (l = w >> 1; l; l--) { #ifdef WORDS_BIGENDIAN *((u64*) D) = ((u64) S[i>>16] << 32) | S[(i+SperD)>>16]; #else *((u64*) D) = ((u64) S[(i+SperD)>>16] << 32) | S[i>>16]; #endif D += 2; i += SperD2; } if (w & 1) *D = S[i>>16]; } static void Dacc_xor_64( GenefxState *gfxs ) { int w = gfxs->length; u64 *D = (u64*) gfxs->Dacc; u64 color; #ifdef WORDS_BIGENDIAN color = ((u64) gfxs->color.b << 48) | ((u64) gfxs->color.g << 32) | ((u64) gfxs->color.r << 16) | ((u64) gfxs->color.a); #else color = ((u64) gfxs->color.a << 48) | ((u64) gfxs->color.r << 32) | ((u64) gfxs->color.g << 16) | ((u64) gfxs->color.b); #endif for (; w; w--) { *D ^= color; D++; } } ================================================ FILE: src/gfx/generic/generic_blit.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include /**********************************************************************************************************************/ typedef void (*XopAdvanceFunc)( GenefxState *gfxs ); void gBlit( CardState *state, DFBRectangle *rect, int dx, int dy ) { GenefxState *gfxs; XopAdvanceFunc Aop_advance; XopAdvanceFunc Bop_advance; int Aop_X; int Aop_Y; int Bop_X; int Bop_Y; XopAdvanceFunc Mop_advance = NULL; int Mop_X = 0; int Mop_Y = 0; int h; int mask_h; int mask_x; int mask_y; DFBSurfaceBlittingFlags rotflip_blittingflags; D_ASSERT( state != NULL ); D_ASSERT( state->gfxs != NULL ); gfxs = state->gfxs; rotflip_blittingflags = state->blittingflags; dfb_simplify_blittingflags( &rotflip_blittingflags ); rotflip_blittingflags &= (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL | DSBLIT_ROTATE90 ); if (dfb_config->software_warn) { D_WARN( "Blit (%4d,%4d-%4dx%4d) %6s, flags 0x%08x, funcs %u/%u, color 0x%02x%02x%02x%02x <- (%4d,%4d) %6s", dx, dy, rect->w, rect->h, dfb_pixelformat_name( gfxs->dst_format ), state->blittingflags, state->src_blend, state->dst_blend, state->color.a, state->color.r, state->color.g, state->color.b, rect->x, rect->y, dfb_pixelformat_name( gfxs->src_format ) ); } D_ASSERT( state->clip.x1 <= dx ); D_ASSERT( state->clip.y1 <= dy ); D_ASSERT( (rotflip_blittingflags & DSBLIT_ROTATE90) || state->clip.x2 >= (dx + rect->w - 1) ); D_ASSERT( (rotflip_blittingflags & DSBLIT_ROTATE90) || state->clip.y2 >= (dy + rect->h - 1) ); D_ASSERT( !(rotflip_blittingflags & DSBLIT_ROTATE90) || state->clip.x2 >= (dx + rect->h - 1) ); D_ASSERT( !(rotflip_blittingflags & DSBLIT_ROTATE90) || state->clip.y2 >= (dy + rect->w - 1) ); CHECK_PIPELINE(); if (!Genefx_ABacc_prepare( gfxs, rect->w )) return; switch (gfxs->src_format) { case DSPF_A4: case DSPF_YUY2: case DSPF_UYVY: rect->x &= ~1; break; default: break; } switch (gfxs->dst_format) { case DSPF_A4: case DSPF_YUY2: case DSPF_UYVY: dx &= ~1; break; default: break; } gfxs->length = rect->w; if (gfxs->src_org[0] == gfxs->dst_org[0] && dy == rect->y && dx > rect->x) /* We must blit from right to left. */ gfxs->Astep = gfxs->Bstep = -1; else /* We must blit from left to right. */ gfxs->Astep = gfxs->Bstep = 1; mask_x = mask_y = 0; if ((state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) && (state->src_mask_flags & DSMF_STENCIL)) { mask_x = state->src_mask_offset.x; mask_y = state->src_mask_offset.y; } mask_h = gfxs->mask_height; if (rotflip_blittingflags == (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL)) { gfxs->Astep *= -1; Aop_X = dx + rect->w - 1; Aop_Y = dy; Bop_X = rect->x; Bop_Y = rect->y + rect->h - 1; Aop_advance = Genefx_Aop_next; Bop_advance = Genefx_Bop_prev; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y + mask_h - 1; Mop_advance = Genefx_Mop_prev; } } else if (rotflip_blittingflags == DSBLIT_FLIP_HORIZONTAL) { gfxs->Astep *= -1; Aop_X = dx + rect->w - 1; Aop_Y = dy; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_next; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } else if (rotflip_blittingflags == DSBLIT_FLIP_VERTICAL) { Aop_X = dx; Aop_Y = dy + rect->h - 1; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_prev; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } else if (rotflip_blittingflags == (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL)) { if (gfxs->dst_bpp == 0) { D_UNIMPLEMENTED(); return; } gfxs->Astep *= gfxs->dst_pitch / gfxs->dst_bpp; Aop_X = dx; Aop_Y = dy; Bop_X = rect->x; Bop_Y = rect->y + rect->h - 1; Aop_advance = Genefx_Aop_crab; Bop_advance = Genefx_Bop_prev; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y + mask_h - 1; Mop_advance = Genefx_Mop_prev; } } else if (rotflip_blittingflags == DSBLIT_ROTATE90) { if (gfxs->dst_bpp == 0) { D_UNIMPLEMENTED(); return; } gfxs->Astep *= -gfxs->dst_pitch / gfxs->dst_bpp; Aop_X = dx; Aop_Y = dy + rect->w - 1; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_crab; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } else if (rotflip_blittingflags == (DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL)) { if (gfxs->dst_bpp == 0) { D_UNIMPLEMENTED(); return; } gfxs->Astep *= -gfxs->dst_pitch / gfxs->dst_bpp; Aop_X = dx + rect->h - 1; Aop_Y = dy + rect->w - 1; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_prev_crab; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } else if (rotflip_blittingflags == (DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL)) { if (gfxs->dst_bpp == 0) { D_UNIMPLEMENTED(); return; } gfxs->Astep *= gfxs->dst_pitch / gfxs->dst_bpp; Aop_X = dx; Aop_Y = dy; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_crab; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } else if (gfxs->src_org[0] == gfxs->dst_org[0] && dy > rect->y && !(state->blittingflags & DSBLIT_DEINTERLACE)) { /* We must blit from bottom to top. */ Aop_X = dx; Aop_Y = dy + rect->h - 1; Bop_X = rect->x; Bop_Y = rect->y + rect->h - 1; Aop_advance = Genefx_Aop_prev; Bop_advance = Genefx_Bop_prev; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y + mask_h - 1; Mop_advance = Genefx_Mop_prev; } } else { /* We must blit from top to bottom. */ Aop_X = dx; Aop_Y = dy; Bop_X = rect->x; Bop_Y = rect->y; Aop_advance = Genefx_Aop_next; Bop_advance = Genefx_Bop_next; if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_X = mask_x; Mop_Y = mask_y; Mop_advance = Genefx_Mop_next; } } Genefx_Aop_xy( gfxs, Aop_X, Aop_Y ); Genefx_Bop_xy( gfxs, Bop_X, Bop_Y ); if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) Genefx_Mop_xy( gfxs, Mop_X, Mop_Y ); if (state->blittingflags & DSBLIT_DEINTERLACE) { if (state->source->field) { Aop_advance( gfxs ); Bop_advance( gfxs ); if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) Mop_advance( gfxs ); rect->h--; } for (h = rect->h / 2; h; h--) { RUN_PIPELINE(); Aop_advance( gfxs ); RUN_PIPELINE(); Aop_advance( gfxs ); Bop_advance( gfxs ); Bop_advance( gfxs ); if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { Mop_advance( gfxs ); Mop_advance( gfxs ); } } } else { for (h = rect->h; h; h--) { RUN_PIPELINE(); Aop_advance( gfxs ); Bop_advance( gfxs ); if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) Mop_advance( gfxs ); } } Genefx_ABacc_flush( gfxs ); } ================================================ FILE: src/gfx/generic/generic_blit.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_BLIT_H__ #define __GENERIC_BLIT_H__ #include /**********************************************************************************************************************/ void gBlit( CardState *state, DFBRectangle *rect, int dx, int dy ); #endif ================================================ FILE: src/gfx/generic/generic_draw_line.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include /**********************************************************************************************************************/ void gDrawLine( CardState *state, DFBRegion *line ) { GenefxState *gfxs; int i, dx, dy, sdy, dxabs, dyabs, x, y, px, py; D_ASSERT( state != NULL ); D_ASSERT( state->gfxs != NULL ); gfxs = state->gfxs; CHECK_PIPELINE(); /* The horizontal distance of the line. */ dx = line->x2 - line->x1; dxabs = ABS( dx ); if (!Genefx_ABacc_prepare( gfxs, dxabs )) return; /* The vertical distance of the line. */ dy = line->y2 - line->y1; dyabs = ABS( dy ); /* Draw horizontal/vertical line. */ if (!dx || !dy) { DFBRectangle rect = { MIN( line->x1, line->x2 ), MIN( line->y1, line->y2 ), dxabs + 1, dyabs + 1 }; gFillRectangle( state, &rect ); return; } if (dfb_config->software_warn) { D_WARN( "DrawLine (%4d,%4d-%4d,%4d) %6s, flags 0x%08x, color 0x%02x%02x%02x%02x", DFB_RECTANGLE_VALS_FROM_REGION( line ), dfb_pixelformat_name( gfxs->dst_format ), state->drawingflags, state->color.a, state->color.r, state->color.g, state->color.b ); } sdy = SIGN( dy ) * SIGN( dx ); x = dyabs >> 1; y = dxabs >> 1; if (dx > 0) { px = line->x1; py = line->y1; } else { px = line->x2; py = line->y2; } /* The line is more horizontal than vertical. */ if (dxabs >= dyabs) { for (i = 0, gfxs->length = 1; i < dxabs; i++, gfxs->length++) { y += dyabs; if (y >= dxabs) { Genefx_Aop_xy( gfxs, px, py ); RUN_PIPELINE(); px += gfxs->length; gfxs->length = 0; y -= dxabs; py += sdy; } } Genefx_Aop_xy( gfxs, px, py ); RUN_PIPELINE(); } /* The line is more vertical than horizontal. */ else { gfxs->length = 1; Genefx_Aop_xy( gfxs, px, py ); RUN_PIPELINE(); for (i = 0; i < dyabs; i++) { x += dxabs; if (x >= dyabs) { x -= dyabs; px++; } py += sdy; Genefx_Aop_xy( gfxs, px, py ); RUN_PIPELINE(); } } Genefx_ABacc_flush( gfxs ); } ================================================ FILE: src/gfx/generic/generic_draw_line.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_DRAW_LINE_H__ #define __GENERIC_DRAW_LINE_H__ #include /**********************************************************************************************************************/ void gDrawLine( CardState *state, DFBRegion *line ); #endif ================================================ FILE: src/gfx/generic/generic_fill_rectangle.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ void gFillRectangle( CardState *state, DFBRectangle *rect ) { GenefxState *gfxs; int h; D_ASSERT( state != NULL ); D_ASSERT( state->gfxs != NULL ); D_ASSERT( state->clip.x1 <= rect->x ); D_ASSERT( state->clip.y1 <= rect->y ); D_ASSERT( state->clip.x2 >= (rect->x + rect->w - 1) ); D_ASSERT( state->clip.y2 >= (rect->y + rect->h - 1) ); gfxs = state->gfxs; if (dfb_config->software_warn) { D_WARN( "FillRectangle (%4d,%4d-%4dx%4d) %6s, flags 0x%08x, color 0x%02x%02x%02x%02x", DFB_RECTANGLE_VALS( rect ), dfb_pixelformat_name( gfxs->dst_format ), state->drawingflags, state->color.a, state->color.r, state->color.g, state->color.b ); } CHECK_PIPELINE(); if (!Genefx_ABacc_prepare( gfxs, rect->w )) return; gfxs->length = rect->w; Genefx_Aop_xy( gfxs, rect->x, rect->y ); h = rect->h; while (h--) { RUN_PIPELINE(); Genefx_Aop_next( gfxs ); } Genefx_ABacc_flush( gfxs ); } ================================================ FILE: src/gfx/generic/generic_fill_rectangle.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_FILL_RECTANGLE_H__ #define __GENERIC_FILL_RECTANGLE_H__ #include /**********************************************************************************************************************/ void gFillRectangle( CardState *state, DFBRectangle *rect ); #endif ================================================ FILE: src/gfx/generic/generic_mmx.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ static void Xacc_blend_srcalpha_MMX( GenefxState *gfxs ) { static const u32 ones[] = { 0x00010001, 0x00010001 }; static const u32 zeros[] = { 0, 0 }; __asm__ __volatile__ ( "movq %3, %%mm7\n\t" "cmp $0, %2\n\t" "jne 3f\n\t" "movq %4, %%mm6\n\t" "movd %5, %%mm0\n\t" "punpcklbw %%mm6, %%mm0\n\t" /* mm0 = 00aa 00rr 00gg 00bb */ "punpcklwd %%mm0, %%mm0\n\t" /* mm0 = 00aa 00aa xxxx xxxx */ "punpckldq %%mm0, %%mm0\n\t" /* mm0 = 00aa 00aa 00aa 00aa */ "paddw %%mm7, %%mm0\n" ".align 16\n" "4:\n\t" /* blend from color */ "testw $0xf000, 6(%0)\n\t" "jnz 6f\n\t" "movq (%0), %%mm1\n\t" "pmullw %%mm0, %%mm1\n\t" "psrlw $8, %%mm1\n\t" "movq %%mm1, (%6)\n\t" "jmp 1f\n" "6:\n\t" "movq (%0), %%mm1\n\t" "movq %%mm1, (%6)\n" "1:\n\t" "add $8, %0\n\t" "add $8, %6\n\t" "dec %1\n\t" "jnz 4b\n\t" "jmp 2f\n" ".align 16\n" "3:\n\t" /* blend from Sacc */ "testw $0xf000, 6(%0)\n\t" "jnz 5f\n\t" "movq (%2), %%mm0\n\t" "movq (%0), %%mm1\n\t" "punpckhwd %%mm0, %%mm0\n\t" /* mm2 = 00aa 00aa xxxx xxxx */ "punpckhdq %%mm0, %%mm0\n\t" /* mm2 = 00aa 00aa 00aa 00aa */ "paddw %%mm7, %%mm0\n\t" "pmullw %%mm0, %%mm1\n\t" "psrlw $8, %%mm1\n\t" "movq %%mm1, (%6)\n\t" "jmp 7f\n" "5:\n\t" "movq (%0), %%mm1\n\t" "movq %%mm1, (%6)\n" "7:\n\t" "add $8, %2\n\t" "add $8, %0\n\t" "add $8, %6\n\t" "dec %1\n\t" "jnz 3b\n" "2:\n\t" "emms" : /* no outputs */ : "D" (gfxs->Yacc), "c" (gfxs->length), "S" (gfxs->Sacc), "m" (*ones), "m" (*zeros), "m" (gfxs->color), "r" (gfxs->Xacc) : "%st", "memory" ); } static void Xacc_blend_invsrcalpha_MMX( GenefxState *gfxs ) { static const u32 ones[] = { 0x01000100, 0x01000100 }; static const u32 zeros[] = { 0, 0 }; __asm__ __volatile__ ( "movq %3, %%mm7\n\t" "cmp $0, %2\n\t" "jne 1f\n\t" "movq %4, %%mm6\n\t" "movd %5, %%mm0\n\t" "punpcklbw %%mm6, %%mm0\n\t" /* mm0 = 00aa 00rr 00gg 00bb */ "punpcklwd %%mm0, %%mm0\n\t" /* mm0 = 00aa 00aa xxxx xxxx */ "movq %%mm7, %%mm1\n\t" "punpckldq %%mm0, %%mm0\n\t" /* mm0 = 00aa 00aa 00aa 00aa */ "psubw %%mm0, %%mm1\n" ".align 16\n" "2:\n\t" /* blend from color */ "testw $0xf000, 6(%0)\n\t" "jnz 3f\n\t" "movq (%0), %%mm0\n\t" "pmullw %%mm1, %%mm0\n\t" "psrlw $8, %%mm0\n\t" "movq %%mm0, (%6)\n\t" "jmp 4f\n" "3:\n\t" "movq (%0), %%mm0\n\t" "movq %%mm0, (%6)\n" "4:\n\t" "add $8, %0\n\t" "add $8, %6\n\t" "dec %1\n\t" "jnz 2b\n\t" "jmp 9f\n" ".align 16\n" "1:\n\t" /* blend from Sacc */ "testw $0xf000, 6(%0)\n\t" "jnz 5f\n\t" "movq (%2), %%mm2\n\t" "movq (%0), %%mm0\n\t" "punpckhwd %%mm2, %%mm2\n\t" /* mm2 = 00aa 00aa xxxx xxxx */ "movq %%mm7, %%mm1\n\t" "punpckhdq %%mm2, %%mm2\n\t" /* mm2 = 00aa 00aa 00aa 00aa */ "psubw %%mm2, %%mm1\n\t" "pmullw %%mm1, %%mm0\n\t" "psrlw $8, %%mm0\n\t" "movq %%mm0, (%6)\n\t" "jmp 6f\n" "5:\n\t" "movq (%0), %%mm0\n\t" "movq %%mm0, (%6)\n" "6:\n\t" "add $8, %2\n\t" "add $8, %0\n\t" "add $8, %6\n\t" "dec %1\n\t" "jnz 1b\n" "9:\n\t" "emms" : /* no outputs */ : "D" (gfxs->Yacc), "c" (gfxs->length), "S" (gfxs->Sacc), "m" (*ones), "m" (*zeros), "m" (gfxs->color), "r" (gfxs->Xacc) : "%st", "memory" ); } static void Dacc_modulate_argb_MMX( GenefxState *gfxs ) { __asm__ __volatile__ ( "movq %2, %%mm0\n" ".align 16\n" "1:\n\t" "testw $0xf000, 6(%0)\n\t" "jnz 2f\n\t" "movq (%0), %%mm1\n\t" "pmullw %%mm0, %%mm1\n\t" "psrlw $8, %%mm1\n\t" "movq %%mm1, (%0)\n" ".align 16\n" "2:\n\t" "add $8, %0\n\t" "dec %1\n\t" "jnz 1b\n\t" "emms" : /* no outputs */ : "D" (gfxs->Dacc), "c" (gfxs->length), "m" (gfxs->Cacc) : "%st", "memory" ); } static void SCacc_add_to_Dacc_MMX( GenefxState *gfxs ) { __asm__ __volatile__ ( "movq %2, %%mm0\n" ".align 16\n" "1:\n\t" "movq (%0), %%mm1\n\t" "paddw %%mm0, %%mm1\n\t" "movq %%mm1, (%0)\n\t" "add $8, %0\n\t" "dec %1\n\t" "jnz 1b\n\t" "emms" : /* no outputs */ : "D" (gfxs->Dacc), "c" (gfxs->length), "m" (gfxs->SCacc) : "%st", "memory" ); } static void Sacc_add_to_Dacc_MMX( GenefxState *gfxs ) { __asm__ __volatile__ ( ".align 16\n" "1:\n\t" "movq (%2), %%mm0\n\t" "movq (%0), %%mm1\n\t" "paddw %%mm1, %%mm0\n\t" "movq %%mm0, (%0)\n\t" "add $8, %0\n\t" "add $8, %2\n\t" "dec %1\n\t" "jnz 1b\n\t" "emms" : /* no outputs */ : "D" (gfxs->Dacc), "c" (gfxs->length), "S" (gfxs->Sacc) : "%st", "memory" ); } ================================================ FILE: src/gfx/generic/generic_neon.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ static void Sop_rgb16_to_Dacc_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int Ostep = gfxs->Ostep; #define EXPAND_Rto8(r) (((r) << 3) | ((r) >> 2)) #define EXPAND_Gto8(g) (((g) << 2) | ((g) >> 4)) #define EXPAND_Bto8(b) (((b) << 3) | ((b) >> 2)) #define EXPAND(d,s) do { \ (d).RGB.a = 0xff; \ (d).RGB.r = EXPAND_Rto8( (s & 0xf800) >> 11 ); \ (d).RGB.g = EXPAND_Gto8( (s & 0x07e0) >> 5 ); \ (d).RGB.b = EXPAND_Bto8( s & 0x001f ); \ } while (0) if (Ostep != 1) { while (w--) { u16 s = *S; EXPAND( *D, s ); S += Ostep; ++D; } return; } l = w & 0x7; while (l) { u16 s = *S; EXPAND( *D, s ); ++S; ++D; --l; } l = w >> 3; if (l) { __asm__ __volatile__ ( "1:\n\t" "pld [%[S], #0xC0]\n\t" "vld1.16 {q0}, [%[S]]!\n\t" "vmov.i16 q4, #0x00FF\n\t" "vshr.u16 q3, q0, #8\n\t" "vsri.u8 q3, q3, #5\n\t" "vshl.u16 q2, q0, #5\n\t" "vshl.u16 q1, q0, #11\n\t" "vshr.u16 q2, q2, #8\n\t" "vshr.u16 q1, q1, #8\n\t" "vsri.u8 q2, q2, #6\n\t" "vsri.u8 q1, q1, #5\n\t" "vst4.16 {d2, d4, d6, d8}, [%[D]]!\n\t" "vst4.16 {d3, d5, d7, d9}, [%[D]]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [S] "r" (S), [D] "r" (D), [l] "r" (l) : "memory", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9" ); } #undef EXPAND #undef EXPAND_Rto8 #undef EXPAND_Gto8 #undef EXPAND_Bto8 } static void Sop_argb_to_Dacc_NEON( GenefxState *gfxs ) { int w = gfxs->length; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int Ostep = gfxs->Ostep; __asm__ __volatile__ ( "mov r5, %[w]\n\t" "cmp %[Ostep], #1\n\t" /* Ostep != 1 */ "bne 1f\n\t" "lsrs r4, %[w], #3\n\t" /* Ostep = 1 && w < 8 */ "beq 1f\n\t" /* Ostep = 1 && w >= 8 */ "2:\n\t" "pld [%[S], #0xC0] \n\t" "vld4.8 {d0, d1, d2, d3}, [%[S]]!\n\t" "vmovl.u8 q2, d0\n\t" "vmovl.u8 q3, d1\n\t" "vmovl.u8 q4, d2\n\t" "vmovl.u8 q5, d3\n\t" "vst4.16 {d4, d6, d8, d10}, [%[D]]!\n\t" "vst4.16 {d5, d7, d9, d11}, [%[D]]!\n\t" "subs r4, r4, #1\n\t" "bne 2b\n\t" "ands r5, %[w], #7\n\t" /* Ostep = 1 && w = 8 */ "beq 5f\n\t" "1:\n\t" "lsl r6, %[Ostep], #2\n\t" "vmov.i32 d0, #0\n\t" "vmov d1, d0\n\t" "vmov d2, d0\n\t" "vmov d3, d0\n\t" "lsrs r4, r5, #2\n\t" /* w < 4 */ "beq 4f\n\t" /* w >= 4 */ "3:\n\t" "pld [%[S], #0xC0]\n\t" "vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [%[S]],r6\n\t" "vld4.8 {d0[2], d1[2], d2[2], d3[2]}, [%[S]],r6\n\t" "vld4.8 {d0[4], d1[4], d2[4], d3[4]}, [%[S]],r6\n\t" "vld4.8 {d0[6], d1[6], d2[6], d3[6]}, [%[S]],r6\n\t" "vst4.16 {d0, d1, d2, d3}, [%[D]]!\n\t" "subs r4, r4, #1\n\t" "bne 3b\n\t" "ands r5, %[w], #3\n\t" /* w = 4 */ "beq 5f\n\t" "4:\n\t" "vld4.8 {d0[0], d1[0], d2[0], d3[0]}, [%[S]],r6\n\t" "vst4.16 {d0[0], d1[0], d2[0], d3[0]}, [%[D]]!\n\t" "subs r5, r5, #1\n\t" "bne 4b\n\t" "5:" : /* no outputs */ : [S] "r" (S), [D] "r" (D), [w] "r" (w), [Ostep] "r" (Ostep) : "memory", "r4", "r5", "r6", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11" ); } static void Sacc_to_Aop_rgb16_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; u32 mask = 0xff00ff00; u32 color = 0x00ff00ff; #define PIXEL_OUT(r,g,b) ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) #define PIXEL(x) PIXEL_OUT( ((x).RGB.r & 0xff00) ? 0xff : (x).RGB.r, \ ((x).RGB.g & 0xff00) ? 0xff : (x).RGB.g, \ ((x).RGB.b & 0xff00) ? 0xff : (x).RGB.b ) if (Dstep != 1) { while (w--) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++S; D += Dstep; } return; } if ((long) D & 2) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++S; ++D; --w; } l = w >> 3; while (l) { int i; for (i = 0; i < 8; i++) { if (S[i].RGB.a & 0xf000) break; } if (i < 8) { int j; for (j = 0; j < i; j++) D[j] = PIXEL( S[j] ); for (j = i + 1; j < 8; j++) { if (!(S[j].RGB.a & 0xf000)) D[j] = PIXEL( S[j] ); } } else { __asm__ __volatile__ ( "mov r4, %[S]\n\t" "pld [r4, #0xC0]\n\t" "pld [r4, #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [r4]!\n\t" "vld4.16 {d1, d3, d5, d7}, [r4]\n\t" "vdup.32 q3, %[mask]\n\t" "vdup.32 q4, %[color]\n\t" /* b */ "vtst.16 q5, q0, q3\n\t" "vceq.u16 q6, q5, #0\n\t" "vand.16 q5, q4, q5\n\t" "vand.16 q6, q0, q6\n\t" "vorr.16 q0, q5, q6\n\t" "vshr.u16 q0, q0, #3\n\t" /* g */ "vtst.16 q5, q1, q3\n\t" "vceq.u16 q6, q5, #0\n\t" "vand.16 q5, q4, q5\n\t" "vand.16 q6, q1, q6\n\t" "vorr.16 q1, q5, q6\n\t" "vshr.u16 q1, q1, #2\n\t" "vshl.u16 q1, q1, #5\n\t" /* r */ "vtst.16 q5, q2, q3\n\t" "vceq.u16 q6, q5, #0\n\t" "vand.16 q5, q4, q5\n\t" "vand.16 q6, q2, q6\n\t" "vorr.16 q2, q5, q6\n\t" "vshr.u16 q2, q2, #3\n\t" "vshl.u16 q2, q2, #11\n\t" /* rgb */ "vorr.16 q1, q1, q2\n\t" "vorr.16 q0, q0, q1\n\t" "vst1.16 {d0, d1}, [%[D]]" : /* no outputs */ : [D] "r" (D), [S] "r" (S), [mask] "r" (mask), [color] "r" (color) : "memory", "r4", "d0", "d1", "d2", "d3", "d4","d5", "d6", "d7" ); } S += 8; D += 8; --l; } l = w & 0x7; while (l) { if (!(S->RGB.a & 0xf000)) { *D = PIXEL( *S ); } ++S; ++D; --l; } #undef PIXEL #undef PIXEL_OUT } static void Bop_argb_blend_alphachannel_src_invsrc_Aop_rgb16_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; u32 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 f0 = 0xf81f; u16 f1 = 0x07e0; u32 vf[4] = { 0x0000f800, 0x0000001f, 0x003e07c0, 0x0001f800 }; #define SET_PIXEL(d,s) \ switch (s >> 26) { \ case 0: \ break; \ case 0x3f: \ d = ((s & 0x00f80000) >> 8) | ((s & 0x0000fc00) >> 5) | ((s & 0x000000f8) >> 3); \ break; \ default: \ d = (((((((s >> 8) & 0xf800) | ((s >> 3) & 0x001f)) - (d & 0xf81f)) * ((s >> 26) + 1) + \ ((d & 0xf81f) << 6) ) & 0x003e07c0) + \ ((((( s >> 5) & 0x07e0) - (d & 0x07e0)) * ((s >> 26) + 1) + \ ((d & 0x07e0) << 6) ) & 0x0001f800) \ ) >> 6; \ } l = w & 3; while (l) { SET_PIXEL( *D, *S ); ++S; ++D; --l; } __asm__ __volatile__ ( "vld1.32 {d0, d1}, [%[vf]]\n\t" "vdup.32 q1, d0[0]\n\t" "vdup.32 q2, d0[1]\n\t" "vdup.32 q3, %[f0]\n\t" "vdup.32 q4, d1[0]\n\t" "vdup.32 q5, %[f1]\n\t" "vdup.32 q6, d1[1]\n\t" "vmov.i32 q11, #0x1\n\t" : /* no outputs */ : [vf] "r" (vf), [f0] "r" (f0), [f1] "r" (f1) : "memory", "d0", "d1" ); l = w >> 2; while (l) { int i; u32 valpha = 0; bool a_flag = false; for (i = 0; i < 4; i++) { u32 alpha; alpha = S[i] >> 26; valpha |= alpha << (i << 3); a_flag = a_flag || (alpha == 0) || (alpha == 0x3f); } switch (valpha) { case 0: break; case 0x3f3f3f3f: __asm__ __volatile__ ( "pld [%[S], #0xC0]\n\t" "vld1.32 {d0, d1}, [%[S]]\n\t" "vshr.u32 q7, q0, #19\n\t" "vshr.u16 q8, q0, #10\n\t" "vshl.u16 q9, q0, #8\n\t" "vshl.u16 q7, q7, #11\n\t" "vshl.u16 q8, q8, #5\n\t" "vshr.u16 q9, q9, #11\n\t" "vorr q7, q7, q8\n\t" "vorr q7, q7, q9\n\t" "vmovn.i32 d14, q7\n\t" "vst1.16 {d14}, [%[D]]" : /* no outputs */ : [S] "r" (S), [D] "r" (D) : "memory", "d0", "d1", "d14" ); break; default: if (a_flag) { for (i = 0; i < 4; i++) SET_PIXEL( D[i], S[i] ); } else { __asm__ __volatile__ ( "pld [%[D], #0xC0]\n\t" "pld [%[S], #0xC0]\n\t" "vld1.16 {d14}, [%[D]]\n\t" "vld1.32 {d0, d1}, [%[S]]\n\t" "vmovl.u16 q7, d14\n\t" "vshr.u32 q8, q0, #8\n\t" "vand q8, q8, q1\n\t" "vshr.u32 q9, q0, #3\n\t" "vand q9, q9, q2\n\t" "vorr q8, q8, q9\n\t" "vand q9, q7, q3\n\t" "vsub.i32 q8, q8, q9\n\t" "vshr.u32 q10, q0, #26\n\t" "vadd.i32 q10, q10, q11\n\t" "vmul.i32 q8, q8, q10\n\t" "vshl.u32 q9, q9, #6\n\t" "vadd.i32 q8, q8, q9\n\t" "vand q8, q8, q4\n\t" "vshr.u32 q12, q0, #5\n\t" "vand q12, q12, q5\n\t" "vand q13, q7, q5\n\t" "vsub.i32 q12, q12, q13\n\t" "vmul.i32 q12, q12, q10\n\t" "vshl.u32 q13, q13, #6\n\t" "vadd.i32 q12, q12, q13\n\t" "vand q12, q12, q6\n\t" "vadd.i32 q8, q8, q12\n\t" "vshrn.u32 d16, q8, #6\n\t" "vst1.16 {d16}, [%[D]]" : /* no outputs */ : [S] "r" (S), [D] "r" (D) : "memory", "d0", "d1", "d14", "d16" ); } break; } S += 4; D += 4; --l; } } static void Xacc_blend_srcalpha_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; u16 mask = 0xf000; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; u16 sadd = 1; l = w >> 3; if (l) { __asm__ __volatile__ ( "vdup.16 q8, %[mask]\n\t" "vdup.16 q9, %[sadd]\n\t" "1:\n\t" "pld [%[Y], #0xC0]\n\t" "pld [%[Y], #0x100]\n\t" "pld [%[S], #0xC0]\n\t" "pld [%[S], #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [%[Y]]!\n\t" "vld4.16 {d1, d3, d5, d7}, [%[Y]]!\n\t" "vld4.16 {d8, d10, d12, d14}, [%[S]]!\n\t" "vld4.16 {d9, d11, d13, d15}, [%[S]]!\n\t" "vand q4, q3, q8\n\t" "vceq.i16 q4, q4, #0\n\t" "vadd.i16 q5, q9, q7\n\t" /* b */ "vmull.u16 q6, d10, d0\n\t" "vshrn.i32 d20, q6, #8\n\t" "vmull.u16 q6, d11, d1\n\t" "vshrn.i32 d21, q6, #8\n\t" /* g */ "vmull.u16 q6, d10, d2\n\t" "vshrn.i32 d22, q6, #8\n\t" "vmull.u16 q6, d11, d3\n\t" "vshrn.i32 d23, q6, #8\n\t" /* r */ "vmull.u16 q6, d10, d4\n\t" "vshrn.i32 d24, q6, #8\n\t" "vmull.u16 q6, d11, d5\n\t" "vshrn.i32 d25, q6, #8\n\t" /* a */ "vmull.u16 q6, d10, d6\n\t" "vshrn.i32 d26, q6, #8\n\t" "vmull.u16 q6, d11, d7\n\t" "vshrn.i32 d27, q6, #8\n\t" /* if (!(Y->RGB.a & 0xf000)) */ "vand q10, q4, q10\n\t" "vand q11, q4, q11\n\t" "vand q12, q4, q12\n\t" "vand q13, q4, q13\n\t" /* if ((Y->RGB.a & 0xf000)) */ "vceq.i16 q4, q4, #0\n\t" "vand q0, q4, q0\n\t" "vand q1, q4, q1\n\t" "vand q2, q4, q2\n\t" "vand q3, q4, q3\n\t" /* X: q0(b), q1(g), q2(r), q3(a) */ "vorr q0, q0, q10\n\t" "vorr q1, q1, q11\n\t" "vorr q2, q2, q12\n\t" "vorr q3, q3, q13\n\t" "vst4.16 {d0, d2, d4, d6}, [%[X]]!\n\t" "vst4.16 {d1, d3, d5, d7}, [%[X]]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [X] "r" (X), [Y] "r" (Y), [S] "r" (S), [mask] "r" (mask), [sadd] "r" (sadd), [l] "r" (l) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" ); } l = w & 0x7; while (l) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = S->RGB.a + 1; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; --l; } } else { u16 Sa = gfxs->color.a + 1; l = w >> 3; if (l) { __asm__ __volatile__ ( "vdup.16 q7, %[mask]\n\t" "vdup.16 q5, %[Sa]\n\t" "1:\n\t" "pld [%[Y], #0xC0]\n\t" "pld [%[Y], #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [%[Y]]!\n\t" "vld4.16 {d1, d3, d5, d7}, [%[Y]]!\n\t" "vand q4, q3, q7\n\t" "vceq.i16 q4, q4, #0\n\t" /* b */ "vmull.u16 q6, d10, d0\n\t" "vshrn.i32 d20, q6, #8\n\t" "vmull.u16 q6, d11, d1\n\t" "vshrn.i32 d21, q6, #8\n\t" /* g */ "vmull.u16 q6, d10, d2\n\t" "vshrn.i32 d22, q6, #8\n\t" "vmull.u16 q6, d11, d3\n\t" "vshrn.i32 d23, q6, #8\n\t" /* r */ "vmull.u16 q6, d10, d4\n\t" "vshrn.i32 d24, q6, #8\n\t" "vmull.u16 q6, d11, d5\n\t" "vshrn.i32 d25, q6, #8\n\t" /* a */ "vmull.u16 q6, d10, d6\n\t" "vshrn.i32 d26, q6, #8\n\t" "vmull.u16 q6, d11, d7\n\t" "vshrn.i32 d27, q6, #8\n\t" /* if (!(Y->RGB.a & 0xf000)) */ "vand q10, q4, q10\n\t" "vand q11, q4, q11\n\t" "vand q12, q4, q12\n\t" "vand q13, q4, q13\n\t" /* if ((Y->RGB.a & 0xf000)) */ "vceq.i16 q4, q4, #0\n\t" "vand q0, q4, q0\n\t" "vand q1, q4, q1\n\t" "vand q2, q4, q2\n\t" "vand q3, q4, q3\n\t" /* X: q0(b), q1(g), q2(r), q3(a) */ "vorr q0, q0, q10\n\t" "vorr q1, q1, q11\n\t" "vorr q2, q2, q12\n\t" "vorr q3, q3, q13\n\t" "vst4.16 {d0, d2, d4, d6}, [%[X]]!\n\t" "vst4.16 {d1, d3, d5, d7}, [%[X]]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [X] "r" (X), [Y] "r" (Y), [Sa] "r" (Sa), [mask] "r" (mask), [l] "r" (l) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d10", "d11", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" ); } l = w & 0x7; while (l) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++X; ++Y; --l; } } } static void Xacc_blend_invsrcalpha_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *X = gfxs->Xacc; GenefxAccumulator *Y = gfxs->Yacc; u16 mask = 0xf000; if (gfxs->Sacc) { GenefxAccumulator *S = gfxs->Sacc; u16 inv = 0x100; l = w >> 3; if (l) { __asm__ __volatile__ ( "vdup.16 q8, %[mask]\n\t" "vdup.16 q9, %[inv]\n\t" "1:\n\t" "pld [%[Y], #0xC0]\n\t" "pld [%[Y], #0x100]\n\t" "pld [%[S], #0xC0]\n\t" "pld [%[S], #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [%[Y]]!\n\t" "vld4.16 {d1, d3, d5, d7}, [%[Y]]!\n\t" "vld4.16 {d8, d10, d12, d14}, [%[S]]!\n\t" "vld4.16 {d9, d11, d13, d15}, [%[S]]!\n\t" "vand q4, q3, q8\n\t" "vceq.i16 q4, q4, #0\n\t" "vsub.i16 q5, q9, q7\n\t" /* b */ "vmull.u16 q6, d10, d0\n\t" "vshrn.i32 d20, q6, #8\n\t" "vmull.u16 q6, d11, d1\n\t" "vshrn.i32 d21, q6, #8\n\t" /* g */ "vmull.u16 q6, d10, d2\n\t" "vshrn.i32 d22, q6, #8\n\t" "vmull.u16 q6, d11, d3\n\t" "vshrn.i32 d23, q6, #8\n\t" /* r */ "vmull.u16 q6, d10, d4\n\t" "vshrn.i32 d24, q6, #8\n\t" "vmull.u16 q6, d11, d5\n\t" "vshrn.i32 d25, q6, #8\n\t" /* a */ "vmull.u16 q6, d10, d6\n\t" "vshrn.i32 d26, q6, #8\n\t" "vmull.u16 q6, d11, d7\n\t" "vshrn.i32 d27, q6, #8\n\t" /* if (!(Y->RGB.a & 0xf000)) */ "vand q10, q4, q10\n\t" "vand q11, q4, q11\n\t" "vand q12, q4, q12\n\t" "vand q13, q4, q13\n\t" /* if ((Y->RGB.a & 0xf000)) */ "vceq.i16 q4, q4, #0\n\t" "vand q0, q4, q0\n\t" "vand q1, q4, q1\n\t" "vand q2, q4, q2\n\t" "vand q3, q4, q3\n\t" /* X: q0(b), q1(g), q2(r), q3(a) */ "vorr q0, q0, q10\n\t" "vorr q1, q1, q11\n\t" "vorr q2, q2, q12\n\t" "vorr q3, q3, q13\n\t" "vst4.16 {d0, d2, d4, d6}, [%[X]]!\n\t" "vst4.16 {d1, d3, d5, d7}, [%[X]]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [X] "r" (X), [Y] "r" (Y), [S] "r" (S), [mask] "r" (mask), [inv] "r" (inv), [l] "r" (l) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" ); } l = w & 0x7; while (l) { if (!(Y->RGB.a & 0xf000)) { u16 Sa = 0x100 - S->RGB.a; X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++S; ++X; ++Y; --l; } } else { u16 Sa = 0x100 - gfxs->color.a; l = w >> 3; if (l) { __asm__ __volatile__ ( "vdup.16 q7, %[mask]\n\t" "vdup.16 q5, %[Sa]\n\t" "1:\n\t" "pld [%[Y], #0xC0]\n\t" "pld [%[Y], #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [%[Y]]!\n\t" "vld4.16 {d1, d3, d5, d7}, [%[Y]]!\n\t" "vand q4, q3, q7\n\t" "vceq.i16 q4, q4, #0\n\t" /* b */ "vmull.u16 q6, d10, d0\n\t" "vshrn.i32 d20, q6, #8\n\t" "vmull.u16 q6, d11, d1\n\t" "vshrn.i32 d21, q6, #8\n\t" /* g */ "vmull.u16 q6, d10, d2\n\t" "vshrn.i32 d22, q6, #8\n\t" "vmull.u16 q6, d11, d3\n\t" "vshrn.i32 d23, q6, #8\n\t" /* r */ "vmull.u16 q6, d10, d4\n\t" "vshrn.i32 d24, q6, #8\n\t" "vmull.u16 q6, d11, d5\n\t" "vshrn.i32 d25, q6, #8\n\t" /* a */ "vmull.u16 q6, d10, d6\n\t" "vshrn.i32 d26, q6, #8\n\t" "vmull.u16 q6, d11, d7\n\t" "vshrn.i32 d27, q6, #8\n\t" /* if (!(Y->RGB.a & 0xf000)) */ "vand q10, q4, q10\n\t" "vand q11, q4, q11\n\t" "vand q12, q4, q12\n\t" "vand q13, q4, q13\n\t" /* if ((Y->RGB.a & 0xf000)) */ "vceq.i16 q4, q4, #0\n\t" "vand q0, q4, q0\n\t" "vand q1, q4, q1\n\t" "vand q2, q4, q2\n\t" "vand q3, q4, q3\n\t" /* X: q0(b), q1(g), q2(r), q3(a) */ "vorr q0, q0, q10\n\t" "vorr q1, q1, q11\n\t" "vorr q2, q2, q12\n\t" "vorr q3, q3, q13\n\t" "vst4.16 {d0, d2, d4, d6}, [%[X]]!\n\t" "vst4.16 {d1, d3, d5, d7}, [%[X]]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [X] "r" (X), [Y] "r" (Y), [Sa] "r" (Sa), [mask] "r" (mask), [l] "r" (l) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d10", "d11", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" ); } l = w & 0x7; while (l) { if (!(Y->RGB.a & 0xf000)) { X->RGB.r = (Sa * Y->RGB.r) >> 8; X->RGB.g = (Sa * Y->RGB.g) >> 8; X->RGB.b = (Sa * Y->RGB.b) >> 8; X->RGB.a = (Sa * Y->RGB.a) >> 8; } else *X = *Y; ++X; ++Y; --l; } } } static void Dacc_modulate_rgb_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; u16 mask = 0xf000; l = w & 0x7; while (l) { if (!(D->RGB.a & 0xf000)) { D->RGB.r = (Cacc.RGB.r * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.g * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.b * D->RGB.b) >> 8; } ++D; --l; } l = w >> 3; if (l) { __asm__ __volatile__ ( "mov r4, %[D]\n\t" "mov r5, %[D]\n\t" "vdup.16 q2, %[Cacc_r]\n\t" "vdup.16 q1, %[Cacc_g]\n\t" "vdup.16 q0, %[Cacc_b]\n\t" "vdup.16 q8, %[mask]\n\t" "1:\n\t" "pld [r4, #0xC0]\n\t" "pld [r4, #0x100]\n\t" "vld4.16 {d8, d10, d12, d14}, [r4]!\n\t" "vld4.16 {d9, d11, d13, d15}, [r4]!\n\t" "vand q9, q7, q8\n\t" "vceq.i16 q9, q9, #0\n\t" /* b */ "vmull.u16 q3, d8, d0\n\t" "vshrn.i32 d20, q3, #8\n\t" "vmull.u16 q3, d9, d1\n\t" "vshrn.i32 d21, q3, #8\n\t" /* g */ "vmull.u16 q3, d10, d2\n\t" "vshrn.i32 d22, q3, #8\n\t" "vmull.u16 q3, d11, d3\n\t" "vshrn.i32 d23, q3, #8\n\t" /* r */ "vmull.u16 q3, d12, d4\n\t" "vshrn.i32 d24, q3, #8\n\t" "vmull.u16 q3, d13, d5\n\t" "vshrn.i32 d25, q3, #8\n\t" /* if (!(D->RGB.a & 0xf000)) */ "vand q10, q9, q10\n\t" "vand q11, q9, q11\n\t" "vand q12, q9, q12\n\t" /* if ((D->RGB.a & 0xf000)) */ "vceq.i16 q9, q9, #0\n\t" "vand q4, q9, q4\n\t" "vand q5, q9, q5\n\t" "vand q6, q9, q6\n\t" /* D: q4(b), q5(g), q6(r), q7(a) */ "vorr q4, q4, q10\n\t" "vorr q5, q5, q11\n\t" "vorr q6, q6, q12\n\t" "vst4.16 {d8, d10, d12, d14}, [r5]!\n\t" "vst4.16 {d9, d11, d13, d15}, [r5]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [Cacc_r] "r" (Cacc.RGB.r), [Cacc_g] "r" (Cacc.RGB.g), [Cacc_b] "r" (Cacc.RGB.b), [D] "r" (D), [mask] "r" (mask), [l] "r" (l) : "memory", "r4", "r5", "d0", "d1", "d2", "d3", "d4", "d5", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d20", "d21", "d22", "d23", "d24", "d25" ); } } static void Dacc_modulate_argb_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator Cacc = gfxs->Cacc; u16 mask = 0xf000; l = w & 0x7; while (l) { if (!(D->RGB.a & 0xf000)) { D->RGB.a = (Cacc.RGB.a * D->RGB.a) >> 8; D->RGB.r = (Cacc.RGB.r * D->RGB.r) >> 8; D->RGB.g = (Cacc.RGB.g * D->RGB.g) >> 8; D->RGB.b = (Cacc.RGB.b * D->RGB.b) >> 8; } ++D; --l; } l = w >> 3; if (l) { __asm__ __volatile__ ( "mov r4, %[D]\n\t" "mov r5, %[D]\n\t" "vdup.16 q3, %[Cacc_a]\n\t" "vdup.16 q2, %[Cacc_r]\n\t" "vdup.16 q1, %[Cacc_g]\n\t" "vdup.16 q0, %[Cacc_b]\n\t" "vdup.16 q8, %[mask]\n\t" "1:\n\t" "pld [r4, #0xC0]\n\t" "pld [r4, #0x100]\n\t" "vld4.16 {d8, d10, d12, d14}, [r4]!\n\t" "vld4.16 {d9, d11, d13, d15}, [r4]!\n\t" "vand q9, q7, q8\n\t" "vceq.i16 q9, q9, #0\n\t" /* b */ "vmull.u16 q14, d8, d0\n\t" "vshrn.i32 d20, q14, #8\n\t" "vmull.u16 q14, d9, d1\n\t" "vshrn.i32 d21, q14, #8\n\t" /* g */ "vmull.u16 q14, d10, d2\n\t" "vshrn.i32 d22, q14, #8\n\t" "vmull.u16 q14, d11, d3\n\t" "vshrn.i32 d23, q14, #8\n\t" /* r */ "vmull.u16 q14, d12, d4\n\t" "vshrn.i32 d24, q14, #8\n\t" "vmull.u16 q14, d13, d5\n\t" "vshrn.i32 d25, q14, #8\n\t" /* a */ "vmull.u16 q14, d14, d6\n\t" "vshrn.i32 d26, q14, #8\n\t" "vmull.u16 q14, d15, d7\n\t" "vshrn.i32 d27, q14, #8\n\t" /* if (!(D->RGB.a & 0xf000)) */ "vand q10, q9, q10\n\t" "vand q11, q9, q11\n\t" "vand q12, q9, q12\n\t" "vand q13, q9, q13\n\t" /* if ((D->RGB.a & 0xf000)) */ "vceq.i16 q9, q9, #0\n\t" "vand q4, q9, q4\n\t" "vand q5, q9, q5\n\t" "vand q6, q9, q6\n\t" "vand q7, q9, q7\n\t" /* D: q4(b), q5(g), q6(r), q7(a) */ "vorr q4, q4, q10\n\t" "vorr q5, q5, q11\n\t" "vorr q6, q6, q12\n\t" "vorr q7, q7, q13\n\t" "vst4.16 {d8, d10, d12, d14}, [r5]!\n\t" "vst4.16 {d9, d11, d13, d15}, [r5]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [Cacc_a] "r" (Cacc.RGB.a), [Cacc_r] "r" (Cacc.RGB.r), [Cacc_g] "r" (Cacc.RGB.g), [Cacc_b] "r" (Cacc.RGB.b), [D] "r" (D), [mask] "r" (mask), [l] "r" (l) : "memory", "r4", "r5", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" ); } } static void SCacc_add_to_Dacc_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator SCacc = gfxs->SCacc; u16 mask = 0xf000; l = w & 0x7; while (l) { if (!(D->RGB.a & 0xf000)) { D->RGB.a += SCacc.RGB.a; D->RGB.r += SCacc.RGB.r; D->RGB.g += SCacc.RGB.g; D->RGB.b += SCacc.RGB.b; } ++D; --l; } l = w >> 3; if (l) { __asm__ __volatile__ ( "mov r4, %[D]\n\t" "mov r5, %[D]\n\t" "vdup.16 q3, %[SCacc_a]\n\t" "vdup.16 q2, %[SCacc_r]\n\t" "vdup.16 q1, %[SCacc_g]\n\t" "vdup.16 q0, %[SCacc_b]\n\t" "vdup.16 q8, %[mask]\n\t" "1:\n\t" "pld [r4, #0xC0]\n\t" "pld [r4, #0x100]\n\t" "vld4.16 {d8, d10, d12, d14}, [r4]!\n\t" "vld4.16 {d9, d11, d13, d15}, [r4]!\n\t" "vand q9, q7, q8\n\t" "vceq.i16 q9, q9, #0\n\t" "vand q10, q9, q0\n\t" "vand q11, q9, q1\n\t" "vand q12, q9, q2\n\t" "vand q13, q9, q3\n\t" "vadd.i16 q4, q4, q10\n\t" "vadd.i16 q5, q5, q11\n\t" "vadd.i16 q6, q6, q12\n\t" "vadd.i16 q7, q7, q13\n\t" "vst4.16 {d8, d10, d12, d14}, [r5]!\n\t" "vst4.16 {d9, d11, d13, d15}, [r5]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [SCacc_a] "r" (gfxs->SCacc.RGB.a), [SCacc_r] "r" (gfxs->SCacc.RGB.r), [SCacc_g] "r" (gfxs->SCacc.RGB.g), [SCacc_b] "r" (gfxs->SCacc.RGB.b), [D] "r" (D), [mask] "r" (mask), [l] "r" (l) : "memory", "r4", "r5", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15" ); } } static void Sacc_add_to_Dacc_NEON( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *D = gfxs->Dacc; GenefxAccumulator *S = gfxs->Sacc; u16 mask = 0xf000; l = w & 0x7; while (l) { if (!(D->RGB.a & 0xf000)) { D->RGB.a += S->RGB.a; D->RGB.r += S->RGB.r; D->RGB.g += S->RGB.g; D->RGB.b += S->RGB.b; } ++S; ++D; --l; } l = w >> 3; if (l) { __asm__ __volatile__ ( "mov r4, %[D]\n\t" "mov r5, %[S]\n\t" "mov r6, %[D]\n\t" "vdup.16 q8, %[mask]\n\t" "1:\n\t" "pld [r4, #0xC0]\n\t" "pld [r4, #0x100]\n\t" "vld4.16 {d8, d10, d12, d14}, [r4]!\n\t" "vld4.16 {d9, d11, d13, d15}, [r4]!\n\t" "pld [r5, #0xC0]\n\t" "pld [r5, #0x100]\n\t" "vld4.16 {d0, d2, d4, d6}, [r5]!\n\t" "vld4.16 {d1, d3, d5, d7}, [r5]!\n\t" "vand q9, q7, q8\n\t" "vceq.i16 q9, q9, #0\n\t" "vand q0, q9, q0\n\t" "vand q1, q9, q1\n\t" "vand q2, q9, q2\n\t" "vand q3, q9, q3\n\t" "vadd.i16 q4, q4, q0\n\t" "vadd.i16 q5, q5, q1\n\t" "vadd.i16 q6, q6, q2\n\t" "vadd.i16 q7, q7, q3\n\t" "vst4.16 {d8, d10, d12, d14}, [r6]!\n\t" "vst4.16 {d9, d11, d13, d15}, [r6]!\n\t" "subs %[l], %[l], #1\n\t" "bne 1b" : /* no outputs */ : [S] "r" (S), [D] "r" (D), [mask] "r" (mask), [l] "r" (l) : "memory", "r4", "r5", "r6", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15" ); } } ================================================ FILE: src/gfx/generic/generic_stretch_blit.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include /**********************************************************************************************************************/ #if DFB_SMOOTH_SCALING typedef struct { DFBRegion clip; const void *colors; unsigned long protect; unsigned long key; } StretchCtx; typedef void (*StretchHVx)( void *dst, int dpitch, const void *src, int spitch, int width, int height, int dst_width, int dst_height, const StretchCtx *ctx ); #define STRETCH_NONE 0 #define STRETCH_SRCKEY 1 #define STRETCH_PROTECT 2 #define STRETCH_SRCKEY_PROTECT 3 #define STRETCH_NUM 4 typedef struct { struct { StretchHVx up[STRETCH_NUM]; StretchHVx down[STRETCH_NUM]; } f[DFB_NUM_PIXELFORMATS]; } StretchFunctionTable; /**********************************************************************************************************************/ /*** 16 bit RGB 565 scalers *******************************************************************************************/ /**********************************************************************************************************************/ #define DST_FORMAT DSPF_RGB16 #define TABLE_NAME stretch_hvx_RGB16 #define FUNC_NAME(UPDOWN,K,P,F) stretch_hvx_RGB16_ ## UPDOWN ## _ ## K ## P ## _ ## F #define SHIFT_R5 5 #define SHIFT_R6 6 #define X_F81F 0xf81f #define X_07E0 0x07e0 #define MASK_RGB 0xffff #define FORMAT_RGB16 #include "stretch_up_down_16.h" #undef FORMAT_RGB16 #undef DST_FORMAT #undef TABLE_NAME #undef FUNC_NAME #undef SHIFT_R5 #undef SHIFT_R6 #undef X_F81F #undef X_07E0 #undef MASK_RGB /**********************************************************************************************************************/ /*** 32 bit RGB 888 scalers *******************************************************************************************/ /**********************************************************************************************************************/ #define DST_FORMAT DSPF_RGB32 #define TABLE_NAME stretch_hvx_RGB32 #define FUNC_NAME(UPDOWN,K,P,F) stretch_hvx_RGB32_ ## UPDOWN ## _ ## K ## P ## _ ## F #define SHIFT_R8 8 #define SHIFT_L8 8 #define X_00FF00FF 0x00ff00ff #define X_FF00FF00 0x0000ff00 #define MASK_RGB 0x00ffffff #include "stretch_up_down_32.h" #undef DST_FORMAT #undef TABLE_NAME #undef FUNC_NAME #undef SHIFT_R8 #undef SHIFT_L8 #undef X_00FF00FF #undef X_FF00FF00 #undef MASK_RGB /**********************************************************************************************************************/ /*** 32 bit ARGB 8888 scalers *****************************************************************************************/ /**********************************************************************************************************************/ #define DST_FORMAT DSPF_ARGB #define TABLE_NAME stretch_hvx_ARGB #define FUNC_NAME(UPDOWN,K,P,F) stretch_hvx_ARGB_ ## UPDOWN ## _ ## K ## P ## _ ## F #define SHIFT_R8 8 #define SHIFT_L8 8 #define X_00FF00FF 0x00ff00ff #define X_FF00FF00 0xff00ff00 #define MASK_RGB 0x00ffffff #define HAS_ALPHA #include "stretch_up_down_32.h" #undef DST_FORMAT #undef TABLE_NAME #undef FUNC_NAME #undef SHIFT_R8 #undef SHIFT_L8 #undef X_00FF00FF #undef X_FF00FF00 #undef MASK_RGB #undef HAS_ALPHA /**********************************************************************************************************************/ /*** 16 bit ARGB 4444 scalers *****************************************************************************************/ /**********************************************************************************************************************/ #define DST_FORMAT DSPF_ARGB4444 #define TABLE_NAME stretch_hvx_ARGB4444 #define FUNC_NAME(UPDOWN,K,P,F) stretch_hvx_ARGB4444_ ## UPDOWN ## _ ## K ## P ## _ ## F #define SHIFT_R5 4 #define SHIFT_R6 4 #define X_F81F 0x0f0f #define X_07E0 0xf0f0 #define MASK_RGB 0x0fff #define HAS_ALPHA #define FORMAT_ARGB4444 #include "stretch_up_down_16.h" #undef FORMAT_ARGB4444 #undef DST_FORMAT #undef TABLE_NAME #undef FUNC_NAME #undef SHIFT_R5 #undef SHIFT_R6 #undef X_F81F #undef X_07E0 #undef MASK_RGB #undef HAS_ALPHA /**********************************************************************************************************************/ /*** 16 bit RGBA 4444 scalers *****************************************************************************************/ /**********************************************************************************************************************/ #define DST_FORMAT DSPF_RGBA4444 #define TABLE_NAME stretch_hvx_RGBA4444 #define FUNC_NAME(UPDOWN,K,P,F) stretch_hvx_RGBA4444_ ## UPDOWN ## _ ## K ## P ## _ ## F #define SHIFT_R5 4 #define SHIFT_R6 4 #define X_F81F 0x0f0f #define X_07E0 0xf0f0 #define MASK_RGB 0xfff0 #define HAS_ALPHA #include "stretch_up_down_16.h" #undef DST_FORMAT #undef TABLE_NAME #undef FUNC_NAME #undef SHIFT_R5 #undef SHIFT_R6 #undef X_F81F #undef X_07E0 #undef MASK_RGB #undef HAS_ALPHA static const StretchFunctionTable *stretch_tables[DFB_NUM_PIXELFORMATS] = { [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB16)] = &stretch_hvx_RGB16, [DFB_PIXELFORMAT_INDEX(DSPF_RGB24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB32)] = &stretch_hvx_RGB32, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB)] = &stretch_hvx_ARGB, [DFB_PIXELFORMAT_INDEX(DSPF_ABGR)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YUY2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB332)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_UYVY)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_I420)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT8)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ALUT44)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AiRGB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV12)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB2554)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)] = &stretch_hvx_ARGB4444, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA4444)] = &stretch_hvx_RGBA4444, [DFB_PIXELFORMAT_INDEX(DSPF_NV21)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AYUV)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A4)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB1666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB6666)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB18)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT1)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_LUT2)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGB555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR555)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBA5551)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y444)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_ARGB8565)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_RGBAF88871)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_AVYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_VYU)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_A1_LSB)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV16)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV61)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_Y42B)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_YV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV24)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_NV42)] = NULL, [DFB_PIXELFORMAT_INDEX(DSPF_BGR24)] = NULL, }; /**********************************************************************************************************************/ /*** NV12 / NV21 8 bit scalers ****************************************************************************************/ /**********************************************************************************************************************/ #define FUNC_NAME(UPDOWN) stretch_hvx_8_ ## UPDOWN #include "stretch_up_down_8.h" #undef FUNC_NAME #define FUNC_NAME(UPDOWN) stretch_hvx_88_ ## UPDOWN #include "stretch_up_down_88.h" #undef FUNC_NAME __attribute__((noinline)) static bool stretch_hvx_planar( CardState *state, DFBRectangle *srect, DFBRectangle *drect, bool down ) { GenefxState *gfxs; void *dst; void *src; DFBRegion clip; D_ASSERT( state != NULL ); DFB_RECTANGLE_ASSERT( srect ); DFB_RECTANGLE_ASSERT( drect ); gfxs = state->gfxs; if (state->blittingflags) return false; if (gfxs->dst_format != gfxs->src_format) return false; clip = state->clip; if (!dfb_region_rectangle_intersect( &clip, drect )) return false; dfb_region_translate( &clip, - drect->x, - drect->y ); dst = gfxs->dst_org[0] + drect->y * gfxs->dst_pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, drect->x ); src = gfxs->src_org[0] + srect->y * gfxs->src_pitch + DFB_BYTES_PER_LINE( gfxs->src_format, srect->x ); switch (gfxs->dst_format) { case DSPF_NV12: case DSPF_NV21: if (down) stretch_hvx_8_down( dst, gfxs->dst_pitch, src, gfxs->src_pitch, srect->w, srect->h, drect->w, drect->h, &clip ); else stretch_hvx_8_up( dst, gfxs->dst_pitch, src, gfxs->src_pitch, srect->w, srect->h, drect->w, drect->h, &clip ); clip.x1 /= 2; clip.x2 /= 2; clip.y1 /= 2; clip.y2 /= 2; dst = gfxs->dst_org[1] + drect->y/2 * gfxs->dst_pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, drect->x ); src = gfxs->src_org[1] + srect->y/2 * gfxs->src_pitch + DFB_BYTES_PER_LINE( gfxs->src_format, srect->x ); if (down) stretch_hvx_88_down( dst, gfxs->dst_pitch, src, gfxs->src_pitch, srect->w / 2, srect->h, drect->w / 2, drect->h, &clip ); else stretch_hvx_88_up( dst, gfxs->dst_pitch, src, gfxs->src_pitch, srect->w / 2, srect->h, drect->w / 2, drect->h, &clip ); break; default: break; } return true; } __attribute__((noinline)) static bool stretch_hvx( CardState *state, DFBRectangle *srect, DFBRectangle *drect ) { GenefxState *gfxs; const StretchFunctionTable *table; StretchHVx stretch; void *dst; void *src; StretchCtx ctx; u32 colors[256]; bool down = false; int idx = STRETCH_NONE; D_ASSERT( state != NULL ); DFB_RECTANGLE_ASSERT( srect ); DFB_RECTANGLE_ASSERT( drect ); gfxs = state->gfxs; if (srect->w > drect->w && srect->h > drect->h) down = true; if (down) { if (!(state->render_options & DSRO_SMOOTH_DOWNSCALE)) return false; } else { if (!(state->render_options & DSRO_SMOOTH_UPSCALE)) return false; } switch (gfxs->dst_format) { case DSPF_NV12: case DSPF_NV21: return stretch_hvx_planar( state, srect, drect, down ); default: break; } if (state->blittingflags & ~(DSBLIT_COLORKEY_PROTECT | DSBLIT_SRC_COLORKEY | DSBLIT_SRC_PREMULTIPLY)) return false; if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY && !DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format )) return false; if (DFB_PIXELFORMAT_INDEX(gfxs->dst_format) >= D_ARRAY_SIZE(stretch_tables)) return false; if (DFB_PIXELFORMAT_INDEX(gfxs->src_format) >= D_ARRAY_SIZE((stretch_tables[0])->f)) return false; table = stretch_tables[DFB_PIXELFORMAT_INDEX(gfxs->dst_format)]; if (!table) return false; if (state->blittingflags & DSBLIT_SRC_COLORKEY) idx |= STRETCH_SRCKEY; if (state->blittingflags & DSBLIT_COLORKEY_PROTECT) idx |= STRETCH_PROTECT; if (down) stretch = table->f[DFB_PIXELFORMAT_INDEX(gfxs->src_format)].down[idx]; else stretch = table->f[DFB_PIXELFORMAT_INDEX(gfxs->src_format)].up[idx]; if (!stretch) return false; ctx.clip = state->clip; if (!dfb_region_rectangle_intersect( &ctx.clip, drect )) return false; dfb_region_translate( &ctx.clip, - drect->x, - drect->y ); if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format )) { int i; const DFBColor *entries; u16 *colors16 = (void*) colors; D_ASSERT( gfxs->Blut != NULL ); entries = gfxs->Blut->entries; switch (gfxs->dst_format) { case DSPF_ARGB: if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { for (i = 0; i < gfxs->Blut->num_entries; i++) { int alpha = entries[i].a + 1; switch (alpha) { case 0: colors[i] = 0; break; case 255: colors[i] = PIXEL_ARGB( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); break; default: colors[i] = PIXEL_ARGB( entries[i].a, (alpha * entries[i].r) >> 8, (alpha * entries[i].g) >> 8, (alpha * entries[i].b) >> 8 ); } } } else { for (i = 0; i < gfxs->Blut->num_entries; i++) colors[i] = PIXEL_ARGB( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); } break; case DSPF_ABGR: if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { for (i = 0; i < gfxs->Blut->num_entries; i++) { int alpha = entries[i].a + 1; switch (alpha) { case 0: colors[i] = 0; break; case 255: colors[i] = PIXEL_ABGR( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); break; default: colors[i] = PIXEL_ABGR( entries[i].a, (alpha * entries[i].r) >> 8, (alpha * entries[i].g) >> 8, (alpha * entries[i].b) >> 8 ); } } } else { for (i = 0; i < gfxs->Blut->num_entries; i++) colors[i] = PIXEL_ABGR( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); } break; case DSPF_RGBAF88871: if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { for (i = 0; i < gfxs->Blut->num_entries; i++) { int alpha = entries[i].a + 1; switch (alpha) { case 0: colors[i] = 0; break; case 255: colors[i] = PIXEL_RGBAF88871( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); break; default: colors[i] = PIXEL_RGBAF88871( entries[i].a, (alpha * entries[i].r) >> 8, (alpha * entries[i].g) >> 8, (alpha * entries[i].b) >> 8 ); } } } else { for (i = 0; i < gfxs->Blut->num_entries; i++) colors[i] = PIXEL_RGBAF88871( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); } break; case DSPF_RGB32: for (i = 0; i < gfxs->Blut->num_entries; i++) colors[i] = PIXEL_RGB32( entries[i].r, entries[i].g, entries[i].b ); break; case DSPF_RGB16: for (i = 0; i < gfxs->Blut->num_entries; i++) colors16[i] = PIXEL_RGB16( entries[i].r, entries[i].g, entries[i].b ); break; case DSPF_ARGB4444: if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { for (i = 0; i < gfxs->Blut->num_entries; i++) { int alpha = entries[i].a + 1; switch (alpha) { case 0: colors16[i] = 0; break; case 255: colors16[i] = PIXEL_ARGB4444( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); break; default: colors16[i] = PIXEL_ARGB4444( entries[i].a, (alpha * entries[i].r) >> 8, (alpha * entries[i].g) >> 8, (alpha * entries[i].b) >> 8 ); } } } else { for (i = 0; i < gfxs->Blut->num_entries; i++) colors16[i] = PIXEL_ARGB4444( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); } break; case DSPF_RGBA4444: if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) { for (i = 0; i < gfxs->Blut->num_entries; i++) { int alpha = entries[i].a + 1; switch (alpha) { case 0: colors16[i] = 0; break; case 255: colors16[i] = PIXEL_RGBA4444( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); break; default: colors16[i] = PIXEL_RGBA4444( entries[i].a, (alpha * entries[i].r) >> 8, (alpha * entries[i].g) >> 8, (alpha * entries[i].b) >> 8 ); } } } else { for (i = 0; i < gfxs->Blut->num_entries; i++) colors16[i] = PIXEL_RGBA4444( entries[i].a, entries[i].r, entries[i].g, entries[i].b ); } break; case DSPF_RGB444: for (i = 0; i < gfxs->Blut->num_entries; i++) colors16[i] = PIXEL_RGB444( entries[i].r, entries[i].g, entries[i].b ); break; default: D_UNIMPLEMENTED(); } ctx.colors = colors; if (state->blittingflags & DSBLIT_SRC_COLORKEY) { if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->dst_format )) ctx.key = state->src_colorkey; else { const DFBColor *color = &entries[state->src_colorkey % gfxs->Blut->num_entries]; ctx.key = dfb_pixel_from_color( gfxs->dst_format, state->destination->config.colorspace, color ); } } } else { ctx.colors = NULL; if (state->blittingflags & DSBLIT_SRC_COLORKEY) { DFBColor color; dfb_pixel_to_color( gfxs->src_format, state->source->config.colorspace, state->src_colorkey, &color ); ctx.key = dfb_pixel_from_color( gfxs->dst_format, state->destination->config.colorspace, &color ); } } if (state->blittingflags & DSBLIT_COLORKEY_PROTECT) { if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->dst_format )) ctx.protect = state->colorkey.index; else { DFBColor color = { 0, state->colorkey.r, state->colorkey.g, state->colorkey.b }; ctx.protect = dfb_pixel_from_color( gfxs->dst_format, state->destination->config.colorspace, &color ); } } dst = gfxs->dst_org[0] + drect->y * gfxs->dst_pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, drect->x ); src = gfxs->src_org[0] + srect->y * gfxs->src_pitch + DFB_BYTES_PER_LINE( gfxs->src_format, srect->x ); stretch( dst, gfxs->dst_pitch, src, gfxs->src_pitch, srect->w, srect->h, drect->w, drect->h, &ctx ); return true; } #endif /* DFB_SMOOTH_SCALING */ /**********************************************************************************************************************/ typedef void (*XopAdvanceFunc)( GenefxState *gfxs ); void gStretchBlit( CardState *state, DFBRectangle *srect, DFBRectangle *drect ) { GenefxState *gfxs; XopAdvanceFunc Aop_advance; XopAdvanceFunc Bop_advance; int Aop_X; int Aop_Y; int Bop_X; int Bop_Y; int fx, fy; int ix, iy; int h; DFBRectangle orect = *drect; bool rotated = false; DFBSurfaceBlittingFlags rotflip_blittingflags; D_ASSERT( state != NULL ); D_ASSERT( state->gfxs != NULL ); gfxs = state->gfxs; rotflip_blittingflags = state->blittingflags; dfb_simplify_blittingflags( &rotflip_blittingflags ); rotflip_blittingflags &= (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL | DSBLIT_ROTATE90 ); if (rotflip_blittingflags & DSBLIT_ROTATE90) rotated = true; if (dfb_config->software_warn) { D_WARN( "StretchBlit (%4d,%4d-%4dx%4d) %6s, flags 0x%08x, color 0x%02x%02x%02x%02x <- (%4d,%4d-%4dx%4d) %6s", drect->x, drect->y, drect->w, drect->h, dfb_pixelformat_name( gfxs->dst_format ), state->blittingflags, state->color.a, state->color.r, state->color.g, state->color.b, srect->x, srect->y, srect->w, srect->h, dfb_pixelformat_name( gfxs->src_format ) ); } CHECK_PIPELINE(); #if DFB_SMOOTH_SCALING if (state->render_options & (DSRO_SMOOTH_UPSCALE | DSRO_SMOOTH_DOWNSCALE) && stretch_hvx( state, srect, drect )) return; #endif /* Clip destination rectangle. */ if (!dfb_rectangle_intersect_by_region( drect, &state->clip )) return; /* Calculate fractions */ if (rotated) { fx = (srect->h << 16) / orect.w; fy = (srect->w << 16) / orect.h; } else { fx = (srect->w << 16) / orect.w; fy = (srect->h << 16) / orect.h; } /* Calculate horizontal and vertical phase. */ switch (rotflip_blittingflags & (DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL | DSBLIT_ROTATE90)) { case DSBLIT_NOFX: ix = fx * (drect->x - orect.x); iy = fy * (drect->y - orect.y); break; case DSBLIT_FLIP_HORIZONTAL: ix = fx * ((orect.x + orect.w - 1) - (drect->x + drect->w - 1)); iy = fy * (drect->y - orect.y); break; case DSBLIT_FLIP_VERTICAL: ix = fx * (drect->x - orect.x); iy = fy * ((orect.y + orect.h - 1) - (drect->y + drect->h - 1)); break; case DSBLIT_ROTATE90: ix = fx * (drect->x - orect.x); iy = fy * ((orect.y + orect.h - 1) - (drect->y + drect->h - 1)); break; case DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL: /* ROTATE180 */ ix = fx * ((orect.x + orect.w - 1) - (drect->x + drect->w - 1)); iy = fy * ((orect.y + orect.h - 1) - (drect->y + drect->h - 1)); break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL | DSBLIT_FLIP_HORIZONTAL: /* ROTATE270 */ ix = fx * ((orect.x + orect.w - 1) - (drect->x + drect->w - 1)); iy = fy * (drect->y - orect.y); break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL: ix = fx * (drect->x - orect.x); iy = fy * (drect->y - orect.y); break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL: ix = fx * ((orect.x + orect.w - 1) - (drect->x + drect->w - 1)); iy = fy * ((orect.y + orect.h - 1) - (drect->y + drect->h - 1)); break; default: ix = 0; iy = 0; } /* Adjust source size. */ if (rotated) { srect->x += iy >> 16; srect->y += ix >> 16; ix &= 0xffff; iy &= 0xffff; srect->w = ((drect->h * fy + iy) + 0xffff) >> 16; srect->h = ((drect->w * fx + ix) + 0xffff) >> 16; } else { srect->x += ix >> 16; srect->y += iy >> 16; ix &= 0xffff; iy &= 0xffff; srect->w = ((drect->w * fx + ix) + 0xffff) >> 16; srect->h = ((drect->h * fy + iy) + 0xffff) >> 16; } D_ASSERT( srect->x + srect->w <= state->source->config.size.w ); D_ASSERT( srect->y + srect->h <= state->source->config.size.h ); D_ASSERT( drect->x + drect->w <= state->clip.x2 + 1 ); D_ASSERT( drect->y + drect->h <= state->clip.y2 + 1 ); if (!Genefx_ABacc_prepare( gfxs, MAX( srect->w, drect->w ) )) return; switch (gfxs->src_format) { case DSPF_A4: case DSPF_YUY2: case DSPF_UYVY: srect->x &= ~1; break; default: break; } switch (gfxs->dst_format) { case DSPF_A4: case DSPF_YUY2: case DSPF_UYVY: drect->x &= ~1; break; default: break; } if (rotated) { gfxs->Dlen = drect->h; gfxs->SperD = fy; gfxs->Xphase = iy; h = drect->w; } else { gfxs->Dlen = drect->w; gfxs->SperD = fx; gfxs->Xphase = ix; h = drect->h; } gfxs->Slen = srect->w; gfxs->length = gfxs->Dlen; Aop_X = drect->x; Aop_Y = drect->y; Bop_X = srect->x; Bop_Y = srect->y; Bop_advance = Genefx_Bop_next; Aop_advance = Genefx_Aop_next; switch ((unsigned int) rotflip_blittingflags) { case DSBLIT_FLIP_HORIZONTAL: gfxs->Astep *= -1; Aop_X += (drect->w - 1); break; case DSBLIT_FLIP_VERTICAL: Aop_Y += (drect->h - 1); Aop_advance = Genefx_Aop_prev; break; case DSBLIT_ROTATE90: Aop_Y = drect->y + drect->h - 1; gfxs->Astep *= -gfxs->dst_pitch / gfxs->dst_bpp; Aop_advance = Genefx_Aop_crab; break; case DSBLIT_FLIP_VERTICAL | DSBLIT_FLIP_HORIZONTAL: /* ROTATE180 */ gfxs->Astep *= -1; Aop_X += (drect->w - 1); Aop_Y += (drect->h - 1); Aop_advance = Genefx_Aop_prev; break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL: /* ROTATE270 */ gfxs->Astep *= gfxs->dst_pitch / gfxs->dst_bpp; Bop_Y = srect->y + srect->h - 1; Aop_advance = Genefx_Aop_crab; Bop_advance = Genefx_Bop_prev; break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_VERTICAL: gfxs->Astep *= -gfxs->dst_pitch / gfxs->dst_bpp; Aop_X = drect->x + drect->w - 1; Aop_Y = drect->y + drect->h - 1; Aop_advance = Genefx_Aop_prev_crab; break; case DSBLIT_ROTATE90 | DSBLIT_FLIP_HORIZONTAL: gfxs->Astep *= gfxs->dst_pitch / gfxs->dst_bpp; Aop_advance = Genefx_Aop_crab; break; default: break; } Genefx_Aop_xy( gfxs, Aop_X, Aop_Y ); Genefx_Bop_xy( gfxs, Bop_X, Bop_Y ); while (h--) { RUN_PIPELINE(); Aop_advance( gfxs ); iy += rotated ? fx : fy; while (iy > 0xffff) { iy -= 0x10000; Bop_advance( gfxs ); } } Genefx_ABacc_flush( gfxs ); } ================================================ FILE: src/gfx/generic/generic_stretch_blit.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_STRETCH_BLIT_H__ #define __GENERIC_STRETCH_BLIT_H__ #include /**********************************************************************************************************************/ void gStretchBlit( CardState *state, DFBRectangle *srect, DFBRectangle *drect ); #endif ================================================ FILE: src/gfx/generic/generic_texture_triangles.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include /**********************************************************************************************************************/ typedef struct { int xi; int xf; int mi; int mf; int _2dy; } DDA; #define SETUP_DDA(xs,ys,xe,ye,dda) \ do { \ int dx = (xe) - (xs); \ int dy = (ye) - (ys); \ dda.xi = (xs); \ if (dy != 0) { \ dda.mi = dx / dy; \ dda.mf = 2 * (dx % dy); \ dda.xf = -dy; \ dda._2dy = 2 * dy; \ if (dda.mf < 0) { \ dda.mf += 2 * ABS( dy ); \ dda.mi--; \ } \ } \ else { \ dda.mi = 0; \ dda.mf = 0; \ dda.xf = 0; \ dda._2dy = 0; \ } \ } while (0) #define INC_DDA(dda) \ do { \ dda.xi += dda.mi; \ dda.xf += dda.mf; \ if (dda.xf > 0) { \ dda.xi++; \ dda.xf -= dda._2dy; \ } \ } while (0) static void Genefx_TextureTriangleAffine( GenefxState *gfxs, GenefxVertexAffine *v0, GenefxVertexAffine *v1, GenefxVertexAffine *v2, const DFBRegion *clip ) { /* All points on one horizontal line. */ if (v0->y == v1->y && v1->y == v2->y) return; GenefxVertexAffine *v_tmp; /* Triangle sorting (vertical). */ if (v1->y < v0->y) { v_tmp = v0; v0 = v1; v1 = v_tmp; } if (v2->y < v0->y) { v_tmp = v2; v2 = v1; v1 = v0; v0 = v_tmp; } else if (v2->y < v1->y) { v_tmp = v1; v1 = v2; v2 = v_tmp; } int y_top = v0->y; int y_bottom = v2->y; /* Totally clipped (vertical). */ if (y_top > clip->y2 || y_bottom < clip->y1) return; /* Totally clipped right. */ if (v0->x > clip->x2 && v1->x > clip->x2 && v2->x > clip->x2) return; /* Totally clipped left. */ if (v0->x < clip->x1 && v1->x < clip->x1 && v2->x < clip->x1) return; int y_update = -1; /* Triangle Sorting (horizontal). */ if (v0->y == v1->y) { if (v0->x > v1->x) { v_tmp = v0; v0 = v1; v1 = v_tmp; } } else if (v1->y == v2->y) { if (v1->x > v2->x) { v_tmp = v1; v1 = v2; v2 = v_tmp; } } else y_update = v1->y; /* Triangle Setup. */ int height = v2->y - v0->y; int half_top = v1->y - v0->y; int half_bottom = v2->y - v1->y; int y; int sl, sr; int tl, tr; int dsl, dsr; int dtl, dtr; int dsl2, dsr2; int dtl2, dtr2; /* Flat top. */ if (v0->y == v1->y) { /* Top points equal. */ if (v0->x == v1->x) return; sl = v0->s; sr = v1->s; dsl = dsl2 = (v2->s - sl) / height; dsr = dsr2 = (v2->s - sr) / height; tl = v0->t; tr = v1->t; dtl = dtl2 = (v2->t - tl) / height; dtr = dtr2 = (v2->t - tr) / height; } /* Flat bottom. */ else if (v1->y == v2->y) { /* Bottom points equal. */ if (v1->x == v2->x) return; sl = sr = v0->s; dsl = dsl2 = (v1->s - sl) / height; dsr = dsr2 = (v2->s - sr) / height; tl = tr = v0->t; dtl = dtl2 = (v1->t - tl) / height; dtr = dtr2 = (v2->t - tr) / height; } /* Two parts. */ else { sl = sr = v0->s; tl = tr = v0->t; int x_v1 = v0->x + (v2->x - v0->x) * (v1->y - v0->y) / height; /* Update left. */ if (x_v1 > v1->x) { dsl = (v1->s - sl) / half_top; dsr = (v2->s - sr) / height; dsl2 = (v2->s - v1->s) / half_bottom; dsr2 = dsr; dtl = (v1->t - tl) / half_top; dtr = (v2->t - tr) / height; dtl2 = (v2->t - v1->t) / half_bottom; dtr2 = dtr; } /* Update right. */ else if (x_v1 < v1->x) { dsl = (v2->s - sl) / height; dsr = (v1->s - sr) / half_top; dsl2 = dsl; dsr2 = (v2->s - v1->s) / half_bottom; dtl = (v2->t - tl) / height; dtr = (v1->t - tr) / half_top; dtl2 = dtl; dtr2 = (v2->t - v1->t) / half_bottom; } /* All points on one line. */ else return; } DDA dda1 = { .xi = 0 }, dda2 = { .xi = 0 }; SETUP_DDA( v0->x, v0->y, v2->x, v2->y, dda1 ); SETUP_DDA( v0->x, v0->y, v1->x, v1->y, dda2 ); /* Vertical clipping. */ if (y_top < clip->y1) { y_top = clip->y1; } if (y_bottom > clip->y2) { y_bottom = clip->y2; } if (y_top > v0->y) { for (y = v0->y; y < y_top; y++) { if (y == v1->y) SETUP_DDA( v1->x, v1->y, v2->x, v2->y, dda2 ); INC_DDA( dda1 ); INC_DDA( dda2 ); } /* Two parts. */ if (y_update != -1 && y_top > y_update) { sl += dsl * (y_update - v0->y) + dsl2 * (y_top - v1->y); sr += dsr * (y_update - v0->y) + dsr2 * (y_top - v1->y); tl += dtl * (y_update - v0->y) + dtl2 * (y_top - v1->y); tr += dtr * (y_update - v0->y) + dtr2 * (y_top - v1->y); dsl = dsl2; dsr = dsr2; dtl = dtl2; dtr = dtr2; } /* One part or only top clipped. */ else { sl += dsl * (y_top - v0->y); sr += dsr * (y_top - v0->y); tl += dtl * (y_top - v0->y); tr += dtr * (y_top - v0->y); } } /* Loop over clipped lines. */ for (y = y_top; y <= y_bottom; y++) { /* Slope update (for bottom half). */ if (y == y_update) { dsl = dsl2; dtl = dtl2; dsr = dsr2; dtr = dtr2; } if (y == v1->y) SETUP_DDA( v1->x, v1->y, v2->x, v2->y, dda2 ); int len = ABS( dda1.xi - dda2.xi ); int x1 = MIN( dda1.xi, dda2.xi ); int x2 = x1 + len - 1; if (len > 0 && x1 <= clip->x2 && x2 >= clip->x1) { int csl = sl; int ctl = tl; int SperD = (sr - sl) / len; int TperD = (tr - tl) / len; /* Horizontal clipping. */ if (x1 < clip->x1) { csl += SperD * (clip->x1 - x1); ctl += TperD * (clip->x1 - x1); x1 = clip->x1; } if (x2 > clip->x2) { x2 = clip->x2; } gfxs->Dlen = x2 - x1 + 1; gfxs->length = gfxs->Dlen; gfxs->SperD = SperD; gfxs->TperD = TperD; gfxs->s = csl; gfxs->t = ctl; Genefx_Aop_xy( gfxs, x1, y ); RUN_PIPELINE(); } sl += dsl; sr += dsr; tl += dtl; tr += dtr; INC_DDA( dda1 ); INC_DDA( dda2 ); } } void Genefx_TextureTrianglesAffine( CardState *state, GenefxVertexAffine *vertices, int num, DFBTriangleFormation formation, const DFBRegion *clip ) { GenefxState *gfxs; int index = 0; D_ASSERT( state != NULL ); D_ASSERT( state->gfxs != NULL ); gfxs = state->gfxs; CHECK_PIPELINE(); if (!Genefx_ABacc_prepare( gfxs, state->destination->config.size.w )) return; /* Reset Bop to 0,0 as texture lookup accesses the whole buffer arbitrarily. */ Genefx_Bop_xy( gfxs, 0, 0 ); /* Render triangles. */ for (index = 0; index < num;) { GenefxVertexAffine *v[3]; if (index == 0) { v[0] = &vertices[index+0]; v[1] = &vertices[index+1]; v[2] = &vertices[index+2]; index += 3; } else { switch (formation) { case DTTF_LIST: v[0] = &vertices[index+0]; v[1] = &vertices[index+1]; v[2] = &vertices[index+2]; index += 3; break; case DTTF_STRIP: v[0] = &vertices[index-2]; v[1] = &vertices[index-1]; v[2] = &vertices[index+0]; index += 1; break; case DTTF_FAN: v[0] = &vertices[0]; v[1] = &vertices[index-1]; v[2] = &vertices[index+0]; index += 1; break; default: D_BUG( "unknown formation %u", formation ); Genefx_ABacc_flush( gfxs ); return; } } if (dfb_config->software_warn) { D_WARN( "TexTriangles (%d,%d-%d,%d-%d,%d) %6s, flags 0x%08x, color 0x%02x%02x%02x%02x <- (%4d,%4d) %6s", v[0]->x, v[0]->y, v[1]->x, v[1]->y, v[2]->x, v[2]->y, dfb_pixelformat_name( gfxs->dst_format ), state->blittingflags, state->color.a, state->color.r, state->color.g, state->color.b, state->source->config.size.w, state->source->config.size.h, dfb_pixelformat_name( gfxs->src_format ) ); } Genefx_TextureTriangleAffine( gfxs, v[0], v[1], v[2], clip ); } Genefx_ABacc_flush( gfxs ); } ================================================ FILE: src/gfx/generic/generic_texture_triangles.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_TEXTURE_TRIANGLES_H__ #define __GENERIC_TEXTURE_TRIANGLES_H__ #include /**********************************************************************************************************************/ typedef struct { int x; int y; int s; int t; } GenefxVertexAffine; /**********************************************************************************************************************/ void Genefx_TextureTrianglesAffine( CardState *state, GenefxVertexAffine *vertices, int num, DFBTriangleFormation formation, const DFBRegion *clip ); #endif ================================================ FILE: src/gfx/generic/generic_util.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include /**********************************************************************************************************************/ void Genefx_Aop_crab( GenefxState *gfxs ) { gfxs->Aop[0] += gfxs->dst_bpp; gfxs->AopY++; } void Genefx_Aop_prev_crab( GenefxState *gfxs ) { gfxs->Aop[0] -= gfxs->dst_bpp; gfxs->AopY++; } void Genefx_Aop_xy( GenefxState *gfxs, int x, int y ) { int pitch = gfxs->dst_pitch; gfxs->Aop[0] = gfxs->dst_org[0]; gfxs->AopY = y; if (gfxs->dst_caps & DSCAPS_SEPARATED) { gfxs->Aop_field = y & 1; if (gfxs->Aop_field) gfxs->Aop[0] += gfxs->dst_field_offset; y /= 2; } D_ASSUME( !(x & DFB_PIXELFORMAT_ALIGNMENT( gfxs->dst_format )) ); gfxs->Aop[0] += y * pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, x ); if (DFB_PLANAR_PIXELFORMAT(gfxs->dst_format)) { int dst_field_offset = gfxs->dst_field_offset; switch (gfxs->dst_format) { case DSPF_I420: case DSPF_YV12: dst_field_offset /= 4; pitch /= 2; y /= 2; x /= 2; break; case DSPF_Y42B: case DSPF_YV16: dst_field_offset /= 2; pitch /= 2; x /= 2; break; case DSPF_NV12: case DSPF_NV21: dst_field_offset /= 2; y /= 2; case DSPF_NV16: case DSPF_NV61: x &= ~1; break; case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: /* nothing to adjust */ default: break; } gfxs->Aop[1] = gfxs->dst_org[1]; gfxs->Aop[2] = gfxs->dst_org[2]; if (gfxs->dst_caps & DSCAPS_SEPARATED && gfxs->Aop_field) { gfxs->Aop[1] += dst_field_offset; gfxs->Aop[2] += dst_field_offset; } gfxs->Aop[1] += y * pitch + x; gfxs->Aop[2] += y * pitch + x; if (gfxs->dst_format == DSPF_NV24 || gfxs->dst_format == DSPF_NV42) gfxs->Aop[1] += y * pitch + x; } } void Genefx_Aop_next( GenefxState *gfxs ) { int pitch = gfxs->dst_pitch; if (gfxs->dst_caps & DSCAPS_SEPARATED) { gfxs->Aop_field++; if (gfxs->Aop_field & 1) gfxs->Aop[0] += gfxs->dst_field_offset; else gfxs->Aop[0] += pitch - gfxs->dst_field_offset; } else gfxs->Aop[0] += pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->dst_format)) { if (gfxs->dst_format == DSPF_I420 || gfxs->dst_format == DSPF_YV12) { if (gfxs->AopY & 1) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) { gfxs->Aop[1] += gfxs->dst_field_offset / 4; gfxs->Aop[2] += gfxs->dst_field_offset / 4; } else { gfxs->Aop[1] += pitch / 2 - gfxs->dst_field_offset / 4; gfxs->Aop[2] += pitch / 2 - gfxs->dst_field_offset / 4; } } else { gfxs->Aop[1] += pitch / 2; gfxs->Aop[2] += pitch / 2; } } } else if (gfxs->dst_format == DSPF_Y42B || gfxs->dst_format == DSPF_YV16) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) { gfxs->Aop[1] += gfxs->dst_field_offset / 2; gfxs->Aop[2] += gfxs->dst_field_offset / 2; } else { gfxs->Aop[1] += pitch / 2 - gfxs->dst_field_offset / 2; gfxs->Aop[2] += pitch / 2 - gfxs->dst_field_offset / 2; } } else { gfxs->Aop[1] += pitch / 2; gfxs->Aop[2] += pitch / 2; } } else if (gfxs->dst_format == DSPF_Y444 || gfxs->dst_format == DSPF_YV24) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) { gfxs->Aop[1] += gfxs->dst_field_offset; gfxs->Aop[2] += gfxs->dst_field_offset; } else { gfxs->Aop[1] += pitch - gfxs->dst_field_offset; gfxs->Aop[2] += pitch - gfxs->dst_field_offset; } } else { gfxs->Aop[1] += pitch; gfxs->Aop[2] += pitch; } } else if (gfxs->dst_format == DSPF_NV12 || gfxs->dst_format == DSPF_NV21) { if (gfxs->AopY & 1) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) gfxs->Aop[1] += gfxs->dst_field_offset / 2; else gfxs->Aop[1] += pitch - gfxs->dst_field_offset / 2; } else { gfxs->Aop[1] += pitch; } } } else if (gfxs->dst_format == DSPF_NV16 || gfxs->dst_format == DSPF_NV61) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) gfxs->Aop[1] += gfxs->dst_field_offset; else gfxs->Aop[1] += pitch - gfxs->dst_field_offset; } else { gfxs->Aop[1] += pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) gfxs->Aop[1] += gfxs->dst_field_offset * 2; else gfxs->Aop[1] += pitch - gfxs->dst_field_offset * 2; } else { gfxs->Aop[1] += pitch * 2; } } } gfxs->AopY++; } void Genefx_Aop_prev( GenefxState *gfxs ) { int pitch = gfxs->dst_pitch; if (gfxs->dst_caps & DSCAPS_SEPARATED) { gfxs->Aop_field++; if (gfxs->Aop_field & 1) gfxs->Aop[0] += gfxs->dst_field_offset - pitch; else gfxs->Aop[0] -= gfxs->dst_field_offset; } else gfxs->Aop[0] -= pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->dst_format)) { if (gfxs->dst_format == DSPF_I420 || gfxs->dst_format == DSPF_YV12) { if (gfxs->AopY & 1) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) { gfxs->Aop[1] += gfxs->dst_field_offset / 4 - pitch / 2; gfxs->Aop[2] += gfxs->dst_field_offset / 4 - pitch / 2; } else { gfxs->Aop[1] -= gfxs->dst_field_offset / 4; gfxs->Aop[2] -= gfxs->dst_field_offset / 4; } } else { gfxs->Aop[1] -= pitch / 2; gfxs->Aop[2] -= pitch / 2; } } } else if (gfxs->dst_format == DSPF_Y42B || gfxs->dst_format == DSPF_YV16) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) { gfxs->Aop[1] += gfxs->dst_field_offset / 2 - pitch / 2; gfxs->Aop[2] += gfxs->dst_field_offset / 2 - pitch / 2; } else { gfxs->Aop[1] -= gfxs->dst_field_offset / 2; gfxs->Aop[2] -= gfxs->dst_field_offset / 2; } } else { gfxs->Aop[1] -= pitch / 2; gfxs->Aop[2] -= pitch / 2; } } else if (gfxs->dst_format == DSPF_Y444 || gfxs->dst_format == DSPF_YV24) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) { gfxs->Aop[1] += gfxs->dst_field_offset - pitch; gfxs->Aop[2] += gfxs->dst_field_offset - pitch; } else { gfxs->Aop[1] -= gfxs->dst_field_offset; gfxs->Aop[2] -= gfxs->dst_field_offset; } } else { gfxs->Aop[1] -= pitch; gfxs->Aop[2] -= pitch; } } else if (gfxs->dst_format == DSPF_NV12 || gfxs->dst_format == DSPF_NV21) { if (gfxs->AopY & 1) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 2) gfxs->Aop[1] += gfxs->dst_field_offset / 2 - pitch; else gfxs->Aop[1] -= gfxs->dst_field_offset / 2; } else { gfxs->Aop[1] -= pitch; } } } else if (gfxs->dst_format == DSPF_NV16 || gfxs->dst_format == DSPF_NV61) { if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) gfxs->Aop[1] += gfxs->dst_field_offset - pitch; else gfxs->Aop[1] -= gfxs->dst_field_offset; } else { gfxs->Aop[1] -= pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->dst_caps & DSCAPS_SEPARATED) { if (gfxs->Aop_field & 1) gfxs->Aop[1] += gfxs->dst_field_offset * 2 - pitch; else gfxs->Aop[1] -= gfxs->dst_field_offset * 2; } else { gfxs->Aop[1] -= pitch * 2; } } } gfxs->AopY--; } void Genefx_Bop_xy( GenefxState *gfxs, int x, int y ) { int pitch = gfxs->src_pitch; gfxs->Bop[0] = gfxs->src_org[0]; gfxs->BopY = y; if (gfxs->src_caps & DSCAPS_SEPARATED) { gfxs->Bop_field = y & 1; if (gfxs->Bop_field) gfxs->Bop[0] += gfxs->src_field_offset; y /= 2; } D_ASSUME( !(x & DFB_PIXELFORMAT_ALIGNMENT( gfxs->src_format )) ); gfxs->Bop[0] += y * pitch + DFB_BYTES_PER_LINE( gfxs->src_format, x ); if (DFB_PLANAR_PIXELFORMAT(gfxs->src_format)) { int src_field_offset = gfxs->src_field_offset; switch (gfxs->src_format) { case DSPF_I420: case DSPF_YV12: src_field_offset /= 4; pitch /= 2; y /= 2; x /= 2; break; case DSPF_Y42B: case DSPF_YV16: src_field_offset /= 2; pitch /= 2; x /= 2; break; case DSPF_NV12: case DSPF_NV21: src_field_offset /= 2; y /= 2; case DSPF_NV16: case DSPF_NV61: x &= ~1; break; case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: /* nothing to adjust */ default: break; } gfxs->Bop[1] = gfxs->src_org[1]; gfxs->Bop[2] = gfxs->src_org[2]; if (gfxs->src_caps & DSCAPS_SEPARATED && gfxs->Bop_field) { gfxs->Bop[1] += src_field_offset; gfxs->Bop[2] += src_field_offset; } gfxs->Bop[1] += y * pitch + x; gfxs->Bop[2] += y * pitch + x; if (gfxs->src_format == DSPF_NV24 || gfxs->src_format == DSPF_NV42) gfxs->Bop[1] += y * pitch + x; } } void Genefx_Bop_next( GenefxState *gfxs ) { int pitch = gfxs->src_pitch; if (gfxs->src_caps & DSCAPS_SEPARATED) { gfxs->Bop_field++; if (gfxs->Bop_field & 1) gfxs->Bop[0] += gfxs->src_field_offset; else gfxs->Bop[0] += pitch - gfxs->src_field_offset; } else gfxs->Bop[0] += pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->src_format)) { if (gfxs->src_format == DSPF_I420 || gfxs->src_format == DSPF_YV12) { if (gfxs->BopY & 1) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) { gfxs->Bop[1] += gfxs->src_field_offset / 4; gfxs->Bop[2] += gfxs->src_field_offset / 4; } else { gfxs->Bop[1] += pitch / 2 - gfxs->src_field_offset / 4; gfxs->Bop[2] += pitch / 2 - gfxs->src_field_offset / 4; } } else { gfxs->Bop[1] += pitch / 2; gfxs->Bop[2] += pitch / 2; } } } else if (gfxs->src_format == DSPF_Y42B || gfxs->src_format == DSPF_YV16) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) { gfxs->Bop[1] += gfxs->src_field_offset / 2; gfxs->Bop[2] += gfxs->src_field_offset / 2; } else { gfxs->Bop[1] += pitch / 2 - gfxs->src_field_offset / 2; gfxs->Bop[2] += pitch / 2 - gfxs->src_field_offset / 2; } } else { gfxs->Bop[1] += pitch / 2; gfxs->Bop[2] += pitch / 2; } } else if (gfxs->src_format == DSPF_Y444 || gfxs->src_format == DSPF_YV24) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) { gfxs->Bop[1] += gfxs->src_field_offset; gfxs->Bop[2] += gfxs->src_field_offset; } else { gfxs->Bop[1] += pitch - gfxs->src_field_offset; gfxs->Bop[2] += pitch - gfxs->src_field_offset; } } else { gfxs->Bop[1] += pitch; gfxs->Bop[2] += pitch; } } else if (gfxs->src_format == DSPF_NV12 || gfxs->src_format == DSPF_NV21) { if (gfxs->BopY & 1) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) gfxs->Bop[1] += gfxs->src_field_offset / 2; else gfxs->Bop[1] += pitch - gfxs->src_field_offset / 2; } else { gfxs->Bop[1] += pitch; } } } else if (gfxs->src_format == DSPF_NV16 || gfxs->src_format == DSPF_NV61) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) gfxs->Bop[1] += gfxs->src_field_offset; else gfxs->Bop[1] += pitch - gfxs->src_field_offset; } else { gfxs->Bop[1] += pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) gfxs->Bop[1] += gfxs->src_field_offset * 2; else gfxs->Bop[1] += pitch - gfxs->src_field_offset * 2; } else { gfxs->Bop[1] += pitch * 2; } } } gfxs->BopY++; } void Genefx_Bop_prev( GenefxState *gfxs ) { int pitch = gfxs->src_pitch; if (gfxs->src_caps & DSCAPS_SEPARATED) { gfxs->Bop_field++; if (gfxs->Bop_field & 1) gfxs->Bop[0] += gfxs->src_field_offset - pitch; else gfxs->Bop[0] -= gfxs->src_field_offset; } else gfxs->Bop[0] -= pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->src_format)) { if (gfxs->src_format == DSPF_I420 || gfxs->src_format == DSPF_YV12) { if (gfxs->BopY & 1) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) { gfxs->Bop[1] += gfxs->src_field_offset / 4 - pitch / 2; gfxs->Bop[2] += gfxs->src_field_offset / 4 - pitch / 2; } else { gfxs->Bop[1] -= gfxs->src_field_offset / 4; gfxs->Bop[2] -= gfxs->src_field_offset / 4; } } else { gfxs->Bop[1] -= pitch / 2; gfxs->Bop[2] -= pitch / 2; } } } else if (gfxs->src_format == DSPF_Y42B || gfxs->src_format == DSPF_YV16) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) { gfxs->Bop[1] += gfxs->src_field_offset / 2 - pitch / 2; gfxs->Bop[2] += gfxs->src_field_offset / 2 - pitch / 2; } else { gfxs->Bop[1] -= gfxs->src_field_offset / 2; gfxs->Bop[2] -= gfxs->src_field_offset / 2; } } else { gfxs->Bop[1] -= pitch / 2; gfxs->Bop[2] -= pitch / 2; } } else if (gfxs->src_format == DSPF_Y444 || gfxs->src_format == DSPF_YV24) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) { gfxs->Bop[1] += gfxs->src_field_offset - pitch; gfxs->Bop[2] += gfxs->src_field_offset - pitch; } else { gfxs->Bop[1] -= gfxs->src_field_offset; gfxs->Bop[2] -= gfxs->src_field_offset; } } else { gfxs->Bop[1] -= pitch; gfxs->Bop[2] -= pitch; } } else if (gfxs->src_format == DSPF_NV12 || gfxs->src_format == DSPF_NV21) { if (gfxs->BopY & 1) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 2) gfxs->Bop[1] += gfxs->src_field_offset / 2 - pitch; else gfxs->Bop[1] -= gfxs->src_field_offset / 2; } else { gfxs->Bop[1] -= pitch; } } } else if (gfxs->src_format == DSPF_NV16 || gfxs->src_format == DSPF_NV61) { if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) gfxs->Bop[1] += gfxs->src_field_offset - pitch; else gfxs->Bop[1] -= gfxs->src_field_offset; } else { gfxs->Bop[1] -= pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->src_caps & DSCAPS_SEPARATED) { if (gfxs->Bop_field & 1) gfxs->Bop[1] += gfxs->src_field_offset * 2 - pitch; else gfxs->Bop[1] -= gfxs->src_field_offset * 2; } else { gfxs->Bop[1] -= pitch * 2; } } } gfxs->BopY--; } void Genefx_Mop_xy( GenefxState *gfxs, int x, int y ) { int pitch = gfxs->mask_pitch; gfxs->Mop[0] = gfxs->mask_org[0]; gfxs->MopY = y; if (gfxs->mask_caps & DSCAPS_SEPARATED) { gfxs->Mop_field = y & 1; if (gfxs->Mop_field) gfxs->Mop[0] += gfxs->mask_field_offset; y /= 2; } D_ASSUME( !(x & DFB_PIXELFORMAT_ALIGNMENT( gfxs->mask_format )) ); gfxs->Mop[0] += y * pitch + DFB_BYTES_PER_LINE( gfxs->mask_format, x ); if (DFB_PLANAR_PIXELFORMAT(gfxs->mask_format)) { int mask_field_offset = gfxs->mask_field_offset; switch (gfxs->mask_format) { case DSPF_I420: case DSPF_YV12: mask_field_offset /= 4; pitch /= 2; y /= 2; x /= 2; break; case DSPF_Y42B: case DSPF_YV16: mask_field_offset /= 2; pitch /= 2; x /= 2; break; case DSPF_NV12: case DSPF_NV21: mask_field_offset /= 2; y /= 2; case DSPF_NV16: case DSPF_NV61: x &= ~1; break; case DSPF_Y444: case DSPF_YV24: case DSPF_NV24: case DSPF_NV42: /* nothing to adjust */ default: break; } gfxs->Mop[1] = gfxs->mask_org[1]; gfxs->Mop[2] = gfxs->mask_org[2]; if (gfxs->mask_caps & DSCAPS_SEPARATED && gfxs->Mop_field) { gfxs->Mop[1] += mask_field_offset; gfxs->Mop[2] += mask_field_offset; } gfxs->Mop[1] += y * pitch + x; gfxs->Mop[2] += y * pitch + x; if (gfxs->mask_format == DSPF_NV24 || gfxs->mask_format == DSPF_NV42) gfxs->Mop[1] += y * pitch + x; } } void Genefx_Mop_next( GenefxState *gfxs ) { int pitch = gfxs->mask_pitch; if (gfxs->mask_caps & DSCAPS_SEPARATED) { gfxs->Mop_field++; if (gfxs->Mop_field & 1) gfxs->Mop[0] += gfxs->mask_field_offset; else gfxs->Mop[0] += pitch - gfxs->mask_field_offset; } else gfxs->Mop[0] += pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->mask_format)) { if (gfxs->mask_format == DSPF_I420 || gfxs->mask_format == DSPF_YV12) { if (gfxs->MopY & 1) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) { gfxs->Mop[1] += gfxs->mask_field_offset / 4; gfxs->Mop[2] += gfxs->mask_field_offset / 4; } else { gfxs->Mop[1] += pitch / 2 - gfxs->mask_field_offset / 4; gfxs->Mop[2] += pitch / 2 - gfxs->mask_field_offset / 4; } } else { gfxs->Mop[1] += pitch / 2; gfxs->Mop[2] += pitch / 2; } } } else if (gfxs->mask_format == DSPF_Y42B || gfxs->mask_format == DSPF_YV16) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) { gfxs->Mop[1] += gfxs->mask_field_offset / 2; gfxs->Mop[2] += gfxs->mask_field_offset / 2; } else { gfxs->Mop[1] += pitch / 2 - gfxs->mask_field_offset / 2; gfxs->Mop[2] += pitch / 2 - gfxs->mask_field_offset / 2; } } else { gfxs->Mop[1] += pitch / 2; gfxs->Mop[2] += pitch / 2; } } else if (gfxs->mask_format == DSPF_Y444 || gfxs->mask_format == DSPF_YV24) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) { gfxs->Mop[1] += gfxs->mask_field_offset; gfxs->Mop[2] += gfxs->mask_field_offset; } else { gfxs->Mop[1] += pitch - gfxs->mask_field_offset; gfxs->Mop[2] += pitch - gfxs->mask_field_offset; } } else { gfxs->Mop[1] += pitch; gfxs->Mop[2] += pitch; } } else if (gfxs->mask_format == DSPF_NV12 || gfxs->mask_format == DSPF_NV21) { if (gfxs->MopY & 1) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) gfxs->Mop[1] += gfxs->mask_field_offset / 2; else gfxs->Mop[1] += pitch - gfxs->mask_field_offset / 2; } else { gfxs->Mop[1] += pitch; } } } else if (gfxs->mask_format == DSPF_NV16 || gfxs->mask_format == DSPF_NV61) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) gfxs->Mop[1] += gfxs->mask_field_offset; else gfxs->Mop[1] += pitch - gfxs->mask_field_offset; } else { gfxs->Mop[1] += pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) gfxs->Mop[1] += gfxs->mask_field_offset * 2; else gfxs->Mop[1] += pitch - gfxs->mask_field_offset * 2; } else { gfxs->Mop[1] += pitch * 2; } } } gfxs->MopY++; } void Genefx_Mop_prev( GenefxState *gfxs ) { int pitch = gfxs->mask_pitch; if (gfxs->mask_caps & DSCAPS_SEPARATED) { gfxs->Mop_field++; if (gfxs->Mop_field & 1) gfxs->Mop[0] += gfxs->mask_field_offset - pitch; else gfxs->Mop[0] -= gfxs->mask_field_offset; } else gfxs->Mop[0] -= pitch; if (DFB_PLANAR_PIXELFORMAT(gfxs->mask_format)) { if (gfxs->mask_format == DSPF_I420 || gfxs->mask_format == DSPF_YV12) { if (gfxs->MopY & 1) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) { gfxs->Mop[1] += gfxs->mask_field_offset / 4 - pitch / 2; gfxs->Mop[2] += gfxs->mask_field_offset / 4 - pitch / 2; } else { gfxs->Mop[1] -= gfxs->mask_field_offset / 4; gfxs->Mop[2] -= gfxs->mask_field_offset / 4; } } else { gfxs->Mop[1] -= pitch / 2; gfxs->Mop[2] -= pitch / 2; } } } else if (gfxs->mask_format == DSPF_Y42B || gfxs->mask_format == DSPF_YV16) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) { gfxs->Mop[1] += gfxs->mask_field_offset / 2 - pitch / 2; gfxs->Mop[2] += gfxs->mask_field_offset / 2 - pitch / 2; } else { gfxs->Mop[1] -= gfxs->mask_field_offset / 2; gfxs->Mop[2] -= gfxs->mask_field_offset / 2; } } else { gfxs->Mop[1] -= pitch / 2; gfxs->Mop[2] -= pitch / 2; } } else if (gfxs->mask_format == DSPF_Y444 || gfxs->mask_format == DSPF_YV24) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) { gfxs->Mop[1] += gfxs->mask_field_offset - pitch; gfxs->Mop[2] += gfxs->mask_field_offset - pitch; } else { gfxs->Mop[1] -= gfxs->mask_field_offset; gfxs->Mop[2] -= gfxs->mask_field_offset; } } else { gfxs->Mop[1] -= pitch; gfxs->Mop[2] -= pitch; } } else if (gfxs->mask_format == DSPF_NV12 || gfxs->mask_format == DSPF_NV21) { if (gfxs->MopY & 1) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 2) gfxs->Mop[1] += gfxs->mask_field_offset / 2 - pitch; else gfxs->Mop[1] -= gfxs->mask_field_offset / 2; } else { gfxs->Mop[1] -= pitch; } } } else if (gfxs->mask_format == DSPF_NV16 || gfxs->mask_format == DSPF_NV61) { if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) gfxs->Mop[1] += gfxs->mask_field_offset - pitch; else gfxs->Mop[1] -= gfxs->mask_field_offset; } else { gfxs->Mop[1] -= pitch; } } else { /* DSPF_NV24 || DSPF_NV42 */ if (gfxs->mask_caps & DSCAPS_SEPARATED) { if (gfxs->Mop_field & 1) gfxs->Mop[1] += gfxs->mask_field_offset * 2 - pitch; else gfxs->Mop[1] -= gfxs->mask_field_offset * 2; } else { gfxs->Mop[1] -= pitch * 2; } } } gfxs->MopY--; } bool Genefx_ABacc_prepare( GenefxState *gfxs, int width ) { int size; if (!gfxs->need_accumulator) return true; size = (width + 31) & ~31; if (gfxs->ABsize < size) { void *ABstart = D_MALLOC( size * sizeof(GenefxAccumulator) * 3 + 31 ); if (!ABstart) { D_WARN( "out of memory" ); return false; } if (gfxs->ABstart) D_FREE( gfxs->ABstart ); gfxs->ABstart = ABstart; gfxs->ABsize = size; gfxs->Aacc = (GenefxAccumulator*) (((unsigned long) ABstart+31) & ~31); gfxs->Bacc = gfxs->Aacc + size; gfxs->Tacc = gfxs->Aacc + size + size; } gfxs->Sacc = gfxs->Dacc = gfxs->Aacc; return true; } void Genefx_ABacc_flush( GenefxState *gfxs ) { if (dfb_config->keep_accumulators >= 0 && gfxs->ABsize > dfb_config->keep_accumulators) { D_FREE( gfxs->ABstart ); gfxs->ABsize = 0; gfxs->ABstart = NULL; gfxs->Aacc = NULL; gfxs->Bacc = NULL; gfxs->Sacc = NULL; gfxs->Dacc = NULL; } } ================================================ FILE: src/gfx/generic/generic_util.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GENERIC_UTIL_H__ #define __GENERIC_UTIL_H__ #include #include #include #include /**********************************************************************************************************************/ #define CHECK_PIPELINE() \ { \ if (!gfxs->funcs[0]) \ return; \ \ if (dfb_config->software_trace) { \ int idx; \ GenefxFunc *funcs = gfxs->funcs; \ DirectLog *log = direct_log_default(); \ \ direct_log_lock( log ); \ direct_log_printf( log, " Software Fallback Pipeline:\n" ); \ \ for (idx = 0; funcs[idx]; ++idx) \ direct_log_printf( log, " [%2d] %s\n", idx, direct_trace_lookup_symbol_at( funcs[idx] ) ); \ \ direct_log_printf( log, "\n" ); \ direct_log_unlock( log ); \ } \ } #define RUN_PIPELINE() \ { \ int idx; \ GenefxFunc *funcs = gfxs->funcs; \ \ for (idx = 0; funcs[idx]; ++idx) \ funcs[idx]( gfxs ); \ } /**********************************************************************************************************************/ void Genefx_Aop_crab ( GenefxState *gfxs ); void Genefx_Aop_prev_crab( GenefxState *gfxs ); void Genefx_Aop_xy ( GenefxState *gfxs, int x, int y ); void Genefx_Aop_next ( GenefxState *gfxs ); void Genefx_Aop_prev ( GenefxState *gfxs ); void Genefx_Bop_xy ( GenefxState *gfxs, int x, int y ); void Genefx_Bop_next ( GenefxState *gfxs ); void Genefx_Bop_prev ( GenefxState *gfxs ); void Genefx_Mop_xy ( GenefxState *gfxs, int x, int y ); void Genefx_Mop_next ( GenefxState *gfxs ); void Genefx_Mop_prev ( GenefxState *gfxs ); bool Genefx_ABacc_prepare( GenefxState *gfxs, int width ); void Genefx_ABacc_flush ( GenefxState *gfxs ); #endif ================================================ FILE: src/gfx/generic/stretch_hvx_16.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef SOURCE_LOOKUP #define SOURCE_LOOKUP(x) (x) #define SOURCE_LOOKUP_AUTO #endif #ifndef SOURCE_TYPE #define SOURCE_TYPE u16 #define SOURCE_TYPE_AUTO #endif #define SHIFT_L5 SHIFT_R5 #define SHIFT_L6 SHIFT_R6 #define SHIFT_L10 (16 - SHIFT_L6) #define X_003F (X_07E0 >> SHIFT_R5) #define X_003E07C0 (X_F81F << SHIFT_L6) #define X_0001F800 (X_07E0 << SHIFT_L6) #define X_07E0F81F ((X_07E0 << 16) | X_F81F) #define X_F81F07E0 ((X_F81F << 16) | X_07E0) #define X_F81FF81F ((X_F81F << 16) | X_F81F) #define X_07E007E0 ((X_07E0 << 16) | X_07E0) #define X_07C0F83F (X_F81F07E0 >> SHIFT_R5) #if D_DEBUG_ENABLED #define HVX_DEBUG(x...) direct_log_printf( NULL, x ) #else #define HVX_DEBUG(x...) do {} while (0) #endif /* static void stretch_hvx_RGB16/ARGB4444/RGBA4444_up/down_KP_F */ ( void *dst, int dpitch, const void *src, int spitch, int width, int height, int dst_width, int dst_height, const StretchCtx *ctx ) { long x, y; long r = 0; long head = ((((unsigned long) dst) & 2) >> 1) ^ (ctx->clip.x1 & 1); long cw = ctx->clip.x2 - ctx->clip.x1 + 1; long ch = ctx->clip.y2 - ctx->clip.y1 + 1; long tail = (cw - head) & 1; long w2 = (cw - head) / 2; long hfraq = ((width - MINUS_1) << 18) / dst_width; long vfraq = ((height - MINUS_1) << 18) / dst_height; long dp4 = dpitch / 4; long point0 = POINT_0 + ctx->clip.x1 * hfraq; long point = point0; long line = LINE_0 + ctx->clip.y1 * vfraq; long ratios[cw]; u32 *dst32; u32 dt; u16 l_; u32 _lbT[w2+8]; u32 _lbB[w2+8]; u32 *lbX; u32 *lbT = (u32*) ((((unsigned long) (&_lbT[0])) + 31) & ~31); u32 *lbB = (u32*) ((((unsigned long) (&_lbB[0])) + 31) & ~31); long lineT = -2000; for (x = 0; x < cw; x++) { ratios[x] = POINT_TO_RATIO( point, hfraq ); point += hfraq; } HVX_DEBUG( "%dx%d -> %dx%d (0x%lx, 0x%lx) prot %lx, key %lx\n", width, height, dst_width, dst_height, (unsigned long) hfraq, (unsigned long) vfraq, ctx->protect, ctx->key ); dst += ctx->clip.x1 * 2 + ctx->clip.y1 * dpitch; dst32 = dst; if (head) { u32 dpT, dpB, L, R; u16 *dst16 = dst; point = point0; for (y = 0; y < ch; y++) { long X = LINE_TO_RATIO( line, vfraq ); const SOURCE_TYPE *srcT = src + spitch * LINE_T( line, vfraq ); const SOURCE_TYPE *srcB = src + spitch * LINE_B( line, vfraq ); /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "h,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); dpT = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) ) >> SHIFT_R6; L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) ) >> SHIFT_R6; /* Vertical interpolation. */ l_ = ((((((dpB & X_F81F) - (dpT & X_F81F)) * X) >> SHIFT_R5) + (dpT & X_F81F)) & X_F81F) + ((((((dpB >> SHIFT_R5) & X_003F) - ((dpT >> SHIFT_R5) & X_003F)) * X) + (dpT & X_07E0)) & X_07E0); #if defined(COLOR_KEY) || defined(KEY_PROTECT) #ifdef COLOR_KEY if ((l_ & MASK_RGB) != (COLOR_KEY)) #endif #ifdef KEY_PROTECT /* Write to destination with color key protection. */ dst16[0] = ((l_ & MASK_RGB) == KEY_PROTECT) ? l_ ^ 1 : l_; #else /* Write to destination without color key protection. */ dst16[0] = l_; #endif #else /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ /* Write to destination without color key protection. */ dst16[0] = l_; #endif /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ dst16 += dpitch / 2; line += vfraq; } /* Adjust. */ point0 += hfraq; dst32 = dst + 2; /* Reset. */ line = LINE_0 + ctx->clip.y1 * vfraq; } /* Scale line by line. */ for (y = 0; y < ch; y++) { long X; long nlT = LINE_T( line, vfraq ); D_ASSERT( nlT >= 0 ); D_ASSERT( nlT < height - 1 ); /* Fill line buffer(s). */ if (nlT != lineT) { u32 L, R, dpT, dpB; const SOURCE_TYPE *srcT = src + spitch * nlT; const SOURCE_TYPE *srcB = src + spitch * (nlT + 1); long diff = nlT - lineT; if (diff > 1) { /* Two output pixels per step. */ for (x = 0, r = head, point = point0; x < w2; x++) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); dpT = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) << SHIFT_L10; #else ) >> SHIFT_R6; #endif L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) << SHIFT_L10; #else ) >> SHIFT_R6; #endif point += hfraq; r++; pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); dpT |= (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) >> SHIFT_R6; #else ) << SHIFT_L10; #endif L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB |= (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) >> SHIFT_R6; #else ) << SHIFT_L10; #endif point += hfraq; r++; /* Store. */ lbT[x] = dpT; lbB[x] = dpB; } } else { /* Swap. */ lbX = lbT; lbT = lbB; lbB = lbX; /* Two output pixels per step. */ for (x = 0, r = head, point = point0; x < w2; x++) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) << SHIFT_L10; #else ) >> SHIFT_R6; #endif point += hfraq; r++; pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB |= (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) #ifdef WORDS_BIGENDIAN ) >> SHIFT_R6; #else ) << SHIFT_L10; #endif point += hfraq; r++; /* Store. */ lbB[x] = dpB; } } lineT = nlT; } /* Vertical interpolation. */ X = LINE_TO_RATIO( line, vfraq ); for (x = 0; x < w2; x++) { #ifdef HAS_ALPHA dt = ((((((lbB[x] & X_F81FF81F) - (lbT[x] & X_F81FF81F)) * X) >> SHIFT_R5) + (lbT[x] & X_F81FF81F)) & X_F81FF81F) + ((((((lbB[x] >> SHIFT_R5) & X_F81FF81F) - ((lbT[x] >> SHIFT_R5) & X_F81FF81F)) * X) + (lbT[x] & X_07E007E0)) & X_07E007E0); #else dt = ((((((lbB[x] & X_07E0F81F) - (lbT[x] & X_07E0F81F)) * X) >> SHIFT_R5) + (lbT[x] & X_07E0F81F)) & X_07E0F81F) + ((((((lbB[x] >> SHIFT_R5) & X_07C0F83F) - ((lbT[x] >> SHIFT_R5) & X_07C0F83F)) * X) + (lbT[x] & X_F81F07E0)) & X_F81F07E0); #endif #if defined(COLOR_KEY) || defined(KEY_PROTECT) u16 h_; /* Get two new pixels. */ l_ = dt; h_ = dt >> 16; #ifdef COLOR_KEY if ((l_ & MASK_RGB) != (COLOR_KEY)) { if ((h_ & MASK_RGB) != (COLOR_KEY)) { #ifdef KEY_PROTECT /* Write to destination with color key protection. */ dst32[x] = ((((h_ & MASK_RGB) == KEY_PROTECT) ? h_ ^ 1 : h_) << 16) | ( ((l_ & MASK_RGB) == KEY_PROTECT) ? l_ ^ 1 : l_); #else /* Write to destination without color key protection. */ dst32[x] = dt; #endif } else { u16 *_dst16 = (u16*) &dst32[x]; #ifdef KEY_PROTECT /* Write to destination with color key protection. */ *_dst16 = (((l_ & MASK_RGB) == KEY_PROTECT) ? l_ ^ 1 : l_); #else /* Write to destination without color key protection. */ *_dst16 = l_; #endif } } else if ((h_ & MASK_RGB) != (COLOR_KEY)) { u16 *_dst16 = ((u16*) &dst32[x]) + 1; #ifdef KEY_PROTECT /* Write to destination with color key protection. */ *_dst16 = (((h_ & MASK_RGB) == KEY_PROTECT) ? h_ ^ 1 : h_); #else /* Write to destination without color key protection. */ *_dst16 = h_; #endif } #else /* Write to destination with color key protection */ dst32[x] = ((((h_ & MASK_RGB) == KEY_PROTECT) ? h_ ^ 1 : h_) << 16) | ( ((l_ & MASK_RGB) == KEY_PROTECT) ? l_ ^ 1 : l_); #endif #else /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ dst32[x] = dt; #endif /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ } dst32 += dp4; line += vfraq; } if (tail) { u32 dpT, dpB, L, R; u16 *dst16 = dst + cw * 2 - 2; /* Reset. */ line = LINE_0 + ctx->clip.y1 * vfraq; for (y = 0; y < ch; y++) { long X = LINE_TO_RATIO( line, vfraq ); const SOURCE_TYPE *srcT = src + spitch * LINE_T( line, vfraq ); const SOURCE_TYPE *srcB = src + spitch * LINE_B( line, vfraq ); /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "t,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[r] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); dpT = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) ) >> SHIFT_R6; L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); dpB = (((((R & X_F81F) - (L & X_F81F)) * ratios[r] + ((L & X_F81F) << SHIFT_L6)) & X_003E07C0) + ((((R & X_07E0) - (L & X_07E0)) * ratios[r] + ((L & X_07E0) << SHIFT_L6)) & X_0001F800) ) >> SHIFT_R6; /* Vertical interpolation. */ l_ = ((((((dpB & X_F81F) - (dpT & X_F81F)) * X) >> SHIFT_R5) + (dpT & X_F81F)) & X_F81F) + ((((((dpB >> SHIFT_R5) & X_003F) - ((dpT >> SHIFT_R5) & X_003F)) * X) + (dpT & X_07E0)) & X_07E0); #if defined(COLOR_KEY) || defined(KEY_PROTECT) #ifdef COLOR_KEY if ((l_ & MASK_RGB) != (COLOR_KEY)) #endif #ifdef KEY_PROTECT /* Write to destination with color key protection. */ dst16[0] = ((l_ & MASK_RGB) == KEY_PROTECT) ? l_ ^ 1 : l_; #else /* Write to destination without color key protection. */ dst16[0] = l_; #endif #else /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ /* Write to destination without color key protection. */ dst16[0] = l_; #endif /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ dst16 += dpitch / 2; line += vfraq; } } } #undef SHIFT_L5 #undef SHIFT_L6 #undef SHIFT_L10 #undef X_003F #undef X_003E07C0 #undef X_0001F800 #undef X_07E0F81F #undef X_F81F07E0 #undef X_07C0F83F #ifdef SOURCE_LOOKUP_AUTO #undef SOURCE_LOOKUP_AUTO #undef SOURCE_LOOKUP #endif #ifdef SOURCE_TYPE_AUTO #undef SOURCE_TYPE_AUTO #undef SOURCE_TYPE #endif ================================================ FILE: src/gfx/generic/stretch_hvx_32.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef SOURCE_LOOKUP #define SOURCE_LOOKUP(x) (x) #define SOURCE_LOOKUP_AUTO #endif #ifndef SOURCE_TYPE #define SOURCE_TYPE u32 #define SOURCE_TYPE_AUTO #endif #if D_DEBUG_ENABLED #define HVX_DEBUG(x...) direct_log_printf( NULL, x ) #else #define HVX_DEBUG(x...) do {} while (0) #endif /* static void stretch_hvx_RGB32/ARGB_up/down_32_KPI */ ( void *dst, int dpitch, const void *src, int spitch, int width, int height, int dst_width, int dst_height, const StretchCtx *ctx ) { long x, y; long cw = ctx->clip.x2 - ctx->clip.x1 + 1; long ch = ctx->clip.y2 - ctx->clip.y1 + 1; long hfraq = ((width - MINUS_1) << 18) / dst_width; long vfraq = ((height - MINUS_1) << 18) / dst_height; long dp4 = dpitch / 4; long point0 = POINT_0 + ctx->clip.x1 * hfraq; long point = point0; long line = LINE_0 + ctx->clip.y1 * vfraq; long ratios[cw]; u32 *dst32; u32 dt; u32 _lbT[cw+8]; u32 _lbB[cw+8]; u32 *lbX; u32 *lbT = (u32*) ((((unsigned long) (&_lbT[0])) + 31) & ~31); u32 *lbB = (u32*) ((((unsigned long) (&_lbB[0])) + 31) & ~31); long lineT = -2000; for (x = 0; x < cw; x++) { ratios[x] = POINT_TO_RATIO( point, hfraq ); point += hfraq; } HVX_DEBUG( "%dx%d -> %dx%d (0x%lx, 0x%lx) prot %lx, key %lx\n", width, height, dst_width, dst_height, (unsigned long) hfraq, (unsigned long) vfraq, ctx->protect, ctx->key ); dst += ctx->clip.x1 * 4 + ctx->clip.y1 * dpitch; dst32 = dst; /* Scale line by line. */ for (y = 0; y < ch; y++) { long X; long nlT = LINE_T( line, vfraq ); D_ASSERT( nlT >= 0 ); D_ASSERT( nlT < height - 1 ); /* Fill line buffer(s). */ if (nlT != lineT) { u32 L, R; const SOURCE_TYPE *srcT = src + spitch * nlT; const SOURCE_TYPE *srcB = src + spitch * (nlT + 1); long diff = nlT - lineT; if (diff > 1) { for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); lbT[x] = ((((((R & X_00FF00FF) - (L & X_00FF00FF)) * ratios[x]) >> SHIFT_R8) + (L & X_00FF00FF)) & X_00FF00FF) + ((((((R >> SHIFT_R8) & X_00FF00FF) - ((L >> SHIFT_R8) & X_00FF00FF)) * ratios[x]) + (L & X_FF00FF00)) & X_FF00FF00); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = ((((((R & X_00FF00FF) - (L & X_00FF00FF)) * ratios[x]) >> SHIFT_R8) + (L & X_00FF00FF)) & X_00FF00FF) + ((((((R >> SHIFT_R8) & X_00FF00FF) - ((L >> SHIFT_R8) & X_00FF00FF)) * ratios[x]) + (L & X_FF00FF00)) & X_FF00FF00); } } else { /* Swap. */ lbX = lbT; lbT = lbB; lbB = lbX; for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = ((((((R & X_00FF00FF) - (L & X_00FF00FF)) * ratios[x]) >> SHIFT_R8) + (L & X_00FF00FF)) & X_00FF00FF) + ((((((R >> SHIFT_R8) & X_00FF00FF) - ((L >> SHIFT_R8) & X_00FF00FF)) * ratios[x]) + (L & X_FF00FF00)) & X_FF00FF00); } } lineT = nlT; } /* Vertical interpolation. */ X = LINE_TO_RATIO( line, vfraq ); for (x = 0; x < cw; x++) { dt = ((((((lbB[x] & X_00FF00FF) - (lbT[x] & X_00FF00FF)) * X) >> SHIFT_R8) + (lbT[x] & X_00FF00FF)) & X_00FF00FF) + ((((((lbB[x] >> SHIFT_R8) & X_00FF00FF) - ((lbT[x] >> SHIFT_R8) & X_00FF00FF)) * X) + (lbT[x] & X_FF00FF00)) & X_FF00FF00); #if defined(COLOR_KEY) || defined(KEY_PROTECT) #ifdef COLOR_KEY if (dt != (COLOR_KEY)) #endif #ifdef KEY_PROTECT /* Write to destination with color key protection. */ dst32[x] = ((dt & MASK_RGB) == KEY_PROTECT) ? dt ^ 1 : dt; #else /* Write to destination without color key protection. */ dst32[x] = dt; #endif #else /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ /* Write to destination without color key protection. */ dst32[x] = dt; #endif /* defined(COLOR_KEY) || defined(KEY_PROTECT) */ } dst32 += dp4; line += vfraq; } } #ifdef SOURCE_LOOKUP_AUTO #undef SOURCE_LOOKUP_AUTO #undef SOURCE_LOOKUP #endif #ifdef SOURCE_TYPE_AUTO #undef SOURCE_TYPE_AUTO #undef SOURCE_TYPE #endif ================================================ FILE: src/gfx/generic/stretch_hvx_8.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define SOURCE_LOOKUP(x) (x) #define SOURCE_TYPE u8 #if D_DEBUG_ENABLED #define HVX_DEBUG(x...) direct_log_printf( NULL, x ) #else #define HVX_DEBUG(x...) do {} while (0) #endif /* static void stretch_hvx_8_up/down */ ( void *dst, int dpitch, const void *src, int spitch, int width, int height, int dst_width, int dst_height, DFBRegion *clip ) { long x, y; long cw = clip->x2 - clip->x1 + 1; long ch = clip->y2 - clip->y1 + 1; long hfraq = ((width - MINUS_1) << 18) / dst_width; long vfraq = ((height - MINUS_1) << 18) / dst_height; long point0 = POINT_0 + clip->x1 * hfraq; long point = point0; long line = LINE_0 + clip->y1 * vfraq; long ratios[cw]; u8 *dst8; u8 _lbT[cw+32]; u8 _lbB[cw+32]; u8 *lbX; u8 *lbT = (u8*) ((((unsigned long) (&_lbT[0])) + 31) & ~31); u8 *lbB = (u8*) ((((unsigned long) (&_lbB[0])) + 31) & ~31); long lineT = -2000; for (x = 0; x < cw; x++) { ratios[x] = POINT_TO_RATIO( point, hfraq ); point += hfraq; } HVX_DEBUG( "%dx%d -> %dx%d (0x%lx, 0x%lx)\n", width, height, dst_width, dst_height, (unsigned long) hfraq, (unsigned long) vfraq ); dst += clip->x1 + clip->y1 * dpitch; dst8 = dst; /* Scale line by line. */ for (y = 0; y < ch; y++) { long X; long nlT = LINE_T( line, vfraq ); D_ASSERT( nlT >= 0 ); D_ASSERT( nlT < height - 1 ); /* Fill line buffer(s). */ if (nlT != lineT) { u8 L, R; const SOURCE_TYPE *srcT = src + spitch * nlT; const SOURCE_TYPE *srcB = src + spitch * (nlT + 1); long diff = nlT - lineT; if (diff > 1) { for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); lbT[x] = (((R - L) * ratios[x]) >> 8) + L; L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = (((R - L) * ratios[x]) >> 8) + L; } } else { /* Swap. */ lbX = lbT; lbT = lbB; lbB = lbX; for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = (((R - L) * ratios[x]) >> 8) + L; } } lineT = nlT; } /* Vertical interpolation. */ X = LINE_TO_RATIO( line, vfraq ); for (x = 0; x < cw; x++) dst8[x] = (((lbB[x] - lbT[x]) * X) >> 8) + lbT[x]; dst8 += dpitch; line += vfraq; } } #undef SOURCE_LOOKUP #undef SOURCE_TYPE ================================================ FILE: src/gfx/generic/stretch_hvx_88.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define SOURCE_LOOKUP(x) (x) #define SOURCE_TYPE u16 #if D_DEBUG_ENABLED #define HVX_DEBUG(x...) direct_log_printf( NULL, x ) #else #define HVX_DEBUG(x...) do {} while (0) #endif /* static void stretch_hvx_88_up/down */ ( void *dst, int dpitch, const void *src, int spitch, int width, int height, int dst_width, int dst_height, DFBRegion *clip ) { long x, y; long cw = clip->x2 - clip->x1 + 1; long ch = clip->y2 - clip->y1 + 1; long hfraq = ((width - MINUS_1) << 18) / dst_width; long vfraq = ((height - MINUS_1) << 18) / dst_height; long point0 = POINT_0 + clip->x1 * hfraq; long point = point0; long line = LINE_0 + clip->y1 * vfraq; long ratios[cw]; u16 *dst16; u16 _lbT[cw+16]; u16 _lbB[cw+16]; u16 *lbX; u16 *lbT = (u16*) ((((unsigned long) (&_lbT[0])) + 31) & ~31); u16 *lbB = (u16*) ((((unsigned long) (&_lbB[0])) + 31) & ~31); long lineT = -2000; for (x = 0; x < cw; x++) { ratios[x] = POINT_TO_RATIO( point, hfraq ); point += hfraq; } HVX_DEBUG( "%dx%d -> %dx%d (0x%lx, 0x%lx)\n", width, height, dst_width, dst_height, (unsigned long) hfraq, (unsigned long) vfraq ); dst += clip->x1 * 2 + clip->y1 * dpitch; dst16 = dst; /* Scale line by line. */ for (y = 0; y < ch; y++) { long X; long nlT = LINE_T( line, vfraq ); D_ASSERT( nlT >= 0 ); D_ASSERT( nlT < height - 1 ); /* Fill line buffer(s). */ if (nlT != lineT) { u16 L, R; const SOURCE_TYPE *srcT = src + spitch * nlT; const SOURCE_TYPE *srcB = src + spitch * (nlT + 1); long diff = nlT - lineT; if (diff > 1) { for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcT[pl] ); R = SOURCE_LOOKUP( srcT[pl+1] ); lbT[x] = (((((R & 0x00ff) - (L & 0x00ff)) * ratios[x] + ((L & 0x00ff) << 8)) & 0x00ff00) + ((((R & 0xff00) - (L & 0xff00)) * ratios[x] + ((L & 0xff00) << 8)) & 0xff0000)) >> 8; L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = (((((R & 0x00ff) - (L & 0x00ff)) * ratios[x] + ((L & 0x00ff) << 8)) & 0x00ff00) + ((((R & 0xff00) - (L & 0xff00)) * ratios[x] + ((L & 0xff00) << 8)) & 0xff0000)) >> 8; } } else { /* Swap. */ lbX = lbT; lbT = lbB; lbB = lbX; for (x = 0, point = point0; x < cw; x++, point += hfraq) { /* Horizontal interpolation. */ long pl = POINT_L( point, hfraq ); HVX_DEBUG( "%ld,%ld %ld (%ld/%ld) 0x%lx 0x%lx\n", x, y, pl, POINT_L( point, hfraq ), POINT_R( point, hfraq ), (unsigned long) point, (unsigned long) ratios[x] ); D_ASSERT( pl >= 0 ); D_ASSERT( pl < width - 1 ); L = SOURCE_LOOKUP( srcB[pl] ); R = SOURCE_LOOKUP( srcB[pl+1] ); lbB[x] = (((((R & 0x00ff) - (L & 0x00ff)) * ratios[x] + ((L & 0x00ff) << 8)) & 0x00ff00) + ((((R & 0xff00) - (L & 0xff00)) * ratios[x] + ((L & 0xff00) << 8)) & 0xff0000)) >> 8; } } lineT = nlT; } /* Vertical interpolation. */ X = LINE_TO_RATIO( line, vfraq ); for (x = 0; x < cw; x++) dst16[x] = (((((lbB[x] & 0x00ff) - (lbT[x] & 0x00ff)) * X + ((lbT[x] & 0x00ff) << 8)) & 0x00ff00) + ((((lbB[x] & 0xff00) - (lbT[x] & 0xff00)) * X + ((lbT[x] & 0xff00) << 8)) & 0xff0000)) >> 8; dst16 += dpitch / 2; line += vfraq; } } #undef SOURCE_LOOKUP #undef SOURCE_TYPE ================================================ FILE: src/gfx/generic/stretch_hvx_N.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #if UPDOWN == 1 #define FUNC_NAME_(K,P,F) FUNC_NAME(up,K,P,F) #else #define FUNC_NAME_(K,P,F) FUNC_NAME(down,K,P,F) #endif /**********************************************************************************************************************/ /* DST_FORMAT */ /* DST_FORMAT NONE */ static void FUNC_NAME_(_,_,DST_FORMAT) #include STRETCH_HVX_N_H /* DST_FORMAT SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,_,DST_FORMAT) #include STRETCH_HVX_N_H #undef COLOR_KEY /* DST_FORMAT PROTECT */ #define KEY_PROTECT ctx->protect static void FUNC_NAME_(_,P,DST_FORMAT) #include STRETCH_HVX_N_H /* DST_FORMAT SRCKEY PROTECT */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,P,DST_FORMAT) #include STRETCH_HVX_N_H #undef COLOR_KEY #undef KEY_PROTECT /**********************************************************************************************************************/ /* DSPF_LUT8 */ #define SOURCE_LOOKUP(x) ((const uN*) ctx->colors)[x] #define SOURCE_TYPE u8 /* DSPF_LUT8 NONE */ static void FUNC_NAME_(_,_,DSPF_LUT8) #include STRETCH_HVX_N_H /* DSPF_LUT8 SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,_,DSPF_LUT8) #include STRETCH_HVX_N_H #undef COLOR_KEY /* DSPF_LUT8 PROTECT */ #define KEY_PROTECT ctx->protect static void FUNC_NAME_(_,P,DSPF_LUT8) #include STRETCH_HVX_N_H /* DSPF_LUT8 SRCKEY PROTECT */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,P,DSPF_LUT8) #include STRETCH_HVX_N_H #undef COLOR_KEY #undef KEY_PROTECT #undef SOURCE_LOOKUP #undef SOURCE_TYPE #ifdef FORMAT_RGB16 /**********************************************************************************************************************/ /* DSPF_ARGB4444 */ #define SOURCE_LOOKUP(x) PIXEL_RGB16( (((x) & 0x0f00) >> 4) | (((x) & 0x0f00) >> 8), \ ( (x) & 0x00f0 ) | (((x) & 0x00f0) >> 4), \ (((x) & 0x000f) << 4) | ( (x) & 0x000f ) ) /* DSPF_ARGB4444 NONE */ static void FUNC_NAME_(_,_,DSPF_ARGB4444) #include STRETCH_HVX_N_H /* DSPF_ARGB4444 SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,_,DSPF_ARGB4444) #include STRETCH_HVX_N_H #undef COLOR_KEY /* DSPF_ARGB4444 PROTECT */ #define KEY_PROTECT ctx->protect static void FUNC_NAME_(_,P,DSPF_ARGB4444) #include STRETCH_HVX_N_H /* DSPF_ARGB4444 PROTECT SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,P,DSPF_ARGB4444) #include STRETCH_HVX_N_H #undef COLOR_KEY #undef KEY_PROTECT #undef SOURCE_LOOKUP #endif /* FORMAT_RGB16 */ #ifdef FORMAT_ARGB4444 /**********************************************************************************************************************/ /* DSPF_RGB16 */ #define SOURCE_LOOKUP(x) PIXEL_ARGB4444( 0xff, \ (((x) & 0xf800) >> 8), \ (((x) & 0x07e0) >> 3), \ (((x) & 0x001f) << 3) ) /* DSPF_RGB16 NONE */ static void FUNC_NAME_(_,_,DSPF_RGB16) #include STRETCH_HVX_N_H /* DSPF_RGB16 SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,_,DSPF_RGB16) #include STRETCH_HVX_N_H #undef COLOR_KEY /* DSPF_RGB16 PROTECT */ #define KEY_PROTECT ctx->protect static void FUNC_NAME_(_,P,DSPF_RGB16) #include STRETCH_HVX_N_H /* DSPF_RGB16 PROTECT SRCKEY */ #define COLOR_KEY ctx->key static void FUNC_NAME_(K,P,DSPF_RGB16) #include STRETCH_HVX_N_H #undef COLOR_KEY #undef KEY_PROTECT #undef SOURCE_LOOKUP #endif /* FORMAT_ARGB4444 */ /**********************************************************************************************************************/ #undef FUNC_NAME_ ================================================ FILE: src/gfx/generic/stretch_up_down_16.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define STRETCH_HVX_N_H "stretch_hvx_16.h" #define uN u16 /**********************************************************************************************************************/ /* Upscaling */ #define POINT_0 0 #define LINE_0 0 #define MINUS_1 1 #define POINT_TO_RATIO(p,ps) ( ((p) & 0x3ffff) >> (18 - SHIFT_L6) ) #define LINE_TO_RATIO(l,ls) ( ((l) & 0x3ffff) >> (18 - SHIFT_L5) ) #define POINT_L(p,ps) ( (p) >> 18 ) #define POINT_R(p,ps) ( ((p) >> 18) + 1 ) #define LINE_T(l,ls) ( (l) >> 18 ) #define LINE_B(l,ls) ( ((l) >> 18) + 1 ) #define UPDOWN 1 #include "stretch_hvx_N.h" #undef UPDOWN #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ /* Downscaling */ #define POINT_0 hfraq #define LINE_0 vfraq #define MINUS_1 0 #define POINT_TO_RATIO(p,ps) ( ((((p) & 0x3ffff) ?: 0x40000) << SHIFT_L6) / (ps) ) #define LINE_TO_RATIO(l,ls) ( ((((l) & 0x3ffff) ?: 0x40000) << SHIFT_L5) / (ls) ) #define POINT_L(p,ps) ( (((p) - 1) >> 18) - 1 ) #define POINT_R(p,ps) ( ((p) - 1) >> 18 ) #define LINE_T(l,ls) ( (((l) - 1) >> 18) - 1 ) #define LINE_B(l,ls) ( ((l) - 1) >> 18 ) #define UPDOWN 0 #include "stretch_hvx_N.h" #undef UPDOWN #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ #undef STRETCH_HVX_N_H #undef uN #include "stretch_up_down_table.h" ================================================ FILE: src/gfx/generic/stretch_up_down_32.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define STRETCH_HVX_N_H "stretch_hvx_32.h" #define uN u32 /**********************************************************************************************************************/ /* Upscaling */ #define POINT_0 0 #define LINE_0 0 #define MINUS_1 1 #define POINT_TO_RATIO(p,ps) ( ((p) & 0x3ffff) >> (18 - SHIFT_L8) ) #define LINE_TO_RATIO(l,ls) ( ((l) & 0x3ffff) >> (18 - SHIFT_L8) ) #define POINT_L(p,ps) ( (p) >> 18 ) #define POINT_R(p,ps) ( ((p) >> 18) + 1 ) #define LINE_T(l,ls) ( (l) >> 18 ) #define LINE_B(l,ls) ( ((l) >> 18) + 1 ) #define UPDOWN 1 #include "stretch_hvx_N.h" #undef UPDOWN #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ /* Downscaling */ #define POINT_0 hfraq #define LINE_0 vfraq #define MINUS_1 0 #define POINT_TO_RATIO(p,ps) ( ((((p) & 0x3ffff) ?: 0x40000) << SHIFT_L8) / (ps) ) #define LINE_TO_RATIO(l,ls) ( ((((l) & 0x3ffff) ?: 0x40000) << SHIFT_L8) / (ls) ) #define POINT_L(p,ps) ( (((p) - 1) >> 18) - 1 ) #define POINT_R(p,ps) ( ((p) - 1) >> 18 ) #define LINE_T(l,ls) ( (((l) - 1) >> 18) - 1 ) #define LINE_B(l,ls) ( ((l) - 1) >> 18 ) #define UPDOWN 0 #include "stretch_hvx_N.h" #undef UPDOWN #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ #undef STRETCH_HVX_N_H #undef uN #include "stretch_up_down_table.h" ================================================ FILE: src/gfx/generic/stretch_up_down_8.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /**********************************************************************************************************************/ /* Upscaling */ #define POINT_0 0 #define LINE_0 0 #define MINUS_1 1 #define POINT_TO_RATIO(p,ps) ( ((p) & 0x3ffff) >> (18 - 8) ) #define LINE_TO_RATIO(l,ls) ( ((l) & 0x3ffff) >> (18 - 8) ) #define POINT_L(p,ps) ( (p) >> 18 ) #define POINT_R(p,ps) ( ((p) >> 18) + 1 ) #define LINE_T(l,ls) ( (l) >> 18 ) #define LINE_B(l,ls) ( ((l) >> 18) + 1 ) static void FUNC_NAME(up) #include "stretch_hvx_8.h" #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ /* Downscaling */ #define POINT_0 hfraq #define LINE_0 vfraq #define MINUS_1 0 #define POINT_TO_RATIO(p,ps) ( ((((p) & 0x3ffff) ?: 0x40000) << 8) / (ps) ) #define LINE_TO_RATIO(l,ls) ( ((((l) & 0x3ffff) ?: 0x40000) << 8) / (ls) ) #define POINT_L(p,ps) ( (((p) - 1) >> 18) - 1 ) #define POINT_R(p,ps) ( ((p) - 1) >> 18 ) #define LINE_T(l,ls) ( (((l) - 1) >> 18) - 1 ) #define LINE_B(l,ls) ( ((l) - 1) >> 18 ) static void FUNC_NAME(down) #include "stretch_hvx_8.h" #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B ================================================ FILE: src/gfx/generic/stretch_up_down_88.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /**********************************************************************************************************************/ /* Upscaling */ #define POINT_0 0 #define LINE_0 0 #define MINUS_1 1 #define POINT_TO_RATIO(p,ps) ( ((p) & 0x3ffff) >> (18 - 8) ) #define LINE_TO_RATIO(l,ls) ( ((l) & 0x3ffff) >> (18 - 8) ) #define POINT_L(p,ps) ( (p) >> 18 ) #define POINT_R(p,ps) ( ((p) >> 18) + 1 ) #define LINE_T(l,ls) ( (l) >> 18 ) #define LINE_B(l,ls) ( ((l) >> 18) + 1 ) static void FUNC_NAME(up) #include "stretch_hvx_88.h" #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B /**********************************************************************************************************************/ /* Downscaling */ #define POINT_0 hfraq #define LINE_0 vfraq #define MINUS_1 0 #define POINT_TO_RATIO(p,ps) ( ((((p) & 0x3ffff) ?: 0x40000) << 8) / (ps) ) #define LINE_TO_RATIO(l,ls) ( ((((l) & 0x3ffff) ?: 0x40000) << 8) / (ls) ) #define POINT_L(p,ps) ( (((p) - 1) >> 18) - 1 ) #define POINT_R(p,ps) ( ((p) - 1) >> 18 ) #define LINE_T(l,ls) ( (((l) - 1) >> 18) - 1 ) #define LINE_B(l,ls) ( ((l) - 1) >> 18 ) static void FUNC_NAME(down) #include "stretch_hvx_88.h" #undef POINT_0 #undef LINE_0 #undef MINUS_1 #undef POINT_TO_RATIO #undef LINE_TO_RATIO #undef POINT_L #undef POINT_R #undef LINE_T #undef LINE_B ================================================ FILE: src/gfx/generic/stretch_up_down_table.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ static const StretchFunctionTable TABLE_NAME = { #define FUNC_NAME_(K,P,F) FUNC_NAME(up,K,P,F) .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].up[STRETCH_NONE] = FUNC_NAME_(_,_,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].up[STRETCH_PROTECT] = FUNC_NAME_(_,P,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].up[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].up[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].up[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].up[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].up[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].up[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_LUT8), #ifdef FORMAT_RGB16 .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].up[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].up[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].up[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].up[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_ARGB4444), #endif #ifdef FORMAT_ARGB4444 .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].up[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].up[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].up[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].up[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_RGB16), #endif #undef FUNC_NAME_ #define FUNC_NAME_(K,P,F) FUNC_NAME(down,K,P,F) .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].down[STRETCH_NONE] = FUNC_NAME_(_,_,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].down[STRETCH_PROTECT] = FUNC_NAME_(_,P,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].down[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DST_FORMAT)].down[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DST_FORMAT), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].down[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].down[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].down[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_LUT8), .f[DFB_PIXELFORMAT_INDEX(DSPF_LUT8)].down[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_LUT8), #ifdef FORMAT_RGB16 .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].down[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].down[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].down[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_ARGB4444), .f[DFB_PIXELFORMAT_INDEX(DSPF_ARGB4444)].down[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_ARGB4444), #endif #ifdef FORMAT_ARGB4444 .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].down[STRETCH_NONE] = FUNC_NAME_(_,_,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].down[STRETCH_PROTECT] = FUNC_NAME_(_,P,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].down[STRETCH_SRCKEY] = FUNC_NAME_(K,_,DSPF_RGB16), .f[DFB_PIXELFORMAT_INDEX(DSPF_RGB16)].down[STRETCH_SRCKEY_PROTECT] = FUNC_NAME_(K,P,DSPF_RGB16), #endif #undef FUNC_NAME_ }; ================================================ FILE: src/gfx/generic/template_acc_16.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define RGB_MASK (R_MASK | G_MASK | B_MASK) #if RGB_MASK == 0xffff #define MASK_RGB(p) (p) #else #define MASK_RGB(p) ((p) & RGB_MASK) #endif #define PIXEL(x) PIXEL_OUT( ((x).RGB.a & 0xff00) ? 0xff : (x).RGB.a, \ ((x).RGB.r & 0xff00) ? 0xff : (x).RGB.r, \ ((x).RGB.g & 0xff00) ? 0xff : (x).RGB.g, \ ((x).RGB.b & 0xff00) ? 0xff : (x).RGB.b ) #define EXPAND(d,s) do { \ (d).RGB.a = EXPAND_Ato8( (s & A_MASK) >> A_SHIFT ); \ (d).RGB.r = EXPAND_Rto8( (s & R_MASK) >> R_SHIFT ); \ (d).RGB.g = EXPAND_Gto8( (s & G_MASK) >> G_SHIFT ); \ (d).RGB.b = EXPAND_Bto8( (s & B_MASK) >> B_SHIFT ); \ } while (0) /********************************************************************************************************************** ********************************* Sop_PFI_to_Dacc ******************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(to)( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int Ostep = gfxs->Ostep; if (Ostep != 1) { w++; while (--w) { u16 s = *S; EXPAND( *D, s ); S += Ostep; ++D; } return; } if ((long) S & 2) { u16 s = *S++; EXPAND( *D, s ); ++D; --w; } l = (w >> 1) + 1; while (--l) { u32 s = *(u32*) S; #ifdef WORDS_BIGENDIAN EXPAND( D[0], s >> 16 ); EXPAND( D[1], s ); #else EXPAND( D[0], s ); EXPAND( D[1], s >> 16 ); #endif S += 2; D += 2; } if (w & 1) { u16 s = *S; EXPAND( *D, s ); } } /********************************************************************************************************************** ********************************* Sop_PFI_Kto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Kto)( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u16 Skey = gfxs->Skey; int Ostep = gfxs->Ostep; while (--w) { u16 s = *S; if (MASK_RGB( s ) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; S += Ostep; ++D; } } /********************************************************************************************************************** ********************************* Sop_PFI_Sto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Sto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u16 s = S[i>>16]; EXPAND( *D, s ); ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_SKto_Dacc ****************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u16 Skey = gfxs->Skey; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u16 s = S[i>>16]; if (MASK_RGB( s ) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_to_Dacc **************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_to)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp2 = gfxs->src_pitch / 2; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u16 p = S[(s>>16)+(t>>16)*sp2]; EXPAND( *D, p ); ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_Kto_Dacc *************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_Kto)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u16 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp2 = gfxs->src_pitch / 2; u16 Skey = gfxs->Skey; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u16 p = S[(s>>16)+(t>>16)*sp2]; if ((p & RGB_MASK) != Skey) EXPAND( *D, p ); else D->RGB.a = 0xf000; ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sacc_to_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(to)( GenefxState *gfxs ) { int l; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; if (Dstep != 1) { w++; while (--w) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++S; D += Dstep; } return; } if ((long) D & 2) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++S; ++D; --w; } l = (w >> 1) + 1; while (--l) { u32 *D2 = (u32*) D; if (!(S[0].RGB.a & 0xf000) && !(S[1].RGB.a & 0xf000)) { #ifdef WORDS_BIGENDIAN *D2 = PIXEL( S[1] ) | PIXEL( S[0] ) << 16; #else *D2 = PIXEL( S[0] ) | PIXEL( S[1] ) << 16; #endif } else { if (!(S[0].RGB.a & 0xf000)) D[0] = PIXEL( S[0] ); else if (!(S[1].RGB.a & 0xf000)) D[1] = PIXEL( S[1] ); } S += 2; D += 2; } if (w & 1) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); } } /********************************************************************************************************************** ********************************* Sacc_toK_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; u16 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; while (--w) { if (!(S->RGB.a & 0xf000) && MASK_RGB( *D ) == Dkey) *D = PIXEL( *S ); ++S; D += Dstep; } } /********************************************************************************************************************** ********************************* Sacc_Sto_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(Sto)( GenefxState *gfxs ) { int l; int i = gfxs->Xphase; int w = gfxs->length; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; if (Dstep != 1) { w++; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) *D = PIXEL( *S0 ); D += Dstep; i += SperD; } return; } if ((long) D & 2) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++D; --w; i += SperD; } l = (w >> 1) + 1; while (--l) { GenefxAccumulator *S0 = &S[i>>16]; GenefxAccumulator *S1 = &S[(i+SperD)>>16]; u32 *D2 = (u32*) D; if (!(S0->RGB.a & 0xf000) && !(S1->RGB.a & 0xf000)) { #ifdef WORDS_BIGENDIAN *D2 = PIXEL( *S1 ) | PIXEL( *S0 ) << 16; #else *D2 = PIXEL( *S0 ) | PIXEL( *S1 ) << 16; #endif } else { if (!(S0->RGB.a & 0xf000)) D[0] = PIXEL( *S0 ); else if (!(S1->RGB.a & 0xf000)) D[1] = PIXEL( *S1 ); } D += 2; i += SperD << 1; } if (w & 1) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) *D = PIXEL( *S0 ); } } /********************************************************************************************************************** ********************************* Sacc_StoK_Aop_PFI ****************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u16 *D = gfxs->Aop[0]; u16 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000) && MASK_RGB( *D ) == Dkey) *D = PIXEL( *S0 ); D += Dstep; i += SperD; } } /**********************************************************************************************************************/ #undef RGB_MASK #undef MASK_RGB #undef PIXEL #undef EXPAND #undef A_SHIFT #undef R_SHIFT #undef G_SHIFT #undef B_SHIFT #undef A_MASK #undef R_MASK #undef G_MASK #undef B_MASK #undef PIXEL_OUT #undef EXPAND_Ato8 #undef EXPAND_Rto8 #undef EXPAND_Gto8 #undef EXPAND_Bto8 #undef Sop_PFI_OP_Dacc #undef Sacc_OP_Aop_PFI ================================================ FILE: src/gfx/generic/template_acc_24.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define RGB_MASK (R_MASK | G_MASK | B_MASK) #if RGB_MASK == 0xffffff #define MASK_RGB(p) (p) #else #define MASK_RGB(p) ((p) & RGB_MASK) #endif #define PIXEL(x) PIXEL_OUT( ((x).RGB.a & 0xff00) ? 0xff : (x).RGB.a, \ ((x).RGB.r & 0xff00) ? 0xff : (x).RGB.r, \ ((x).RGB.g & 0xff00) ? 0xff : (x).RGB.g, \ ((x).RGB.b & 0xff00) ? 0xff : (x).RGB.b ) #define EXPAND(d,s) do { \ (d).RGB.a = EXPAND_Ato8( (s & A_MASK) >> A_SHIFT ); \ (d).RGB.r = EXPAND_Rto8( (s & R_MASK) >> R_SHIFT ); \ (d).RGB.g = EXPAND_Gto8( (s & G_MASK) >> G_SHIFT ); \ (d).RGB.b = EXPAND_Bto8( (s & B_MASK) >> B_SHIFT ); \ } while (0) #ifdef WORD_BIGENDIAN #define READ_PIXEL(S) \ ( \ ((S)[0] << 16) | \ ((S)[1] << 8) | \ (S)[2] \ ) #define WRITE_PIXEL(D,pix) \ do { \ (D)[0] = ((pix) >> 16) & 0xff; \ (D)[1] = ((pix) >> 8) & 0xff; \ (D)[2] = (pix) & 0xff; \ } while (0) #else #define READ_PIXEL(S) \ ( \ ((S)[2] << 16) | \ ((S)[1] << 8) | \ (S)[0] \ ) #define WRITE_PIXEL(D,pix) \ do { \ (D)[0] = (pix) & 0xff; \ (D)[1] = ((pix) >> 8) & 0xff; \ (D)[2] = ((pix) >> 16) & 0xff; \ } while (0) #endif /********************************************************************************************************************** ********************************* Sop_PFI_to_Dacc ******************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(to)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int Ostep = gfxs->Ostep * 3; while (--w) { u32 s = READ_PIXEL( S ); EXPAND( *D, s ); S += Ostep; ++D; } } /********************************************************************************************************************** ********************************* Sop_PFI_Kto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Kto)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep * 3; while (--w) { u32 s = READ_PIXEL( S ); if (MASK_RGB( s ) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; S += Ostep; ++D; } } /********************************************************************************************************************** ********************************* Sop_PFI_Sto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Sto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { int pixelstart = (i >> 16) * 3; u32 s = READ_PIXEL( &S[pixelstart] ); EXPAND( *D, s ); ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_SKto_Dacc ****************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { int pixelstart = (i >> 16) * 3; u32 s = READ_PIXEL( &S[pixelstart] ); if (MASK_RGB( s ) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_to_Dacc **************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_to)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp3 = gfxs->src_pitch / 3; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep * 3; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { int pixelstart = ((s >> 16) + (t >> 16) * sp3) * 3; u32 p = READ_PIXEL( &S[pixelstart] ); EXPAND( *D, p ); ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_Kto_Dacc *************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_Kto)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u8 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp3 = gfxs->src_pitch / 3; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep * 3; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { int pixelstart = ((s >> 16) + (t >> 16) * sp3) * 3; u32 p = READ_PIXEL( &S[pixelstart] ); if (MASK_RGB( p ) != Skey) EXPAND( *D, p ); else D->RGB.a = 0xf000; ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sacc_to_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(to)( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep * 3; while (--w) { if (!(S->RGB.a & 0xf000)) { u32 pix = PIXEL( *S ); WRITE_PIXEL( D, pix ); } ++S; D += Dstep; } } /********************************************************************************************************************** ********************************* Sacc_toK_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep * 3; while (--w) { if (!(S->RGB.a & 0xf000)) { u32 pix = READ_PIXEL( D ); if (MASK_RGB( pix ) == Dkey) { pix = PIXEL( *S ); WRITE_PIXEL( D, pix ); } } ++S; D += Dstep; } } /********************************************************************************************************************** ********************************* Sacc_Sto_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(Sto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep * 3; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) { u32 pix = PIXEL( *S0 ); WRITE_PIXEL( D, pix ); } D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Sacc_StoK_Aop_PFI ****************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep * 3; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) { u32 pix = READ_PIXEL( D ); if (MASK_RGB( pix ) == Dkey) { pix = PIXEL( *S0 ); WRITE_PIXEL( D, pix ); } } D += Dstep; i += SperD; } } /**********************************************************************************************************************/ #undef RGB_MASK #undef MASK_RGB #undef PIXEL #undef EXPAND #undef READ_PIXEL #undef WRITE_PIXEL #undef A_SHIFT #undef R_SHIFT #undef G_SHIFT #undef B_SHIFT #undef A_MASK #undef R_MASK #undef G_MASK #undef B_MASK #undef PIXEL_OUT #undef EXPAND_Ato8 #undef EXPAND_Rto8 #undef EXPAND_Gto8 #undef EXPAND_Bto8 #undef Sop_PFI_OP_Dacc #undef Sacc_OP_Aop_PFI ================================================ FILE: src/gfx/generic/template_acc_32.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #define RGB_MASK (R_MASK | G_MASK | B_MASK) #define PIXEL(s) PIXEL_OUT( ((s).RGB.a & 0xff00) ? 0xff : (s).RGB.a, \ ((s).RGB.r & 0xff00) ? 0xff : (s).RGB.r, \ ((s).RGB.g & 0xff00) ? 0xff : (s).RGB.g, \ ((s).RGB.b & 0xff00) ? 0xff : (s).RGB.b ) #define EXPAND(d,s) \ do { \ (d).RGB.a = EXPAND_Ato8( (s & A_MASK) >> A_SHIFT ); \ (d).RGB.r = EXPAND_Rto8( (s & R_MASK) >> R_SHIFT ); \ (d).RGB.g = EXPAND_Gto8( (s & G_MASK) >> G_SHIFT ); \ (d).RGB.b = EXPAND_Bto8( (s & B_MASK) >> B_SHIFT ); \ } while (0) /********************************************************************************************************************** ********************************* Sop_PFI_to_Dacc ******************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(to)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int Ostep = gfxs->Ostep; while (--w) { u32 s = *S; EXPAND( *D, s ); S += Ostep; ++D; } } /********************************************************************************************************************** ********************************* Sop_PFI_Kto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Kto)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep; while (--w) { u32 s = *S; if ((s & RGB_MASK) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; S += Ostep; ++D; } } /********************************************************************************************************************** ********************************* Sop_PFI_Sto_Dacc ******************************************************************* **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(Sto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u32 s = S[i>>16]; EXPAND( *D, s ); ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_SKto_Dacc ****************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u32 s = S[i>>16]; if ((s & RGB_MASK) != Skey) EXPAND( *D, s ); else D->RGB.a = 0xf000; ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_to_Dacc **************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_to)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp4 = gfxs->src_pitch / 4; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u32 p = S[(s>>16) + (t>>16) * sp4]; EXPAND( *D, p ); ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sop_PFI_TEX_Kto_Dacc *************************************************************** **********************************************************************************************************************/ static void Sop_PFI_OP_Dacc(TEX_Kto)( GenefxState *gfxs ) { int s = gfxs->s; int t = gfxs->t; int w = gfxs->length + 1; u32 *S = gfxs->Sop[0]; GenefxAccumulator *D = gfxs->Dacc; int sp4 = gfxs->src_pitch / 4; u32 Skey = gfxs->Skey; int SperD = gfxs->SperD; int TperD = gfxs->TperD; int Ostep = gfxs->Ostep; if (Ostep != 1) D_UNIMPLEMENTED(); while (--w) { u32 p = S[(s>>16) + (t>>16) * sp4]; if ((p & RGB_MASK) != Skey) EXPAND( *D, p ); else D->RGB.a = 0xf000; ++D; s += SperD; t += TperD; } } /********************************************************************************************************************** ********************************* Sacc_to_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(to)( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; while (--w) { if (!(S->RGB.a & 0xf000)) *D = PIXEL( *S ); ++S; D += Dstep; } } /********************************************************************************************************************** ********************************* Sacc_toK_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; while (--w) { if (!(S->RGB.a & 0xf000) && (*D & RGB_MASK) == Dkey) *D = PIXEL( *S ); ++S; D += Dstep; } } /********************************************************************************************************************** ********************************* Sacc_Sto_Aop_PFI ******************************************************************* **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(Sto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000)) *D = PIXEL( *S0 ); D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Sacc_StoK_Aop_PFI ****************************************************************** **********************************************************************************************************************/ static void Sacc_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; GenefxAccumulator *S = gfxs->Sacc; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { GenefxAccumulator *S0 = &S[i>>16]; if (!(S0->RGB.a & 0xf000) && (*D & RGB_MASK) == Dkey) *D = PIXEL( *S0 ); D += Dstep; i += SperD; } } /**********************************************************************************************************************/ #undef RGB_MASK #undef PIXEL #undef EXPAND #undef A_SHIFT #undef R_SHIFT #undef G_SHIFT #undef B_SHIFT #undef A_MASK #undef R_MASK #undef G_MASK #undef B_MASK #undef PIXEL_OUT #undef EXPAND_Ato8 #undef EXPAND_Rto8 #undef EXPAND_Gto8 #undef EXPAND_Bto8 #undef Sop_PFI_OP_Dacc #undef Sacc_OP_Aop_PFI ================================================ FILE: src/gfx/generic/template_colorkey_16.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #if RGB_MASK == 0xffff #define MASK_RGB(p) (p) #else #define MASK_RGB(p) ((p) & RGB_MASK) #endif #define MASK_RGB_L(p) ((p) & RGB_MASK) #define MASK_RGB_H(p) ((p) & (RGB_MASK << 16)) #define MASK_RGB_32(p) ((p) & (RGB_MASK << 16 | RGB_MASK)) /********************************************************************************************************************** ********************************* Cop_toK_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Cop_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *D = gfxs->Aop[0]; u16 Cop = gfxs->Cop; u16 Dkey = gfxs->Dkey; while (--w) { if (MASK_RGB( *D ) == Dkey) *D = Cop; ++D; } } /********************************************************************************************************************** ********************************* Bop_PFI_toK_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Dkey = gfxs->Dkey; u32 DkeyH = gfxs->Dkey << 16; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } if (((long) S & 2) != ((long) D & 2)) { w++; while (--w) { if (MASK_RGB( *D ) == Dkey) *D = *S; S += Ostep; D += Ostep; } return; } if ((Ostep > 0)) { if ((long) D & 2) { if (MASK_RGB( *D ) == Dkey) *D = *S; ++S; ++D; --w; } } else { if ((long) D & 2) { --S; --D; } else { if (MASK_RGB( *D ) == Dkey) *D = *S; S -= 2; D -= 2; --w; } } Ostep <<= 1; l = (w >> 1) + 1; while (--l) { u32 d = *(u32*) D; if (MASK_RGB_32( d ) == (DkeyH | Dkey)) { *(u32*) D = *(u32*) S; } else { if (MASK_RGB_L( d ) == Dkey) { #ifdef WORDS_BIGENDIAN D[0] = S[0]; #else D[1] = S[1]; #endif } else if (MASK_RGB_H( d ) == DkeyH) { #ifdef WORDS_BIGENDIAN D[1] = S[1]; #else D[0] = S[0]; #endif } } S += Ostep; D += Ostep; } if (w & 1) { if (Ostep < 0) { ++S; ++D; } if (MASK_RGB( *D ) == Dkey) *D = *S; } } /********************************************************************************************************************** ********************************* Bop_PFI_Kto_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(Kto)( GenefxState *gfxs ) { int l; int w = gfxs->length; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Skey = gfxs->Skey; u32 SkeyH = gfxs->Skey << 16; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } if (((long) S & 2) != ((long) D & 2)) { w++; while (--w) { u16 s = *S; if (MASK_RGB( s ) != Skey) *D = s; S += Ostep; D += Ostep; } return; } if (Ostep > 0) { if ((long) D & 2) { u16 s = *S; if (MASK_RGB( s ) != Skey) *D = s; ++S; ++D; --w; } } else { if ((long) D & 2) { --S; --D; } else { u16 s = *S; if (MASK_RGB( s ) != Skey) *D = s; S -= 2; D -= 2; --w; } } Ostep <<= 1; l = (w >> 1) + 1; while (--l) { u32 s = *(u32*) S; if (MASK_RGB_L( s ) != Skey) { if (MASK_RGB_H( s ) != SkeyH) { *(u32*) D = s; } else { #ifdef WORDS_BIGENDIAN D[1] = (u16) s; #else D[0] = (u16) s; #endif } } else if (MASK_RGB_H( s ) != SkeyH) { #ifdef WORDS_BIGENDIAN D[0] = (u16) (s >> 16); #else D[1] = (u16) (s >> 16); #endif } S += Ostep; D += Ostep; } if (w & 1) { u16 s; if (Ostep < 0) { ++S; ++D; } s = *S; if (MASK_RGB( s ) != Skey) *D = s; } } /********************************************************************************************************************** ********************************* Bop_PFI_KtoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(KtoK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Skey = gfxs->Skey; u16 Dkey = gfxs->Dkey; int Ostep = gfxs->Ostep; if (Ostep < 0) { S += gfxs->length - 1; D += gfxs->length - 1; } while (--w) { u16 s = *S; if (MASK_RGB( s ) != Skey && MASK_RGB( *D ) == Dkey) *D = s; S += Ostep; D += Ostep; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKto_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Skey = gfxs->Skey; int SperD = gfxs->SperD; while (--w) { u16 s = S[i>>16]; if (MASK_RGB( s ) != Skey) *D = s; ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_StoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { if (MASK_RGB( *D ) == Dkey) *D = S[i>>16]; ++D; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKtoK_Aop_PFI ************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKtoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u16 *S = gfxs->Bop[0]; u16 *D = gfxs->Aop[0]; u16 Skey = gfxs->Skey; u16 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { u16 s = S[i>>16]; if (MASK_RGB( s ) != Skey && MASK_RGB( *D ) == Dkey) *D = s; ++D; i += SperD; } } /**********************************************************************************************************************/ #undef MASK_RGB #undef MASK_RGB_L #undef MASK_RGB_H #undef MASK_RGB_32 #undef RGB_MASK #undef Cop_OP_Aop_PFI #undef Bop_PFI_OP_Aop_PFI ================================================ FILE: src/gfx/generic/template_colorkey_24.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifdef WORD_BIGENDIAN #define READ_PIXEL(S) \ ( \ ((S)[0] << 16) | \ ((S)[1] << 8) | \ (S)[2] \ ) #define WRITE_PIXEL(D,pix) \ do { \ (D)[0] = ((pix) >> 16) & 0xff; \ (D)[1] = ((pix) >> 8) & 0xff; \ (D)[2] = (pix) & 0xff; \ } while (0) #else #define READ_PIXEL(S) \ ( \ ((S)[2] << 16) | \ ((S)[1] << 8) | \ (S)[0] \ ) #define WRITE_PIXEL(d,pix) \ do { \ (D)[0] = (pix) & 0xff; \ (D)[1] = ((pix) >> 8) & 0xff; \ (D)[2] = ((pix) >> 16) & 0xff; \ } while (0) #endif /********************************************************************************************************************** ********************************* Cop_toK_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Cop_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { u32 d = READ_PIXEL( D ); if ((d & RGB_MASK) == Dkey) WRITE_PIXEL( D, Cop ); D += 3; } } /********************************************************************************************************************** ********************************* Bop_PFI_toK_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Ostep = gfxs->Ostep * 3; if (Ostep < 0) { S += (gfxs->length - 1) * 3; D += (gfxs->length - 1) * 3; } while (--w) { u32 d = READ_PIXEL( D ); if ((d & RGB_MASK) == Dkey) { D[0] = S[0]; D[1] = S[1]; D[2] = S[2]; } S += Ostep; D += Ostep; } } /********************************************************************************************************************** ********************************* Bop_PFI_Kto_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(Kto)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Ostep = gfxs->Ostep * 3; if (Ostep < 0) { S += (gfxs->length - 1) * 3; D += (gfxs->length - 1) * 3; } while (--w) { u32 s = READ_PIXEL( S ); if ((s & RGB_MASK) != Skey) { D[0] = S[0]; D[1] = S[1]; D[2] = S[2]; } S += Ostep; D += Ostep; } } /********************************************************************************************************************** ********************************* Bop_PFI_KtoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(KtoK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int Ostep = gfxs->Ostep * 3; if (Ostep < 0) { S += (gfxs->length - 1) * 3; D += (gfxs->length - 1) * 3; } while (--w) { u32 s = READ_PIXEL( S ); if ((s & RGB_MASK) != Skey) { u32 d = READ_PIXEL( D ); if ((d & RGB_MASK) == Dkey) { D[0] = S[0]; D[1] = S[1]; D[2] = S[2]; } } S += Ostep; D += Ostep; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKto_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Dstep = gfxs->Astep * 3; int SperD = gfxs->SperD; while (--w) { int pixelstart = (i >> 16) * 3; u32 s = READ_PIXEL( &S[pixelstart] ); if ((s & RGB_MASK) != Skey) { D[0] = S[pixelstart++]; D[1] = S[pixelstart++]; D[2] = S[pixelstart]; } D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_StoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep * 3; int SperD = gfxs->SperD; while (--w) { u32 d = READ_PIXEL( D ); if ((d & RGB_MASK) == Dkey) { int pixelstart = (i >> 16) * 3; D[0] = S[pixelstart++]; D[1] = S[pixelstart++]; D[2] = S[pixelstart]; } D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKtoK_Aop_PFI ************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKtoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u8 *S = gfxs->Bop[0]; u8 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int SperD = gfxs->SperD; while (--w) { int pixelstart = (i >> 16) * 3; u32 s = READ_PIXEL( &S[pixelstart] ); if ((s & RGB_MASK) != Skey) { u32 d = READ_PIXEL( D ); if ((d & RGB_MASK) == Dkey) { D[0] = S[pixelstart++]; D[1] = S[pixelstart++]; D[2] = S[pixelstart]; } } D += 3; i += SperD; } } /**********************************************************************************************************************/ #undef READ_PIXEL #undef WRITE_PIXEL #undef RGB_MASK #undef Cop_OP_Aop_PFI #undef Bop_PFI_OP_Aop_PFI ================================================ FILE: src/gfx/generic/template_colorkey_32.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /********************************************************************************************************************** ********************************* Cop_toK_Aop_PFI ******************************************************************** **********************************************************************************************************************/ static void Cop_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *D = gfxs->Aop[0]; u32 Cop = gfxs->Cop; u32 Dkey = gfxs->Dkey; while (--w) { if ((*D & RGB_MASK) == Dkey) *D = Cop; ++D; } } /********************************************************************************************************************** ********************************* Bop_PFI_toK_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(toK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Sstep = gfxs->Bstep; int Dstep = gfxs->Astep; if (Sstep < 0) { S += gfxs->length - 1; D += (gfxs->length - 1) * Dstep; } while (--w) { if ((*D & RGB_MASK) == Dkey) *D = *S; S += Sstep; D += Dstep; } } /********************************************************************************************************************** ********************************* Bop_PFI_Kto_Aop_PFI **************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(Kto)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Sstep = gfxs->Bstep; int Dstep = gfxs->Astep; if (Sstep < 0) { S += gfxs->length - 1; D += (gfxs->length - 1) * Dstep; } while (--w) { u32 s = *S; if ((s & RGB_MASK) != Skey) *D = s; S += Sstep; D += Dstep; } } /********************************************************************************************************************** ********************************* Bop_PFI_KtoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(KtoK)( GenefxState *gfxs ) { int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int Sstep = gfxs->Bstep; int Dstep = gfxs->Astep; if (Sstep < 0) { S += gfxs->length - 1; D += (gfxs->length - 1) * Dstep; } while (--w) { u32 s = *S; if ((s & RGB_MASK) != Skey && (*D & RGB_MASK) == Dkey) *D = s; S += Sstep; D += Dstep; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKto_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKto)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>16]; if ((s & RGB_MASK) != Skey) *D = s; D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_StoK_Aop_PFI *************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(StoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { if ((*D & RGB_MASK) == Dkey) *D = S[i>>16]; D += Dstep; i += SperD; } } /********************************************************************************************************************** ********************************* Bop_PFI_SKtoK_Aop_PFI ************************************************************** **********************************************************************************************************************/ static void Bop_PFI_OP_Aop_PFI(SKtoK)( GenefxState *gfxs ) { int i = gfxs->Xphase; int w = gfxs->length + 1; u32 *S = gfxs->Bop[0]; u32 *D = gfxs->Aop[0]; u32 Skey = gfxs->Skey; u32 Dkey = gfxs->Dkey; int Dstep = gfxs->Astep; int SperD = gfxs->SperD; while (--w) { u32 s = S[i>>16]; if ((s & RGB_MASK) != Skey && (*D & RGB_MASK) == Dkey) *D = s; D += Dstep; i += SperD; } } /**********************************************************************************************************************/ #undef RGB_MASK #undef Cop_OP_Aop_PFI #undef Bop_PFI_OP_Aop_PFI ================================================ FILE: src/gfx/util.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include /**********************************************************************************************************************/ static bool copy_state_inited; static CardState copy_state; static bool btf_state_inited; static CardState btf_state; static DirectMutex copy_lock = DIRECT_MUTEX_INITIALIZER(); static DirectMutex btf_lock = DIRECT_MUTEX_INITIALIZER(); void dfb_gfx_copy_stereo( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *rect, int x, int y, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; direct_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO; copy_state.clip.x2 = destination->config.size.w - 1; copy_state.clip.y2 = destination->config.size.h - 1; copy_state.source = source; copy_state.destination = destination; copy_state.from = from_back ? DSBR_BACK : DSBR_FRONT; copy_state.from_eye = source_eye; copy_state.to = DSBR_BACK; copy_state.to_eye = destination_eye; if (rect) { if (dfb_rectangle_intersect( &sourcerect, rect )) dfb_gfxcard_blit( &sourcerect, x + sourcerect.x - rect->x, y + sourcerect.y - rect->y, ©_state ); } else dfb_gfxcard_blit( &sourcerect, x, y, ©_state ); dfb_gfxcard_flush(); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); copy_state.destination = NULL; copy_state.source = NULL; direct_mutex_unlock( ©_lock ); } void dfb_gfx_clear( CoreSurface *surface, DFBSurfaceBufferRole role ) { DFBRectangle rect = { 0, 0, surface->config.size.w, surface->config.size.h }; direct_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_COLOR | SMF_DESTINATION | SMF_TO; copy_state.clip.x2 = surface->config.size.w - 1; copy_state.clip.y2 = surface->config.size.h - 1; copy_state.destination = surface; copy_state.to = role; copy_state.to_eye = DSSE_LEFT; copy_state.color.a = 0; copy_state.color.r = 0; copy_state.color.g = 0; copy_state.color.b = 0; copy_state.color_index = 0; dfb_gfxcard_fillrectangles( &rect, 1, ©_state ); dfb_gfxcard_flush(); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); copy_state.destination = NULL; direct_mutex_unlock( ©_lock ); } void dfb_gfx_stretch_stereo( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *srect, const DFBRectangle *drect, bool from_back ) { DFBRectangle sourcerect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle destrect = { 0, 0, destination->config.size.w, destination->config.size.h }; if (srect) { if (!dfb_rectangle_intersect( &sourcerect, srect )) return; } if (drect) { if (!dfb_rectangle_intersect( &destrect, drect )) return; } direct_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } copy_state.modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO; copy_state.clip.x2 = destination->config.size.w - 1; copy_state.clip.y2 = destination->config.size.h - 1; copy_state.source = source; copy_state.destination = destination; copy_state.from = from_back ? DSBR_BACK : DSBR_FRONT; copy_state.from_eye = source_eye; copy_state.to = DSBR_BACK; copy_state.to_eye = destination_eye; dfb_gfxcard_stretchblit( &sourcerect, &destrect, ©_state ); dfb_gfxcard_flush(); /* Signal end of sequence. */ dfb_state_stop_drawing( ©_state ); copy_state.destination = NULL; copy_state.source = NULL; direct_mutex_unlock( ©_lock ); } void dfb_gfx_copy_regions_client( CoreSurface *source, DFBSurfaceBufferRole from, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceBufferRole to, DFBSurfaceStereoEye destination_eye, const DFBRegion *regions, unsigned int num, int x, int y, CoreGraphicsStateClient *client ) { unsigned int i, n = 0; DFBRectangle rect = { 0, 0, source->config.size.w, source->config.size.h }; DFBRectangle rects[num]; DFBPoint points[num]; CardState *state; CardState backup; for (i = 0; i < num; i++) { DFB_REGION_ASSERT( ®ions[i] ); rects[n] = DFB_RECTANGLE_INIT_FROM_REGION( ®ions[i] ); if (dfb_rectangle_intersect( &rects[n], &rect )) { points[n].x = x + rects[n].x; points[n].y = y + rects[n].y; n++; } } if (n > 0) { if (!client) { direct_mutex_lock( ©_lock ); if (!copy_state_inited) { dfb_state_init( ©_state, NULL ); copy_state_inited = true; } state = ©_state; } else state = client->state; backup.clip = state->clip; backup.source = state->source; backup.destination = state->destination; backup.from = state->from; backup.from_eye = state->from_eye; backup.to = state->to; backup.to_eye = state->to_eye; backup.blittingflags = state->blittingflags; state->modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO | SMF_BLITTING_FLAGS; state->clip.x1 = 0; state->clip.y1 = 0; state->clip.x2 = destination->config.size.w - 1; state->clip.y2 = destination->config.size.h - 1; state->source = source; state->destination = destination; state->from = from; state->from_eye = source_eye; state->to = to; state->to_eye = destination_eye; state->blittingflags = DSBLIT_NOFX; if (!client) { dfb_gfxcard_batchblit( rects, points, n, ©_state ); dfb_gfxcard_flush(); } else { CoreGraphicsStateClient_Blit( client, rects, points, n ); CoreGraphicsStateClient_Flush( client ); } state->modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO | SMF_BLITTING_FLAGS; state->clip = backup.clip; state->source = backup.source; state->destination = backup.destination; state->from = backup.from; state->from_eye = backup.from_eye; state->to = backup.to; state->to_eye = backup.to_eye; state->blittingflags = backup.blittingflags; if (!client) direct_mutex_unlock( ©_lock ); } } static void back_to_front_copy( CoreSurface *surface, DFBSurfaceStereoEye eye, const DFBRegion *region, DFBSurfaceBlittingFlags flags, int rotation ) { DFBRectangle rect; int dx, dy; CardState *state = &btf_state; if (region) { rect.x = region->x1; rect.y = region->y1; rect.w = region->x2 - region->x1 + 1; rect.h = region->y2 - region->y1 + 1; } else { rect.x = 0; rect.y = 0; rect.w = surface->config.size.w; rect.h = surface->config.size.h; } dx = rect.x; dy = rect.y; direct_mutex_lock( &btf_lock ); if (!btf_state_inited) { dfb_state_init( state, NULL ); state->from = DSBR_BACK; state->to = DSBR_FRONT; btf_state_inited = true; } state->modified |= SMF_CLIP | SMF_SOURCE | SMF_DESTINATION | SMF_FROM | SMF_TO; state->clip.x2 = surface->config.size.w - 1; state->clip.y2 = surface->config.size.h - 1; state->source = surface; state->destination = surface; state->from_eye = eye; state->to_eye = eye; if (rotation == 90) { dx = rect.y; dy = surface->config.size.w - rect.w - rect.x; flags |= DSBLIT_ROTATE90; } else if (rotation == 180) { dx = surface->config.size.w - rect.w - rect.x; dy = surface->config.size.h - rect.h - rect.y; flags |= DSBLIT_ROTATE180; } else if (rotation == 270) { dx = surface->config.size.h - rect.h - rect.y; dy = rect.x; flags |= DSBLIT_ROTATE270; } dfb_state_set_blitting_flags( state, flags ); dfb_gfxcard_blit( &rect, dx, dy, state ); dfb_gfxcard_flush(); /* Signal end of sequence. */ dfb_state_stop_drawing( state ); direct_mutex_unlock( &btf_lock ); } void dfb_back_to_front_copy_stereo( CoreSurface *surface, DFBSurfaceStereoEye eyes, const DFBRegion *left_region, const DFBRegion *right_region, int rotation ) { if (eyes & DSSE_LEFT) back_to_front_copy( surface, DSSE_LEFT, left_region, DSBLIT_NOFX, rotation ); if (eyes & DSSE_RIGHT) back_to_front_copy( surface, DSSE_RIGHT, right_region, DSBLIT_NOFX, rotation ); } void dfb_sort_triangle( DFBTriangle *tri ) { int temp; if (tri->y1 > tri->y2) { temp = tri->x1; tri->x1 = tri->x2; tri->x2 = temp; temp = tri->y1; tri->y1 = tri->y2; tri->y2 = temp; } if (tri->y2 > tri->y3) { temp = tri->x2; tri->x2 = tri->x3; tri->x3 = temp; temp = tri->y2; tri->y2 = tri->y3; tri->y3 = temp; } if (tri->y1 > tri->y2) { temp = tri->x1; tri->x1 = tri->x2; tri->x2 = temp; temp = tri->y1; tri->y1 = tri->y2; tri->y2 = temp; } } void dfb_sort_trapezoid( DFBTrapezoid *trap ) { int temp; if (trap->y1 > trap->y2) { temp = trap->x1; trap->x1 = trap->x2; trap->x2 = temp; temp = trap->y1; trap->y1 = trap->y2; trap->y2 = temp; temp = trap->w1; trap->w1 = trap->w2; trap->w2 = temp; } } ================================================ FILE: src/gfx/util.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __GFX__UTIL_H__ #define __GFX__UTIL_H__ #include /**********************************************************************************************************************/ void dfb_gfx_copy_stereo ( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *rect, int x, int y, bool from_back ); void dfb_gfx_clear ( CoreSurface *surface, DFBSurfaceBufferRole role ); void dfb_gfx_stretch_stereo ( CoreSurface *source, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceStereoEye destination_eye, const DFBRectangle *srect, const DFBRectangle *drect, bool from_back ); void dfb_gfx_copy_regions_client ( CoreSurface *source, DFBSurfaceBufferRole from, DFBSurfaceStereoEye source_eye, CoreSurface *destination, DFBSurfaceBufferRole to, DFBSurfaceStereoEye destination_eye, const DFBRegion *regions, unsigned int num, int x, int y, CoreGraphicsStateClient *client ); void dfb_back_to_front_copy_stereo( CoreSurface *surface, DFBSurfaceStereoEye eyes, const DFBRegion *left_region, const DFBRegion *right_region, int rotation ); void dfb_sort_triangle ( DFBTriangle *tri ); void dfb_sort_trapezoid ( DFBTrapezoid *trap ); /**********************************************************************************************************************/ /* * Simplify blitting flags. * * Allow any combination of DSBLIT_ROTATE_ and DSBLIT_FLIP_ flags to be reduced to a combination of DSBLIT_ROTATE_90, * DSBLIT_FLIP_HORIZONTAL and DSBLIT_FLIP_VERTICAL */ static __inline__ void dfb_simplify_blittingflags( DFBSurfaceBlittingFlags *flags ) { if (*flags & DSBLIT_ROTATE180) *flags = *flags ^ (DSBLIT_ROTATE180 | DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL); if (*flags & DSBLIT_ROTATE270) { if (*flags & DSBLIT_ROTATE90) *flags = *flags ^ (DSBLIT_ROTATE90 | DSBLIT_ROTATE270); else *flags = *flags ^ (DSBLIT_ROTATE90 | DSBLIT_ROTATE270 | DSBLIT_FLIP_HORIZONTAL | DSBLIT_FLIP_VERTICAL); } } #endif ================================================ FILE: src/idirectfb.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB, "IDirectFB", "IDirectFB Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFB */ typedef struct { int ref; /* reference counter */ CoreDFB *core; /* the core object */ DFBCooperativeLevel level; /* current cooperative level */ CoreLayer *layer; /* primary display layer */ CoreLayerContext *context; /* shared context of primary layer */ CoreWindowStack *stack; /* window stack of primary layer */ struct { int width; int height; DFBSurfacePixelFormat format; DFBSurfaceColorSpace colorspace; CoreWindow *window; Reaction reaction; bool focused; CoreLayerContext *context; DFBWindowOptions window_options; } primary; bool app_focus; struct { CoreLayer *layer; CoreLayerContext *context; CoreLayerRegion *region; CoreSurface *surface; CorePalette *palette; } layers[MAX_LAYERS]; bool init_done; DirectMutex init_lock; DirectWaitQueue init_wq; } IDirectFB_data; typedef struct { DFBScreenCallback callback; void *callback_ctx; } EnumScreens_Context; typedef struct { IDirectFBScreen **interface; DFBScreenID id; DFBResult ret; } GetScreen_Context; typedef struct { DFBDisplayLayerCallback callback; void *callback_ctx; } EnumDisplayLayers_Context; typedef struct { IDirectFBDisplayLayer **interface; DFBDisplayLayerID id; DFBResult ret; CoreDFB *core; IDirectFB *idirectfb; } GetDisplayLayer_Context; typedef struct { DFBInputDeviceCallback callback; void *callback_ctx; } EnumInputDevices_Context; typedef struct { IDirectFBInputDevice **interface; DFBInputDeviceID id; DFBResult ret; } GetInputDevice_Context; typedef struct { IDirectFBEventBuffer **interface; DFBInputDeviceCapabilities caps; } CreateEventBuffer_Context; static DFBEnumerationResult EnumScreens_Callback ( CoreScreen *screen, void *ctx ); static DFBEnumerationResult GetScreen_Callback ( CoreScreen *screen, void *ctx ); static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer *layer, void *ctx ); static DFBEnumerationResult GetDisplayLayer_Callback ( CoreLayer *layer, void *ctx ); static DFBEnumerationResult EnumInputDevices_Callback ( CoreInputDevice *device, void *ctx ); static DFBEnumerationResult GetInputDevice_Callback ( CoreInputDevice *device, void *ctx ); static DFBEnumerationResult CreateEventBuffer_Callback( CoreInputDevice *device, void *ctx ); /**********************************************************************************************************************/ typedef struct { DirectLink link; DFBInputDeviceCapabilities caps; IDirectFBEventBuffer *iface; } EventBuffer_Container; static DirectLink *eventbuffer_containers = NULL; static DirectMutex eventbuffer_containers_lock = DIRECT_MUTEX_INITIALIZER(); static void eventbuffer_containers_add( CreateEventBuffer_Context *context ) { EventBuffer_Container *container; D_DEBUG_AT( DirectFB, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &eventbuffer_containers_lock ); container = D_CALLOC( 1, sizeof(EventBuffer_Container) ); if (!container) { D_OOM(); } container->caps = context->caps; container->iface = *context->interface; direct_list_append( &eventbuffer_containers, &container->link ); direct_mutex_unlock( &eventbuffer_containers_lock ); } void eventbuffer_containers_remove( IDirectFBEventBuffer *thiz ) { EventBuffer_Container *container, *next; D_DEBUG_AT( DirectFB, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &eventbuffer_containers_lock ); direct_list_foreach_safe (container, next, eventbuffer_containers) { if (thiz == container->iface) { direct_list_remove( &eventbuffer_containers, &container->link ); D_FREE( container ); } } direct_mutex_unlock( &eventbuffer_containers_lock ); } void eventbuffer_containers_attach_device( CoreInputDevice *device ) { EventBuffer_Container *container; DFBInputDeviceCapabilities dev_caps; D_DEBUG_AT( DirectFB, "%s()\n", __FUNCTION__ ); dev_caps = dfb_input_device_caps( device ); direct_mutex_lock( &eventbuffer_containers_lock ); direct_list_foreach (container, eventbuffer_containers) { if (dev_caps & container->caps) { IDirectFBEventBuffer_AttachInputDevice( container->iface, device ); } } direct_mutex_unlock( &eventbuffer_containers_lock ); } void eventbuffer_containers_detach_device( CoreInputDevice *device ) { EventBuffer_Container *container; D_DEBUG_AT( DirectFB, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &eventbuffer_containers_lock ); direct_list_foreach (container, eventbuffer_containers) { IDirectFBEventBuffer_DetachInputDevice( container->iface, device ); } direct_mutex_unlock( &eventbuffer_containers_lock ); } /**********************************************************************************************************************/ static void drop_window( IDirectFB_data *data, bool enable_cursor ) { if (!data->primary.window) return; dfb_window_detach( data->primary.window, &data->primary.reaction ); dfb_window_unref( data->primary.window ); data->primary.window = NULL; data->primary.focused = false; if (dfb_config->cursor_automation) CoreWindowStack_CursorEnable( data->stack, enable_cursor ); } static DFBResult IDirectFB_Destruct( IDirectFB *thiz ) { DFBResult ret; IDirectFB_data *data = thiz->priv; int i; D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); drop_window( data, false ); if (data->primary.context) dfb_layer_context_unref( data->primary.context ); dfb_layer_context_unref( data->context ); direct_thread_sleep( 10000 ); for (i = 0; i < MAX_LAYERS; i++) { if (data->layers[i].context) { if (data->layers[i].palette) dfb_palette_unref( data->layers[i].palette ); dfb_surface_unref( data->layers[i].surface ); dfb_layer_region_unref( data->layers[i].region ); dfb_layer_context_unref( data->layers[i].context ); } } ret = dfb_core_destroy( data->core, false ); DIRECT_DEALLOCATE_INTERFACE( thiz ); direct_shutdown(); if (thiz == idirectfb_singleton) idirectfb_singleton = NULL; return ret; } static DirectResult IDirectFB_AddRef( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFB_Release( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) return IDirectFB_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFB_SetCooperativeLevel( IDirectFB *thiz, DFBCooperativeLevel level ) { DFBResult ret; CoreLayerContext *context; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %u )\n", __FUNCTION__, thiz, level ); if (level == data->level) return DFB_OK; switch (level) { case DFSCL_NORMAL: data->primary.focused = false; dfb_layer_context_unref( data->primary.context ); data->primary.context = NULL; break; case DFSCL_FULLSCREEN: case DFSCL_EXCLUSIVE: if (dfb_config->primary_id) return DFB_ACCESSDENIED; if (dfb_config->force_windowed) return DFB_ACCESSDENIED; if (data->level == DFSCL_NORMAL) { ret = CoreLayer_CreateContext( data->layer, &context ); if (ret) return ret; ret = CoreLayer_ActivateContext( data->layer, context ); if (ret) { dfb_layer_context_unref( context ); return ret; } drop_window( data, true ); data->primary.context = context; } data->primary.focused = true; break; default: return DFB_INVARG; } data->level = level; return DFB_OK; } static DFBResult IDirectFB_SetVideoMode( IDirectFB *thiz, int width, int height, int bpp ) { DFBResult ret; DFBDisplayLayerConfig config; DFBSurfacePixelFormat format; DFBSurfaceColorSpace colorspace; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %dx%d %dbit )\n", __FUNCTION__, thiz, width, height, bpp ); if (width < 1 || height < 1 || bpp < 1) return DFB_INVARG; format = dfb_pixelformat_for_depth( bpp ); if (format == DSPF_UNKNOWN) return DFB_INVARG; colorspace = DFB_COLORSPACE_DEFAULT( format ); switch (data->level) { case DFSCL_NORMAL: if (data->primary.window) { ret = dfb_window_resize( data->primary.window, width, height ); if (ret) return ret; } break; case DFSCL_FULLSCREEN: case DFSCL_EXCLUSIVE: config.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT; config.width = width; config.height = height; config.pixelformat = format; config.colorspace = colorspace; ret = CoreLayerContext_SetConfiguration( data->primary.context, &config ); if (ret) return ret; break; } data->primary.width = width; data->primary.height = height; data->primary.format = format; data->primary.colorspace = colorspace; data->primary.window_options = DWOP_KEEP_SIZE; return DFB_OK; } static DFBResult IDirectFB_GetDeviceDescription( IDirectFB *thiz, DFBGraphicsDeviceDescription *ret_desc ) { GraphicsDeviceInfo device_info; GraphicsDriverInfo driver_info; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; dfb_gfxcard_get_device_info( &device_info ); dfb_gfxcard_get_driver_info( &driver_info ); ret_desc->acceleration_mask = device_info.caps.accel; ret_desc->blitting_flags = device_info.caps.blitting; ret_desc->drawing_flags = device_info.caps.drawing; ret_desc->video_memory = dfb_gfxcard_memory_length(); direct_snputs( ret_desc->name, device_info.name, DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH ); direct_snputs( ret_desc->vendor, device_info.vendor, DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH ); ret_desc->driver.major = driver_info.version.major; ret_desc->driver.minor = driver_info.version.minor; direct_snputs( ret_desc->driver.name, driver_info.name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH ); direct_snputs( ret_desc->driver.vendor, driver_info.vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH ); return DFB_OK; } static DFBResult IDirectFB_EnumVideoModes( IDirectFB *thiz, DFBVideoModeCallback callback, void *callbackdata ) { VideoMode *m; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!callback) return DFB_INVARG; m = dfb_system_modes(); while (m) { if (callback( m->xres, m->yres, m->bpp, callbackdata ) == DFENUM_CANCEL) break; m = m->next; } return DFB_OK; } static DFBResult init_palette( CoreSurface *surface, const DFBSurfaceDescription *desc ) { DFBResult ret; CorePalette *palette; if (!(desc->flags & DSDESC_PALETTE)) return DFB_OK; ret = CoreSurface_GetPalette( surface, &palette ); if (ret) return ret; ret = CorePalette_SetEntries( palette, desc->palette.entries, MIN( desc->palette.size, palette->num_entries ), 0 ); dfb_palette_unref( palette ); return ret; } static ReactionResult focus_listener( const void *msg_data, void *ctx ) { const DFBWindowEvent *evt = msg_data; IDirectFB_data *data = ctx; switch (evt->type) { case DWET_DESTROYED: dfb_window_unref( data->primary.window ); data->primary.window = NULL; data->primary.focused = false; return RS_REMOVE; case DWET_GOTFOCUS: data->primary.focused = true; break; case DWET_LOSTFOCUS: data->primary.focused = false; break; default: break; } return RS_OK; } static DFBResult IDirectFB_CreateSurface( IDirectFB *thiz, const DFBSurfaceDescription *desc, IDirectFBSurface **ret_interface ) { DFBResult ret; DFBDisplayLayerConfig config; DFBSurfacePixelFormat format; DFBSurfaceColorSpace colorspace; CoreSurface *surface; IDirectFBSurface *iface; unsigned long resource_id = 0; int width = 256; int height = 256; DFBSurfaceCapabilities caps = DSCAPS_NONE; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (data->primary.context) dfb_layer_context_get_configuration( data->primary.context, &config ); else if (data->context) dfb_layer_context_get_configuration( data->context, &config ); else { config.width = 512; config.height = 512; config.pixelformat = DSPF_ARGB; config.colorspace = DSCS_RGB; } if (desc->flags & DSDESC_HINTS && desc->hints & DSHF_FONT) { format = dfb_config->font_format; colorspace = DFB_COLORSPACE_DEFAULT( format ); if (dfb_config->font_premult) caps = DSCAPS_PREMULTIPLIED; } else { format = config.pixelformat; colorspace = config.colorspace; } if (!desc || !ret_interface) return DFB_INVARG; D_DEBUG_AT( DirectFB, " -> flags 0x%08x\n", desc->flags ); if (desc->flags & DSDESC_WIDTH) { D_DEBUG_AT( DirectFB, " -> width %d\n", desc->width ); width = desc->width; if (width < 1 || width > 20480) return DFB_INVARG; } if (desc->flags & DSDESC_HEIGHT) { D_DEBUG_AT( DirectFB, " -> height %d\n", desc->height ); height = desc->height; if (height < 1 || height > 20480) return DFB_INVARG; } if (desc->flags & DSDESC_PALETTE) { D_DEBUG_AT( DirectFB, " -> PALETTE\n" ); if (!desc->palette.entries) { D_DEBUG_AT( DirectFB, " -> no entries!\n" ); return DFB_INVARG; } if (!desc->palette.size) { D_DEBUG_AT( DirectFB, " -> no size!\n" ); return DFB_INVARG; } } if (desc->flags & DSDESC_CAPS) { D_DEBUG_AT( DirectFB, " -> caps 0x%08x\n", desc->caps ); caps = desc->caps; } if (desc->flags & DSDESC_PIXELFORMAT) { D_DEBUG_AT( DirectFB, " -> format %s\n", dfb_pixelformat_name( desc->pixelformat ) ); format = desc->pixelformat; colorspace = DFB_COLORSPACE_DEFAULT( format ); } if (desc->flags & DSDESC_COLORSPACE) { D_DEBUG_AT( DirectFB, " -> colorspace %s\n", dfb_colorspace_name( desc->pixelformat ) ); if (!DFB_COLORSPACE_IS_COMPATIBLE( desc->colorspace, format )) { D_DEBUG_AT( DirectFB, " -> incompatible colorspace!\n" ); return DFB_INVARG; } colorspace = desc->colorspace; } if (desc->flags & DSDESC_RESOURCE_ID) resource_id = desc->resource_id; switch (format) { case DSPF_A1: case DSPF_A1_LSB: case DSPF_A4: case DSPF_A8: case DSPF_ARGB: case DSPF_ABGR: case DSPF_ARGB8565: case DSPF_ARGB1555: case DSPF_RGBA5551: case DSPF_ARGB1666: case DSPF_ARGB6666: case DSPF_ARGB2554: case DSPF_ARGB4444: case DSPF_RGBA4444: case DSPF_AYUV: case DSPF_AVYU: case DSPF_AiRGB: case DSPF_I420: case DSPF_Y42B: case DSPF_Y444: case DSPF_LUT1: case DSPF_LUT2: case DSPF_LUT8: case DSPF_ALUT44: case DSPF_RGB16: case DSPF_RGB18: case DSPF_RGB24: case DSPF_BGR24: case DSPF_RGB32: case DSPF_RGB332: case DSPF_UYVY: case DSPF_YUY2: case DSPF_YV12: case DSPF_YV16: case DSPF_YV24: case DSPF_NV12: case DSPF_NV21: case DSPF_NV16: case DSPF_NV61: case DSPF_NV24: case DSPF_NV42: case DSPF_VYU: case DSPF_RGB444: case DSPF_RGB555: case DSPF_BGR555: case DSPF_RGBAF88871: break; default: D_DEBUG_AT( DirectFB, " -> invalid pixelformat 0x%08x\n", (unsigned int) format ); return DFB_INVARG; } if (caps & DSCAPS_PRIMARY) { D_DEBUG_AT( DirectFB, " -> PRIMARY\n" ); if (dfb_config->primary_id) { D_DEBUG_AT( DirectFB, " -> primary-id 0x%x\n", dfb_config->primary_id ); ret = CoreDFB_GetSurface( data->core, dfb_config->primary_id, &surface ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Construct( iface, NULL, NULL, NULL, NULL, surface, DSCAPS_PRIMARY, data->core, thiz ); if (ret) { dfb_surface_unref( surface ); return ret; } init_palette( surface, desc ); dfb_surface_unref( surface ); *ret_interface = iface; return ret; } if (desc->flags & DSDESC_PREALLOCATED) { D_DEBUG_AT( DirectFB, " -> cannot make preallocated primary!\n" ); return DFB_INVARG; } if (desc->flags & DSDESC_PIXELFORMAT) format = desc->pixelformat; else if (data->primary.format) { format = data->primary.format; colorspace = data->primary.colorspace; } else if (dfb_config->mode.format) { format = dfb_config->mode.format; colorspace = DFB_COLORSPACE_DEFAULT( format ); } else { format = config.pixelformat; colorspace = config.colorspace; } if (desc->flags & DSDESC_WIDTH) width = desc->width; else if (data->primary.width) width = data->primary.width; else if (dfb_config->mode.width) width = dfb_config->mode.width; else width = config.width; if (desc->flags & DSDESC_HEIGHT) height = desc->height; else if (data->primary.height) height = data->primary.height; else if (dfb_config->mode.height) height = dfb_config->mode.height; else height = config.height; switch (data->level) { case DFSCL_NORMAL: { D_DEBUG_AT( DirectFB, " -> level normal\n" ); CoreWindow *window; DFBWindowDescription wd; memset( &wd, 0, sizeof(wd) ); wd.flags = DWDESC_POSX | DWDESC_POSY | DWDESC_CAPS | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_OPTIONS | DWDESC_PIXELFORMAT | DWDESC_COLORSPACE | DWDESC_SURFACE_CAPS | DWDESC_RESOURCE_ID; if (dfb_config->scaled.width && dfb_config->scaled.height) { wd.posx = (config.width - dfb_config->scaled.width) / 2; wd.posy = (config.height - dfb_config->scaled.height) / 2; } else { wd.posx = (config.width - width) / 2; wd.posy = (config.height - height) / 2; } if (!(caps & (DSCAPS_VIDEOONLY | DSCAPS_SYSTEMONLY))) { if (dfb_config->window_policy == DWSP_SYSTEMONLY) caps |= DSCAPS_SYSTEMONLY; else if (dfb_config->window_policy == DWSP_VIDEOONLY) caps |= DSCAPS_VIDEOONLY; } wd.width = width; wd.height = height; wd.pixelformat = format; wd.colorspace = colorspace; wd.surface_caps = caps; wd.resource_id = resource_id; wd.options = data->primary.window_options; if (desc->flags & (DSDESC_WIDTH | DSDESC_HEIGHT)) wd.options |= DWOP_KEEP_SIZE; switch (format) { case DSPF_ARGB8565: case DSPF_ARGB4444: case DSPF_RGBA4444: case DSPF_ARGB2554: case DSPF_ARGB1555: case DSPF_RGBA5551: case DSPF_ARGB: case DSPF_ABGR: case DSPF_AYUV: case DSPF_AVYU: case DSPF_AiRGB: case DSPF_RGBAF88871: wd.caps |= DWCAPS_ALPHACHANNEL; if (caps & DSCAPS_PREMULTIPLIED) wd.options |= DWOP_ALPHACHANNEL; break; default: break; } if ((caps & DSCAPS_FLIPPING) == DSCAPS_DOUBLE) wd.caps |= DWCAPS_DOUBLEBUFFER; if (caps & DSCAPS_STEREO) wd.caps |= DWCAPS_STEREO; ret = CoreLayerContext_CreateWindow( data->context, &wd, &window ); if (ret) return ret; drop_window( data, true ); data->primary.window = window; dfb_window_attach( window, focus_listener, data, &data->primary.reaction ); CoreWindow_ChangeOptions( window, DWOP_NONE, DWOP_SCALE ); CoreWindow_AllowFocus( window ); if (dfb_config->scaled.width && dfb_config->scaled.height) CoreWindow_Resize( window, dfb_config->scaled.width, dfb_config->scaled.height ); init_palette( window->surface, desc ); DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Window_Construct( iface, NULL, NULL, NULL, window, caps, data->core, thiz ); if (ret == DFB_OK) *ret_interface = iface; return ret; } case DFSCL_FULLSCREEN: case DFSCL_EXCLUSIVE: { CoreLayerRegion *region; CoreLayerContext *context = data->primary.context; config.flags |= DLCONF_PIXELFORMAT | DLCONF_COLORSPACE | DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_BUFFERMODE; config.surface_caps = DSCAPS_NONE; if (caps & DSCAPS_PREMULTIPLIED) { config.flags |= DLCONF_SURFACE_CAPS; config.surface_caps |= DSCAPS_PREMULTIPLIED; } if (caps & DSCAPS_GL) { config.flags |= DLCONF_SURFACE_CAPS; config.surface_caps |= DSCAPS_GL; } if (caps & DSCAPS_TRIPLE) { if (caps & DSCAPS_SYSTEMONLY) return DFB_UNSUPPORTED; config.buffermode = DLBM_TRIPLE; } else if (caps & DSCAPS_DOUBLE) { if (caps & DSCAPS_SYSTEMONLY) config.buffermode = DLBM_BACKSYSTEM; else config.buffermode = DLBM_BACKVIDEO; } else config.buffermode = DLBM_FRONTONLY; if (caps & DSCAPS_STEREO) { config.flags |= DLCONF_OPTIONS; config.options = DLOP_STEREO; } config.pixelformat = format; config.colorspace = colorspace; config.width = width; config.height = height; ret = CoreLayerContext_SetConfiguration( context, &config ); if (ret) { if (caps & (DSCAPS_SYSTEMONLY | DSCAPS_VIDEOONLY)) return ret; if (config.buffermode == DLBM_TRIPLE) { config.buffermode = DLBM_BACKVIDEO; ret = CoreLayerContext_SetConfiguration( context, &config ); if (ret) { config.buffermode = DLBM_BACKSYSTEM; ret = CoreLayerContext_SetConfiguration( context, &config ); if (ret) return ret; } } else if (config.buffermode == DLBM_BACKVIDEO) { config.buffermode = DLBM_BACKSYSTEM; ret = CoreLayerContext_SetConfiguration( context, &config ); if (ret) return ret; } else return ret; } if ((caps & DSCAPS_FLIPPING) == DSCAPS_FLIPPING) { if (config.buffermode == DLBM_TRIPLE) caps &= ~DSCAPS_DOUBLE; else caps &= ~DSCAPS_TRIPLE; } ret = CoreLayerContext_GetPrimaryRegion( context, true, ®ion ); if (ret) return ret; ret = CoreLayerRegion_GetSurface( region, &surface ); if (ret) { dfb_layer_region_unref( region ); return ret; } init_palette( surface, desc ); if (config.buffermode != DLBM_BACKVIDEO && config.buffermode != DLBM_TRIPLE) { /* If a window stack is available, give it the opportunity to render the background and flip the display layer so it is visible. Otherwise, just directly flip the display layer and make it visible. */ if (data->stack) { CoreWindowStack_RepaintAll( data->stack ); } else { CoreSurface_Flip2( surface, DFB_FALSE, NULL, NULL, DSFLIP_NONE, -1 ); } } DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Layer_Construct( iface, NULL, NULL, NULL, region, caps, data->core, thiz ); dfb_surface_unref( surface ); dfb_layer_region_unref( region ); if (ret == DFB_OK) *ret_interface = iface; return ret; } } } if ((caps & DSCAPS_FLIPPING) == DSCAPS_FLIPPING) caps &= ~DSCAPS_TRIPLE; if (desc->flags & DSDESC_PREALLOCATED) { int min_pitch; CoreSurfaceConfig surface_config; int i, num = 1; min_pitch = DFB_BYTES_PER_LINE( format, width ); if (caps & DSCAPS_DOUBLE) num = 2; else if (caps & DSCAPS_TRIPLE) num = 3; D_DEBUG_AT( DirectFB, " -> %d buffers, min pitch %d\n", num, min_pitch ); for (i = 0; i < num; i++) { if (!desc->preallocated[i].data) { D_DEBUG_AT( DirectFB, " -> no data in preallocated [%d]\n", i ); return DFB_INVARG; } if (desc->preallocated[i].pitch < min_pitch) { D_DEBUG_AT( DirectFB, " -> wrong pitch (%d) in preallocated [%d]\n", desc->preallocated[i].pitch, i ); return DFB_INVARG; } } surface_config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS | CSCONF_PREALLOCATED; surface_config.size.w = width; surface_config.size.h = height; surface_config.format = format; surface_config.colorspace = colorspace; surface_config.caps = caps; ret = dfb_surface_pools_prealloc( desc, &surface_config ); if (ret) { D_DERROR( ret, "IDirectFB: Preallocation failed!\n" ); return ret; } ret = CoreDFB_CreateSurface( data->core, &surface_config, CSTF_PREALLOCATED, resource_id, NULL, &surface ); if (ret) return ret; } else { CoreSurfaceConfig surface_config; surface_config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_COLORSPACE | CSCONF_CAPS; surface_config.size.w = width; surface_config.size.h = height; surface_config.format = format; surface_config.colorspace = colorspace; surface_config.caps = caps; ret = CoreDFB_CreateSurface( data->core, &surface_config, CSTF_NONE, resource_id, NULL, &surface ); if (ret) return ret; } init_palette( surface, desc ); DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Construct( iface, NULL, NULL, NULL, NULL, surface, caps, data->core, thiz ); dfb_surface_unref( surface ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_CreatePalette( IDirectFB *thiz, const DFBPaletteDescription *desc, IDirectFBPalette **ret_interface ) { DFBResult ret; CorePalette *palette; IDirectFBPalette *iface; unsigned int size = 256; DFBSurfaceColorSpace colorspace = DSCS_RGB; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; if (desc && desc->flags & DPDESC_SIZE) { if (!desc->size) return DFB_INVARG; size = desc->size; } if (desc && desc->flags & DPDESC_COLORSPACE) { colorspace = desc->colorspace; } ret = CoreDFB_CreatePalette( data->core, size, colorspace, &palette ); if (ret) return ret; if (desc && desc->flags & DPDESC_ENTRIES) CorePalette_SetEntries( palette, desc->entries, size, 0 ); else dfb_palette_generate_rgb332_map( palette ); DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBPalette ); ret = IDirectFBPalette_Construct( iface, palette, data->core ); dfb_palette_unref( palette ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_EnumScreens( IDirectFB *thiz, DFBScreenCallback callback, void *callbackdata ) { EnumScreens_Context context; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!callback) return DFB_INVARG; context.callback = callback; context.callback_ctx = callbackdata; dfb_screens_enumerate( EnumScreens_Callback, &context ); return DFB_OK; } static DFBResult IDirectFB_GetScreen( IDirectFB *thiz, DFBScreenID screen_id, IDirectFBScreen **ret_interface ) { GetScreen_Context context; IDirectFBScreen *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %u )\n", __FUNCTION__, thiz, screen_id ); if (!ret_interface) return DFB_INVARG; if (dfb_config->primary_only && screen_id != DLID_PRIMARY) return DFB_IDNOTFOUND; context.interface = &iface; context.id = screen_id; context.ret = DFB_IDNOTFOUND; dfb_screens_enumerate( GetScreen_Callback, &context ); if (!context.ret) *ret_interface = iface; return context.ret; } static DFBResult IDirectFB_EnumDisplayLayers( IDirectFB *thiz, DFBDisplayLayerCallback callback, void *callbackdata ) { EnumDisplayLayers_Context context; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!callback) return DFB_INVARG; context.callback = callback; context.callback_ctx = callbackdata; dfb_layers_enumerate( EnumDisplayLayers_Callback, &context ); return DFB_OK; } static DFBResult IDirectFB_GetDisplayLayer( IDirectFB *thiz, DFBDisplayLayerID layer_id, IDirectFBDisplayLayer **ret_interface ) { GetDisplayLayer_Context context; IDirectFBDisplayLayer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %u )\n", __FUNCTION__, thiz, layer_id ); if (!ret_interface) return DFB_INVARG; if (dfb_config->primary_only && layer_id != DLID_PRIMARY) return DFB_IDNOTFOUND; context.interface = &iface; context.id = layer_id; context.ret = DFB_IDNOTFOUND; context.core = data->core; context.idirectfb = thiz; dfb_layers_enumerate( GetDisplayLayer_Callback, &context ); if (!context.ret) *ret_interface = iface; return context.ret; } static DFBResult IDirectFB_EnumInputDevices( IDirectFB *thiz, DFBInputDeviceCallback callback, void *callbackdata ) { EnumInputDevices_Context context; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!callback) return DFB_INVARG; context.callback = callback; context.callback_ctx = callbackdata; dfb_input_enumerate_devices( EnumInputDevices_Callback, &context, DICAPS_ALL ); return DFB_OK; } static DFBResult IDirectFB_GetInputDevice( IDirectFB *thiz, DFBInputDeviceID device_id, IDirectFBInputDevice **ret_interface ) { GetInputDevice_Context context; IDirectFBInputDevice *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %u )\n", __FUNCTION__, thiz, device_id ); if (!ret_interface) return DFB_INVARG; context.interface = &iface; context.id = device_id; context.ret = DFB_IDNOTFOUND; dfb_input_enumerate_devices( GetInputDevice_Callback, &context, DICAPS_ALL ); if (!context.ret) *ret_interface = iface; return context.ret; } static DFBResult IDirectFB_CreateEventBuffer( IDirectFB *thiz, IDirectFBEventBuffer **ret_interface ) { DFBResult ret; IDirectFBEventBuffer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBEventBuffer ); ret = IDirectFBEventBuffer_Construct( iface, NULL, NULL ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static bool input_filter_local( DFBEvent *evt, void *ctx ) { IDirectFB_data *data = ctx; if (evt->clazz == DFEC_INPUT) { DFBInputEvent *event = &evt->input; if (!data->primary.focused && !data->app_focus) return true; if (dfb_config->cursor_automation) { switch (event->type) { case DIET_BUTTONPRESS: if (data->primary.window) CoreWindowStack_CursorEnable( data->stack, false ); break; case DIET_KEYPRESS: if (data->primary.window) CoreWindowStack_CursorEnable( data->stack, (event->key_symbol == DIKS_ESCAPE) || (event->modifiers & DIMM_META) ); break; default: break; } } } return false; } static bool input_filter_global( DFBEvent *evt, void *ctx ) { IDirectFB_data *data = ctx; if (evt->clazz == DFEC_INPUT) { DFBInputEvent *event = &evt->input; if (!data->primary.focused && !data->app_focus) event->flags |= DIEF_GLOBAL; } return false; } static DFBResult IDirectFB_CreateInputEventBuffer( IDirectFB *thiz, DFBInputDeviceCapabilities caps, DFBBoolean global, IDirectFBEventBuffer **ret_interface ) { DFBResult ret; CreateEventBuffer_Context context; IDirectFBEventBuffer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBEventBuffer ); ret = IDirectFBEventBuffer_Construct( iface, global ? input_filter_global : input_filter_local, data ); if (ret) return ret; context.caps = caps; context.interface = &iface; /* Store the context of the event buffer for input device hotplug support. */ eventbuffer_containers_add( &context ); dfb_input_enumerate_devices( CreateEventBuffer_Callback, &context, caps ); *ret_interface = iface; return DFB_OK; } static DFBResult CreateDataBufferFile( IDirectFB *thiz, const char *filename, IDirectFBDataBuffer **buffer ) { DFBResult ret; DFBDataBufferDescription desc; desc.flags = DBDESC_FILE; desc.file = filename; ret = thiz->CreateDataBuffer( thiz, &desc, buffer ); if (ret) return ret; return DFB_OK; } static DFBResult IDirectFB_CreateImageProvider( IDirectFB *thiz, const char *filename, IDirectFBImageProvider **ret_interface ) { DFBResult ret; IDirectFBDataBuffer *buffer; IDirectFBImageProvider *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, '%s' )\n", __FUNCTION__, thiz, filename ); /* Check arguments. */ if (!filename || !ret_interface) return DFB_INVARG; /* Create a data buffer. */ ret = CreateDataBufferFile( thiz, filename, &buffer ); if (ret) { D_DEBUG_AT( DirectFB, " -> data buffer creation failed!\n" ); return ret; } /* Create (probing) the image provider. */ ret = IDirectFBImageProvider_CreateFromBuffer( buffer, data->core, thiz, &iface ); /* We don't need it anymore, image provider has its own reference. */ buffer->Release( buffer ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_CreateVideoProvider( IDirectFB *thiz, const char *filename, IDirectFBVideoProvider **ret_interface ) { DFBResult ret; IDirectFBDataBuffer *buffer; IDirectFBVideoProvider *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, '%s' )\n", __FUNCTION__, thiz, filename ); /* Check arguments. */ if (!filename || !ret_interface) return DFB_INVARG; /* Create a data buffer. */ ret = CreateDataBufferFile( thiz, filename, &buffer ); if (ret) { D_DEBUG_AT( DirectFB, " -> data buffer creation failed!\n" ); return ret; } /* Create (probing) the video provider. */ ret = IDirectFBVideoProvider_CreateFromBuffer( buffer, data->core, thiz, &iface ); /* We don't need it anymore, video provider has its own reference. */ buffer->Release( buffer ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_CreateFont( IDirectFB *thiz, const char *filename, const DFBFontDescription *desc, IDirectFBFont **ret_interface ) { DFBResult ret; IDirectFBDataBuffer *buffer; IDirectFBFont *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, '%s' )\n", __FUNCTION__, thiz, filename ); /* Check arguments. */ if (!filename || !desc || !ret_interface) return DFB_INVARG; if ((desc->flags & DFDESC_HEIGHT) && desc->height < 1) { D_DEBUG_AT( DirectFB, " -> invalid height %d\n", desc->height ); return DFB_INVARG; } if ((desc->flags & DFDESC_WIDTH) && desc->width < 1) { D_DEBUG_AT( DirectFB, " -> invalid width %d\n", desc->width ); return DFB_INVARG; } /* Create a data buffer. */ ret = CreateDataBufferFile( thiz, filename, &buffer ); if (ret) { D_DEBUG_AT( DirectFB, " -> data buffer creation failed!\n" ); return ret; } /* Create (probing) the font. */ ret = IDirectFBFont_CreateFromBuffer( buffer, data->core, desc, &iface ); /* We don't need it anymore. */ buffer->Release( buffer ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_CreateDataBuffer( IDirectFB *thiz, const DFBDataBufferDescription *desc, IDirectFBDataBuffer **ret_interface ) { DFBResult ret; IDirectFBDataBuffer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_interface) return DFB_INVARG; if (!desc) { DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBDataBuffer ); ret = IDirectFBDataBuffer_Streamed_Construct( iface, data->core, thiz ); } else if (desc->flags & DBDESC_FILE) { /* Check for valid filename. */ if (!desc->file) return DFB_INVARG; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBDataBuffer ); ret = IDirectFBDataBuffer_File_Construct( iface, desc->file, data->core, thiz ); } else if (desc->flags & DBDESC_MEMORY) { if (!desc->memory.data || !desc->memory.length) return DFB_INVARG; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBDataBuffer ); ret = IDirectFBDataBuffer_Memory_Construct( iface, desc->memory.data, desc->memory.length, data->core, thiz ); } else return DFB_INVARG; if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_SetClipboardData( IDirectFB *thiz, const char *mime_type, const void *clip_data, unsigned int size, struct timeval *timestamp ) { struct timeval tv; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!mime_type || !data || !size) return DFB_INVARG; if (timestamp) tv = *timestamp; else { long long timestamp_us = direct_clock_get_abs_micros(); tv.tv_sec = timestamp_us / 1000000; tv.tv_usec = timestamp_us % 1000000; } return CoreDFB_ClipboardSet( data->core, mime_type, strlen( mime_type ) + 1, clip_data, size, tv.tv_sec * 1000000 + tv.tv_usec ); } static DFBResult IDirectFB_GetClipboardData( IDirectFB *thiz, char **ret_mime_type, void **ret_clip_data, unsigned int *ret_size ) { DFBResult ret; char mime_type[MAX_CLIPBOARD_MIME_TYPE_SIZE]; u32 mime_type_size; char clip_data[MAX_CLIPBOARD_DATA_SIZE]; u32 size; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_mime_type && !data && !ret_size) return DFB_INVARG; ret = CoreDFB_ClipboardGet( data->core, mime_type, &mime_type_size, clip_data, &size ); if (ret) return ret; *ret_mime_type = D_STRDUP( mime_type ); if (!*ret_mime_type) return D_OOM(); *ret_clip_data = D_MALLOC( size ); if (!*ret_clip_data) { free( *ret_mime_type ); return D_OOM(); } direct_memcpy( *ret_clip_data, clip_data, size ); *ret_size = size; return DFB_OK; } static DFBResult IDirectFB_GetClipboardTimeStamp( IDirectFB *thiz, struct timeval *ret_timestamp ) { DFBResult ret; u64 ts; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_timestamp) return DFB_INVARG; ret = CoreDFB_ClipboardGetTimestamp( data->core, &ts ); if (ret) return ret; ret_timestamp->tv_sec = ts / 1000000; ret_timestamp->tv_usec = ts % 1000000; return DFB_OK; } static DFBResult IDirectFB_Suspend( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); return dfb_core_suspend( data->core ); } static DFBResult IDirectFB_Resume( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); return dfb_core_resume( data->core ); } static DFBResult IDirectFB_WaitIdle( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); CoreDFB_WaitIdle( data->core ); return DFB_OK; } static DFBResult IDirectFB_WaitForSync( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); CoreLayer_WaitVSync( data->layer ); return DFB_OK; } static DFBResult IDirectFB_GetInterface( IDirectFB *thiz, const char *type, const char *implementation, void *arg, void **ret_interface ) { DFBResult ret; DirectInterfaceFuncs *funcs = NULL; void *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, '%s' )\n", __FUNCTION__, thiz, type ); if (!type || !ret_interface) return DFB_INVARG; ret = DirectGetInterface( &funcs, type, implementation, DirectProbeInterface, arg ); if (ret) return ret; ret = funcs->Allocate( &iface ); if (ret) return ret; ret = funcs->Construct( iface, arg, data->core ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_GetSurface( IDirectFB *thiz, DFBSurfaceID surface_id, IDirectFBSurface **ret_interface ) { DFBResult ret; CoreSurface *surface; IDirectFBSurface *iface; DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %u )\n", __FUNCTION__, thiz, surface_id ); ret = CoreDFB_GetSurface( data->core, surface_id, &surface ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface ); ret = IDirectFBSurface_Construct( iface, NULL, NULL, NULL, NULL, surface, surface->config.caps, data->core, thiz ); dfb_surface_unref( surface ); if (ret == DFB_OK) *ret_interface = iface; return ret; } static DFBResult IDirectFB_GetFontSurfaceFormat( IDirectFB *thiz, DFBSurfacePixelFormat *ret_fontformat ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_fontformat) return DFB_INVARG; *ret_fontformat = dfb_config->font_format; return DFB_OK; } static void LoadBackgroundImage( IDirectFB *dfb, CoreWindowStack *stack, DFBConfigLayer *conf ) { DFBResult ret; DFBSurfaceDescription desc; IDirectFBImageProvider *provider; IDirectFBSurface *image; IDirectFBSurface_data *image_data; ret = dfb->CreateImageProvider( dfb, conf->background.filename, &provider ); if (ret) { D_DERROR( ret, "IDirectFB: Failed loading background image '%s'!\n", conf->background.filename ); return; } if (conf->background.mode == DLBM_IMAGE) { desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT; desc.width = conf->config.width; desc.height = conf->config.height; } else { provider->GetSurfaceDescription( provider, &desc ); } desc.flags |= DSDESC_CAPS | DSDESC_PIXELFORMAT; desc.caps = DSCAPS_SHARED; desc.pixelformat = conf->config.pixelformat; ret = dfb->CreateSurface( dfb, &desc, &image ); if (ret) { D_DERROR( ret, "IDirectFB: Failed creating surface for background image!\n" ); provider->Release( provider ); return; } ret = provider->RenderTo( provider, image, NULL ); if (ret) { D_DERROR( ret, "IDirectFB: Failed loading background image!\n" ); image->Release( image ); provider->Release( provider ); return; } provider->Release( provider ); image_data = image->priv; CoreWindowStack_BackgroundSetImage( stack, image_data->surface ); image->Release( image ); } static DFBResult InitLayerPalette( IDirectFB_data *data, DFBConfigLayer *conf, CoreSurface *surface, CorePalette **ret_palette ) { DFBResult ret; CorePalette *palette; ret = dfb_palette_create( data->core, 256, surface->config.colorspace, &palette ); if (ret) { D_DERROR( ret, "IDirectFB: Could not create palette!\n" ); return ret; } direct_memcpy( palette->entries, conf->palette, sizeof(DFBColor) * 256 ); ret = dfb_surface_set_palette( surface, palette ); if (ret) { D_DERROR( ret, "IDirectFB: Could not set palette!\n" ); dfb_palette_unref( palette ); return ret; } *ret_palette = palette; return DFB_OK; } static DFBResult InitLayers( IDirectFB *thiz ) { DFBResult ret; int i; int num = dfb_layers_num(); DIRECT_INTERFACE_GET_DATA( IDirectFB ) for (i = 0; i < num; i++) { CoreLayer *layer = dfb_layer_at_translated( i ); DFBConfigLayer *conf = &dfb_config->layers[i]; if (conf->init) { CoreLayerContext *context; CoreWindowStack *stack; CardCapabilities caps; DFBDisplayLayerConfigFlags fail; DFBColorKey key; ret = CoreLayer_GetPrimaryContext( layer, false, &context ); if (ret) { D_DERROR( ret, "IDirectFB: Could not get context of layer %d!\n", i ); goto error; } stack = dfb_layer_context_windowstack( context ); D_ASSERT( stack != NULL ); /* Set default desktop configuration. */ if (!(conf->config.flags & DLCONF_BUFFERMODE)) { dfb_gfxcard_get_capabilities( &caps ); conf->config.flags |= DLCONF_BUFFERMODE; conf->config.buffermode = (caps.accel & DFXL_BLIT) ? DLBM_BACKVIDEO : DLBM_BACKSYSTEM; } if (CoreLayerContext_TestConfiguration( context, &conf->config, &fail )) { if (fail & (DLCONF_WIDTH | DLCONF_HEIGHT)) { D_ERROR( "IDirectFB: Setting desktop resolution to %dx%d failed!\n" " -> Using default resolution\n", conf->config.width, conf->config.height ); conf->config.flags &= ~(DLCONF_WIDTH | DLCONF_HEIGHT); } if (fail & DLCONF_PIXELFORMAT) { D_ERROR( "IDirectFB: Setting desktop format failed!\n" " -> Using default format\n" ); conf->config.flags &= ~DLCONF_PIXELFORMAT; } if (fail & DLCONF_BUFFERMODE) { D_ERROR( "IDirectFB: Setting desktop buffer mode failed!\n" " -> No virtual resolution support or not enough memory\n" " Falling back to system back buffer\n" ); conf->config.buffermode = DLBM_BACKSYSTEM; if (CoreLayerContext_TestConfiguration( context, &conf->config, &fail )) { D_ERROR( "IDirectFB: Setting system memory desktop back buffer failed!\n" " -> Using front buffer only mode\n" ); conf->config.flags &= ~DLCONF_BUFFERMODE; } } } if (conf->config.flags) { ret = CoreLayerContext_SetConfiguration( context, &conf->config ); if (ret) { D_DERROR( ret, "IDirectFB: Could not set configuration for layer %d!\n", i ); dfb_layer_context_unref( context ); goto error; } } ret = dfb_layer_context_get_configuration( context, &conf->config ); if (ret) goto error; ret = CoreLayerContext_GetPrimaryRegion( context, true, &data->layers[i].region ); if (ret) { D_DERROR( ret, "IDirectFB: Could not get primary region of layer %d!\n", i ); dfb_layer_context_unref( context ); goto error; } ret = dfb_layer_region_get_surface( data->layers[i].region, &data->layers[i].surface ); if (ret) { D_DERROR( ret, "IDirectFB: Could not get surface of primary region of layer %d!\n", i ); dfb_layer_region_unref( data->layers[i].region ); dfb_layer_context_unref( context ); goto error; } if (conf->palette_set) InitLayerPalette( data, conf, data->layers[i].surface, &data->layers[i].palette ); if (conf->src_key_index >= 0 && conf->src_key_index < 256) { conf->src_key.r = conf->palette[conf->src_key_index].r; conf->src_key.g = conf->palette[conf->src_key_index].g; conf->src_key.b = conf->palette[conf->src_key_index].b; } key.r = conf->src_key.r; key.g = conf->src_key.g; key.b = conf->src_key.b; key.index = conf->src_key_index; CoreLayerContext_SetSrcColorKey( context, &key ); switch (conf->background.mode) { case DLBM_COLOR: CoreWindowStack_BackgroundSetColor( stack, &conf->background.color ); CoreWindowStack_BackgroundSetColorIndex( stack, conf->background.color_index ); break; case DLBM_IMAGE: case DLBM_TILE: LoadBackgroundImage( thiz, stack, conf ); break; default: break; } CoreWindowStack_BackgroundSetMode( stack, conf->background.mode ); data->layers[i].context = context; } data->layers[i].layer = layer; } for (i = 0; i < num; i++) { if (data->layers[i].context) dfb_layer_activate_context( data->layers[i].layer, data->layers[i].context ); } return DFB_OK; error: for (i = num - 1; i >= 0; i--) { if (data->layers[i].context) { if (data->layers[i].palette) dfb_palette_unref( data->layers[i].palette ); dfb_surface_unref( data->layers[i].surface ); dfb_layer_region_unref( data->layers[i].region ); dfb_layer_context_unref( data->layers[i].context ); data->layers[i].context = NULL; } } return ret; } static void InitIDirectFB_Async( void *ctx, void *ctx2 ) { DFBResult ret; IDirectFB *thiz = ctx; IDirectFB_data *data = ctx2; D_DEBUG_AT( DirectFB, "%s( %p, %p )\n", __FUNCTION__, thiz, data ); ret = CoreLayer_GetPrimaryContext( data->layer, true, &data->context ); if (ret) { D_ERROR( "IDirectFB: Could not get default context of primary layer!\n" ); return; } data->stack = dfb_layer_context_windowstack( data->context ); if (dfb_core_is_master( data->core )) { ret = InitLayers( thiz ); if (ret) return; ret = dfb_wm_post_init( data->core ); if (ret) D_DERROR( ret, "IDirectFB: Post initialization of WM failed!\n" ); dfb_core_activate( data->core ); } direct_mutex_lock( &data->init_lock ); data->init_done = true; direct_waitqueue_broadcast( &data->init_wq ); direct_mutex_unlock( &data->init_lock ); } DFBResult IDirectFB_Construct( IDirectFB *thiz ) { DFBResult ret; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_core_create( &core_dfb ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } if (dfb_layers_num() < 1) { D_ERROR( "IDirectFB: No layers available!\n" ); dfb_core_destroy( core_dfb, false ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_UNSUPPORTED; } data->ref = 1; data->core = core_dfb; data->level = DFSCL_NORMAL; data->layer = dfb_layer_at_translated( DLID_PRIMARY ); thiz->AddRef = IDirectFB_AddRef; thiz->Release = IDirectFB_Release; thiz->SetCooperativeLevel = IDirectFB_SetCooperativeLevel; thiz->SetVideoMode = IDirectFB_SetVideoMode; thiz->GetDeviceDescription = IDirectFB_GetDeviceDescription; thiz->EnumVideoModes = IDirectFB_EnumVideoModes; thiz->CreateSurface = IDirectFB_CreateSurface; thiz->CreatePalette = IDirectFB_CreatePalette; thiz->EnumScreens = IDirectFB_EnumScreens; thiz->GetScreen = IDirectFB_GetScreen; thiz->EnumDisplayLayers = IDirectFB_EnumDisplayLayers; thiz->GetDisplayLayer = IDirectFB_GetDisplayLayer; thiz->EnumInputDevices = IDirectFB_EnumInputDevices; thiz->GetInputDevice = IDirectFB_GetInputDevice; thiz->CreateEventBuffer = IDirectFB_CreateEventBuffer; thiz->CreateInputEventBuffer = IDirectFB_CreateInputEventBuffer; thiz->CreateImageProvider = IDirectFB_CreateImageProvider; thiz->CreateVideoProvider = IDirectFB_CreateVideoProvider; thiz->CreateFont = IDirectFB_CreateFont; thiz->CreateDataBuffer = IDirectFB_CreateDataBuffer; thiz->SetClipboardData = IDirectFB_SetClipboardData; thiz->GetClipboardData = IDirectFB_GetClipboardData; thiz->GetClipboardTimeStamp = IDirectFB_GetClipboardTimeStamp; thiz->Suspend = IDirectFB_Suspend; thiz->Resume = IDirectFB_Resume; thiz->WaitIdle = IDirectFB_WaitIdle; thiz->WaitForSync = IDirectFB_WaitForSync; thiz->GetInterface = IDirectFB_GetInterface; thiz->GetSurface = IDirectFB_GetSurface; thiz->GetFontSurfaceFormat = IDirectFB_GetFontSurfaceFormat; direct_mutex_init( &data->init_lock ); direct_waitqueue_init( &data->init_wq ); if (dfb_config->call_nodirect && dfb_core_is_master( data->core )) Core_AsyncCall( InitIDirectFB_Async, thiz, data ); else InitIDirectFB_Async( thiz, data ); return DFB_OK; } DFBResult IDirectFB_WaitInitialised( IDirectFB *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p )\n", __FUNCTION__, thiz ); direct_mutex_lock( &data->init_lock ); while (!data->init_done) direct_waitqueue_wait( &data->init_wq, &data->init_lock ); direct_mutex_unlock( &data->init_lock ); return DFB_OK; } DFBResult IDirectFB_SetAppFocus( IDirectFB *thiz, DFBBoolean focused ) { DIRECT_INTERFACE_GET_DATA( IDirectFB ) D_DEBUG_AT( DirectFB, "%s( %p, %s )\n", __FUNCTION__, thiz, focused ? "true" : "false" ); data->app_focus = focused; return DFB_OK; } /**********************************************************************************************************************/ static DFBEnumerationResult EnumScreens_Callback( CoreScreen *screen, void *ctx ) { DFBScreenDescription desc; DFBScreenID id; EnumScreens_Context *context = ctx; id = dfb_screen_id_translated( screen ); if (dfb_config->primary_only && id != DSCID_PRIMARY) return DFENUM_OK; dfb_screen_get_info( screen, NULL, &desc ); return context->callback( id, desc, context->callback_ctx ); } static DFBEnumerationResult GetScreen_Callback( CoreScreen *screen, void *ctx ) { GetScreen_Context *context = ctx; if (dfb_screen_id_translated( screen ) != context->id) return DFENUM_OK; DIRECT_ALLOCATE_INTERFACE( *context->interface, IDirectFBScreen ); context->ret = IDirectFBScreen_Construct( *context->interface, screen ); return DFENUM_CANCEL; } static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer *layer, void *ctx ) { DFBDisplayLayerDescription desc; DFBDisplayLayerID id; EnumDisplayLayers_Context *context = ctx; id = dfb_layer_id_translated( layer ); if (dfb_config->primary_only && id != DLID_PRIMARY) return DFENUM_OK; dfb_layer_get_description( layer, &desc ); return context->callback( id, desc, context->callback_ctx ); } static DFBEnumerationResult GetDisplayLayer_Callback( CoreLayer *layer, void *ctx ) { GetDisplayLayer_Context *context = ctx; if (dfb_layer_id_translated( layer ) != context->id) return DFENUM_OK; DIRECT_ALLOCATE_INTERFACE( *context->interface, IDirectFBDisplayLayer ); context->ret = IDirectFBDisplayLayer_Construct( *context->interface, layer, context->core, context->idirectfb ); return DFENUM_CANCEL; } static DFBEnumerationResult EnumInputDevices_Callback( CoreInputDevice *device, void *ctx ) { DFBInputDeviceDescription desc; EnumInputDevices_Context *context = ctx; dfb_input_device_description( device, &desc ); return context->callback( dfb_input_device_id( device ), desc, context->callback_ctx ); } static DFBEnumerationResult GetInputDevice_Callback( CoreInputDevice *device, void *ctx ) { GetInputDevice_Context *context = ctx; if (dfb_input_device_id( device ) != context->id) return DFENUM_OK; DIRECT_ALLOCATE_INTERFACE( *context->interface, IDirectFBInputDevice ); context->ret = IDirectFBInputDevice_Construct( *context->interface, device ); return DFENUM_CANCEL; } static DFBEnumerationResult CreateEventBuffer_Callback( CoreInputDevice *device, void *ctx ) { DFBInputDeviceDescription desc; CreateEventBuffer_Context *context = ctx; dfb_input_device_description( device, &desc ); IDirectFBEventBuffer_AttachInputDevice( *context->interface, device ); return DFENUM_OK; } ================================================ FILE: src/idirectfb.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __IDIRECTFB_H__ #define __IDIRECTFB_H__ #include void eventbuffer_containers_remove( IDirectFBEventBuffer *thiz ); /* * initializes interface struct and private data */ DFBResult IDirectFB_Construct ( IDirectFB *thiz ); DFBResult IDirectFB_WaitInitialised( IDirectFB *thiz ); DFBResult IDirectFB_SetAppFocus ( IDirectFB *thiz, DFBBoolean focused ); #endif ================================================ FILE: src/init.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include /**********************************************************************************************************************/ typedef void (*Func)( void ); static Func init_funcs[] = { DFBResult__init, Core_TLS__init, }; static Func deinit_funcs[] = { Core_TLS__deinit, DFBResult__deinit, }; /**********************************************************************************************************************/ __dfb_constructor__ void __DFB_init_all( void ) { size_t i; for (i = 0; i < D_ARRAY_SIZE(init_funcs); i++) init_funcs[i](); } __dfb_destructor__ void __DFB_deinit_all( void ) { size_t i; dfb_config_deinit(); for (i = 0; i < D_ARRAY_SIZE(deinit_funcs); i++) deinit_funcs[i](); } ================================================ FILE: src/input/idirectfbeventbuffer.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( EventBuffer, "IDirectFBEventBuffer", "IDirectFBEventBuffer Interface" ); D_DEBUG_DOMAIN( EventBuffer_Feed, "IDirectFBEventBuffer/Feed", "IDirectFBEventBuffer Interface Feed" ); D_DEBUG_DOMAIN( EventBuffer_Surface, "IDirectFBEventBuffer/Surface", "IDirectFBEventBuffer Interface Surface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBEventBuffer */ typedef struct { int ref; /* reference counter */ EventBufferFilterCallback filter; /* input filter callback */ void *filter_ctx; /* context passed as argument of the filter callback */ DirectLink *devices; /* attached devices */ DirectLink *windows; /* attached windows */ DirectLink *surfaces; /* attached surfaces */ DirectLink *events; /* linked list containing events */ DirectMutex events_mutex; /* mutex lock for accessing the event queue */ DirectWaitQueue wait_condition; /* condition used for idle wait */ bool pipe; /* pipe mode */ int pipe_fds[2]; /* read & write file descriptors */ DirectThread *pipe_thread; /* thread feeding the pipe */ DFBEventBufferStats stats; bool stats_enabled; } IDirectFBEventBuffer_data; typedef struct { DirectLink link; DFBEvent evt; } EventBufferItem; static void IDirectFBEventBuffer_AddItem( IDirectFBEventBuffer_data *data, EventBufferItem *item ); typedef struct { DirectLink link; CoreInputDevice *device; Reaction reaction; DFBInputDeviceDescription desc; } AttachedDevice; typedef struct { DirectLink link; CoreWindow *window; Reaction reaction; } AttachedWindow; typedef struct { DirectLink link; CoreSurface *surface; Reaction reaction; } AttachedSurface; static ReactionResult IDirectFBEventBuffer_InputReact ( const void *msg_data, void *ctx ); static ReactionResult IDirectFBEventBuffer_WindowReact ( const void *msg_data, void *ctx ); static ReactionResult IDirectFBEventBuffer_SurfaceReact( const void *msg_data, void *ctx ); static void *IDirectFBEventBuffer_Feed( DirectThread *thread, void *arg ); static void CollectEventStatistics( DFBEventBufferStats *stats, const DFBEvent *event, int incdec ); /**********************************************************************************************************************/ static void dump_event( const DFBEvent *event ) { switch (event->clazz) { case DFEC_INPUT: D_DEBUG_AT( EventBuffer, " -> INPUT %u (type 0x%08x)\n", event->input.device_id, event->input.type ); break; case DFEC_WINDOW: D_DEBUG_AT( EventBuffer, " -> WINDOW %u (type 0x%08x)\n", event->window.window_id, event->window.type ); break; case DFEC_USER: D_DEBUG_AT( EventBuffer, " -> USER (type 0x%08x, data %p)\n", event->user.type, event->user.data ); break; case DFEC_VIDEOPROVIDER: D_DEBUG_AT( EventBuffer, " -> VIDEOPROVIDER (type 0x%08x, data_type 0x%08x)\n", event->videoprovider.type, event->videoprovider.data_type ); break; case DFEC_SURFACE: D_DEBUG_AT( EventBuffer, " -> SURFACE %u (type 0x%08x)\n", event->surface.surface_id, event->surface.type ); break; case DFEC_UNIVERSAL: D_DEBUG_AT( EventBuffer, " -> UNIVERSAL (size %u)\n", event->universal.size ); break; default: D_DEBUG_AT( EventBuffer, " -> UNKNOWN EVENT CLASS 0x%08x\n", event->clazz ); break; } } static void IDirectFBEventBuffer_Destruct( IDirectFBEventBuffer *thiz ) { IDirectFBEventBuffer_data *data = thiz->priv; AttachedDevice *device; AttachedWindow *window; AttachedSurface *surface; EventBufferItem *item; DirectLink *next; D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* Remove the event buffer from the containers linked list. */ eventbuffer_containers_remove( thiz ); direct_mutex_lock( &data->events_mutex ); if (data->pipe) { data->pipe = false; direct_waitqueue_broadcast( &data->wait_condition ); direct_mutex_unlock( &data->events_mutex ); direct_thread_join( data->pipe_thread ); direct_thread_destroy( data->pipe_thread ); direct_mutex_lock( &data->events_mutex ); close( data->pipe_fds[0] ); close( data->pipe_fds[1] ); } direct_mutex_unlock( &data->events_mutex ); direct_list_foreach_safe (surface, next, data->surfaces) { dfb_surface_detach( surface->surface, &surface->reaction ); dfb_surface_unref( surface->surface ); D_FREE( surface ); } direct_list_foreach_safe (device, next, data->devices) { dfb_input_detach( device->device, &device->reaction ); D_FREE( device ); } direct_list_foreach_safe (window, next, data->windows) { if (window->window) dfb_window_detach( window->window, &window->reaction ); } direct_list_foreach_safe (window, next, data->windows) { if (window->window) dfb_window_unref( window->window ); D_FREE( window ); } direct_mutex_lock( &data->events_mutex ); direct_list_foreach_safe (item, next, data->events) { D_FREE( item ); } direct_waitqueue_deinit( &data->wait_condition ); direct_mutex_deinit( &data->events_mutex ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBEventBuffer_AddRef( IDirectFBEventBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBEventBuffer_Release( IDirectFBEventBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBEventBuffer_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_Reset( IDirectFBEventBuffer *thiz ) { EventBufferItem *item, *next; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pipe) return DFB_UNSUPPORTED; direct_mutex_lock( &data->events_mutex ); direct_list_foreach_safe (item, next, data->events) { D_FREE( item ); } data->events = NULL; direct_mutex_unlock( &data->events_mutex ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_WaitForEvent( IDirectFBEventBuffer *thiz ) { DFBResult ret = DFB_OK; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pipe) return DFB_UNSUPPORTED; direct_mutex_lock( &data->events_mutex ); if (!data->events) direct_waitqueue_wait( &data->wait_condition, &data->events_mutex ); if (!data->events) ret = DFB_INTERRUPTED; direct_mutex_unlock( &data->events_mutex ); return ret; } static DFBResult IDirectFBEventBuffer_WaitForEventWithTimeout( IDirectFBEventBuffer *thiz, unsigned int seconds, unsigned int milli_seconds ) { DirectResult ret = DR_OK; int locked = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %u, %u )\n", __FUNCTION__, thiz, seconds, milli_seconds ); if (data->pipe) return DFB_UNSUPPORTED; if (direct_mutex_trylock( &data->events_mutex ) == 0) { if (data->events) { direct_mutex_unlock ( &data->events_mutex ); return ret; } locked = 1; } if (!locked) direct_mutex_lock( &data->events_mutex ); if (!data->events) { ret = direct_waitqueue_wait_timeout( &data->wait_condition, &data->events_mutex, seconds * 1000000 + milli_seconds * 1000 ); if (ret != DR_TIMEOUT && !data->events) ret = DFB_INTERRUPTED; } direct_mutex_unlock( &data->events_mutex ); return ret; } static DFBResult IDirectFBEventBuffer_GetEvent( IDirectFBEventBuffer *thiz, DFBEvent *ret_event ) { EventBufferItem *item; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %p )\n", __FUNCTION__, thiz, ret_event ); if (data->pipe) { D_DEBUG_AT( EventBuffer, " -> pipe mode, returning UNSUPPORTED\n" ); return DFB_UNSUPPORTED; } direct_mutex_lock( &data->events_mutex ); if (!data->events) { D_DEBUG_AT( EventBuffer, " -> no events, returning BUFFEREMPTY\n" ); direct_mutex_unlock( &data->events_mutex ); return DFB_BUFFEREMPTY; } item = (EventBufferItem*) data->events; switch (item->evt.clazz) { case DFEC_INPUT: ret_event->input = item->evt.input; break; case DFEC_WINDOW: ret_event->window = item->evt.window; break; case DFEC_USER: ret_event->user = item->evt.user; break; case DFEC_VIDEOPROVIDER: ret_event->videoprovider = item->evt.videoprovider; break; case DFEC_UNIVERSAL: direct_memcpy( ret_event, &item->evt, item->evt.universal.size ); break; case DFEC_SURFACE: ret_event->surface = item->evt.surface; break; default: D_BUG( "unknown event class" ); } if (data->stats_enabled) CollectEventStatistics( &data->stats, &item->evt, -1 ); direct_list_remove( &data->events, &item->link ); D_FREE( item ); direct_mutex_unlock( &data->events_mutex ); dump_event( ret_event ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_PeekEvent( IDirectFBEventBuffer *thiz, DFBEvent *ret_event ) { EventBufferItem *item; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %p )\n", __FUNCTION__, thiz, ret_event ); if (data->pipe) return DFB_UNSUPPORTED; direct_mutex_lock( &data->events_mutex ); if (!data->events) { direct_mutex_unlock( &data->events_mutex ); return DFB_BUFFEREMPTY; } item = (EventBufferItem*) data->events; switch (item->evt.clazz) { case DFEC_INPUT: ret_event->input = item->evt.input; break; case DFEC_WINDOW: ret_event->window = item->evt.window; break; case DFEC_USER: ret_event->user = item->evt.user; break; case DFEC_VIDEOPROVIDER: ret_event->videoprovider = item->evt.videoprovider; break; case DFEC_UNIVERSAL: direct_memcpy( ret_event, &item->evt, item->evt.universal.size ); break; case DFEC_SURFACE: ret_event->surface = item->evt.surface; break; default: D_BUG( "unknown event class" ); } direct_mutex_unlock( &data->events_mutex ); dump_event( ret_event ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_HasEvent( IDirectFBEventBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p ) <- events %p, pipe %d\n", __FUNCTION__, thiz, data->events, data->pipe ); if (data->pipe) return DFB_UNSUPPORTED; return (data->events ? DFB_OK : DFB_BUFFEREMPTY); } static DFBResult IDirectFBEventBuffer_PostEvent( IDirectFBEventBuffer *thiz, const DFBEvent *event ) { EventBufferItem *item; int size; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %p [class %u, type %u, data %p] )\n", __FUNCTION__, thiz, event, event->clazz, event->user.type, event->user.data ); dump_event( event ); switch (event->clazz) { case DFEC_INPUT: case DFEC_WINDOW: case DFEC_USER: case DFEC_VIDEOPROVIDER: case DFEC_SURFACE: size = sizeof(EventBufferItem); break; case DFEC_UNIVERSAL: size = event->universal.size; if (size < sizeof(DFBUniversalEvent)) return DFB_INVARG; /* We must not exceed the union for the generic code (reading DFBEvent) and to support pipe mode where each written block must have a fixed size. */ if (size > sizeof(DFBEvent)) return DFB_INVARG; size += sizeof(DirectLink); break; default: return DFB_INVARG; } item = D_CALLOC( 1, size ); if (!item) return D_OOM(); switch (event->clazz) { case DFEC_INPUT: item->evt.input = event->input; break; case DFEC_WINDOW: item->evt.window = event->window; break; case DFEC_USER: item->evt.user = event->user; break; case DFEC_VIDEOPROVIDER: item->evt.videoprovider = event->videoprovider; break; case DFEC_UNIVERSAL: direct_memcpy( &item->evt, event, event->universal.size ); break; case DFEC_SURFACE: item->evt.surface = event->surface; break; default: D_BUG( "unexpected event class" ); } IDirectFBEventBuffer_AddItem( data, item ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_WakeUp( IDirectFBEventBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pipe) return DFB_UNSUPPORTED; direct_waitqueue_broadcast( &data->wait_condition ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_CreateFileDescriptor( IDirectFBEventBuffer *thiz, int *ret_fd ) { DirectResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* Check arguments. */ if (!ret_fd) return DFB_INVARG; /* Lock the event queue. */ direct_mutex_lock( &data->events_mutex ); /* Already in pipe mode. */ if (data->pipe) { direct_mutex_unlock( &data->events_mutex ); return DFB_BUSY; } /* Create the file descriptor(s). */ #if DIRECT_BUILD_NETWORK ret = socketpair( PF_LOCAL, SOCK_STREAM, 0, data->pipe_fds ); #else /* DIRECT_BUILD_NETWORK */ ret = pipe( data->pipe_fds ); #endif /* DIRECT_BUILD_NETWORK */ if (ret) { direct_mutex_unlock( &data->events_mutex ); return ret; } D_DEBUG_AT( EventBuffer, " -> entering pipe mode\n" ); /* Enter pipe mode. */ data->pipe = true; /* Signal any waiting processes. */ direct_waitqueue_broadcast( &data->wait_condition ); /* Create the feeding thread. */ data->pipe_thread = direct_thread_create( DTT_MESSAGING, IDirectFBEventBuffer_Feed, data, "EventBuffer Feed" ); /* Unlock the event queue. */ direct_mutex_unlock( &data->events_mutex ); /* Return the file descriptor for reading. */ *ret_fd = data->pipe_fds[0]; D_DEBUG_AT( EventBuffer, " -> fd %d/%d\n", data->pipe_fds[0], data->pipe_fds[1] ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_EnableStatistics( IDirectFBEventBuffer *thiz, DFBBoolean enable ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %sable )\n", __FUNCTION__, thiz, enable ? "en" : "dis" ); /* Lock the event queue. */ direct_mutex_lock( &data->events_mutex ); /* Already enabled. */ if (data->stats_enabled == enable) { direct_mutex_unlock( &data->events_mutex ); return DFB_OK; } if (enable) { EventBufferItem *item; /* Collect statistics for events already in the queue. */ direct_list_foreach (item, data->events) { CollectEventStatistics( &data->stats, &item->evt, 1 ); } } else { /* Clear statistics. */ memset( &data->stats, 0, sizeof(DFBEventBufferStats) ); } /* Remember state. */ data->stats_enabled = enable; /* Unlock the event queue. */ direct_mutex_unlock( &data->events_mutex ); return DFB_OK; } static DFBResult IDirectFBEventBuffer_GetStatistics( IDirectFBEventBuffer *thiz, DFBEventBufferStats *ret_stats ) { DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %p )\n", __FUNCTION__, thiz, ret_stats ); if (!ret_stats) return DFB_INVARG; /* Lock the event queue. */ direct_mutex_lock( &data->events_mutex ); /* Not enabled. */ if (!data->stats_enabled) { direct_mutex_unlock( &data->events_mutex ); return DFB_UNSUPPORTED; } /* Return current stats. */ *ret_stats = data->stats; /* Unlock the event queue. */ direct_mutex_unlock( &data->events_mutex ); return DFB_OK; } DFBResult IDirectFBEventBuffer_Construct( IDirectFBEventBuffer *thiz, EventBufferFilterCallback filter, void *filter_ctx ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBEventBuffer ) D_DEBUG_AT( EventBuffer, "%s( %p, %p, %p )\n", __FUNCTION__, thiz, filter, filter_ctx ); data->ref = 1; data->filter = filter; data->filter_ctx = filter_ctx; direct_mutex_init( &data->events_mutex ); direct_waitqueue_init( &data->wait_condition ); thiz->AddRef = IDirectFBEventBuffer_AddRef; thiz->Release = IDirectFBEventBuffer_Release; thiz->Reset = IDirectFBEventBuffer_Reset; thiz->WaitForEvent = IDirectFBEventBuffer_WaitForEvent; thiz->WaitForEventWithTimeout = IDirectFBEventBuffer_WaitForEventWithTimeout; thiz->GetEvent = IDirectFBEventBuffer_GetEvent; thiz->PeekEvent = IDirectFBEventBuffer_PeekEvent; thiz->HasEvent = IDirectFBEventBuffer_HasEvent; thiz->PostEvent = IDirectFBEventBuffer_PostEvent; thiz->WakeUp = IDirectFBEventBuffer_WakeUp; thiz->CreateFileDescriptor = IDirectFBEventBuffer_CreateFileDescriptor; thiz->EnableStatistics = IDirectFBEventBuffer_EnableStatistics; thiz->GetStatistics = IDirectFBEventBuffer_GetStatistics; return DFB_OK; } DFBResult IDirectFBEventBuffer_AttachInputDevice( IDirectFBEventBuffer *thiz, CoreInputDevice *device ) { AttachedDevice *attached; DFBInputDeviceDescription desc; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( device != NULL ); dfb_input_device_description( device, &desc ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u - %s] )\n", __FUNCTION__, thiz, device, dfb_input_device_id( device ), desc.name ); attached = D_CALLOC( 1, sizeof(AttachedDevice) ); attached->device = device; attached->desc = desc; direct_list_prepend( &data->devices, &attached->link ); dfb_input_attach( device, IDirectFBEventBuffer_InputReact, data, &attached->reaction ); return DFB_OK; } DFBResult IDirectFBEventBuffer_DetachInputDevice( IDirectFBEventBuffer *thiz, CoreInputDevice *device ) { AttachedDevice *attached, *next; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( device != NULL ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u] )\n", __FUNCTION__, thiz, device, dfb_input_device_id( device ) ); direct_list_foreach_safe (attached, next, data->devices) { if (attached->device == device) { direct_list_remove( &data->devices, &attached->link ); dfb_input_detach( attached->device, &attached->reaction ); D_FREE( attached ); return DFB_OK; } } return DFB_ITEMNOTFOUND; } DFBResult IDirectFBEventBuffer_AttachWindow( IDirectFBEventBuffer *thiz, CoreWindow *window ) { AttachedWindow *attached; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( window != NULL ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u - %4d,%4d-%4dx%4d] )\n", __FUNCTION__, thiz, window, window->id, window->config.bounds.x, window->config.bounds.y, window->config.bounds.w, window->config.bounds.h ); attached = D_CALLOC( 1, sizeof(AttachedWindow) ); attached->window = window; dfb_window_ref( window ); direct_list_prepend( &data->windows, &attached->link ); dfb_window_attach( window, IDirectFBEventBuffer_WindowReact, data, &attached->reaction ); CoreWindow_AllowFocus( window ); return DFB_OK; } DFBResult IDirectFBEventBuffer_DetachWindow( IDirectFBEventBuffer *thiz, CoreWindow *window ) { AttachedWindow *attached, *next; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( window != NULL ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u - %4d,%4d-%4dx%4d] )\n", __FUNCTION__, thiz, window, window->id, window->config.bounds.x, window->config.bounds.y, window->config.bounds.w, window->config.bounds.h ); direct_list_foreach_safe (attached, next, data->windows) { if (!attached->window || attached->window == window) { direct_list_remove( &data->windows, &attached->link ); if (attached->window) { dfb_window_detach( attached->window, &attached->reaction ); dfb_window_unref( attached->window ); } D_FREE( attached ); } } return DFB_OK; } DFBResult IDirectFBEventBuffer_AttachSurface( IDirectFBEventBuffer *thiz, CoreSurface *surface ) { AttachedSurface *attached; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( surface != NULL ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u - %dx%d] )\n", __FUNCTION__, thiz, surface, surface->object.id, surface->config.size.w, surface->config.size.h ); attached = D_CALLOC( 1, sizeof(AttachedSurface) ); attached->surface = surface; dfb_surface_ref( surface ); direct_list_prepend( &data->surfaces, &attached->link ); dfb_surface_attach_channel( surface, CSCH_EVENT, IDirectFBEventBuffer_SurfaceReact, data, &attached->reaction ); D_DEBUG_AT( EventBuffer, " -> flip count %u\n", surface->flips ); if (surface->flips > 0 || !(surface->config.caps & DSCAPS_FLIPPING)) { EventBufferItem *item; item = D_CALLOC( 1, sizeof(EventBufferItem) ); if (!item) return D_OOM(); else { item->evt.surface.clazz = DFEC_SURFACE; item->evt.surface.type = DSEVT_UPDATE; item->evt.surface.surface_id = surface->object.id; item->evt.surface.update.x1 = 0; item->evt.surface.update.y1 = 0; item->evt.surface.update.x2 = surface->config.size.w - 1; item->evt.surface.update.y2 = surface->config.size.h - 1; item->evt.surface.update_right = item->evt.surface.update; item->evt.surface.flip_count = surface->flips; item->evt.surface.time_stamp = surface->last_frame_time; IDirectFBEventBuffer_AddItem( data, item ); } } return DFB_OK; } DFBResult IDirectFBEventBuffer_DetachSurface( IDirectFBEventBuffer *thiz, CoreSurface *surface ) { AttachedSurface *attached, *next; DIRECT_INTERFACE_GET_DATA( IDirectFBEventBuffer ) D_ASSERT( surface != NULL ); D_DEBUG_AT( EventBuffer, "%s( %p, %p [%02u - %dx%d] )\n", __FUNCTION__, thiz, surface, surface->object.id, surface->config.size.w, surface->config.size.h ); direct_list_foreach_safe (attached, next, data->surfaces) { if (!attached->surface || attached->surface == surface) { direct_list_remove( &data->surfaces, &attached->link ); if (attached->surface) { dfb_surface_detach( attached->surface, &attached->reaction ); dfb_surface_unref( attached->surface ); } D_FREE( attached ); } } return DFB_OK; } /**********************************************************************************************************************/ /* * Adds an event to the event queue. */ static void IDirectFBEventBuffer_AddItem( IDirectFBEventBuffer_data *data, EventBufferItem *item ) { if (data->filter && data->filter( &item->evt, data->filter_ctx )) { D_FREE( item ); return; } direct_mutex_lock( &data->events_mutex ); if (data->stats_enabled) CollectEventStatistics( &data->stats, &item->evt, 1 ); direct_list_append( &data->events, &item->link ); direct_waitqueue_broadcast( &data->wait_condition ); direct_mutex_unlock( &data->events_mutex ); } static ReactionResult IDirectFBEventBuffer_InputReact( const void *msg_data, void *ctx ) { const DFBInputEvent *evt = msg_data; IDirectFBEventBuffer_data *data = ctx; EventBufferItem *item; D_DEBUG_AT( EventBuffer, "%s( %p, %p ) <- type %06x\n", __FUNCTION__, evt, data, evt->type ); if (dfb_config->discard_repeat_events && (evt->flags & DIEF_REPEAT)) { D_DEBUG_AT( EventBuffer, " -> discarding repeat event!\n" ); return DFB_OK; } item = D_CALLOC( 1, sizeof(EventBufferItem) ); item->evt.input = *evt; item->evt.clazz = DFEC_INPUT; IDirectFBEventBuffer_AddItem( data, item ); return RS_OK; } static ReactionResult IDirectFBEventBuffer_WindowReact( const void *msg_data, void *ctx ) { const DFBWindowEvent *evt = msg_data; IDirectFBEventBuffer_data *data = ctx; EventBufferItem *item; D_DEBUG_AT( EventBuffer, "%s( %p, %p ) <- type %06x\n", __FUNCTION__, evt, data, evt->type ); if (dfb_config->discard_repeat_events && (evt->flags & DWEF_REPEAT)) { D_DEBUG_AT( EventBuffer, " -> discarding repeat event!\n" ); return DFB_OK; } item = D_CALLOC( 1, sizeof(EventBufferItem) ); item->evt.window = *evt; item->evt.clazz = DFEC_WINDOW; IDirectFBEventBuffer_AddItem( data, item ); if (evt->type == DWET_DESTROYED) { AttachedWindow *window; direct_list_foreach (window, data->windows) { if (!window->window) continue; if (window->window->id == evt->window_id) { dfb_window_unref( window->window ); window->window = NULL; } } return RS_REMOVE; } return RS_OK; } static ReactionResult IDirectFBEventBuffer_SurfaceReact( const void *msg_data, void *ctx ) { const DFBSurfaceEvent *evt = msg_data; IDirectFBEventBuffer_data *data = ctx; EventBufferItem *item; D_DEBUG_AT( EventBuffer_Surface, "%s( %p, %p ) <- type %06x\n", __FUNCTION__, evt, data, evt->type ); D_DEBUG_AT( EventBuffer_Surface, " -> surface id %u\n", evt->surface_id ); if (evt->type == DSEVT_UPDATE) { D_DEBUG_AT( EventBuffer_Surface, " -> updated %4d,%4d-%4dx%4d (left)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update ) ); D_DEBUG_AT( EventBuffer_Surface, " -> updated %4d,%4d-%4dx%4d (right)\n", DFB_RECTANGLE_VALS_FROM_REGION( &evt->update_right ) ); D_DEBUG_AT( EventBuffer_Surface, " -> flip count %u\n", evt->flip_count ); D_DEBUG_AT( EventBuffer_Surface, " -> time stamp %lld\n", evt->time_stamp ); } item = D_CALLOC( 1, sizeof(EventBufferItem) ); item->evt.surface = *evt; item->evt.clazz = DFEC_SURFACE; IDirectFBEventBuffer_AddItem( data, item ); if (evt->type == DSEVT_DESTROYED) { AttachedSurface *surface; direct_list_foreach (surface, data->surfaces) { if (!surface->surface) continue; if (surface->surface->object.id == evt->surface_id) { dfb_surface_unref( surface->surface ); surface->surface = NULL; } } return RS_REMOVE; } return RS_OK; } static void * IDirectFBEventBuffer_Feed( DirectThread *thread, void *arg ) { IDirectFBEventBuffer_data *data = arg; direct_mutex_lock( &data->events_mutex ); while (data->pipe) { while (data->events && data->pipe) { ssize_t num; EventBufferItem *item = (EventBufferItem*) data->events; D_UNUSED_P( num ); if (data->stats_enabled) CollectEventStatistics( &data->stats, &item->evt, -1 ); direct_list_remove( &data->events, &item->link ); if (item->evt.clazz == DFEC_UNIVERSAL) { D_WARN( "universal events not supported in pipe mode" ); continue; } direct_mutex_unlock( &data->events_mutex ); D_DEBUG_AT( EventBuffer_Feed, "Going to write "_ZU" bytes to file descriptor %d...\n", sizeof(DFBEvent), data->pipe_fds[1] ); num = write( data->pipe_fds[1], &item->evt, sizeof(DFBEvent) ); D_DEBUG_AT( EventBuffer_Feed, "...wrote "_ZD" bytes to file descriptor %d\n", num, data->pipe_fds[1] ); D_FREE( item ); direct_mutex_lock( &data->events_mutex ); } if (data->pipe) direct_waitqueue_wait( &data->wait_condition, &data->events_mutex ); } direct_mutex_unlock( &data->events_mutex ); return NULL; } static void CollectEventStatistics( DFBEventBufferStats *stats, const DFBEvent *event, int incdec ) { stats->num_events += incdec; switch (event->clazz) { case DFEC_INPUT: stats->DFEC_INPUT += incdec; switch (event->input.type) { case DIET_KEYPRESS: stats->DIET_KEYPRESS += incdec; break; case DIET_KEYRELEASE: stats->DIET_KEYRELEASE += incdec; break; case DIET_BUTTONPRESS: stats->DIET_BUTTONPRESS += incdec; break; case DIET_BUTTONRELEASE: stats->DIET_BUTTONRELEASE += incdec; break; case DIET_AXISMOTION: stats->DIET_AXISMOTION += incdec; break; default: D_BUG( "unknown input event type 0x%08x", event->input.type ); } break; case DFEC_WINDOW: stats->DFEC_WINDOW += incdec; switch (event->window.type) { case DWET_POSITION: stats->DWET_POSITION += incdec; break; case DWET_SIZE: stats->DWET_SIZE += incdec; break; case DWET_CLOSE: stats->DWET_CLOSE += incdec; break; case DWET_DESTROYED: stats->DWET_DESTROYED += incdec; break; case DWET_GOTFOCUS: stats->DWET_GOTFOCUS += incdec; break; case DWET_LOSTFOCUS: stats->DWET_LOSTFOCUS += incdec; break; case DWET_KEYDOWN: stats->DWET_KEYDOWN += incdec; break; case DWET_KEYUP: stats->DWET_KEYUP += incdec; break; case DWET_BUTTONDOWN: stats->DWET_BUTTONDOWN += incdec; break; case DWET_BUTTONUP: stats->DWET_BUTTONUP += incdec; break; case DWET_MOTION: stats->DWET_MOTION += incdec; break; case DWET_ENTER: stats->DWET_ENTER += incdec; break; case DWET_LEAVE: stats->DWET_LEAVE += incdec; break; case DWET_WHEEL: stats->DWET_WHEEL += incdec; break; case DWET_POSITION_SIZE: stats->DWET_POSITION_SIZE += incdec; break; default: D_BUG( "unknown window event type 0x%08x", event->window.type ); } break; case DFEC_USER: stats->DFEC_USER += incdec; break; case DFEC_VIDEOPROVIDER: stats->DFEC_VIDEOPROVIDER +=incdec; switch (event->videoprovider.type) { case DVPET_STARTED: stats->DVPET_STARTED += incdec; break; case DVPET_STOPPED: stats->DVPET_STOPPED += incdec; break; case DVPET_SPEEDCHANGE: stats->DVPET_SPEEDCHANGE += incdec; break; case DVPET_STREAMCHANGE: stats->DVPET_STREAMCHANGE += incdec; break; case DVPET_FATALERROR: stats->DVPET_FATALERROR += incdec; break; case DVPET_FINISHED: stats->DVPET_FINISHED += incdec; break; case DVPET_SURFACECHANGE: stats->DVPET_SURFACECHANGE += incdec; break; case DVPET_FRAMEDECODED: stats->DVPET_FRAMEDECODED += incdec; break; case DVPET_FRAMEDISPLAYED: stats->DVPET_FRAMEDISPLAYED += incdec; break; case DVPET_DATAEXHAUSTED: stats->DVPET_DATAEXHAUSTED += incdec; break; case DVPET_VIDEOACTION: stats->DVPET_VIDEOACTION += incdec; break; case DVPET_DATALOW: stats->DVPET_DATALOW += incdec; break; case DVPET_DATAHIGH: stats->DVPET_DATAHIGH += incdec; break; case DVPET_BUFFERTIMELOW: stats->DVPET_BUFFERTIMELOW += incdec; break; case DVPET_BUFFERTIMEHIGH: stats->DVPET_BUFFERTIMEHIGH += incdec; break; default: D_BUG( "unknown video provider event type 0x%08x", event->videoprovider.type ); } break; case DFEC_UNIVERSAL: stats->DFEC_UNIVERSAL += incdec; break; default: D_BUG( "unknown event class 0x%08x", event->clazz ); } } ================================================ FILE: src/input/idirectfbeventbuffer.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __INPUT__IDIRECTFBEVENTBUFFER_H__ #define __INPUT__IDIRECTFBEVENTBUFFER_H__ #include typedef bool (*EventBufferFilterCallback)( DFBEvent *evt, void *ctx ); /* * initializes interface struct and private data */ DFBResult IDirectFBEventBuffer_Construct ( IDirectFBEventBuffer *thiz, EventBufferFilterCallback filter, void *filter_ctx ); DFBResult IDirectFBEventBuffer_AttachInputDevice( IDirectFBEventBuffer *thiz, CoreInputDevice *device ); DFBResult IDirectFBEventBuffer_DetachInputDevice( IDirectFBEventBuffer *thiz, CoreInputDevice *device ); DFBResult IDirectFBEventBuffer_AttachWindow ( IDirectFBEventBuffer *thiz, CoreWindow *window ); DFBResult IDirectFBEventBuffer_DetachWindow ( IDirectFBEventBuffer *thiz, CoreWindow *window ); DFBResult IDirectFBEventBuffer_AttachSurface ( IDirectFBEventBuffer *thiz, CoreSurface *surface ); DFBResult IDirectFBEventBuffer_DetachSurface ( IDirectFBEventBuffer *thiz, CoreSurface *surface ); #endif ================================================ FILE: src/input/idirectfbinputdevice.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include D_DEBUG_DOMAIN( InputDevice, "IDirectFBInputDevice", "IDirectFBInputDevice Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBInputDevice */ typedef struct { int ref; /* reference counter */ CoreInputDevice *device; /* the input device object */ int axis[DIAI_LAST+1]; /* position of all axes */ DFBInputDeviceKeyState keystates[DIKI_NUMBER_OF_KEYS]; /* state of all keys */ DFBInputDeviceDescription desc; /* device description */ Reaction reaction; } IDirectFBInputDevice_data; /**********************************************************************************************************************/ static void IDirectFBInputDevice_Destruct( IDirectFBInputDevice *thiz ) { IDirectFBInputDevice_data *data = thiz->priv; D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); dfb_input_detach( data->device, &data->reaction ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBInputDevice_AddRef( IDirectFBInputDevice *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBInputDevice_Release( IDirectFBInputDevice *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBInputDevice_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBInputDevice_GetID( IDirectFBInputDevice *thiz, DFBInputDeviceID *ret_device_id ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_device_id) return DFB_INVARG; *ret_device_id = dfb_input_device_id( data->device ); return DFB_OK; } static DFBResult IDirectFBInputDevice_GetDescription( IDirectFBInputDevice *thiz, DFBInputDeviceDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->desc; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetKeymapEntry( IDirectFBInputDevice *thiz, int keycode, DFBInputDeviceKeymapEntry *ret_entry ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_entry) return DFB_INVARG; if (data->desc.min_keycode < 0 || data->desc.max_keycode < 0) return DFB_UNSUPPORTED; if (keycode < data->desc.min_keycode || keycode > data->desc.max_keycode) return DFB_INVARG; return dfb_input_device_get_keymap_entry( data->device, keycode, ret_entry ); } static DFBResult IDirectFBInputDevice_SetKeymapEntry( IDirectFBInputDevice *thiz, int keycode, DFBInputDeviceKeymapEntry *entry ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!entry) return DFB_INVARG; if (data->desc.min_keycode < 0 || data->desc.max_keycode < 0) return DFB_UNSUPPORTED; if (keycode < data->desc.min_keycode || keycode > data->desc.max_keycode) return DFB_INVARG; return CoreInputDevice_SetKeymapEntry( data->device, keycode, entry ); } static DFBResult IDirectFBInputDevice_LoadKeymap ( IDirectFBInputDevice *thiz, char *filename ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!filename) return DFB_INVARG; return dfb_input_device_load_keymap( data->device, filename ); } static DFBResult IDirectFBInputDevice_CreateEventBuffer( IDirectFBInputDevice *thiz, IDirectFBEventBuffer **ret_interface ) { IDirectFBEventBuffer *iface; DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBEventBuffer ); IDirectFBEventBuffer_Construct( iface, NULL, NULL ); IDirectFBEventBuffer_AttachInputDevice( iface, data->device ); *ret_interface = iface; return DFB_OK; } static DFBResult IDirectFBInputDevice_AttachEventBuffer( IDirectFBInputDevice *thiz, IDirectFBEventBuffer *buffer ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); return IDirectFBEventBuffer_AttachInputDevice( buffer, data->device ); } static DFBResult IDirectFBInputDevice_DetachEventBuffer( IDirectFBInputDevice *thiz, IDirectFBEventBuffer *buffer ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); return IDirectFBEventBuffer_DetachInputDevice( buffer, data->device ); } static DFBResult IDirectFBInputDevice_GetKeyState( IDirectFBInputDevice *thiz, DFBInputDeviceKeyIdentifier key_id, DFBInputDeviceKeyState *ret_state ) { unsigned int index = key_id - DFB_KEY( IDENTIFIER, 0 ); DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_state || index >= DIKI_NUMBER_OF_KEYS) return DFB_INVARG; *ret_state = data->keystates[index]; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetModifiers( IDirectFBInputDevice *thiz, DFBInputDeviceModifierMask *ret_modifiers ) { DFBResult ret; InputDeviceState state; DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_modifiers) return DFB_INVARG; ret = dfb_input_device_get_state( data->device, &state ); if (ret) return ret; *ret_modifiers = state.modifiers_l | state.modifiers_r; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetLockState( IDirectFBInputDevice *thiz, DFBInputDeviceLockState *ret_locks ) { DFBResult ret; InputDeviceState state; DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_locks) return DFB_INVARG; ret = dfb_input_device_get_state( data->device, &state ); if (ret) return ret; *ret_locks = state.locks; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetButtons( IDirectFBInputDevice *thiz, DFBInputDeviceButtonMask *ret_buttons ) { DFBResult ret; InputDeviceState state; DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_buttons) return DFB_INVARG; ret = dfb_input_device_get_state( data->device, &state ); if (ret) return ret; *ret_buttons = state.buttons; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetButtonState( IDirectFBInputDevice *thiz, DFBInputDeviceButtonIdentifier button, DFBInputDeviceButtonState *ret_state ) { DFBResult ret; InputDeviceState state; DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); ret = dfb_input_device_get_state( data->device, &state ); if (ret) return ret; if (!ret_state || button < DIBI_FIRST || button > DIBI_LAST) return DFB_INVARG; *ret_state = (state.buttons & (1 << button)) ? DIBS_DOWN : DIBS_UP; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetAxis( IDirectFBInputDevice *thiz, DFBInputDeviceAxisIdentifier axis, int *ret_pos ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_pos || axis < DIAI_FIRST || axis > DIAI_LAST) return DFB_INVARG; *ret_pos = data->axis[axis]; return DFB_OK; } static DFBResult IDirectFBInputDevice_GetXY( IDirectFBInputDevice *thiz, int *ret_x, int *ret_y ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_x && !ret_y) return DFB_INVARG; if (ret_x) *ret_x = data->axis[DIAI_X]; if (ret_y) *ret_y = data->axis[DIAI_Y]; return DFB_OK; } static DFBResult IDirectFBInputDevice_SetConfiguration( IDirectFBInputDevice *thiz, const DFBInputDeviceConfig *config ) { DIRECT_INTERFACE_GET_DATA( IDirectFBInputDevice ) return CoreInputDevice_SetConfiguration( data->device, config ); } static ReactionResult IDirectFBInputDevice_React( const void *msg_data, void *ctx ) { const DFBInputEvent *evt = msg_data; IDirectFBInputDevice_data *data = ctx; unsigned int index; D_DEBUG_AT( InputDevice, "%s( %p, %p ) <- type %06x\n", __FUNCTION__, evt, data, evt->type ); switch (evt->type) { case DIET_KEYPRESS: index = evt->key_id - DFB_KEY( IDENTIFIER, 0 ); if (index < DIKI_NUMBER_OF_KEYS) data->keystates[index] = DIKS_DOWN; break; case DIET_KEYRELEASE: index = evt->key_id - DFB_KEY( IDENTIFIER, 0 ); if (index < DIKI_NUMBER_OF_KEYS) data->keystates[index] = DIKS_UP; break; case DIET_AXISMOTION: if (evt->flags & DIEF_AXISREL) data->axis[evt->axis] += evt->axisrel; if (evt->flags & DIEF_AXISABS) data->axis[evt->axis] = evt->axisabs; break; default: D_DEBUG_AT( InputDevice, " -> unknown event type, skipping!\n" ); } return RS_OK; } DFBResult IDirectFBInputDevice_Construct( IDirectFBInputDevice *thiz, CoreInputDevice *device ) { DFBResult ret; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBInputDevice ) D_DEBUG_AT( InputDevice, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->device = device; dfb_input_device_description( device, &data->desc ); ret = dfb_input_attach( data->device, IDirectFBInputDevice_React, data, &data->reaction ); if (ret) { D_DERROR( ret, "IDirectFBInputDevice: Could not attach to reactor!\n" ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } thiz->AddRef = IDirectFBInputDevice_AddRef; thiz->Release = IDirectFBInputDevice_Release; thiz->GetID = IDirectFBInputDevice_GetID; thiz->GetDescription = IDirectFBInputDevice_GetDescription; thiz->GetKeymapEntry = IDirectFBInputDevice_GetKeymapEntry; thiz->SetKeymapEntry = IDirectFBInputDevice_SetKeymapEntry; thiz->LoadKeymap = IDirectFBInputDevice_LoadKeymap; thiz->CreateEventBuffer = IDirectFBInputDevice_CreateEventBuffer; thiz->AttachEventBuffer = IDirectFBInputDevice_AttachEventBuffer; thiz->DetachEventBuffer = IDirectFBInputDevice_DetachEventBuffer; thiz->GetKeyState = IDirectFBInputDevice_GetKeyState; thiz->GetModifiers = IDirectFBInputDevice_GetModifiers; thiz->GetLockState = IDirectFBInputDevice_GetLockState; thiz->GetButtons = IDirectFBInputDevice_GetButtons; thiz->GetButtonState = IDirectFBInputDevice_GetButtonState; thiz->GetAxis = IDirectFBInputDevice_GetAxis; thiz->GetXY = IDirectFBInputDevice_GetXY; thiz->SetConfiguration = IDirectFBInputDevice_SetConfiguration; return DFB_OK; } ================================================ FILE: src/input/idirectfbinputdevice.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __INPUT__IDIRECTFBINPUTDEVICE_H__ #define __INPUT__IDIRECTFBINPUTDEVICE_H__ #include /* * initializes interface struct and private data */ DFBResult IDirectFBInputDevice_Construct( IDirectFBInputDevice *thiz, CoreInputDevice *device ); #endif ================================================ FILE: src/media/idirectfbdatabuffer.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( DataBuffer, "IDirectFBDataBuffer", "IDirectFBDataBuffer Interface" ); /**********************************************************************************************************************/ void IDirectFBDataBuffer_Destruct( IDirectFBDataBuffer *thiz ) { IDirectFBDataBuffer_data *data = thiz->priv; D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->filename) D_FREE( data->filename ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBDataBuffer_AddRef( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBDataBuffer_Release( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBDataBuffer_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Flush( IDirectFBDataBuffer *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_Finish( IDirectFBDataBuffer *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_SeekTo( IDirectFBDataBuffer *thiz, unsigned int offset ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_GetPosition( IDirectFBDataBuffer *thiz, unsigned int *ret_offset ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_GetLength( IDirectFBDataBuffer *thiz, unsigned int *ret_length ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_WaitForData( IDirectFBDataBuffer *thiz, unsigned int length ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_WaitForDataWithTimeout( IDirectFBDataBuffer *thiz, unsigned int length, unsigned int seconds, unsigned int milli_seconds ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_GetData( IDirectFBDataBuffer *thiz, unsigned int length, void *ret_data_ptr, unsigned int *ret_read ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_PeekData( IDirectFBDataBuffer *thiz, unsigned int length, int offset, void *ret_data_ptr, unsigned int *ret_read ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_HasData( IDirectFBDataBuffer *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_PutData( IDirectFBDataBuffer *thiz, const void *data_ptr, unsigned int length ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBDataBuffer_CreateImageProvider( IDirectFBDataBuffer *thiz, IDirectFBImageProvider **ret_interface ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* Check arguments. */ if (!ret_interface) return DFB_INVARG; return IDirectFBImageProvider_CreateFromBuffer( thiz, data->core, data->idirectfb, ret_interface ); } static DFBResult IDirectFBDataBuffer_CreateVideoProvider( IDirectFBDataBuffer *thiz, IDirectFBVideoProvider **ret_interface ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* Check arguments. */ if (!ret_interface) return DFB_INVARG; return IDirectFBVideoProvider_CreateFromBuffer( thiz, data->core, data->idirectfb, ret_interface ); } static DFBResult IDirectFBDataBuffer_CreateFont( IDirectFBDataBuffer *thiz, const DFBFontDescription *desc, IDirectFBFont **ret_interface ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* Check arguments. */ if (!desc || !ret_interface) return DFB_INVARG; return IDirectFBFont_CreateFromBuffer( thiz, data->core, desc, ret_interface ); } DFBResult IDirectFBDataBuffer_Construct( IDirectFBDataBuffer *thiz, const char *filename, const void *buffer, unsigned int length, CoreDFB *core, IDirectFB *idirectfb ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->core = core; data->idirectfb = idirectfb; if (filename) data->filename = D_STRDUP( filename ); if (buffer) { data->buffer = (void*) buffer; data->length = length; } thiz->AddRef = IDirectFBDataBuffer_AddRef; thiz->Release = IDirectFBDataBuffer_Release; thiz->Flush = IDirectFBDataBuffer_Flush; thiz->Finish = IDirectFBDataBuffer_Finish; thiz->SeekTo = IDirectFBDataBuffer_SeekTo; thiz->GetPosition = IDirectFBDataBuffer_GetPosition; thiz->GetLength = IDirectFBDataBuffer_GetLength; thiz->WaitForData = IDirectFBDataBuffer_WaitForData; thiz->WaitForDataWithTimeout = IDirectFBDataBuffer_WaitForDataWithTimeout; thiz->GetData = IDirectFBDataBuffer_GetData; thiz->PeekData = IDirectFBDataBuffer_PeekData; thiz->HasData = IDirectFBDataBuffer_HasData; thiz->PutData = IDirectFBDataBuffer_PutData; thiz->CreateImageProvider = IDirectFBDataBuffer_CreateImageProvider; thiz->CreateVideoProvider = IDirectFBDataBuffer_CreateVideoProvider; thiz->CreateFont = IDirectFBDataBuffer_CreateFont; return DFB_OK; } ================================================ FILE: src/media/idirectfbdatabuffer.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBDATABUFFER_H__ #define __MEDIA__IDIRECTFBDATABUFFER_H__ #include /* * private data struct of IDirectFBDataBuffer */ typedef struct { int ref; /* reference counter */ char *filename; /* only set if databuffer is created from file */ void *buffer; /* only set if databuffer is created from memory */ unsigned int length; CoreDFB *core; IDirectFB *idirectfb; } IDirectFBDataBuffer_data; /* * initializes interface struct and private data */ DFBResult IDirectFBDataBuffer_Construct( IDirectFBDataBuffer *thiz, const char *filename, const void *buffer, unsigned int length, CoreDFB *core, IDirectFB *idirectfb ); /* * destroys databuffer and frees private data */ void IDirectFBDataBuffer_Destruct ( IDirectFBDataBuffer *thiz ); #endif ================================================ FILE: src/media/idirectfbdatabuffer_file.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( DataBuffer, "IDirectFBDataBufferF", "IDirectFBDataBuffer_File Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBDataBuffer_File */ typedef struct { IDirectFBDataBuffer_data base; /* base databuffer implementation */ DirectStream *stream; DirectMutex mutex; } IDirectFBDataBuffer_File_data; /**********************************************************************************************************************/ static void IDirectFBDataBuffer_File_Destruct( IDirectFBDataBuffer *thiz ) { IDirectFBDataBuffer_File_data *data = thiz->priv; D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); direct_stream_destroy( data->stream ); direct_mutex_deinit( &data->mutex ); IDirectFBDataBuffer_Destruct( thiz ); } static DirectResult IDirectFBDataBuffer_File_Release( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBDataBuffer_File_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_File_Flush( IDirectFBDataBuffer *thiz ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_File_Finish( IDirectFBDataBuffer *thiz ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_File_SeekTo( IDirectFBDataBuffer *thiz, unsigned int offset ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!direct_stream_seekable( data->stream )) return DFB_UNSUPPORTED; direct_mutex_lock( &data->mutex ); ret = direct_stream_seek( data->stream, offset ); direct_mutex_unlock( &data->mutex ); return ret; } static DFBResult IDirectFBDataBuffer_File_GetPosition( IDirectFBDataBuffer *thiz, unsigned int *ret_offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_offset) return DFB_INVARG; *ret_offset = direct_stream_offset( data->stream ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_File_GetLength( IDirectFBDataBuffer *thiz, unsigned int *ret_length ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_length) return DFB_INVARG; *ret_length = direct_stream_length( data->stream ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_File_WaitForData( IDirectFBDataBuffer *thiz, unsigned int length ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); direct_mutex_lock( &data->mutex ); ret = direct_stream_wait( data->stream, length, NULL ); direct_mutex_unlock( &data->mutex ); return ret; } static DFBResult IDirectFBDataBuffer_File_WaitForDataWithTimeout( IDirectFBDataBuffer *thiz, unsigned int length, unsigned int seconds, unsigned int milli_seconds ) { DirectResult ret; struct timeval tv; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); tv.tv_sec = seconds; tv.tv_usec = milli_seconds*1000; while ((ret = direct_mutex_trylock( &data->mutex ))) { struct timespec t, r; if (ret != DR_BUSY) return ret; t.tv_sec = 0; t.tv_nsec = 10000; nanosleep( &t, &r ); tv.tv_usec -= (t.tv_nsec - r.tv_nsec + 500) / 1000; if (tv.tv_usec < 0) { if (tv.tv_sec < 1) return DFB_TIMEOUT; tv.tv_sec--; tv.tv_usec += 999999; } } ret = direct_stream_wait( data->stream, length, &tv ); direct_mutex_unlock( &data->mutex ); return ret; } static DFBResult IDirectFBDataBuffer_File_GetData( IDirectFBDataBuffer *thiz, unsigned int length, void *ret_data_ptr, unsigned int *ret_read ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length) return DFB_INVARG; direct_mutex_lock( &data->mutex ); ret = direct_stream_read( data->stream, length, ret_data_ptr, ret_read ); direct_mutex_unlock( &data->mutex ); return ret; } static DFBResult IDirectFBDataBuffer_File_PeekData( IDirectFBDataBuffer *thiz, unsigned int length, int offset, void *ret_data_ptr, unsigned int *ret_read ) { DFBResult ret; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length) return DFB_INVARG; direct_mutex_lock( &data->mutex ); ret = direct_stream_peek( data->stream, length, offset, ret_data_ptr, ret_read ); direct_mutex_unlock( &data->mutex ); return ret; } static DFBResult IDirectFBDataBuffer_File_HasData( IDirectFBDataBuffer *thiz ) { struct timeval tv = { 0, 0 }; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return direct_stream_wait( data->stream, 1, &tv ); } static DFBResult IDirectFBDataBuffer_File_PutData( IDirectFBDataBuffer *thiz, const void *data_ptr, unsigned int length ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } DFBResult IDirectFBDataBuffer_File_Construct( IDirectFBDataBuffer *thiz, const char *filename, CoreDFB *core, IDirectFB *idirectfb ) { DFBResult ret; DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBDataBuffer_File ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); IDirectFBDataBuffer_Construct( thiz, filename, NULL, 0, core, idirectfb ); ret = direct_stream_create( filename, &data->stream ); if (ret) { D_DERROR( ret, "IDirectFBDataBufferF: Failed to create stream '%s'!\n", filename ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } direct_mutex_init( &data->mutex ); thiz->Release = IDirectFBDataBuffer_File_Release; thiz->Flush = IDirectFBDataBuffer_File_Flush; thiz->Finish = IDirectFBDataBuffer_File_Finish; thiz->SeekTo = IDirectFBDataBuffer_File_SeekTo; thiz->GetPosition = IDirectFBDataBuffer_File_GetPosition; thiz->GetLength = IDirectFBDataBuffer_File_GetLength; thiz->WaitForData = IDirectFBDataBuffer_File_WaitForData; thiz->WaitForDataWithTimeout = IDirectFBDataBuffer_File_WaitForDataWithTimeout; thiz->GetData = IDirectFBDataBuffer_File_GetData; thiz->PeekData = IDirectFBDataBuffer_File_PeekData; thiz->HasData = IDirectFBDataBuffer_File_HasData; thiz->PutData = IDirectFBDataBuffer_File_PutData; return DFB_OK; } ================================================ FILE: src/media/idirectfbdatabuffer_file.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBDATABUFFER_FILE_H__ #define __MEDIA__IDIRECTFBDATABUFFER_FILE_H__ #include /* * calls base databuffer constructor and initializes file based static databuffer */ DFBResult IDirectFBDataBuffer_File_Construct( IDirectFBDataBuffer *thiz, const char *filename, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/media/idirectfbdatabuffer_memory.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include D_DEBUG_DOMAIN( DataBuffer, "IDirectFBDataBufferM", "IDirectFBDataBuffer_Memory Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBDataBuffer_Memory */ typedef struct { IDirectFBDataBuffer_data base; const void *buffer; unsigned int length; unsigned int pos; } IDirectFBDataBuffer_Memory_data; /**********************************************************************************************************************/ static void IDirectFBDataBuffer_Memory_Destruct( IDirectFBDataBuffer *thiz ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); IDirectFBDataBuffer_Destruct( thiz ); } static DirectResult IDirectFBDataBuffer_Memory_Release( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBDataBuffer_Memory_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_Flush( IDirectFBDataBuffer *thiz ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_Memory_Finish( IDirectFBDataBuffer *thiz ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_Memory_SeekTo( IDirectFBDataBuffer *thiz, unsigned int offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (offset >= data->length) return DFB_INVARG; data->pos = offset; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_GetPosition( IDirectFBDataBuffer *thiz, unsigned int *ret_offset ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_offset) return DFB_INVARG; *ret_offset = data->pos; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_GetLength( IDirectFBDataBuffer *thiz, unsigned int *ret_length ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_length) return DFB_INVARG; *ret_length = data->length; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_WaitForData( IDirectFBDataBuffer *thiz, unsigned int length ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pos + length > data->length) return DFB_EOF; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_WaitForDataWithTimeout( IDirectFBDataBuffer *thiz, unsigned int length, unsigned int seconds, unsigned int milli_seconds ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pos + length > data->length) return DFB_EOF; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_GetData( IDirectFBDataBuffer *thiz, unsigned int length, void *ret_data_ptr, unsigned int *ret_read ) { unsigned int size; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length) return DFB_INVARG; if (data->pos >= data->length) return DFB_EOF; size = MIN( length, data->length - data->pos ); direct_memcpy( ret_data_ptr, data->buffer + data->pos, size ); data->pos += size; if (ret_read) *ret_read = size; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_PeekData( IDirectFBDataBuffer *thiz, unsigned int length, int offset, void *ret_data_ptr, unsigned int *ret_read ) { unsigned int size; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length) return DFB_INVARG; if (data->pos + offset >= data->length) return DFB_EOF; size = MIN( length, data->length - data->pos - offset ); direct_memcpy( ret_data_ptr, data->buffer + data->pos + offset, size ); if (ret_read) *ret_read = size; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_HasData( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->pos >= data->length) return DFB_EOF; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Memory_PutData( IDirectFBDataBuffer *thiz, const void *data_ptr, unsigned int length ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } DFBResult IDirectFBDataBuffer_Memory_Construct( IDirectFBDataBuffer *thiz, const void *buffer, unsigned int length, CoreDFB *core, IDirectFB *idirectfb ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBDataBuffer_Memory ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); IDirectFBDataBuffer_Construct( thiz, NULL, buffer, length, core, idirectfb ); data->buffer = buffer; data->length = length; thiz->Release = IDirectFBDataBuffer_Memory_Release; thiz->Flush = IDirectFBDataBuffer_Memory_Flush; thiz->Finish = IDirectFBDataBuffer_Memory_Finish; thiz->SeekTo = IDirectFBDataBuffer_Memory_SeekTo; thiz->GetPosition = IDirectFBDataBuffer_Memory_GetPosition; thiz->GetLength = IDirectFBDataBuffer_Memory_GetLength; thiz->WaitForData = IDirectFBDataBuffer_Memory_WaitForData; thiz->WaitForDataWithTimeout = IDirectFBDataBuffer_Memory_WaitForDataWithTimeout; thiz->GetData = IDirectFBDataBuffer_Memory_GetData; thiz->PeekData = IDirectFBDataBuffer_Memory_PeekData; thiz->HasData = IDirectFBDataBuffer_Memory_HasData; thiz->PutData = IDirectFBDataBuffer_Memory_PutData; return DFB_OK; } ================================================ FILE: src/media/idirectfbdatabuffer_memory.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBDATABUFFER_MEMORY_H__ #define __MEDIA__IDIRECTFBDATABUFFER_MEMORY_H__ #include /* * calls base databuffer constructor and initializes memory based static databuffer */ DFBResult IDirectFBDataBuffer_Memory_Construct( IDirectFBDataBuffer *thiz, const void *buffer, unsigned int length, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/media/idirectfbdatabuffer_streamed.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include D_DEBUG_DOMAIN( DataBuffer, "IDirectFBDataBufferS", "IDirectFBDataBuffer_Streamed Interface" ); /**********************************************************************************************************************/ /* * private data struct of IDirectFBDataBuffer_Streamed */ typedef struct { IDirectFBDataBuffer_data base; /* base databuffer implementation */ DirectLink *chunks; /* data chunks */ unsigned int length; /* total length of all chunks */ bool finished; /* whether Finish() has been called */ DirectMutex chunks_mutex; /* mutex lock for accessing the chunk list */ DirectWaitQueue wait_condition; /* condition used for idle wait */ } IDirectFBDataBuffer_Streamed_data; typedef struct { DirectLink link; void *data; /* actual data hold */ unsigned int length; /* length of chunk */ unsigned int done; /* number of bytes already consumed */ } DataChunk; static DataChunk *create_chunk ( const void *data, int length ); static void destroy_chunk( DataChunk *chunk ); static void DestroyAllChunks( IDirectFBDataBuffer_Streamed_data *data ); static void ReadChunkData ( IDirectFBDataBuffer_Streamed_data *data, void *buffer, unsigned int offset, unsigned int length, bool flush ); /**********************************************************************************************************************/ static void IDirectFBDataBuffer_Streamed_Destruct( IDirectFBDataBuffer *thiz ) { IDirectFBDataBuffer_Streamed_data *data = thiz->priv; D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); direct_waitqueue_deinit( &data->wait_condition ); direct_mutex_deinit( &data->chunks_mutex ); IDirectFBDataBuffer_Destruct( thiz ); } static DirectResult IDirectFBDataBuffer_Streamed_Release( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBDataBuffer_Streamed_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_Flush( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); direct_mutex_lock( &data->chunks_mutex ); DestroyAllChunks( data ); direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_Finish( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!data->finished) { data->finished = true; direct_mutex_lock( &data->chunks_mutex ); direct_waitqueue_broadcast( &data->wait_condition ); direct_mutex_unlock( &data->chunks_mutex ); } return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_SeekTo( IDirectFBDataBuffer *thiz, unsigned int offset ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_Streamed_GetPosition( IDirectFBDataBuffer *thiz, unsigned int *ret_offset ) { D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); return DFB_UNSUPPORTED; } static DFBResult IDirectFBDataBuffer_Streamed_GetLength( IDirectFBDataBuffer *thiz, unsigned int *ret_length ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_length) return DFB_INVARG; *ret_length = data->length; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_WaitForData( IDirectFBDataBuffer *thiz, unsigned int length ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->finished && !data->chunks) return DFB_EOF; direct_mutex_lock( &data->chunks_mutex ); while (data->length < length && !data->finished) direct_waitqueue_wait( &data->wait_condition, &data->chunks_mutex ); direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_WaitForDataWithTimeout( IDirectFBDataBuffer *thiz, unsigned int length, unsigned int seconds, unsigned int milli_seconds ) { DirectResult ret = DR_OK; bool locked = false; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (data->finished && !data->chunks) return DFB_EOF; if (direct_mutex_trylock( &data->chunks_mutex ) == 0) { if (data->length >= length) { direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } locked = true; } if (!locked) direct_mutex_lock( &data->chunks_mutex ); while (data->length < length && !data->finished) { ret = direct_waitqueue_wait_timeout( &data->wait_condition, &data->chunks_mutex, seconds * 1000000 + milli_seconds * 1000 ); if (ret == DR_TIMEOUT) break; } direct_mutex_unlock( &data->chunks_mutex ); return ret; } static DFBResult IDirectFBDataBuffer_Streamed_GetData( IDirectFBDataBuffer *thiz, unsigned int length, void *ret_data_ptr, unsigned int *ret_read ) { unsigned int len; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length) return DFB_INVARG; direct_mutex_lock( &data->chunks_mutex ); if (!data->chunks) { direct_mutex_unlock( &data->chunks_mutex ); return data->finished ? DFB_EOF : DFB_BUFFEREMPTY; } /* Calculate maximum number of bytes to be read. */ len = MIN( length, data->length ); /* Read data from chunks (destructive). */ ReadChunkData( data, ret_data_ptr, 0, len, true ); /* Decrease total number of bytes. */ data->length -= len; /* Return number of bytes read. */ if (ret_read) *ret_read = len; direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_PeekData( IDirectFBDataBuffer *thiz, unsigned int length, int offset, void *ret_data_ptr, unsigned int *ret_read ) { unsigned int len; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_data_ptr || !length || offset < 0) return DFB_INVARG; direct_mutex_lock( &data->chunks_mutex ); if (!data->chunks || (unsigned int) offset >= data->length) { direct_mutex_unlock( &data->chunks_mutex ); return data->finished ? DFB_EOF : DFB_BUFFEREMPTY; } /* Calculate maximum number of bytes to be read. */ len = MIN( length, data->length - offset ); /* Read data from chunks (non-destructive). */ ReadChunkData( data, ret_data_ptr, offset, len, false ); /* Return number of bytes read. */ if (ret_read) *ret_read = len; direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_HasData( IDirectFBDataBuffer *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); /* If there's no chunk there's no data. */ if (!data->chunks) return data->finished ? DFB_EOF : DFB_BUFFEREMPTY; return DFB_OK; } static DFBResult IDirectFBDataBuffer_Streamed_PutData( IDirectFBDataBuffer *thiz, const void *data_ptr, unsigned int length ) { DataChunk *chunk; DIRECT_INTERFACE_GET_DATA( IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); if (!data_ptr || !length) return DFB_INVARG; /* Fail if Finish() has been called. */ if (data->finished) return DFB_UNSUPPORTED; /* Create a chunk containing a copy of the provided data. */ chunk = create_chunk( data_ptr, length ); if (!chunk) return DFB_NOSYSTEMMEMORY; direct_mutex_lock( &data->chunks_mutex ); /* Append new chunk. */ direct_list_append( &data->chunks, &chunk->link ); /* Increase total length. */ data->length += length; direct_waitqueue_broadcast( &data->wait_condition ); direct_mutex_unlock( &data->chunks_mutex ); return DFB_OK; } DFBResult IDirectFBDataBuffer_Streamed_Construct( IDirectFBDataBuffer *thiz, CoreDFB *core, IDirectFB *idirectfb ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBDataBuffer_Streamed ) D_DEBUG_AT( DataBuffer, "%s( %p )\n", __FUNCTION__, thiz ); IDirectFBDataBuffer_Construct( thiz, NULL, NULL, 0, core, idirectfb ); direct_mutex_init( &data->chunks_mutex ); direct_waitqueue_init( &data->wait_condition ); thiz->Release = IDirectFBDataBuffer_Streamed_Release; thiz->Flush = IDirectFBDataBuffer_Streamed_Flush; thiz->Finish = IDirectFBDataBuffer_Streamed_Finish; thiz->SeekTo = IDirectFBDataBuffer_Streamed_SeekTo; thiz->GetPosition = IDirectFBDataBuffer_Streamed_GetPosition; thiz->GetLength = IDirectFBDataBuffer_Streamed_GetLength; thiz->WaitForData = IDirectFBDataBuffer_Streamed_WaitForData; thiz->WaitForDataWithTimeout = IDirectFBDataBuffer_Streamed_WaitForDataWithTimeout; thiz->GetData = IDirectFBDataBuffer_Streamed_GetData; thiz->PeekData = IDirectFBDataBuffer_Streamed_PeekData; thiz->HasData = IDirectFBDataBuffer_Streamed_HasData; thiz->PutData = IDirectFBDataBuffer_Streamed_PutData; return DFB_OK; } /**********************************************************************************************************************/ static void DestroyAllChunks( IDirectFBDataBuffer_Streamed_data *data ) { DataChunk *chunk, *next; D_ASSERT( data != NULL ); /* Loop through list. */ direct_list_foreach_safe (chunk, next, data->chunks) { /* Deallocate chunk. */ destroy_chunk( chunk ); } /* Clear lists. */ data->chunks = NULL; } static void ReadChunkData( IDirectFBDataBuffer_Streamed_data *data, void *buffer, unsigned int offset, unsigned int length, bool flush ) { DataChunk *chunk, *next; D_ASSERT( data != NULL ); D_ASSERT( buffer != NULL ); /* Loop through list. */ direct_list_foreach_safe (chunk, next, data->chunks) { unsigned int len; unsigned int off = 0; /* Data to be skipped. */ if (offset) { /* Calculate number of bytes to be skipped from this chunk. */ off = MIN( offset, chunk->length - chunk->done ); /* Decrease number of bytes to skipped. */ offset -= off; } /* Calculate number of bytes to be read from this chunk. */ len = MIN( length, chunk->length - chunk->done - off ); /* Read from this chunk. */ if (len) { /* Copy as many bytes as possible. */ direct_memcpy( buffer, chunk->data + chunk->done + off, len ); /* Increase write pointer. */ buffer = buffer + len; /* Decrease number of bytes to read. */ length -= len; } /* Destructive read. */ if (flush) { /* Increase number of consumed bytes. */ chunk->done += len + off; /* Chunk completely consumed. */ if (chunk->done == chunk->length) { /* Remove the chunk from the list. */ direct_list_remove( &data->chunks, &chunk->link ); /* Deallocate chunk. */ destroy_chunk( chunk ); } } } } static DataChunk * create_chunk( const void *data, int length ) { DataChunk *chunk; D_ASSERT( data != NULL ); D_ASSERT( length > 0 ); /* Allocate chunk information. */ chunk = D_CALLOC( 1, sizeof(DataChunk) ); if (!chunk) return NULL; /* Allocate chunk data. */ chunk->data = D_MALLOC( length ); if (!chunk->data) { D_FREE( chunk ); return NULL; } /* Fill chunk data. */ direct_memcpy( chunk->data, data, length ); /* Remember chunk length. */ chunk->length = length; return chunk; } static void destroy_chunk( DataChunk *chunk ) { D_ASSERT( chunk != NULL ); D_ASSERT( chunk->data != NULL ); /* Deallocate chunk data. */ D_FREE( chunk->data ); /* Deallocate chunk information. */ D_FREE( chunk ); } ================================================ FILE: src/media/idirectfbdatabuffer_streamed.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBDATABUFFER_STREAMED_H__ #define __MEDIA__IDIRECTFBDATABUFFER_STREAMED_H__ #include /* * calls base databuffer constructor and initializes generic streamed databuffer */ DFBResult IDirectFBDataBuffer_Streamed_Construct( IDirectFBDataBuffer *thiz, CoreDFB *core, IDirectFB *idirectfb ); #endif ================================================ FILE: src/media/idirectfbfont.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Font, "IDirectFBFont", "IDirectFBFont Interface" ); /**********************************************************************************************************************/ static unsigned int sqrt16( unsigned int val ) { unsigned short op = 1 << 15; unsigned int res = 1 << 15; while (1) { if (res * res > val) res = res ^ op; op >>= 1; if (op == 0) { res = res + ((val - res * res) > res ? 1 : 0); break; } res = res | op; } return res; } /**********************************************************************************************************************/ void IDirectFBFont_Destruct( IDirectFBFont *thiz ) { IDirectFBFont_data *data = thiz->priv; D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); dfb_font_destroy( data->font ); if (data->content) { switch (data->content_type) { case IDFBFONT_CONTEXT_CONTENT_TYPE_MALLOCED: D_FREE( data->content ); break; case IDFBFONT_CONTEXT_CONTENT_TYPE_MAPPED: direct_file_unmap( data->content, data->content_size ); break; case IDFBFONT_CONTEXT_CONTENT_TYPE_MEMORY: break; default: D_BUG( "unexpected content type %u", data->content_type ); } } DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DirectResult IDirectFBFont_AddRef( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); data->ref++; return DFB_OK; } static DirectResult IDirectFBFont_Release( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (--data->ref == 0) IDirectFBFont_Destruct( thiz ); return DFB_OK; } static DFBResult IDirectFBFont_GetAscender( IDirectFBFont *thiz, int *ret_ascender ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_ascender) return DFB_INVARG; *ret_ascender = data->font->ascender; return DFB_OK; } static DFBResult IDirectFBFont_GetDescender( IDirectFBFont *thiz, int *ret_descender ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_descender) return DFB_INVARG; *ret_descender = data->font->descender; return DFB_OK; } static DFBResult IDirectFBFont_GetHeight( IDirectFBFont *thiz, int *ret_height ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_height) return DFB_INVARG; *ret_height = data->font->height; return DFB_OK; } static DFBResult IDirectFBFont_GetMaxAdvance( IDirectFBFont *thiz, int *ret_maxadvance ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_maxadvance) return DFB_INVARG; *ret_maxadvance = data->font->maxadvance; return DFB_OK; } static DFBResult IDirectFBFont_GetKerning( IDirectFBFont *thiz, unsigned int prev, unsigned int current, int *ret_kern_x, int *ret_kern_y ) { DFBResult ret; int x = 0, y = 0; unsigned int prev_index, current_index; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_kern_x && !ret_kern_y) return DFB_INVARG; dfb_font_lock( data->font ); if (data->font->GetKerning) { ret = dfb_font_decode_character( data->font, data->encoding, prev, &prev_index ); if (ret) goto error; ret = dfb_font_decode_character( data->font, data->encoding, current, ¤t_index ); if (ret) goto error; ret = data->font->GetKerning( data->font, prev_index, current_index, &x, &y ); if (ret) goto error; } dfb_font_unlock( data->font ); if (ret_kern_x) *ret_kern_x = x; if (ret_kern_y) *ret_kern_y = y; return DFB_OK; error: dfb_font_unlock( data->font ); return ret; } static DFBResult IDirectFBFont_GetStringWidth( IDirectFBFont *thiz, const char *text, int bytes, int *ret_width ) { DFBResult ret; int xsize = 0; int ysize = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!text || !ret_width) return DFB_INVARG; if (bytes < 0) bytes = strlen( text ); if (bytes > 0) { int i, num; unsigned int prev = 0; unsigned int indices[bytes]; dfb_font_lock( data->font ); /* Decode string to character indices. */ ret = dfb_font_decode_text( data->font, data->encoding, text, bytes, indices, &num ); if (ret) { dfb_font_unlock( data->font ); return ret; } /* Calculate string width. */ for (i = 0; i < num; i++) { unsigned int current = indices[i]; CoreGlyphData *glyph; if (dfb_font_get_glyph_data( data->font, current, 0, &glyph ) == DFB_OK) { int kx, ky; xsize += glyph->xadvance; ysize += glyph->yadvance; if (prev && data->font->GetKerning && data->font->GetKerning( data->font, prev, current, &kx, &ky ) == DFB_OK) { xsize += kx << 8; ysize += ky << 8; } } prev = current; } dfb_font_unlock( data->font ); } if (!ysize) { *ret_width = xsize >> 8; } else if (!xsize) { *ret_width = ysize >> 8; } else { *ret_width = sqrt16( xsize * xsize + ysize * ysize ) / 4096.0f; } return DFB_OK; } static DFBResult IDirectFBFont_GetStringExtents( IDirectFBFont *thiz, const char *text, int bytes, DFBRectangle *ret_logical_rect, DFBRectangle *ret_ink_rect ) { DFBResult ret; int xbaseline = 0; int ybaseline = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!text) return DFB_INVARG; if (!ret_logical_rect && !ret_ink_rect) return DFB_INVARG; if (bytes < 0) bytes = strlen( text ); if (ret_ink_rect) memset( ret_ink_rect, 0, sizeof(DFBRectangle) ); dfb_font_lock( data->font ); if (bytes > 0) { int i, num; unsigned int prev = 0; unsigned int indices[bytes]; /* Decode string to character indices. */ ret = dfb_font_decode_text( data->font, data->encoding, text, bytes, indices, &num ); if (ret) { dfb_font_unlock( data->font ); return ret; } for (i = 0; i < num; i++) { unsigned int current = indices[i]; CoreGlyphData *glyph; if (dfb_font_get_glyph_data( data->font, current, 0, &glyph ) == DFB_OK) { int kx, ky; if (prev && data->font->GetKerning && data->font->GetKerning( data->font, prev, current, &kx, &ky ) == DFB_OK) { xbaseline += kx << 8; ybaseline += ky << 8; } if (ret_ink_rect) { DFBRectangle glyph_rect = { xbaseline + (glyph->left << 8), ybaseline + (glyph->top << 8), glyph->width << 8, glyph->height << 8 }; dfb_rectangle_union( ret_ink_rect, &glyph_rect ); } xbaseline += glyph->xadvance; ybaseline += glyph->yadvance; } prev = current; } } if (ret_logical_rect) { /* We already have the text baseline vector in (xbaseline,ybaseline). Find the ascender and descender vectors. */ int xascender = data->font->ascender * data->font->up_unit_x; int yascender = data->font->ascender * data->font->up_unit_y; int xdescender = data->font->descender * data->font->up_unit_x; int ydescender = data->font->descender * data->font->up_unit_y; /* Now find top/bottom and left/right points relative to the text. */ int top_left_x = xascender; int top_left_y = yascender; int bottom_left_x = xdescender; int bottom_left_y = ydescender; int top_right_x = top_left_x + (xbaseline >> 8); int top_right_y = top_left_y + (ybaseline >> 8); int bottom_right_x = bottom_left_x + (xbaseline >> 8); int bottom_right_y = bottom_left_y + (ybaseline >> 8); /* The logical rectangle is the bounding-box of these points. */ #define MIN4(a,b,c,d) (MIN( MIN( a, b ), MIN( c, d ) )) #define MAX4(a,b,c,d) (MAX( MAX( a, b ), MAX( c, d ) )) ret_logical_rect->x = MIN4( top_left_x, bottom_left_x, top_right_x, bottom_right_x ); ret_logical_rect->y = MIN4( top_left_y, bottom_left_y, top_right_y, bottom_right_y ); ret_logical_rect->w = MAX4( top_left_x, bottom_left_x, top_right_x, bottom_right_x ) - ret_logical_rect->x; ret_logical_rect->h = MAX4( top_left_y, bottom_left_y, top_right_y, bottom_right_y ) - ret_logical_rect->y; } if (ret_ink_rect) { if (ret_ink_rect->w < 0) { ret_ink_rect->x += ret_ink_rect->w; ret_ink_rect->w = -ret_ink_rect->w; } ret_ink_rect->x += (data->font->ascender * data->font->up_unit_x) / 256.0f; ret_ink_rect->y += (data->font->ascender * data->font->up_unit_y) / 256.0f; ret_ink_rect->x >>= 8; ret_ink_rect->y >>= 8; ret_ink_rect->w >>= 8; ret_ink_rect->h >>= 8; } dfb_font_unlock( data->font ); return DFB_OK; } static DFBResult IDirectFBFont_GetGlyphExtents( IDirectFBFont *thiz, unsigned int character, DFBRectangle *ret_rect, int *ret_advance ) { DFBResult ret; CoreGlyphData *glyph; unsigned int index; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_rect && !ret_advance) return DFB_INVARG; dfb_font_lock( data->font ); ret = dfb_font_decode_character( data->font, data->encoding, character, &index ); if (ret) { dfb_font_unlock( data->font ); return ret; } if (dfb_font_get_glyph_data( data->font, index, 0, &glyph ) != DFB_OK) { if (ret_rect) ret_rect->x = ret_rect->y = ret_rect->w = ret_rect->h = 0; if (ret_advance) *ret_advance = 0; } else { if (ret_rect) { ret_rect->x = glyph->left; ret_rect->y = glyph->top - data->font->ascender; ret_rect->w = glyph->width; ret_rect->h = glyph->height; } if (ret_advance) *ret_advance = glyph->xadvance >> 8; } dfb_font_unlock( data->font ); return DFB_OK; } static DFBResult IDirectFBFont_GetStringBreak( IDirectFBFont *thiz, const char *text, int bytes, int max_width, int *ret_width, int *ret_str_length, const char **ret_next_line ) { DFBResult ret; const u8 *string; const u8 *last; const u8 *end; CoreGlyphData *glyph; int kern_x; int kern_y; int length = 0; int xsize = 0; int ysize = 0; int width = 0; unichar current; unsigned int index; unsigned int prev = 0; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) if (!text || !ret_next_line || !ret_str_length || !ret_width) return DFB_INVARG; if (data->encoding != DTEID_UTF8) return DFB_UNSUPPORTED; if (bytes < 0) bytes = strlen( text ); if (!bytes) { *ret_next_line = NULL; *ret_str_length = 0; *ret_width = 0; return DFB_OK; } string = (const u8*) text; end = string + bytes; *ret_next_line = NULL; dfb_font_lock( data->font ); do { *ret_width = width >> 8; current = DIRECT_UTF8_GET_CHAR( string ); last = string; string += DIRECT_UTF8_SKIP( string[0] ); if (current == ' ' || current == 0x0a) { *ret_next_line = (const char*) string; *ret_str_length = length; *ret_width = width >> 8; } length++; ret = dfb_font_decode_character( data->font, data->encoding, current, &index ); if (ret) continue; ret = dfb_font_get_glyph_data( data->font, index, 0, &glyph ); if (ret) continue; xsize += glyph->xadvance; ysize += glyph->yadvance; if (prev && data->font->GetKerning && data->font->GetKerning( data->font, prev, index, &kern_x, NULL ) == DFB_OK) width += kern_x << 8; if (prev && data->font->GetKerning && data->font->GetKerning( data->font, prev, index, &kern_x, &kern_y) == DFB_OK) { xsize += kern_x << 8; ysize += kern_y << 8; } if (!ysize) { width = xsize; } else if (!xsize) { width = ysize; } else { width = sqrt16( xsize * xsize + ysize * ysize ) / 256.0f; } prev = index; } while ((width >> 8) < max_width && string < end && current != 0x0a); dfb_font_unlock( data->font ); if ((width >> 8) < max_width && string >= end) { *ret_next_line = NULL; *ret_str_length = length; *ret_width = width >> 8; return DFB_OK; } if (*ret_next_line == NULL) { if (length == 1) { *ret_str_length = length; *ret_next_line = (const char*) string; *ret_width = width >> 8; } else { *ret_str_length = length - 1; *ret_next_line = (const char*) last; } } return DFB_OK; } static DFBResult IDirectFBFont_SetEncoding( IDirectFBFont *thiz, DFBTextEncodingID encoding ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p, %u )\n", __FUNCTION__, thiz, encoding ); if (encoding > data->font->last_encoding) return DFB_IDNOTFOUND; data->encoding = encoding; return DFB_OK; } static DFBResult IDirectFBFont_EnumEncodings( IDirectFBFont *thiz, DFBTextEncodingCallback callback, void *callbackdata ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) if (!callback) return DFB_INVARG; D_DEBUG_AT( Font, "%s( %p, %p, %p )\n", __FUNCTION__, thiz, callback, callbackdata ); if (callback( DTEID_UTF8, "UTF8", callbackdata ) == DFENUM_OK) { for (i = DTEID_OTHER; i <= data->font->last_encoding; i++) { if (callback( i, data->font->encodings[i]->name, callbackdata ) != DFENUM_OK) break; } } return DFB_OK; } static DFBResult IDirectFBFont_FindEncoding( IDirectFBFont *thiz, const char *name, DFBTextEncodingID *ret_encoding ) { int i; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) if (!name || !ret_encoding) return DFB_INVARG; D_DEBUG_AT( Font, "%s( %p, '%s', %p )\n", __FUNCTION__, thiz, name, ret_encoding ); if (!strcasecmp( name, "UTF8" )) { *ret_encoding = DTEID_UTF8; return DFB_OK; } for (i = DTEID_OTHER; i <= data->font->last_encoding; i++) { if (!strcasecmp( name, data->font->encodings[i]->name )) { *ret_encoding = i; return DFB_OK; } } return DFB_IDNOTFOUND; } static DFBResult IDirectFBFont_Dispose( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); return dfb_font_dispose( data->font ); } static DFBResult IDirectFBFont_GetLineSpacingVector( IDirectFBFont *thiz, int *ret_xspacing, int *ret_yspacing ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_xspacing && !ret_yspacing) return DFB_INVARG; if (ret_xspacing) { *ret_xspacing = - data->font->height * data->font->up_unit_x; } if (ret_yspacing) { *ret_yspacing = - data->font->height * data->font->up_unit_y; } return DFB_OK; } static DFBResult IDirectFBFont_GetGlyphExtentsXY( IDirectFBFont *thiz, unsigned int character, DFBRectangle *ret_rect, int *ret_xadvance, int *ret_yadvance ) { DFBResult ret; CoreGlyphData *glyph; unsigned int index; DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_rect && !ret_xadvance && !ret_yadvance) return DFB_INVARG; dfb_font_lock( data->font ); ret = dfb_font_decode_character( data->font, data->encoding, character, &index ); if (ret) { dfb_font_unlock( data->font ); return ret; } if (dfb_font_get_glyph_data( data->font, index, 0, &glyph ) != DFB_OK) { if (ret_rect) ret_rect->x = ret_rect->y = ret_rect->w = ret_rect->h = 0; if (ret_xadvance) *ret_xadvance = 0; if (ret_yadvance) *ret_yadvance = 0; } else { if (ret_rect) { ret_rect->x = glyph->left + data->font->ascender * data->font->up_unit_x; ret_rect->y = glyph->top + data->font->ascender * data->font->up_unit_y; ret_rect->w = glyph->width; ret_rect->h = glyph->height; } if (ret_xadvance) *ret_xadvance = glyph->xadvance; if (ret_yadvance) *ret_yadvance = glyph->yadvance; } dfb_font_unlock( data->font ); return DFB_OK; } static DFBResult IDirectFBFont_GetUnderline( IDirectFBFont *thiz, int *ret_underline_position, int *ret_underline_thickness ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (ret_underline_position) *ret_underline_position = data->font->underline_position; if (ret_underline_thickness) *ret_underline_thickness = data->font->underline_thickness; return DFB_OK; } static DFBResult IDirectFBFont_GetDescription( IDirectFBFont *thiz, DFBFontDescription *ret_desc ) { DIRECT_INTERFACE_GET_DATA( IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); if (!ret_desc) return DFB_INVARG; *ret_desc = data->font->description; return DFB_OK; } DFBResult IDirectFBFont_Construct( IDirectFBFont *thiz, CoreFont *font ) { DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBFont ) D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, thiz ); data->ref = 1; data->font = font; thiz->AddRef = IDirectFBFont_AddRef; thiz->Release = IDirectFBFont_Release; thiz->GetAscender = IDirectFBFont_GetAscender; thiz->GetDescender = IDirectFBFont_GetDescender; thiz->GetHeight = IDirectFBFont_GetHeight; thiz->GetMaxAdvance = IDirectFBFont_GetMaxAdvance; thiz->GetKerning = IDirectFBFont_GetKerning; thiz->GetStringWidth = IDirectFBFont_GetStringWidth; thiz->GetStringExtents = IDirectFBFont_GetStringExtents; thiz->GetGlyphExtents = IDirectFBFont_GetGlyphExtents; thiz->GetStringBreak = IDirectFBFont_GetStringBreak; thiz->SetEncoding = IDirectFBFont_SetEncoding; thiz->EnumEncodings = IDirectFBFont_EnumEncodings; thiz->FindEncoding = IDirectFBFont_FindEncoding; thiz->Dispose = IDirectFBFont_Dispose; thiz->GetLineSpacingVector = IDirectFBFont_GetLineSpacingVector; thiz->GetGlyphExtentsXY = IDirectFBFont_GetGlyphExtentsXY; thiz->GetUnderline = IDirectFBFont_GetUnderline; thiz->GetDescription = IDirectFBFont_GetDescription; return DFB_OK; } static void unmap_or_free( IDirectFBFont_ProbeContext *ctx ) { if (ctx->content) { switch (ctx->content_type) { case IDFBFONT_CONTEXT_CONTENT_TYPE_MALLOCED: D_FREE( ctx->content ); break; case IDFBFONT_CONTEXT_CONTENT_TYPE_MAPPED: direct_file_unmap( ctx->content, ctx->content_size ); break; case IDFBFONT_CONTEXT_CONTENT_TYPE_MEMORY: break; default: D_BUG( "unexpected content type %u", ctx->content_type ); } ctx->content = NULL; } } DFBResult IDirectFBFont_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, const DFBFontDescription *desc, IDirectFBFont **ret_interface ) { DFBResult ret; DirectInterfaceFuncs *funcs = NULL; IDirectFBDataBuffer_data *buffer_data; IDirectFBFont *iface; IDirectFBFont_ProbeContext ctx = { NULL, NULL, 0, IDFBFONT_CONTEXT_CONTENT_TYPE_UNKNOWN }; IDirectFBFont_data *data; D_DEBUG_AT( Font, "%s( %p )\n", __FUNCTION__, buffer ); /* Get the private information of the data buffer. */ buffer_data = buffer->priv; if (!buffer_data) return DFB_DEAD; /* Provide a fallback for fonts without data buffer support. */ ctx.filename = buffer_data->filename; if (buffer_data->buffer) { ctx.content = buffer_data->buffer; ctx.content_size = buffer_data->length; ctx.content_type = IDFBFONT_CONTEXT_CONTENT_TYPE_MEMORY; } else if (buffer_data->filename) { DirectFile fd; DirectFileInfo info; void *ptr; /* Open the file. */ ret = direct_file_open( &fd, ctx.filename, O_RDONLY, 0 ); if (ret) { D_DERROR( ret, "IDirectFBFont: Could not open '%s'\n", ctx.filename ); return ret; } /* Query file size. */ ret = direct_file_get_info( &fd, &info ); if (ret) { D_DERROR( ret, "IDirectFBFont: Could not query info about '%s'\n", ctx.filename ); direct_file_close( &fd ); return ret; } /* Memory-mapped file. */ ret = direct_file_map( &fd, NULL, 0, info.size, DFP_READ, &ptr ); if (ret) { D_DERROR( ret, "IDirectFBFont: Could not mmap '%s'\n", ctx.filename ); direct_file_close( &fd ); return ret; } ctx.content = ptr; ctx.content_size = info.size; ctx.content_type = IDFBFONT_CONTEXT_CONTENT_TYPE_MAPPED; direct_file_close( &fd ); } else { ctx.content_size = 0; ctx.content_type = IDFBFONT_CONTEXT_CONTENT_TYPE_MALLOCED; while (1) { unsigned int bytes; ctx.content = D_REALLOC( ctx.content, ctx.content_size + 4096 ); if (!ctx.content) { ret = D_OOM(); return ret; } buffer->WaitForData( buffer, 4096 ); if (buffer->GetData( buffer, 4096, ctx.content + ctx.content_size, &bytes )) break; ctx.content_size += bytes; } } D_ASSERT( ctx.content_type != IDFBFONT_CONTEXT_CONTENT_TYPE_UNKNOWN ); /* Find a suitable implementation. */ ret = DirectGetInterface( &funcs, "IDirectFBFont", NULL, DirectProbeInterface, &ctx ); if (ret) { unmap_or_free( &ctx ); return ret; } DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBFont ); /* Construct the interface. */ ret = funcs->Construct( iface, core, &ctx, desc ); if (ret) { DIRECT_DEALLOCATE_INTERFACE( iface ); unmap_or_free( &ctx ); return ret; } /* Store content pointer informations for deletion. */ data = iface->priv; data->content = ctx.content; data->content_size = ctx.content_size; data->content_type = ctx.content_type; *ret_interface = iface; return DFB_OK; } ================================================ FILE: src/media/idirectfbfont.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBFONT_H__ #define __MEDIA__IDIRECTFBFONT_H__ #include /* * type of probing context */ typedef enum { IDFBFONT_CONTEXT_CONTENT_TYPE_UNKNOWN = 0x00000000, IDFBFONT_CONTEXT_CONTENT_TYPE_MALLOCED = 0x00000001, IDFBFONT_CONTEXT_CONTENT_TYPE_MAPPED = 0x00000002, IDFBFONT_CONTEXT_CONTENT_TYPE_MEMORY = 0x00000003 } IDirectFBFont_ProbeContextContentType; /* * probing context */ typedef struct { const char *filename; unsigned char *content; unsigned int content_size; IDirectFBFont_ProbeContextContentType content_type; } IDirectFBFont_ProbeContext; /* * private data struct of IDirectFBFont */ typedef struct { int ref; /* reference counter */ CoreFont *font; /* the font object */ unsigned char *content; unsigned int content_size; IDirectFBFont_ProbeContextContentType content_type; DFBTextEncodingID encoding; } IDirectFBFont_data; /* * common code to initialize interface struct and private data */ DFBResult IDirectFBFont_Construct ( IDirectFBFont *thiz, CoreFont *font ); /* * common code to destroy font and free private data */ void IDirectFBFont_Destruct ( IDirectFBFont *thiz ); /* * create (probing) the font */ DFBResult IDirectFBFont_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, const DFBFontDescription *desc, IDirectFBFont **ret_interface ); #endif ================================================ FILE: src/media/idirectfbimageprovider.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( ImageProvider, "IDirectFBImageProvider", "IDirectFBImageProvider Interface" ); /**********************************************************************************************************************/ static DirectResult IDirectFBImageProvider_AddRef( IDirectFBImageProvider *thiz ) { return DFB_UNIMPLEMENTED; } static DirectResult IDirectFBImageProvider_Release( IDirectFBImageProvider *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBImageProvider_GetSurfaceDescription( IDirectFBImageProvider *thiz, DFBSurfaceDescription *ret_desc ) { if (!ret_desc) return DFB_INVARG; ret_desc->flags = DSDESC_NONE; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBImageProvider_GetImageDescription( IDirectFBImageProvider *thiz, DFBImageDescription *ret_desc ) { if (!ret_desc) return DFB_INVARG; ret_desc->caps = DICAPS_NONE; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBImageProvider_RenderTo( IDirectFBImageProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBImageProvider_SetRenderCallback( IDirectFBImageProvider *thiz, DIRenderCallback callback, void *ctx ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBImageProvider_SetRenderFlags( IDirectFBImageProvider *thiz, DIRenderFlags flags ) { return DFB_UNIMPLEMENTED; } static void IDirectFBImageProvider_Construct( IDirectFBImageProvider *thiz ) { D_DEBUG_AT( ImageProvider, "%s( %p )\n", __FUNCTION__, thiz ); thiz->AddRef = IDirectFBImageProvider_AddRef; thiz->Release = IDirectFBImageProvider_Release; thiz->GetSurfaceDescription = IDirectFBImageProvider_GetSurfaceDescription; thiz->GetImageDescription = IDirectFBImageProvider_GetImageDescription; thiz->RenderTo = IDirectFBImageProvider_RenderTo; thiz->SetRenderCallback = IDirectFBImageProvider_SetRenderCallback; thiz->SetRenderFlags = IDirectFBImageProvider_SetRenderFlags; } DFBResult IDirectFBImageProvider_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb, IDirectFBImageProvider **ret_interface ) { DFBResult ret; DirectInterfaceFuncs *funcs = NULL; IDirectFBDataBuffer_data *buffer_data; IDirectFBImageProvider *iface; IDirectFBImageProvider_ProbeContext ctx; D_DEBUG_AT( ImageProvider, "%s( %p )\n", __FUNCTION__, buffer ); /* Get the private information of the data buffer. */ buffer_data = buffer->priv; if (!buffer_data) return DFB_DEAD; /* Clear probe context header. */ memset( ctx.header, 0, sizeof(ctx.header) ); /* Provide a fallback for image providers without data buffer support. */ ctx.filename = buffer_data->filename; /* Wait until 32 bytes are available. */ ret = buffer->WaitForData( buffer, sizeof(ctx.header) ); if (ret) return ret; /* Read the first 32 bytes. */ buffer->PeekData( buffer, sizeof(ctx.header), 0, ctx.header, NULL ); /* Find a suitable implementation. */ ret = DirectGetInterface( &funcs, "IDirectFBImageProvider", NULL, DirectProbeInterface, &ctx ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBImageProvider ); /* Initialize interface pointers. */ IDirectFBImageProvider_Construct( iface ); /* Construct the interface. */ ret = funcs->Construct( iface, buffer, core, idirectfb ); if (ret) return ret; *ret_interface = iface; return DFB_OK; } ================================================ FILE: src/media/idirectfbimageprovider.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBIMAGEPROVIDER_H__ #define __MEDIA__IDIRECTFBIMAGEPROVIDER_H__ #include /* * probing context */ typedef struct { unsigned char header[32]; const char *filename; } IDirectFBImageProvider_ProbeContext; /* * create (probing) the image provider */ DFBResult IDirectFBImageProvider_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb, IDirectFBImageProvider **ret_interface ); #endif ================================================ FILE: src/media/idirectfbvideoprovider.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include D_DEBUG_DOMAIN( VideoProvider, "IDirectFBVideoProvider", "IDirectFBVideoProvider Interface" ); /**********************************************************************************************************************/ static DirectResult IDirectFBVideoProvider_AddRef( IDirectFBVideoProvider *thiz ) { return DFB_UNIMPLEMENTED; } static DirectResult IDirectFBVideoProvider_Release( IDirectFBVideoProvider *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetCapabilities( IDirectFBVideoProvider *thiz, DFBVideoProviderCapabilities *ret_caps ) { if (!ret_caps) return DFB_INVARG; *ret_caps = DVCAPS_BASIC; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetSurfaceDescription( IDirectFBVideoProvider *thiz, DFBSurfaceDescription *ret_desc ) { if (!ret_desc) return DFB_INVARG; ret_desc->flags = DSDESC_NONE; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetStreamDescription( IDirectFBVideoProvider *thiz, DFBStreamDescription *ret_desc ) { if (!ret_desc) return DFB_INVARG; memset( ret_desc, 0, sizeof(DFBStreamDescription) ); return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_PlayTo( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect, DVFrameCallback callback, void *ctx ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_Stop( IDirectFBVideoProvider *thiz ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetStatus( IDirectFBVideoProvider *thiz, DFBVideoProviderStatus *ret_status ) { if (!ret_status) return DFB_INVARG; *ret_status = DVSTATE_UNKNOWN; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SeekTo( IDirectFBVideoProvider *thiz, double seconds ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetPos( IDirectFBVideoProvider *thiz, double *ret_seconds ) { if (!ret_seconds) return DFB_INVARG; *ret_seconds = 0.0; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetLength( IDirectFBVideoProvider *thiz, double *ret_seconds ) { if (!ret_seconds) return DFB_INVARG; *ret_seconds = 0.0; return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetColorAdjustment( IDirectFBVideoProvider *thiz, DFBColorAdjustment *ret_adj ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetColorAdjustment( IDirectFBVideoProvider *thiz, const DFBColorAdjustment *adj ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SendEvent( IDirectFBVideoProvider *thiz, const DFBEvent *event ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetPlaybackFlags( IDirectFBVideoProvider *thiz, DFBVideoProviderPlaybackFlags flags ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetSpeed( IDirectFBVideoProvider *thiz, double multiplier ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetSpeed( IDirectFBVideoProvider *thiz, double *ret_multiplier ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetVolume( IDirectFBVideoProvider *thiz, float level ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetVolume( IDirectFBVideoProvider *thiz, float *ret_level ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_CreateEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer **ret_interface ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_AttachEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_EnableEvents(IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_DisableEvents(IDirectFBVideoProvider *thiz, DFBVideoProviderEventType mask ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_DetachEventBuffer( IDirectFBVideoProvider *thiz, IDirectFBEventBuffer *buffer ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetBufferOccupancy( IDirectFBVideoProvider *thiz, DFBBufferOccupancy *ret_occ ) { if (!ret_occ) return DFB_INVARG; memset( ret_occ, 0, sizeof(DFBBufferOccupancy) ); return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetBufferThresholds( IDirectFBVideoProvider *thiz, DFBBufferThresholds thresh ) { return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_GetBufferThresholds( IDirectFBVideoProvider *thiz, DFBBufferThresholds *ret_thresh ) { if (!ret_thresh) return DFB_INVARG; memset( ret_thresh, 0, sizeof(DFBBufferThresholds) ); return DFB_UNIMPLEMENTED; } static DFBResult IDirectFBVideoProvider_SetDestination( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, const DFBRectangle *dest_rect ) { return DFB_UNIMPLEMENTED; } static void IDirectFBVideoProvider_Construct( IDirectFBVideoProvider *thiz ) { D_DEBUG_AT( VideoProvider, "%s( %p )\n", __FUNCTION__, thiz ); thiz->AddRef = IDirectFBVideoProvider_AddRef; thiz->Release = IDirectFBVideoProvider_Release; thiz->GetCapabilities = IDirectFBVideoProvider_GetCapabilities; thiz->GetSurfaceDescription = IDirectFBVideoProvider_GetSurfaceDescription; thiz->GetStreamDescription = IDirectFBVideoProvider_GetStreamDescription; thiz->PlayTo = IDirectFBVideoProvider_PlayTo; thiz->Stop = IDirectFBVideoProvider_Stop; thiz->GetStatus = IDirectFBVideoProvider_GetStatus; thiz->SeekTo = IDirectFBVideoProvider_SeekTo; thiz->GetPos = IDirectFBVideoProvider_GetPos; thiz->GetLength = IDirectFBVideoProvider_GetLength; thiz->GetColorAdjustment = IDirectFBVideoProvider_GetColorAdjustment; thiz->SetColorAdjustment = IDirectFBVideoProvider_SetColorAdjustment; thiz->SendEvent = IDirectFBVideoProvider_SendEvent; thiz->SetPlaybackFlags = IDirectFBVideoProvider_SetPlaybackFlags; thiz->SetSpeed = IDirectFBVideoProvider_SetSpeed; thiz->GetSpeed = IDirectFBVideoProvider_GetSpeed; thiz->SetVolume = IDirectFBVideoProvider_SetVolume; thiz->GetVolume = IDirectFBVideoProvider_GetVolume; thiz->CreateEventBuffer = IDirectFBVideoProvider_CreateEventBuffer; thiz->AttachEventBuffer = IDirectFBVideoProvider_AttachEventBuffer; thiz->EnableEvents = IDirectFBVideoProvider_EnableEvents; thiz->DisableEvents = IDirectFBVideoProvider_DisableEvents; thiz->DetachEventBuffer = IDirectFBVideoProvider_DetachEventBuffer; thiz->GetBufferOccupancy = IDirectFBVideoProvider_GetBufferOccupancy; thiz->SetBufferThresholds = IDirectFBVideoProvider_SetBufferThresholds; thiz->GetBufferThresholds = IDirectFBVideoProvider_GetBufferThresholds; thiz->SetDestination = IDirectFBVideoProvider_SetDestination; } DFBResult IDirectFBVideoProvider_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb, IDirectFBVideoProvider **ret_interface ) { DFBResult ret; DirectInterfaceFuncs *funcs = NULL; IDirectFBDataBuffer_data *buffer_data; IDirectFBVideoProvider *iface; IDirectFBVideoProvider_ProbeContext ctx; D_DEBUG_AT( VideoProvider, "%s( %p )\n", __FUNCTION__, buffer ); /* Get the private information of the data buffer. */ buffer_data = buffer->priv; if (!buffer_data) return DFB_DEAD; /* Clear probe context header. */ memset( ctx.header, 0, sizeof(ctx.header) ); /* Provide a fallback for video providers without data buffer support. */ ctx.filename = buffer_data->filename; ctx.buffer = buffer; /* Wait until 64 bytes are available. */ ret = buffer->WaitForData( buffer, sizeof(ctx.header) ); if (ret) return ret; /* Read the first 64 bytes. */ buffer->PeekData( buffer, sizeof(ctx.header), 0, ctx.header, NULL ); /* Find a suitable implementation. */ ret = DirectGetInterface( &funcs, "IDirectFBVideoProvider", NULL, DirectProbeInterface, &ctx ); if (ret) return ret; DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBVideoProvider ); /* Initialize interface pointers. */ IDirectFBVideoProvider_Construct( iface ); /* Construct the interface. */ ret = funcs->Construct( iface, buffer, core, idirectfb ); if (ret) return ret; *ret_interface = iface; return DFB_OK; } ================================================ FILE: src/media/idirectfbvideoprovider.h ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __MEDIA__IDIRECTFBVIDEOPROVIDER_H__ #define __MEDIA__IDIRECTFBVIDEOPROVIDER_H__ #include /* * probing context */ typedef struct { unsigned char header[64]; const char *filename; IDirectFBDataBuffer *buffer; /* useful if provider needs more data for probing */ } IDirectFBVideoProvider_ProbeContext; /* * create (probing) the video provider */ DFBResult IDirectFBVideoProvider_CreateFromBuffer( IDirectFBDataBuffer *buffer, CoreDFB *core, IDirectFB *idirectfb, IDirectFBVideoProvider **ret_interface ); #endif ================================================ FILE: src/meson.build ================================================ # This file is part of DirectFB. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA subdir('core') directfb_sources = [ 'directfb.c', 'directfb_result.c', 'idirectfb.c', 'init.c', 'core/CoreDFB_real.c', 'core/CoreGraphicsState_real.c', 'core/CoreGraphicsStateClient.c', 'core/CoreInputDevice_real.c', 'core/CoreLayer_real.c', 'core/CoreLayerContext_real.c', 'core/CoreLayerRegion_real.c', 'core/CorePalette_real.c', 'core/CoreScreen_real.c', 'core/CoreSlave_real.c', 'core/CoreSurface_real.c', 'core/CoreSurfaceAllocation_real.c', 'core/CoreSurfaceClient_real.c', 'core/CoreWindow_real.c', 'core/CoreWindowStack_real.c', 'core/clipboard.c', 'core/colorhash.c', 'core/core.c', 'core/core_parts.c', 'core/fonts.c', 'core/gfxcard.c', 'core/graphics_state.c', 'core/input.c', directfb_keynames, 'core/layer_context.c', 'core/layer_control.c', 'core/layer_region.c', 'core/layers.c', 'core/palette.c', 'core/prealloc_surface_pool.c', 'core/prealloc_surface_pool_bridge.c', 'core/screen.c', 'core/screens.c', 'core/state.c', 'core/surface.c', 'core/surface_allocation.c', 'core/surface_buffer.c', 'core/surface_client.c', 'core/surface_core.c', 'core/surface_pool.c', 'core/surface_pool_bridge.c', 'core/system.c', 'core/windows.c', 'core/windowstack.c', 'core/wm.c', 'display/idirectfbdisplaylayer.c', 'display/idirectfbpalette.c', 'display/idirectfbscreen.c', 'display/idirectfbsurface.c', 'display/idirectfbsurfaceallocation.c', 'display/idirectfbsurface_layer.c', 'display/idirectfbsurface_window.c', 'gfx/clip.c', 'gfx/convert.c', 'gfx/util.c', 'gfx/generic/generic.c', 'gfx/generic/generic_blit.c', 'gfx/generic/generic_draw_line.c', 'gfx/generic/generic_fill_rectangle.c', 'gfx/generic/generic_stretch_blit.c', 'gfx/generic/generic_texture_triangles.c', 'gfx/generic/generic_util.c', 'input/idirectfbeventbuffer.c', 'input/idirectfbinputdevice.c', 'media/idirectfbdatabuffer.c', 'media/idirectfbdatabuffer_file.c', 'media/idirectfbdatabuffer_memory.c', 'media/idirectfbdatabuffer_streamed.c', 'media/idirectfbfont.c', 'media/idirectfbimageprovider.c', 'media/idirectfbvideoprovider.c', 'misc/conf.c', 'misc/gfx_util.c', 'misc/util.c', directfb_strings, 'windows/idirectfbwindow.c' ] core_headers = [ 'core/CoreGraphicsStateClient.h', 'core/CoreSlave_includes.h', 'core/core.h', 'core/core_resourcemanager.h', 'core/core_system.h', 'core/coredefs.h', 'core/coretypes.h', 'core/fonts.h', 'core/gfxcard.h', 'core/graphics_driver.h', 'core/input.h', 'core/input_driver.h', 'core/layer_context.h', 'core/layer_control.h', 'core/layer_region.h', 'core/layers.h', 'core/palette.h', 'core/screen.h', 'core/screens.h', 'core/state.h', 'core/surface.h', 'core/surface_allocation.h', 'core/surface_buffer.h', 'core/surface_client.h', 'core/surface_pool.h', 'core/surface_pool_bridge.h', 'core/system.h', 'core/video_mode.h', 'core/windows.h', 'core/windowstack.h', 'core/wm.h', 'core/wm_module.h' ] display_headers = [ 'display/idirectfbsurface.h', ] gfx_headers = [ 'gfx/clip.h', 'gfx/convert.h', 'gfx/util.h' ] media_headers = [ 'media/idirectfbdatabuffer.h', 'media/idirectfbfont.h', 'media/idirectfbimageprovider.h', 'media/idirectfbvideoprovider.h' ] misc_headers = [ 'misc/conf.h', 'misc/gfx_util.h', ] if get_option('multi') surface_pool_sources = [ 'core/shared_secure_surface_pool.c', 'core/shared_surface_pool.c' ] else surface_pool_sources = 'core/local_surface_pool.c' endif build_conf = configuration_data() build_conf.set_quoted('DIRECTFB_VERSION_VENDOR', get_option('vendor-version')) build_conf.set10('DFB_SMOOTH_SCALING', get_option('smooth-scaling')) configure_file(configuration: build_conf, output: 'build.h', install: true, install_dir: get_option('includedir') / 'directfb-internal') directfb_private = [] if get_option('default_library') == 'static' directfb_private = 'directfb-gfxdriver directfb-inputdriver directfb-interface directfb-system directfb-wm' endif libdirectfb_private = [] if get_option('default_library') == 'static' and get_option('constructors') libdirectfb_private = '-Wl,-u,__DFB_init_all' endif libdirectfb = library('directfb-@0@.@1@'.format(directfb_major_version, directfb_minor_version), directfb_sources, flux_sources, surface_pool_sources, include_directories: [config_inc, directfb_inc], c_args: ['-DBUILDTIME="' + run_command('date', '-u', '+%Y-%m-%d %H:%M', check: true).stdout().strip() + '"', '-DSYSCONFDIR="' + get_option('prefix') / get_option('sysconfdir') + '"'], build_rpath: get_option('prefix') / get_option('libdir'), dependencies: [direct_dep, fusion_dep], version: '0.@0@.0'.format(directfb_micro_version), install: true, install_rpath: get_option('prefix') / get_option('libdir')) install_symlink('libdirectfb' + libsuffix, pointing_to: 'libdirectfb-@0@.@1@'.format(directfb_major_version, directfb_minor_version) + libsuffix, install_dir: get_option('prefix') / get_option('libdir')) install_headers('idirectfb.h', subdir: 'directfb-internal') install_headers(core_headers, subdir: 'directfb-internal/core') install_headers(display_headers, subdir: 'directfb-internal/display') install_headers(gfx_headers, subdir: 'directfb-internal/gfx') install_headers(media_headers, subdir: 'directfb-internal/media') install_headers(misc_headers, subdir: 'directfb-internal/misc') pkgconfig.generate(filebase: 'directfb', name: 'DirectFB', description: 'Graphics and windowing library in Framebuffer memory', requires: 'direct fusion', requires_private: directfb_private, libraries: '-L${libdir} -ldirectfb', libraries_private: libdirectfb_private, subdirs: 'directfb') pkgconfig.generate(filebase: 'directfb-internal', variables: ['moduledirname=' + moduledirname, 'moduledir=' + moduledir], name: 'DirectFB-internal', description: 'DirectFB internal module infrastructure', requires: 'directfb', subdirs: 'directfb-internal') directfb_dep = declare_dependency(include_directories: directfb_inc, link_with: [libdirectfb, libdirect, libfusion]) ================================================ FILE: src/misc/conf.c ================================================ /* This file is part of DirectFB. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( DirectFB_Config, "DirectFB/Config", "DirectFB Runtime Configuration options" ); /**********************************************************************************************************************/ DFBConfig *dfb_config = NULL; const char *dfb_config_usage = "\n" " --dfb-help Output DirectFB usage information and exit\n" " --dfb: