├── .gitignore ├── Doxyfile.in ├── LICENSE ├── Makefile.am ├── README.md ├── USAGE.md ├── autogen.sh ├── configure.ac ├── include ├── Makefile.am └── allocator │ ├── allocator.h │ ├── common.h │ └── driver.h ├── liballocator.pc.in ├── m4 ├── ax_check_enable_debug.m4 └── ax_search_libs_opt.m4 ├── src ├── Makefile.am ├── allocator.c ├── cJSON │ ├── LICENSE │ ├── cJSON.c │ └── cJSON.h ├── constraint_funcs.c ├── constraint_funcs.h ├── constraints │ ├── address_alignment.c │ ├── lcm.c │ ├── lcm.h │ ├── max_pitch.c │ └── pitch_alignment.c ├── driver_manager.c └── driver_manager.h └── tests ├── Makefile.am ├── capability_set_ops.c ├── create_allocation.c ├── device_alloc.c ├── drm_import_allocation.c ├── test_utils.c └── test_utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | aclocal.m4 2 | autom4te.cache/ 3 | bin/ 4 | config.log 5 | config.status 6 | configure 7 | .deps/ 8 | Doxyfile 9 | doxygen 10 | *.la 11 | liballocator.pc 12 | .libs/ 13 | libtool 14 | *.lo 15 | m4/libtool.m4 16 | m4/lt*.m4 17 | Makefile 18 | Makefile.in 19 | *.o 20 | *.so 21 | *.dirstamp 22 | *.timestamp 23 | tests/capability_merging 24 | tests/device_alloc 25 | tests/create_allocation 26 | tests/capability_set_ops 27 | tests/drm_import_allocation 28 | liballocator-0.0.1.tar.gz 29 | -------------------------------------------------------------------------------- /Doxyfile.in: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.8.6 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | DOXYFILE_ENCODING = UTF-8 7 | PROJECT_NAME = @PACKAGE_NAME@ 8 | PROJECT_NUMBER = @PACKAGE_VERSION@ 9 | PROJECT_BRIEF = 10 | PROJECT_LOGO = 11 | OUTPUT_DIRECTORY = doxygen 12 | CREATE_SUBDIRS = NO 13 | OUTPUT_LANGUAGE = English 14 | BRIEF_MEMBER_DESC = YES 15 | REPEAT_BRIEF = YES 16 | ABBREVIATE_BRIEF = 17 | ALWAYS_DETAILED_SEC = NO 18 | INLINE_INHERITED_MEMB = NO 19 | FULL_PATH_NAMES = YES 20 | STRIP_FROM_PATH = 21 | STRIP_FROM_INC_PATH = 22 | SHORT_NAMES = NO 23 | JAVADOC_AUTOBRIEF = NO 24 | QT_AUTOBRIEF = NO 25 | MULTILINE_CPP_IS_BRIEF = NO 26 | INHERIT_DOCS = YES 27 | SEPARATE_MEMBER_PAGES = NO 28 | TAB_SIZE = 4 29 | ALIASES = 30 | TCL_SUBST = 31 | OPTIMIZE_OUTPUT_FOR_C = NO 32 | OPTIMIZE_OUTPUT_JAVA = NO 33 | OPTIMIZE_FOR_FORTRAN = NO 34 | OPTIMIZE_OUTPUT_VHDL = NO 35 | EXTENSION_MAPPING = 36 | MARKDOWN_SUPPORT = YES 37 | AUTOLINK_SUPPORT = YES 38 | BUILTIN_STL_SUPPORT = NO 39 | CPP_CLI_SUPPORT = NO 40 | SIP_SUPPORT = NO 41 | IDL_PROPERTY_SUPPORT = YES 42 | DISTRIBUTE_GROUP_DOC = NO 43 | SUBGROUPING = YES 44 | INLINE_GROUPED_CLASSES = NO 45 | INLINE_SIMPLE_STRUCTS = NO 46 | TYPEDEF_HIDES_STRUCT = NO 47 | LOOKUP_CACHE_SIZE = 0 48 | #--------------------------------------------------------------------------- 49 | # Build related configuration options 50 | #--------------------------------------------------------------------------- 51 | EXTRACT_ALL = NO 52 | EXTRACT_PRIVATE = NO 53 | EXTRACT_PACKAGE = NO 54 | EXTRACT_STATIC = NO 55 | EXTRACT_LOCAL_CLASSES = YES 56 | EXTRACT_LOCAL_METHODS = NO 57 | EXTRACT_ANON_NSPACES = NO 58 | HIDE_UNDOC_MEMBERS = NO 59 | HIDE_UNDOC_CLASSES = NO 60 | HIDE_FRIEND_COMPOUNDS = NO 61 | HIDE_IN_BODY_DOCS = NO 62 | INTERNAL_DOCS = NO 63 | CASE_SENSE_NAMES = YES 64 | HIDE_SCOPE_NAMES = NO 65 | SHOW_INCLUDE_FILES = YES 66 | SHOW_GROUPED_MEMB_INC = NO 67 | FORCE_LOCAL_INCLUDES = NO 68 | INLINE_INFO = YES 69 | SORT_MEMBER_DOCS = YES 70 | SORT_BRIEF_DOCS = NO 71 | SORT_MEMBERS_CTORS_1ST = NO 72 | SORT_GROUP_NAMES = NO 73 | SORT_BY_SCOPE_NAME = NO 74 | STRICT_PROTO_MATCHING = NO 75 | GENERATE_TODOLIST = YES 76 | GENERATE_TESTLIST = YES 77 | GENERATE_BUGLIST = YES 78 | GENERATE_DEPRECATEDLIST= YES 79 | ENABLED_SECTIONS = 80 | MAX_INITIALIZER_LINES = 30 81 | SHOW_USED_FILES = YES 82 | SHOW_FILES = YES 83 | SHOW_NAMESPACES = YES 84 | FILE_VERSION_FILTER = 85 | LAYOUT_FILE = 86 | CITE_BIB_FILES = 87 | #--------------------------------------------------------------------------- 88 | # Configuration options related to warning and progress messages 89 | #--------------------------------------------------------------------------- 90 | QUIET = NO 91 | WARNINGS = YES 92 | WARN_IF_UNDOCUMENTED = YES 93 | WARN_IF_DOC_ERROR = YES 94 | WARN_NO_PARAMDOC = NO 95 | WARN_FORMAT = "$file:$line: $text" 96 | WARN_LOGFILE = 97 | #--------------------------------------------------------------------------- 98 | # Configuration options related to the input files 99 | #--------------------------------------------------------------------------- 100 | INPUT = @top_srcdir@ 101 | INPUT_ENCODING = UTF-8 102 | FILE_PATTERNS = 103 | RECURSIVE = YES 104 | EXCLUDE = 105 | EXCLUDE_SYMLINKS = NO 106 | EXCLUDE_PATTERNS = 107 | EXCLUDE_SYMBOLS = 108 | EXAMPLE_PATH = 109 | EXAMPLE_PATTERNS = 110 | EXAMPLE_RECURSIVE = NO 111 | IMAGE_PATH = 112 | INPUT_FILTER = 113 | FILTER_PATTERNS = 114 | FILTER_SOURCE_FILES = NO 115 | FILTER_SOURCE_PATTERNS = 116 | USE_MDFILE_AS_MAINPAGE = 117 | #--------------------------------------------------------------------------- 118 | # Configuration options related to source browsing 119 | #--------------------------------------------------------------------------- 120 | SOURCE_BROWSER = NO 121 | INLINE_SOURCES = NO 122 | STRIP_CODE_COMMENTS = YES 123 | REFERENCED_BY_RELATION = NO 124 | REFERENCES_RELATION = NO 125 | REFERENCES_LINK_SOURCE = YES 126 | SOURCE_TOOLTIPS = YES 127 | USE_HTAGS = NO 128 | VERBATIM_HEADERS = YES 129 | #--------------------------------------------------------------------------- 130 | # Configuration options related to the alphabetical class index 131 | #--------------------------------------------------------------------------- 132 | ALPHABETICAL_INDEX = YES 133 | COLS_IN_ALPHA_INDEX = 5 134 | IGNORE_PREFIX = 135 | #--------------------------------------------------------------------------- 136 | # Configuration options related to the HTML output 137 | #--------------------------------------------------------------------------- 138 | GENERATE_HTML = YES 139 | HTML_OUTPUT = html 140 | HTML_FILE_EXTENSION = .html 141 | HTML_HEADER = 142 | HTML_FOOTER = 143 | HTML_STYLESHEET = 144 | HTML_EXTRA_STYLESHEET = 145 | HTML_EXTRA_FILES = 146 | HTML_COLORSTYLE_HUE = 220 147 | HTML_COLORSTYLE_SAT = 100 148 | HTML_COLORSTYLE_GAMMA = 80 149 | HTML_TIMESTAMP = YES 150 | HTML_DYNAMIC_SECTIONS = NO 151 | HTML_INDEX_NUM_ENTRIES = 100 152 | GENERATE_DOCSET = NO 153 | DOCSET_FEEDNAME = "Doxygen generated docs" 154 | DOCSET_BUNDLE_ID = org.doxygen.Project 155 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 156 | DOCSET_PUBLISHER_NAME = Publisher 157 | GENERATE_HTMLHELP = NO 158 | CHM_FILE = 159 | HHC_LOCATION = 160 | GENERATE_CHI = NO 161 | CHM_INDEX_ENCODING = 162 | BINARY_TOC = NO 163 | TOC_EXPAND = NO 164 | GENERATE_QHP = NO 165 | QCH_FILE = 166 | QHP_NAMESPACE = org.doxygen.Project 167 | QHP_VIRTUAL_FOLDER = doc 168 | QHP_CUST_FILTER_NAME = 169 | QHP_CUST_FILTER_ATTRS = 170 | QHP_SECT_FILTER_ATTRS = 171 | QHG_LOCATION = 172 | GENERATE_ECLIPSEHELP = NO 173 | ECLIPSE_DOC_ID = org.doxygen.Project 174 | DISABLE_INDEX = NO 175 | GENERATE_TREEVIEW = NO 176 | ENUM_VALUES_PER_LINE = 4 177 | TREEVIEW_WIDTH = 250 178 | EXT_LINKS_IN_WINDOW = NO 179 | FORMULA_FONTSIZE = 10 180 | FORMULA_TRANSPARENT = YES 181 | USE_MATHJAX = NO 182 | MATHJAX_FORMAT = HTML-CSS 183 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 184 | MATHJAX_EXTENSIONS = 185 | MATHJAX_CODEFILE = 186 | SEARCHENGINE = YES 187 | SERVER_BASED_SEARCH = NO 188 | EXTERNAL_SEARCH = NO 189 | SEARCHENGINE_URL = 190 | SEARCHDATA_FILE = searchdata.xml 191 | EXTERNAL_SEARCH_ID = 192 | EXTRA_SEARCH_MAPPINGS = 193 | #--------------------------------------------------------------------------- 194 | # Configuration options related to the LaTeX output 195 | #--------------------------------------------------------------------------- 196 | GENERATE_LATEX = YES 197 | LATEX_OUTPUT = latex 198 | LATEX_CMD_NAME = latex 199 | MAKEINDEX_CMD_NAME = makeindex 200 | COMPACT_LATEX = NO 201 | PAPER_TYPE = a4 202 | EXTRA_PACKAGES = 203 | LATEX_HEADER = 204 | LATEX_FOOTER = 205 | LATEX_EXTRA_FILES = 206 | PDF_HYPERLINKS = YES 207 | USE_PDFLATEX = YES 208 | LATEX_BATCHMODE = NO 209 | LATEX_HIDE_INDICES = NO 210 | LATEX_SOURCE_CODE = NO 211 | LATEX_BIB_STYLE = plain 212 | #--------------------------------------------------------------------------- 213 | # Configuration options related to the RTF output 214 | #--------------------------------------------------------------------------- 215 | GENERATE_RTF = NO 216 | RTF_OUTPUT = rtf 217 | COMPACT_RTF = NO 218 | RTF_HYPERLINKS = NO 219 | RTF_STYLESHEET_FILE = 220 | RTF_EXTENSIONS_FILE = 221 | #--------------------------------------------------------------------------- 222 | # Configuration options related to the man page output 223 | #--------------------------------------------------------------------------- 224 | GENERATE_MAN = NO 225 | MAN_OUTPUT = man 226 | MAN_EXTENSION = .3 227 | MAN_LINKS = NO 228 | #--------------------------------------------------------------------------- 229 | # Configuration options related to the XML output 230 | #--------------------------------------------------------------------------- 231 | GENERATE_XML = NO 232 | XML_OUTPUT = xml 233 | XML_SCHEMA = 234 | XML_DTD = 235 | XML_PROGRAMLISTING = YES 236 | #--------------------------------------------------------------------------- 237 | # Configuration options related to the DOCBOOK output 238 | #--------------------------------------------------------------------------- 239 | GENERATE_DOCBOOK = NO 240 | DOCBOOK_OUTPUT = docbook 241 | #--------------------------------------------------------------------------- 242 | # Configuration options for the AutoGen Definitions output 243 | #--------------------------------------------------------------------------- 244 | GENERATE_AUTOGEN_DEF = NO 245 | #--------------------------------------------------------------------------- 246 | # Configuration options related to the Perl module output 247 | #--------------------------------------------------------------------------- 248 | GENERATE_PERLMOD = NO 249 | PERLMOD_LATEX = NO 250 | PERLMOD_PRETTY = YES 251 | PERLMOD_MAKEVAR_PREFIX = 252 | #--------------------------------------------------------------------------- 253 | # Configuration options related to the preprocessor 254 | #--------------------------------------------------------------------------- 255 | ENABLE_PREPROCESSING = YES 256 | MACRO_EXPANSION = NO 257 | EXPAND_ONLY_PREDEF = NO 258 | SEARCH_INCLUDES = YES 259 | INCLUDE_PATH = 260 | INCLUDE_FILE_PATTERNS = 261 | PREDEFINED = 262 | EXPAND_AS_DEFINED = 263 | SKIP_FUNCTION_MACROS = YES 264 | #--------------------------------------------------------------------------- 265 | # Configuration options related to external references 266 | #--------------------------------------------------------------------------- 267 | TAGFILES = 268 | GENERATE_TAGFILE = 269 | ALLEXTERNALS = NO 270 | EXTERNAL_GROUPS = YES 271 | EXTERNAL_PAGES = YES 272 | PERL_PATH = /usr/bin/perl 273 | #--------------------------------------------------------------------------- 274 | # Configuration options related to the dot tool 275 | #--------------------------------------------------------------------------- 276 | CLASS_DIAGRAMS = YES 277 | MSCGEN_PATH = 278 | DIA_PATH = 279 | HIDE_UNDOC_RELATIONS = YES 280 | HAVE_DOT = NO 281 | DOT_NUM_THREADS = 0 282 | DOT_FONTNAME = Helvetica 283 | DOT_FONTSIZE = 10 284 | DOT_FONTPATH = 285 | CLASS_GRAPH = YES 286 | COLLABORATION_GRAPH = YES 287 | GROUP_GRAPHS = YES 288 | UML_LOOK = NO 289 | UML_LIMIT_NUM_FIELDS = 10 290 | TEMPLATE_RELATIONS = NO 291 | INCLUDE_GRAPH = YES 292 | INCLUDED_BY_GRAPH = YES 293 | CALL_GRAPH = NO 294 | CALLER_GRAPH = NO 295 | GRAPHICAL_HIERARCHY = YES 296 | DIRECTORY_GRAPH = YES 297 | DOT_IMAGE_FORMAT = png 298 | INTERACTIVE_SVG = NO 299 | DOT_PATH = 300 | DOTFILE_DIRS = 301 | MSCFILE_DIRS = 302 | DIAFILE_DIRS = 303 | DOT_GRAPH_MAX_NODES = 50 304 | MAX_DOT_GRAPH_DEPTH = 0 305 | DOT_TRANSPARENT = NO 306 | DOT_MULTI_TARGETS = YES 307 | GENERATE_LEGEND = YES 308 | DOT_CLEANUP = YES 309 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | SUBDIRS = src include tests 22 | ACLOCAL_AMFLAGS = -I m4 23 | EXTRA_DIST = autogen.sh README.md 24 | 25 | pkgconfigdir = $(libdir)/pkgconfig 26 | pkgconfig_DATA = liballocator.pc 27 | 28 | HEADERS_TO_TEST = \ 29 | allocator/common.h \ 30 | allocator/allocator.h 31 | 32 | LOCAL_TARGETS = test_headers.timestamp 33 | LOCAL_CLEAN = $(top_builddir)/test_headers.timestamp 34 | 35 | test_headers.timestamp: $(add_prefix $(top_srcdir),$(HEADERS_TO_TEST)) 36 | for HEADER in $(HEADERS_TO_TEST); do \ 37 | echo -n '#include "' >> .test.c; \ 38 | echo -n $$HEADER >> .test.c; \ 39 | echo '"' >> .test.c; \ 40 | done 41 | $(CC) -I$(top_srcdir)/include -Wall -Werror -c .test.c -o .test.o 42 | rm .test.o .test.c 43 | echo Timestamp > test_headers.timestamp 44 | 45 | if HAVE_DOXYGEN 46 | LOCAL_TARGETS += doxygen/doxygen.timestamp 47 | LOCAL_CLEAN += $(top_builddir)/doxygen 48 | 49 | doxygen/doxygen.timestamp: 50 | $(DOXYGEN) Doxyfile 51 | echo Timestamp > doxygen/doxygen.timestamp 52 | endif 53 | 54 | all-local: $(LOCAL_TARGETS) 55 | 56 | clean-local: 57 | rm -rf $(LOCAL_CLEAN) 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Unix Device Memory Allocator 2 | ============================ 3 | 4 | This document describes the design of a Unix Device Memory Allocation 5 | library. This repository contains an implementation of an allocator 6 | based on the design outlined in this document. 7 | 8 | **This is a living document.** Please update it as the design of the 9 | allocator code evolves. 10 | 11 | High-Level Design 12 | ----------------- 13 | 14 | The allocator library consists of two separate APIs and corresponding 15 | ABIs: 16 | 17 | 1. An application-facing API and ABI 18 | 19 | 2. A driver/backend/plugin API and ABI 20 | 21 | While the APIs will be similar, if not identical, they serve different 22 | purposes. The application API will be used by clients of the library 23 | to (TODO: [JRJ] This list is incomplete and may contain non-concensus 24 | items): 25 | 26 | 1. Enumerate target devices in the system 27 | 28 | 2. Open target devices. 29 | 30 | 3. Enumerate and filter capabilities and constraints of [open?] target 31 | devices based on asserted and requested usage. 32 | 33 | 4. Sort capabilities based on requested usage. 34 | 35 | 5. Allocate memory (images?) based on usage and a chosen set of 36 | capabilities. 37 | 38 | 6. Export handles for allocated memory that can be shared across 39 | process and API boundaries. 40 | 41 | 7. Import previously exported handles. 42 | 43 | The driver API will handle roughly the same functions, but will be used 44 | only within the allocation library to service requests from the 45 | application API. 46 | 47 | Terms 48 | ----- 49 | 50 | The set of terms below is used throughout this design document and the 51 | allocator implementation: 52 | 53 | * **Device** - A single logical unit within a computer system. 54 | Generally, this will correspond to a single unix device node. A 55 | device may contain mulitple engines or perform multiple functions, 56 | such as graphics processing and display scan out, or it may be 57 | dedicated to a single task such as display scan out or video 58 | encoding. (TODO: [JRJ] Is there a better way to describe what is 59 | intended to be represented by a device? Are there cases not covered 60 | by this description?) 61 | 62 | * **Usage** - Usage is the description of which operations the 63 | application intends to perform on an allocation. These include 64 | "asserted" or "global" usage, such as the width and height of an 65 | image, as well as "requested" or "local" usage such as graphics 66 | rendering, display scan out, or video encoding. Asserted usage 67 | is state that must be supported by all devices an allocation will be 68 | used on. Requested usage may be needed only on particular devices 69 | and the application may specify those devices along with the 70 | requested usage. Generally, words used to name usages will be 71 | verbs, such as "render", "display", and "encode". 72 | 73 | * **Constraint** - Constraints describe limitations of particular 74 | devices for a given set of usage. Examples of common constraints are 75 | image pitch alignment, allocation address alignment, or memory bank 76 | spanning requirements. Generally, constraints are defined using 77 | negative adjectives. These are words that describe what a device can 78 | not do, or the minimum requirements that must be met to use the 79 | device. 80 | 81 | * **Capability** - Capabilities describe properties of an allocation a 82 | device can support for a given set of usage. Examples of capabilities 83 | include image tiling formats such as pitch/linear or device-specific 84 | swizzling and memory compression techniques. In general, capabilities 85 | are defined using positive adjectives. These are words that describe 86 | what a device can do. 87 | 88 | * **Allocation** - A range of memory, its requested usage, and its 89 | chosen capabilities. 90 | 91 | Requirements 92 | ------------ 93 | 94 | * The Usage, Constraint, and Capability data must be serializable such 95 | that it can be shared across process boundaries, building up image 96 | properties across multiple instances of the allocator library. 97 | 98 | Capabilities Set Math 99 | --------------------- 100 | 101 | A description of what it means to construct the union of constraints and 102 | intersection of capabilities. 103 | 104 | A capabilities set is an array of capabilities descriptors (each with one 105 | or more `capabilities_header_t` plus associated payload if any) with a 106 | corresponding `constraint_t` block. For example: 107 | 108 | device A: 109 | ``` 110 | {FOO_TILED(32,64) | FOO_COMPRESSED}, 111 | {FOO_TILED(32,64)}, 112 | {BAR_TILED(16,16)}, 113 | {BASE_LINEAR}, 114 | ``` 115 | which means that device A supports TILED+COMPRESSED, or TILED, or LINEAR. 116 | 117 | device B: 118 | ``` 119 | {BAR_TILED(16,16)}, 120 | {BASE_LINEAR}, 121 | ``` 122 | 123 | intersection: 124 | ``` 125 | {BAR_TILED(16,16)}, union(, ) 126 | {BASE_LINEAR}, union(, ) 127 | ``` 128 | 129 | TODO I guess if we used dataformat, maybe the capabilities block simply 130 | becomes a dataformat block? So a *Capabilities Set* is just a set of 131 | pairs of dataformat block plus corresponding `constraint_t` block? 132 | 133 | Constraint Merging 134 | ------------------ 135 | 136 | Constraint lists are joined by a merge operation. Given two lists of 137 | constraints, merging them results in a new list with at least as many 138 | entries as the longer of the two input lists. If a given constraint, 139 | identified by its name, is in only one of the two original lists, it is 140 | included verbatim in the resulting list. If a constraint appears in 141 | both lists, the two constraint values are merged and only the resulting 142 | constraint is included in the merged list. 143 | 144 | Capability Filtering 145 | -------------------- 146 | 147 | As additive constructs, capability lists are naively merged via 148 | intersection, with one caveat: Any entry in a list can be marked as 149 | "required", meaning if the intersection operation removes it from the 150 | resulting list, the resulting list is invalid and the intersection 151 | operation has failed. 152 | 153 | Capability comparison is also naive. While capabilities themselves are 154 | opaque to the library beyond their header content, the library can 155 | compare the non-header content using memcmp(). Note, however, that the 156 | above-mentioned "required" flag is ignored when comparing capabilities and 157 | set if true in either of the matching capabilities in the resulting list, 158 | since its value should not alter an allocation operation. Because 159 | compilers may introduce padding in structures to account for architectural 160 | alignment requirements or preferences, care must be taken to ensure memcpy- 161 | based comparisons are reliable despite this invisible data. Consequently, 162 | all capability struct allocation should be done using calloc() or an 163 | equivalent function. 164 | 165 | Because capabilities in the list can be arbitrarily culled, all hard 166 | dependencies between capabilities in a given list must be expressible using 167 | the simple "required" flag. 168 | 169 | An alternate design considered was to allow general interdependence between 170 | capabilities in a given list, and allow any two sets of "compatible" 171 | capabilities to be merged into a single list, where compatibility could 172 | be certified by the vendor of either of the two capabilities in 173 | question. This design initially seemed sound and is more powerful and 174 | flexible than the final design. 175 | 176 | Consider the case of two capability sets, one corresponding to a 177 | particular device or engine which enables use of a particular local 178 | cache, and another which corresponds to a separate engine or device 179 | without access to that and hence doesn't include the corresponding 180 | capability. Assuming the device or engine corresponding to the set with 181 | access to the cache is capable of flushing the cache, the lack of 182 | support for that cache in the other set need not disqualify 183 | compatibiliy. However, note the device or engine exposing the cache 184 | capability must take care to include a cache flush when when building a 185 | transition to a usage that involves other engines or other devices not 186 | capable of accessing the cache. 187 | 188 | This ability to match non-identical combined with the ability for 189 | drivers to report vendor-specific capabilities that are opaque to other 190 | vendors further complicates the capability intersection logic. Consider 191 | again the above cache capability. Assume it arises while intersecting 192 | capability sets from two vendors, A and B, where vendor A is the one 193 | reporting the cache capability. Vendor A can trivially succeed 194 | intersecting the cache capability with any other capability, but Vendor 195 | B has no way to know if the opaque capability is compatible with any of 196 | its capabilities. Because of this, each capability comparison must be 197 | broadcast to both vendors. The final result is the logical OR of each 198 | vendor's result. 199 | 200 | Despite it's apparent power, this alternative design proves unworkable 201 | though when considering how an allocation would be realized based on the 202 | resulting capability set. Since the set would potentially contain more 203 | capabilities than any one vendor was familiar with, potentially even 204 | vendor-specific capabilities from multiple vendors, it's not clear any 205 | one vendor would know how to properly create an allocation encompassing 206 | all the requested capabilities. 207 | 208 | A variation of this alternative design is to require exact set matches, 209 | expose properties such as cache capabilities in both sets, and rely on 210 | the transition flushing logic to handle the transition. However, this 211 | is infeasible when the caches are vendor specific, as they likely will 212 | be for all but the special CPU cache special case. It is unlikely 213 | vendor A would know when to include the capability to use vendor B's on- 214 | chip or on-engine cache in its capability sets. 215 | 216 | Another alternative implementation is to simply dispatch intersection to 217 | application-chosen vendors directly, providing them with the sets in 218 | full. This allows tests based on combinations of capabilities rather 219 | than the simple atomic comparisons enabled by the above design. 220 | However, it moves a great deal of complexity form the common code to the 221 | drivers. Additionally, it could ideally be asserted that if such a 222 | combination comparison is necessary to determine compatibility, the 223 | capabilities in question are not in fact distinct atoms and instead 224 | should be combined into one, larger capability object. Whether this 225 | assertion holds up in practice remains to be seen. 226 | 227 | Acknowledgments 228 | ---------------- 229 | 230 | This project includes code from the following projects: 231 | 232 | * **cJSON** - https://github.com/DaveGamble/cJSON 233 | 234 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 235 | 236 | Permission is hereby granted, free of charge, to any person obtaining a copy 237 | of this software and associated documentation files (the "Software"), to deal 238 | in the Software without restriction, including without limitation the rights 239 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 240 | copies of the Software, and to permit persons to whom the Software is 241 | furnished to do so, subject to the following conditions: 242 | 243 | The above copyright notice and this permission notice shall be included in 244 | all copies or substantial portions of the Software. 245 | 246 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 247 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 248 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 249 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 250 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 251 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 252 | THE SOFTWARE. 253 | 254 | * **libglvnd** - https://github.com/NVIDIA/libglvnd 255 | 256 | Copyright (c) 2013, NVIDIA CORPORATION. 257 | 258 | Permission is hereby granted, free of charge, to any person obtaining a 259 | copy of this software and/or associated documentation files (the 260 | "Materials"), to deal in the Materials without restriction, including 261 | without limitation the rights to use, copy, modify, merge, publish, 262 | distribute, sublicense, and/or sell copies of the Materials, and to 263 | permit persons to whom the Materials are furnished to do so, subject to 264 | the following conditions: 265 | 266 | The above copyright notice and this permission notice shall be included 267 | unaltered in all copies or substantial portions of the Materials. 268 | Any additions, deletions, or changes to the original source files 269 | must be clearly indicated in accompanying documentation. 270 | 271 | If only executable code is distributed, then the accompanying 272 | documentation must state that "this software is based in part on the 273 | work of the Khronos Group." 274 | 275 | THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 276 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 277 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 278 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 279 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 280 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 281 | MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 282 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | Example Usage 2 | ============= 3 | 4 | Just wanted to try to capture some thoughts about how the usage of this API 5 | might roughly look. 6 | 7 | Note that we want to take into account scenarios where some processes may not 8 | be permitted to open all devices. For example a client of the display server 9 | running in a sandbox, etc. And we don't want window-system specific IPC 10 | knowledge in "liballoc". 11 | 12 | So each `alloc_dev_t` should be exposed to the user, and logic for 13 | constructing the union of constraints and intersection of capabilities 14 | should be decoupled from `alloc_dev_t`. And of course, constraints/ 15 | capabilities should be easily serializable. 16 | 17 | To keep things simple, a hypothetical example with a camera + display, in 18 | single process but with some comments about where things would be serialized 19 | in a multi-process scenario. 20 | 21 | All error checking omitted for brevity. 22 | 23 | Open Devices 24 | ------------ 25 | 26 | Generally an `alloc_dev_t` represents a single device file or API. In cases 27 | where the underlying device file is not exposed (such as OpenMAX or OpenCL, 28 | or OpenGL when not running on top of gbm) an extension would be required to 29 | retrieve the `alloc_dev_t` from that particular API. 30 | 31 | ``` 32 | alloc_dev_t *display = alloc_dev_create(open("/dev/dri/card0", O_RDWR)); 33 | alloc_dev_t *camera = alloc_dev_create(open("/dev/video0", O_RDWR)); 34 | #ifdef HAVE_ION 35 | /* for systems with ION, it could be used as an optional allocator device: */ 36 | alloc_dev_t *ion = alloc_dev_create(open("/dev/ion", O_RDWR)); 37 | #endif 38 | ``` 39 | 40 | Setup Usage 41 | ----------- 42 | 43 | The `assertion_t` represents global generic properties of the buffer (width, 44 | height, and "external" color format, ie. ignoring tiled/compressed/etc format 45 | modifiers), plus per-device usage structs. 46 | 47 | ``` 48 | assertion_t assertion = { 49 | .width = 1920, 50 | .height = 1080, 51 | .format = NV12, 52 | }; 53 | 54 | usage_t *display_usage = NULL, *camera_usage = NULL; 55 | 56 | usage_add(&display_usage, &(usage_display_t) { 57 | .header = { VENDOR_BASE, USAGE_BASE_DISPLAY, 1 }, 58 | .rotation_types = USAGE_BASE_DISPLAY_ROTATION_0 | USAGE_BASE_DISPLAY_ROTATION_180, 59 | }); 60 | usage_add(&display_usage, &(usage_texture_t) { 61 | .header = { VENDOR_BASE, USAGE_BASE_TEXTURE, 0 }, 62 | }); 63 | 64 | usage_add(&camera_usage, &(user_write_t) { 65 | .header = { VENDOR_BASE, USAGE_BASE_WRITE, 0 }, /* generic usage for device writing to buffer */ 66 | }); 67 | ``` 68 | 69 | Get Device Caps 70 | --------------- 71 | 72 | Get per-device constraints and capabilities for a given usage. 73 | 74 | ``` 75 | capabilities_set_t *display_capabilities, *camera_capabilities; 76 | 77 | alloc_dev_get_caps(display, &assertion, display_usage, &display_capabilites); 78 | alloc_dev_get_caps(camera, &assertion, camera_usage, &camera_capabilites); 79 | ``` 80 | 81 | At this point, if (for example) camera was remote, the `alloc_dev_get_caps()` 82 | call would happen in the remote process and caps sent to the local process. 83 | 84 | Find Common Caps 85 | ---------------- 86 | 87 | If it is possible to share a buffer across various devices, we need to use 88 | the union of all device's constraints, and intersection of all device's 89 | capabilities. 90 | 91 | Note that the helpers to find result caps are common (not provided by device) 92 | and do not require a `alloc_dev_t`, since that may only be available in the 93 | remote process. 94 | 95 | ``` 96 | capabilities_t *result_capabilities = display_capabilities; 97 | 98 | combine_capabilities(&result_capabilities, camera_capabilities); 99 | ``` 100 | 101 | Allocate Buffer 102 | --------------- 103 | 104 | Just try allocating from each device until one succeeds. 105 | 106 | ``` 107 | alloc_bo_t *buf; 108 | 109 | buf = alloc_bo_create(display, &assertion, &result_capabilities); 110 | if (!buf) 111 | buf = alloc_bo_create(camera, &assertion, &result_capabilities); 112 | #ifdef HAVE_ION 113 | if (!buf) 114 | buf = alloc_bo_create(ion, &assertion, &result_capabilities); 115 | #endif 116 | 117 | assert(buf); 118 | ``` 119 | 120 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | srcdir=`dirname "$0"` 4 | test -z "$srcdir" && srcdir=. 5 | 6 | ORIGDIR=`pwd` 7 | cd "$srcdir" 8 | 9 | autoreconf --force --verbose --install || exit 1 10 | cd "$ORIGDIR" || exit $? 11 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl configure.ac 2 | dnl Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.63]) 5 | AC_INIT([liballocator], [0.0.1], [jajones@nvidia.com]) 6 | 7 | AC_CONFIG_AUX_DIR([bin]) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | AC_CANONICAL_SYSTEM 10 | 11 | dnl Add an --enable-debug option 12 | AX_CHECK_ENABLE_DEBUG(no, DEBUG) 13 | 14 | AC_USE_SYSTEM_EXTENSIONS 15 | 16 | AM_INIT_AUTOMAKE([1.11 foreign silent-rules subdir-objects]) 17 | AM_SILENT_RULES([yes]) 18 | 19 | dnl Checks for programs. 20 | AC_PROG_CC 21 | AC_PROG_CC_C99 22 | AC_PROG_INSTALL 23 | AC_PROG_MAKE_SET 24 | AC_PROG_LIBTOOL 25 | AC_CHECK_PROGS([DOXYGEN], [doxygen]) 26 | 27 | if test "x$ac_cv_prog_cc_c99" = xno; then 28 | AC_MSG_ERROR([Building liballocator requires a C99-enabled compiler]) 29 | fi 30 | 31 | AX_SEARCH_LIBS_OPT([floor], [m], [MATH_LIBS], [], [ 32 | AC_MSG_ERROR([unable to find the floor() function]) 33 | ]) 34 | 35 | AX_SEARCH_LIBS_OPT([dlopen], [dl dld], [DL_LIBS], [], [ 36 | AC_MSG_ERROR([unable to find the dlopen() function]) 37 | ]) 38 | 39 | AC_CHECK_FUNC([strdup], [], [ 40 | AC_MSG_ERROR([The function strdup() is required and was not found.]) 41 | ]) 42 | 43 | if test -z "$DOXYGEN"; then 44 | AC_MSG_WARN([Doxygen not found - documentation will not be built]) 45 | fi 46 | AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) 47 | 48 | PKG_CHECK_MODULES(LIBDRM, [libdrm], [have_libdrm="yes"], [have_libdrm="no"]) 49 | if test "x$have_libdrm" != xyes; then 50 | AC_MSG_WARN([libdrm is a hard build-time dependency for some allocator 51 | tests. They will be skipped when building.]) 52 | fi 53 | AM_CONDITIONAL([HAVE_LIBDRM], [test "x$have_libdrm" = xyes]) 54 | 55 | AC_CONFIG_FILES([Makefile 56 | src/Makefile 57 | include/Makefile 58 | tests/Makefile 59 | liballocator.pc]) 60 | AM_COND_IF([HAVE_DOXYGEN], 61 | [AC_CONFIG_FILES([Doxyfile])]) 62 | 63 | AC_OUTPUT 64 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_include_HEADERS = allocator/common.h \ 2 | allocator/allocator.h \ 3 | allocator/driver.h 4 | -------------------------------------------------------------------------------- /include/allocator/allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __ALLOCATOR_ALLOCATOR_H__ 24 | #define __ALLOCATOR_ALLOCATOR_H__ 25 | 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /*! 33 | * \file Allocator constructs specific to allocator clients/applications. 34 | */ 35 | 36 | /*! 37 | * Initialize a device context on the specified device file descriptor. 38 | */ 39 | extern device_t *device_create(int dev_fd); 40 | 41 | /*! 42 | * Tear down a device context returned by dev_create(). 43 | */ 44 | extern void device_destroy(device_t *dev); 45 | 46 | /*! 47 | * Query device capabilities for a given assertion. 48 | * 49 | * The caller is responsible for freeing the memory pointed to by 50 | * : 51 | * 52 | * free_capability_sets(*num_capability_sets, *capability_sets); 53 | */ 54 | extern int device_get_capabilities(device_t *dev, 55 | const assertion_t *assertion, 56 | uint32_t num_uses, 57 | const usage_t *uses, 58 | uint32_t *num_capability_sets, 59 | capability_set_t** capability_sets); 60 | 61 | /*! 62 | * Compute a list of common capabilities by determining the compatible combination 63 | * of two existing capability set lists. 64 | * 65 | * The caller is responsible for freeing the memory pointed to by 66 | * : 67 | * 68 | * free_capability_sets(*num_capability_sets, *capability_sets); 69 | */ 70 | extern int derive_capabilities(uint32_t num_caps0, 71 | const capability_set_t *caps0, 72 | uint32_t num_caps1, 73 | const capability_set_t *caps1, 74 | uint32_t *num_capability_sets, 75 | capability_set_t** capability_sets); 76 | 77 | /*! 78 | * Query device assertion hints for a given usage 79 | * 80 | * Returns both the number of hints and a malloc'ed array of hints 81 | * . 82 | * 83 | * The caller is responsible of freeing the memory pointed by : 84 | * 85 | * free_assertion_hints(*num_hints, *hints); 86 | */ 87 | extern int device_get_assertion_hints(device_t *dev, 88 | uint32_t num_uses, 89 | const usage_t *uses, 90 | uint32_t *num_hints, 91 | assertion_hint_t **hints); 92 | 93 | /*! 94 | * Free an array of assertion hints created by the allocator library 95 | */ 96 | extern void free_assertion_hints(uint32_t num_hints, assertion_hint_t *hints); 97 | 98 | /*! 99 | * Create an allocation conforming to an assertion and capability set on the 100 | * specified device. 101 | */ 102 | extern int device_create_allocation(device_t *dev, 103 | const assertion_t *assertion, 104 | const capability_set_t *capability_set, 105 | allocation_t **allocation); 106 | 107 | /*! 108 | * Destroy an allocation previously created on the specified device. 109 | */ 110 | extern void device_destroy_allocation(device_t *dev, 111 | allocation_t *allocation); 112 | 113 | /*! 114 | * Export an allocation previously created on the specified device. 115 | * 116 | * On success, the caller takes ownership of the file descriptor returned in 117 | * and must free the memory pointed to by : 118 | * 119 | * free(*metadata); 120 | */ 121 | extern int device_export_allocation(device_t *dev, 122 | const allocation_t *allocation, 123 | uint64_t *allocation_size, 124 | size_t *metadata_size, 125 | void **metadata, 126 | int *fd); 127 | 128 | /*! 129 | * Free an array of capability sets created by the allocator library 130 | */ 131 | extern void free_capability_sets(uint32_t num_capability_sets, 132 | capability_set_t *capability_sets); 133 | 134 | /*! 135 | * Serialize a capability set to a stream of raw bytes. 136 | * 137 | * The caller is responsible for freeing the memory pointed to by 138 | * : 139 | * 140 | * free(data); 141 | */ 142 | extern int serialize_capability_set(const capability_set_t *capability_set, 143 | size_t *data_size, 144 | void **data); 145 | 146 | /*! 147 | * Allocate a capability set and populate it from a raw stream of bytes. 148 | * 149 | * The caller is responsible for freeing the memory pointed to by 150 | * : 151 | * 152 | * free_capability_sets(1, *capability_set); 153 | */ 154 | extern int deserialize_capability_set(size_t data_size, 155 | const void *data, 156 | capability_set_t **capability_set); 157 | 158 | #ifdef __cplusplus 159 | } /* extern "C" */ 160 | #endif 161 | 162 | #endif /* __ALLOCATOR_ALLOCATOR_H__ */ 163 | -------------------------------------------------------------------------------- /include/allocator/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __ALLOCATOR_COMMON_H__ 24 | #define __ALLOCATOR_COMMON_H__ 25 | 26 | #include 27 | #include 28 | 29 | /*! TODO: Namespace everything when we settle on a project name (libgbm2?) */ 30 | 31 | /*! 32 | * \file Allocator definitions and declarations shared between the application 33 | * and driver APIs 34 | */ 35 | 36 | /*! 37 | * Vendor IDs 38 | * 39 | * Vendor IDs are used to establish namespaces where device manufacturers and 40 | * driver authors may define vendor-specific extensions and allocation 41 | * properties. The special vendor VENDOR_BASE is used to define a global 42 | * namespace that is expected to be understood by all driver vendors. Vendors 43 | * may reference and parse properties and extensions from eachother's 44 | * namespaces as well, but applications should not rely on such interopation 45 | * in general. 46 | * 47 | * Vendors should register their vendor ID by adding it here. The suggested 48 | * value is the same as the vendor's Vulkan vendor ID if it has one, which is 49 | * generally the vendor's PCI vendor ID or a value of the form 0x0001XXXX 50 | * registered with Khronos. If the vendor does not have a PCI vendor ID or 51 | * a Vulkan vendor ID registered with Khronos, please use the first available 52 | * ID of the form 0xFFFFXXXX. 53 | * 54 | * For clarity, keep the vendor ID list in numerical order. 55 | */ 56 | #define VENDOR_BASE 0x00000000 57 | #define VENDOR_NVIDIA 0x000010DE 58 | #define VENDOR_ARM 0x000013B5 59 | #define VENDOR_INTEL 0x00008086 60 | 61 | /*! 62 | * \defgroup objects 63 | * @{ 64 | */ 65 | 66 | /*! 67 | * An initialized device context. This is the object type against which 68 | * allocation requests can be made. 69 | */ 70 | typedef struct device device_t; 71 | #define DEVICE_NONE ((device_t *)0) 72 | 73 | /*! 74 | * A memory allocation handle. Returned by a successful allocation request. 75 | */ 76 | typedef struct allocation allocation_t; 77 | 78 | /*! 79 | * @} 80 | * End of the objects group 81 | */ 82 | 83 | /*! 84 | * \defgroup constraints 85 | * @{ 86 | */ 87 | 88 | typedef struct constraint { 89 | uint32_t name; 90 | 91 | /*! 92 | * TODO: [JRJ] Is it portable to send unions of this form over the 93 | * wire using a simple memcpy()/write()? 94 | */ 95 | union { 96 | /*! CONSTRAINT_ADDRESS_ALIGNMENT */ 97 | struct { 98 | uint64_t value; 99 | } address_alignment; 100 | 101 | /*! CONSTRAINT_PITCH_ALIGNMENT */ 102 | struct { 103 | uint32_t value; 104 | } pitch_alignment; 105 | 106 | /*! CONSTRAINT_MAX_PITCH */ 107 | struct { 108 | uint32_t value; 109 | } max_pitch; 110 | } u; 111 | } constraint_t; 112 | #define CONSTRAINT_ADDRESS_ALIGNMENT 0x00000000 113 | #define CONSTRAINT_PITCH_ALIGNMENT 0x00000001 114 | #define CONSTRAINT_MAX_PITCH 0x00000002 115 | #define CONSTRAINT_END ((CONSTRAINT_MAX_PITCH) + 1) 116 | 117 | /*! 118 | * @} 119 | * End of the constraint group 120 | */ 121 | 122 | /*! 123 | * Common header for usage and capabilities 124 | */ 125 | typedef struct header { 126 | uint32_t vendor; 127 | uint16_t name; 128 | uint16_t length_in_words; 129 | } header_t; 130 | 131 | /*! 132 | * \defgroup capabilities 133 | * @{ 134 | */ 135 | 136 | /*! 137 | * Capabilities need an additional "required" field so they subclass header_t 138 | * 139 | * Note common_header::length_in_words does not include any bytes in the 140 | * defined header, meaning the "required" field is not included in 141 | * length_in_words. 142 | */ 143 | typedef struct capability_header { 144 | header_t common; 145 | 146 | /*! 147 | * If non-zero, removing this field via capability list intersection causes 148 | * the intersection operation to fail. 149 | */ 150 | int8_t required; 151 | } capability_header_t; 152 | 153 | #define CAPABILITY_LENGTH_IN_WORDS(t) \ 154 | ((sizeof(t) - sizeof(capability_header_t) + sizeof(uint32_t) - 1) / \ 155 | sizeof(uint32_t)) 156 | 157 | /*! 158 | * The ability to represent 2D images using pitch x height pixel layout. 159 | * 160 | * This is a binary capability with no additional properties, so its mere 161 | * presence is sufficient to express it. No additional fields beyond the 162 | * header are needed. 163 | */ 164 | typedef struct capability_pitch_linear { 165 | capability_header_t header; // { VENDOR_BASE, CAP_BASE_PITCH_LINEAR, 0 } 166 | } capability_pitch_linear_t; 167 | #define CAP_BASE_PITCH_LINEAR 0x0000 168 | 169 | /*! 170 | * Capability sets are made up of zero or more constraints and one or more 171 | * capability descriptors 172 | * 173 | * Device capabilities and constraints can not be mixed arbitrarily. For 174 | * example, a device may support pitch linear tiling, proprietary tiling, 175 | * and image compression, but not all independently. Compression may only 176 | * be available when using certain proprietary tiling capabilities. 177 | * Therefore, capabilities must be reported and compared as immutable sets. 178 | * 179 | * Constraints need to be included in capability sets because they may be 180 | * specific to a set of capabilities. For example, a device may have one 181 | * address alignment requirement for pitch linear, but another requirement 182 | * for proprietary tiling. 183 | */ 184 | typedef struct capability_set { 185 | uint32_t num_constraints; 186 | uint32_t num_capabilities; 187 | const constraint_t *constraints; 188 | const capability_header_t *const *capabilities; 189 | } capability_set_t; 190 | 191 | /*! 192 | * @} 193 | * End of the capabilities group 194 | */ 195 | 196 | /*! 197 | * \defgroup usage 198 | * @{ 199 | */ 200 | 201 | typedef struct header usage_header_t; 202 | 203 | #define USAGE_LENGTH_IN_WORDS(t) \ 204 | ((sizeof(t) - sizeof(usage_header_t) + sizeof(uint32_t) - 1) / \ 205 | sizeof(uint32_t)) 206 | 207 | /*! 208 | * Request to support sampling from a 2D image using a GPU's texture units. 209 | */ 210 | typedef struct usage_texture { 211 | usage_header_t header; // { VENDOR_BASE, USAGE_BASE_TEXTURE, 0 } 212 | } usage_texture_t; 213 | #define USAGE_BASE_TEXTURE 0x0000 214 | 215 | /*! 216 | * Request to support displaying a 2D image at the specified rotation. 217 | */ 218 | typedef struct usage_display { 219 | usage_header_t header; // { VENDOR_BASE, USAGE_BASE_DISPLAY, 1 } 220 | uint32_t rotation_types; 221 | } usage_display_t; 222 | #define USAGE_BASE_DISPLAY 0x0001 223 | /* 2 bits to describe rotation */ 224 | #define USAGE_BASE_DISPLAY_ROTATION_0 0x00000000 225 | #define USAGE_BASE_DISPLAY_ROTATION_90 0x00000001 226 | #define USAGE_BASE_DISPLAY_ROTATION_180 0x00000002 227 | #define USAGE_BASE_DISPLAY_ROTATION_270 0x00000003 228 | /* mirror flag */ 229 | #define USAGE_BASE_DISPLAY_MIRROR 0x00000004 230 | 231 | /*! 232 | * Structure to specify a single usage atom. 233 | * 234 | * Usage is always specified relative to a device. If the 235 | * application wishes to specify a usage on all devices, 236 | * it can specify DEVICE_NONE as the device. 237 | */ 238 | typedef struct usage { 239 | device_t *dev; 240 | const usage_header_t *usage; 241 | } usage_t; 242 | 243 | /*! 244 | * @} 245 | * End of the usage group 246 | */ 247 | 248 | /*! 249 | * \defgroup assertions 250 | * @{ 251 | */ 252 | 253 | /*! 254 | * An assertion is the parameters the application supplies when requesting 255 | * a surface allocation, or when requesting capabilities. The parameters 256 | * here are different from requested usage in that they are requirements. 257 | * In other words, it is not expected that the application will retry with 258 | * different values for these parameters if the returned capability set is 259 | * zero, whereas usage is something that is intended to be negotiated via 260 | * several capability requests. As such, these should be kept to a minimum. 261 | */ 262 | typedef struct assertion { 263 | /*! Required surface width */ 264 | uint32_t width; 265 | 266 | /*! Required surface height */ 267 | uint32_t height; 268 | 269 | /*! Required surface pixel format. 270 | * 271 | * TODO: Non-consensus! Decide if this is Khronos data format or fourcc 272 | */ 273 | const uint32_t *format; 274 | 275 | /*! 276 | * To handle extended assertions, define a new structure whose first 277 | * member is a value describing its type, and point to it here. 278 | */ 279 | void *ext; 280 | } assertion_t; 281 | 282 | /*! 283 | * Assertion hints can be queried by applications so that they know what 284 | * assertion values would be supported/recommended for a surface allocation 285 | * given a certain usage. 286 | * 287 | * Depending on the specific assertion value, hints may be presented as a range 288 | * (e.g. max width/height) or a list of supported values (e.g. formats). 289 | * 290 | * Assertion hints are read-only structures 291 | */ 292 | typedef struct assertion_hint { 293 | /*! Surface width limits */ 294 | const uint32_t max_width; 295 | 296 | /*! Surface height limits */ 297 | const uint32_t max_height; 298 | 299 | /*! List of valid surface pixel formats 300 | * 301 | * TODO: Non-consensus! Decide if this is Khronos data format or fourcc 302 | */ 303 | const uint32_t num_formats; 304 | const uint32_t * const formats; 305 | 306 | /*! For extended assertion hints */ 307 | const void * const ext; 308 | } assertion_hint_t; 309 | 310 | /*! 311 | * @} 312 | * End of the assertions group 313 | */ 314 | 315 | #endif /* __ALLOCATOR_COMMON_H__ */ 316 | -------------------------------------------------------------------------------- /include/allocator/driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __ALLOCATOR_DRIVER_H__ 24 | #define __ALLOCATOR_DRIVER_H__ 25 | 26 | #include 27 | 28 | /*! 29 | * Top-level function table exported by drivers. 30 | */ 31 | typedef struct driver { 32 | /*! 33 | * Maximum version of the allocator<->driver interface supported by both 34 | * this driver and the allocation library. 35 | * 36 | * Populated by the allocator library before initializing the driver. The 37 | * driver in turn should set this value to its maximum supported version if 38 | * it is lower than the version set by the allocator library. 39 | */ 40 | unsigned int driver_interface_version; 41 | 42 | /*! 43 | * Private data used by the driver implementation. 44 | * 45 | * Populated by the driver, if needed. This value must never be used by 46 | * the allocation library itself. 47 | */ 48 | void *driver_private; 49 | 50 | /*! 51 | * Handle to the library containing the driver implementation referred to by 52 | * this structure. 53 | * 54 | * Populated by the allocator library. The allocator library will use this 55 | * to unload the library after calling the destructor function. This field 56 | * should generally be ignored by the driver code. 57 | */ 58 | void *lib_handle; 59 | 60 | /*! 61 | * Linked list of initialized drivers. 62 | * 63 | * Populated by the allocator library and used to maintain a list of all 64 | * available drivers. This field should generally be ignored by the driver 65 | * code. 66 | */ 67 | struct driver *next; 68 | 69 | /*! 70 | * Driver destructor function, called by the allocator library before 71 | * unloading a driver. 72 | * 73 | * Populated by the driver. 74 | */ 75 | void (*destroy)(struct driver *driver); 76 | 77 | /*! 78 | * Check whether this driver can initialize a device on the specified 79 | * file descriptor. 80 | * 81 | * Populated by the driver. 82 | * 83 | * \param[in] driver A pointer to this structure. 84 | * 85 | * \param[in] dev_fd A file descriptor referring to a device node. 86 | * 87 | * \return 0 if the file descriptor represents a device supported by 88 | * this driver. -1 if it does not. 89 | */ 90 | int (*is_fd_supported)(struct driver *driver, int dev_fd); 91 | 92 | /*! 93 | * Initialize a device context on the device specified by a file descriptor 94 | * 95 | * Populated by the driver. 96 | * 97 | * \param[in] driver A pointer to this structure. 98 | * 99 | * \param[in] dev_fd A device file descriptor previously verified to be 100 | * compatible with this driver by \ref is_fd_supported. 101 | * 102 | * \return An initialized device context on success. NULL on failure. 103 | */ 104 | device_t *(*device_create_from_fd)(struct driver *driver, int dev_fd); 105 | } driver_t; 106 | 107 | /*! 108 | * Structure representing an initialized device context within the allocator 109 | */ 110 | struct device { 111 | /*! Pointer back to the driver instance that created this device. */ 112 | driver_t *driver; 113 | 114 | /*! 115 | * Private data used by the device's driver implementation. 116 | * 117 | * Populated by the driver. This value must never be used by the 118 | * allocation library itself. 119 | */ 120 | void *device_private; 121 | 122 | /*! 123 | * Device destructor function. Called when the application destroys a 124 | * device object. 125 | * 126 | * Populated by the driver. 127 | */ 128 | void (*destroy)(device_t *dev); 129 | 130 | /*! 131 | * Query the capabilities and constraints of a device for a specified usage. 132 | * 133 | * Populated by the driver. 134 | * 135 | * Given an assertion and a list of uses, return the capabilities, if any, 136 | * this device supports for the requested usage. 137 | */ 138 | int (*get_capabilities)(device_t *dev, 139 | const assertion_t *assertion, 140 | uint32_t num_uses, 141 | const usage_t *uses, 142 | uint32_t *num_capability_sets, 143 | capability_set_t **capability_sets); 144 | 145 | /*! 146 | * Query the assertion hints of a device for a specified usage. 147 | * 148 | * Populated by the driver. 149 | * 150 | * Given a list of uses, return a list of assertion hints, if any, 151 | * this device supports for the requested usage. 152 | */ 153 | int (*get_assertion_hints)(device_t *dev, 154 | uint32_t num_uses, 155 | const usage_t *uses, 156 | uint32_t *num_hints, 157 | assertion_hint_t **hints); 158 | 159 | /*! 160 | * Create an allocation given an assertion and capability set. 161 | * 162 | * Populated by the driver. 163 | * 164 | * Given an assertion and a single capability set, realize an allocation. 165 | * 166 | * The capability set must previously have been retrieved from this device 167 | * using get_capabilities() or be derived from a capability set returned 168 | * from the same function. The capability will no necessarily originate 169 | * from this device instance or library instance. It could have come from 170 | * another process or some other serialized form, but in such cases, it 171 | * must be equivalent to one that could be queried from this driver 172 | * instance. 173 | */ 174 | int (*create_allocation)(device_t *dev, 175 | const assertion_t *assertion, 176 | const capability_set_t *capability_set, 177 | allocation_t **allocation); 178 | 179 | /*! 180 | * Destroy an allocation previously returned by create_allocate(). 181 | * 182 | * Populated by the driver. 183 | */ 184 | void (*destroy_allocation)(device_t *dev, allocation_t *allocation); 185 | 186 | /*! 187 | * Get a file-descriptor handle for an allocation previously returned 188 | * by create_allocation(). 189 | * 190 | * Populated by the driver. 191 | */ 192 | int (*get_allocation_fd)(device_t *dev, 193 | const allocation_t *allocation, 194 | int *fd); 195 | }; 196 | 197 | /*! 198 | * Structure representing a device memory allocation within the allocator 199 | * library and its driver backends. 200 | */ 201 | struct allocation { 202 | /*! 203 | * Private data used by the driver of the device that created the 204 | * allocation. 205 | * 206 | * This value should be populated by the driver if needed, and must never 207 | * be used by the allocation library itself. 208 | */ 209 | void *allocation_private; 210 | 211 | /*! 212 | * The exact capability set used to realize this allocation. Serves as 213 | * metadata describing the allocation properties in an exportable form. 214 | * 215 | * Populated and freed by the allocating driver. 216 | */ 217 | const capability_set_t *capability_set; 218 | 219 | /*! 220 | * Exact size of the allocation. Should include any rounding done by 221 | * vendor kernel or userspace drivers. 222 | * 223 | * Populated by the allocating driver. 224 | */ 225 | uint64_t size; 226 | }; 227 | 228 | /*! 229 | * Top-level driver entry point. 230 | * 231 | * \param[in,out] drv Top-level function table to be initialized by the driver. 232 | * drv->driver_interface_version will be set by the 233 | * allocator library prior to calling this function, and 234 | * the driver should set it to the version it supports if 235 | * that version is less than the version set by the 236 | * allocator library. 237 | * 238 | * \return 0 on success. 239 | */ 240 | typedef int (*driver_init_func_t)(driver_t *drv); 241 | 242 | /*! 243 | * Name of the top-level driver entry point. 244 | */ 245 | #define DRIVER_INIT_FUNC "allocator_driver_init" 246 | 247 | /*! 248 | * Current driver interface version 249 | */ 250 | #define DRIVER_INTERFACE_VERSION 1 251 | 252 | /*! 253 | * Current driver json file major version 254 | */ 255 | #define JSON_FILE_VERSION_MAJOR 1 256 | 257 | /*! 258 | * Current driver json file minor version 259 | */ 260 | #define JSON_FILE_VERSION_MINOR 0 261 | 262 | /*! 263 | * Current driver json file micro version 264 | */ 265 | #define JSON_FILE_VERSION_MICRO 0 266 | 267 | #endif /* __ALLOCATOR_DRIVER_H__ */ 268 | -------------------------------------------------------------------------------- /liballocator.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | includedir=@includedir@ 3 | datarootdir=@datarootdir@ 4 | datadir=@datadir@ 5 | exec_prefix=@exec_prefix@ 6 | libdir=@libdir@ 7 | 8 | Name: liballocator 9 | Description: Generic device-accessible memory allocator 10 | Version: @PACKAGE_VERSION@ 11 | Libs: -L${libdir} -lallocator 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /m4/ax_check_enable_debug.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for the presence of an --enable-debug option to configure, with 12 | # the specified default value used when the option is not present. Return 13 | # the value in the variable $ax_enable_debug. 14 | # 15 | # Specifying 'yes' adds '-g -O0' to the compilation flags for all 16 | # languages. Specifying 'info' adds '-g' to the compilation flags. 17 | # Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to 18 | # the linking flags. Otherwise, nothing is added. 19 | # 20 | # Define the variables listed in the second argument if debug is enabled, 21 | # defaulting to no variables. Defines the variables listed in the third 22 | # argument if debug is disabled, defaulting to NDEBUG. All lists of 23 | # variables should be space-separated. 24 | # 25 | # If debug is not enabled, ensure AC_PROG_* will not add debugging flags. 26 | # Should be invoked prior to any AC_PROG_* compiler checks. 27 | # 28 | # IS-RELEASE can be used to change the default to 'no' when making a 29 | # release. Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it 30 | # uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE 31 | # macro, there is no need to pass this parameter. 32 | # 33 | # AX_IS_RELEASE([git-directory]) 34 | # AX_CHECK_ENABLE_DEBUG() 35 | # 36 | # LICENSE 37 | # 38 | # Copyright (c) 2011 Rhys Ulerich 39 | # Copyright (c) 2014, 2015 Philip Withnall 40 | # 41 | # Copying and distribution of this file, with or without modification, are 42 | # permitted in any medium without royalty provided the copyright notice 43 | # and this notice are preserved. 44 | 45 | #serial 5 46 | 47 | AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[ 48 | AC_BEFORE([$0],[AC_PROG_CC])dnl 49 | AC_BEFORE([$0],[AC_PROG_CXX])dnl 50 | AC_BEFORE([$0],[AC_PROG_F77])dnl 51 | AC_BEFORE([$0],[AC_PROG_FC])dnl 52 | 53 | AC_MSG_CHECKING(whether to enable debugging) 54 | 55 | ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1]))) 56 | ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],, 57 | [$ax_is_release], 58 | [$4]))) 59 | 60 | # If this is a release, override the default. 61 | AS_IF([test "$ax_enable_debug_is_release" = "yes"], 62 | [ax_enable_debug_default="no"]) 63 | 64 | m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))]) 65 | m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))]) 66 | 67 | AC_ARG_ENABLE(debug, 68 | [AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])], 69 | [],enable_debug=$ax_enable_debug_default) 70 | 71 | # empty mean debug yes 72 | AS_IF([test "x$enable_debug" = "x"], 73 | [enable_debug="yes"]) 74 | 75 | # case of debug 76 | AS_CASE([$enable_debug], 77 | [yes],[ 78 | AC_MSG_RESULT(yes) 79 | CFLAGS="${CFLAGS} -g -O0" 80 | CXXFLAGS="${CXXFLAGS} -g -O0" 81 | FFLAGS="${FFLAGS} -g -O0" 82 | FCFLAGS="${FCFLAGS} -g -O0" 83 | OBJCFLAGS="${OBJCFLAGS} -g -O0" 84 | ], 85 | [info],[ 86 | AC_MSG_RESULT(info) 87 | CFLAGS="${CFLAGS} -g" 88 | CXXFLAGS="${CXXFLAGS} -g" 89 | FFLAGS="${FFLAGS} -g" 90 | FCFLAGS="${FCFLAGS} -g" 91 | OBJCFLAGS="${OBJCFLAGS} -g" 92 | ], 93 | [profile],[ 94 | AC_MSG_RESULT(profile) 95 | CFLAGS="${CFLAGS} -g -pg" 96 | CXXFLAGS="${CXXFLAGS} -g -pg" 97 | FFLAGS="${FFLAGS} -g -pg" 98 | FCFLAGS="${FCFLAGS} -g -pg" 99 | OBJCFLAGS="${OBJCFLAGS} -g -pg" 100 | LDFLAGS="${LDFLAGS} -pg" 101 | ], 102 | [ 103 | AC_MSG_RESULT(no) 104 | dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags 105 | dnl by setting any unset environment flag variables 106 | AS_IF([test "x${CFLAGS+set}" != "xset"], 107 | [CFLAGS=""]) 108 | AS_IF([test "x${CXXFLAGS+set}" != "xset"], 109 | [CXXFLAGS=""]) 110 | AS_IF([test "x${FFLAGS+set}" != "xset"], 111 | [FFLAGS=""]) 112 | AS_IF([test "x${FCFLAGS+set}" != "xset"], 113 | [FCFLAGS=""]) 114 | AS_IF([test "x${OBJCFLAGS+set}" != "xset"], 115 | [OBJCFLAGS=""]) 116 | ]) 117 | 118 | dnl Define various variables if debugging is disabled. 119 | dnl assert.h is a NOP if NDEBUG is defined, so define it by default. 120 | AS_IF([test "x$enable_debug" = "xyes"], 121 | [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])], 122 | [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])]) 123 | ax_enable_debug=$enable_debug 124 | ]) 125 | -------------------------------------------------------------------------------- /m4/ax_search_libs_opt.m4: -------------------------------------------------------------------------------- 1 | # SYNOPSIS 2 | # 3 | # AX_SEARCH_LIBS_OPT([function], [libraries-list], [libs-variable], [action-if-found], [action-if-not-found], [extra-libraries]) 4 | # 5 | # DESCRIPTION 6 | # 7 | # Behaves exactly like AC_SEARCH_LIBS except the result is stored in 8 | # "libs-variable" rather than "LIBS" 9 | # 10 | AC_DEFUN([AX_SEARCH_LIBS_OPT],[ 11 | _ax_old_libs=$LIBS 12 | LIBS=$$3 $LIBS 13 | AC_SEARCH_LIBS([$1], [$2], [$4], [$5], [$6]) 14 | AC_SUBST([$3], $LIBS) 15 | LIBS=$_ax_old_libs 16 | ]) 17 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | lib_LTLIBRARIES = liballocator.la 22 | 23 | liballocator_la_CFLAGS = -I$(top_srcdir)/include 24 | 25 | liballocator_la_LIBADD = $(MATH_LIBS) $(DL_LIBS) 26 | 27 | liballocator_la_SOURCES = allocator.c 28 | liballocator_la_SOURCES += constraint_funcs.c 29 | liballocator_la_SOURCES += constraint_funcs.h 30 | liballocator_la_SOURCES += driver_manager.c 31 | liballocator_la_SOURCES += driver_manager.h 32 | liballocator_la_SOURCES += cJSON/cJSON.c 33 | liballocator_la_SOURCES += cJSON/cJSON.h 34 | liballocator_la_SOURCES += constraints/lcm.c 35 | liballocator_la_SOURCES += constraints/lcm.h 36 | liballocator_la_SOURCES += constraints/address_alignment.c 37 | liballocator_la_SOURCES += constraints/pitch_alignment.c 38 | liballocator_la_SOURCES += constraints/max_pitch.c 39 | -------------------------------------------------------------------------------- /src/allocator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "driver_manager.h" 30 | #include "constraint_funcs.h" 31 | 32 | device_t *device_create(int dev_fd) 33 | { 34 | driver_t *driver = find_driver_for_fd(dev_fd); 35 | 36 | if (!driver) { 37 | return NULL; 38 | } 39 | 40 | return driver->device_create_from_fd(driver, dev_fd); 41 | } 42 | 43 | void device_destroy(device_t *dev) 44 | { 45 | if (dev) { 46 | dev->destroy(dev); 47 | } 48 | } 49 | 50 | int device_get_capabilities(device_t *dev, 51 | const assertion_t *assert, 52 | uint32_t num_uses, 53 | const usage_t *uses, 54 | uint32_t *num_capability_sets, 55 | capability_set_t **capability_sets) 56 | { 57 | return dev->get_capabilities(dev, 58 | assert, 59 | num_uses, 60 | uses, 61 | num_capability_sets, 62 | capability_sets); 63 | } 64 | 65 | #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0])) 66 | 67 | /*! 68 | * Merge two lists of constraints. 69 | * 70 | * Entries in only one of the two original lists are included verbatim in the 71 | * merged list. 72 | * 73 | * If the two lists each contain a given constraint name, the two values for 74 | * that constraint itself are merged and the result is included in the merged 75 | * list. 76 | * 77 | * This will allocate and return memory in *new_constraints. The caller is 78 | * responsible for freeing this memory using free(). 79 | */ 80 | static int merge_constraints(uint32_t num_constraints0, 81 | const constraint_t *constraints0, 82 | uint32_t num_constraints1, 83 | const constraint_t *constraints1, 84 | uint32_t *num_new_constraints, 85 | constraint_t **new_constraints) 86 | { 87 | int res; 88 | uint32_t i, j, k, common_constraints; 89 | 90 | *new_constraints = calloc(num_constraints0, sizeof((*new_constraints)[0])); 91 | 92 | if (!*new_constraints) { 93 | return -1; 94 | } 95 | 96 | common_constraints = 0; 97 | k = 0; 98 | 99 | for (i = 0; i < num_constraints0; i++) { 100 | for (j = 0; j < num_constraints1; j++) { 101 | if (constraints0[i].name == constraints1[j].name) { 102 | if (constraints0[i].name >= 103 | ARRAY_LEN(constraint_merge_func_table)) { 104 | return -1; 105 | } 106 | 107 | res = constraint_merge_func_table[constraints0[i].name]( 108 | &constraints0[i], 109 | &constraints1[j], 110 | &(*new_constraints)[k++]); 111 | 112 | if (res) { 113 | free(*new_constraints); 114 | return res; 115 | } 116 | 117 | common_constraints++; 118 | 119 | break; 120 | } 121 | } 122 | 123 | if (j == num_constraints1) { 124 | memcpy(&(*new_constraints)[k++], &constraints0[i], 125 | sizeof(constraints0[i])); 126 | } 127 | } 128 | 129 | assert(k == num_constraints0); 130 | assert(common_constraints <= num_constraints0); 131 | 132 | *num_new_constraints = k + num_constraints1 - common_constraints; 133 | 134 | if (*num_new_constraints != num_constraints0) { 135 | constraint_t *tmp_constraints = 136 | realloc(*new_constraints, 137 | sizeof((*new_constraints)[0]) * *num_new_constraints); 138 | 139 | if (!tmp_constraints) { 140 | free(*new_constraints); 141 | return -1; 142 | } 143 | 144 | *new_constraints = tmp_constraints; 145 | 146 | for (j = 0; j < num_constraints1; j++) { 147 | for (i = 0; i < num_constraints0; i++) { 148 | if (constraints1[j].name == constraints0[i].name) { 149 | break; 150 | } 151 | } 152 | 153 | if (i == num_constraints0) { 154 | memcpy(&(*new_constraints)[k++], &constraints1[j], 155 | sizeof(constraints1[j])); 156 | } 157 | } 158 | } 159 | 160 | assert(*num_new_constraints == k); 161 | 162 | return 0; 163 | } 164 | 165 | /*! 166 | * Compare two individual capabilities for equivalence. 167 | */ 168 | static int compare_capabilities(const capability_header_t *cap0, 169 | const capability_header_t *cap1) 170 | { 171 | int diff = (int)cap0->common.length_in_words - 172 | (int)cap1->common.length_in_words; 173 | 174 | if (diff != 0) { 175 | return diff; 176 | } 177 | 178 | /* 179 | * Compare the header manually, so the "required" field can be ignored. 180 | * 181 | * TODO: Is ignoring the required field necessary and desirable? 182 | */ 183 | diff = memcmp(&cap0->common, 184 | &cap1->common, 185 | sizeof(cap0->common)); 186 | 187 | if (diff != 0) { 188 | return diff; 189 | } 190 | 191 | /* 192 | * This works as long as no uninitialized padding data exists in the 193 | * structs. To ensure that, all capability headers * and their tail 194 | * data need to be allocated using calloc. 195 | */ 196 | return memcmp(&cap0[1], 197 | &cap1[1], 198 | cap0->common.length_in_words * sizeof(uint32_t)); 199 | } 200 | 201 | /*! 202 | * Helper function to deep-free an array of capabilities. 203 | */ 204 | static void free_capabilities(uint32_t num_caps, capability_header_t **caps) 205 | { 206 | uint32_t i; 207 | 208 | for (i = 0; i < num_caps; i++) { 209 | free(caps[i]); 210 | } 211 | 212 | free(caps); 213 | } 214 | 215 | /*! 216 | * Generate the intersection of two lists of capabilities. 217 | * 218 | * Each capability can be included at most once in a given capability list. 219 | * 220 | * If a capability exist in only one of the two original lists, it will not be 221 | * included in the final list. 222 | * 223 | * If a capability name exists in both lists but the two capabilities are not 224 | * equivalent, they will not be included in the final list. There is no merging 225 | * or intersecting of capability values. 226 | * 227 | * Capability lists are unordered. Culling a capability marked as required 228 | * invalidates the list, causing the intersection operation to fail. 229 | * 230 | * This will allocate and return memory in *new_capabilities. The caller is 231 | * responsible for freeing this memory using free(). 232 | */ 233 | static int intersect_capabilities(uint32_t num_caps0, 234 | const capability_header_t *const *caps0, 235 | uint32_t num_caps1, 236 | const capability_header_t *const *caps1, 237 | uint32_t *num_new_capabilities, 238 | capability_header_t ***new_capabilities) 239 | { 240 | const uint32_t max_new_caps = num_caps0 > num_caps1 ? num_caps1 : num_caps0; 241 | int *matched_caps1 = NULL; 242 | capability_header_t **new_caps = NULL; 243 | uint32_t num_new_caps = 0; 244 | uint32_t i0, i1; 245 | 246 | 247 | if ((num_caps0 < 1) || (num_caps1 < 1)) { 248 | return -1; 249 | } 250 | 251 | new_caps = (capability_header_t **)calloc(max_new_caps, 252 | sizeof(capability_header_t *)); 253 | matched_caps1 = calloc(num_caps1, sizeof(*matched_caps1)); 254 | 255 | if (!new_caps || !matched_caps1) { 256 | free(new_caps); 257 | free(matched_caps1); 258 | return -1; 259 | } 260 | 261 | for (uint32_t i0 = 0; i0 < num_caps0; i0++) { 262 | int required = 0; 263 | 264 | for (i1 = 0; i1 < num_caps1; i1++) { 265 | if (compare_capabilities(caps0[i0], caps1[i1])) { 266 | continue; 267 | } else { 268 | /* Capabilities should never be duplicated in either list */ 269 | assert(matched_caps1[i1] == 0); 270 | matched_caps1[i1] = 1; 271 | required = caps1[i1]->required; 272 | break; 273 | } 274 | } 275 | 276 | if (i1 < num_caps1) { 277 | /* 278 | * An equivalent capability was found. Include this capability in 279 | * the new list. 280 | */ 281 | size_t cap_size = sizeof(*caps0[i0]) + 282 | caps0[i0]->common.length_in_words * sizeof(uint32_t); 283 | 284 | new_caps[num_new_caps] = (capability_header_t *)calloc(1, cap_size); 285 | 286 | if (!new_caps[num_new_caps]) { 287 | free_capabilities(num_new_caps, new_caps); 288 | free(matched_caps1); 289 | return -1; 290 | } 291 | 292 | memcpy(new_caps[num_new_caps], caps0[i0], cap_size); 293 | new_caps[num_new_caps++]->required |= required; 294 | } else if (caps0[i0]->required) { 295 | free_capabilities(num_new_caps, new_caps); 296 | free(matched_caps1); 297 | 298 | return -1; 299 | } 300 | } 301 | 302 | for (i1 = 0; i1 < num_caps1; i1++) { 303 | if ((matched_caps1[i1] == 0) && caps1[i1]->required) { 304 | /* 305 | * A required capability from caps1 was not included in the 306 | * intersected list. The resulting list is therefore invalid from 307 | * the point of view of the generator of the list caps1, so the 308 | * intersection fails. 309 | */ 310 | free_capabilities(num_new_caps, new_caps); 311 | free(matched_caps1); 312 | return -1; 313 | } 314 | } 315 | 316 | assert(num_new_caps >= 1); 317 | assert(num_new_caps <= max_new_caps); 318 | 319 | *new_capabilities = 320 | (capability_header_t **)realloc(new_caps, 321 | num_new_caps * 322 | sizeof(capability_header_t *)); 323 | 324 | if (!*new_capabilities) { 325 | /* 326 | * Shrinking an allocation shouldn't fail, but if it somehow does just 327 | * return the existing, slightly larger than necessary allocation. 328 | */ 329 | *new_capabilities = new_caps; 330 | } 331 | 332 | *num_new_capabilities = num_new_caps; 333 | 334 | free(matched_caps1); 335 | 336 | return 0; 337 | } 338 | 339 | /*! 340 | * Given two lists of capability sets, find the subset of compatible sets. 341 | * 342 | * Capability sets are only partially mutable. This function attempts to 343 | * merge each capability set in caps0[] against each capability set in 344 | * caps1[] by merging the two sets' constraints and intersecting their 345 | * capabilities. Constraint list and capability list merging is defined 346 | * by the helper functions \ref merge_constraints() and 347 | * \ref intersect_capabilities(). 348 | * 349 | * This function will allocate new memory to store a list of capability 350 | * sets and return it in *capability_sets, and the capability sets 351 | * themselves will be allocated as well. It is the callers responsibility 352 | * to free this memory using free(). 353 | */ 354 | int derive_capabilities(uint32_t num_caps0, 355 | const capability_set_t *caps0, 356 | uint32_t num_caps1, 357 | const capability_set_t *caps1, 358 | uint32_t *num_capability_sets, 359 | capability_set_t **capability_sets) 360 | { 361 | uint32_t num_new_capability_sets = 0; 362 | capability_set_t *new_capability_sets = NULL; 363 | 364 | // 1) Filter based on compatible constraints. 365 | // 2) Remove capability sets with any incompatible capabilities 366 | // 3) Return the resulting capability set. 367 | 368 | for (uint32_t i0 = 0; i0 < num_caps0; i0++) { 369 | for (uint32_t i1 = 0; i1 < num_caps1; i1++) { 370 | uint32_t num_new_constraints; 371 | constraint_t *new_constraints; 372 | uint32_t num_new_capabilities; 373 | capability_header_t **new_capabilities; 374 | capability_set_t *temp_caps; 375 | 376 | if (merge_constraints(caps0[i0].num_constraints, 377 | caps0[i0].constraints, 378 | caps1[i1].num_constraints, 379 | caps1[i1].constraints, 380 | &num_new_constraints, 381 | &new_constraints)) { 382 | continue; 383 | } 384 | 385 | if (intersect_capabilities(caps0[i0].num_capabilities, 386 | caps0[i0].capabilities, 387 | caps1[i1].num_capabilities, 388 | caps1[i1].capabilities, 389 | &num_new_capabilities, 390 | &new_capabilities)) { 391 | continue; 392 | } 393 | 394 | temp_caps = realloc(new_capability_sets, 395 | sizeof(*new_capability_sets) * 396 | (num_new_capability_sets + 1)); 397 | 398 | if (!temp_caps) { 399 | free(new_capability_sets); 400 | free(new_constraints); 401 | free(new_capabilities); 402 | return -1; 403 | } 404 | 405 | new_capability_sets = temp_caps; 406 | new_capability_sets[num_new_capability_sets].num_constraints = 407 | num_new_constraints; 408 | new_capability_sets[num_new_capability_sets].constraints = 409 | new_constraints; 410 | new_capability_sets[num_new_capability_sets].num_capabilities = 411 | num_new_capabilities; 412 | new_capability_sets[num_new_capability_sets].capabilities = 413 | (const capability_header_t *const *)new_capabilities; 414 | num_new_capability_sets++; 415 | } 416 | } 417 | 418 | *num_capability_sets = num_new_capability_sets; 419 | *capability_sets = new_capability_sets; 420 | 421 | return 0; 422 | } 423 | 424 | /*! 425 | * Given a list of uses, returns a list of assertion hints. 426 | * 427 | * An application can use the returned hints to tweak its requirements to fall 428 | * within valid and supported ranges. 429 | * 430 | * This function will allocate new memory to store a list of assertion hints and 431 | * return it in *hints. It is the callers responsibility to free this memory 432 | * using free(). 433 | */ 434 | int device_get_assertion_hints(device_t *dev, 435 | uint32_t num_uses, 436 | const usage_t *uses, 437 | uint32_t *num_hints, 438 | assertion_hint_t **hints) 439 | { 440 | return dev->get_assertion_hints(dev, 441 | num_uses, 442 | uses, 443 | num_hints, 444 | hints); 445 | } 446 | 447 | void free_assertion_hints(uint32_t num_hints, assertion_hint_t *hints) 448 | { 449 | uint32_t h; 450 | 451 | for (h = 0; h < num_hints; h++) { 452 | free((void *)hints[h].formats); 453 | } 454 | 455 | free(hints); 456 | } 457 | 458 | int device_create_allocation(device_t *dev, 459 | const assertion_t *assertion, 460 | const capability_set_t *capability_set, 461 | allocation_t **allocation) 462 | { 463 | return dev->create_allocation(dev, assertion, capability_set, allocation); 464 | } 465 | 466 | void device_destroy_allocation(device_t *dev, allocation_t *allocation) 467 | { 468 | dev->destroy_allocation(dev, allocation); 469 | } 470 | 471 | void free_capability_sets(uint32_t num_capability_sets, 472 | capability_set_t *capability_sets) 473 | { 474 | uint32_t i, j; 475 | 476 | if (capability_sets) { 477 | for (i = 0; i < num_capability_sets; i++) { 478 | if (capability_sets[i].capabilities) { 479 | for (j = 0; j < capability_sets[i].num_capabilities; j++) { 480 | free((void *)capability_sets[i].capabilities[j]); 481 | } 482 | 483 | free((void *)capability_sets[i].capabilities); 484 | } 485 | 486 | free((void *)capability_sets[i].constraints); 487 | } 488 | 489 | free(capability_sets); 490 | } 491 | } 492 | 493 | int serialize_capability_set(const capability_set_t *set, 494 | size_t *data_size, 495 | void **data) 496 | { 497 | size_t size = 0; 498 | unsigned char *d = NULL; 499 | uint32_t i; 500 | 501 | size += sizeof(set->num_constraints); 502 | size += sizeof(set->num_capabilities); 503 | 504 | /* constraints are fixed-size objects */ 505 | size += set->num_constraints * sizeof(set->constraints[0]); 506 | 507 | for (i = 0; i < set->num_capabilities; i++) { 508 | /* length_in_words does not include the size of the capability header */ 509 | size += sizeof(*set->capabilities[i]); 510 | 511 | /* Add in the size of the post-header capability content. */ 512 | size += set->capabilities[i]->common.length_in_words * sizeof(uint32_t); 513 | } 514 | 515 | d = malloc(size); 516 | 517 | if (!d) { 518 | return -1; 519 | } 520 | 521 | *data = d; 522 | *data_size = size; 523 | 524 | #define SERIALIZE(src, len) \ 525 | assert(((d + (len)) - (unsigned char *)*data) <= size); \ 526 | memcpy(d, (src), (len)); \ 527 | d += (len) 528 | 529 | SERIALIZE(&set->num_constraints, sizeof(set->num_constraints)); 530 | SERIALIZE(&set->num_capabilities, sizeof(set->num_capabilities)); 531 | for (i = 0; i < set->num_constraints; i++) { 532 | SERIALIZE(&set->constraints[i], sizeof(set->constraints[i])); 533 | } 534 | 535 | for (i = 0; i < set->num_capabilities; i++) { 536 | size_t cap_size = sizeof(*set->capabilities[i]) + 537 | set->capabilities[i]->common.length_in_words * sizeof(uint32_t); 538 | 539 | SERIALIZE(set->capabilities[i], cap_size); 540 | } 541 | 542 | #undef SERIALIZE 543 | 544 | return 0; 545 | } 546 | 547 | int deserialize_capability_set(size_t data_size, 548 | const void *data, 549 | capability_set_t **capability_set) 550 | { 551 | const unsigned char *d = data; 552 | constraint_t *constraints = NULL; 553 | capability_header_t **capabilities = NULL; 554 | uint32_t i; 555 | 556 | capability_set_t *set = calloc(1, sizeof(capability_set_t)); 557 | 558 | if (!set) { 559 | goto fail; 560 | } 561 | 562 | #define PEEK_DESERIALIZE(dst, size) \ 563 | if (((d + size) - (const unsigned char *)data) > data_size) goto fail; \ 564 | memcpy((dst), d, (size)) 565 | 566 | #define DESERIALIZE(dst, size) \ 567 | PEEK_DESERIALIZE((dst), (size)); \ 568 | d += (size) 569 | 570 | DESERIALIZE(&set->num_constraints, sizeof(set->num_constraints)); 571 | DESERIALIZE(&set->num_capabilities, sizeof(set->num_capabilities)); 572 | 573 | set->constraints = constraints = 574 | calloc(set->num_constraints, sizeof(*set->constraints)); 575 | capabilities = calloc(set->num_capabilities, sizeof(*capabilities)); 576 | set->capabilities = (const capability_header_t *const *)capabilities; 577 | 578 | if (!constraints || !capabilities) { 579 | goto fail; 580 | } 581 | 582 | for (i = 0; i < set->num_constraints; i++) { 583 | DESERIALIZE(&constraints[i], sizeof(set->constraints[i])); 584 | } 585 | 586 | for (i = 0; i < set->num_capabilities; i++) { 587 | capability_header_t header; 588 | 589 | PEEK_DESERIALIZE(&header, sizeof(header)); 590 | 591 | capabilities[i] = calloc(1, sizeof(header) + 592 | header.common.length_in_words * 593 | sizeof(uint32_t)); 594 | 595 | if (!capabilities[i]) { 596 | goto fail; 597 | } 598 | 599 | DESERIALIZE(capabilities[i], sizeof(*capabilities[i]) + 600 | header.common.length_in_words * sizeof(uint32_t)); 601 | } 602 | 603 | #undef DESERIALIZE 604 | #undef PEEK_DESERIALIZE 605 | 606 | set->constraints = constraints; 607 | set->capabilities = (const capability_header_t *const *)capabilities; 608 | *capability_set = set; 609 | 610 | return 0; 611 | 612 | fail: 613 | free_capability_sets(1, set); 614 | 615 | return -1; 616 | } 617 | 618 | int device_export_allocation(device_t *dev, 619 | const allocation_t *allocation, 620 | uint64_t *allocation_size, 621 | size_t *metadata_size, 622 | void **metadata, 623 | int *fd) 624 | { 625 | int status = serialize_capability_set(allocation->capability_set, 626 | metadata_size, 627 | metadata); 628 | 629 | if (status) { 630 | return status; 631 | } 632 | 633 | *allocation_size = allocation->size; 634 | 635 | return dev->get_allocation_fd(dev, allocation, fd); 636 | } 637 | -------------------------------------------------------------------------------- /src/cJSON/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /src/cJSON/cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* project version */ 32 | #define CJSON_VERSION_MAJOR 1 33 | #define CJSON_VERSION_MINOR 5 34 | #define CJSON_VERSION_PATCH 7 35 | 36 | #include 37 | 38 | /* cJSON Types: */ 39 | #define cJSON_Invalid (0) 40 | #define cJSON_False (1 << 0) 41 | #define cJSON_True (1 << 1) 42 | #define cJSON_NULL (1 << 2) 43 | #define cJSON_Number (1 << 3) 44 | #define cJSON_String (1 << 4) 45 | #define cJSON_Array (1 << 5) 46 | #define cJSON_Object (1 << 6) 47 | #define cJSON_Raw (1 << 7) /* raw json */ 48 | 49 | #define cJSON_IsReference 256 50 | #define cJSON_StringIsConst 512 51 | 52 | /* The cJSON structure: */ 53 | typedef struct cJSON 54 | { 55 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 56 | struct cJSON *next; 57 | struct cJSON *prev; 58 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 59 | struct cJSON *child; 60 | 61 | /* The type of the item, as above. */ 62 | int type; 63 | 64 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 65 | char *valuestring; 66 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 67 | int valueint; 68 | /* The item's number, if type==cJSON_Number */ 69 | double valuedouble; 70 | 71 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 72 | char *string; 73 | } cJSON; 74 | 75 | typedef struct cJSON_Hooks 76 | { 77 | void *(*malloc_fn)(size_t sz); 78 | void (*free_fn)(void *ptr); 79 | } cJSON_Hooks; 80 | 81 | typedef int cJSON_bool; 82 | 83 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 84 | #define __WINDOWS__ 85 | #endif 86 | #ifdef __WINDOWS__ 87 | 88 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: 89 | 90 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 91 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 92 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 93 | 94 | For *nix builds that support visibility attribute, you can define similar behavior by 95 | 96 | setting default visibility to hidden by adding 97 | -fvisibility=hidden (for gcc) 98 | or 99 | -xldscope=hidden (for sun cc) 100 | to CFLAGS 101 | 102 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 103 | 104 | */ 105 | 106 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 107 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 108 | #define CJSON_EXPORT_SYMBOLS 109 | #endif 110 | 111 | #if defined(CJSON_HIDE_SYMBOLS) 112 | #define CJSON_PUBLIC(type) type __stdcall 113 | #elif defined(CJSON_EXPORT_SYMBOLS) 114 | #define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall 115 | #elif defined(CJSON_IMPORT_SYMBOLS) 116 | #define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall 117 | #endif 118 | #else /* !WIN32 */ 119 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 120 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 121 | #else 122 | #define CJSON_PUBLIC(type) type 123 | #endif 124 | #endif 125 | 126 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 127 | * This is to prevent stack overflows. */ 128 | #ifndef CJSON_NESTING_LIMIT 129 | #define CJSON_NESTING_LIMIT 1000 130 | #endif 131 | 132 | /* returns the version of cJSON as a string */ 133 | CJSON_PUBLIC(const char*) cJSON_Version(void); 134 | 135 | /* Supply malloc, realloc and free functions to cJSON */ 136 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 137 | 138 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 139 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 140 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 141 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 142 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ 143 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 144 | 145 | /* Render a cJSON entity to text for transfer/storage. */ 146 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 147 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 148 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 149 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 150 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 151 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 152 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 153 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 154 | /* Delete a cJSON entity and all subentities. */ 155 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); 156 | 157 | /* Returns the number of items in an array (or object). */ 158 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 159 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 160 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 161 | /* Get item "string" from object. Case insensitive. */ 162 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 163 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 164 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 165 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 166 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 167 | 168 | /* These functions check the type of an item */ 169 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 170 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 171 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 172 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 173 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 175 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 176 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 177 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 178 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 179 | 180 | /* These calls create a cJSON item of the appropriate type. */ 181 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 182 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 183 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 184 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 185 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 186 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 187 | /* raw json */ 188 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 189 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 190 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 191 | 192 | /* These utilities create an Array of count items. */ 193 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 194 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); 197 | 198 | /* Append item to the specified array/object. */ 199 | CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); 200 | CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 201 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 202 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 203 | * writing to `item->string` */ 204 | CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 205 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 206 | CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 207 | CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 208 | 209 | /* Remove/Detatch items from Arrays/Objects. */ 210 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 211 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 212 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 213 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 214 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 215 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 216 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 217 | 218 | /* Update array items. */ 219 | CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 220 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 221 | CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 222 | CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 223 | CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 224 | 225 | /* Duplicate a cJSON item */ 226 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 227 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 228 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 229 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 230 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 231 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 232 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 233 | 234 | 235 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 236 | 237 | /* Macros for creating things quickly. */ 238 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 239 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 240 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 241 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 242 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 243 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 244 | #define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) 245 | 246 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 247 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 248 | /* helper for the cJSON_SetNumberValue macro */ 249 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 250 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 251 | 252 | /* Macro for iterating over an array or object */ 253 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 254 | 255 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 256 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 257 | CJSON_PUBLIC(void) cJSON_free(void *object); 258 | 259 | #ifdef __cplusplus 260 | } 261 | #endif 262 | 263 | #endif 264 | -------------------------------------------------------------------------------- /src/constraint_funcs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "constraint_funcs.h" 24 | 25 | /* XXX This should be auto-generated */ 26 | constraint_merge_func_t constraint_merge_func_table[] = { 27 | &merge_address_alignment, /* CONSTRAINT_ADDRESS_ALIGNMENT */ 28 | &merge_pitch_alignment, /* CONSTRAINT_PITCH_ALIGNMENT */ 29 | &merge_max_pitch, /* CONSTRAINT_MAX_PITCH */ 30 | }; 31 | -------------------------------------------------------------------------------- /src/constraint_funcs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __SRC_CONSTRAINT_FUNCS_H__ 24 | #define __SRC_CONSTRAINT_FUNCS_H__ 25 | 26 | #include 27 | 28 | typedef int (*constraint_merge_func_t)(const constraint_t *a, 29 | const constraint_t *b, 30 | constraint_t *merged); 31 | 32 | extern constraint_merge_func_t constraint_merge_func_table[CONSTRAINT_END]; 33 | 34 | /* XXX The below should be auto-generated */ 35 | 36 | extern int merge_address_alignment(const constraint_t *a, 37 | const constraint_t *b, 38 | constraint_t *merged); 39 | 40 | extern int merge_pitch_alignment(const constraint_t *a, 41 | const constraint_t *b, 42 | constraint_t *merged); 43 | 44 | extern int merge_max_pitch(const constraint_t *a, 45 | const constraint_t *b, 46 | constraint_t *merged); 47 | 48 | #endif /* __SRC_CONSTRAINT_FUNCS_H__ */ 49 | -------------------------------------------------------------------------------- /src/constraints/address_alignment.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "constraint_funcs.h" 24 | #include "lcm.h" 25 | 26 | int merge_address_alignment(const constraint_t *a, 27 | const constraint_t *b, 28 | constraint_t *merged) 29 | { 30 | merged->name = CONSTRAINT_ADDRESS_ALIGNMENT; 31 | merged->u.address_alignment.value = lcm(a->u.address_alignment.value, 32 | b->u.address_alignment.value); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/constraints/lcm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "lcm.h" 24 | 25 | static uint32_t gcd(uint32_t m, uint32_t n) 26 | { 27 | uint32_t temp; 28 | 29 | if (m == n) { 30 | return m; 31 | } 32 | 33 | while (m && n) { 34 | temp = m; 35 | m = m % n; 36 | n = n % temp; 37 | } 38 | 39 | return m + n; 40 | } 41 | 42 | uint32_t lcm(uint32_t m, uint32_t n) 43 | { 44 | return (m * n) / gcd(m, n); 45 | } 46 | -------------------------------------------------------------------------------- /src/constraints/lcm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | extern uint32_t lcm(uint32_t m, uint32_t n); 26 | -------------------------------------------------------------------------------- /src/constraints/max_pitch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "constraint_funcs.h" 24 | 25 | int merge_max_pitch(const constraint_t *a, 26 | const constraint_t *b, 27 | constraint_t *merged) 28 | { 29 | merged->name = CONSTRAINT_MAX_PITCH; 30 | merged->u.max_pitch.value = 31 | a->u.max_pitch.value < b->u.max_pitch.value ? 32 | a->u.max_pitch.value : b->u.max_pitch.value; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/constraints/pitch_alignment.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "constraint_funcs.h" 24 | #include "lcm.h" 25 | 26 | int merge_pitch_alignment(const constraint_t *a, 27 | const constraint_t *b, 28 | constraint_t *merged) 29 | { 30 | merged->name = CONSTRAINT_PITCH_ALIGNMENT; 31 | merged->u.pitch_alignment.value = lcm(a->u.pitch_alignment.value, 32 | b->u.pitch_alignment.value); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/driver_manager.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "driver_manager.h" 37 | #include "cJSON/cJSON.h" 38 | 39 | /*! 40 | * A linked list of all the available driver instances. 41 | * 42 | * TODO Make access to this thread_safe 43 | * TODO Use an existing linked-list implementation instead of open-coding 44 | */ 45 | driver_t *driver_list = NULL; 46 | 47 | /*! Non-zero if driver enumeration & initialization has been run */ 48 | int drivers_initialized = 0; 49 | 50 | /*! 51 | * Run a driver's destructor and unload its library. 52 | * 53 | * \param[in] driver A pointer to a driver instance. 54 | */ 55 | static void remove_one_driver(driver_t *driver) 56 | { 57 | if (driver) { 58 | for (driver_t **d = &driver_list; *d; d = &(*d)->next) { 59 | if (*d == driver) { 60 | *d = driver->next; 61 | break; 62 | } 63 | } 64 | 65 | if (driver->destroy) { 66 | driver->destroy(driver); 67 | } 68 | 69 | if (driver->lib_handle) { 70 | dlclose(driver->lib_handle); 71 | } 72 | 73 | free(driver); 74 | } 75 | } 76 | 77 | /*! 78 | * Load and initialize one driver library. 79 | * 80 | * \param[in] driver_file The driver library file name. 81 | * 82 | * \return 0 on success, -1 on failure. 83 | * 84 | * TODO Need to define error propagation policy. Should this and other 85 | * functions return a more detailed error code and/or set errno? 86 | */ 87 | static int add_one_driver(const char *driver_file) 88 | { 89 | driver_init_func_t driver_init_func; 90 | driver_t *driver = calloc(1, sizeof(driver_t)); 91 | driver_t **d; 92 | int ret = 0; 93 | 94 | if (!driver) { 95 | ret = -1; 96 | goto done; 97 | } 98 | 99 | driver->driver_interface_version = DRIVER_INTERFACE_VERSION; 100 | 101 | driver->lib_handle = dlopen(driver_file, RTLD_LAZY); 102 | 103 | if (!driver->lib_handle) { 104 | ret = -1; 105 | goto done; 106 | } 107 | 108 | driver_init_func = (driver_init_func_t)dlsym(driver->lib_handle, 109 | DRIVER_INIT_FUNC); 110 | 111 | if (!driver_init_func) { 112 | ret = -1; 113 | goto done; 114 | } 115 | 116 | if (driver_init_func(driver) < 0) { 117 | ret = -1; 118 | goto done; 119 | } 120 | 121 | /* 122 | * The intention is that the allocator library be both backwards and 123 | * forwards compatible, so this logic should change once a stable ABI 124 | * is declared. For now, there's no way to be compatible with a prior 125 | * version because this code is the first version of the driver 126 | * interface. 127 | */ 128 | if (driver->driver_interface_version < DRIVER_INTERFACE_VERSION) { 129 | ret = -1; 130 | goto done; 131 | } 132 | 133 | if (!driver->is_fd_supported || 134 | !driver->device_create_from_fd) { 135 | ret = -1; 136 | goto done; 137 | } 138 | 139 | /* 140 | * Because the ordering of drivers affects system behavior, the driver needs 141 | * to be appended rather than prepended to the list to preserve the 142 | * configuration directory sort order. 143 | */ 144 | for (d = &driver_list; *d; d = &(*d)->next); 145 | *d = driver; 146 | 147 | done: 148 | if (ret < 0) { 149 | remove_one_driver(driver); 150 | } 151 | 152 | return ret; 153 | } 154 | 155 | static int check_json_format_version(const char *version_string) 156 | { 157 | int major; 158 | int minor; 159 | int micro; 160 | int length; 161 | 162 | major = minor = micro = -1; 163 | length = sscanf(version_string, "%d.%d.%d", &major, &minor, µ); 164 | 165 | /* A major version must be specified */ 166 | if (length < 1) { 167 | return -1; 168 | } 169 | 170 | if (length < 2) { 171 | minor = 0; 172 | } 173 | 174 | if (length < 3) { 175 | micro = 0; 176 | } 177 | 178 | if (major != JSON_FILE_VERSION_MAJOR) { 179 | return -1; 180 | } 181 | 182 | if (minor > JSON_FILE_VERSION_MINOR) { 183 | return -1; 184 | } 185 | 186 | return 0; 187 | } 188 | 189 | /*! 190 | * Load and initialize the driver defined by a single JSON driver config file. 191 | * 192 | * \param[in] driver_json_file A driver JSON config file. 193 | * 194 | * \return 0 on success, -1 on failure. 195 | */ 196 | static int add_one_driver_from_config(const char *driver_json_file) 197 | { 198 | int ret = 0; 199 | char *file_buf = NULL; 200 | cJSON *json_root = NULL; 201 | cJSON *format_node; 202 | cJSON *driver_node; 203 | cJSON *driver_path_node; 204 | struct stat stats; 205 | FILE *fp = fopen(driver_json_file, "r"); 206 | 207 | if (!fp) { 208 | ret = -1; 209 | goto done; 210 | } 211 | 212 | if (fstat(fileno(fp), &stats)) { 213 | ret = -1; 214 | goto done; 215 | } 216 | 217 | file_buf = malloc(stats.st_size + 1); 218 | 219 | if (!file_buf) { 220 | ret = -1; 221 | goto done; 222 | } 223 | 224 | if (fread(file_buf, stats.st_size, 1, fp) != 1) { 225 | ret = -1; 226 | goto done; 227 | } 228 | 229 | json_root = cJSON_Parse(file_buf); 230 | 231 | if (!json_root) { 232 | ret = -1; 233 | goto done; 234 | } 235 | 236 | format_node = cJSON_GetObjectItem(json_root, "file_format_version"); 237 | if (!format_node || 238 | (format_node->type != cJSON_String) || 239 | check_json_format_version(format_node->valuestring)) { 240 | ret = -1; 241 | goto done; 242 | } 243 | 244 | driver_node = cJSON_GetObjectItem(json_root, "allocator_driver"); 245 | if (!driver_node || 246 | (driver_node->type != cJSON_Object)) { 247 | ret = -1; 248 | goto done; 249 | } 250 | 251 | driver_path_node = cJSON_GetObjectItem(driver_node, "library_path"); 252 | if (!driver_path_node || 253 | (driver_path_node->type != cJSON_String)) { 254 | ret = -1; 255 | goto done; 256 | } 257 | 258 | ret = add_one_driver(driver_path_node->valuestring); 259 | 260 | done: 261 | cJSON_Delete(json_root); 262 | 263 | free(file_buf); 264 | 265 | if (fp) { 266 | fclose(fp); 267 | } 268 | 269 | return ret; 270 | } 271 | 272 | static int scandir_filter(const struct dirent *ent) 273 | { 274 | /* Ignore the entry if we know that it's not a regular file or symlink */ 275 | if ((ent->d_type != DT_REG) && 276 | (ent->d_type != DT_LNK) && 277 | (ent->d_type != DT_UNKNOWN)) { 278 | return 0; 279 | } 280 | 281 | /* Otherwise, select any JSON files */ 282 | if (fnmatch("*.json", ent->d_name, 0) == 0) { 283 | return 1; 284 | } else { 285 | return 0; 286 | } 287 | } 288 | 289 | /*! 290 | * Helper function to compare two filenames without taking locale into account 291 | * 292 | * This is used in place of alphasort() to avoid loading drivers in a different 293 | * order depending on the locale of the machine, which would be a pain to 294 | * debug if it ever caused problems. 295 | */ 296 | static int compare_filenames(const struct dirent **ent1, 297 | const struct dirent **ent2) 298 | { 299 | return strcmp((*ent1)->d_name, (*ent2)->d_name); 300 | } 301 | 302 | /*! 303 | * Enumerate driver JSON config files in the specified directory, and load the 304 | * drivers they refer to. 305 | * 306 | * \param[in] dir_name A directory path. 307 | * 308 | * \return 0 on success, -1 on failure. Note success does not mean any drivers 309 | * were found. 310 | */ 311 | static int add_drivers_in_dir(const char *dir_name) 312 | { 313 | struct dirent **entries = NULL; 314 | int ret = 0; 315 | const char *path_separator; 316 | static const char *PATH_FMT = "%s%s%s"; 317 | int i; 318 | int count = scandir(dir_name, &entries, scandir_filter, compare_filenames); 319 | size_t dir_name_len; 320 | 321 | if (count < 0 ) { 322 | ret = -1; 323 | goto done; 324 | } else if (count == 0) { 325 | ret = 0; 326 | goto done; 327 | } 328 | 329 | dir_name_len = strlen(dir_name); 330 | 331 | if ((dir_name_len > 0) && (dir_name[dir_name_len - 1] != '/')) { 332 | path_separator = "/"; 333 | } else { 334 | path_separator = ""; 335 | } 336 | 337 | for (i = 0; i < count; i++) { 338 | char *path; 339 | int load_result; 340 | int path_len = snprintf(NULL, 0, PATH_FMT, 341 | dir_name, path_separator, entries[i]->d_name); 342 | 343 | if (path_len < 0 ) { 344 | ret = -1; 345 | goto done; 346 | } 347 | 348 | /* Since only files ending in json were found, path_len should be > 0 */ 349 | assert(path_len > 0); 350 | 351 | path = malloc(path_len + 1); 352 | 353 | if (!path) { 354 | ret = -1; 355 | goto done; 356 | } 357 | 358 | snprintf(path, path_len + 1, PATH_FMT, 359 | dir_name, path_separator, entries[i]->d_name); 360 | 361 | load_result = add_one_driver_from_config(path); 362 | 363 | free(path); 364 | 365 | if (load_result < 0) { 366 | ret = load_result; 367 | goto done; 368 | } 369 | } 370 | 371 | done: 372 | free(entries); 373 | 374 | return ret; 375 | } 376 | 377 | /*! 378 | * Enumerate, load, and initialize all available driver libraries on the system 379 | * 380 | * TODO expand this function to scan home directories and other default config 381 | * file locations and locations specified by environment variables. Be sure 382 | * to check for suid when checking non-secure locations. 383 | * 384 | * \return 0 on success, -1 on failure. Not success does not indicate any 385 | * drivers were found. 386 | */ 387 | static int init_drivers(void) 388 | { 389 | if (!drivers_initialized) { 390 | drivers_initialized = 1; 391 | 392 | /* TODO Don't use a single hard-coded path. */ 393 | return add_drivers_in_dir("/etc/allocator"); 394 | } 395 | 396 | return 0; 397 | } 398 | 399 | /*! 400 | * Given a file descriptor, attempt to find a driver that supports it. 401 | * 402 | * Initializes any available drivers and then scans through them in the 403 | * order they were enumerated. 404 | * 405 | * \param[in] fd The file descriptor for which a driver is requested. 406 | * 407 | * \return An initialized driver instance on success, NULL on failure. 408 | */ 409 | driver_t *find_driver_for_fd(int fd) 410 | { 411 | if (init_drivers() < 0) { 412 | return NULL; 413 | } 414 | 415 | for (driver_t *driver = driver_list; driver; driver = driver->next) { 416 | if (driver->is_fd_supported(driver, fd)) { 417 | return driver; 418 | } 419 | } 420 | 421 | return NULL; 422 | } 423 | -------------------------------------------------------------------------------- /src/driver_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __SRC_DRIVER_MANAGER_H__ 24 | #define __SRC_DRIVER_MANAGER_H__ 25 | 26 | extern driver_t *find_driver_for_fd(int fd); 27 | 28 | #endif /* __SRC_DRIVER_MANAGER_H__ */ 29 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to deal 5 | # in the Software without restriction, including without limitation the rights 6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | # copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in all 11 | # copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | bin_PROGRAMS = capability_set_ops device_alloc create_allocation 22 | 23 | capability_set_ops_CFLAGS = -I$(top_srcdir)/include 24 | capability_set_ops_SOURCES = capability_set_ops.c test_utils.c 25 | capability_set_ops_LDADD = $(top_builddir)/src/liballocator.la 26 | 27 | device_alloc_CFLAGS = -I$(top_srcdir)/include 28 | device_alloc_SOURCES = device_alloc.c test_utils.c 29 | device_alloc_LDADD = $(top_builddir)/src/liballocator.la 30 | 31 | create_allocation_CFLAGS = -I$(top_srcdir)/include 32 | create_allocation_SOURCES = create_allocation.c test_utils.c 33 | create_allocation_LDADD = $(top_builddir)/src/liballocator.la 34 | 35 | if HAVE_LIBDRM 36 | bin_PROGRAMS += drm_import_allocation 37 | drm_import_allocation_CFLAGS = -I$(top_srcdir)/include $(LIBDRM_CFLAGS) 38 | drm_import_allocation_SOURCES = drm_import_allocation.c test_utils.c 39 | drm_import_allocation_LDADD = $(top_builddir)/src/liballocator.la 40 | drm_import_allocation_LDFLAGS = $(LIBDRM_LIBS) 41 | endif 42 | 43 | noinst_HEADERS = test_utils.h 44 | -------------------------------------------------------------------------------- /tests/capability_set_ops.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* For getopt_long */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "test_utils.h" 36 | 37 | static void usage(void) 38 | { 39 | printf("\nUsage: capability_set_ops [-d|--device] DEVICE0_FILE_NAME " 40 | "[[-d|--device] DEVICE1_FILE_NAME ...] [-v|--verbose]\n"); 41 | } 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | static struct option long_options[] = { 46 | {"device", required_argument, NULL, 'd'}, 47 | {"verbose", no_argument, NULL, 'v'}, 48 | {NULL, 0, NULL, 0} 49 | }; 50 | 51 | static assertion_t assertion = { 52 | 256, /* width */ 53 | 256, /* height */ 54 | NULL, /* format */ 55 | NULL /* ext */ 56 | }; 57 | 58 | static usage_texture_t texture_usage = { 59 | { /* header */ 60 | VENDOR_BASE, /* usage vendor */ 61 | USAGE_BASE_TEXTURE, /* usage name */ 62 | USAGE_LENGTH_IN_WORDS(usage_texture_t) /* length_in_word */ 63 | } 64 | }; 65 | 66 | static usage_t uses = { 67 | NULL, /* dev, overidden below */ 68 | &texture_usage.header /* usage */ 69 | }; 70 | static const uint32_t num_uses = 1; 71 | 72 | uint32_t num_assertion_hints = 0; 73 | assertion_hint_t *assertion_hints; 74 | 75 | uint32_t *num_capability_sets; 76 | capability_set_t **capability_sets; 77 | 78 | uint32_t tmp_num_sets[2]; 79 | capability_set_t *tmp_sets[2]; 80 | 81 | int opt; 82 | size_t num_devices = 0; 83 | int i; 84 | char **dev_file_names = NULL; 85 | char **temp; 86 | int *dev_fds; 87 | device_t **devs; 88 | bool verbose = false; 89 | 90 | while ((opt = getopt_long(argc, argv, "d:v", long_options, NULL)) != -1) { 91 | switch (opt) { 92 | case 'd': 93 | dev_file_names = realloc(dev_file_names, 94 | sizeof(dev_file_names[0]) * 95 | (num_devices + 1)); 96 | 97 | if (!dev_file_names) { 98 | FAIL("Not enough memory for device file name list\n"); 99 | } 100 | 101 | dev_file_names[num_devices] = strdup(optarg); 102 | if (!dev_file_names[num_devices]) { 103 | FAIL("Failed to make a copy of the device string\n"); 104 | } 105 | 106 | num_devices++; 107 | break; 108 | 109 | case 'v': 110 | verbose = true; 111 | break; 112 | 113 | case '?': 114 | usage(); 115 | exit(1); 116 | 117 | default: 118 | FAIL("Invalid option\n"); 119 | break; 120 | } 121 | } 122 | 123 | if (!num_devices) { 124 | usage(); 125 | exit(1); 126 | } 127 | 128 | dev_fds = malloc(sizeof(dev_fds[0]) * num_devices); 129 | devs = malloc(sizeof(devs[0]) * num_devices); 130 | num_capability_sets = malloc(sizeof(num_capability_sets[0]) * num_devices); 131 | capability_sets = malloc(sizeof(capability_sets[0]) * num_devices); 132 | 133 | if (!dev_fds || !devs || !num_capability_sets || !capability_sets) { 134 | FAIL("Couldn't allocate memory for device lists\n"); 135 | } 136 | 137 | for (i = 0; i < num_devices; i++) { 138 | dev_fds[i] = open(dev_file_names[i], O_RDWR); 139 | 140 | if (dev_fds[i] < 0) { 141 | FAIL("Couldn't open device file %s\n", dev_file_names[i]); 142 | } 143 | 144 | devs[i] = device_create(dev_fds[i]); 145 | 146 | if (!devs[i]) { 147 | FAIL("Couldn't create allocator device from device FD\n"); 148 | } 149 | 150 | uses.dev = devs[i]; 151 | 152 | /* Query assertion hints and use maximum surface size reported */ 153 | if (device_get_assertion_hints(devs[i], num_uses, &uses, 154 | &num_assertion_hints, 155 | &assertion_hints) || 156 | (num_assertion_hints == 0)) { 157 | FAIL("Couldn't get assertion hints for given usage from " 158 | "device %i\n", i); 159 | } 160 | 161 | assertion.width = assertion_hints[0].max_width; 162 | assertion.height = assertion_hints[0].max_height; 163 | 164 | free_assertion_hints(num_assertion_hints, assertion_hints); 165 | 166 | /* Query capabilities for a common usage case from the device */ 167 | if (device_get_capabilities(devs[i], &assertion, num_uses, &uses, 168 | &num_capability_sets[i], 169 | &capability_sets[i])) { 170 | FAIL("Couldn't get capabilities for given usage from device %i\n", 171 | i); 172 | } 173 | 174 | /* Print initial capability sets */ 175 | if (verbose) { 176 | uint32_t n; 177 | 178 | for (n = 0; n < num_capability_sets[i]; n++) { 179 | printf("Device %i - Set %d:\n", i, n); 180 | print_capability_set(&capability_sets[i][n]); 181 | } 182 | } 183 | } 184 | 185 | for (i = 0; i < num_devices; i++) { 186 | if (num_capability_sets[i]) { 187 | uint32_t n; 188 | 189 | /* 190 | * Ensure serializing and deserializing capability sets is an 191 | * identity operation. 192 | */ 193 | for (n = 0; n < num_capability_sets[i]; n++) { 194 | void *data; 195 | size_t data_size; 196 | capability_set_t *tmp_set; 197 | 198 | if (serialize_capability_set(&capability_sets[i][n], 199 | &data_size, 200 | &data)) { 201 | FAIL("Could not serialize a capability set\n"); 202 | } 203 | 204 | if (deserialize_capability_set(data_size, data, &tmp_set)) { 205 | FAIL("Could not deserialize a capability set\n"); 206 | } 207 | 208 | if (compare_capability_sets(&capability_sets[i][n], 209 | tmp_set)) { 210 | /* Print tmp_set to compare */ 211 | if (verbose) { 212 | printf("Deserialized (Device %i - Set %d):\n", i, n); 213 | print_capability_set(tmp_set); 214 | } 215 | 216 | FAIL("Serializing then deserializing a capability set " 217 | "modified the set contents\n"); 218 | } 219 | 220 | free_capability_sets(1, tmp_set); 221 | free(data); 222 | } 223 | 224 | /* 225 | * Ensure deriving capabilities from two identical lists of sets is 226 | * an identity operation. 227 | */ 228 | if (derive_capabilities(num_capability_sets[i], 229 | capability_sets[i], 230 | num_capability_sets[i], 231 | capability_sets[i], 232 | &tmp_num_sets[0], 233 | &tmp_sets[0])) { 234 | FAIL("Couldn't derive capabilities from identical set lists\n"); 235 | } 236 | 237 | if (tmp_num_sets[0] != num_capability_sets[i]) { 238 | /* Print tmp_sets to compare */ 239 | if (verbose) { 240 | for (n = 0; n < tmp_num_sets[0]; n++) { 241 | printf("Derived (Device %i - Set %d):\n", i, n); 242 | print_capability_set(&tmp_sets[0][n]); 243 | } 244 | } 245 | 246 | FAIL("Deriving capabilities from two identical lists removed " 247 | "or added sets\n"); 248 | } 249 | 250 | for (n = 0; n < num_capability_sets[i]; n++) { 251 | if (compare_capability_sets(&capability_sets[i][n], 252 | &tmp_sets[0][n])) { 253 | /* Print tmp_set to compare */ 254 | if (verbose) { 255 | printf("Derived (Device %i - Set %d):\n", i, n); 256 | print_capability_set(&tmp_sets[0][n]); 257 | } 258 | 259 | FAIL("Deriving capabilities from two identical lists " 260 | "was not an identity operation\n"); 261 | } 262 | } 263 | 264 | free_capability_sets(tmp_num_sets[0], tmp_sets[0]); 265 | tmp_sets[0] = NULL; 266 | tmp_num_sets[0] = 0; 267 | } 268 | } 269 | 270 | tmp_sets[0] = capability_sets[0]; 271 | tmp_num_sets[0] = num_capability_sets[0]; 272 | for (i = 1; i < num_devices; i++) { 273 | size_t last = !(i % 2); 274 | size_t next = i % 2; 275 | if (derive_capabilities(tmp_num_sets[last], 276 | tmp_sets[last], 277 | num_capability_sets[i], 278 | capability_sets[i], 279 | &tmp_num_sets[next], 280 | &tmp_sets[next])) { 281 | FAIL("Couldn't derive capabilities\n"); 282 | } 283 | 284 | if (verbose) { 285 | uint32_t n; 286 | for (n = 0; n < tmp_num_sets[next]; n++) { 287 | printf("Derived against device %i (set %d):\n", i, n); 288 | print_capability_set(&tmp_sets[next][n]); 289 | } 290 | } 291 | 292 | free_capability_sets(tmp_num_sets[last], tmp_sets[last]); 293 | tmp_sets[last] = NULL; 294 | tmp_num_sets[last] = 0; 295 | } 296 | 297 | for (i = 0; i < num_devices; i++) { 298 | device_destroy(devs[i]); 299 | 300 | close(dev_fds[i]); 301 | } 302 | 303 | printf("Success\n"); 304 | 305 | return 0; 306 | } 307 | -------------------------------------------------------------------------------- /tests/create_allocation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* For getopt_long */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "test_utils.h" 35 | 36 | static void usage(void) 37 | { 38 | printf("\nUsage: create_allocation [-d|--device] DEVICE_FILE_NAME\n"); 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | static struct option long_options[] = { 44 | {"device", required_argument, NULL, 'd'}, 45 | {NULL, 0, NULL, 0} 46 | }; 47 | 48 | static assertion_t assertion = { 49 | 256, /* width */ 50 | 256, /* height */ 51 | NULL, /* format */ 52 | NULL /* ext */ 53 | }; 54 | 55 | static usage_texture_t texture_usage = { 56 | { /* header */ 57 | VENDOR_BASE, /* usage vendor */ 58 | USAGE_BASE_TEXTURE, /* usage name */ 59 | USAGE_LENGTH_IN_WORDS(usage_texture_t) /* length_in_word */ 60 | } 61 | }; 62 | 63 | static usage_t uses = { 64 | NULL, /* dev, overidden below */ 65 | &texture_usage.header /* usage */ 66 | }; 67 | static const uint32_t num_uses = 1; 68 | 69 | uint32_t num_capability_sets; 70 | capability_set_t *capability_sets; 71 | 72 | int opt; 73 | char *dev_file_name = NULL; 74 | 75 | device_t *dev; 76 | allocation_t *allocation; 77 | int dev_fd; 78 | uint32_t i; 79 | 80 | while ((opt = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { 81 | switch (opt) { 82 | case 'd': 83 | dev_file_name = strdup(optarg); 84 | if (!dev_file_name) { 85 | FAIL("Failed to make a copy of the device string\n"); 86 | } 87 | break; 88 | 89 | case '?': 90 | usage(); 91 | exit(1); 92 | 93 | default: 94 | FAIL("Invalid option\n"); 95 | break; 96 | } 97 | } 98 | 99 | if (!dev_file_name) { 100 | usage(); 101 | exit(1); 102 | } 103 | 104 | dev_fd = open(dev_file_name, O_RDWR); 105 | 106 | if (dev_fd < 0) { 107 | FAIL("Couldn't open device file %s\n", dev_file_name); 108 | } 109 | 110 | dev = device_create(dev_fd); 111 | 112 | if (!dev) { 113 | FAIL("Couldn't create allocator device from device FD\n"); 114 | } 115 | 116 | 117 | /* Query capabilities for a common usage case from the device */ 118 | if (device_get_capabilities(dev, &assertion, num_uses, &uses, 119 | &num_capability_sets, 120 | &capability_sets)) { 121 | FAIL("Couldn't get capabilities for given usage from device %s\n", 122 | dev_file_name); 123 | } 124 | 125 | for (i = 0; i < num_capability_sets; i++) { 126 | int allocation_fd; 127 | size_t metadata_size; 128 | void *metadata; 129 | uint64_t allocation_size; 130 | 131 | if (device_create_allocation(dev, 132 | &assertion, 133 | &capability_sets[i], 134 | &allocation)) { 135 | FAIL("Couldn't create allocation from capability set %u\n", i); 136 | } 137 | 138 | if (device_export_allocation(dev, 139 | allocation, 140 | &allocation_size, 141 | &metadata_size, 142 | &metadata, 143 | &allocation_fd)) { 144 | FAIL("Couldn't export an allocation created from capability set " 145 | "%u\n", i); 146 | } 147 | 148 | close(allocation_fd); 149 | free(metadata); 150 | 151 | device_destroy_allocation(dev, allocation); 152 | } 153 | 154 | device_destroy(dev); 155 | 156 | close(dev_fd); 157 | 158 | printf("Success\n"); 159 | 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /tests/device_alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* For getopt_long */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "test_utils.h" 35 | 36 | static void usage(void) 37 | { 38 | printf("\nUsage: device_alloc [-d|--device] DEVICE_FILE_NAME\n"); 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | static struct option long_options[] = { 44 | {"device", required_argument, NULL, 'd'}, 45 | {NULL, 0, NULL, 0} 46 | }; 47 | 48 | int opt; 49 | char *dev_file_name = NULL; 50 | int dev_fd; 51 | device_t *dev; 52 | 53 | while ((opt = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { 54 | switch (opt) { 55 | case 'd': 56 | dev_file_name = strdup(optarg); 57 | if (!dev_file_name) { 58 | FAIL("Failed to make a copy of the device string\n"); 59 | } 60 | break; 61 | 62 | case '?': 63 | usage(); 64 | exit(1); 65 | 66 | default: 67 | FAIL("Invalid option\n"); 68 | break; 69 | } 70 | } 71 | 72 | if (!dev_file_name) { 73 | usage(); 74 | exit(1); 75 | } 76 | 77 | dev_fd = open(dev_file_name, O_RDWR); 78 | 79 | if (dev_fd < 0) { 80 | FAIL("Couldn't open device file %s\n", dev_file_name); 81 | } 82 | 83 | dev = device_create(dev_fd); 84 | 85 | if (!dev) { 86 | FAIL("Couldn't create allocator device from device FD\n"); 87 | } 88 | 89 | device_destroy(dev); 90 | 91 | close(dev_fd); 92 | 93 | printf("Success\n"); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /tests/drm_import_allocation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* For getopt_long */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "test_utils.h" 39 | 40 | static void usage(void) 41 | { 42 | printf("\nUsage: drm_import_allocation [-f|--file] " 43 | "[-d|--drm-file] \n"); 44 | } 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | static struct option long_options[] = { 49 | {"file", required_argument, NULL, 'f'}, 50 | {"drm-file", required_argument, NULL, 'd'}, 51 | {NULL, 0, NULL, 0} 52 | }; 53 | 54 | static assertion_t assertion = { 55 | 256, /* width */ 56 | 256, /* height */ 57 | NULL, /* format */ 58 | NULL /* ext */ 59 | }; 60 | 61 | static usage_texture_t texture_usage = { 62 | { /* header */ 63 | VENDOR_BASE, /* usage vendor */ 64 | USAGE_BASE_TEXTURE, /* usage name */ 65 | USAGE_LENGTH_IN_WORDS(usage_texture_t) /* length_in_word */ 66 | } 67 | }; 68 | 69 | static usage_t uses = { 70 | NULL, /* dev, overidden below */ 71 | &texture_usage.header /* usage */ 72 | }; 73 | static const uint32_t num_uses = 1; 74 | 75 | uint32_t num_capability_sets; 76 | capability_set_t *capability_sets; 77 | 78 | int opt; 79 | char *dev_file_name = NULL; 80 | char *drm_file_name = NULL; 81 | 82 | device_t *dev; 83 | allocation_t *allocation; 84 | int dev_fd; 85 | 86 | int drm_fd; 87 | uint32_t drm_fb; 88 | 89 | uint32_t bpp = 4; /* allocator assumes ARGB8888 allocations for now */ 90 | const constraint_t *pitch_alignment_cons; 91 | uint32_t pitch_alignment = 1; 92 | uint32_t pitch; 93 | 94 | uint32_t i; 95 | 96 | while ((opt = getopt_long(argc, argv, "f:d:c:l", long_options, NULL)) != -1) { 97 | switch (opt) { 98 | case 'f': 99 | dev_file_name = strdup(optarg); 100 | if (!dev_file_name) { 101 | FAIL("Failed to make a copy of the allocator device string\n"); 102 | } 103 | break; 104 | 105 | case 'd': 106 | drm_file_name = strdup(optarg); 107 | if (!drm_file_name) { 108 | FAIL("Failed to make a copy of the DRM device string\n"); 109 | } 110 | break; 111 | 112 | case '?': 113 | usage(); 114 | exit(1); 115 | 116 | default: 117 | FAIL("Invalid option\n"); 118 | break; 119 | } 120 | } 121 | 122 | if (!dev_file_name || !drm_file_name) { 123 | usage(); 124 | exit(1); 125 | } 126 | 127 | dev_fd = open(dev_file_name, O_RDWR); 128 | if (dev_fd < 0) { 129 | FAIL("Couldn't open allocator device file %s\n", dev_file_name); 130 | } 131 | 132 | dev = device_create(dev_fd); 133 | if (!dev) { 134 | FAIL("Couldn't create allocator device from device FD\n"); 135 | } 136 | 137 | drm_fd = open(drm_file_name, O_RDWR); 138 | if (drm_fd < 0) { 139 | FAIL("Couldn't open DRM device file %s\n", dev_file_name); 140 | } 141 | 142 | /* Query capabilities for a common usage case from the device */ 143 | if (device_get_capabilities(dev, &assertion, num_uses, &uses, 144 | &num_capability_sets, 145 | &capability_sets)) { 146 | FAIL("Couldn't get capabilities for given usage from device %s\n", 147 | dev_file_name); 148 | } 149 | 150 | for (i = 0; i < num_capability_sets; i++) { 151 | int allocation_fd; 152 | size_t metadata_size; 153 | void *metadata; 154 | uint64_t allocation_size; 155 | uint32_t drm_gem_handle; 156 | struct drm_gem_close gemCloseArgs; 157 | int ret; 158 | 159 | if (device_create_allocation(dev, 160 | &assertion, 161 | &capability_sets[i], 162 | &allocation)) { 163 | FAIL("Couldn't create allocation from capability set %d\n", i); 164 | } 165 | 166 | if (device_export_allocation(dev, 167 | allocation, 168 | &allocation_size, 169 | &metadata_size, 170 | &metadata, 171 | &allocation_fd)) { 172 | FAIL("Couldn't export an allocation created from capability set " 173 | "%d\n", i); 174 | } 175 | 176 | /* Create a DRM FB */ 177 | ret = drmPrimeFDToHandle(drm_fd, allocation_fd, &drm_gem_handle); 178 | if (ret != 0) { 179 | FAIL("Couldn't get DRM GEM handle from allocation created from " 180 | "capability set %d (error = %d)\n", i, ret); 181 | } 182 | 183 | pitch_alignment_cons = 184 | find_constraint(&capability_sets[i], CONSTRAINT_PITCH_ALIGNMENT); 185 | if (pitch_alignment_cons) { 186 | pitch_alignment = pitch_alignment_cons->u.pitch_alignment.value; 187 | } 188 | 189 | pitch = assertion.width * bpp; 190 | pitch += (pitch_alignment - 1); 191 | pitch &= ~(pitch_alignment - 1); 192 | 193 | // TODO: Use a more versatile API that allows to pass allocator metadata 194 | ret = drmModeAddFB(drm_fd, assertion.width, assertion.height, 0, 8 * bpp, 195 | pitch, drm_gem_handle, &drm_fb); 196 | if (ret != 0) { 197 | FAIL("Couldn't create DRM FB from allocation created from " 198 | "capability set %d (error = %d)\n", i, ret); 199 | } 200 | 201 | drmModeRmFB(drm_fd, drm_fb); 202 | 203 | memset(&gemCloseArgs, 0, sizeof(gemCloseArgs)); 204 | gemCloseArgs.handle = drm_gem_handle; 205 | drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gemCloseArgs); 206 | 207 | close(allocation_fd); 208 | free(metadata); 209 | 210 | device_destroy_allocation(dev, allocation); 211 | } 212 | 213 | close(drm_fd); 214 | 215 | done: 216 | device_destroy(dev); 217 | 218 | close(dev_fd); 219 | 220 | printf("Success\n"); 221 | 222 | return 0; 223 | } 224 | -------------------------------------------------------------------------------- /tests/test_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "test_utils.h" 30 | 31 | void FAIL(const char *fmt, ...) 32 | { 33 | va_list ap; 34 | va_start(ap, fmt); 35 | vfprintf(stderr, fmt, ap); 36 | va_end(ap); 37 | 38 | exit(1); 39 | } 40 | 41 | int compare_capability_sets(capability_set_t *set0, capability_set_t *set1) 42 | { 43 | uint32_t i; 44 | 45 | if (!set0 || !set1) { 46 | return 1; 47 | } 48 | 49 | if (set0->num_constraints != set1->num_constraints) { 50 | return 1; 51 | } 52 | 53 | if (set0->num_capabilities != set1->num_capabilities) { 54 | return 1; 55 | } 56 | 57 | if (memcmp(set0->constraints, set1->constraints, 58 | sizeof(set0->constraints[0]) * set0->num_constraints)) { 59 | return 1; 60 | } 61 | 62 | for (i = 0; i < set0->num_capabilities; i++) { 63 | if (memcmp(set0->capabilities[i], set1->capabilities[i], 64 | sizeof(*set0->capabilities[i]) + 65 | (set0->capabilities[i]->common.length_in_words * 66 | sizeof(uint32_t)))) { 67 | return 1; 68 | } 69 | } 70 | 71 | return 0; 72 | } 73 | 74 | const constraint_t *find_constraint(const capability_set_t *set, uint32_t name) 75 | { 76 | int i; 77 | 78 | for (i = 0; i < set->num_constraints; i++) { 79 | if (set->constraints[i].name == name) { 80 | return &set->constraints[i]; 81 | } 82 | } 83 | 84 | return NULL; 85 | } 86 | 87 | void print_constraint(const constraint_t *constraint) 88 | { 89 | int i; 90 | 91 | #define DO_PRINT_CONSTRAINT(NAME, FMT, UNION_MEMBER) \ 92 | case CONSTRAINT_ ## NAME: \ 93 | printf(" name: CONSTRAINT_" #NAME " (0x%x)\n", \ 94 | constraint->name); \ 95 | printf(" value: %" FMT "\n", constraint->u.UNION_MEMBER.value); \ 96 | break 97 | 98 | switch (constraint->name) { 99 | DO_PRINT_CONSTRAINT(ADDRESS_ALIGNMENT, PRIu64, address_alignment); 100 | DO_PRINT_CONSTRAINT(PITCH_ALIGNMENT, PRIu32, pitch_alignment); 101 | DO_PRINT_CONSTRAINT(MAX_PITCH, PRIu32, max_pitch); 102 | default: 103 | printf(" name: UNKNOWN (0x%x)\n", constraint->name); 104 | printf(" value: "); 105 | for (i = 0; i < sizeof(constraint->u); i++) { 106 | if (i > 0) { 107 | printf(":"); 108 | } 109 | printf("%02X", ((const char *)(&constraint->u))[i]); 110 | } 111 | printf("\n"); 112 | break; 113 | } 114 | 115 | #undef DO_PRINT_CONSTRAINT 116 | } 117 | 118 | void print_capability_header(const capability_header_t *capability) 119 | { 120 | #define PRINT_VENDOR(NAME) \ 121 | printf(" vendor: " #NAME " (0x%x)\n", \ 122 | capability->common.vendor); \ 123 | break 124 | #define DO_PRINT_VENDOR(NAME) case VENDOR_ ## NAME: PRINT_VENDOR(NAME) 125 | 126 | #define PRINT_CAP(NAME) \ 127 | printf(" name: %s (0x%x)\n", \ 128 | (capability->common.vendor == VENDOR_BASE) ? "CAP_BASE_" #NAME : \ 129 | "VENDOR_CAP", \ 130 | capability->common.name); \ 131 | break 132 | #define DO_PRINT_CAP(NAME) case CAP_BASE_ ## NAME: PRINT_CAP(NAME) 133 | 134 | switch (capability->common.vendor) { 135 | DO_PRINT_VENDOR(BASE); 136 | DO_PRINT_VENDOR(NVIDIA); 137 | DO_PRINT_VENDOR(ARM); 138 | DO_PRINT_VENDOR(INTEL); 139 | default: 140 | PRINT_VENDOR(UNKNOWN); 141 | } 142 | 143 | switch (capability->common.name) { 144 | DO_PRINT_CAP(PITCH_LINEAR); 145 | default: 146 | PRINT_CAP(UNKNOWN); 147 | } 148 | 149 | printf(" length_in_words: %u\n", capability->common.length_in_words); 150 | printf(" required: %s\n", capability->required ? "true" : "false"); 151 | 152 | if (capability->common.length_in_words > 0) { 153 | int i; 154 | 155 | printf(" value: "); 156 | for (i = 0; i < capability->common.length_in_words; i++) { 157 | if (i > 0) { 158 | printf(":"); 159 | } 160 | printf("%04X", ((const uint32_t *)(&capability[1]))[i]); 161 | } 162 | printf("\n"); 163 | } 164 | 165 | #undef PRINT_VENDOR 166 | #undef DO_PRINT_VENDOR 167 | #undef PRINT_CAP 168 | #undef DO_PRINT_CAP 169 | } 170 | 171 | void print_capability_set(const capability_set_t *set) 172 | { 173 | int i; 174 | 175 | printf(" capability_set_t (%p):\n", set); 176 | printf(" num_constraints: %u\n", set->num_constraints); 177 | printf(" constraints:\n"); 178 | for (i = 0; i < set->num_constraints; i++) { 179 | printf(" %d:\n", i); 180 | print_constraint(&set->constraints[i]); 181 | printf("\n"); 182 | } 183 | 184 | printf(" num_capabilities: %u\n", set->num_capabilities); 185 | printf(" capabilities:\n"); 186 | for (i = 0; i < set->num_capabilities; i++) { 187 | printf(" %d:\n", i); 188 | print_capability_header(set->capabilities[i]); 189 | printf("\n"); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /tests/test_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef __ALLOCATOR_TEST_UTILS_H__ 24 | #define __ALLOCATOR_TEST_UTILS_H__ 25 | 26 | #include 27 | 28 | extern void FAIL(const char *fmt, ...); 29 | extern int compare_capability_sets(capability_set_t *set0, 30 | capability_set_t *set1); 31 | extern const constraint_t *find_constraint(const capability_set_t *set, 32 | uint32_t name); 33 | extern void print_constraint(const constraint_t *constraint); 34 | extern void print_capability_header(const capability_header_t *capability); 35 | extern void print_capability_set(const capability_set_t *set); 36 | 37 | #endif /* __ALLOCATOR_TEST_UTILS_H__ */ 38 | --------------------------------------------------------------------------------